LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - ecpg.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16devel Lines: 111 253 43.9 %
Date: 2022-08-17 05:10:35 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-2022, 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         774 : add_include_path(char *path)
      68             : {
      69         774 :     struct _include_path *ip = include_paths,
      70             :                *new;
      71             : 
      72         774 :     new = mm_alloc(sizeof(struct _include_path));
      73         774 :     new->path = path;
      74         774 :     new->next = NULL;
      75             : 
      76         774 :     if (ip == NULL)
      77         126 :         include_paths = new;
      78             :     else
      79             :     {
      80        1998 :         for (; ip->next != NULL; ip = ip->next);
      81         648 :         ip->next = new;
      82             :     }
      83         774 : }
      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         126 : 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         126 :                 out_option = 0;
     128         126 :     bool        verbose = false,
     129         126 :                 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         126 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("ecpg"));
     136             : 
     137         126 :     progname = get_progname(argv[0]);
     138             : 
     139         126 :     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         126 :     if (argc > 1)
     146             :     {
     147         126 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     148             :         {
     149           0 :             help(progname);
     150           0 :             exit(0);
     151             :         }
     152         126 :         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         126 :     output_filename = NULL;
     160         662 :     while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h", ecpg_options, NULL)) != -1)
     161             :     {
     162         536 :         switch (c)
     163             :         {
     164         126 :             case ECPG_GETOPT_LONG_REGRESSION:
     165         126 :                 regression_mode = true;
     166         126 :                 break;
     167         126 :             case 'o':
     168         126 :                 output_filename = mm_strdup(optarg);
     169         126 :                 if (strcmp(output_filename, "-") == 0)
     170           0 :                     base_yyout = stdout;
     171             :                 else
     172         126 :                     base_yyout = fopen(output_filename, PG_BINARY_W);
     173             : 
     174         126 :                 if (base_yyout == NULL)
     175             :                 {
     176           0 :                     fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     177           0 :                             progname, output_filename, strerror(errno));
     178           0 :                     output_filename = NULL;
     179             :                 }
     180             :                 else
     181         126 :                     out_option = 1;
     182         126 :                 break;
     183         252 :             case 'I':
     184         252 :                 add_include_path(optarg);
     185         252 :                 break;
     186           0 :             case 't':
     187           0 :                 autocommit = true;
     188           0 :                 break;
     189           0 :             case 'v':
     190           0 :                 verbose = true;
     191           0 :                 break;
     192           0 :             case 'h':
     193           0 :                 header_mode = true;
     194             :                 /* this must include "-c" to make sense, so fall through */
     195             :                 /* FALLTHROUGH */
     196           4 :             case 'c':
     197           4 :                 auto_create_c = true;
     198           4 :                 break;
     199           2 :             case 'i':
     200           2 :                 system_includes = true;
     201           2 :                 break;
     202          20 :             case 'C':
     203          20 :                 if (pg_strcasecmp(optarg, "INFORMIX") == 0 || pg_strcasecmp(optarg, "INFORMIX_SE") == 0)
     204          18 :                 {
     205             :                     char        pkginclude_path[MAXPGPATH];
     206             :                     char        informix_path[MAXPGPATH];
     207             : 
     208          18 :                     compat = (pg_strcasecmp(optarg, "INFORMIX") == 0) ? ECPG_COMPAT_INFORMIX : ECPG_COMPAT_INFORMIX_SE;
     209          18 :                     get_pkginclude_path(my_exec_path, pkginclude_path);
     210          18 :                     snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
     211          18 :                     add_include_path(informix_path);
     212             :                 }
     213           2 :                 else if (pg_strcasecmp(optarg, "ORACLE") == 0)
     214             :                 {
     215           2 :                     compat = ECPG_COMPAT_ORACLE;
     216             :                 }
     217             :                 else
     218             :                 {
     219           0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     220           0 :                     return ILLEGAL_OPTION;
     221             :                 }
     222          20 :                 break;
     223           6 :             case 'r':
     224           6 :                 if (pg_strcasecmp(optarg, "no_indicator") == 0)
     225           2 :                     force_indicator = false;
     226           4 :                 else if (pg_strcasecmp(optarg, "prepare") == 0)
     227           2 :                     auto_prepare = true;
     228           2 :                 else if (pg_strcasecmp(optarg, "questionmarks") == 0)
     229           2 :                     questionmarks = true;
     230             :                 else
     231             :                 {
     232           0 :                     fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     233           0 :                     return ILLEGAL_OPTION;
     234             :                 }
     235           6 :                 break;
     236           0 :             case 'D':
     237           0 :                 add_preprocessor_define(optarg);
     238           0 :                 break;
     239           0 :             case 'd':
     240             : #ifdef YYDEBUG
     241             :                 base_yydebug = 1;
     242             : #else
     243           0 :                 fprintf(stderr, _("%s: parser debug support (-d) not available\n"),
     244             :                         progname);
     245             : #endif
     246           0 :                 break;
     247           0 :             default:
     248           0 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     249           0 :                 return ILLEGAL_OPTION;
     250             :         }
     251             :     }
     252             : 
     253         126 :     add_include_path(".");
     254         126 :     add_include_path("/usr/local/include");
     255         126 :     get_include_path(my_exec_path, include_path);
     256         126 :     add_include_path(include_path);
     257         126 :     add_include_path("/usr/include");
     258             : 
     259         126 :     if (verbose)
     260             :     {
     261           0 :         fprintf(stderr,
     262           0 :                 _("%s, the PostgreSQL embedded C preprocessor, version %s\n"),
     263             :                 progname, PG_VERSION);
     264           0 :         fprintf(stderr, _("EXEC SQL INCLUDE ... search starts here:\n"));
     265           0 :         for (ip = include_paths; ip != NULL; ip = ip->next)
     266           0 :             fprintf(stderr, " %s\n", ip->path);
     267           0 :         fprintf(stderr, _("end of search list\n"));
     268           0 :         return 0;
     269             :     }
     270             : 
     271         126 :     if (optind >= argc)          /* no files specified */
     272             :     {
     273           0 :         fprintf(stderr, _("%s: no input files specified\n"), progname);
     274           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
     275           0 :         return ILLEGAL_OPTION;
     276             :     }
     277             :     else
     278             :     {
     279             :         /* after the options there must not be anything but filenames */
     280         252 :         for (fnr = optind; fnr < argc; fnr++)
     281             :         {
     282             :             char       *ptr2ext;
     283             : 
     284             :             /* If argv[fnr] is "-" we have to read from stdin */
     285         126 :             if (strcmp(argv[fnr], "-") == 0)
     286             :             {
     287           0 :                 input_filename = mm_alloc(strlen("stdin") + 1);
     288           0 :                 strcpy(input_filename, "stdin");
     289           0 :                 base_yyin = stdin;
     290             :             }
     291             :             else
     292             :             {
     293         126 :                 input_filename = mm_alloc(strlen(argv[fnr]) + 5);
     294         126 :                 strcpy(input_filename, argv[fnr]);
     295             : 
     296             :                 /* take care of relative paths */
     297         126 :                 ptr2ext = last_dir_separator(input_filename);
     298         126 :                 ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
     299             : 
     300             :                 /* no extension? */
     301         126 :                 if (ptr2ext == NULL)
     302             :                 {
     303           0 :                     ptr2ext = input_filename + strlen(input_filename);
     304             : 
     305             :                     /* no extension => add .pgc or .pgh */
     306           0 :                     ptr2ext[0] = '.';
     307           0 :                     ptr2ext[1] = 'p';
     308           0 :                     ptr2ext[2] = 'g';
     309           0 :                     ptr2ext[3] = (header_mode == true) ? 'h' : 'c';
     310           0 :                     ptr2ext[4] = '\0';
     311             :                 }
     312             : 
     313         126 :                 base_yyin = fopen(input_filename, PG_BINARY_R);
     314             :             }
     315             : 
     316         126 :             if (out_option == 0)    /* calculate the output name */
     317             :             {
     318           0 :                 if (strcmp(input_filename, "stdin") == 0)
     319           0 :                     base_yyout = stdout;
     320             :                 else
     321             :                 {
     322           0 :                     output_filename = mm_alloc(strlen(input_filename) + 3);
     323           0 :                     strcpy(output_filename, input_filename);
     324             : 
     325           0 :                     ptr2ext = strrchr(output_filename, '.');
     326             :                     /* make extension = .c resp. .h */
     327           0 :                     ptr2ext[1] = (header_mode == true) ? 'h' : 'c';
     328           0 :                     ptr2ext[2] = '\0';
     329             : 
     330           0 :                     base_yyout = fopen(output_filename, PG_BINARY_W);
     331           0 :                     if (base_yyout == NULL)
     332             :                     {
     333           0 :                         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     334           0 :                                 progname, output_filename, strerror(errno));
     335           0 :                         free(output_filename);
     336           0 :                         output_filename = NULL;
     337           0 :                         free(input_filename);
     338           0 :                         continue;
     339             :                     }
     340             :                 }
     341             :             }
     342             : 
     343         126 :             if (base_yyin == NULL)
     344           0 :                 fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
     345           0 :                         progname, argv[fnr], strerror(errno));
     346             :             else
     347             :             {
     348             :                 struct cursor *ptr;
     349             :                 struct _defines *defptr;
     350             :                 struct typedefs *typeptr;
     351             :                 struct declared_list *list;
     352             : 
     353             :                 /* remove old cursor definitions if any are still there */
     354         126 :                 for (ptr = cur; ptr != NULL;)
     355             :                 {
     356           0 :                     struct cursor *this = ptr;
     357             :                     struct arguments *l1,
     358             :                                *l2;
     359             : 
     360           0 :                     free(ptr->command);
     361           0 :                     free(ptr->connection);
     362           0 :                     free(ptr->name);
     363           0 :                     for (l1 = ptr->argsinsert; l1; l1 = l2)
     364             :                     {
     365           0 :                         l2 = l1->next;
     366           0 :                         free(l1);
     367             :                     }
     368           0 :                     for (l1 = ptr->argsresult; l1; l1 = l2)
     369             :                     {
     370           0 :                         l2 = l1->next;
     371           0 :                         free(l1);
     372             :                     }
     373           0 :                     ptr = ptr->next;
     374           0 :                     free(this);
     375             :                 }
     376         126 :                 cur = NULL;
     377             : 
     378             :                 /* remove old declared statements if any are still there */
     379         126 :                 for (list = g_declared_list; list != NULL;)
     380             :                 {
     381           0 :                     struct declared_list *this = list;
     382             : 
     383           0 :                     list = list->next;
     384           0 :                     free(this);
     385             :                 }
     386             : 
     387             :                 /* remove non-pertinent old defines as well */
     388         126 :                 while (defines && !defines->pertinent)
     389             :                 {
     390           0 :                     defptr = defines;
     391           0 :                     defines = defines->next;
     392             : 
     393           0 :                     free(defptr->newdef);
     394           0 :                     free(defptr->olddef);
     395           0 :                     free(defptr);
     396             :                 }
     397             : 
     398         126 :                 for (defptr = defines; defptr != NULL; defptr = defptr->next)
     399             :                 {
     400           0 :                     struct _defines *this = defptr->next;
     401             : 
     402           0 :                     if (this && !this->pertinent)
     403             :                     {
     404           0 :                         defptr->next = this->next;
     405             : 
     406           0 :                         free(this->newdef);
     407           0 :                         free(this->olddef);
     408           0 :                         free(this);
     409             :                     }
     410             :                 }
     411             : 
     412             :                 /* and old typedefs */
     413         126 :                 for (typeptr = types; typeptr != NULL;)
     414             :                 {
     415           0 :                     struct typedefs *this = typeptr;
     416             : 
     417           0 :                     free(typeptr->name);
     418           0 :                     ECPGfree_struct_member(typeptr->struct_member_list);
     419           0 :                     free(typeptr->type);
     420           0 :                     typeptr = typeptr->next;
     421           0 :                     free(this);
     422             :                 }
     423         126 :                 types = NULL;
     424             : 
     425             :                 /* initialize whenever structures */
     426         126 :                 memset(&when_error, 0, sizeof(struct when));
     427         126 :                 memset(&when_nf, 0, sizeof(struct when));
     428         126 :                 memset(&when_warn, 0, sizeof(struct when));
     429             : 
     430             :                 /* and structure member lists */
     431         126 :                 memset(struct_member_list, 0, sizeof(struct_member_list));
     432             : 
     433             :                 /*
     434             :                  * and our variable counter for out of scope cursors'
     435             :                  * variables
     436             :                  */
     437         126 :                 ecpg_internal_var = 0;
     438             : 
     439             :                 /* finally the actual connection */
     440         126 :                 connection = NULL;
     441             : 
     442             :                 /* initialize lex */
     443         126 :                 lex_init();
     444             : 
     445             :                 /* we need several includes */
     446             :                 /* but not if we are in header mode */
     447         126 :                 if (regression_mode)
     448         126 :                     fprintf(base_yyout, "/* Processed by ecpg (regression mode) */\n");
     449             :                 else
     450           0 :                     fprintf(base_yyout, "/* Processed by ecpg (%s) */\n", PG_VERSION);
     451             : 
     452         126 :                 if (header_mode == false)
     453             :                 {
     454         126 :                     fprintf(base_yyout, "/* These include files are added by the preprocessor */\n#include <ecpglib.h>\n#include <ecpgerrno.h>\n#include <sqlca.h>\n");
     455             : 
     456             :                     /* add some compatibility headers */
     457         126 :                     if (INFORMIX_MODE)
     458          18 :                         fprintf(base_yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
     459             : 
     460         126 :                     fprintf(base_yyout, "/* End of automatic include section */\n");
     461             :                 }
     462             : 
     463         126 :                 if (regression_mode)
     464         126 :                     fprintf(base_yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n");
     465             : 
     466         126 :                 output_line_number();
     467             : 
     468             :                 /* and parse the source */
     469         126 :                 base_yyparse();
     470             : 
     471             :                 /*
     472             :                  * Check whether all cursors were indeed opened.  It does not
     473             :                  * really make sense to declare a cursor but not open it.
     474             :                  */
     475         198 :                 for (ptr = cur; ptr != NULL; ptr = ptr->next)
     476          72 :                     if (!(ptr->opened))
     477           0 :                         mmerror(PARSE_ERROR, ET_WARNING, "cursor \"%s\" has been declared but not opened", ptr->name);
     478             : 
     479         126 :                 if (base_yyin != NULL && base_yyin != stdin)
     480         126 :                     fclose(base_yyin);
     481         126 :                 if (out_option == 0 && base_yyout != stdout)
     482           0 :                     fclose(base_yyout);
     483             : 
     484             :                 /*
     485             :                  * If there was an error, delete the output file.
     486             :                  */
     487         126 :                 if (ret_value != 0)
     488             :                 {
     489           0 :                     if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
     490           0 :                         fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
     491             :                 }
     492             :             }
     493             : 
     494         126 :             if (output_filename && out_option == 0)
     495             :             {
     496           0 :                 free(output_filename);
     497           0 :                 output_filename = NULL;
     498             :             }
     499             : 
     500         126 :             free(input_filename);
     501             :         }
     502             :     }
     503         126 :     return ret_value;
     504             : }

Generated by: LCOV version 1.14