]> granicus.if.org Git - postgresql/blob - src/backend/nodes/read.c
Postgres95 1.01 Distribution - Virgin Sources
[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.1.1.1 1996/07/09 06:21:33 scrappy 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     (void) 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;
68     
69     /*
70      * Check if the token is a number (decimal or integer,
71      * positive or negative
72      */
73     if (isdigit(*token) ||
74         (length>=2 && *token=='-' && isdigit(*(token+1)) ))
75         {
76             /*
77              * skip the optional '-' (i.e. negative number)
78              */
79             if (*token == '-') {
80                 token++;
81             }
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))
96         retval = ATOM_TOKEN;
97     else if (*token == '(')
98         retval = LEFT_PAREN;
99     else if (*token == ')')
100         retval = RIGHT_PAREN;
101     else if (*token == '@')
102         retval = AT_SYMBOL;
103     else if (*token == '\"')
104         retval = T_String;
105     else if (*token == '{')
106         retval = PLAN_SYM;
107     return(retval);
108 }
109
110 /*
111  * Works kinda like strtok, except it doesn't put nulls into string.
112  * 
113  * Returns the length in length instead.  The string can be set without
114  * returning a token by calling lsptok with length == NULL.
115  *
116  */
117 char *
118 lsptok(char *string, int *length)
119 {
120     static char *local_str;
121     char *ret_string;
122     
123     if (string != NULL) {
124         local_str = string;
125         if (length == NULL) {
126             return(NULL);
127         }
128     }
129     
130     for (; *local_str == ' '
131          || *local_str == '\n'
132          || *local_str == '\t'; local_str++);
133     
134     /*
135      * Now pointing at next token.
136      */
137     ret_string = local_str;
138     if (*local_str == '\0') return(NULL);
139     *length = 1;
140     
141     if (*local_str == '\"') {
142         for (local_str++; *local_str != '\"'; (*length)++, local_str++);
143         (*length)++; local_str++;
144     }else if (*local_str == ')' || *local_str == '(' ||
145               *local_str == '}' || *local_str == '{') {
146         local_str++;
147     }else {
148         for (; *local_str != ' '
149              && *local_str != '\n'
150              && *local_str != '\t'
151              && *local_str != '{'
152              && *local_str != '}'
153              && *local_str != '('
154              && *local_str != ')'; local_str++, (*length)++);
155         (*length)--;
156     }
157     return(ret_string);
158 }
159
160 /*
161  * This guy does all the reading.
162  *
163  * Secrets:  He assumes that lsptok already has the string (see below).
164  * Any callers should set read_car_only to true.
165  */
166 void *
167 nodeRead(bool read_car_only)
168 {
169     char *token;
170     NodeTag type;
171     Node *this_value, *return_value;
172     int tok_len;
173     char tmp;
174     bool make_dotted_pair_cell = false;
175     
176     token = lsptok(NULL, &tok_len);
177     
178     if (token == NULL) return(NULL);
179     
180     type = nodeTokenType(token, tok_len);
181     
182     switch(type) {
183     case PLAN_SYM:
184         this_value = parsePlanString();
185         token = lsptok(NULL, &tok_len);
186         if (token[0] != '}') return(NULL);
187
188         if (!read_car_only)
189             make_dotted_pair_cell = true;
190         else
191             make_dotted_pair_cell = false;
192         break;
193     case LEFT_PAREN:
194         if (!read_car_only) {
195             List *l = makeNode(List);
196
197             lfirst(l) = nodeRead(false);
198             lnext(l) = nodeRead(false);
199             this_value = (Node*)l;
200         }else {
201             this_value = nodeRead(false);
202         }
203         break;
204     case RIGHT_PAREN:
205         this_value = NULL;
206         break;
207     case AT_SYMBOL:
208         break;
209     case ATOM_TOKEN:
210         if (!strncmp(token, "nil", 3)) {
211             this_value = NULL;
212             /*
213              * It might be "nil" but it is an atom!
214              */
215             if (read_car_only) {
216                 make_dotted_pair_cell = false;
217             } else {
218                 make_dotted_pair_cell = true;
219             }
220         }else {
221             tmp = token[tok_len];
222             token[tok_len] = '\0';
223             this_value = (Node*)pstrdup(token); /* !attention! not a Node.
224                                                    use with caution */
225             token[tok_len] = tmp;
226             make_dotted_pair_cell = true;
227         }
228         break;
229     case T_Float:
230         tmp = token[tok_len];
231         token[tok_len] = '\0';
232         this_value = (Node*)makeFloat(atof(token));
233         token[tok_len] = tmp;
234         make_dotted_pair_cell = true;
235         break;
236     case T_Integer:
237         tmp = token[tok_len];
238         token[tok_len] = '\0';
239         this_value = (Node*)makeInteger(atoi(token));
240         token[tok_len] = tmp;
241         make_dotted_pair_cell = true;
242         break;
243     case T_String:
244         tmp = token[tok_len - 1];
245         token[tok_len - 1] = '\0';
246         token++;
247         this_value = (Node*)makeString(token);          /* !! not strdup'd */
248         token[tok_len - 2] = tmp;
249         make_dotted_pair_cell = true;
250         break;
251     default:
252         elog(WARN, "nodeRead: Bad type %d", type);
253         break;
254     }
255     if (make_dotted_pair_cell) {
256         List *l = makeNode(List);
257
258         lfirst(l) = this_value;
259         if (!read_car_only) {
260             lnext(l) = nodeRead(false);
261         }else {
262             lnext(l) = NULL;
263         }
264         return_value = (Node*)l;
265     }else {
266         return_value = this_value;
267     }
268     return(return_value);
269 }
270