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