Header And Logo

PostgreSQL
| The world's most advanced open source database.

variable.c

Go to the documentation of this file.
00001 /* src/interfaces/ecpg/preproc/variable.c */
00002 
00003 #include "postgres_fe.h"
00004 
00005 #include "extern.h"
00006 
00007 static struct variable *allvariables = NULL;
00008 
00009 struct variable *
00010 new_variable(const char *name, struct ECPGtype * type, int brace_level)
00011 {
00012     struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
00013 
00014     p->name = mm_strdup(name);
00015     p->type = type;
00016     p->brace_level = brace_level;
00017 
00018     p->next = allvariables;
00019     allvariables = p;
00020 
00021     return (p);
00022 }
00023 
00024 static struct variable *
00025 find_struct_member(char *name, char *str, struct ECPGstruct_member * members, int brace_level)
00026 {
00027     char       *next = strpbrk(++str, ".-["),
00028                *end,
00029                 c = '\0';
00030 
00031     if (next != NULL)
00032     {
00033         c = *next;
00034         *next = '\0';
00035     }
00036 
00037     for (; members; members = members->next)
00038     {
00039         if (strcmp(members->name, str) == 0)
00040         {
00041             if (next == NULL)
00042             {
00043                 /* found the end */
00044                 switch (members->type->type)
00045                 {
00046                     case ECPGt_array:
00047                         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));
00048                     case ECPGt_struct:
00049                     case ECPGt_union:
00050                         return (new_variable(name, ECPGmake_struct_type(members->type->u.members, members->type->type, members->type->type_name, members->type->struct_sizeof), brace_level));
00051                     default:
00052                         return (new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size, members->type->counter), brace_level));
00053                 }
00054             }
00055             else
00056             {
00057                 *next = c;
00058                 if (c == '[')
00059                 {
00060                     int         count;
00061 
00062                     /*
00063                      * We don't care about what's inside the array braces so
00064                      * just eat up the character
00065                      */
00066                     for (count = 1, end = next + 1; count; end++)
00067                     {
00068                         switch (*end)
00069                         {
00070                             case '[':
00071                                 count++;
00072                                 break;
00073                             case ']':
00074                                 count--;
00075                                 break;
00076                             default:
00077                                 break;
00078                         }
00079                     }
00080                 }
00081                 else
00082                     end = next;
00083 
00084                 switch (*end)
00085                 {
00086                     case '\0':  /* found the end, but this time it has to be
00087                                  * an array element */
00088                         if (members->type->type != ECPGt_array)
00089                             mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable \"%s\"", name);
00090 
00091                         switch (members->type->u.element->type)
00092                         {
00093                             case ECPGt_array:
00094                                 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));
00095                             case ECPGt_struct:
00096                             case ECPGt_union:
00097                                 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));
00098                             default:
00099                                 return (new_variable(name, ECPGmake_simple_type(members->type->u.element->type, members->type->u.element->size, members->type->u.element->counter), brace_level));
00100                         }
00101                         break;
00102                     case '-':
00103                         if (members->type->type == ECPGt_array)
00104                             return (find_struct_member(name, ++end, members->type->u.element->u.members, brace_level));
00105                         else
00106                             return (find_struct_member(name, ++end, members->type->u.members, brace_level));
00107                         break;
00108                         break;
00109                     case '.':
00110                         if (members->type->type == ECPGt_array)
00111                             return (find_struct_member(name, end, members->type->u.element->u.members, brace_level));
00112                         else
00113                             return (find_struct_member(name, end, members->type->u.members, brace_level));
00114                         break;
00115                     default:
00116                         mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable \"%s\"", name);
00117                         break;
00118                 }
00119             }
00120         }
00121     }
00122 
00123     return (NULL);
00124 }
00125 
00126 static struct variable *
00127 find_struct(char *name, char *next, char *end)
00128 {
00129     struct variable *p;
00130     char        c = *next;
00131 
00132     /* first get the mother structure entry */
00133     *next = '\0';
00134     p = find_variable(name);
00135 
00136     if (c == '-')
00137     {
00138         if (p->type->type != ECPGt_array)
00139             mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a pointer", name);
00140 
00141         if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
00142             mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a pointer to a structure or a union", name);
00143 
00144         /* restore the name, we will need it later */
00145         *next = c;
00146 
00147         return find_struct_member(name, ++end, p->type->u.element->u.members, p->brace_level);
00148     }
00149     else
00150     {
00151         if (next == end)
00152         {
00153             if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
00154                 mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is neither a structure nor a union", name);
00155 
00156             /* restore the name, we will need it later */
00157             *next = c;
00158 
00159             return find_struct_member(name, end, p->type->u.members, p->brace_level);
00160         }
00161         else
00162         {
00163             if (p->type->type != ECPGt_array)
00164                 mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not an array", name);
00165 
00166             if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
00167                 mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a pointer to a structure or a union", name);
00168 
00169             /* restore the name, we will need it later */
00170             *next = c;
00171 
00172             return find_struct_member(name, end, p->type->u.element->u.members, p->brace_level);
00173         }
00174     }
00175 }
00176 
00177 static struct variable *
00178 find_simple(char *name)
00179 {
00180     struct variable *p;
00181 
00182     for (p = allvariables; p; p = p->next)
00183     {
00184         if (strcmp(p->name, name) == 0)
00185             return p;
00186     }
00187 
00188     return (NULL);
00189 }
00190 
00191 /* Note that this function will end the program in case of an unknown */
00192 /* variable */
00193 struct variable *
00194 find_variable(char *name)
00195 {
00196     char       *next,
00197                *end;
00198     struct variable *p;
00199     int         count;
00200 
00201     next = strpbrk(name, ".[-");
00202     if (next)
00203     {
00204         if (*next == '[')
00205         {
00206             /*
00207              * We don't care about what's inside the array braces so just eat
00208              * up the characters
00209              */
00210             for (count = 1, end = next + 1; count; end++)
00211             {
00212                 switch (*end)
00213                 {
00214                     case '[':
00215                         count++;
00216                         break;
00217                     case ']':
00218                         count--;
00219                         break;
00220                     default:
00221                         break;
00222                 }
00223             }
00224             if (*end == '.')
00225                 p = find_struct(name, next, end);
00226             else
00227             {
00228                 char        c = *next;
00229 
00230                 *next = '\0';
00231                 p = find_simple(name);
00232                 if (p == NULL)
00233                     mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not declared", name);
00234 
00235                 *next = c;
00236                 switch (p->type->u.element->type)
00237                 {
00238                     case ECPGt_array:
00239                         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));
00240                     case ECPGt_struct:
00241                     case ECPGt_union:
00242                         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));
00243                     default:
00244                         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));
00245                 }
00246             }
00247         }
00248         else
00249             p = find_struct(name, next, next);
00250     }
00251     else
00252         p = find_simple(name);
00253 
00254     if (p == NULL)
00255         mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not declared", name);
00256 
00257     return (p);
00258 }
00259 
00260 void
00261 remove_typedefs(int brace_level)
00262 {
00263     struct typedefs *p,
00264                *prev;
00265 
00266     for (p = prev = types; p;)
00267     {
00268         if (p->brace_level >= brace_level)
00269         {
00270             /* remove it */
00271             if (p == types)
00272                 prev = types = p->next;
00273             else
00274                 prev->next = p->next;
00275 
00276             if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
00277                 free(p->struct_member_list);
00278             free(p->type);
00279             free(p->name);
00280             free(p);
00281             if (prev == types)
00282                 p = types;
00283             else
00284                 p = prev ? prev->next : NULL;
00285         }
00286         else
00287         {
00288             prev = p;
00289             p = prev->next;
00290         }
00291     }
00292 }
00293 
00294 void
00295 remove_variables(int brace_level)
00296 {
00297     struct variable *p,
00298                *prev;
00299 
00300     for (p = prev = allvariables; p;)
00301     {
00302         if (p->brace_level >= brace_level)
00303         {
00304             /* is it still referenced by a cursor? */
00305             struct cursor *ptr;
00306 
00307             for (ptr = cur; ptr != NULL; ptr = ptr->next)
00308             {
00309                 struct arguments *varptr,
00310                            *prevvar;
00311 
00312                 for (varptr = prevvar = ptr->argsinsert; varptr != NULL; varptr = varptr->next)
00313                 {
00314                     if (p == varptr->variable)
00315                     {
00316                         /* remove from list */
00317                         if (varptr == ptr->argsinsert)
00318                             ptr->argsinsert = varptr->next;
00319                         else
00320                             prevvar->next = varptr->next;
00321                     }
00322                 }
00323                 for (varptr = prevvar = ptr->argsresult; varptr != NULL; varptr = varptr->next)
00324                 {
00325                     if (p == varptr->variable)
00326                     {
00327                         /* remove from list */
00328                         if (varptr == ptr->argsresult)
00329                             ptr->argsresult = varptr->next;
00330                         else
00331                             prevvar->next = varptr->next;
00332                     }
00333                 }
00334             }
00335 
00336             /* remove it */
00337             if (p == allvariables)
00338                 prev = allvariables = p->next;
00339             else
00340                 prev->next = p->next;
00341 
00342             ECPGfree_type(p->type);
00343             free(p->name);
00344             free(p);
00345             if (prev == allvariables)
00346                 p = allvariables;
00347             else
00348                 p = prev ? prev->next : NULL;
00349         }
00350         else
00351         {
00352             prev = p;
00353             p = prev->next;
00354         }
00355     }
00356 }
00357 
00358 
00359 /*
00360  * Here are the variables that need to be handled on every request.
00361  * These are of two kinds: input and output.
00362  * I will make two lists for them.
00363  */
00364 
00365 struct arguments *argsinsert = NULL;
00366 struct arguments *argsresult = NULL;
00367 
00368 void
00369 reset_variables(void)
00370 {
00371     argsinsert = NULL;
00372     argsresult = NULL;
00373 }
00374 
00375 /* Insert a new variable into our request list.
00376  * Note: The list is dumped from the end,
00377  * so we have to add new entries at the beginning */
00378 void
00379 add_variable_to_head(struct arguments ** list, struct variable * var, struct variable * ind)
00380 {
00381     struct arguments *p = (struct arguments *) mm_alloc(sizeof(struct arguments));
00382 
00383     p->variable = var;
00384     p->indicator = ind;
00385     p->next = *list;
00386     *list = p;
00387 }
00388 
00389 /* Append a new variable to our request list. */
00390 void
00391 add_variable_to_tail(struct arguments ** list, struct variable * var, struct variable * ind)
00392 {
00393     struct arguments *p,
00394                *new = (struct arguments *) mm_alloc(sizeof(struct arguments));
00395 
00396     for (p = *list; p && p->next; p = p->next);
00397 
00398     new->variable = var;
00399     new->indicator = ind;
00400     new->next = NULL;
00401 
00402     if (p)
00403         p->next = new;
00404     else
00405         *list = new;
00406 }
00407 
00408 void
00409 remove_variable_from_list(struct arguments ** list, struct variable * var)
00410 {
00411     struct arguments *p,
00412                *prev = NULL;
00413     bool        found = false;
00414 
00415     for (p = *list; p; p = p->next)
00416     {
00417         if (p->variable == var)
00418         {
00419             found = true;
00420             break;
00421         }
00422         prev = p;
00423     }
00424     if (found)
00425     {
00426         if (prev)
00427             prev->next = p->next;
00428         else
00429             *list = p->next;
00430     }
00431 }
00432 
00433 /* Dump out a list of all the variable on this list.
00434    This is a recursive function that works from the end of the list and
00435    deletes the list as we go on.
00436  */
00437 void
00438 dump_variables(struct arguments * list, int mode)
00439 {
00440     if (list == NULL)
00441         return;
00442 
00443     /*
00444      * The list is build up from the beginning so lets first dump the end of
00445      * the list:
00446      */
00447 
00448     dump_variables(list->next, mode);
00449 
00450     /* Then the current element and its indicator */
00451     ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->variable->brace_level,
00452                     list->indicator->name, list->indicator->type, list->indicator->brace_level,
00453                     NULL, NULL, mm_strdup("0"), NULL, NULL);
00454 
00455     /* Then release the list element. */
00456     if (mode != 0)
00457         free(list);
00458 }
00459 
00460 void
00461 check_indicator(struct ECPGtype * var)
00462 {
00463     /* make sure this is a valid indicator variable */
00464     switch (var->type)
00465     {
00466             struct ECPGstruct_member *p;
00467 
00468         case ECPGt_short:
00469         case ECPGt_int:
00470         case ECPGt_long:
00471         case ECPGt_long_long:
00472         case ECPGt_unsigned_short:
00473         case ECPGt_unsigned_int:
00474         case ECPGt_unsigned_long:
00475         case ECPGt_unsigned_long_long:
00476             break;
00477 
00478         case ECPGt_struct:
00479         case ECPGt_union:
00480             for (p = var->u.members; p; p = p->next)
00481                 check_indicator(p->type);
00482             break;
00483 
00484         case ECPGt_array:
00485             check_indicator(var->u.element);
00486             break;
00487         default:
00488             mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
00489             break;
00490     }
00491 }
00492 
00493 struct typedefs *
00494 get_typedef(char *name)
00495 {
00496     struct typedefs *this;
00497 
00498     for (this = types; this && strcmp(this->name, name) != 0; this = this->next);
00499     if (!this)
00500         mmerror(PARSE_ERROR, ET_FATAL, "unrecognized data type name \"%s\"", name);
00501 
00502     return (this);
00503 }
00504 
00505 void
00506 adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len, bool type_definition)
00507 {
00508     if (atoi(type_index) >= 0)
00509     {
00510         if (atoi(*length) >= 0)
00511             mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays are not supported");
00512 
00513         *length = type_index;
00514     }
00515 
00516     if (atoi(type_dimension) >= 0)
00517     {
00518         if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
00519             mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays are not supported");
00520 
00521         if (atoi(*dimension) >= 0)
00522             *length = *dimension;
00523 
00524         *dimension = type_dimension;
00525     }
00526 
00527     if (pointer_len > 2)
00528         mmerror(PARSE_ERROR, ET_FATAL, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
00529                                                 "multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
00530                 pointer_len);
00531 
00532     if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
00533         mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
00534 
00535     if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
00536         mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays are not supported");
00537 
00538     if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
00539         mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays are not supported");
00540 
00541     switch (type_enum)
00542     {
00543         case ECPGt_struct:
00544         case ECPGt_union:
00545             /* pointer has to get dimension 0 */
00546             if (pointer_len)
00547             {
00548                 *length = *dimension;
00549                 *dimension = mm_strdup("0");
00550             }
00551 
00552             if (atoi(*length) >= 0)
00553                 mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays for structures are not supported");
00554 
00555             break;
00556         case ECPGt_varchar:
00557             /* pointer has to get dimension 0 */
00558             if (pointer_len)
00559                 *dimension = mm_strdup("0");
00560 
00561             /* one index is the string length */
00562             if (atoi(*length) < 0)
00563             {
00564                 *length = *dimension;
00565                 *dimension = mm_strdup("-1");
00566             }
00567 
00568             break;
00569         case ECPGt_char:
00570         case ECPGt_unsigned_char:
00571         case ECPGt_string:
00572             /* char ** */
00573             if (pointer_len == 2)
00574             {
00575                 *length = *dimension = mm_strdup("0");
00576                 break;
00577             }
00578 
00579             /* pointer has to get length 0 */
00580             if (pointer_len == 1)
00581                 *length = mm_strdup("0");
00582 
00583             /* one index is the string length */
00584             if (atoi(*length) < 0)
00585             {
00586                 /*
00587                  * make sure we return length = -1 for arrays without given
00588                  * bounds
00589                  */
00590                 if (atoi(*dimension) < 0 && !type_definition)
00591 
00592                     /*
00593                      * do not change this for typedefs since it will be
00594                      * changed later on when the variable is defined
00595                      */
00596                     *length = mm_strdup("1");
00597                 else if (strcmp(*dimension, "0") == 0)
00598                     *length = mm_strdup("-1");
00599                 else
00600                     *length = *dimension;
00601 
00602                 *dimension = mm_strdup("-1");
00603             }
00604             break;
00605         default:
00606             /* a pointer has dimension = 0 */
00607             if (pointer_len)
00608             {
00609                 *length = *dimension;
00610                 *dimension = mm_strdup("0");
00611             }
00612 
00613             if (atoi(*length) >= 0)
00614                 mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays for simple data types are not supported");
00615 
00616             break;
00617     }
00618 }