2010-09-20 22:08:53 +02:00
|
|
|
/* src/interfaces/ecpg/preproc/ecpg.c */
|
2001-08-25 00:37:36 +02:00
|
|
|
|
2009-08-05 13:42:20 +02:00
|
|
|
/* Main for ecpg, the PostgreSQL embedded SQL precompiler. */
|
2020-01-01 18:21:45 +01:00
|
|
|
/* Copyright (c) 1996-2020, PostgreSQL Global Development Group */
|
1998-02-05 16:46:43 +01:00
|
|
|
|
2001-02-10 03:31:31 +01:00
|
|
|
#include "postgres_fe.h"
|
|
|
|
|
1999-07-19 03:18:05 +02:00
|
|
|
#include <unistd.h>
|
2017-02-25 22:12:24 +01:00
|
|
|
|
2007-01-11 16:47:34 +01:00
|
|
|
#include "getopt_long.h"
|
2001-08-25 00:37:36 +02:00
|
|
|
|
2018-12-01 22:34:00 +01:00
|
|
|
#include "preproc_extern.h"
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2010-11-02 18:12:01 +01:00
|
|
|
int ret_value = 0;
|
2011-04-10 17:42:00 +02:00
|
|
|
bool autocommit = false,
|
2003-05-01 19:16:57 +02:00
|
|
|
auto_create_c = false,
|
2003-06-25 12:44:21 +02:00
|
|
|
system_includes = false,
|
2004-01-28 21:43:03 +01:00
|
|
|
force_indicator = true,
|
2007-08-14 12:01:54 +02:00
|
|
|
questionmarks = false,
|
|
|
|
regression_mode = false,
|
|
|
|
auto_prepare = false;
|
2003-02-13 14:11:52 +01:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
char *output_filename;
|
2007-06-11 13:52:08 +02:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL;
|
2003-02-13 14:11:52 +01:00
|
|
|
|
1999-12-26 22:31:35 +01:00
|
|
|
struct _include_path *include_paths = NULL;
|
1998-08-11 20:33:37 +02:00
|
|
|
struct cursor *cur = NULL;
|
1999-02-20 08:01:08 +01:00
|
|
|
struct typedefs *types = NULL;
|
1999-12-26 22:31:35 +01:00
|
|
|
struct _defines *defines = NULL;
|
|
|
|
|
1998-02-06 14:32:34 +01:00
|
|
|
static void
|
2001-08-25 00:37:36 +02:00
|
|
|
help(const char *progname)
|
1998-02-06 14:32:34 +01:00
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_("%s is the PostgreSQL embedded SQL preprocessor for C programs.\n\n"),
|
2001-08-25 00:37:36 +02:00
|
|
|
progname);
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_("Usage:\n"
|
2009-06-11 16:49:15 +02:00
|
|
|
" %s [OPTION]... FILE...\n\n"),
|
2001-08-28 04:47:18 +02:00
|
|
|
progname);
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_("Options:\n"));
|
|
|
|
printf(_(" -c automatically generate C code from embedded SQL code;\n"
|
2009-01-23 13:43:32 +01:00
|
|
|
" this affects EXEC SQL TYPE\n"));
|
|
|
|
printf(_(" -C MODE set compatibility mode; MODE can be one of\n"
|
2018-03-14 00:54:13 +01:00
|
|
|
" \"INFORMIX\", \"INFORMIX_SE\", \"ORACLE\"\n"));
|
2000-11-07 09:46:27 +01:00
|
|
|
#ifdef YYDEBUG
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_(" -d generate parser debug output\n"));
|
2000-11-07 09:46:27 +01:00
|
|
|
#endif
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_(" -D SYMBOL define SYMBOL\n"));
|
|
|
|
printf(_(" -h parse a header file, this option includes option \"-c\"\n"));
|
|
|
|
printf(_(" -i parse system include files as well\n"));
|
|
|
|
printf(_(" -I DIRECTORY search DIRECTORY for include files\n"));
|
|
|
|
printf(_(" -o OUTFILE write result to OUTFILE\n"));
|
2009-01-23 13:43:32 +01:00
|
|
|
printf(_(" -r OPTION specify run-time behavior; OPTION can be:\n"
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
" \"no_indicator\", \"prepare\", \"questionmarks\"\n"));
|
2009-02-25 14:03:07 +01:00
|
|
|
printf(_(" --regression run in regression testing mode\n"));
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_(" -t turn on autocommit of transactions\n"));
|
2016-09-18 12:46:32 +02:00
|
|
|
printf(_(" -V, --version output version information, then exit\n"));
|
2012-06-18 01:44:00 +02:00
|
|
|
printf(_(" -?, --help show this help, then exit\n"));
|
2008-05-16 17:20:04 +02:00
|
|
|
printf(_("\nIf no output file is specified, the name is formed by adding .c to the\n"
|
2009-06-11 16:49:15 +02:00
|
|
|
"input file name, after stripping off .pgc if present.\n"));
|
2020-02-28 08:54:49 +01:00
|
|
|
printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
2020-02-28 08:54:49 +01:00
|
|
|
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
|
1998-03-20 04:08:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-09-01 06:40:42 +02:00
|
|
|
add_include_path(char *path)
|
1998-03-20 04:08:11 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
struct _include_path *ip = include_paths,
|
|
|
|
*new;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2003-05-13 13:29:14 +02:00
|
|
|
new = mm_alloc(sizeof(struct _include_path));
|
|
|
|
new->path = path;
|
|
|
|
new->next = NULL;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2003-05-13 13:29:14 +02:00
|
|
|
if (ip == NULL)
|
|
|
|
include_paths = new;
|
|
|
|
else
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
for (; ip->next != NULL; ip = ip->next);
|
2003-05-13 13:29:14 +02:00
|
|
|
ip->next = new;
|
|
|
|
}
|
1998-02-06 14:32:34 +01:00
|
|
|
}
|
|
|
|
|
2000-01-18 14:03:49 +01:00
|
|
|
static void
|
|
|
|
add_preprocessor_define(char *define)
|
|
|
|
{
|
|
|
|
struct _defines *pd = defines;
|
2003-08-04 02:43:34 +02:00
|
|
|
char *ptr,
|
|
|
|
*define_copy = mm_strdup(define);
|
|
|
|
|
2000-01-18 14:03:49 +01:00
|
|
|
defines = mm_alloc(sizeof(struct _defines));
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-03-18 11:46:39 +01:00
|
|
|
/* look for = sign */
|
|
|
|
ptr = strchr(define_copy, '=');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
char *tmp;
|
|
|
|
|
2004-07-20 20:06:41 +02:00
|
|
|
/* symbol has a value */
|
2003-08-04 02:43:34 +02:00
|
|
|
for (tmp = ptr - 1; *tmp == ' '; tmp--);
|
2003-03-18 11:46:39 +01:00
|
|
|
tmp[1] = '\0';
|
2019-05-31 18:38:53 +02:00
|
|
|
defines->olddef = define_copy;
|
|
|
|
defines->newdef = ptr + 1;
|
2003-03-18 11:46:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-31 18:38:53 +02:00
|
|
|
defines->olddef = define_copy;
|
|
|
|
defines->newdef = mm_strdup("1");
|
2003-03-18 11:46:39 +01:00
|
|
|
}
|
2000-01-18 14:03:49 +01:00
|
|
|
defines->pertinent = true;
|
2004-07-20 20:06:41 +02:00
|
|
|
defines->used = NULL;
|
2000-01-18 14:03:49 +01:00
|
|
|
defines->next = pd;
|
|
|
|
}
|
|
|
|
|
2016-09-18 12:46:32 +02:00
|
|
|
#define ECPG_GETOPT_LONG_REGRESSION 1
|
1998-02-06 14:32:34 +01:00
|
|
|
int
|
|
|
|
main(int argc, char *const argv[])
|
1998-02-05 16:46:43 +01:00
|
|
|
{
|
2007-01-11 16:47:34 +01:00
|
|
|
static struct option ecpg_options[] = {
|
|
|
|
{"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION},
|
2007-11-15 22:14:46 +01:00
|
|
|
{NULL, 0, NULL, 0}
|
2007-01-11 16:47:34 +01:00
|
|
|
};
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
int fnr,
|
|
|
|
c,
|
|
|
|
out_option = 0;
|
2011-04-10 17:42:00 +02:00
|
|
|
bool verbose = false,
|
2010-11-02 18:12:01 +01:00
|
|
|
header_mode = false;
|
1998-09-01 06:40:42 +02:00
|
|
|
struct _include_path *ip;
|
2004-05-12 15:38:49 +02:00
|
|
|
const char *progname;
|
2004-08-29 07:07:03 +02:00
|
|
|
char my_exec_path[MAXPGPATH];
|
|
|
|
char include_path[MAXPGPATH];
|
|
|
|
|
2008-12-11 08:34:09 +01:00
|
|
|
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("ecpg"));
|
2008-05-16 17:20:04 +02:00
|
|
|
|
2003-04-04 22:42:13 +02:00
|
|
|
progname = get_progname(argv[0]);
|
2001-08-25 00:37:36 +02:00
|
|
|
|
2014-03-02 04:14:14 +01:00
|
|
|
if (find_my_exec(argv[0], my_exec_path) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not locate my own executable path\n"), argv[0]);
|
2017-08-17 18:39:20 +02:00
|
|
|
return ILLEGAL_OPTION;
|
2014-03-02 04:14:14 +01:00
|
|
|
}
|
2004-05-17 16:35:34 +02:00
|
|
|
|
2016-09-18 12:46:32 +02:00
|
|
|
if (argc > 1)
|
|
|
|
{
|
|
|
|
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
|
|
|
|
{
|
|
|
|
help(progname);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
|
|
|
|
{
|
2018-09-12 14:33:15 +02:00
|
|
|
printf("ecpg (PostgreSQL) %s\n", PG_VERSION);
|
2016-09-18 12:46:32 +02:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-11 13:52:08 +02:00
|
|
|
output_filename = NULL;
|
2016-09-18 12:46:32 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h", ecpg_options, NULL)) != -1)
|
1998-02-06 14:32:34 +01:00
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
2007-01-11 16:47:34 +01:00
|
|
|
case ECPG_GETOPT_LONG_REGRESSION:
|
|
|
|
regression_mode = true;
|
|
|
|
break;
|
1998-02-06 14:32:34 +01:00
|
|
|
case 'o':
|
2013-06-30 04:14:56 +02:00
|
|
|
output_filename = mm_strdup(optarg);
|
2007-06-11 13:52:08 +02:00
|
|
|
if (strcmp(output_filename, "-") == 0)
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyout = stdout;
|
2003-05-27 16:36:00 +02:00
|
|
|
else
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyout = fopen(output_filename, PG_BINARY_W);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
if (base_yyout == NULL)
|
2007-06-11 13:52:08 +02:00
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
|
2007-06-11 13:52:08 +02:00
|
|
|
progname, output_filename, strerror(errno));
|
|
|
|
output_filename = NULL;
|
|
|
|
}
|
1998-02-06 14:32:34 +01:00
|
|
|
else
|
|
|
|
out_option = 1;
|
|
|
|
break;
|
1998-03-20 04:08:11 +01:00
|
|
|
case 'I':
|
|
|
|
add_include_path(optarg);
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
|
|
|
case 't':
|
2002-03-21 10:42:52 +01:00
|
|
|
autocommit = true;
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
1998-02-11 16:30:00 +01:00
|
|
|
case 'v':
|
1999-12-23 13:33:19 +01:00
|
|
|
verbose = true;
|
The first fix is to allow an input file with a relative path and without
a ".pgc " extension. The second patch fixes a coredump when there is
more than one input file (in that case, cur and types were not set to
NULL before processing the second f ile)
The patch below modifies the accepted grammar of ecpg to accept
FETCH [direction] [amount] cursor name
i.e. the IN|FROM clause becomes optional (as in Oracle and Informix).
This removes the incompatibility mentioned in section "Porting From
Other RDBMS Packages" p169, PostgreSQL Programmer's Guide. The grammar
is modified in such a way as to avoid shift/reduce conflicts. It does
not accept the statement "EXEC SQL FETCH;" anymore, as the old grammar
did (this seems to be a bug of the old grammar anyway).
This patch cleans up the handling of space characters in the scanner;
some patte rns require \n to be in {space}, some do not. A second fix is
the handling of cpp continuati on lines; the old pattern did not match
these. The parser is patched to fix an off-by-one error in the #line
directives. The pa rser is also enhanced to report the correct location
of errors in declarations in the "E XEC SQL DECLARE SECTION". Finally,
some right recursions in the parser were replaced by left-recursions.
This patch adds preprocessor directives to ecpg; in particular
EXEC SQL IFDEF, EXEC SQL IFNDEF, EXEC SQL ELSE, EXEC SQL ELIF and EXEC SQL ENDIF
"EXEC SQL IFDEF" is used with defines made with "EXEC SQL DEFINE" and
defines, specified on the command line with -D. Defines, specified on
the command line are persistent across multiple input files. Defines can
be nested up to a maximum level of 128 (see patch). There is a fair
amount of error checking to make sure directives are matched properly. I
need preprocessor directives for porting code, that is written for an
Informix database, to a PostgreSQL database, while maintaining
compatibility with the original code. I decided not to extend the
already large ecpg grammar. Everything is done in the scanner by adding
some states, e.g. to skip all input except newlines and directives. The
preprocessor commands are compatible with Informix. Oracle uses a cpp
replacement.
Rene Hogendoorn
1999-12-21 18:42:16 +01:00
|
|
|
break;
|
2004-01-28 10:52:14 +01:00
|
|
|
case 'h':
|
|
|
|
header_mode = true;
|
2018-05-02 01:35:08 +02:00
|
|
|
/* this must include "-c" to make sense, so fall through */
|
|
|
|
/* FALLTHROUGH */
|
2002-03-21 10:42:52 +01:00
|
|
|
case 'c':
|
|
|
|
auto_create_c = true;
|
|
|
|
break;
|
2003-05-01 19:16:57 +02:00
|
|
|
case 'i':
|
|
|
|
system_includes = true;
|
|
|
|
break;
|
2003-02-13 14:11:52 +01:00
|
|
|
case 'C':
|
2018-01-12 15:59:43 +01:00
|
|
|
if (pg_strcasecmp(optarg, "INFORMIX") == 0 || pg_strcasecmp(optarg, "INFORMIX_SE") == 0)
|
2003-03-18 11:46:39 +01:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
char pkginclude_path[MAXPGPATH];
|
|
|
|
char informix_path[MAXPGPATH];
|
|
|
|
|
2018-01-12 15:59:43 +01:00
|
|
|
compat = (pg_strcasecmp(optarg, "INFORMIX") == 0) ? ECPG_COMPAT_INFORMIX : ECPG_COMPAT_INFORMIX_SE;
|
2004-05-17 16:35:34 +02:00
|
|
|
get_pkginclude_path(my_exec_path, pkginclude_path);
|
|
|
|
snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
|
|
|
|
add_include_path(informix_path);
|
2003-03-18 11:46:39 +01:00
|
|
|
}
|
2019-07-02 03:34:58 +02:00
|
|
|
else if (pg_strcasecmp(optarg, "ORACLE") == 0)
|
2018-03-14 00:54:13 +01:00
|
|
|
{
|
|
|
|
compat = ECPG_COMPAT_ORACLE;
|
|
|
|
}
|
2003-02-13 14:11:52 +01:00
|
|
|
else
|
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
|
2003-02-13 14:11:52 +01:00
|
|
|
return ILLEGAL_OPTION;
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
2003-02-13 14:11:52 +01:00
|
|
|
break;
|
2003-06-25 12:44:21 +02:00
|
|
|
case 'r':
|
2019-07-02 03:34:58 +02:00
|
|
|
if (pg_strcasecmp(optarg, "no_indicator") == 0)
|
2003-06-25 12:44:21 +02:00
|
|
|
force_indicator = false;
|
2019-07-02 03:34:58 +02:00
|
|
|
else if (pg_strcasecmp(optarg, "prepare") == 0)
|
2007-08-14 12:01:54 +02:00
|
|
|
auto_prepare = true;
|
2019-07-02 03:34:58 +02:00
|
|
|
else if (pg_strcasecmp(optarg, "questionmarks") == 0)
|
2007-08-14 12:01:54 +02:00
|
|
|
questionmarks = true;
|
2003-06-25 12:44:21 +02:00
|
|
|
else
|
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
|
2003-06-25 12:44:21 +02:00
|
|
|
return ILLEGAL_OPTION;
|
|
|
|
}
|
|
|
|
break;
|
2000-01-18 14:03:49 +01:00
|
|
|
case 'D':
|
2000-04-12 19:17:23 +02:00
|
|
|
add_preprocessor_define(optarg);
|
|
|
|
break;
|
2000-11-07 09:46:27 +01:00
|
|
|
case 'd':
|
2001-08-25 00:37:36 +02:00
|
|
|
#ifdef YYDEBUG
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yydebug = 1;
|
2001-08-25 00:37:36 +02:00
|
|
|
#else
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("%s: parser debug support (-d) not available\n"),
|
2001-08-25 00:37:36 +02:00
|
|
|
progname);
|
2000-11-07 09:46:27 +01:00
|
|
|
#endif
|
2001-08-25 00:37:36 +02:00
|
|
|
break;
|
1998-02-06 14:32:34 +01:00
|
|
|
default:
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
|
1998-09-01 05:29:17 +02:00
|
|
|
return ILLEGAL_OPTION;
|
1998-02-06 14:32:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-13 13:29:14 +02:00
|
|
|
add_include_path(".");
|
|
|
|
add_include_path("/usr/local/include");
|
2004-05-17 16:35:34 +02:00
|
|
|
get_include_path(my_exec_path, include_path);
|
|
|
|
add_include_path(include_path);
|
2003-05-13 13:29:14 +02:00
|
|
|
add_include_path("/usr/include");
|
|
|
|
|
1999-12-23 13:33:19 +01:00
|
|
|
if (verbose)
|
|
|
|
{
|
2016-08-16 18:49:30 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
_("%s, the PostgreSQL embedded C preprocessor, version %s\n"),
|
|
|
|
progname, PG_VERSION);
|
2009-01-23 13:43:32 +01:00
|
|
|
fprintf(stderr, _("EXEC SQL INCLUDE ... search starts here:\n"));
|
1999-12-23 13:33:19 +01:00
|
|
|
for (ip = include_paths; ip != NULL; ip = ip->next)
|
|
|
|
fprintf(stderr, " %s\n", ip->path);
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("end of search list\n"));
|
2001-08-25 00:37:36 +02:00
|
|
|
return 0;
|
1999-12-23 13:33:19 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
if (optind >= argc) /* no files specified */
|
1998-03-20 04:08:11 +01:00
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("%s: no input files specified\n"), progname);
|
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
|
2017-08-17 18:39:20 +02:00
|
|
|
return ILLEGAL_OPTION;
|
1998-03-20 04:08:11 +01:00
|
|
|
}
|
1998-02-11 16:30:00 +01:00
|
|
|
else
|
1998-02-06 14:32:34 +01:00
|
|
|
{
|
1998-02-11 16:30:00 +01:00
|
|
|
/* after the options there must not be anything but filenames */
|
|
|
|
for (fnr = optind; fnr < argc; fnr++)
|
1998-02-06 14:32:34 +01:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *ptr2ext;
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2003-05-27 16:36:00 +02:00
|
|
|
/* If argv[fnr] is "-" we have to read from stdin */
|
|
|
|
if (strcmp(argv[fnr], "-") == 0)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
input_filename = mm_alloc(strlen("stdin") + 1);
|
2003-05-27 16:36:00 +02:00
|
|
|
strcpy(input_filename, "stdin");
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyin = stdin;
|
2003-05-27 16:36:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
input_filename = mm_alloc(strlen(argv[fnr]) + 5);
|
|
|
|
strcpy(input_filename, argv[fnr]);
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2003-05-27 16:36:00 +02:00
|
|
|
/* take care of relative paths */
|
2004-06-11 00:26:24 +02:00
|
|
|
ptr2ext = last_dir_separator(input_filename);
|
2003-05-27 16:36:00 +02:00
|
|
|
ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2003-05-27 16:36:00 +02:00
|
|
|
/* no extension? */
|
|
|
|
if (ptr2ext == NULL)
|
|
|
|
{
|
|
|
|
ptr2ext = input_filename + strlen(input_filename);
|
|
|
|
|
2004-01-28 10:52:14 +01:00
|
|
|
/* no extension => add .pgc or .pgh */
|
2003-05-27 16:36:00 +02:00
|
|
|
ptr2ext[0] = '.';
|
|
|
|
ptr2ext[1] = 'p';
|
|
|
|
ptr2ext[2] = 'g';
|
2004-08-29 07:07:03 +02:00
|
|
|
ptr2ext[3] = (header_mode == true) ? 'h' : 'c';
|
2003-05-27 16:36:00 +02:00
|
|
|
ptr2ext[4] = '\0';
|
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyin = fopen(input_filename, PG_BINARY_R);
|
1998-02-11 16:30:00 +01:00
|
|
|
}
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2001-10-28 07:26:15 +01:00
|
|
|
if (out_option == 0) /* calculate the output name */
|
1998-02-10 17:44:17 +01:00
|
|
|
{
|
2003-05-27 16:36:00 +02:00
|
|
|
if (strcmp(input_filename, "stdin") == 0)
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyout = stdout;
|
2003-05-27 16:36:00 +02:00
|
|
|
else
|
|
|
|
{
|
2016-12-22 08:28:13 +01:00
|
|
|
output_filename = mm_alloc(strlen(input_filename) + 3);
|
|
|
|
strcpy(output_filename, input_filename);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2003-05-27 16:36:00 +02:00
|
|
|
ptr2ext = strrchr(output_filename, '.');
|
2004-01-28 10:52:14 +01:00
|
|
|
/* make extension = .c resp. .h */
|
2004-08-29 07:07:03 +02:00
|
|
|
ptr2ext[1] = (header_mode == true) ? 'h' : 'c';
|
2003-05-27 16:36:00 +02:00
|
|
|
ptr2ext[2] = '\0';
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
base_yyout = fopen(output_filename, PG_BINARY_W);
|
|
|
|
if (base_yyout == NULL)
|
2003-05-27 16:36:00 +02:00
|
|
|
{
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
|
2004-11-09 16:57:57 +01:00
|
|
|
progname, output_filename, strerror(errno));
|
2003-05-27 16:36:00 +02:00
|
|
|
free(output_filename);
|
2018-03-14 00:47:49 +01:00
|
|
|
output_filename = NULL;
|
2003-05-27 16:36:00 +02:00
|
|
|
free(input_filename);
|
|
|
|
continue;
|
|
|
|
}
|
1998-02-11 16:30:00 +01:00
|
|
|
}
|
1998-02-06 14:32:34 +01:00
|
|
|
}
|
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
if (base_yyin == NULL)
|
2008-05-16 17:20:04 +02:00
|
|
|
fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
|
2004-11-09 16:57:57 +01:00
|
|
|
progname, argv[fnr], strerror(errno));
|
1998-02-11 16:30:00 +01:00
|
|
|
else
|
|
|
|
{
|
1998-04-21 15:23:24 +02:00
|
|
|
struct cursor *ptr;
|
1998-08-25 14:17:27 +02:00
|
|
|
struct _defines *defptr;
|
1999-02-20 08:01:08 +01:00
|
|
|
struct typedefs *typeptr;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1998-08-11 20:33:37 +02:00
|
|
|
/* remove old cursor definitions if any are still there */
|
2019-09-20 18:47:21 +02:00
|
|
|
for (ptr = cur; ptr != NULL;)
|
1998-08-11 20:33:37 +02:00
|
|
|
{
|
2019-09-20 18:47:21 +02:00
|
|
|
struct cursor *this = ptr;
|
|
|
|
struct arguments *l1,
|
|
|
|
*l2;
|
|
|
|
|
|
|
|
free(ptr->command);
|
|
|
|
free(ptr->connection);
|
|
|
|
free(ptr->name);
|
|
|
|
for (l1 = ptr->argsinsert; l1; l1 = l2)
|
|
|
|
{
|
|
|
|
l2 = l1->next;
|
|
|
|
free(l1);
|
|
|
|
}
|
|
|
|
for (l1 = ptr->argsresult; l1; l1 = l2)
|
|
|
|
{
|
|
|
|
l2 = l1->next;
|
|
|
|
free(l1);
|
|
|
|
}
|
|
|
|
ptr = ptr->next;
|
|
|
|
free(this);
|
1998-08-11 20:33:37 +02:00
|
|
|
}
|
2019-09-20 18:47:21 +02:00
|
|
|
cur = NULL;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2000-01-18 14:03:49 +01:00
|
|
|
/* remove non-pertinent old defines as well */
|
2000-04-12 19:17:23 +02:00
|
|
|
while (defines && !defines->pertinent)
|
|
|
|
{
|
|
|
|
defptr = defines;
|
|
|
|
defines = defines->next;
|
2000-01-18 14:03:49 +01:00
|
|
|
|
2019-05-31 18:38:53 +02:00
|
|
|
free(defptr->newdef);
|
|
|
|
free(defptr->olddef);
|
2000-04-12 19:17:23 +02:00
|
|
|
free(defptr);
|
2000-01-18 14:03:49 +01:00
|
|
|
}
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
for (defptr = defines; defptr != NULL; defptr = defptr->next)
|
1998-08-25 14:17:27 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
struct _defines *this = defptr->next;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
if (this && !this->pertinent)
|
|
|
|
{
|
|
|
|
defptr->next = this->next;
|
|
|
|
|
2019-05-31 18:38:53 +02:00
|
|
|
free(this->newdef);
|
|
|
|
free(this->olddef);
|
2000-04-12 19:17:23 +02:00
|
|
|
free(this);
|
|
|
|
}
|
1998-08-25 14:17:27 +02:00
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1999-02-20 08:01:08 +01:00
|
|
|
/* and old typedefs */
|
|
|
|
for (typeptr = types; typeptr != NULL;)
|
|
|
|
{
|
|
|
|
struct typedefs *this = typeptr;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1999-02-20 08:01:08 +01:00
|
|
|
free(typeptr->name);
|
|
|
|
ECPGfree_struct_member(typeptr->struct_member_list);
|
2000-01-18 14:03:49 +01:00
|
|
|
free(typeptr->type);
|
1999-02-20 08:01:08 +01:00
|
|
|
typeptr = typeptr->next;
|
|
|
|
free(this);
|
|
|
|
}
|
2000-01-18 14:03:49 +01:00
|
|
|
types = NULL;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-01-18 14:03:49 +01:00
|
|
|
/* initialize whenever structures */
|
|
|
|
memset(&when_error, 0, sizeof(struct when));
|
|
|
|
memset(&when_nf, 0, sizeof(struct when));
|
|
|
|
memset(&when_warn, 0, sizeof(struct when));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-01-18 14:03:49 +01:00
|
|
|
/* and structure member lists */
|
|
|
|
memset(struct_member_list, 0, sizeof(struct_member_list));
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
/*
|
|
|
|
* and our variable counter for out of scope cursors'
|
|
|
|
* variables
|
|
|
|
*/
|
2010-01-26 10:07:32 +01:00
|
|
|
ecpg_internal_var = 0;
|
2003-06-13 12:50:58 +02:00
|
|
|
|
2000-02-17 20:48:58 +01:00
|
|
|
/* finally the actual connection */
|
|
|
|
connection = NULL;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
1998-02-11 16:30:00 +01:00
|
|
|
/* initialize lex */
|
|
|
|
lex_init();
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2002-01-10 11:42:54 +01:00
|
|
|
/* we need several includes */
|
2004-01-28 10:52:14 +01:00
|
|
|
/* but not if we are in header mode */
|
2007-11-15 22:14:46 +01:00
|
|
|
if (regression_mode)
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "/* Processed by ecpg (regression mode) */\n");
|
2007-01-11 16:47:34 +01:00
|
|
|
else
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "/* Processed by ecpg (%s) */\n", PG_VERSION);
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-01-28 10:52:14 +01:00
|
|
|
if (header_mode == false)
|
|
|
|
{
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "/* These include files are added by the preprocessor */\n#include <ecpglib.h>\n#include <ecpgerrno.h>\n#include <sqlca.h>\n");
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2004-01-28 10:52:14 +01:00
|
|
|
/* add some compatibility headers */
|
|
|
|
if (INFORMIX_MODE)
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "/* Needed for informix compatibility */\n#include <ecpg_informix.h>\n");
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "/* End of automatic include section */\n");
|
2004-01-28 10:52:14 +01:00
|
|
|
}
|
2003-02-14 14:17:13 +01:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
if (regression_mode)
|
2016-12-11 20:54:25 +01:00
|
|
|
fprintf(base_yyout, "#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))\n");
|
2007-01-12 11:00:14 +01:00
|
|
|
|
2006-02-08 10:10:05 +01:00
|
|
|
output_line_number();
|
2004-08-29 07:07:03 +02:00
|
|
|
|
1998-02-11 16:30:00 +01:00
|
|
|
/* and parse the source */
|
2007-03-17 20:25:24 +01:00
|
|
|
base_yyparse();
|
1998-02-06 14:32:34 +01:00
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
/*
|
|
|
|
* Check whether all cursors were indeed opened. It does not
|
|
|
|
* really make sense to declare a cursor but not open it.
|
2009-01-23 13:43:32 +01:00
|
|
|
*/
|
|
|
|
for (ptr = cur; ptr != NULL; ptr = ptr->next)
|
2004-01-28 10:52:14 +01:00
|
|
|
if (!(ptr->opened))
|
2009-01-23 13:43:32 +01:00
|
|
|
mmerror(PARSE_ERROR, ET_WARNING, "cursor \"%s\" has been declared but not opened", ptr->name);
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2016-12-11 20:54:25 +01:00
|
|
|
if (base_yyin != NULL && base_yyin != stdin)
|
|
|
|
fclose(base_yyin);
|
|
|
|
if (out_option == 0 && base_yyout != stdout)
|
|
|
|
fclose(base_yyout);
|
2010-07-06 21:19:02 +02:00
|
|
|
|
2010-04-03 21:30:49 +02:00
|
|
|
/*
|
|
|
|
* If there was an error, delete the output file.
|
|
|
|
*/
|
|
|
|
if (ret_value != 0)
|
|
|
|
{
|
|
|
|
if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
|
|
|
|
fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
|
|
|
|
}
|
1998-02-11 16:30:00 +01:00
|
|
|
}
|
1998-04-21 15:23:24 +02:00
|
|
|
|
2018-04-26 20:47:16 +02:00
|
|
|
if (output_filename && out_option == 0)
|
|
|
|
{
|
1998-04-21 15:23:24 +02:00
|
|
|
free(output_filename);
|
2018-03-14 00:47:49 +01:00
|
|
|
output_filename = NULL;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-03-20 04:08:11 +01:00
|
|
|
free(input_filename);
|
1998-02-11 16:30:00 +01:00
|
|
|
}
|
1998-02-06 14:32:34 +01:00
|
|
|
}
|
1999-12-08 10:52:29 +01:00
|
|
|
return ret_value;
|
1998-02-05 16:46:43 +01:00
|
|
|
}
|