]> granicus.if.org Git - postgresql/blob - contrib/string/string_io.c
I have two small patches which correct some very obscure bug in the parser
[postgresql] / contrib / string / string_io.c
1 /*
2  * string_io.c --
3  *
4  * This file defines new input/output conversion routines for strings.
5  *
6  * Copyright (c) 1996, Massimo Dal Zotto <dz@cs.unitn.it>
7  */
8
9 #include <ctype.h>
10 #include <string.h>
11
12 #include "postgres.h"
13 #include "utils/elog.h"
14 #include "utils/palloc.h"
15 #include "utils/builtins.h"
16
17 /* define this if you want to see iso-8859 characters */
18 #define ISO8859
19
20 #define MIN(x, y)       ((x) < (y) ? (x) : (y))
21 #define VALUE(char)     ((char) - '0')
22 #define DIGIT(val)      ((val) + '0')
23 #define ISOCTAL(c)      (((c) >= '0') && ((c) <= '7'))
24 #ifndef ISO8859
25 #define NOTPRINTABLE(c) (!isprint(c))
26 #else
27 #define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0))
28 #endif
29
30 /*
31  * string_output() --
32  *
33  * This function takes a pointer to a string data and an optional
34  * data size and returns a printable representation of the data
35  * translating all escape sequences to C-like \nnn or \c escapes.
36  * The function is used by output methods of various string types.
37  *
38  * Arguments:
39  *      data -          input data (can be NULL)
40  *      size -          optional size of data. A negative value indicates
41  *                      that data is a null terminated string.
42  *
43  * Returns:
44  *      a pointer to a new string containing the printable
45  *      representation of data.
46  */
47
48 char *
49 string_output(char *data, int size)
50 {
51     register unsigned char c, *p, *r, *result;
52     register int l, len;
53
54     if (data == NULL) {
55         result = (char *) palloc(2);
56         result[0] = '-';
57         result[1] = '\0';
58         return (result);
59     }
60
61     if (size < 0) {
62         size = strlen(data);
63     }
64
65     /* adjust string length for escapes */
66     len = size;
67     for (p=data,l=size; l>0; p++,l--) {
68         switch (*p) {
69           case '\\':
70           case '"' :
71           case '{':
72           case '}':
73           case '\b':
74           case '\f':
75           case '\n':
76           case '\r':
77           case '\t':
78           case '\v':
79             len++;
80             break;
81           default:
82             if (NOTPRINTABLE(*p)) {
83                 len += 3;
84             }
85         }
86     }
87     len++;
88
89     result = (char *) palloc(len);
90
91     for (p=data,r=result,l=size; (l > 0) && (c = *p); p++,l--) {
92         switch (c) {
93           case '\\':
94           case '"' :
95           case '{':
96           case '}':
97             *r++ = '\\';
98             *r++ = c;
99             break;
100           case '\b':
101             *r++ = '\\';
102             *r++ = 'b';
103             break;
104           case '\f':
105             *r++ = '\\';
106             *r++ = 'f';
107             break;
108           case '\n':
109             *r++ = '\\';
110             *r++ = 'n';
111             break;
112           case '\r':
113             *r++ = '\\';
114             *r++ = 'r';
115             break;
116           case '\t':
117             *r++ = '\\';
118             *r++ = 't';
119             break;
120           case '\v':
121             *r++ = '\\';
122             *r++ = 'v';
123             break;
124           default:
125             if (NOTPRINTABLE(c)) {
126                 *r = '\\';
127                 r += 3;
128                 *r-- = DIGIT(c & 07);
129                 c >>= 3;
130                 *r-- = DIGIT(c & 07);
131                 c >>= 3;
132                 *r   = DIGIT(c & 03);
133                 r += 3;
134             } else {
135                 *r++ = c;
136             }
137         }
138     }
139     *r = '\0';
140
141     return((char *) result);
142 }
143
144 /*
145  * string_input() --
146  *
147  * This function accepts a C string in input and copies it into a new 
148  * object allocated with palloc() translating all escape sequences.
149  * An optional header can be allocatd before the string, for example
150  * to hold the length of a varlena object.
151  * This function is not necessary for input from sql commands because
152  * the parser already does escape translation, all data input routines
153  * receive strings in internal form.
154  *
155  * Arguments:
156  *      str -           input string possibly with escapes
157  *      size -          the required size of new data. A value of 0
158  *                      indicates a variable size string, while a
159  *                      negative value indicates a variable size string
160  *                      of size not greater than this absolute value.
161  *      hdrsize -       size of an optional header to be allocated before
162  *                      the data. It must then be filled by the caller.
163  *      rtn_size -      an optional pointer to an int variable where the
164  *                      size of the new string is stored back.
165  *
166  * Returns:
167  *      a pointer to the new string or the header.
168  */
169
170 char *
171 string_input(char *str, int size, int hdrsize, int *rtn_size)
172 {
173     register unsigned char *p, *r;
174     unsigned char *result;
175     int len;
176
177     if ((str == NULL) || (hdrsize < 0)) {
178         return (char *) NULL;
179     }
180
181     /* Compute result size */
182     len = strlen(str);
183     for (p=str; *p; ) {
184         if (*p++ == '\\') {
185             if (ISOCTAL(*p)) {
186                 if (ISOCTAL(*(p+1))) {
187                     p++;
188                     len--;
189                 }
190                 if (ISOCTAL(*(p+1))) {
191                     p++;
192                     len--;
193                 }
194             }
195             if (*p) p++;
196             len--;
197         }
198     }
199
200     /* result has variable length */
201     if (size == 0) {
202         size = len+1;
203     } else
204
205     /* result has variable length with maximum size */
206     if (size < 0) {
207         size = MIN(len, - size)+1;
208     }
209
210     result = (char *) palloc(hdrsize+size);
211     memset(result, 0, hdrsize+size);
212     if (rtn_size) {
213         *rtn_size = size;
214     }
215
216     r = result + hdrsize;
217     for (p=str; *p; ) {
218         register unsigned char c;
219         if ((c = *p++) == '\\') {
220             switch (c = *p++) {
221               case '\0':
222                 p--;
223                 break;
224               case '0':
225               case '1':
226               case '2':
227               case '3':
228               case '4':
229               case '5':
230               case '6':
231               case '7':
232                 c = VALUE(c);
233                 if (isdigit(*p)) {
234                     c = (c<<3) + VALUE(*p++);
235                 }
236                 if (isdigit(*p)) {
237                     c = (c<<3) + VALUE(*p++);
238                 }
239                 *r++ = c;
240                 break;
241               case 'b':
242                 *r++ = '\b';
243                 break;
244               case 'f':
245                 *r++ = '\f';
246                 break;
247               case 'n':
248                 *r++ = '\n';
249                 break;
250               case 'r':
251                 *r++ = '\r';
252                 break;
253               case 't':
254                 *r++ = '\t';
255                 break;
256               case 'v':
257                 *r++ = '\v';
258                 break;
259               default:
260                 *r++ = c;
261             }
262         } else {
263             *r++ = c;
264         }
265     }
266
267     return((char *) result);
268 }
269
270 char *
271 c_charout(int32 c)
272 {
273     char str[2];
274
275     str[0] = (char) c;
276     str[1] = '\0';
277
278     return (string_output(str, 1));
279 }
280
281 char *
282 c_char2out(uint16 s)
283 {
284     return (string_output((char *) &s, 2));
285 }
286
287 char *
288 c_char4out(uint32 s)
289 {
290     return (string_output((char *) &s, 4));
291 }
292
293 char *
294 c_char8out(char *s)
295 {
296     return (string_output(s, 8));
297 }
298
299 char *
300 c_char16out(char *s)
301 {
302     return (string_output(s, 16));
303 }
304
305 /*
306  * This can be used for text, bytea, SET and unknown data types
307  */
308
309 char *
310 c_textout(struct varlena *vlena)
311 {
312     int len = 0;
313     char *s = NULL;
314
315     if (vlena) {
316         len = VARSIZE(vlena) - VARHDRSZ;
317         s = VARDATA(vlena);
318     }
319     return (string_output(s, len));
320 }
321
322 /*
323  * This can be used for varchar and bpchar strings
324  */
325
326 char *
327 c_varcharout(char *s)
328 {
329     int len;
330
331     if (s) {
332         len = *(int32*)s - 4;
333         s += 4;
334     }
335     return (string_output(s, len));
336 }
337
338 #ifdef 0
339 struct varlena *
340 c_textin(char *str)
341 {
342     struct varlena *result;
343     int len;
344
345     if (str == NULL) {
346         return ((struct varlena *) NULL);
347     }
348
349     result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
350     VARSIZE(result) = len;
351
352     return (result);
353 }
354
355 char *
356 c_char16in(char *str)
357 {
358     return (string_input(str, 16, 0, NULL));
359 }
360 #endif
361