2 /*-------------------------------------------------------------------------
5 * lexical scanner for ecpg
7 * This is a modified version of src/backend/parser/scan.l
10 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.119 2003/07/25 05:42:27 meskes Exp $
17 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
22 #include <sys/types.h>
28 extern YYSTYPE yylval;
30 static int xcdepth = 0; /* depth of nesting in slash-star comments */
33 * literalbuf is used to accumulate literal values when multiple rules
34 * are needed to parse a single literal. Call startlit to reset buffer
35 * to empty, addlit to add text. Note that the buffer is permanently
36 * malloc'd to the largest size needed so far in the current run.
38 static char *literalbuf = NULL; /* expandable buffer */
39 static int literallen; /* actual current length */
40 static int literalalloc; /* current allocated buffer size */
42 #define startlit() (literalbuf[0] = '\0', literallen = 0)
43 static void addlit(char *ytext, int yleng);
44 static void addlitchar (unsigned char);
45 static void parse_include (void);
52 YY_BUFFER_STATE buffer;
55 struct _yy_buffer *next;
60 #define MAX_NESTED_IF 128
61 static short preproc_tos;
63 static struct _if_value
67 } stacked_if_value[MAX_NESTED_IF];
72 %option never-interactive
77 %s C SQL incl def def_ident
80 * OK, here is a short description of lex/flex rules behavior.
81 * The longest pattern which matches an input string is always chosen.
82 * For equal-length patterns, the first occurring in the rules list is chosen.
83 * INITIAL is the starting state, to which all non-conditional rules apply.
84 * Exclusive states change parsing rules while the state is active. When in
85 * an exclusive state, only those rules defined for that state apply.
87 * We use exclusive states for quoted strings, extended comments,
88 * and to eliminate parsing troubles for numeric strings.
90 * <xb> bit string literal
91 * <xc> extended C-style comments - thomas 1997-07-12
92 * <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
93 * <xh> hexadecimal numeric string - thomas 1997-11-16
94 * <xq> quoted strings - thomas 1997-07-30
112 xbcat {quote}{whitespace_with_newline}{quote}
114 /* Hexadecimal number
119 xhcat {quote}{whitespace_with_newline}{quote}
121 /* National character
125 /* C version of hex number
127 xch 0[xX][0-9A-Fa-f]*
130 * xqdouble implements SQL92 embedded quote
131 * xqcat allows strings to cross input lines
136 xqdouble {quote}{quote}
139 xqoctesc [\\][0-7]{1,3}
140 xqcat {quote}{whitespace_with_newline}{quote}
143 * Allows embedded spaces and other special characters into identifiers.
148 xddouble {dquote}{dquote}
151 /* special stuff for C strings */
155 xdcinside ({xdcqq}|{xdcqdq}|{xdcother})
159 * The "extended comment" syntax closely resembles allowable operator syntax.
160 * The tricky part here is to get lex to recognize a string starting with
161 * slash-star as a comment, when interpreting it as an operator would produce
162 * a longer match --- remember lex will prefer a longer match! Also, if we
163 * have something like plus-slash-star, lex will think this is a 3-character
164 * operator whereas we want to see it as a + operator and a comment start.
165 * The solution is two-fold:
166 * 1. append {op_chars}* to xcstart so that it matches as much text as
167 * {operator} would. Then the tie-breaker (first matching rule of same
168 * length) ensures xcstart wins. We put back the extra stuff with yyless()
169 * in case it contains a star-slash that should terminate the comment.
170 * 2. In the operator rule, check for slash-star within the operator, and
171 * if found throw it back with yyless(). This handles the plus-slash-star
173 * SQL92-style comments, which start with dash-dash, have similar interactions
174 * with the operator rule.
176 xcstart \/\*{op_chars}*
181 ident_start [A-Za-z\200-\377_]
182 ident_cont [A-Za-z\200-\377_0-9\$]
184 identifier {ident_start}{ident_cont}*
186 array ({ident_cont}|[\+\-\*\%\/\(\)])*
190 * "self" is the set of chars that should be returned as single-character
191 * tokens. "op_chars" is the set of chars that can make up "Op" tokens,
192 * which can be one or more characters long (but if a single-char token
193 * appears in the "self" set, it is not to be returned as an Op). Note
194 * that the sets overlap, but each has some chars that are not in the other.
196 * If you change either set, adjust the character lists appearing in the
197 * rule for "operator"!
199 self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
200 op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
203 /* we no longer allow unary minus in numbers.
204 * instead we pass it separately to parser. there it gets
205 * coerced via doNegate() -- Leon aug 20 1999
209 decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
210 real ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
215 * In order to make the world safe for Windows and Mac clients as well as
216 * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n
217 * sequence will be seen as two successive newlines, but that doesn't cause
218 * any problems. SQL92-style comments, which start with -- and extend to the
219 * next newline, are treated as equivalent to a single whitespace character.
221 * NOTE a fine point: if there is no newline following --, we will absorb
222 * everything to the end of the input as a comment. This is correct. Older
223 * versions of Postgres failed to recognize -- as a comment if the input
224 * did not end with a newline.
226 * XXX perhaps \f (formfeed) should be treated as a newline as well?
236 comment ("--"{non_newline}*)
238 whitespace ({space}+|{comment})
241 * SQL92 requires at least one newline in the whitespace separating
242 * string literals that are to be concatenated. Silly, but who are we
243 * to argue? Note that {whitespace_with_newline} should not have * after
244 * it, whereas {whitespace} should generally have a * after it...
247 horiz_whitespace ({horiz_space}|{comment})
248 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
250 /* special characters for other dbms */
251 /* we have to react differently in compat mode */
252 informix_special [\$]
256 /* some stuff needed for ecpg */
257 exec [eE][xX][eE][cC]
259 define [dD][eE][fF][iI][nN][eE]
260 include [iI][nN][cC][lL][uU][dD][eE]
262 ifdef [iI][fF][dD][eE][fF]
263 ifndef [iI][fF][nN][dD][eE][fF]
264 else [eE][lL][sS][eE]
265 elif [eE][lL][iI][fF]
266 endif [eE][nN][dD][iI][fF]
268 struct [sS][tT][rR][uU][cC][tT]
270 exec_sql {exec}{space}*{sql}{space}*
271 ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
272 ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
274 /* we might want to parse all cpp include files */
275 cppinclude {space}*#{include}{space}*
277 /* Take care of cpp continuation lines */
278 cppline {space}*#(.*\\{space})+.*
281 * Quoted strings must allow some special characters such as single-quote
283 * Embedded single-quotes are implemented both in the SQL92-standard
284 * style of two adjacent single quotes "''" and in the Postgres/Java style
285 * of escaped-quote "\'".
286 * Other embedded escaped characters are matched explicitly and the leading
287 * backslash is dropped from the string. - thomas 1997-09-24
288 * Note that xcstart must appear before operator, as explained above!
289 * Also whitespace (comment) must appear before operator.
295 /* code to execute during start of each call of yylex() */
299 <SQL>{whitespace} { /* ignore */ }
302 token_start = yytext;
303 state_before = YYSTATE;
306 /* Put back any characters past slash-star; see above */
312 /* Put back any characters past slash-star; see above */
328 <xc>{xcinside} { ECHO; }
329 <xc>{op_chars} { ECHO; }
331 <xc><<EOF>> { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated /* comment"); }
334 token_start = yytext;
341 if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
342 mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string input.");
343 yylval.str = literalbuf;
348 <xb>{xbinside} { addlit(yytext, yyleng); }
350 <xb>{xbcat} { /* ignore */ }
351 <xb><<EOF>> { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated bit string"); }
354 token_start = yytext;
360 yylval.str = literalbuf;
364 <xh><<EOF>> { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated hexadecimal integer"); }
366 /* National character.
367 * Need to remember type info to flow it forward into the parser.
368 * Not yet implemented. - thomas 2002-06-17
370 token_start = yytext;
375 token_start = yytext;
376 state_before = YYSTATE;
382 yylval.str = mm_strdup(literalbuf);
385 <xq>{xqdouble} { addlitchar('\''); }
386 <xq>{xqinside} { addlit(yytext, yyleng); }
387 <xq>{xqescape} { addlit(yytext, yyleng); }
388 <xq>{xqoctesc} { addlit(yytext, yyleng); }
389 <xq>{xqcat} { /* ignore */ }
391 <xq><<EOF>> { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted string"); }
394 state_before = YYSTATE;
401 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
402 yylval.str = mm_strdup(literalbuf);
407 yylval.str = mm_strdup(literalbuf);
410 <xd>{xddouble} { addlitchar('"'); }
411 <xd>{xdinside} { addlit(yytext, yyleng); }
412 <xd,xdc><<EOF>> { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted identifier"); }
414 state_before = YYSTATE;
418 <xdc>{xdcinside} { addlit(yytext, yyleng); }
419 <SQL>{typecast} { return TYPECAST; }
420 <SQL>{informix_special} {
421 /* are we simulating Informix? */
430 * We may find a ';' inside a structure
431 * definition in a TYPE or VAR statement.
432 * This is not an EOL marker.
434 if (yytext[0] == ';' && struct_level == 0)
440 * Check for embedded slash-star or dash-dash; those
441 * are comment starts, so operator must stop there.
442 * Note that slash-star or dash-dash at the first
443 * character will match a prior rule, not this one.
446 char *slashstar = strstr(yytext, "/*");
447 char *dashdash = strstr(yytext, "--");
449 if (slashstar && dashdash)
451 /* if both appear, take the first one */
452 if (slashstar > dashdash)
453 slashstar = dashdash;
456 slashstar = dashdash;
458 nchars = slashstar - yytext;
461 * For SQL92 compatibility, '+' and '-' cannot be the
462 * last char of a multi-char operator unless the operator
463 * contains chars that are not in SQL92 operators.
464 * The idea is to lex '=-' as two operators, but not
465 * to forbid operator names like '?-' that could not be
466 * sequences of SQL92 operators.
469 (yytext[nchars-1] == '+' ||
470 yytext[nchars-1] == '-'))
474 for (ic = nchars-2; ic >= 0; ic--)
476 if (strchr("~!@#^&|`?%", yytext[ic]))
480 break; /* found a char that makes it OK */
481 nchars--; /* else remove the +/-, and check again */
486 /* Strip the unwanted chars from the token */
489 * If what we have left is only one char, and it's
490 * one of the characters matching "self", then
491 * return it as a character token the same way
492 * that the "self" rule would have.
495 strchr(",()[].;:+-*/%^<>=", yytext[0]))
499 /* Convert "!=" operator to "<>" for compatibility */
500 if (strcmp(yytext, "!=") == 0)
501 yylval.str = mm_strdup("<>");
503 yylval.str = mm_strdup(yytext);
507 yylval.ival = atol(yytext+1);
515 val = strtol((char *)yytext, &endptr,10);
516 if (*endptr != '\0' || errno == ERANGE
517 #ifdef HAVE_LONG_INT_64
518 /* if long > 32 bits, check for overflow of int4 */
519 || val != (long) ((int32) val)
524 yylval.str = mm_strdup(yytext);
531 yylval.str = mm_strdup(yytext);
535 yylval.str = mm_strdup(yytext);
539 yylval.str = mm_strdup(yytext);
542 <SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))* {
543 yylval.str = mm_strdup(yytext+1);
547 ScanKeyword *keyword;
548 struct _defines *ptr;
550 /* How about a DEFINE? */
551 for (ptr = defines; ptr; ptr = ptr->next)
553 if (strcmp(yytext, ptr->old) == 0)
555 struct _yy_buffer *yb;
557 yb = mm_alloc(sizeof(struct _yy_buffer));
559 yb->buffer = YY_CURRENT_BUFFER;
560 yb->lineno = yylineno;
561 yb->filename = mm_strdup(input_filename);
562 yb->next = yy_buffer;
566 yy_scan_string(ptr->new);
573 /* Is it an SQL keyword? */
574 keyword = ScanKeywordLookup(yytext);
576 return keyword->value;
578 /* Is it an ECPG keyword? */
579 keyword = ScanECPGKeywordLookup( yytext);
581 return keyword->value;
583 /* Is it a C keyword? */
584 keyword = ScanCKeywordLookup(yytext);
586 return keyword->value;
589 * None of the above. Return it as an identifier.
591 * The backend would attempt to truncate and case-fold
592 * the identifier, but I see no good reason for ecpg
593 * to do so; that's just another way that ecpg could get
594 * out of step with the backend.
598 yylval.str = mm_strdup(yytext);
603 <SQL>{other} { return yytext[0]; }
604 <C>{exec_sql} { BEGIN SQL; return SQL_START; }
605 <C>{informix_special} {
606 /* are we simulating Informix? */
615 <C>{ccomment} { ECHO; }
620 yylval.ival = strtoul((char *)yytext,&endptr,16);
621 if (*endptr != '\0' || errno == ERANGE)
624 yylval.str = mm_strdup(yytext);
636 yylval.str = mm_strdup(yytext);
641 yylval.str = mm_strdup(yytext);
645 ScanKeyword *keyword;
646 struct _defines *ptr;
648 /* is it a define? */
649 for (ptr = defines; ptr; ptr = ptr->next)
651 if (strcmp(yytext, ptr->old) == 0)
653 struct _yy_buffer *yb;
655 yb = mm_alloc(sizeof(struct _yy_buffer));
657 yb->buffer = YY_CURRENT_BUFFER;
658 yb->lineno = yylineno;
659 yb->filename = mm_strdup(input_filename);
660 yb->next = yy_buffer;
664 yy_scan_string(ptr->new);
671 keyword = ScanCKeywordLookup(yytext);
673 return keyword->value;
676 yylval.str = mm_strdup(yytext);
681 <C>";" { return(';'); }
682 <C>"," { return(','); }
683 <C>"*" { return('*'); }
684 <C>"%" { return('%'); }
685 <C>"/" { return('/'); }
686 <C>"+" { return('+'); }
687 <C>"-" { return('-'); }
688 <C>"(" { return('('); }
689 <C>")" { return(')'); }
691 <C>\{ { return('{'); }
692 <C>\} { return('}'); }
693 <C>\[ { return('['); }
694 <C>\] { return(']'); }
695 <C>\= { return('='); }
696 <C>"->" { return(S_MEMBER); }
697 <C>">>" { return(S_RSHIFT); }
698 <C>"<<" { return(S_LSHIFT); }
699 <C>"||" { return(S_OR); }
700 <C>"&&" { return(S_AND); }
701 <C>"++" { return(S_INC); }
702 <C>"--" { return(S_DEC); }
703 <C>"==" { return(S_EQUAL); }
704 <C>"!=" { return(S_NEQUAL); }
705 <C>"+=" { return(S_ADD); }
706 <C>"-=" { return(S_SUB); }
707 <C>"*=" { return(S_MUL); }
708 <C>"/=" { return(S_DIV); }
709 <C>"%=" { return(S_MOD); }
710 <C>"->*" { return(S_MEMPOINT); }
711 <C>".*" { return(S_DOTPOINT); }
712 <C>{other} { return S_ANYTHING; }
714 <C>{exec_sql}{define}{space}* { BEGIN(def_ident); }
715 <C>{informix_special}{define}{space}* {
716 /* are we simulating Informix? */
727 <C>{exec_sql}{include}{space}* { BEGIN(incl); }
728 <C>{informix_special}{include}{space}* {
729 /* are we simulating Informix? */
740 <C,xskip>{exec_sql}{ifdef}{space}* { ifcond = TRUE; BEGIN(xcond); }
741 <C,xskip>{informix_special}{ifdef}{space}* {
742 /* are we simulating Informix? */
754 <C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
755 <C,xskip>{informix_special}{ifndef}{space}* {
756 /* are we simulating Informix? */
768 <C,xskip>{exec_sql}{elif}{space}* { /* pop stack */
769 if ( preproc_tos == 0 ) {
770 mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
772 else if ( stacked_if_value[preproc_tos].else_branch )
773 mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
777 ifcond = TRUE; BEGIN(xcond);
779 <C,xskip>{informix_special}{elif}{space}* {
780 /* are we simulating Informix? */
783 if ( preproc_tos == 0 ) {
784 mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
786 else if ( stacked_if_value[preproc_tos].else_branch )
787 mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
791 ifcond = TRUE; BEGIN(xcond);
800 <C,xskip>{exec_sql}{else}{space}*";" { /* only exec sql endif pops the stack, so take care of duplicated 'else' */
801 if ( stacked_if_value[preproc_tos].else_branch ) {
802 mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
805 stacked_if_value[preproc_tos].else_branch = TRUE;
806 stacked_if_value[preproc_tos].condition =
807 (stacked_if_value[preproc_tos-1].condition &&
808 ! stacked_if_value[preproc_tos].condition);
810 if ( stacked_if_value[preproc_tos].condition )
816 <C,xskip>{informix_special}{else}{space}* {
817 /* are we simulating Informix? */
820 if ( stacked_if_value[preproc_tos].else_branch ) {
821 mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
824 stacked_if_value[preproc_tos].else_branch = TRUE;
825 stacked_if_value[preproc_tos].condition =
826 (stacked_if_value[preproc_tos-1].condition &&
827 ! stacked_if_value[preproc_tos].condition);
829 if ( stacked_if_value[preproc_tos].condition )
841 <C,xskip>{exec_sql}{endif}{space}*";" {
842 if ( preproc_tos == 0 )
843 mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
847 if ( stacked_if_value[preproc_tos].condition )
852 <C,xskip>{informix_special}{endif}{space}*";" {
853 /* are we simulating Informix? */
856 if ( preproc_tos == 0 )
857 mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
861 if ( stacked_if_value[preproc_tos].condition )
873 <xskip>{other} { /* ignore */ }
875 <xcond>{identifier}{space}*";" {
876 if ( preproc_tos >= MAX_NESTED_IF-1 ) {
877 mmerror(PARSE_ERROR, ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
881 struct _defines *defptr;
884 /* skip the ";" and trailing whitespace. Note that yytext contains
885 at least one non-space character plus the ";" */
886 for ( i = strlen(yytext)-2;
887 i > 0 && isspace((unsigned char) yytext[i]);
892 for ( defptr = defines; defptr != NULL &&
893 ( strcmp(yytext, defptr->old) != 0 ); defptr = defptr->next );
896 stacked_if_value[preproc_tos].else_branch = FALSE;
897 stacked_if_value[preproc_tos].condition =
898 ( (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition );
901 if ( stacked_if_value[preproc_tos].condition )
907 <def_ident>{identifier} {
908 old = mm_strdup(yytext);
913 struct _defines *ptr, *this;
915 for (ptr = defines; ptr != NULL; ptr = ptr->next)
917 if (strcmp(old, ptr->old) == 0)
920 /* ptr->new = mm_strdup(scanstr(literalbuf));*/
921 ptr->new = mm_strdup(literalbuf);
926 this = (struct _defines *) mm_alloc(sizeof(struct _defines));
928 /* initial definition */
930 this->new = mm_strdup(literalbuf);
931 this->next = defines;
937 <def>[^;] { addlit(yytext, yyleng); }
939 <incl>\<[^\>]+\>{space}*";"? { parse_include(); }
940 <incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); }
941 <incl>[^;\<\>\"]+";" { parse_include(); }
944 if (yy_buffer == NULL) {
945 if ( preproc_tos > 0 )
948 mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
954 struct _yy_buffer *yb = yy_buffer;
960 yy_delete_buffer( YY_CURRENT_BUFFER );
961 yy_switch_to_buffer(yy_buffer->buffer);
963 yylineno = yy_buffer->lineno;
965 /* We have to output the filename only if we change files here */
966 i = strcmp(input_filename, yy_buffer->filename);
968 free(input_filename);
969 input_filename = yy_buffer->filename;
971 yy_buffer = yy_buffer->next;
975 output_line_number();
987 stacked_if_value[preproc_tos].condition = ifcond;
988 stacked_if_value[preproc_tos].else_branch = FALSE;
990 /* initialize literal buffer to a reasonable but expansible size */
991 if (literalbuf == NULL)
994 literalbuf = (char *) malloc(literalalloc);
1002 addlit(char *ytext, int yleng)
1004 /* enlarge buffer if needed */
1005 if ((literallen+yleng) >= literalalloc)
1009 while ((literallen+yleng) >= literalalloc);
1010 literalbuf = (char *) realloc(literalbuf, literalalloc);
1012 /* append new data, add trailing null */
1013 memcpy(literalbuf+literallen, ytext, yleng);
1014 literallen += yleng;
1015 literalbuf[literallen] = '\0';
1019 addlitchar(unsigned char ychar)
1021 /* enlarge buffer if needed */
1022 if ((literallen+1) >= literalalloc)
1025 literalbuf = (char *) realloc(literalbuf, literalalloc);
1027 /* append new data, add trailing null */
1028 literalbuf[literallen] = ychar;
1030 literalbuf[literallen] = '\0';
1036 /* got the include file name */
1037 struct _yy_buffer *yb;
1038 struct _include_path *ip;
1039 char inc_file[MAXPGPATH];
1042 yb = mm_alloc(sizeof(struct _yy_buffer));
1044 yb->buffer = YY_CURRENT_BUFFER;
1045 yb->lineno = yylineno;
1046 yb->filename = input_filename;
1047 yb->next = yy_buffer;
1052 * skip the ";" if there is one and trailing whitespace. Note that
1053 * yytext contains at least one non-space character plus the ";"
1055 for ( i = strlen(yytext)-2;
1056 i > 0 && isspace((unsigned char) yytext[i]);
1060 if (yytext[i] == ';')
1067 /* If file name is enclosed in '"' remove these and look only in '.' */
1068 /* Informix does look into all include paths though, except filename starts with '/' */
1069 if ((yytext[0] == '"' && yytext[i] == '"') && (compat != ECPG_COMPAT_INFORMIX || yytext[1] == '/'))
1072 memmove(yytext, yytext+1, strlen(yytext));
1074 strncpy(inc_file, yytext, sizeof(inc_file));
1075 yyin = fopen(inc_file, "r");
1078 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1080 strcat(inc_file, ".h");
1081 yyin = fopen(inc_file, "r");
1088 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
1091 memmove(yytext, yytext+1, strlen(yytext));
1094 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
1096 if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
1098 fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
1101 snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
1102 yyin = fopen(inc_file, "r");
1105 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1107 strcat(inc_file, ".h");
1108 yyin = fopen( inc_file, "r" );
1115 snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
1116 mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
1119 input_filename = mm_strdup(inc_file);
1120 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
1122 output_line_number();