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