summaryrefslogtreecommitdiffstats
path: root/src/interfaces/ecpg/preproc/variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/preproc/variable.c')
-rw-r--r--src/interfaces/ecpg/preproc/variable.c625
1 files changed, 625 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c
new file mode 100644
index 0000000..887d479
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/variable.c
@@ -0,0 +1,625 @@
+/* src/interfaces/ecpg/preproc/variable.c */
+
+#include "postgres_fe.h"
+
+#include "preproc_extern.h"
+
+static struct variable *allvariables = NULL;
+
+struct variable *
+new_variable(const char *name, struct ECPGtype *type, int brace_level)
+{
+ struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
+
+ p->name = mm_strdup(name);
+ p->type = type;
+ p->brace_level = brace_level;
+
+ p->next = allvariables;
+ allvariables = p;
+
+ return p;
+}
+
+static struct variable *
+find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level)
+{
+ char *next = strpbrk(++str, ".-["),
+ *end,
+ c = '\0';
+
+ if (next != NULL)
+ {
+ c = *next;
+ *next = '\0';
+ }
+
+ for (; members; members = members->next)
+ {
+ if (strcmp(members->name, str) == 0)
+ {
+ if (next == NULL)
+ {
+ /* found the end */
+ switch (members->type->type)
+ {
+ case ECPGt_array:
+ 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);
+ case ECPGt_struct:
+ case ECPGt_union:
+ return new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level);
+ default:
+ return new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level);
+ }
+ }
+ else
+ {
+ *next = c;
+ if (c == '[')
+ {
+ int count;
+
+ /*
+ * We don't care about what's inside the array braces so
+ * just eat up the character
+ */
+ for (count = 1, end = next + 1; count; end++)
+ {
+ switch (*end)
+ {
+ case '[':
+ count++;
+ break;
+ case ']':
+ count--;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ end = next;
+
+ switch (*end)
+ {
+ case '\0': /* found the end, but this time it has to be
+ * an array element */
+ if (members->type->type != ECPGt_array)
+ mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
+
+ switch (members->type->u.element->type)
+ {
+ case ECPGt_array:
+ 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);
+ case ECPGt_struct:
+ case ECPGt_union:
+ 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);
+ default:
+ return new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level);
+ }
+ break;
+ case '-':
+ if (members->type->type == ECPGt_array)
+ return find_struct_member(name, ++end, members->type->u.element->u.members, brace_level);
+ else
+ return find_struct_member(name, ++end, members->type->u.members, brace_level);
+ break;
+ break;
+ case '.':
+ if (members->type->type == ECPGt_array)
+ return find_struct_member(name, end, members->type->u.element->u.members, brace_level);
+ else
+ return find_struct_member(name, end, members->type->u.members, brace_level);
+ break;
+ default:
+ mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", name);
+ break;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static struct variable *
+find_struct(char *name, char *next, char *end)
+{
+ struct variable *p;
+ char c = *next;
+
+ /* first get the mother structure entry */
+ *next = '\0';
+ p = find_variable(name);
+
+ if (c == '-')
+ {
+ if (p->type->type != ECPGt_array)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", name);
+
+ if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
+
+ /* restore the name, we will need it later */
+ *next = c;
+
+ return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
+ }
+ else
+ {
+ if (next == end)
+ {
+ if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", name);
+
+ /* restore the name, we will need it later */
+ *next = c;
+
+ return find_struct_member(name, end, p->type->u.members, p->brace_level);
+ }
+ else
+ {
+ if (p->type->type != ECPGt_array)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", name);
+
+ if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", name);
+
+ /* restore the name, we will need it later */
+ *next = c;
+
+ return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
+ }
+ }
+}
+
+static struct variable *
+find_simple(char *name)
+{
+ struct variable *p;
+
+ for (p = allvariables; p; p = p->next)
+ {
+ if (strcmp(p->name, name) == 0)
+ return p;
+ }
+
+ return NULL;
+}
+
+/* Note that this function will end the program in case of an unknown */
+/* variable */
+struct variable *
+find_variable(char *name)
+{
+ char *next,
+ *end;
+ struct variable *p;
+ int count;
+
+ next = strpbrk(name, ".[-");
+ if (next)
+ {
+ if (*next == '[')
+ {
+ /*
+ * We don't care about what's inside the array braces so just eat
+ * up the characters
+ */
+ for (count = 1, end = next + 1; count; end++)
+ {
+ switch (*end)
+ {
+ case '[':
+ count++;
+ break;
+ case ']':
+ count--;
+ break;
+ default:
+ break;
+ }
+ }
+ if (*end == '.')
+ p = find_struct(name, next, end);
+ else
+ {
+ char c = *next;
+
+ *next = '\0';
+ p = find_simple(name);
+ if (p == NULL)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
+
+ *next = c;
+ switch (p->type->u.element->type)
+ {
+ case ECPGt_array:
+ 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);
+ case ECPGt_struct:
+ case ECPGt_union:
+ 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);
+ default:
+ 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);
+ }
+ }
+ }
+ else
+ p = find_struct(name, next, next);
+ }
+ else
+ p = find_simple(name);
+
+ if (p == NULL)
+ mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", name);
+
+ return p;
+}
+
+void
+remove_typedefs(int brace_level)
+{
+ struct typedefs *p,
+ *prev;
+
+ for (p = prev = types; p;)
+ {
+ if (p->brace_level >= brace_level)
+ {
+ /* remove it */
+ if (p == types)
+ prev = types = p->next;
+ else
+ prev->next = p->next;
+
+ if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
+ free(p->struct_member_list);
+ free(p->type);
+ free(p->name);
+ free(p);
+ if (prev == types)
+ p = types;
+ else
+ p = prev ? prev->next : NULL;
+ }
+ else
+ {
+ prev = p;
+ p = prev->next;
+ }
+ }
+}
+
+void
+remove_variables(int brace_level)
+{
+ struct variable *p,
+ *prev;
+
+ for (p = prev = allvariables; p;)
+ {
+ if (p->brace_level >= brace_level)
+ {
+ /* is it still referenced by a cursor? */
+ struct cursor *ptr;
+
+ for (ptr = cur; ptr != NULL; ptr = ptr->next)
+ {
+ struct arguments *varptr,
+ *prevvar;
+
+ for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
+ {
+ if (p == varptr->variable)
+ {
+ /* remove from list */
+ if (varptr == ptr->argsinsert)
+ ptr->argsinsert = varptr->next;
+ else
+ prevvar->next = varptr->next;
+ }
+ }
+ for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
+ {
+ if (p == varptr->variable)
+ {
+ /* remove from list */
+ if (varptr == ptr->argsresult)
+ ptr->argsresult = varptr->next;
+ else
+ prevvar->next = varptr->next;
+ }
+ }
+ }
+
+ /* remove it */
+ if (p == allvariables)
+ prev = allvariables = p->next;
+ else
+ prev->next = p->next;
+
+ ECPGfree_type(p->type);
+ free(p->name);
+ free(p);
+ if (prev == allvariables)
+ p = allvariables;
+ else
+ p = prev ? prev->next : NULL;
+ }
+ else
+ {
+ prev = p;
+ p = prev->next;
+ }
+ }
+}
+
+
+/*
+ * Here are the variables that need to be handled on every request.
+ * These are of two kinds: input and output.
+ * I will make two lists for them.
+ */
+
+struct arguments *argsinsert = NULL;
+struct arguments *argsresult = NULL;
+
+void
+reset_variables(void)
+{
+ argsinsert = NULL;
+ argsresult = NULL;
+}
+
+/* Insert a new variable into our request list.
+ * Note: The list is dumped from the end,
+ * so we have to add new entries at the beginning */
+void
+add_variable_to_head(struct arguments **list, struct variable *var, struct variable *ind)
+{
+ struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
+
+ p->variable = var;
+ p->indicator = ind;
+ p->next = *list;
+ *list = p;
+}
+
+/* Append a new variable to our request list. */
+void
+add_variable_to_tail(struct arguments **list, struct variable *var, struct variable *ind)
+{
+ struct arguments *p,
+ *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
+
+ for (p = *list; p && p->next; p = p->next);
+
+ new->variable = var;
+ new->indicator = ind;
+ new->next = NULL;
+
+ if (p)
+ p->next = new;
+ else
+ *list = new;
+}
+
+void
+remove_variable_from_list(struct arguments **list, struct variable *var)
+{
+ struct arguments *p,
+ *prev = NULL;
+ bool found = false;
+
+ for (p = *list; p; p = p->next)
+ {
+ if (p->variable == var)
+ {
+ found = true;
+ break;
+ }
+ prev = p;
+ }
+ if (found)
+ {
+ if (prev)
+ prev->next = p->next;
+ else
+ *list = p->next;
+ }
+}
+
+/* Dump out a list of all the variable on this list.
+ This is a recursive function that works from the end of the list and
+ deletes the list as we go on.
+ */
+void
+dump_variables(struct arguments *list, int mode)
+{
+ char *str_zero;
+
+ if (list == NULL)
+ return;
+
+ str_zero = mm_strdup("0");
+
+ /*
+ * The list is build up from the beginning so lets first dump the end of
+ * the list:
+ */
+
+ dump_variables(list->next, mode);
+
+ /* Then the current element and its indicator */
+ ECPGdump_a_type(base_yyout, list->variable->name, list->variable->type, list->variable->brace_level,
+ list->indicator->name, list->indicator->type, list->indicator->brace_level,
+ NULL, NULL, str_zero, NULL, NULL);
+
+ /* Then release the list element. */
+ if (mode != 0)
+ free(list);
+
+ free(str_zero);
+}
+
+void
+check_indicator(struct ECPGtype *var)
+{
+ /* make sure this is a valid indicator variable */
+ switch (var->type)
+ {
+ struct ECPGstruct_member *p;
+
+ case ECPGt_short:
+ case ECPGt_int:
+ case ECPGt_long:
+ case ECPGt_long_long:
+ case ECPGt_unsigned_short:
+ case ECPGt_unsigned_int:
+ case ECPGt_unsigned_long:
+ case ECPGt_unsigned_long_long:
+ break;
+
+ case ECPGt_struct:
+ case ECPGt_union:
+ for (p = var->u.members; p; p = p->next)
+ check_indicator(p->type);
+ break;
+
+ case ECPGt_array:
+ check_indicator(var->u.element);
+ break;
+ default:
+ mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
+ break;
+ }
+}
+
+struct typedefs *
+get_typedef(char *name)
+{
+ struct typedefs *this;
+
+ for (this = types; this && strcmp(this->name, name) != 0; this = this->next);
+ if (!this)
+ mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", name);
+
+ return this;
+}
+
+void
+adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
+{
+ if (atoi(type_index) >= 0)
+ {
+ if (atoi(*length) >= 0)
+ mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
+
+ *length = type_index;
+ }
+
+ if (atoi(type_dimension) >= 0)
+ {
+ if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
+ mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
+
+ if (atoi(*dimension) >= 0)
+ *length = *dimension;
+
+ *dimension = type_dimension;
+ }
+
+ if (pointer_len > 2)
+ mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
+ "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
+ pointer_len);
+
+ if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
+ mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");
+
+ if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
+ mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
+
+ if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
+ mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");
+
+ switch (type_enum)
+ {
+ case ECPGt_struct:
+ case ECPGt_union:
+ /* pointer has to get dimension 0 */
+ if (pointer_len)
+ {
+ *length = *dimension;
+ *dimension = mm_strdup("0");
+ }
+
+ if (atoi(*length) >= 0)
+ mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");
+
+ break;
+ case ECPGt_varchar:
+ case ECPGt_bytea:
+ /* pointer has to get dimension 0 */
+ if (pointer_len)
+ *dimension = mm_strdup("0");
+
+ /* one index is the string length */
+ if (atoi(*length) < 0)
+ {
+ *length = *dimension;
+ *dimension = mm_strdup("-1");
+ }
+
+ break;
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ case ECPGt_string:
+ /* char ** */
+ if (pointer_len == 2)
+ {
+ *length = *dimension = mm_strdup("0");
+ break;
+ }
+
+ /* pointer has to get length 0 */
+ if (pointer_len == 1)
+ *length = mm_strdup("0");
+
+ /* one index is the string length */
+ if (atoi(*length) < 0)
+ {
+ /*
+ * make sure we return length = -1 for arrays without given
+ * bounds
+ */
+ if (atoi(*dimension) < 0 && !type_definition)
+
+ /*
+ * do not change this for typedefs since it will be
+ * changed later on when the variable is defined
+ */
+ *length = mm_strdup("1");
+ else if (strcmp(*dimension, "0") == 0)
+ *length = mm_strdup("-1");
+ else
+ *length = *dimension;
+
+ *dimension = mm_strdup("-1");
+ }
+ break;
+ default:
+ /* a pointer has dimension = 0 */
+ if (pointer_len)
+ {
+ *length = *dimension;
+ *dimension = mm_strdup("0");
+ }
+
+ if (atoi(*length) >= 0)
+ mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");
+
+ break;
+ }
+}