]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/ecpg.c
7cf8eeebb2faa8b33c0067a6590559796741c47f
[postgresql] / src / interfaces / ecpg / preproc / ecpg.c
1 /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.77 2003/08/04 00:43:33 momjian 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 #ifdef HAVE_GETOPT_H
12 #include <getopt.h>
13 #endif
14
15 extern int      optind;
16 extern char *optarg;
17
18 #include "extern.h"
19
20 int                     ret_value = 0,
21                         autocommit = false,
22                         auto_create_c = false,
23                         system_includes = false,
24                         force_indicator = true;
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 #ifdef YYDEBUG
45         printf("  -d             generate parser debug output\n");
46 #endif
47         printf("  -C <mode>      set compatibility mode\n"
48                    "                 mode may be one of\n"
49                    "                 \"INFORMIX\"\n"
50                    "                 \"INFORMIX_SE\"\n");
51         printf("  -r <option>    specify runtime behaviour\n"
52                    "                 option may be only \"no_indicator\" at the moment\n");
53         printf("  -D SYMBOL      define SYMBOL\n");
54         printf("  -I DIRECTORY   search DIRECTORY for include files\n");
55         printf("  -o OUTFILE     write result to OUTFILE\n");
56         printf("  -t             turn on autocommit of transactions\n");
57         printf("  -i             parse system include files as well\n");
58         printf("  --help         show this help, then exit\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 gets 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("");
109         }
110         defines->pertinent = true;
111         defines->next = pd;
112 }
113
114 int
115 main(int argc, char *const argv[])
116 {
117         int                     fnr,
118                                 c,
119                                 verbose = false,
120                                 out_option = 0;
121         struct _include_path *ip;
122         char       *progname;
123
124         progname = get_progname(argv[0]);
125
126         if (argc > 1)
127         {
128                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
129                 {
130                         help(progname);
131                         exit(0);
132                 }
133                 else if (strcmp(argv[1], "--version") == 0)
134                 {
135                         printf("ecpg (PostgreSQL %s) %d.%d.%d\n", PG_VERSION,
136                                    MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
137                         exit(0);
138                 }
139         }
140
141         while ((c = getopt(argc, argv, "vcio:I:tD:dC:r:")) != -1)
142         {
143                 switch (c)
144                 {
145                         case 'o':
146                                 if (strcmp(optarg, "-") == 0)
147                                         yyout = stdout;
148                                 else
149                                         yyout = fopen(optarg, PG_BINARY_W);
150
151                                 if (yyout == NULL)
152                                         perror(optarg);
153                                 else
154                                         out_option = 1;
155                                 break;
156                         case 'I':
157                                 add_include_path(optarg);
158                                 break;
159                         case 't':
160                                 autocommit = true;
161                                 break;
162                         case 'v':
163                                 verbose = true;
164                                 break;
165                         case 'c':
166                                 auto_create_c = true;
167                                 break;
168                         case 'i':
169                                 system_includes = true;
170                                 break;
171                         case 'C':
172                                 if (strncmp(optarg, "INFORMIX", strlen("INFORMIX")) == 0)
173                                 {
174                                         compat = (strcmp(optarg, "INFORMIX") == 0) ? ECPG_COMPAT_INFORMIX : ECPG_COMPAT_INFORMIX_SE;
175                                         /* system_includes = true; */
176                                         add_preprocessor_define("dec_t=Numeric");
177                                         add_preprocessor_define("intrvl_t=Interval");
178                                         add_preprocessor_define("dtime_t=Timestamp");
179                                 }
180                                 else
181                                 {
182                                         fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
183                                         return ILLEGAL_OPTION;
184                                 }
185                                 break;
186                         case 'r':
187                                 if (strcmp(optarg, "no_indicator") == 0)
188                                         force_indicator = false;
189                                 else
190                                 {
191                                         fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
192                                         return ILLEGAL_OPTION;
193                                 }
194                                 break;
195                         case 'D':
196                                 add_preprocessor_define(optarg);
197                                 break;
198                         case 'd':
199 #ifdef YYDEBUG
200                                 yydebug = 1;
201 #else
202                                 fprintf(stderr, "%s: parser debug support (-d) not available\n",
203                                                 progname);
204 #endif
205                                 break;
206                         default:
207                                 fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
208                                 return ILLEGAL_OPTION;
209                 }
210         }
211
212         add_include_path(".");
213         add_include_path("/usr/local/include");
214         add_include_path(INCLUDE_PATH);
215         add_include_path("/usr/include");
216
217         if (verbose)
218         {
219                 fprintf(stderr, "%s, the PostgreSQL embedded C preprocessor, version %d.%d.%d\n",
220                                 progname, MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
221                 fprintf(stderr, "exec sql include ... search starts here:\n");
222                 for (ip = include_paths; ip != NULL; ip = ip->next)
223                         fprintf(stderr, " %s\n", ip->path);
224                 fprintf(stderr, "end of search list\n");
225                 return 0;
226         }
227
228         if (optind >= argc)                     /* no files specified */
229         {
230                 fprintf(stderr, "%s: no input files specified\n", progname);
231                 fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
232                 return (ILLEGAL_OPTION);
233         }
234         else
235         {
236                 /* after the options there must not be anything but filenames */
237                 for (fnr = optind; fnr < argc; fnr++)
238                 {
239                         char       *output_filename = NULL,
240                                            *ptr2ext;
241
242                         /* If argv[fnr] is "-" we have to read from stdin */
243                         if (strcmp(argv[fnr], "-") == 0)
244                         {
245                                 input_filename = mm_alloc(strlen("stdin") + 1);
246                                 strcpy(input_filename, "stdin");
247                                 yyin = stdin;
248                         }
249                         else
250                         {
251                                 input_filename = mm_alloc(strlen(argv[fnr]) + 5);
252                                 strcpy(input_filename, argv[fnr]);
253
254                                 /* take care of relative paths */
255                                 ptr2ext = last_path_separator(input_filename);
256                                 ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
257
258                                 /* no extension? */
259                                 if (ptr2ext == NULL)
260                                 {
261                                         ptr2ext = input_filename + strlen(input_filename);
262
263                                         /* no extension => add .pgc */
264                                         ptr2ext[0] = '.';
265                                         ptr2ext[1] = 'p';
266                                         ptr2ext[2] = 'g';
267                                         ptr2ext[3] = 'c';
268                                         ptr2ext[4] = '\0';
269                                 }
270
271                                 yyin = fopen(input_filename, PG_BINARY_R);
272                         }
273
274                         if (out_option == 0)    /* calculate the output name */
275                         {
276                                 if (strcmp(input_filename, "stdin") == 0)
277                                         yyout = stdout;
278                                 else
279                                 {
280                                         output_filename = strdup(input_filename);
281
282                                         ptr2ext = strrchr(output_filename, '.');
283                                         /* make extension = .c */
284                                         ptr2ext[1] = 'c';
285                                         ptr2ext[2] = '\0';
286
287                                         yyout = fopen(output_filename, PG_BINARY_W);
288                                         if (yyout == NULL)
289                                         {
290                                                 perror(output_filename);
291                                                 free(output_filename);
292                                                 free(input_filename);
293                                                 continue;
294                                         }
295                                 }
296                         }
297
298                         if (yyin == NULL)
299                                 perror(argv[fnr]);
300                         else
301                         {
302                                 struct cursor *ptr;
303                                 struct _defines *defptr;
304                                 struct typedefs *typeptr;
305
306                                 /* remove old cursor definitions if any are still there */
307                                 for (ptr = cur; ptr != NULL;)
308                                 {
309                                         struct cursor *this = ptr;
310                                         struct arguments *l1,
311                                                            *l2;
312
313                                         free(ptr->command);
314                                         free(ptr->connection);
315                                         free(ptr->name);
316                                         for (l1 = ptr->argsinsert; l1; l1 = l2)
317                                         {
318                                                 l2 = l1->next;
319                                                 free(l1);
320                                         }
321                                         for (l1 = ptr->argsresult; l1; l1 = l2)
322                                         {
323                                                 l2 = l1->next;
324                                                 free(l1);
325                                         }
326                                         ptr = ptr->next;
327                                         free(this);
328                                 }
329                                 cur = NULL;
330
331                                 /* remove non-pertinent old defines as well */
332                                 while (defines && !defines->pertinent)
333                                 {
334                                         defptr = defines;
335                                         defines = defines->next;
336
337                                         free(defptr->new);
338                                         free(defptr->old);
339                                         free(defptr);
340                                 }
341
342                                 for (defptr = defines; defptr != NULL; defptr = defptr->next)
343                                 {
344                                         struct _defines *this = defptr->next;
345
346                                         if (this && !this->pertinent)
347                                         {
348                                                 defptr->next = this->next;
349
350                                                 free(this->new);
351                                                 free(this->old);
352                                                 free(this);
353                                         }
354                                 }
355
356                                 /* and old typedefs */
357                                 for (typeptr = types; typeptr != NULL;)
358                                 {
359                                         struct typedefs *this = typeptr;
360
361                                         free(typeptr->name);
362                                         ECPGfree_struct_member(typeptr->struct_member_list);
363                                         free(typeptr->type);
364                                         typeptr = typeptr->next;
365                                         free(this);
366                                 }
367                                 types = NULL;
368
369                                 /* initialize whenever structures */
370                                 memset(&when_error, 0, sizeof(struct when));
371                                 memset(&when_nf, 0, sizeof(struct when));
372                                 memset(&when_warn, 0, sizeof(struct when));
373
374                                 /* and structure member lists */
375                                 memset(struct_member_list, 0, sizeof(struct_member_list));
376
377                                 /* and our variable counter for Informix compatibility */
378                                 ecpg_informix_var = 0;
379
380                                 /* finally the actual connection */
381                                 connection = NULL;
382
383                                 /* initialize lex */
384                                 lex_init();
385
386                                 /* we need several includes */
387                                 fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n#include <ecpgerrno.h>\n#include <sqlca.h>\n#line 1 \"%s\"\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, input_filename);
388
389                                 /* add some compatibility headers */
390                                 if (INFORMIX_MODE)
391                                         fprintf(yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
392
393                                 fprintf(yyout, "/* End of automatic include section */\n");
394
395                                 /* and parse the source */
396                                 yyparse();
397
398                                 if (yyin != NULL && yyin != stdin)
399                                         fclose(yyin);
400                                 if (out_option == 0 && yyout != stdout)
401                                         fclose(yyout);
402                         }
403
404                         if (output_filename)
405                                 free(output_filename);
406
407                         free(input_filename);
408                 }
409         }
410         return ret_value;
411 }