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

Generated by: LCOV version 1.13