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 | 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 * |
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 * |
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 * |
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 * |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 * |
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 |
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 | case ECPGt_bytea: |
564 | /* pointer has to get dimension 0 */ |
565 | if (pointer_len) |
566 | *dimension = mm_strdup("0" ); |
567 | |
568 | /* one index is the string length */ |
569 | if (atoi(*length) < 0) |
570 | { |
571 | *length = *dimension; |
572 | *dimension = mm_strdup("-1" ); |
573 | } |
574 | |
575 | break; |
576 | case ECPGt_char: |
577 | case ECPGt_unsigned_char: |
578 | case ECPGt_string: |
579 | /* char ** */ |
580 | if (pointer_len == 2) |
581 | { |
582 | *length = *dimension = mm_strdup("0" ); |
583 | break; |
584 | } |
585 | |
586 | /* pointer has to get length 0 */ |
587 | if (pointer_len == 1) |
588 | *length = mm_strdup("0" ); |
589 | |
590 | /* one index is the string length */ |
591 | if (atoi(*length) < 0) |
592 | { |
593 | /* |
594 | * make sure we return length = -1 for arrays without given |
595 | * bounds |
596 | */ |
597 | if (atoi(*dimension) < 0 && !type_definition) |
598 | |
599 | /* |
600 | * do not change this for typedefs since it will be |
601 | * changed later on when the variable is defined |
602 | */ |
603 | *length = mm_strdup("1" ); |
604 | else if (strcmp(*dimension, "0" ) == 0) |
605 | *length = mm_strdup("-1" ); |
606 | else |
607 | *length = *dimension; |
608 | |
609 | *dimension = mm_strdup("-1" ); |
610 | } |
611 | break; |
612 | default: |
613 | /* a pointer has dimension = 0 */ |
614 | if (pointer_len) |
615 | { |
616 | *length = *dimension; |
617 | *dimension = mm_strdup("0" ); |
618 | } |
619 | |
620 | if (atoi(*length) >= 0) |
621 | mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported" ); |
622 | |
623 | break; |
624 | } |
625 | } |
626 | |