1/* src/interfaces/ecpg/preproc/variable.c */
2
3#include "postgres_fe.h"
4
5#include "preproc_extern.h"
6
7static struct variable *allvariables = NULL;
8
9struct variable *
10new_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
24static struct variable *
25find_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
126static struct variable *
127find_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
177static struct variable *
178find_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 */
193struct variable *
194find_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
260void
261remove_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
294void
295remove_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
365struct arguments *argsinsert = NULL;
366struct arguments *argsresult = NULL;
367
368void
369reset_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 */
378void
379add_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. */
390void
391add_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
408void
409remove_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 */
437void
438dump_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
466void
467check_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
499struct typedefs *
500get_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
511void
512adjust_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