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