]> granicus.if.org Git - postgresql/blob - src/backend/nodes/read.c
Cleanup of outnodes.
[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.9 1998/01/07 15:32:31 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) || *token == '_' || 
98                          (token[0] == '<' && token[1] == '>'))
99                 retval = ATOM_TOKEN;
100         else if (*token == '(')
101                 retval = LEFT_PAREN;
102         else if (*token == ')')
103                 retval = RIGHT_PAREN;
104         else if (*token == '@')
105                 retval = AT_SYMBOL;
106         else if (*token == '\"')
107                 retval = T_String;
108         else if (*token == '{')
109                 retval = PLAN_SYM;
110         return (retval);
111 }
112
113 /*
114  * Works kinda like strtok, except it doesn't put nulls into string.
115  *
116  * Returns the length in length instead.  The string can be set without
117  * returning a token by calling lsptok with length == NULL.
118  *
119  */
120 char       *
121 lsptok(char *string, int *length)
122 {
123         static char *local_str;
124         char       *ret_string;
125
126         if (string != NULL)
127         {
128                 local_str = string;
129                 if (length == NULL)
130                 {
131                         return (NULL);
132                 }
133         }
134
135         for (; *local_str == ' '
136                  || *local_str == '\n'
137                  || *local_str == '\t'; local_str++);
138
139         /*
140          * Now pointing at next token.
141          */
142         ret_string = local_str;
143         if (*local_str == '\0')
144                 return (NULL);
145         *length = 1;
146
147         if (*local_str == '"')
148         {
149                 for (local_str++; *local_str != '"'; (*length)++, local_str++)
150                         ;
151                 (*length)++;
152                 local_str++;
153         }
154                         /* NULL */
155         else if (local_str[0] == '<' && local_str[1] == '>' )
156         {
157                 *length = 0;
158                 local_str += 2;
159         }
160         else if (*local_str == ')' || *local_str == '(' ||
161                          *local_str == '}' || *local_str == '{')
162         {
163                 local_str++;
164         }
165         else
166         {
167                 for (; *local_str != ' '
168                          && *local_str != '\n'
169                          && *local_str != '\t'
170                          && *local_str != '{'
171                          && *local_str != '}'
172                          && *local_str != '('
173                          && *local_str != ')'; local_str++, (*length)++);
174                 (*length)--;
175         }
176         return (ret_string);
177 }
178
179 /*
180  * This guy does all the reading.
181  *
182  * Secrets:  He assumes that lsptok already has the string (see below).
183  * Any callers should set read_car_only to true.
184  */
185 void       *
186 nodeRead(bool read_car_only)
187 {
188         char       *token;
189         NodeTag         type;
190         Node       *this_value = NULL,
191                            *return_value = NULL;
192         int                     tok_len;
193         char            tmp;
194         bool            make_dotted_pair_cell = false;
195
196         token = lsptok(NULL, &tok_len);
197
198         if (token == NULL)
199                 return (NULL);
200
201         type = nodeTokenType(token, tok_len);
202
203         switch (type)
204         {
205                 case PLAN_SYM:
206                         this_value = parsePlanString();
207                         token = lsptok(NULL, &tok_len);
208                         if (token[0] != '}')
209                                 return (NULL);
210
211                         if (!read_car_only)
212                                 make_dotted_pair_cell = true;
213                         else
214                                 make_dotted_pair_cell = false;
215                         break;
216                 case LEFT_PAREN:
217                         if (!read_car_only)
218                         {
219                                 List       *l = makeNode(List);
220
221                                 lfirst(l) = nodeRead(false);
222                                 lnext(l) = nodeRead(false);
223                                 this_value = (Node *) l;
224                         }
225                         else
226                         {
227                                 this_value = nodeRead(false);
228                         }
229                         break;
230                 case RIGHT_PAREN:
231                         this_value = NULL;
232                         break;
233                 case AT_SYMBOL:
234                         break;
235                 case ATOM_TOKEN:
236                         if (!strncmp(token, "<>", 2))
237                         {
238                                 this_value = NULL;
239
240                                 /*
241                                  * It might be NULL but it is an atom!
242                                  */
243                                 if (read_car_only)
244                                 {
245                                         make_dotted_pair_cell = false;
246                                 }
247                                 else
248                                 {
249                                         make_dotted_pair_cell = true;
250                                 }
251                         }
252                         else
253                         {
254                                 tmp = token[tok_len];
255                                 token[tok_len] = '\0';
256                                 this_value = (Node *) pstrdup(token);   /* !attention! not a
257                                                                                                                  * Node. use with
258                                                                                                                  * caution */
259                                 token[tok_len] = tmp;
260                                 make_dotted_pair_cell = true;
261                         }
262                         break;
263                 case T_Float:
264                         tmp = token[tok_len];
265                         token[tok_len] = '\0';
266                         this_value = (Node *) makeFloat(atof(token));
267                         token[tok_len] = tmp;
268                         make_dotted_pair_cell = true;
269                         break;
270                 case T_Integer:
271                         tmp = token[tok_len];
272                         token[tok_len] = '\0';
273                         this_value = (Node *) makeInteger(atoi(token));
274                         token[tok_len] = tmp;
275                         make_dotted_pair_cell = true;
276                         break;
277                 case T_String:
278                         tmp = token[tok_len - 1];
279                         token[tok_len - 1] = '\0';
280                         token++;
281                         this_value = (Node *) makeString(token);        /* !! not strdup'd */
282                         token[tok_len - 2] = tmp;
283                         make_dotted_pair_cell = true;
284                         break;
285                 default:
286                         elog(ABORT, "nodeRead: Bad type %d", type);
287                         break;
288         }
289         if (make_dotted_pair_cell)
290         {
291                 List       *l = makeNode(List);
292
293                 lfirst(l) = this_value;
294
295                 if (!read_car_only)
296                 {
297                         lnext(l) = nodeRead(false);
298                 }
299                 else
300                 {
301                         lnext(l) = NULL;
302                 }
303                 return_value = (Node *) l;
304         }
305         else
306         {
307                 return_value = this_value;
308         }
309         return (return_value);
310 }