stringutils.c 3.54 KB
Newer Older
Peter Eisentraut's avatar
Peter Eisentraut committed
1 2 3
/*
 * psql - the PostgreSQL interactive terminal
 *
4
 * Copyright 2000 by PostgreSQL Global Development Group
Peter Eisentraut's avatar
Peter Eisentraut committed
5
 *
6
 * $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.27 2001/02/10 02:31:28 tgl Exp $
Peter Eisentraut's avatar
Peter Eisentraut committed
7
 */
8
#include "postgres_fe.h"
9 10
#include "stringutils.h"

Bruce Momjian's avatar
Bruce Momjian committed
11
#include <ctype.h>
12
#include <assert.h>
13

14
#include "libpq-fe.h"
15

16

17

18
static void unescape_quotes(char *source, int quote, int escape);
19

20

21 22 23 24
/*
 * Replacement for strtok() (a.k.a. poor man's flex)
 *
 * The calling convention is similar to that of strtok.
Bruce Momjian's avatar
Bruce Momjian committed
25 26 27 28
 * 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
29
 * was_quoted - if not NULL, stores the quoting character if any was encountered
Bruce Momjian's avatar
Bruce Momjian committed
30 31
 * token_pos -	if not NULL, receives a count to the start of the token in the
 *				parsed string
32 33 34
 *
 * Note that the string s is _not_ overwritten in this implementation.
 */
Bruce Momjian's avatar
Bruce Momjian committed
35 36 37 38
char *
strtokx(const char *s,
		const char *delim,
		const char *quote,
39
		int escape,
Bruce Momjian's avatar
Bruce Momjian committed
40
		char *was_quoted,
41 42
		unsigned int *token_pos,
		int encoding)
43
{
Bruce Momjian's avatar
Bruce Momjian committed
44 45 46 47 48 49 50 51 52 53
	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;

54
#ifndef MULTIBYTE
55
	(void) encoding;			/* not used */
56 57
#endif

Bruce Momjian's avatar
Bruce Momjian committed
58 59 60 61 62 63
	if (s)
	{
		free(storage);
		storage = strdup(s);
		string = storage;
	}
64

Bruce Momjian's avatar
Bruce Momjian committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	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;
	}
80

Bruce Momjian's avatar
Bruce Momjian committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	/* 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);
97
#ifdef MULTIBYTE
98
			 p += PQmblen(p, encoding)
99
#else
Bruce Momjian's avatar
Bruce Momjian committed
100
			 p++
101
#endif
Bruce Momjian's avatar
Bruce Momjian committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
			);

		/* 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;
		}
123
	}
124

Bruce Momjian's avatar
Bruce Momjian committed
125 126
	/* otherwise no quoting character. scan till next delimiter */
	start = &string[offset];
127

Bruce Momjian's avatar
Bruce Momjian committed
128 129
	if (token_pos)
		*token_pos = start - storage;
130

Bruce Momjian's avatar
Bruce Momjian committed
131 132 133
	offset = strcspn(start, delim);
	if (was_quoted)
		*was_quoted = 0;
134

Bruce Momjian's avatar
Bruce Momjian committed
135 136 137 138
	if (start[offset] != '\0')
	{
		start[offset] = '\0';
		string = &start[offset] + 1;
139

Bruce Momjian's avatar
Bruce Momjian committed
140 141 142 143 144 145 146
		return start;
	}
	else
	{
		string = &start[offset];
		return start;
	}
147 148
}

149 150 151 152 153 154 155 156 157



/*
 * unescape_quotes
 *
 * Resolves escaped quotes. Used by strtokx above.
 */
static void
158
unescape_quotes(char *source, int quote, int escape)
159
{
Bruce Momjian's avatar
Bruce Momjian committed
160 161 162
	char	   *p;
	char	   *destination,
			   *tmp;
163

164
#ifdef USE_ASSERT_CHECKING
Bruce Momjian's avatar
Bruce Momjian committed
165
	assert(source);
166
#endif
167

168
	destination = calloc(1, strlen(source) + 1);
Bruce Momjian's avatar
Bruce Momjian committed
169 170 171 172 173
	if (!destination)
	{
		perror("calloc");
		exit(EXIT_FAILURE);
	}
174

Bruce Momjian's avatar
Bruce Momjian committed
175
	tmp = destination;
176

Bruce Momjian's avatar
Bruce Momjian committed
177 178 179
	for (p = source; *p; p++)
	{
		char		c;
180

Bruce Momjian's avatar
Bruce Momjian committed
181 182 183 184 185 186 187
		if (*p == escape && *(p + 1) && quote == *(p + 1))
		{
			c = *(p + 1);
			p++;
		}
		else
			c = *p;
188

Bruce Momjian's avatar
Bruce Momjian committed
189 190 191
		*tmp = c;
		tmp++;
	}
192

Bruce Momjian's avatar
Bruce Momjian committed
193 194
	/* Terminating null character */
	*tmp = '\0';
195

Bruce Momjian's avatar
Bruce Momjian committed
196
	strcpy(source, destination);
197
}