LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/preproc - ecpg.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 103 235 43.8 %
Date: 2019-09-22 08:06:49 Functions: 2 4 50.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13