-/* $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. */
/* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */
int ret_value = 0,
autocommit = false,
- auto_create_c = false;
+ auto_create_c = false,
+ system_includes = false;
enum COMPAT_MODE compat = ECPG_COMPAT_PGSQL;
printf(" -d generate parser debug output\n");
#endif
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(" -I DIRECTORY search DIRECTORY for include files\n");
printf(" -o OUTFILE write result to OUTFILE\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(" --version output version information, then exit\n");
printf("\nIf no output file is specified, the name is formed by adding .c to the\n"
add_include_path("/usr/local/include");
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)
{
case 'c':
auto_create_c = true;
break;
+ case 'i':
+ system_includes = true;
+ break;
case 'C':
if (strcmp(optarg, "INFORMIX") == 0)
{
compat = ECPG_COMPAT_INFORMIX;
+ system_includes = true;
add_preprocessor_define("dec_t=Numeric");
add_preprocessor_define("intrvl_t=Interval");
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "extern.h"
-
extern YYSTYPE yylval;
static int xcdepth = 0; /* depth of nesting in slash-star comments */
static void addlit(char *ytext, int yleng);
static void addlitchar (unsigned char);
static void string_unput (char *);
+static void parse_include (void);
char *token_start;
int state_before;
elif [eE][lL][iI][fF]
endif [eE][nN][dD][iI][fF]
+struct [sS][tT][rR][uU][cC][tT]
+
exec_sql {exec}{space}*{sql}{space}*
ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
+/* we might want to parse all cpp include files */
+cppinclude {space}*#{include}{space}*
+
/* Take care of cpp continuation lines */
-cppline {space}*#(.*\\{space})*.*
+cppline {space}*#(.*\\{space})+.*
/*
* Quoted strings must allow some special characters such as single-quote
else
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} { /*
* We may find a ';' inside a structure
* definition in a TYPE or VAR statement.
ScanKeyword *keyword;
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? */
for (ptr = defines; ptr; ptr = ptr->next)
{
}
}
+ /* 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.
*
}
return ICONST;
}
+<C>{cppinclude} {
+ if (system_includes)
+ {
+ BEGIN(incl);
+ }
+ else
+ {
+ yylval.str = mm_strdup(yytext);
+ return(CPP_LINE);
+ }
+ }
<C>{cppline} {
yylval.str = mm_strdup(yytext);
return(CPP_LINE);
}
<C>{identifier} {
ScanKeyword *keyword;
+ struct _defines *ptr;
- keyword = ScanCKeywordLookup(yytext);
- if (keyword != NULL) {
- return keyword->value;
- }
- else
+ /* is it a define? */
+ for (ptr = defines; ptr; ptr = ptr->next)
{
- struct _defines *ptr;
-
- for (ptr = defines; ptr; ptr = ptr->next)
+ if (strcmp(yytext, ptr->old) == 0)
{
- 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->lineno = yylineno;
- yb->filename = mm_strdup(input_filename);
- yb->next = yy_buffer;
+ yb->buffer = YY_CURRENT_BUFFER;
+ yb->lineno = yylineno;
+ yb->filename = mm_strdup(input_filename);
+ yb->next = yy_buffer;
- yy_buffer = yb;
+ yy_buffer = yb;
- yy_scan_string(ptr->new);
- break;
- }
+ yy_scan_string(ptr->new);
+ break;
}
- if (ptr == NULL)
- {
+ }
+
+ if (ptr == NULL)
+ {
+ keyword = ScanCKeywordLookup(yytext);
+ if (keyword != NULL)
+ return keyword->value;
+
+ else {
yylval.str = mm_strdup(yytext);
return IDENT;
}
}
<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 */
struct _yy_buffer *yb;
struct _include_path *ip;
output_line_number();
BEGIN C;
+#endif
}
<<EOF>> {
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;
+}