postgresql/contrib/string/string_io.c
Tom Lane d08741eab5 Restructure the key include files per recent pghackers discussion: there
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.
2001-02-10 02:31:31 +00:00

374 lines
6.6 KiB
C

/*
* string_io.c --
*
* This file defines C-like input/output conversion routines for strings.
*
* Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it>
*
* This software is distributed under the GNU General Public License
* either version 2, or (at your option) any later version.
*/
#include "postgres.h"
#include <ctype.h>
#include "utils/builtins.h"
#include "string_io.h"
/* define this if you want to see iso-8859 characters */
#define ISO8859
#undef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define VALUE(char) ((char) - '0')
#define DIGIT(val) ((val) + '0')
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
#ifndef ISO8859
#define NOTPRINTABLE(c) (!isprint((unsigned char) (c)))
#else
#define NOTPRINTABLE(c) (!isprint((unsigned char) (c)) && \
((unsigned char) (c) < (unsigned char) 0xa0))
#endif
/*
* string_output() --
*
* This function takes a pointer to a string data and an optional
* data size and returns a printable representation of the string
* translating all escape sequences to C-like \nnn or \c escapes.
* The function is used by output methods of various string types.
*
* Arguments:
* data - input data (can be NULL)
* size - optional size of data. A negative value indicates
* that data is a null terminated string.
*
* Returns:
* a pointer to a new string containing the printable
* representation of data.
*/
unsigned char *
string_output(unsigned char *data, int size)
{
register unsigned char c,
*p,
*r,
*result;
register int l,
len;
if (data == NULL)
{
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
return (result);
}
if (size < 0)
size = strlen(data);
/* adjust string length for escapes */
len = size;
for (p = data, l = size; l > 0; p++, l--)
{
switch (*p)
{
case '\\':
case '"':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
len++;
break;
case '{':
/* Escape beginning of string, to distinguish from arrays */
if (p == data)
len++;
break;
default:
if (NOTPRINTABLE(*p))
len += 3;
}
}
len++;
result = (char *) palloc(len);
for (p = data, r = result, l = size; (l > 0) && (c = *p); p++, l--)
{
switch (c)
{
case '\\':
case '"':
*r++ = '\\';
*r++ = c;
break;
case '\b':
*r++ = '\\';
*r++ = 'b';
break;
case '\f':
*r++ = '\\';
*r++ = 'f';
break;
case '\n':
*r++ = '\\';
*r++ = 'n';
break;
case '\r':
*r++ = '\\';
*r++ = 'r';
break;
case '\t':
*r++ = '\\';
*r++ = 't';
break;
case '\v':
*r++ = '\\';
*r++ = 'v';
break;
case '{':
/* Escape beginning of string, to distinguish from arrays */
if (p == data)
*r++ = '\\';
*r++ = c;
break;
default:
if (NOTPRINTABLE(c))
{
*r = '\\';
r += 3;
*r-- = DIGIT(c & 07);
c >>= 3;
*r-- = DIGIT(c & 07);
c >>= 3;
*r = DIGIT(c & 03);
r += 3;
}
else
*r++ = c;
}
}
*r = '\0';
return ((char *) result);
}
/*
* string_input() --
*
* This function accepts a C string in input and copies it into a new
* object allocated with palloc() translating all escape sequences.
* An optional header can be allocatd before the string, for example
* to hold the length of a varlena object.
* This function is not necessary for input from sql commands because
* the parser already does escape translation, all data input routines
* receive strings in internal form.
*
* Arguments:
* str - input string possibly with escapes
* size - the required size of new data. A value of 0
* indicates a variable size string, while a
* negative value indicates a variable size string
* of size not greater than this absolute value.
* hdrsize - size of an optional header to be allocated before
* the data. It must then be filled by the caller.
* rtn_size - an optional pointer to an int variable where the
* size of the new string is stored back.
*
* Returns:
* a pointer to the new string or the header.
*/
unsigned char *
string_input(unsigned char *str, int size, int hdrsize, int *rtn_size)
{
register unsigned char *p,
*r;
unsigned char *result;
int len;
if ((str == NULL) || (hdrsize < 0))
return (char *) NULL;
/* Compute result size */
len = strlen(str);
for (p = str; *p;)
{
if (*p++ == '\\')
{
if (ISOCTAL(*p))
{
if (ISOCTAL(*(p + 1)))
{
p++;
len--;
}
if (ISOCTAL(*(p + 1)))
{
p++;
len--;
}
}
if (*p)
p++;
len--;
}
}
/* result has variable length */
if (size == 0)
size = len + 1;
else
/* result has variable length with maximum size */
if (size < 0)
size = MIN(len, -size) + 1;
result = (char *) palloc(hdrsize + size);
memset(result, 0, hdrsize + size);
if (rtn_size)
*rtn_size = size;
r = result + hdrsize;
for (p = str; *p;)
{
register unsigned char c;
if ((c = *p++) == '\\')
{
switch (c = *p++)
{
case '\0':
p--;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c = VALUE(c);
if (isdigit(*p))
c = (c << 3) + VALUE(*p++);
if (isdigit(*p))
c = (c << 3) + VALUE(*p++);
*r++ = c;
break;
case 'b':
*r++ = '\b';
break;
case 'f':
*r++ = '\f';
break;
case 'n':
*r++ = '\n';
break;
case 'r':
*r++ = '\r';
break;
case 't':
*r++ = '\t';
break;
case 'v':
*r++ = '\v';
break;
default:
*r++ = c;
}
}
else
*r++ = c;
}
return ((char *) result);
}
unsigned char *
c_charout(int32 c)
{
char str[2];
str[0] = (char) c;
str[1] = '\0';
return (string_output(str, 1));
}
/*
* This can be used for SET, bytea, text and unknown data types
*/
unsigned char *
c_textout(struct varlena * vlena)
{
int len = 0;
char *s = NULL;
if (vlena)
{
len = VARSIZE(vlena) - VARHDRSZ;
s = VARDATA(vlena);
}
return (string_output(s, len));
}
/*
* This can be used for varchar and bpchar strings
*/
unsigned char *
c_varcharout(unsigned char *s)
{
int len = 0;
if (s)
{
len = *(int32 *) s - 4;
s += 4;
}
return (string_output(s, len));
}
#if 0
struct varlena *
c_textin(unsigned char *str)
{
struct varlena *result;
int len;
if (str == NULL)
return ((struct varlena *) NULL);
result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
VARSIZE(result) = len;
return (result);
}
int32 *
c_charin(unsigned char *str)
{
return (string_input(str, 1, 0, NULL));
}
#endif
/* end of file */
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/