]> granicus.if.org Git - postgresql/blob - src/backend/nodes/read.c
Massive commit to run PGINDENT on all *.c and *.h files.
[postgresql] / src / backend / nodes / read.c
1 /*-------------------------------------------------------------------------
2  *
3  * read.c--
4  *        routines to convert a string (legal ascii representation of node) back
5  *        to nodes
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.4 1997/09/07 04:42:56 momjian Exp $
12  *
13  * HISTORY
14  *        AUTHOR                        DATE                    MAJOR EVENT
15  *        Andrew Yu                     Nov 2, 1994             file creation
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include "postgres.h"
23 #include "nodes/pg_list.h"
24 #include "nodes/readfuncs.h"
25 #include "utils/elog.h"
26
27 /*
28  * stringToNode -
29  *        returns a Node with a given legal ascii representation
30  */
31 void               *
32 stringToNode(char *str)
33 {
34         void               *retval;
35
36         lsptok(str, NULL);                      /* set the string used in lsptok */
37         retval = nodeRead(true);        /* start reading */
38
39         return retval;
40 }
41
42 /*****************************************************************************
43  *
44  * the lisp token parser
45  *
46  *****************************************************************************/
47
48 #define RIGHT_PAREN (1000000 + 1)
49 #define LEFT_PAREN      (1000000 + 2)
50 #define PLAN_SYM        (1000000 + 3)
51 #define AT_SYMBOL       (1000000 + 4)
52 #define ATOM_TOKEN      (1000000 + 5)
53
54 /*
55  * nodeTokenType -
56  *        returns the type of the node token contained in token.
57  *        It returns one of the following valid NodeTags:
58  *              T_Integer, T_Float, T_String
59  *        and some of its own:
60  *              RIGHT_PAREN, LEFT_PAREN, PLAN_SYM, AT_SYMBOL, ATOM_TOKEN
61  *
62  *        Assumption: the ascii representation is legal
63  */
64 static                  NodeTag
65 nodeTokenType(char *token, int length)
66 {
67         NodeTag                 retval = 0;
68
69         /*
70          * Check if the token is a number (decimal or integer, positive or
71          * negative
72          */
73         if (isdigit(*token) ||
74                 (length >= 2 && *token == '-' && isdigit(*(token + 1))))
75         {
76
77                 /*
78                  * skip the optional '-' (i.e. negative number)
79                  */
80                 if (*token == '-')
81                 {
82                         token++;
83                 }
84
85                 /*
86                  * See if there is a decimal point
87                  */
88
89                 for (; length && *token != '.'; token++, length--);
90
91                 /*
92                  * if there isn't, token's an int, otherwise it's a float.
93                  */
94
95                 retval = (*token != '.') ? T_Integer : T_Float;
96         }
97         else if (isalpha(*token))
98                 retval = ATOM_TOKEN;
99         else if (*token == '(')
100                 retval = LEFT_PAREN;
101         else if (*token == ')')
102                 retval = RIGHT_PAREN;
103         else if (*token == '@')
104                 retval = AT_SYMBOL;
105         else if (*token == '\"')
106                 retval = T_String;
107         else if (*token == '{')
108                 retval = PLAN_SYM;
109         return (retval);
110 }
111
112 /*
113  * Works kinda like strtok, except it doesn't put nulls into string.
114  *
115  * Returns the length in length instead.  The string can be set without
116  * returning a token by calling lsptok with length == NULL.
117  *
118  */
119 char               *
120 lsptok(char *string, int *length)
121 {
122         static char    *local_str;
123         char               *ret_string;
124
125         if (string != NULL)
126         {
127                 local_str = string;
128                 if (length == NULL)
129                 {
130                         return (NULL);
131                 }
132         }
133
134         for (; *local_str == ' '
135                  || *local_str == '\n'
136                  || *local_str == '\t'; local_str++);
137
138         /*
139          * Now pointing at next token.
140          */
141         ret_string = local_str;
142         if (*local_str == '\0')
143                 return (NULL);
144         *length = 1;
145
146         if (*local_str == '\"')
147         {
148                 for (local_str++; *local_str != '\"'; (*length)++, local_str++);
149                 (*length)++;
150                 local_str++;
151         }
152         else if (*local_str == ')' || *local_str == '(' ||
153                          *local_str == '}' || *local_str == '{')
154         {
155                 local_str++;
156         }
157         else
158         {
159                 for (; *local_str != ' '
160                          && *local_str != '\n'
161                          && *local_str != '\t'
162                          && *local_str != '{'
163                          && *local_str != '}'
164                          && *local_str != '('
165                          && *local_str != ')'; local_str++, (*length)++);
166                 (*length)--;
167         }
168         return (ret_string);
169 }
170
171 /*
172  * This guy does all the reading.
173  *
174  * Secrets:  He assumes that lsptok already has the string (see below).
175  * Any callers should set read_car_only to true.
176  */
177 void               *
178 nodeRead(bool read_car_only)
179 {
180         char               *token;
181         NodeTag                 type;
182         Node               *this_value = NULL,
183                                    *return_value = NULL;
184         int                             tok_len;
185         char                    tmp;
186         bool                    make_dotted_pair_cell = false;
187
188         token = lsptok(NULL, &tok_len);
189
190         if (token == NULL)
191                 return (NULL);
192
193         type = nodeTokenType(token, tok_len);
194
195         switch (type)
196         {
197         case PLAN_SYM:
198                 this_value = parsePlanString();
199                 token = lsptok(NULL, &tok_len);
200                 if (token[0] != '}')
201                         return (NULL);
202
203                 if (!read_car_only)
204                         make_dotted_pair_cell = true;
205                 else
206                         make_dotted_pair_cell = false;
207                 break;
208         case LEFT_PAREN:
209                 if (!read_car_only)
210                 {
211                         List               *l = makeNode(List);
212
213                         lfirst(l) = nodeRead(false);
214                         lnext(l) = nodeRead(false);
215                         this_value = (Node *) l;
216                 }
217                 else
218                 {
219                         this_value = nodeRead(false);
220                 }
221                 break;
222         case RIGHT_PAREN:
223                 this_value = NULL;
224                 break;
225         case AT_SYMBOL:
226                 break;
227         case ATOM_TOKEN:
228                 if (!strncmp(token, "nil", 3))
229                 {
230                         this_value = NULL;
231
232                         /*
233                          * It might be "nil" but it is an atom!
234                          */
235                         if (read_car_only)
236                         {
237                                 make_dotted_pair_cell = false;
238                         }
239                         else
240                         {
241                                 make_dotted_pair_cell = true;
242                         }
243                 }
244                 else
245                 {
246                         tmp = token[tok_len];
247                         token[tok_len] = '\0';
248                         this_value = (Node *) pstrdup(token);           /* !attention! not a
249                                                                                                                  * Node. use with
250                                                                                                                  * caution */
251                         token[tok_len] = tmp;
252                         make_dotted_pair_cell = true;
253                 }
254                 break;
255         case T_Float:
256                 tmp = token[tok_len];
257                 token[tok_len] = '\0';
258                 this_value = (Node *) makeFloat(atof(token));
259                 token[tok_len] = tmp;
260                 make_dotted_pair_cell = true;
261                 break;
262         case T_Integer:
263                 tmp = token[tok_len];
264                 token[tok_len] = '\0';
265                 this_value = (Node *) makeInteger(atoi(token));
266                 token[tok_len] = tmp;
267                 make_dotted_pair_cell = true;
268                 break;
269         case T_String:
270                 tmp = token[tok_len - 1];
271                 token[tok_len - 1] = '\0';
272                 token++;
273                 this_value = (Node *) makeString(token);                /* !! not strdup'd */
274                 token[tok_len - 2] = tmp;
275                 make_dotted_pair_cell = true;
276                 break;
277         default:
278                 elog(WARN, "nodeRead: Bad type %d", type);
279                 break;
280         }
281         if (make_dotted_pair_cell)
282         {
283                 List               *l = makeNode(List);
284
285                 lfirst(l) = this_value;
286                 if (!read_car_only)
287                 {
288                         lnext(l) = nodeRead(false);
289                 }
290                 else
291                 {
292                         lnext(l) = NULL;
293                 }
294                 return_value = (Node *) l;
295         }
296         else
297         {
298                 return_value = this_value;
299         }
300         return (return_value);
301 }