are now separate files "postgres.h" and "postgres_fe.h", which are meant to be the primary include files for backend .c files and frontend .c files respectively. By default, only include files meant for frontend use are installed into the installation include directory. There is a new make target 'make install-all-headers' that adds the whole content of the src/include tree to the installed fileset, for use by people who want to develop server-side code without keeping the complete source tree on hand. Cleaned up a whole lot of crufty and inconsistent header inclusions.
197 lines
3.5 KiB
C
197 lines
3.5 KiB
C
/*
|
|
* psql - the PostgreSQL interactive terminal
|
|
*
|
|
* Copyright 2000 by PostgreSQL Global Development Group
|
|
*
|
|
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.27 2001/02/10 02:31:28 tgl Exp $
|
|
*/
|
|
#include "postgres_fe.h"
|
|
#include "stringutils.h"
|
|
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#include "libpq-fe.h"
|
|
|
|
|
|
|
|
static void unescape_quotes(char *source, int quote, int 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,
|
|
int escape,
|
|
char *was_quoted,
|
|
unsigned int *token_pos,
|
|
int encoding)
|
|
{
|
|
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;
|
|
|
|
#ifndef MULTIBYTE
|
|
(void) encoding; /* not used */
|
|
#endif
|
|
|
|
if (s)
|
|
{
|
|
free(storage);
|
|
storage = strdup(s);
|
|
string = storage;
|
|
}
|
|
|
|
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, encoding)
|
|
#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, int quote, int escape)
|
|
{
|
|
char *p;
|
|
char *destination,
|
|
*tmp;
|
|
|
|
#ifdef USE_ASSERT_CHECKING
|
|
assert(source);
|
|
#endif
|
|
|
|
destination = calloc(1, strlen(source) + 1);
|
|
if (!destination)
|
|
{
|
|
perror("calloc");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
tmp = destination;
|
|
|
|
for (p = source; *p; p++)
|
|
{
|
|
char c;
|
|
|
|
if (*p == escape && *(p + 1) && quote == *(p + 1))
|
|
{
|
|
c = *(p + 1);
|
|
p++;
|
|
}
|
|
else
|
|
c = *p;
|
|
|
|
*tmp = c;
|
|
tmp++;
|
|
}
|
|
|
|
/* Terminating null character */
|
|
*tmp = '\0';
|
|
|
|
strcpy(source, destination);
|
|
}
|