%option nounput %option noinput %{ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: cflexor.lex,v 1.11 2007/03/22 16:08:18 steve Exp $" #endif # include "cfparse.h" # include "cfparse_misc.h" # include "globals.h" # include static int comment_enter; static char* trim_trailing_white(char*txt, int trim); /* * Mostly copied from the flex manual. Do not make this arbitrary * depth without checking for looping files. */ #define MAX_CMDFILE_DEPTH 15 typedef struct t_cmdfile { char *cmdfile; YY_BUFFER_STATE buffer; } s_cmdfile; s_cmdfile cmdfile_stack[MAX_CMDFILE_DEPTH]; int cmdfile_stack_ptr = 0; %} %x CCOMMENT %x LCOMMENT %x PLUS_ARGS %x FILE_NAME %% /* Accept C++ style comments. */ "//".* { comment_enter = YY_START; BEGIN(LCOMMENT); } . { yymore(); } \n { cflloc.first_line += 1; BEGIN(comment_enter); } /* Accept C style comments. */ "/*" { comment_enter = YY_START; BEGIN(CCOMMENT); } . { yymore(); } \n { cflloc.first_line += 1; yymore(); } "*/" { BEGIN(comment_enter); } /* Accept shell type comments. */ ^"#".* { ; } /* Skip white space. */ [ \t\f\r] { ; } /* Skip line ends, but also count the line. */ \n { cflloc.first_line += 1; } "+define+" { BEGIN(PLUS_ARGS); return TOK_DEFINE; } "+incdir+" { BEGIN(PLUS_ARGS); return TOK_INCDIR; } "+libdir+" { BEGIN(PLUS_ARGS); return TOK_LIBDIR; } "+libdir-nocase+" { BEGIN(PLUS_ARGS); return TOK_LIBDIR_NOCASE; } "+libext+" { BEGIN(PLUS_ARGS); return TOK_LIBEXT; } "+integer-width+" { BEGIN(PLUS_ARGS); return TOK_INTEGER_WIDTH; } /* If it is not any known plus-flag, return the generic form. */ "+"[^\n \t\b\f\r+]* { cflval.text = strdup(yytext); BEGIN(PLUS_ARGS); return TOK_PLUSWORD; } /* Once in PLUS_ARGS mode, words are delimited by + characters. White space and line end terminate PLUS_ARGS mode, but + terminates only the word. */ [^\n \t\b\f\r+]* { cflval.text = strdup(yytext); return TOK_PLUSARG; } /* Within plusargs, this is a delimiter. */ "+" { } /* White space end plus_args mode. */ [ \t\b\f\r] { BEGIN(0); } \n { cflloc.first_line += 1; BEGIN(0); } /* Notice the -a flag. */ "-a" { return TOK_Da; } /* Notice the -c or -f flag. */ "-c" { return TOK_Dc; } "-f" { return TOK_Dc; } /* Notice the -v flag. */ "-v" { return TOK_Dv; } /* Notice the -y flag. */ "-y" { return TOK_Dy; } /* This rule matches paths and strings that may be file names. This is a little bit tricky, as we don't want to mistake a comment for a string word. */ "/"[\r\n] { /* Special case of file name "/" */ cflval.text = trim_trailing_white(yytext, 0); return TOK_STRING; } "/"[^\*\/] { /* A file name that starts with "/". */ yymore(); BEGIN(FILE_NAME); } [^/\n \t\b\r+-][^/\n\r]* { /* A file name that starts with other than "/" */ yymore(); BEGIN(FILE_NAME); } "//" { /* Found a trailing comment. Returning the terminated name. */ cflval.text = trim_trailing_white(yytext, 2); BEGIN(LCOMMENT); return TOK_STRING; } "/"?[^/\n\r]* { yymore(); /* not a comment... continuing */; } [\n\r] { /* No trailing comment. Return the file name. */ cflval.text = trim_trailing_white(yytext, 0); BEGIN(0); return TOK_STRING; } /* Fallback match. */ . { return yytext[0]; } /* At the end of file switch back to the previous buffer. */ <> { if (--cmdfile_stack_ptr < 0) { free(current_file); yyterminate(); } else { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(cmdfile_stack[cmdfile_stack_ptr].buffer); free(current_file); current_file = cmdfile_stack[cmdfile_stack_ptr].cmdfile; } } %% static char* trim_trailing_white(char*text, int trim) { char*cp = text + strlen(text); while (cp > text && trim > 0) { trim -= 1; cp -= 1; *cp = 0; } while (cp > text && strchr("\n\r\t\b", cp[-1])) cp -= 1; cp[0] = 0; return strdup(text); } int yywrap() { return 1; } void switch_to_command_file(const char *file) { char path[4096]; char *cp; if (cmdfile_stack_ptr >= MAX_CMDFILE_DEPTH) { fprintf(stderr, "Error: command files nested too deeply (%d) " "at %s:%d.\n", MAX_CMDFILE_DEPTH, current_file, cflloc.first_line); exit(1); } cmdfile_stack[cmdfile_stack_ptr].buffer = YY_CURRENT_BUFFER; cmdfile_stack[cmdfile_stack_ptr].cmdfile = current_file; cmdfile_stack_ptr += 1; /* * If this is a relative file then add the current path to the * file name. */ if (file[0] != '/') { strcpy(path, current_file); cp = strrchr(path, '/'); if (cp == 0) strcpy(path, file); /* A base file. */ else { *(cp+1) = '\0'; strcat(path, file); } } else strcpy(path, file); /* An absolute path. */ yyin = fopen(path, "r"); if (yyin == NULL) { fprintf(stderr, "Error: unable to read nested command file (%s) " "at %s:%d.\n", path, current_file, cflloc.first_line); exit(1); } current_file = strdup(path); yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); cflloc.first_line = 1; } void cfreset(FILE*fd, const char*path) { yyin = fd; yyrestart(fd); current_file = strdup(path); cflloc.first_line = 1; }