LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - ecpg.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 111 255 43.5 %
Date: 2023-12-05 09:10:49 Functions: 2 4 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* src/interfaces/ecpg/preproc/ecpg.c */
       2             : 
       3             : /* Main for ecpg, the PostgreSQL embedded SQL precompiler. */
       4             : /* Copyright (c) 1996-2023, PostgreSQL Global Development Group */
       5             : 
       6             : #include "postgres_fe.h"
       7             : 
       8             : #include <unistd.h>
       9             : 
      10             : #include "getopt_long.h"
      11             : 
      12             : #include "preproc_extern.h"
      13             : 
      14             : int         ret_value = 0;
      15             : bool        autocommit = false,
      16             :             auto_create_c = false,
      17             :             system_includes = false,
      18             :             force_indicator = true,
      19             :             questionmarks = false,
      20             :             regression_mode = false,
      21             :             auto_prepare = false;
      22             : 
      23             : char       *output_filename;
      24             : 
      25             : enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL;
      26             : 
      27             : struct _include_path *include_paths = NULL;
      28             : struct cursor *cur = NULL;
      29             : struct typedefs *types = NULL;
      30             : struct _defines *defines = NULL;
      31             : struct declared_list *g_declared_list = NULL;
      32             : 
      33             : static void
      34           0 : help(const char *progname)
      35             : {
      36           0 :     printf(_("%s is the PostgreSQL embedded SQL preprocessor for C programs.\n\n"),
      37             :            progname);
      38           0 :     printf(_("Usage:\n"
      39             :              "  %s [OPTION]... FILE...\n\n"),
      40             :            progname);
      41           0 :     printf(_("Options:\n"));
      42           0 :     printf(_("  -c             automatically generate C code from embedded SQL code;\n"
      43             :              "                 this affects EXEC SQL TYPE\n"));
      44           0 :     printf(_("  -C MODE        set compatibility mode; MODE can be one of\n"
      45             :              "                 \"INFORMIX\", \"INFORMIX_SE\", \"ORACLE\"\n"));
      46             : #ifdef YYDEBUG
      47             :     printf(_("  -d             generate parser debug output\n"));
      48             : #endif
      49           0 :     printf(_("  -D SYMBOL      define SYMBOL\n"));
      50           0 :     printf(_("  -h             parse a header file, this option includes option \"-c\"\n"));
      51           0 :     printf(_("  -i             parse system include files as well\n"));
      52           0 :     printf(_("  -I DIRECTORY   search DIRECTORY for include files\n"));
      53           0 :     printf(_("  -o OUTFILE     write result to OUTFILE\n"));
      54           0 :     printf(_("  -r OPTION      specify run-time behavior; OPTION can be:\n"
      55             :              "                 \"no_indicator\", \"prepare\", \"questionmarks\"\n"));
      56           0 :     printf(_("  --regression   run in regression testing mode\n"));
      57           0 :     printf(_("  -t             turn on autocommit of transactions\n"));
      58           0 :     printf(_("  -V, --version  output version information, then exit\n"));
      59           0 :     printf(_("  -?, --help     show this help, then exit\n"));
      60           0 :     printf(_("\nIf no output file is specified, the name is formed by adding .c to the\n"
      61             :              "input file name, after stripping off .pgc if present.\n"));
      62           0 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
      63           0 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
      64           0 : }
      65             : 
      66             : static void
      67         786 : add_include_path(char *path)
      68             : {
      69         786 :     struct _include_path *ip = include_paths,
      70             :                *new;
      71             : 
      72         786 :     new = mm_alloc(sizeof(struct _include_path));
      73         786 :     new->path = path;
      74         786 :     new->next = NULL;
      75             : 
      76         786 :     if (ip == NULL)
      77         128 :         include_paths = new;
      78             :     else
      79             :     {
      80        2028 :         for (; ip->next != NULL; ip = ip->next);
      81         658 :         ip->next = new;
      82             :     }
      83         786 : }
      84             : 
      85             : static void
      86           0 : add_preprocessor_define(char *define)
      87             : {
      88           0 :     struct _defines *pd = defines;
      89             :     char       *ptr,
      90           0 :                *define_copy = mm_strdup(define);
      91             : 
      92           0 :     defines = mm_alloc(sizeof(struct _defines));
      93             : 
      94             :     /* look for = sign */
      95           0 :     ptr = strchr(define_copy, '=');
      96           0 :     if (ptr != NULL)
      97             :     {
      98             :         char       *tmp;
      99             : 
     100             :         /* symbol has a value */
     101           0 :         for (tmp = ptr - 1; *tmp == ' '; tmp--);
     102           0 :         tmp[1] = '\0';
     103           0 :         defines->olddef = define_copy;
     104           0 :         defines->newdef = ptr + 1;
     105             :     }
     106             :     else
     107             :     {
     108           0 :         defines->olddef = define_copy;
     109           0 :         defines->newdef = mm_strdup("1");
     110             :     }
     111           0 :     defines->pertinent = true;
     112           0 :     defines->used = NULL;
     113           0 :     defines->next = pd;
     114           0 : }
     115             : 
     116             : #define ECPG_GETOPT_LONG_REGRESSION     1
     117             : int
     118         128 : main(int argc, char *const argv[])
     119             : {
     120             :     static struct option ecpg_options[] = {
     121             :         {"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION},
     122             :         {NULL, 0, NULL, 0}
     123             :     };
     124             : 
     125             :     int         fnr,
     126             :                 c,
     127         128 :                 out_option = 0;
     128         128 :     bool        verbose = false,
     129         128 :                 header_mode = false;
     130             :     struct _include_path *ip;
     131             :     const char *progname;
     132             :     char        my_exec_path[MAXPGPATH];
     133             :     char        include_path[MAXPGPATH];
     134             : 
     135         128 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("ecpg"));
     136             : 
     137         128 :     progname = get_progname(argv[0]);
     138             : 
     139         128 :     if (find_my_exec(argv[0], my_exec_path) < 0)
     140             :     {
     141           0 :         fprintf(stderr, _("%s: could not locate my own executable path\n"), argv[0]);
     142           0 :         return ILLEGAL_OPTION;
     143             :     }
     144             : 
     145         128 :     if (argc > 1)
     146             :     {
     147         128 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     148             :         {
     149           0 :             help(progname);
     150           0 :             exit(0);
     151             :         }
     152         128 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     153             :         {
     154           0 :             printf("ecpg (PostgreSQL) %s\n", PG_VERSION);
     155           0 :             exit(0);
     156             :         }
     157             :     }
     158             : 
     159         128 :     output_filename = NULL;
     160         672 :     while ((c = getopt_long(argc, argv, "cC:dD:hiI:o:r:tv", ecpg_options, NULL)) != -1)
     161             :     {
     162         544 :         switch (c)
     163             :         {
     164           4 :             case 'c':
     165           4 :                 auto_create_c = true;
     166           4 :                 break;
     167          20 :             case 'C':
     168          20 :                 if (pg_strcasecmp(optarg, "INFORMIX") == 0 || pg_strcasecmp(optarg, "INFORMIX_SE") == 0)
     169          18 :                 {
     170             :                     char        pkginclude_path[MAXPGPATH];
     171             :                     char        informix_path[MAXPGPATH];
     172             : 
     173          18 :                     compat = (pg_strcasecmp(optarg, "INFORMIX") == 0) ? ECPG_COMPAT_INFORMIX : ECPG_COMPAT_INFORMIX_SE;
     174          18 :                     get_pkginclude_path(my_exec_path, pkginclude_path);
     175          18 :                     snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
     176          18 :                     add_include_path(informix_path);
     177             :                 }
     178           2 :                 else if (pg_strcasecmp(optarg, "ORACLE") == 0)
     179             :                 {
     180           2 :                     compat = ECPG_COMPAT_ORACLE;
     181             :                 }
     182             :                 else
     183             :                 {
     184           0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     185           0 :                     return ILLEGAL_OPTION;
     186             :                 }
     187          20 :                 break;
     188           0 :             case 'd':
     189             : #ifdef YYDEBUG
     190             :                 base_yydebug = 1;
     191             : #else
     192           0 :                 fprintf(stderr, _("%s: parser debug support (-d) not available\n"),
     193             :                         progname);
     194             : #endif
     195           0 :                 break;
     196           0 :             case 'D':
     197           0 :                 add_preprocessor_define(optarg);
     198           0 :                 break;
     199           0 :             case 'h':
     200           0 :                 header_mode = true;
     201             :                 /* this must include "-c" to make sense: */
     202           0 :                 auto_create_c = true;
     203           0 :                 break;
     204           2 :             case 'i':
     205           2 :                 system_includes = true;
     206           2 :                 break;
     207         256 :             case 'I':
     208         256 :                 add_include_path(optarg);
     209         256 :                 break;
     210         128 :             case 'o':
     211         128 :                 output_filename = mm_strdup(optarg);
     212         128 :                 if (strcmp(output_filename, "-") == 0)
     213           0 :                     base_yyout = stdout;
     214             :                 else
     215         128 :                     base_yyout = fopen(output_filename, PG_BINARY_W);
     216             : 
     217         128 :                 if (base_yyout == NULL)
     218             :                 {
     219           0 :                     fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     220           0 :                             progname, output_filename, strerror(errno));
     221           0 :                     output_filename = NULL;
     222             :                 }
     223             :                 else
     224         128 :                     out_option = 1;
     225         128 :                 break;
     226           6 :             case 'r':
     227           6 :                 if (pg_strcasecmp(optarg, "no_indicator") == 0)
     228           2 :                     force_indicator = false;
     229           4 :                 else if (pg_strcasecmp(optarg, "prepare") == 0)
     230           2 :                     auto_prepare = true;
     231           2 :                 else if (pg_strcasecmp(optarg, "questionmarks") == 0)
     232           2 :                     questionmarks = true;
     233             :                 else
     234             :                 {
     235           0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     236           0 :                     return ILLEGAL_OPTION;
     237             :                 }
     238           6 :                 break;
     239           0 :             case 't':
     240           0 :                 autocommit = true;
     241           0 :                 break;
     242           0 :             case 'v':
     243           0 :                 verbose = true;
     244           0 :                 break;
     245         128 :             case ECPG_GETOPT_LONG_REGRESSION:
     246         128 :                 regression_mode = true;
     247         128 :                 break;
     248           0 :             default:
     249           0 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     250           0 :                 return ILLEGAL_OPTION;
     251             :         }
     252             :     }
     253             : 
     254         128 :     add_include_path(".");
     255         128 :     add_include_path("/usr/local/include");
     256         128 :     get_include_path(my_exec_path, include_path);
     257         128 :     add_include_path(include_path);
     258         128 :     add_include_path("/usr/include");
     259             : 
     260         128 :     if (verbose)
     261             :     {
     262           0 :         fprintf(stderr,
     263           0 :                 _("%s, the PostgreSQL embedded C preprocessor, version %s\n"),
     264             :                 progname, PG_VERSION);
     265           0 :         fprintf(stderr, _("EXEC SQL INCLUDE ... search starts here:\n"));
     266           0 :         for (ip = include_paths; ip != NULL; ip = ip->next)
     267           0 :             fprintf(stderr, " %s\n", ip->path);
     268           0 :         fprintf(stderr, _("end of search list\n"));
     269           0 :         return 0;
     270             :     }
     271             : 
     272         128 :     if (optind >= argc)          /* no files specified */
     273             :     {
     274           0 :         fprintf(stderr, _("%s: no input files specified\n"), progname);
     275           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     276           0 :         return ILLEGAL_OPTION;
     277             :     }
     278             :     else
     279             :     {
     280             :         /* after the options there must not be anything but filenames */
     281         256 :         for (fnr = optind; fnr < argc; fnr++)
     282             :         {
     283             :             char       *ptr2ext;
     284             : 
     285             :             /* If argv[fnr] is "-" we have to read from stdin */
     286         128 :             if (strcmp(argv[fnr], "-") == 0)
     287             :             {
     288           0 :                 input_filename = mm_alloc(strlen("stdin") + 1);
     289           0 :                 strcpy(input_filename, "stdin");
     290           0 :                 base_yyin = stdin;
     291             :             }
     292             :             else
     293             :             {
     294         128 :                 input_filename = mm_alloc(strlen(argv[fnr]) + 5);
     295         128 :                 strcpy(input_filename, argv[fnr]);
     296             : 
     297             :                 /* take care of relative paths */
     298         128 :                 ptr2ext = last_dir_separator(input_filename);
     299         128 :                 ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
     300             : 
     301             :                 /* no extension? */
     302         128 :                 if (ptr2ext == NULL)
     303             :                 {
     304           0 :                     ptr2ext = input_filename + strlen(input_filename);
     305             : 
     306             :                     /* no extension => add .pgc or .pgh */
     307           0 :                     ptr2ext[0] = '.';
     308           0 :                     ptr2ext[1] = 'p';
     309           0 :                     ptr2ext[2] = 'g';
     310           0 :                     ptr2ext[3] = (header_mode == true) ? 'h' : 'c';
     311           0 :                     ptr2ext[4] = '\0';
     312             :                 }
     313             : 
     314         128 :                 base_yyin = fopen(input_filename, PG_BINARY_R);
     315             :             }
     316             : 
     317         128 :             if (out_option == 0)    /* calculate the output name */
     318             :             {
     319           0 :                 if (strcmp(input_filename, "stdin") == 0)
     320           0 :                     base_yyout = stdout;
     321             :                 else
     322             :                 {
     323           0 :                     output_filename = mm_alloc(strlen(input_filename) + 3);
     324           0 :                     strcpy(output_filename, input_filename);
     325             : 
     326           0 :                     ptr2ext = strrchr(output_filename, '.');
     327             :                     /* make extension = .c resp. .h */
     328           0 :                     ptr2ext[1] = (header_mode == true) ? 'h' : 'c';
     329           0 :                     ptr2ext[2] = '\0';
     330             : 
     331           0 :                     base_yyout = fopen(output_filename, PG_BINARY_W);
     332           0 :                     if (base_yyout == NULL)
     333             :                     {
     334           0 :                         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     335           0 :                                 progname, output_filename, strerror(errno));
     336           0 :                         free(output_filename);
     337           0 :                         output_filename = NULL;
     338           0 :                         free(input_filename);
     339           0 :                         continue;
     340             :                     }
     341             :                 }
     342             :             }
     343             : 
     344         128 :             if (base_yyin == NULL)
     345           0 :                 fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     346           0 :                         progname, argv[fnr], strerror(errno));
     347             :             else
     348             :             {
     349             :                 struct cursor *ptr;
     350             :                 struct _defines *defptr;
     351             :                 struct typedefs *typeptr;
     352             :                 struct declared_list *list;
     353             : 
     354             :                 /* remove old cursor definitions if any are still there */
     355         128 :                 for (ptr = cur; ptr != NULL;)
     356             :                 {
     357           0 :                     struct cursor *this = ptr;
     358             :                     struct arguments *l1,
     359             :                                *l2;
     360             : 
     361           0 :                     free(ptr->command);
     362           0 :                     free(ptr->connection);
     363           0 :                     free(ptr->name);
     364           0 :                     for (l1 = ptr->argsinsert; l1; l1 = l2)
     365             :                     {
     366           0 :                         l2 = l1->next;
     367           0 :                         free(l1);
     368             :                     }
     369           0 :                     for (l1 = ptr->argsresult; l1; l1 = l2)
     370             :                     {
     371           0 :                         l2 = l1->next;
     372           0 :                         free(l1);
     373             :                     }
     374           0 :                     ptr = ptr->next;
     375           0 :                     free(this);
     376             :                 }
     377         128 :                 cur = NULL;
     378             : 
     379             :                 /* remove old declared statements if any are still there */
     380         128 :                 for (list = g_declared_list; list != NULL;)
     381             :                 {
     382           0 :                     struct declared_list *this = list;
     383             : 
     384           0 :                     list = list->next;
     385           0 :                     free(this);
     386             :                 }
     387             : 
     388             :                 /* remove non-pertinent old defines as well */
     389         128 :                 while (defines && !defines->pertinent)
     390             :                 {
     391           0 :                     defptr = defines;
     392           0 :                     defines = defines->next;
     393             : 
     394           0 :                     free(defptr->newdef);
     395           0 :                     free(defptr->olddef);
     396           0 :                     free(defptr);
     397             :                 }
     398             : 
     399         128 :                 for (defptr = defines; defptr != NULL; defptr = defptr->next)
     400             :                 {
     401           0 :                     struct _defines *this = defptr->next;
     402             : 
     403           0 :                     if (this && !this->pertinent)
     404             :                     {
     405           0 :                         defptr->next = this->next;
     406             : 
     407           0 :                         free(this->newdef);
     408           0 :                         free(this->olddef);
     409           0 :                         free(this);
     410             :                     }
     411             :                 }
     412             : 
     413             :                 /* and old typedefs */
     414         128 :                 for (typeptr = types; typeptr != NULL;)
     415             :                 {
     416           0 :                     struct typedefs *this = typeptr;
     417             : 
     418           0 :                     free(typeptr->name);
     419           0 :                     ECPGfree_struct_member(typeptr->struct_member_list);
     420           0 :                     free(typeptr->type);
     421           0 :                     typeptr = typeptr->next;
     422           0 :                     free(this);
     423             :                 }
     424         128 :                 types = NULL;
     425             : 
     426             :                 /* initialize whenever structures */
     427         128 :                 memset(&when_error, 0, sizeof(struct when));
     428         128 :                 memset(&when_nf, 0, sizeof(struct when));
     429         128 :                 memset(&when_warn, 0, sizeof(struct when));
     430             : 
     431             :                 /* and structure member lists */
     432         128 :                 memset(struct_member_list, 0, sizeof(struct_member_list));
     433             : 
     434             :                 /*
     435             :                  * and our variable counter for out of scope cursors'
     436             :                  * variables
     437             :                  */
     438         128 :                 ecpg_internal_var = 0;
     439             : 
     440             :                 /* finally the actual connection */
     441         128 :                 connection = NULL;
     442             : 
     443             :                 /* initialize lex */
     444         128 :                 lex_init();
     445             : 
     446             :                 /* we need several includes */
     447             :                 /* but not if we are in header mode */
     448         128 :                 if (regression_mode)
     449         128 :                     fprintf(base_yyout, "/* Processed by ecpg (regression mode) */\n");
     450             :                 else
     451           0 :                     fprintf(base_yyout, "/* Processed by ecpg (%s) */\n", PG_VERSION);
     452             : 
     453         128 :                 if (header_mode == false)
     454             :                 {
     455         128 :                     fprintf(base_yyout, "/* These include files are added by the preprocessor */\n#include <ecpglib.h>\n#include <ecpgerrno.h>\n#include <sqlca.h>\n");
     456             : 
     457             :                     /* add some compatibility headers */
     458         128 :                     if (INFORMIX_MODE)
     459          18 :                         fprintf(base_yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
     460             : 
     461         128 :                     fprintf(base_yyout, "/* End of automatic include section */\n");
     462             :                 }
     463             : 
     464         128 :                 if (regression_mode)
     465         128 :                     fprintf(base_yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n");
     466             : 
     467         128 :                 output_line_number();
     468             : 
     469             :                 /* and parse the source */
     470         128 :                 base_yyparse();
     471             : 
     472             :                 /*
     473             :                  * Check whether all cursors were indeed opened.  It does not
     474             :                  * really make sense to declare a cursor but not open it.
     475             :                  */
     476         202 :                 for (ptr = cur; ptr != NULL; ptr = ptr->next)
     477          74 :                     if (!(ptr->opened))
     478           0 :                         mmerror(PARSE_ERROR, ET_WARNING, "cursor \"%s\" has been declared but not opened", ptr->name);
     479             : 
     480         128 :                 if (base_yyin != NULL && base_yyin != stdin)
     481         128 :                     fclose(base_yyin);
     482         128 :                 if (out_option == 0 && base_yyout != stdout)
     483           0 :                     fclose(base_yyout);
     484             : 
     485             :                 /*
     486             :                  * If there was an error, delete the output file.
     487             :                  */
     488         128 :                 if (ret_value != 0)
     489             :                 {
     490           0 :                     if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
     491           0 :                         fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
     492             :                 }
     493             :             }
     494             : 
     495         128 :             if (output_filename && out_option == 0)
     496             :             {
     497           0 :                 free(output_filename);
     498           0 :                 output_filename = NULL;
     499             :             }
     500             : 
     501         128 :             free(input_filename);
     502             :         }
     503             :     }
     504         128 :     return ret_value;
     505             : }

Generated by: LCOV version 1.14