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

Generated by: LCOV version 1.13