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