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

Generated by: LCOV version 2.3.2-1