mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Major psql overhaul by Peter Eisentraut.
This commit is contained in:
@ -1,119 +1,179 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* stringutils.c
|
||||
* simple string manipulation routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.17 1999/07/17 20:18:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <ctype.h>
|
||||
|
||||
#include "postgres.h"
|
||||
#ifndef HAVE_STRDUP
|
||||
#include "strdup.h"
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
#include <c.h>
|
||||
#include "stringutils.h"
|
||||
|
||||
/* all routines assume null-terminated strings! */
|
||||
//#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
//#include <stdio.h>
|
||||
|
||||
/* The following routines remove whitespaces from the left, right
|
||||
and both sides of a string */
|
||||
/* MODIFIES the string passed in and returns the head of it */
|
||||
#include <postgres.h>
|
||||
#ifndef HAVE_STRDUP
|
||||
#include <strdup.h>
|
||||
#endif
|
||||
#include <libpq-fe.h>
|
||||
|
||||
#ifdef NOT_USED
|
||||
static char *
|
||||
leftTrim(char *s)
|
||||
|
||||
|
||||
static void
|
||||
unescape_quotes(char *source, char quote, char escape);
|
||||
|
||||
|
||||
/*
|
||||
* Replacement for strtok() (a.k.a. poor man's flex)
|
||||
*
|
||||
* The calling convention is similar to that of strtok.
|
||||
* s - string to parse, if NULL continue parsing the last string
|
||||
* delim - set of characters that delimit tokens (usually whitespace)
|
||||
* quote - set of characters that quote stuff, they're not part of the token
|
||||
* escape - character than can quote quotes
|
||||
* was_quoted - if not NULL, stores the quoting character if any was encountered
|
||||
* token_pos - if not NULL, receives a count to the start of the token in the
|
||||
* parsed string
|
||||
*
|
||||
* Note that the string s is _not_ overwritten in this implementation.
|
||||
*/
|
||||
char * strtokx(const char *s,
|
||||
const char *delim,
|
||||
const char *quote,
|
||||
char escape,
|
||||
char * was_quoted,
|
||||
unsigned int * token_pos)
|
||||
{
|
||||
char *s2 = s;
|
||||
int shift = 0;
|
||||
int j = 0;
|
||||
static char * storage = NULL; /* store the local copy of the users string here */
|
||||
static char * string = NULL; /* pointer into storage where to continue on next call */
|
||||
/* variously abused variables: */
|
||||
unsigned int offset;
|
||||
char * start;
|
||||
char *cp = NULL;
|
||||
|
||||
while (isspace(*s))
|
||||
{
|
||||
s++;
|
||||
shift++;
|
||||
}
|
||||
if (shift > 0)
|
||||
{
|
||||
while ((s2[j] = s2[j + shift]) != '\0')
|
||||
j++;
|
||||
}
|
||||
if (s) {
|
||||
free(storage);
|
||||
storage = strdup(s);
|
||||
string = storage;
|
||||
}
|
||||
|
||||
return s2;
|
||||
if (!storage)
|
||||
return NULL;
|
||||
|
||||
/* skip leading "whitespace" */
|
||||
offset = strspn(string, delim);
|
||||
|
||||
/* end of string reached */
|
||||
if (string[offset] == '\0') {
|
||||
/* technically we don't need to free here, but we're nice */
|
||||
free(storage);
|
||||
storage = NULL;
|
||||
string = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* test if quoting character */
|
||||
if (quote)
|
||||
cp = strchr(quote, string[offset]);
|
||||
|
||||
if (cp) {
|
||||
/* okay, we have a quoting character, now scan for the closer */
|
||||
char *p;
|
||||
start = &string[offset+1];
|
||||
|
||||
if (token_pos)
|
||||
*token_pos = start - storage;
|
||||
|
||||
for(p = start;
|
||||
*p && (*p != *cp || *(p-1) == escape) ;
|
||||
#ifdef MULTIBYTE
|
||||
p += PQmblen(p)
|
||||
#else
|
||||
p++
|
||||
#endif
|
||||
);
|
||||
|
||||
/* not yet end of string? */
|
||||
if (*p != '\0') {
|
||||
*p = '\0';
|
||||
string = p + 1;
|
||||
if (was_quoted)
|
||||
*was_quoted = *cp;
|
||||
unescape_quotes (start, *cp, escape);
|
||||
return start;
|
||||
}
|
||||
else {
|
||||
if (was_quoted)
|
||||
*was_quoted = *cp;
|
||||
string = p;
|
||||
|
||||
unescape_quotes (start, *cp, escape);
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
/* otherwise no quoting character. scan till next delimiter */
|
||||
start = &string[offset];
|
||||
|
||||
if (token_pos)
|
||||
*token_pos = start - storage;
|
||||
|
||||
offset = strcspn(start, delim);
|
||||
if (was_quoted)
|
||||
*was_quoted = 0;
|
||||
|
||||
if (start[offset] != '\0') {
|
||||
start[offset] = '\0';
|
||||
string = &start[offset]+1;
|
||||
|
||||
return start;
|
||||
}
|
||||
else {
|
||||
string = &start[offset];
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* unescape_quotes
|
||||
*
|
||||
* Resolves escaped quotes. Used by strtokx above.
|
||||
*/
|
||||
static void
|
||||
unescape_quotes(char *source, char quote, char escape)
|
||||
{
|
||||
char *p;
|
||||
char *destination, *tmp;
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
assert(source);
|
||||
#endif
|
||||
|
||||
char *
|
||||
rightTrim(char *s)
|
||||
{
|
||||
char *sEnd,
|
||||
*bsEnd;
|
||||
bool in_bs = false;
|
||||
destination = (char *) calloc(1, strlen(source)+1);
|
||||
if (!destination) {
|
||||
perror("calloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sEnd = s + strlen(s) - 1;
|
||||
while (sEnd >= s && isspace(*sEnd))
|
||||
sEnd--;
|
||||
bsEnd = sEnd;
|
||||
while (bsEnd >= s && *bsEnd == '\\')
|
||||
{
|
||||
in_bs = (in_bs == false);
|
||||
bsEnd--;
|
||||
tmp = destination;
|
||||
|
||||
for (p = source; *p; p++)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (*p == escape && *(p+1) && quote == *(p+1)) {
|
||||
c = *(p+1);
|
||||
p++;
|
||||
}
|
||||
if (in_bs && *sEnd)
|
||||
sEnd++;
|
||||
if (sEnd < s)
|
||||
s[0] = '\0';
|
||||
else
|
||||
s[sEnd - s + 1] = '\0';
|
||||
return s;
|
||||
c = *p;
|
||||
|
||||
*tmp = c;
|
||||
tmp ++;
|
||||
}
|
||||
|
||||
/* Terminating null character */
|
||||
*tmp = '\0';
|
||||
|
||||
strcpy(source, destination);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
static char *
|
||||
doubleTrim(char *s)
|
||||
{
|
||||
strcpy(s, leftTrim(rightTrim(s)));
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef STRINGUTILS_TEST
|
||||
void
|
||||
testStringUtils()
|
||||
{
|
||||
static char *tests[] = {" goodbye \n", /* space on both ends */
|
||||
"hello world", /* no spaces to trim */
|
||||
"", /* empty string */
|
||||
"a", /* string with one char */
|
||||
" ", /* string with one whitespace */
|
||||
NULL_STR};
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (tests[i] != NULL_STR)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = strdup(tests[i]);
|
||||
printf("leftTrim(%s) = ", t);
|
||||
printf("%sEND\n", leftTrim(t));
|
||||
t = strdup(tests[i]);
|
||||
printf("rightTrim(%s) = ", t);
|
||||
printf("%sEND\n", rightTrim(t));
|
||||
t = strdup(tests[i]);
|
||||
printf("doubleTrim(%s) = ", t);
|
||||
printf("%sEND\n", doubleTrim(t));
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user