1 /* src/interfaces/ecpg/preproc/variable.c */
2
3 #include "postgres_fe.h"
4
5 #include "extern.h"
6
7 static struct variable *allvariables = NULL;
8
9 struct variable *
new_variable(const char * name,struct ECPGtype * type,int brace_level)10 new_variable(const char *name, struct ECPGtype *type, int brace_level)
11 {
12 struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
13
14 p->name = mm_strdup(name);
15 p->type = type;
16 p->brace_level = brace_level;
17
18 p->next = allvariables;
19 allvariables = p;
20
21 return p;
22 }
23
24 static struct variable *
find_struct_member(char * name,char * str,struct ECPGstruct_member * members,int brace_level)25 find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level)
26 {
27 char *next = strpbrk(++str, ".-["),
28 *end,
29 c = '\0';
30
31 if (next != NULL)
32 {
33 c = *next;
34 *next = '\0';
35 }
36
37 for (; members; members = members->next)
38 {
39 if (strcmp(members->name, str) == 0)
40 {
41 if (next == NULL)
42 {
43 /* found the end */
44 switch (members->type->type)
45 {
46 case ECPGt_array:
47 return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), members->type->size), brace_level);
48 case ECPGt_struct:
49 case ECPGt_union:
50 return new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level);
51 default:
52 return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
53 }
54 }
55 else
56 {
57 *next = c;
58 if (c == '[')
59 {
60 int count;
61
62 /*
63 * We don't care about what's inside the array braces so
64 * just eat up the character
65 */
66 for (count = 1, end = next + 1; count; end++)
67 {
68 switch (*end)
69 {
70 case '[':
71 count++;
72 break;
73 case ']':
74 count--;
75 break;
76 default:
77 break;
78 }
79 }
80 }
81 else
82 end = next;
83
84 switch (*end)
85 {
86 case '\0': /* found the end, but this time it has to be
87 * an array element */
88 if (members->type->type != ECPGt_array)
89 mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
90
91 switch (members->type->u.element->type)
92 {
93 case ECPGt_array:
94 return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type, members->type->u.element->u.element->size, members->type->u.element->u.element->counter), members->type->u.element->size), brace_level);
95 case ECPGt_struct:
96 case ECPGt_union:
97 return new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members, members->type->u.element->type, members->type->u.element->type_name, members->type->u.element->struct_sizeof), brace_level);
98 default:
99 return new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level);
100 }
101 break;
102 case '-':
103 if (members->type->type == ECPGt_array)
104 return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
105 else
106 return find_struct_member(name, ++end, members->type->u.members, brace_level);
107 break;
108 break;
109 case '.':
110 if (members->type->type == ECPGt_array)
111 return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
112 else
113 return find_struct_member(name, end, members->type->u.members, brace_level);
114 break;
115 default:
116 mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
117 break;
118 }
119 }
120 }
121 }
122
123 return NULL;
124 }
125
126 static struct variable *
find_struct(char * name,char * next,char * end)127 find_struct(char *name, char *next, char *end)
128 {
129 struct variable *p;
130 char c = *next;
131
132 /* first get the mother structure entry */
133 *next = '\0';
134 p = find_variable(name);
135
136 if (c == '-')
137 {
138 if (p->type->type != ECPGt_array)
139 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
140
141 if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
142 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
143
144 /* restore the name, we will need it later */
145 *next = c;
146
147 return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
148 }
149 else
150 {
151 if (next == end)
152 {
153 if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
154 mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", name);
155
156 /* restore the name, we will need it later */
157 *next = c;
158
159 return find_struct_member(name, end, p->type->u.members, p->brace_level);
160 }
161 else
162 {
163 if (p->type->type != ECPGt_array)
164 mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", name);
165
166 if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
167 mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
168
169 /* restore the name, we will need it later */
170 *next = c;
171
172 return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
173 }
174 }
175 }
176
177 static struct variable *
find_simple(char * name)178 find_simple(char *name)
179 {
180 struct variable *p;
181
182 for (p = allvariables; p; p = p->next)
183 {
184 if (strcmp(p->name, name) == 0)
185 return p;
186 }
187
188 return NULL;
189 }
190
191 /* Note that this function will end the program in case of an unknown */
192 /* variable */
193 struct variable *
find_variable(char * name)194 find_variable(char *name)
195 {
196 char *next,
197 *end;
198 struct variable *p;
199 int count;
200
201 next = strpbrk(name, ".[-");
202 if (next)
203 {
204 if (*next == '[')
205 {
206 /*
207 * We don't care about what's inside the array braces so just eat
208 * up the characters
209 */
210 for (count = 1, end = next + 1; count; end++)
211 {
212 switch (*end)
213 {
214 case '[':
215 count++;
216 break;
217 case ']':
218 count--;
219 break;
220 default:
221 break;
222 }
223 }
224 if (*end == '.')
225 p = find_struct(name, next, end);
226 else
227 {
228 char c = *next;
229
230 *next = '\0';
231 p = find_simple(name);
232 if (p == NULL)
233 mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
234
235 *next = c;
236 switch (p->type->u.element->type)
237 {
238 case ECPGt_array:
239 return new_variable(name, ECPGmake_array_type(ECPGmake_simple_type(p->type->u.element->u.element->type, p->type->u.element->u.element->size, p->type->u.element->u.element->counter), p->type->u.element->size), p->brace_level);
240 case ECPGt_struct:
241 case ECPGt_union:
242 return new_variable(name, ECPGmake_struct_type(p->type->u.element->u.members, p->type->u.element->type, p->type->u.element->type_name, p->type->u.element->struct_sizeof), p->brace_level);
243 default:
244 return new_variable(name, ECPGmake_simple_type(p->type->u.element->type, p->type->u.element->size, p->type->u.element->counter), p->brace_level);
245 }
246 }
247 }
248 else
249 p = find_struct(name, next, next);
250 }
251 else
252 p = find_simple(name);
253
254 if (p == NULL)
255 mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
256
257 return p;
258 }
259
260 void
remove_typedefs(int brace_level)261 remove_typedefs(int brace_level)
262 {
263 struct typedefs *p,
264 *prev;
265
266 for (p = prev = types; p;)
267 {
268 if (p->brace_level >= brace_level)
269 {
270 /* remove it */
271 if (p == types)
272 prev = types = p->next;
273 else
274 prev->next = p->next;
275
276 if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
277 free(p->struct_member_list);
278 free(p->type);
279 free(p->name);
280 free(p);
281 if (prev == types)
282 p = types;
283 else
284 p = prev ? prev->next : NULL;
285 }
286 else
287 {
288 prev = p;
289 p = prev->next;
290 }
291 }
292 }
293
294 void
remove_variables(int brace_level)295 remove_variables(int brace_level)
296 {
297 struct variable *p,
298 *prev;
299
300 for (p = prev = allvariables; p;)
301 {
302 if (p->brace_level >= brace_level)
303 {
304 /* is it still referenced by a cursor? */
305 struct cursor *ptr;
306
307 for (ptr = cur; ptr != NULL; ptr = ptr->next)
308 {
309 struct arguments *varptr,
310 *prevvar;
311
312 for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
313 {
314 if (p == varptr->variable)
315 {
316 /* remove from list */
317 if (varptr == ptr->argsinsert)
318 ptr->argsinsert = varptr->next;
319 else
320 prevvar->next = varptr->next;
321 }
322 }
323 for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
324 {
325 if (p == varptr->variable)
326 {
327 /* remove from list */
328 if (varptr == ptr->argsresult)
329 ptr->argsresult = varptr->next;
330 else
331 prevvar->next = varptr->next;
332 }
333 }
334 }
335
336 /* remove it */
337 if (p == allvariables)
338 prev = allvariables = p->next;
339 else
340 prev->next = p->next;
341
342 ECPGfree_type(p->type);
343 free(p->name);
344 free(p);
345 if (prev == allvariables)
346 p = allvariables;
347 else
348 p = prev ? prev->next : NULL;
349 }
350 else
351 {
352 prev = p;
353 p = prev->next;
354 }
355 }
356 }
357
358
359 /*
360 * Here are the variables that need to be handled on every request.
361 * These are of two kinds: input and output.
362 * I will make two lists for them.
363 */
364
365 struct arguments *argsinsert = NULL;
366 struct arguments *argsresult = NULL;
367
368 void
reset_variables(void)369 reset_variables(void)
370 {
371 argsinsert = NULL;
372 argsresult = NULL;
373 }
374
375 /* Insert a new variable into our request list.
376 * Note: The list is dumped from the end,
377 * so we have to add new entries at the beginning */
378 void
add_variable_to_head(struct arguments ** list,struct variable * var,struct variable * ind)379 add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
380 {
381 struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
382
383 p->variable = var;
384 p->indicator = ind;
385 p->next = *list;
386 *list = p;
387 }
388
389 /* Append a new variable to our request list. */
390 void
add_variable_to_tail(struct arguments ** list,struct variable * var,struct variable * ind)391 add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
392 {
393 struct arguments *p,
394 *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
395
396 for (p = *list; p && p->next; p = p->next);
397
398 new->variable = var;
399 new->indicator = ind;
400 new->next = NULL;
401
402 if (p)
403 p->next = new;
404 else
405 *list = new;
406 }
407
408 void
remove_variable_from_list(struct arguments ** list,struct variable * var)409 remove_variable_from_list(struct arguments **list, struct variable *var)
410 {
411 struct arguments *p,
412 *prev = NULL;
413 bool found = false;
414
415 for (p = *list; p; p = p->next)
416 {
417 if (p->variable == var)
418 {
419 found = true;
420 break;
421 }
422 prev = p;
423 }
424 if (found)
425 {
426 if (prev)
427 prev->next = p->next;
428 else
429 *list = p->next;
430 }
431 }
432
433 /* Dump out a list of all the variable on this list.
434 This is a recursive function that works from the end of the list and
435 deletes the list as we go on.
436 */
437 void
dump_variables(struct arguments * list,int mode)438 dump_variables(struct arguments *list, int mode)
439 {
440 char *str_zero;
441
442 if (list == NULL)
443 return;
444
445 str_zero = mm_strdup("0");
446
447 /*
448 * The list is build up from the beginning so lets first dump the end of
449 * the list:
450 */
451
452 dump_variables(list->next, mode);
453
454 /* Then the current element and its indicator */
455 ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
456 list->indicator->name, list->indicator->type, list->indicator->brace_level,
457 NULL, NULL, str_zero, NULL, NULL);
458
459 /* Then release the list element. */
460 if (mode != 0)
461 free(list);
462
463 free(str_zero);
464 }
465
466 void
check_indicator(struct ECPGtype * var)467 check_indicator(struct ECPGtype *var)
468 {
469 /* make sure this is a valid indicator variable */
470 switch (var->type)
471 {
472 struct ECPGstruct_member *p;
473
474 case ECPGt_short:
475 case ECPGt_int:
476 case ECPGt_long:
477 case ECPGt_long_long:
478 case ECPGt_unsigned_short:
479 case ECPGt_unsigned_int:
480 case ECPGt_unsigned_long:
481 case ECPGt_unsigned_long_long:
482 break;
483
484 case ECPGt_struct:
485 case ECPGt_union:
486 for (p = var->u.members; p; p = p->next)
487 check_indicator(p->type);
488 break;
489
490 case ECPGt_array:
491 check_indicator(var->u.element);
492 break;
493 default:
494 mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
495 break;
496 }
497 }
498
499 struct typedefs *
get_typedef(char * name)500 get_typedef(char *name)
501 {
502 struct typedefs *this;
503
504 for (this = types; this && strcmp(this->name, name) != 0; this = this->next);
505 if (!this)
506 mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
507
508 return this;
509 }
510
511 void
adjust_array(enum ECPGttype type_enum,char ** dimension,char ** length,char * type_dimension,char * type_index,int pointer_len,bool type_definition)512 adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
513 {
514 if (atoi(type_index) >= 0)
515 {
516 if (atoi(*length) >= 0)
517 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
518
519 *length = type_index;
520 }
521
522 if (atoi(type_dimension) >= 0)
523 {
524 if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
525 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
526
527 if (atoi(*dimension) >= 0)
528 *length = *dimension;
529
530 *dimension = type_dimension;
531 }
532
533 if (pointer_len > 2)
534 mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
535 "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
536 pointer_len);
537
538 if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
539 mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
540
541 if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
542 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
543
544 if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
545 mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
546
547 switch (type_enum)
548 {
549 case ECPGt_struct:
550 case ECPGt_union:
551 /* pointer has to get dimension 0 */
552 if (pointer_len)
553 {
554 *length = *dimension;
555 *dimension = mm_strdup("0");
556 }
557
558 if (atoi(*length) >= 0)
559 mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
560
561 break;
562 case ECPGt_varchar:
563 /* pointer has to get dimension 0 */
564 if (pointer_len)
565 *dimension = mm_strdup("0");
566
567 /* one index is the string length */
568 if (atoi(*length) < 0)
569 {
570 *length = *dimension;
571 *dimension = mm_strdup("-1");
572 }
573
574 break;
575 case ECPGt_char:
576 case ECPGt_unsigned_char:
577 case ECPGt_string:
578 /* char ** */
579 if (pointer_len == 2)
580 {
581 *length = *dimension = mm_strdup("0");
582 break;
583 }
584
585 /* pointer has to get length 0 */
586 if (pointer_len == 1)
587 *length = mm_strdup("0");
588
589 /* one index is the string length */
590 if (atoi(*length) < 0)
591 {
592 /*
593 * make sure we return length = -1 for arrays without given
594 * bounds
595 */
596 if (atoi(*dimension) < 0 && !type_definition)
597
598 /*
599 * do not change this for typedefs since it will be
600 * changed later on when the variable is defined
601 */
602 *length = mm_strdup("1");
603 else if (strcmp(*dimension, "0") == 0)
604 *length = mm_strdup("-1");
605 else
606 *length = *dimension;
607
608 *dimension = mm_strdup("-1");
609 }
610 break;
611 default:
612 /* a pointer has dimension = 0 */
613 if (pointer_len)
614 {
615 *length = *dimension;
616 *dimension = mm_strdup("0");
617 }
618
619 if (atoi(*length) >= 0)
620 mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
621
622 break;
623 }
624 }
625