]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/ecpg.c
5c3245bd8850e7d6dc931d8e8f807e876ce1fd0a
[postgresql] / src / interfaces / ecpg / preproc / ecpg.c
1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.105 2008/05/16 15:20:04 petere Exp $ */
2
3 /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */
4 /* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */
5 /* Placed under the same license as PostgreSQL */
6
7 #include "postgres_fe.h"
8
9 #include <unistd.h>
10 #include <string.h>
11 #include "getopt_long.h"
12
13 #include "extern.h"
14
15 int                     ret_value = 0,
16                         autocommit = false,
17                         auto_create_c = false,
18                         system_includes = false,
19                         force_indicator = true,
20                         questionmarks = false,
21                         regression_mode = false,
22                         auto_prepare = false;
23
24 char       *output_filename;
25
26 enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL;
27
28 struct _include_path *include_paths = NULL;
29 struct cursor *cur = NULL;
30 struct typedefs *types = NULL;
31 struct _defines *defines = NULL;
32
33 static void
34 help(const char *progname)
35 {
36         printf(_("%s is the PostgreSQL embedded SQL preprocessor for C programs.\n\n"),
37                    progname);
38         printf(_("Usage:\n"
39                    "  %s [OPTION]... FILE...\n\n"),
40                    progname);
41         printf(_("Options:\n"));
42         printf(_("  -c             automatically generate C code from embedded SQL code;\n"
43                    "                 currently this works for EXEC SQL TYPE\n"));
44         printf(_("  -C MODE        set compatibility mode;\n"
45           "                 MODE can be one of \"INFORMIX\", \"INFORMIX_SE\"\n"));
46 #ifdef YYDEBUG
47         printf(_("  -d             generate parser debug output\n"));
48 #endif
49         printf(_("  -D SYMBOL      define SYMBOL\n"));
50         printf(_("  -h             parse a header file, this option includes option \"-c\"\n"));
51         printf(_("  -i             parse system include files as well\n"));
52         printf(_("  -I DIRECTORY   search DIRECTORY for include files\n"));
53         printf(_("  -o OUTFILE     write result to OUTFILE\n"));
54         printf(_("  -r OPTION      specify runtime behaviour;\n"
55                    "                 OPTION can be:\n"
56                    "                  \"no_indicator\"\n"
57                    "                  \"prepare\"\n"
58                    "                  \"questionmarks\"\n"));
59         printf(_("  -t             turn on autocommit of transactions\n"));
60         printf(_("  --help         show this help, then exit\n"));
61         printf(_("  --regression   run in regression testing mode\n"));
62         printf(_("  --version      output version information, then exit\n"));
63         printf(_("\nIf no output file is specified, the name is formed by adding .c to the\n"
64                    "input file name, after stripping off .pgc if present.\n"));
65         printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
66 }
67
68 static void
69 add_include_path(char *path)
70 {
71         struct _include_path *ip = include_paths,
72                            *new;
73
74         new = mm_alloc(sizeof(struct _include_path));
75         new->path = path;
76         new->next = NULL;
77
78         if (ip == NULL)
79                 include_paths = new;
80         else
81         {
82                 for (; ip->next != NULL; ip = ip->next);
83                 ip->next = new;
84         }
85 }
86
87 static void
88 add_preprocessor_define(char *define)
89 {
90         struct _defines *pd = defines;
91         char       *ptr,
92                            *define_copy = mm_strdup(define);
93
94         defines = mm_alloc(sizeof(struct _defines));
95
96         /* look for = sign */
97         ptr = strchr(define_copy, '=');
98         if (ptr != NULL)
99         {
100                 char       *tmp;
101
102                 /* symbol has a value */
103                 for (tmp = ptr - 1; *tmp == ' '; tmp--);
104                 tmp[1] = '\0';
105                 defines->old = define_copy;
106                 defines->new = ptr + 1;
107         }
108         else
109         {
110                 defines->old = define_copy;
111                 defines->new = mm_strdup("1");
112         }
113         defines->pertinent = true;
114         defines->used = NULL;
115         defines->next = pd;
116 }
117
118 #define ECPG_GETOPT_LONG_HELP                   1
119 #define ECPG_GETOPT_LONG_VERSION                2
120 #define ECPG_GETOPT_LONG_REGRESSION             3
121 int
122 main(int argc, char *const argv[])
123 {
124         static struct option ecpg_options[] = {
125                 {"help", no_argument, NULL, ECPG_GETOPT_LONG_HELP},
126                 {"version", no_argument, NULL, ECPG_GETOPT_LONG_VERSION},
127                 {"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION},
128                 {NULL, 0, NULL, 0}
129         };
130
131         int                     fnr,
132                                 c,
133                                 verbose = false,
134                                 header_mode = false,
135                                 out_option = 0;
136         struct _include_path *ip;
137         const char *progname;
138         char            my_exec_path[MAXPGPATH];
139         char            include_path[MAXPGPATH];
140
141         set_pglocale_pgservice(argv[0], "ecpg");
142
143         progname = get_progname(argv[0]);
144
145         find_my_exec(argv[0], my_exec_path);
146
147         output_filename = NULL;
148         while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h?", ecpg_options, NULL)) != -1)
149         {
150                 switch (c)
151                 {
152                         case ECPG_GETOPT_LONG_VERSION:
153                                 printf("ecpg (PostgreSQL %s) %d.%d.%d\n", PG_VERSION,
154                                            MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
155                                 exit(0);
156                         case ECPG_GETOPT_LONG_HELP:
157                                 help(progname);
158                                 exit(0);
159
160                                 /*
161                                  * -? is an alternative spelling of --help. However it is also
162                                  * returned by getopt_long for unknown options. We can
163                                  * distinguish both cases by means of the optopt variable
164                                  * which is set to 0 if it was really -? and not an unknown
165                                  * option character.
166                                  */
167                         case '?':
168                                 if (optopt == 0)
169                                 {
170                                         help(progname);
171                                         exit(0);
172                                 }
173                                 break;
174                         case ECPG_GETOPT_LONG_REGRESSION:
175                                 regression_mode = true;
176                                 break;
177                         case 'o':
178                                 output_filename = optarg;
179                                 if (strcmp(output_filename, "-") == 0)
180                                         yyout = stdout;
181                                 else
182                                         yyout = fopen(output_filename, PG_BINARY_W);
183
184                                 if (yyout == NULL)
185                                 {
186                                         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
187                                                         progname, output_filename, strerror(errno));
188                                         output_filename = NULL;
189                                 }
190                                 else
191                                         out_option = 1;
192                                 break;
193                         case 'I':
194                                 add_include_path(optarg);
195                                 break;
196                         case 't':
197                                 autocommit = true;
198                                 break;
199                         case 'v':
200                                 verbose = true;
201                                 break;
202                         case 'h':
203                                 header_mode = true;
204                                 /* this must include "-c" to make sense */
205                                 /* so do not place a "break;" here */
206                         case 'c':
207                                 auto_create_c = true;
208                                 break;
209                         case 'i':
210                                 system_includes = true;
211                                 break;
212                         case 'C':
213                                 if (strncmp(optarg, "INFORMIX", strlen("INFORMIX")) == 0)
214                                 {
215                                         char            pkginclude_path[MAXPGPATH];
216                                         char            informix_path[MAXPGPATH];
217
218                                         compat = (strcmp(optarg, "INFORMIX") == 0) ? ECPG_COMPAT_INFORMIX : ECPG_COMPAT_INFORMIX_SE;
219                                         get_pkginclude_path(my_exec_path, pkginclude_path);
220                                         snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
221                                         add_include_path(informix_path);
222                                 }
223                                 else
224                                 {
225                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
226                                         return ILLEGAL_OPTION;
227                                 }
228                                 break;
229                         case 'r':
230                                 if (strcmp(optarg, "no_indicator") == 0)
231                                         force_indicator = false;
232                                 else if (strcmp(optarg, "prepare") == 0)
233                                         auto_prepare = true;
234                                 else if (strcmp(optarg, "questionmarks") == 0)
235                                         questionmarks = true;
236                                 else
237                                 {
238                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
239                                         return ILLEGAL_OPTION;
240                                 }
241                                 break;
242                         case 'D':
243                                 add_preprocessor_define(optarg);
244                                 break;
245                         case 'd':
246 #ifdef YYDEBUG
247                                 yydebug = 1;
248 #else
249                                 fprintf(stderr, _("%s: parser debug support (-d) not available\n"),
250                                                 progname);
251 #endif
252                                 break;
253                         default:
254                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
255                                 return ILLEGAL_OPTION;
256                 }
257         }
258
259         add_include_path(".");
260         add_include_path("/usr/local/include");
261         get_include_path(my_exec_path, include_path);
262         add_include_path(include_path);
263         add_include_path("/usr/include");
264
265         if (verbose)
266         {
267                 fprintf(stderr, _("%s, the PostgreSQL embedded C preprocessor, version %d.%d.%d\n"),
268                                 progname, MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
269                 fprintf(stderr, _("exec sql include ... search starts here:\n"));
270                 for (ip = include_paths; ip != NULL; ip = ip->next)
271                         fprintf(stderr, " %s\n", ip->path);
272                 fprintf(stderr, _("end of search list\n"));
273                 return 0;
274         }
275
276         if (optind >= argc)                     /* no files specified */
277         {
278                 fprintf(stderr, _("%s: no input files specified\n"), progname);
279                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
280                 return (ILLEGAL_OPTION);
281         }
282         else
283         {
284                 /* after the options there must not be anything but filenames */
285                 for (fnr = optind; fnr < argc; fnr++)
286                 {
287                         char       *ptr2ext;
288
289                         /* If argv[fnr] is "-" we have to read from stdin */
290                         if (strcmp(argv[fnr], "-") == 0)
291                         {
292                                 input_filename = mm_alloc(strlen("stdin") + 1);
293                                 strcpy(input_filename, "stdin");
294                                 yyin = stdin;
295                         }
296                         else
297                         {
298                                 input_filename = mm_alloc(strlen(argv[fnr]) + 5);
299                                 strcpy(input_filename, argv[fnr]);
300
301                                 /* take care of relative paths */
302                                 ptr2ext = last_dir_separator(input_filename);
303                                 ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
304
305                                 /* no extension? */
306                                 if (ptr2ext == NULL)
307                                 {
308                                         ptr2ext = input_filename + strlen(input_filename);
309
310                                         /* no extension => add .pgc or .pgh */
311                                         ptr2ext[0] = '.';
312                                         ptr2ext[1] = 'p';
313                                         ptr2ext[2] = 'g';
314                                         ptr2ext[3] = (header_mode == true) ? 'h' : 'c';
315                                         ptr2ext[4] = '\0';
316                                 }
317
318                                 yyin = fopen(input_filename, PG_BINARY_R);
319                         }
320
321                         if (out_option == 0)    /* calculate the output name */
322                         {
323                                 if (strcmp(input_filename, "stdin") == 0)
324                                         yyout = stdout;
325                                 else
326                                 {
327                                         output_filename = strdup(input_filename);
328
329                                         ptr2ext = strrchr(output_filename, '.');
330                                         /* make extension = .c resp. .h */
331                                         ptr2ext[1] = (header_mode == true) ? 'h' : 'c';
332                                         ptr2ext[2] = '\0';
333
334                                         yyout = fopen(output_filename, PG_BINARY_W);
335                                         if (yyout == NULL)
336                                         {
337                                                 fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
338                                                                 progname, output_filename, strerror(errno));
339                                                 free(output_filename);
340                                                 free(input_filename);
341                                                 continue;
342                                         }
343                                 }
344                         }
345
346                         if (yyin == NULL)
347                                 fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
348                                                 progname, argv[fnr], strerror(errno));
349                         else
350                         {
351                                 struct cursor *ptr;
352                                 struct _defines *defptr;
353                                 struct typedefs *typeptr;
354
355                                 /* remove old cursor definitions if any are still there */
356                                 for (ptr = cur; ptr != NULL;)
357                                 {
358                                         struct cursor *this = ptr;
359                                         struct arguments *l1,
360                                                            *l2;
361
362                                         free(ptr->command);
363                                         free(ptr->connection);
364                                         free(ptr->name);
365                                         for (l1 = ptr->argsinsert; l1; l1 = l2)
366                                         {
367                                                 l2 = l1->next;
368                                                 free(l1);
369                                         }
370                                         for (l1 = ptr->argsresult; l1; l1 = l2)
371                                         {
372                                                 l2 = l1->next;
373                                                 free(l1);
374                                         }
375                                         ptr = ptr->next;
376                                         free(this);
377                                 }
378                                 cur = NULL;
379
380                                 /* remove non-pertinent old defines as well */
381                                 while (defines && !defines->pertinent)
382                                 {
383                                         defptr = defines;
384                                         defines = defines->next;
385
386                                         free(defptr->new);
387                                         free(defptr->old);
388                                         free(defptr);
389                                 }
390
391                                 for (defptr = defines; defptr != NULL; defptr = defptr->next)
392                                 {
393                                         struct _defines *this = defptr->next;
394
395                                         if (this && !this->pertinent)
396                                         {
397                                                 defptr->next = this->next;
398
399                                                 free(this->new);
400                                                 free(this->old);
401                                                 free(this);
402                                         }
403                                 }
404
405                                 /* and old typedefs */
406                                 for (typeptr = types; typeptr != NULL;)
407                                 {
408                                         struct typedefs *this = typeptr;
409
410                                         free(typeptr->name);
411                                         ECPGfree_struct_member(typeptr->struct_member_list);
412                                         free(typeptr->type);
413                                         typeptr = typeptr->next;
414                                         free(this);
415                                 }
416                                 types = NULL;
417
418                                 /* initialize whenever structures */
419                                 memset(&when_error, 0, sizeof(struct when));
420                                 memset(&when_nf, 0, sizeof(struct when));
421                                 memset(&when_warn, 0, sizeof(struct when));
422
423                                 /* and structure member lists */
424                                 memset(struct_member_list, 0, sizeof(struct_member_list));
425
426                                 /* and our variable counter for Informix compatibility */
427                                 ecpg_informix_var = 0;
428
429                                 /* finally the actual connection */
430                                 connection = NULL;
431
432                                 /* initialize lex */
433                                 lex_init();
434
435                                 /* we need several includes */
436                                 /* but not if we are in header mode */
437                                 if (regression_mode)
438                                         fprintf(yyout, "/* Processed by ecpg (regression mode) */\n");
439                                 else
440                                         fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
441
442                                 if (header_mode == false)
443                                 {
444                                         fprintf(yyout, "/* These include files are added by the preprocessor */\n#include <ecpglib.h>\n#include <ecpgerrno.h>\n#include <sqlca.h>\n");
445
446                                         /* add some compatibility headers */
447                                         if (INFORMIX_MODE)
448                                                 fprintf(yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
449
450                                         fprintf(yyout, "/* End of automatic include section */\n");
451                                 }
452
453                                 if (regression_mode)
454                                         fprintf(yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n");
455
456                                 output_line_number();
457
458                                 /* and parse the source */
459                                 base_yyparse();
460
461                                 /* check if all cursors were indeed opened */
462                                 for (ptr = cur; ptr != NULL;)
463                                 {
464                                         char            errortext[128];
465
466                                         if (!(ptr->opened))
467                                         {
468                                                 /*
469                                                  * Does not really make sense to declare a cursor but
470                                                  * not open it
471                                                  */
472                                                 snprintf(errortext, sizeof(errortext), _("cursor \"%s\" has been declared but not opened\n"), ptr->name);
473                                                 mmerror(PARSE_ERROR, ET_WARNING, errortext);
474                                         }
475                                         ptr = ptr->next;
476                                 }
477
478                                 if (yyin != NULL && yyin != stdin)
479                                         fclose(yyin);
480                                 if (out_option == 0 && yyout != stdout)
481                                         fclose(yyout);
482                         }
483
484                         if (output_filename && out_option == 0)
485                                 free(output_filename);
486
487                         free(input_filename);
488                 }
489         }
490         return ret_value;
491 }