Added an option to force ecpg to also parse files includes via '#include' and some more Informix stuff.

This commit is contained in:
Michael Meskes 2003-05-01 17:16:57 +00:00
parent cffded96ea
commit 9e9d8d54e3
4 changed files with 186 additions and 46 deletions

View File

@ -1391,6 +1391,11 @@ Tue Apr 8 14:03:32 CEST 2003
- Added rstrdate function. - Added rstrdate function.
- Made Informix mode honor environment variable to set dbname to - Made Informix mode honor environment variable to set dbname to
connect to. connect to.
Thu May 1 14:54:41 CEST 2003
- Enable more Informix shortcuts.
- Added option '-i' to parse files included via cpp diretive as well.
- Set ecpg version to 2.12.0. - Set ecpg version to 2.12.0.
- Set ecpg library to 3.4.2. - Set ecpg library to 3.4.2.
- Set pgtypes library to 1.0.0 - Set pgtypes library to 1.0.0

View File

@ -1,4 +1,4 @@
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.66 2003/04/08 12:34:25 meskes Exp $ */ /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.67 2003/05/01 17:16:57 meskes Exp $ */
/* New main for ecpg, the PostgreSQL embedded SQL precompiler. */ /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */
/* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */ /* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */
@ -19,7 +19,8 @@ extern char *optarg;
int ret_value = 0, int ret_value = 0,
autocommit = false, autocommit = false,
auto_create_c = false; auto_create_c = false,
system_includes = false;
enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL; enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL;
@ -43,11 +44,13 @@ help(const char *progname)
printf(" -d generate parser debug output\n"); printf(" -d generate parser debug output\n");
#endif #endif
printf(" -C <mode> set compatibility mode\n" printf(" -C <mode> set compatibility mode\n"
" mode may be INFORMIX only at the moment\n"); " mode may be INFORMIX only at the moment\n"
" INFORMIX mode implies '-i'\n");
printf(" -D SYMBOL define SYMBOL\n"); printf(" -D SYMBOL define SYMBOL\n");
printf(" -I DIRECTORY search DIRECTORY for include files\n"); printf(" -I DIRECTORY search DIRECTORY for include files\n");
printf(" -o OUTFILE write result to OUTFILE\n"); printf(" -o OUTFILE write result to OUTFILE\n");
printf(" -t turn on autocommit of transactions\n"); printf(" -t turn on autocommit of transactions\n");
printf(" -i parse system include files as well\n");
printf(" --help show this help, then exit\n"); printf(" --help show this help, then exit\n");
printf(" --version output version information, then exit\n"); printf(" --version output version information, then exit\n");
printf("\nIf no output file is specified, the name is formed by adding .c to the\n" printf("\nIf no output file is specified, the name is formed by adding .c to the\n"
@ -127,7 +130,7 @@ main(int argc, char *const argv[])
add_include_path("/usr/local/include"); add_include_path("/usr/local/include");
add_include_path("."); add_include_path(".");
while ((c = getopt(argc, argv, "vco:I:tD:dC:")) != -1) while ((c = getopt(argc, argv, "vcio:I:tD:dC:")) != -1)
{ {
switch (c) switch (c)
{ {
@ -150,10 +153,14 @@ main(int argc, char *const argv[])
case 'c': case 'c':
auto_create_c = true; auto_create_c = true;
break; break;
case 'i':
system_includes = true;
break;
case 'C': case 'C':
if (strcmp(optarg, "INFORMIX") == 0) if (strcmp(optarg, "INFORMIX") == 0)
{ {
compat = ECPG_COMPAT_INFORMIX; compat = ECPG_COMPAT_INFORMIX;
system_includes = true;
add_preprocessor_define("dec_t=Numeric"); add_preprocessor_define("dec_t=Numeric");
add_preprocessor_define("intrvl_t=Interval"); add_preprocessor_define("intrvl_t=Interval");
} }

View File

@ -15,6 +15,7 @@
extern int braces_open, extern int braces_open,
autocommit, autocommit,
auto_create_c, auto_create_c,
system_includes,
ret_value, ret_value,
struct_level; struct_level;
extern char *descriptor_index; extern char *descriptor_index;

View File

@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.106 2003/02/17 14:06:39 meskes Exp $ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.107 2003/05/01 17:16:57 meskes Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -25,7 +25,6 @@
#include "extern.h" #include "extern.h"
extern YYSTYPE yylval; extern YYSTYPE yylval;
static int xcdepth = 0; /* depth of nesting in slash-star comments */ static int xcdepth = 0; /* depth of nesting in slash-star comments */
@ -44,6 +43,7 @@ static int literalalloc; /* current allocated buffer size */
static void addlit(char *ytext, int yleng); static void addlit(char *ytext, int yleng);
static void addlitchar (unsigned char); static void addlitchar (unsigned char);
static void string_unput (char *); static void string_unput (char *);
static void parse_include (void);
char *token_start; char *token_start;
int state_before; int state_before;
@ -265,12 +265,17 @@ else [eE][lL][sS][eE]
elif [eE][lL][iI][fF] elif [eE][lL][iI][fF]
endif [eE][nN][dD][iI][fF] endif [eE][nN][dD][iI][fF]
struct [sS][tT][rR][uU][cC][tT]
exec_sql {exec}{space}*{sql}{space}* exec_sql {exec}{space}*{sql}{space}*
ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit}) ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit} ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
/* we might want to parse all cpp include files */
cppinclude {space}*#{include}{space}*
/* Take care of cpp continuation lines */ /* Take care of cpp continuation lines */
cppline {space}*#(.*\\{space})*.* cppline {space}*#(.*\\{space})+.*
/* /*
* Quoted strings must allow some special characters such as single-quote * Quoted strings must allow some special characters such as single-quote
@ -429,6 +434,20 @@ cppline {space}*#(.*\\{space})*.*
else else
return yytext[0]; return yytext[0];
} }
<C>{informix_special}{struct} {
/* are we simulating Informix? */
if (compat == ECPG_COMPAT_INFORMIX)
{
string_unput("typedef struct ");
BEGIN SQL;
return SQL_START;
}
else
{
string_unput("struct ");
return S_ANYTHING;
}
}
<SQL>{self} { /* <SQL>{self} { /*
* We may find a ';' inside a structure * We may find a ';' inside a structure
* definition in a TYPE or VAR statement. * definition in a TYPE or VAR statement.
@ -550,22 +569,6 @@ cppline {space}*#(.*\\{space})*.*
ScanKeyword *keyword; ScanKeyword *keyword;
struct _defines *ptr; struct _defines *ptr;
/* Is it an SQL keyword? */
keyword = ScanKeywordLookup(yytext);
if (keyword != NULL)
return keyword->value;
/* Is it an ECPG keyword? */
keyword = ScanECPGKeywordLookup( yytext);
if (keyword != NULL)
return keyword->value;
/* Is it a C keyword? */
keyword = ScanCKeywordLookup(yytext);
if (keyword != NULL)
return keyword->value;
/* How about a DEFINE? */ /* How about a DEFINE? */
for (ptr = defines; ptr; ptr = ptr->next) for (ptr = defines; ptr; ptr = ptr->next)
{ {
@ -587,6 +590,21 @@ cppline {space}*#(.*\\{space})*.*
} }
} }
/* Is it an SQL keyword? */
keyword = ScanKeywordLookup(yytext);
if (keyword != NULL)
return keyword->value;
/* Is it an ECPG keyword? */
keyword = ScanECPGKeywordLookup( yytext);
if (keyword != NULL)
return keyword->value;
/* Is it a C keyword? */
keyword = ScanCKeywordLookup(yytext);
if (keyword != NULL)
return keyword->value;
/* /*
* None of the above. Return it as an identifier. * None of the above. Return it as an identifier.
* *
@ -627,42 +645,53 @@ cppline {space}*#(.*\\{space})*.*
} }
return ICONST; return ICONST;
} }
<C>{cppinclude} {
if (system_includes)
{
BEGIN(incl);
}
else
{
yylval.str = mm_strdup(yytext);
return(CPP_LINE);
}
}
<C>{cppline} { <C>{cppline} {
yylval.str = mm_strdup(yytext); yylval.str = mm_strdup(yytext);
return(CPP_LINE); return(CPP_LINE);
} }
<C>{identifier} { <C>{identifier} {
ScanKeyword *keyword; ScanKeyword *keyword;
struct _defines *ptr;
keyword = ScanCKeywordLookup(yytext); /* is it a define? */
if (keyword != NULL) { for (ptr = defines; ptr; ptr = ptr->next)
return keyword->value;
}
else
{ {
struct _defines *ptr; if (strcmp(yytext, ptr->old) == 0)
for (ptr = defines; ptr; ptr = ptr->next)
{ {
if (strcmp(yytext, ptr->old) == 0) struct _yy_buffer *yb;
{
struct _yy_buffer *yb;
yb = mm_alloc(sizeof(struct _yy_buffer)); yb = mm_alloc(sizeof(struct _yy_buffer));
yb->buffer = YY_CURRENT_BUFFER; yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno; yb->lineno = yylineno;
yb->filename = mm_strdup(input_filename); yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer; yb->next = yy_buffer;
yy_buffer = yb; yy_buffer = yb;
yy_scan_string(ptr->new); yy_scan_string(ptr->new);
break; break;
}
} }
if (ptr == NULL) }
{
if (ptr == NULL)
{
keyword = ScanCKeywordLookup(yytext);
if (keyword != NULL)
return keyword->value;
else {
yylval.str = mm_strdup(yytext); yylval.str = mm_strdup(yytext);
return IDENT; return IDENT;
} }
@ -940,7 +969,11 @@ cppline {space}*#(.*\\{space})*.*
} }
<def>[^;] { addlit(yytext, yyleng); } <def>[^;] { addlit(yytext, yyleng); }
<incl>[^;]+";" { <incl>\<[^\>]+\>{space}*";"? { parse_include(); }
<incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); }
<incl>[^;\<\>\"]+";" {
parse_include();
#if 0
/* got the include file name */ /* got the include file name */
struct _yy_buffer *yb; struct _yy_buffer *yb;
struct _include_path *ip; struct _include_path *ip;
@ -1026,6 +1059,7 @@ cppline {space}*#(.*\\{space})*.*
output_line_number(); output_line_number();
BEGIN C; BEGIN C;
#endif
} }
<<EOF>> { <<EOF>> {
@ -1128,3 +1162,96 @@ string_unput (char *string)
unput(string[i]); unput(string[i]);
} }
static void
parse_include(void)
{
/* got the include file name */
struct _yy_buffer *yb;
struct _include_path *ip;
char inc_file[MAXPGPATH];
unsigned int i;
yb = mm_alloc(sizeof(struct _yy_buffer));
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
yb->filename = input_filename;
yb->next = yy_buffer;
yy_buffer = yb;
/*
* skip the ";" if there is one and trailing whitespace. Note that
* yytext contains at least one non-space character plus the ";"
*/
for ( i = strlen(yytext)-2;
i > 0 && isspace((unsigned char) yytext[i]);
i-- )
{}
if (yytext[i] == ';')
i--;
yytext[i+1] = '\0';
yyin = NULL;
/* If file name is enclosed in '"' remove these and look only in '.' */
/* Informix does look into all include paths though, except filename starts with '/' */
if ((yytext[0] == '"' && yytext[i] == '"') && (compat != ECPG_COMPAT_INFORMIX || yytext[1] == '/'))
{
yytext[i] = '\0';
memmove(yytext, yytext+1, strlen(yytext));
strncpy(inc_file, yytext, sizeof(inc_file));
yyin = fopen(inc_file, "r");
if (!yyin)
{
if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
{
strcat(inc_file, ".h");
yyin = fopen(inc_file, "r");
}
}
}
else
{
if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
{
yytext[i] = '\0';
memmove(yytext, yytext+1, strlen(yytext));
}
for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
{
if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
{
fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
continue;
}
snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
yyin = fopen(inc_file, "r");
if (!yyin)
{
if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
{
strcat(inc_file, ".h");
yyin = fopen( inc_file, "r" );
}
}
}
}
if (!yyin)
{
snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
}
input_filename = mm_strdup(inc_file);
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
yylineno = 1;
output_line_number();
BEGIN C;
}