PostgreSQL Source Code  git master
ecpg.c
Go to the documentation of this file.
1 /* src/interfaces/ecpg/preproc/ecpg.c */
2 
3 /* Main for ecpg, the PostgreSQL embedded SQL precompiler. */
4 /* Copyright (c) 1996-2018, PostgreSQL Global Development Group */
5 
6 #include "postgres_fe.h"
7 
8 #include <unistd.h>
9 
10 #include "getopt_long.h"
11 
12 #include "extern.h"
13 
14 int ret_value = 0;
15 bool autocommit = false,
16  auto_create_c = false,
17  system_includes = false,
19  questionmarks = false,
20  regression_mode = false,
21  auto_prepare = false;
22 
24 
26 
28 struct cursor *cur = NULL;
29 struct typedefs *types = NULL;
30 struct _defines *defines = NULL;
31 
32 static void
33 help(const char *progname)
34 {
35  printf(_("%s is the PostgreSQL embedded SQL preprocessor for C programs.\n\n"),
36  progname);
37  printf(_("Usage:\n"
38  " %s [OPTION]... FILE...\n\n"),
39  progname);
40  printf(_("Options:\n"));
41  printf(_(" -c automatically generate C code from embedded SQL code;\n"
42  " this affects EXEC SQL TYPE\n"));
43  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  printf(_(" -D SYMBOL define SYMBOL\n"));
49  printf(_(" -h parse a header file, this option includes option \"-c\"\n"));
50  printf(_(" -i parse system include files as well\n"));
51  printf(_(" -I DIRECTORY search DIRECTORY for include files\n"));
52  printf(_(" -o OUTFILE write result to OUTFILE\n"));
53  printf(_(" -r OPTION specify run-time behavior; OPTION can be:\n"
54  " \"no_indicator\", \"prepare\", \"questionmarks\"\n"));
55  printf(_(" --regression run in regression testing mode\n"));
56  printf(_(" -t turn on autocommit of transactions\n"));
57  printf(_(" -V, --version output version information, then exit\n"));
58  printf(_(" -?, --help show this help, then exit\n"));
59  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  printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
62 }
63 
64 static void
65 add_include_path(char *path)
66 {
67  struct _include_path *ip = include_paths,
68  *new;
69 
70  new = mm_alloc(sizeof(struct _include_path));
71  new->path = path;
72  new->next = NULL;
73 
74  if (ip == NULL)
75  include_paths = new;
76  else
77  {
78  for (; ip->next != NULL; ip = ip->next);
79  ip->next = new;
80  }
81 }
82 
83 static void
85 {
86  struct _defines *pd = defines;
87  char *ptr,
88  *define_copy = mm_strdup(define);
89 
90  defines = mm_alloc(sizeof(struct _defines));
91 
92  /* look for = sign */
93  ptr = strchr(define_copy, '=');
94  if (ptr != NULL)
95  {
96  char *tmp;
97 
98  /* symbol has a value */
99  for (tmp = ptr - 1; *tmp == ' '; tmp--);
100  tmp[1] = '\0';
101  defines->old = define_copy;
102  defines->new = ptr + 1;
103  }
104  else
105  {
106  defines->old = define_copy;
107  defines->new = mm_strdup("1");
108  }
109  defines->pertinent = true;
110  defines->used = NULL;
111  defines->next = pd;
112 }
113 
114 #define ECPG_GETOPT_LONG_REGRESSION 1
115 int
116 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  out_option = 0;
126  bool verbose = false,
127  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  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("ecpg"));
134 
135  progname = get_progname(argv[0]);
136 
137  if (find_my_exec(argv[0], my_exec_path) < 0)
138  {
139  fprintf(stderr, _("%s: could not locate my own executable path\n"), argv[0]);
140  return ILLEGAL_OPTION;
141  }
142 
143  if (argc > 1)
144  {
145  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
146  {
147  help(progname);
148  exit(0);
149  }
150  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
151  {
152  printf("ecpg %s\n", PG_VERSION);
153  exit(0);
154  }
155  }
156 
157  output_filename = NULL;
158  while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h", ecpg_options, NULL)) != -1)
159  {
160  switch (c)
161  {
163  regression_mode = true;
164  break;
165  case 'o':
167  if (strcmp(output_filename, "-") == 0)
168  base_yyout = stdout;
169  else
171 
172  if (base_yyout == NULL)
173  {
174  fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
175  progname, output_filename, strerror(errno));
176  output_filename = NULL;
177  }
178  else
179  out_option = 1;
180  break;
181  case 'I':
183  break;
184  case 't':
185  autocommit = true;
186  break;
187  case 'v':
188  verbose = true;
189  break;
190  case 'h':
191  header_mode = true;
192  /* this must include "-c" to make sense, so fall through */
193  /* FALLTHROUGH */
194  case 'c':
195  auto_create_c = true;
196  break;
197  case 'i':
198  system_includes = true;
199  break;
200  case 'C':
201  if (pg_strcasecmp(optarg, "INFORMIX") == 0 || pg_strcasecmp(optarg, "INFORMIX_SE") == 0)
202  {
203  char pkginclude_path[MAXPGPATH];
204  char informix_path[MAXPGPATH];
205 
207  get_pkginclude_path(my_exec_path, pkginclude_path);
208  snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
209  add_include_path(informix_path);
210  }
211  else if (strncmp(optarg, "ORACLE", strlen("ORACLE")) == 0)
212  {
214  }
215  else
216  {
217  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
218  return ILLEGAL_OPTION;
219  }
220  break;
221  case 'r':
222  if (strcmp(optarg, "no_indicator") == 0)
223  force_indicator = false;
224  else if (strcmp(optarg, "prepare") == 0)
225  auto_prepare = true;
226  else if (strcmp(optarg, "questionmarks") == 0)
227  questionmarks = true;
228  else
229  {
230  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
231  return ILLEGAL_OPTION;
232  }
233  break;
234  case 'D':
236  break;
237  case 'd':
238 #ifdef YYDEBUG
239  base_yydebug = 1;
240 #else
241  fprintf(stderr, _("%s: parser debug support (-d) not available\n"),
242  progname);
243 #endif
244  break;
245  default:
246  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
247  return ILLEGAL_OPTION;
248  }
249  }
250 
251  add_include_path(".");
252  add_include_path("/usr/local/include");
253  get_include_path(my_exec_path, include_path);
254  add_include_path(include_path);
255  add_include_path("/usr/include");
256 
257  if (verbose)
258  {
259  fprintf(stderr,
260  _("%s, the PostgreSQL embedded C preprocessor, version %s\n"),
261  progname, PG_VERSION);
262  fprintf(stderr, _("EXEC SQL INCLUDE ... search starts here:\n"));
263  for (ip = include_paths; ip != NULL; ip = ip->next)
264  fprintf(stderr, " %s\n", ip->path);
265  fprintf(stderr, _("end of search list\n"));
266  return 0;
267  }
268 
269  if (optind >= argc) /* no files specified */
270  {
271  fprintf(stderr, _("%s: no input files specified\n"), progname);
272  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
273  return ILLEGAL_OPTION;
274  }
275  else
276  {
277  /* after the options there must not be anything but filenames */
278  for (fnr = optind; fnr < argc; fnr++)
279  {
280  char *ptr2ext;
281 
282  /* If argv[fnr] is "-" we have to read from stdin */
283  if (strcmp(argv[fnr], "-") == 0)
284  {
285  input_filename = mm_alloc(strlen("stdin") + 1);
286  strcpy(input_filename, "stdin");
287  base_yyin = stdin;
288  }
289  else
290  {
291  input_filename = mm_alloc(strlen(argv[fnr]) + 5);
292  strcpy(input_filename, argv[fnr]);
293 
294  /* take care of relative paths */
296  ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
297 
298  /* no extension? */
299  if (ptr2ext == NULL)
300  {
301  ptr2ext = input_filename + strlen(input_filename);
302 
303  /* no extension => add .pgc or .pgh */
304  ptr2ext[0] = '.';
305  ptr2ext[1] = 'p';
306  ptr2ext[2] = 'g';
307  ptr2ext[3] = (header_mode == true) ? 'h' : 'c';
308  ptr2ext[4] = '\0';
309  }
310 
312  }
313 
314  if (out_option == 0) /* calculate the output name */
315  {
316  if (strcmp(input_filename, "stdin") == 0)
317  base_yyout = stdout;
318  else
319  {
320  output_filename = mm_alloc(strlen(input_filename) + 3);
322 
323  ptr2ext = strrchr(output_filename, '.');
324  /* make extension = .c resp. .h */
325  ptr2ext[1] = (header_mode == true) ? 'h' : 'c';
326  ptr2ext[2] = '\0';
327 
329  if (base_yyout == NULL)
330  {
331  fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
332  progname, output_filename, strerror(errno));
334  output_filename = NULL;
336  continue;
337  }
338  }
339  }
340 
341  if (base_yyin == NULL)
342  fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
343  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  for (ptr = cur; ptr != NULL;)
352  {
353  struct cursor *this = ptr;
354  struct arguments *l1,
355  *l2;
356 
357  free(ptr->command);
358  free(ptr->connection);
359  free(ptr->name);
360  for (l1 = ptr->argsinsert; l1; l1 = l2)
361  {
362  l2 = l1->next;
363  free(l1);
364  }
365  for (l1 = ptr->argsresult; l1; l1 = l2)
366  {
367  l2 = l1->next;
368  free(l1);
369  }
370  ptr = ptr->next;
371  free(this);
372  }
373  cur = NULL;
374 
375  /* remove non-pertinent old defines as well */
376  while (defines && !defines->pertinent)
377  {
378  defptr = defines;
379  defines = defines->next;
380 
381  free(defptr->new);
382  free(defptr->old);
383  free(defptr);
384  }
385 
386  for (defptr = defines; defptr != NULL; defptr = defptr->next)
387  {
388  struct _defines *this = defptr->next;
389 
390  if (this && !this->pertinent)
391  {
392  defptr->next = this->next;
393 
394  free(this->new);
395  free(this->old);
396  free(this);
397  }
398  }
399 
400  /* and old typedefs */
401  for (typeptr = types; typeptr != NULL;)
402  {
403  struct typedefs *this = typeptr;
404 
405  free(typeptr->name);
407  free(typeptr->type);
408  typeptr = typeptr->next;
409  free(this);
410  }
411  types = NULL;
412 
413  /* initialize whenever structures */
414  memset(&when_error, 0, sizeof(struct when));
415  memset(&when_nf, 0, sizeof(struct when));
416  memset(&when_warn, 0, sizeof(struct when));
417 
418  /* and structure member lists */
419  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  ecpg_internal_var = 0;
426 
427  /* finally the actual connection */
428  connection = NULL;
429 
430  /* initialize lex */
431  lex_init();
432 
433  /* we need several includes */
434  /* but not if we are in header mode */
435  if (regression_mode)
436  fprintf(base_yyout, "/* Processed by ecpg (regression mode) */\n");
437  else
438  fprintf(base_yyout, "/* Processed by ecpg (%s) */\n", PG_VERSION);
439 
440  if (header_mode == false)
441  {
442  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  if (INFORMIX_MODE)
446  fprintf(base_yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
447 
448  fprintf(base_yyout, "/* End of automatic include section */\n");
449  }
450 
451  if (regression_mode)
452  fprintf(base_yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n");
453 
455 
456  /* and parse the source */
457  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  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 (base_yyin != NULL && base_yyin != stdin)
468  fclose(base_yyin);
469  if (out_option == 0 && base_yyout != stdout)
470  fclose(base_yyout);
471 
472  /*
473  * If there was an error, delete the output file.
474  */
475  if (ret_value != 0)
476  {
477  if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
478  fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
479  }
480  }
481 
482  if (output_filename && out_option == 0)
483  {
485  output_filename = NULL;
486  }
487 
489  }
490  }
491  return ret_value;
492 }
bool regression_mode
Definition: ecpg.c:20
int ret_value
Definition: ecpg.c:14
#define ECPG_GETOPT_LONG_REGRESSION
Definition: ecpg.c:114
static int32 next
Definition: blutils.c:211
char * new
Definition: type.h:150
int base_yyparse(core_yyscan_t yyscanner)
struct typedefs * types
Definition: ecpg.c:29
void output_line_number(void)
Definition: output.c:10
#define INFORMIX_MODE(X)
Definition: extern.h:23
const char * get_progname(const char *argv0)
Definition: path.c:453
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
struct cursor * next
Definition: type.h:135
static void help(const char *progname)
Definition: ecpg.c:33
bool auto_create_c
Definition: ecpg.c:16
int ecpg_internal_var
struct cursor * cur
Definition: ecpg.c:28
bool system_includes
Definition: ecpg.c:17
void * used
Definition: type.h:152
#define PG_BINARY_W
Definition: c.h:1083
struct _include_path * include_paths
Definition: ecpg.c:27
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
char * old
Definition: type.h:149
Definition: type.h:147
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * name
Definition: type.h:126
Definition: type.h:138
struct typedefs * next
Definition: type.h:144
const char * progname
Definition: pg_standby.c:37
#define PG_BINARY_R
Definition: c.h:1082
static void add_include_path(char *path)
Definition: ecpg.c:65
void mmerror(int errorcode, enum errortype type, const char *error,...) pg_attribute_printf(3
static void add_preprocessor_define(char *define)
Definition: ecpg.c:84
int optind
Definition: getopt.c:51
struct arguments * next
Definition: type.h:169
struct when when_error when_nf when_warn
Definition: output.c:30
void * mm_alloc(size_t)
void get_pkginclude_path(const char *my_exec_path, char *ret_path)
Definition: path.c:731
struct arguments * argsinsert
Definition: type.h:131
char * input_filename
struct this_type * type
Definition: type.h:141
#define MAXPGPATH
int find_my_exec(const char *argv0, char *retpath)
Definition: exec.c:119
void ECPGfree_struct_member(struct ECPGstruct_member *rm)
Definition: type.c:632
char * c
char * name
Definition: type.h:140
Definition: type.h:124
Definition: type.h:82
bool questionmarks
Definition: ecpg.c:19
char * connection
Definition: type.h:129
FILE * base_yyout
#define ILLEGAL_OPTION
Definition: extern.h:115
enum COMPAT_MODE compat
Definition: ecpg.c:25
static int verbose
Definition: pg_basebackup.c:88
#define no_argument
Definition: getopt_long.h:24
struct _defines * next
Definition: type.h:153
char my_exec_path[MAXPGPATH]
Definition: globals.c:71
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1054
struct ECPGstruct_member * struct_member_list[STRUCT_DEPTH]
int main(int argc, char *const argv[])
Definition: ecpg.c:116
char * last_dir_separator(const char *filename)
Definition: path.c:138
int pertinent
Definition: type.h:151
struct arguments * argsresult
Definition: type.h:133
#define free(a)
Definition: header.h:65
bool autocommit
Definition: ecpg.c:15
FILE * base_yyin
bool auto_prepare
Definition: ecpg.c:21
struct _defines * defines
Definition: ecpg.c:30
bool opened
Definition: type.h:130
void get_include_path(const char *my_exec_path, char *ret_path)
Definition: path.c:722
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:550
char * optarg
Definition: getopt.c:53
char * path
Definition: type.h:120
bool force_indicator
Definition: ecpg.c:18
#define PARSE_ERROR
Definition: extern.h:117
const char * strerror(int errnum)
Definition: strerror.c:19
char * mm_strdup(const char *)
Definition: type.c:25
COMPAT_MODE
Definition: extern.h:16
void lex_init(void)
struct ECPGstruct_member * struct_member_list
Definition: type.h:142
char * output_filename
Definition: ecpg.c:23
#define _(x)
Definition: elog.c:84
char * command
Definition: type.h:128
struct _include_path * next
Definition: type.h:121