Include and import file searching now searches for the file name given based on
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sun, 6 Apr 2008 23:49:01 +0000 (23:49 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sun, 6 Apr 2008 23:49:01 +0000 (23:49 +0000)
the location of the current file, not the program's current path. Additional
search locations can be given using the -I option.

git-svn-id: http://svn.complang.org/ragel/trunk@424 052ea7fc-9027-0410-9066-f65837a77df0

ragel/main.cpp
ragel/parsetree.cpp
ragel/parsetree.h
ragel/ragel.h
ragel/rlscan.h
ragel/rlscan.rl

index 00b03d0..bc80364 100644 (file)
@@ -73,9 +73,9 @@ bool printStatistics = false;
 bool frontendOnly = false;
 bool generateDot = false;
 
-typedef Vector<const char *> ArgsVector;
 ArgsVector frontendArgs;
 ArgsVector backendArgs;
+ArgsVector includePaths;
 
 /* Print a summary of the options. */
 void usage()
@@ -168,7 +168,7 @@ void escapeLineDirectivePath( std::ostream &out, char *path )
 
 void processArgs( int argc, char **argv, char *&inputFileName, char *&outputFileName )
 {
-       ParamCheck pc("xo:dnmleabjkS:M:CDJRAvHh?-:sT:F:G:P:LpV", argc, argv);
+       ParamCheck pc("xo:dnmleabjkS:M:I:CDJRAvHh?-:sT:F:G:P:LpV", argc, argv);
 
        while ( pc.check() ) {
                switch ( pc.state ) {
@@ -262,6 +262,16 @@ void processArgs( int argc, char **argv, char *&inputFileName, char *&outputFile
                                }
                                break;
 
+                       case 'I':
+                               if ( *pc.parameterArg == 0 )
+                                       error() << "please specify an argument to -I" << endl;
+                               else {
+                                       includePaths.append( pc.parameterArg );
+                                       frontendArgs.append( "-I" );
+                                       frontendArgs.append( pc.parameterArg );
+                               }
+                               break;
+
                        /* Host language types. */
                        case 'C':
                                hostLang = &hostLangC;
index 0230467..9450f74 100644 (file)
@@ -37,28 +37,28 @@ ostream &operator<<( ostream &out, const NameInst &nameInst );
 /* Convert the literal string which comes in from the scanner into an array of
  * characters with escapes and options interpreted. Also null terminates the
  * string. Though this null termination should not be relied on for
- * interpreting literals in the parser because the string may contain a
- * literal string with \0 */
-void Token::prepareLitString( Token &result, bool &caseInsensitive )
+ * interpreting literals in the parser because the string may contain \0 */
+char *prepareLitString( const InputLoc &loc, char *data, long length, 
+               long &resLen, bool &caseInsensitive )
 {
-       result.data = new char[this->length+1];
+       char *resData = new char[length+1];
        caseInsensitive = false;
 
-       char *src = this->data + 1;
-       char *end = this->data + this->length - 1;
+       char *src = data + 1;
+       char *end = data + length - 1;
 
        while ( *end != '\'' && *end != '\"' ) {
                if ( *end == 'i' )
                        caseInsensitive = true;
                else {
-                       error( this->loc ) << "literal string '" << *end << 
+                       error( loc ) << "literal string '" << *end << 
                                        "' option not supported" << endl;
                }
                end -= 1;
        }
 
-       char *dest = result.data;
-       int len = 0;
+       char *dest = resData;
+       long len = 0;
        while ( src != end ) {
                if ( *src == '\\' ) {
                        switch ( src[1] ) {
@@ -79,10 +79,11 @@ void Token::prepareLitString( Token &result, bool &caseInsensitive )
                        dest[len++] = *src++;
                }
        }
-       result.length = len;
-       result.data[result.length] = 0;
-}
 
+       resLen = len;
+       resData[resLen] = 0;
+       return resData;
+}
 
 FsmAp *VarDef::walk( ParseData *pd )
 {
@@ -1887,19 +1888,20 @@ FsmAp *Literal::walk( ParseData *pd )
        }
        case LitString: {
                /* Make the array of keys in int format. */
-               Token interp;
+               long length;
                bool caseInsensitive;
-               token.prepareLitString( interp, caseInsensitive );
-               Key *arr = new Key[interp.length];
-               makeFsmKeyArray( arr, interp.data, interp.length, pd );
+               char *data = prepareLitString( token.loc, token.data, token.length, 
+                               length, caseInsensitive );
+               Key *arr = new Key[length];
+               makeFsmKeyArray( arr, data, length, pd );
 
                /* Make the new machine. */
                rtnVal = new FsmAp();
                if ( caseInsensitive )
-                       rtnVal->concatFsmCI( arr, interp.length );
+                       rtnVal->concatFsmCI( arr, length );
                else
-                       rtnVal->concatFsm( arr, interp.length );
-               delete[] interp.data;
+                       rtnVal->concatFsm( arr, length );
+               delete[] data;
                delete[] arr;
                break;
        }}
index 7e35c34..fe0db4f 100644 (file)
@@ -198,11 +198,13 @@ struct Token
        int length;
        InputLoc loc;
 
-       void prepareLitString( Token &result, bool &caseInsensitive );
        void append( const Token &other );
        void set( const char *str, int len );
 };
 
+char *prepareLitString( const InputLoc &loc, char *src, long length, 
+                       long &resLen, bool &caseInsensitive );
+
 /* Store the value and type of a priority augmentation. */
 struct PriorityAug
 {
index 2484773..bbb2e93 100644 (file)
@@ -26,6 +26,7 @@
 #include <iostream>
 #include <fstream>
 #include <string>
+#include "vector.h"
 #include "config.h"
 
 #define PROGNAME "ragel"
@@ -72,4 +73,7 @@ void terminateAllParsers( );
 void writeMachines( std::ostream &out, std::string hostData, char *inputFileName );
 void xmlEscapeHost( std::ostream &out, char *data, long len );
 
+typedef Vector<const char *> ArgsVector;
+extern ArgsVector includePaths;
+
 #endif /* _RAGEL_H */
index 80ed52f..acbc40b 100644 (file)
@@ -69,15 +69,13 @@ struct Scanner
 
        bool recursiveInclude( char *inclFileName, char *inclSectionName );
 
-       char *prepareFileName( char *fileName, int len )
-       {
-               bool caseInsensitive;
-               Token tokenFnStr, tokenRes;
-               tokenFnStr.data = fileName;
-               tokenFnStr.length = len;
-               tokenFnStr.prepareLitString( tokenRes, caseInsensitive );
-               return tokenRes.data;
-       }
+       /* Make a list of places to look for an included file. */
+       char **makeIncludePathChecks( char *curFileName, char *fileName, int len );
+       std::ifstream *tryOpenInclude( char **pathChecks, long &found );
+
+       void handleMachine();
+       void handleInclude();
+       void handleImport();
 
        void init();
        void token( int type, char *start, char *end );
index d450fe1..39dd29b 100644 (file)
@@ -41,6 +41,12 @@ enum InlineBlockType
        SemiTerminated
 };
 
+#ifdef WIN32
+#define PATH_SEP '\\'
+#else
+#define PATH_SEP '/'
+#endif
+
 
 /*
  * The Scanner for Importing
@@ -262,85 +268,71 @@ void Scanner::updateCol()
        lastnl = 0;
 }
 
-%%{
-       machine section_parse;
-
-       # Need the defines representing tokens.
-       import "rlparse.h"; 
+void Scanner::handleMachine()
+{
+       /* Assign a name to the machine. */
+       char *machine = word;
+
+       if ( !importMachines && inclSectionTarg == 0 ) {
+               ignoreSection = false;
+
+               ParserDictEl *pdEl = parserDict.find( machine );
+               if ( pdEl == 0 ) {
+                       pdEl = new ParserDictEl( machine );
+                       pdEl->value = new Parser( fileName, machine, sectionLoc );
+                       pdEl->value->init();
+                       parserDict.insert( pdEl );
+               }
 
-       action clear_words { word = lit = 0; word_len = lit_len = 0; }
-       action store_word { word = tokdata; word_len = toklen; }
-       action store_lit { lit = tokdata; lit_len = toklen; }
+               parser = pdEl->value;
+       }
+       else if ( !importMachines && strcmp( inclSectionTarg, machine ) == 0 ) {
+               /* found include target */
+               ignoreSection = false;
+               parser = inclToParser;
+       }
+       else {
+               /* ignoring section */
+               ignoreSection = true;
+               parser = 0;
+       }
+}
 
-       action mach_err { scan_error() << "bad machine statement" << endl; }
-       action incl_err { scan_error() << "bad include statement" << endl; }
-       action import_err { scan_error() << "bad import statement" << endl; }
-       action write_err { scan_error() << "bad write statement" << endl; }
+void Scanner::handleInclude()
+{
+       if ( active() ) {
+               char *inclSectionName = word;
+               char **inclFileName = 0;
 
-       action handle_machine
-       {
-               /* Assign a name to the machine. */
-               char *machine = word;
-
-               if ( !importMachines && inclSectionTarg == 0 ) {
-                       ignoreSection = false;
-
-                       ParserDictEl *pdEl = parserDict.find( machine );
-                       if ( pdEl == 0 ) {
-                               pdEl = new ParserDictEl( machine );
-                               pdEl->value = new Parser( fileName, machine, sectionLoc );
-                               pdEl->value->init();
-                               parserDict.insert( pdEl );
-                       }
+               /* Implement defaults for the input file and section name. */
+               if ( inclSectionName == 0 )
+                       inclSectionName = parser->sectionName;
 
-                       parser = pdEl->value;
-               }
-               else if ( !importMachines && strcmp( inclSectionTarg, machine ) == 0 ) {
-                       /* found include target */
-                       ignoreSection = false;
-                       parser = inclToParser;
-               }
+               if ( lit != 0 )
+                       inclFileName = makeIncludePathChecks( fileName, lit, lit_len );
                else {
-                       /* ignoring section */
-                       ignoreSection = true;
-                       parser = 0;
-               }
-       }
-
-       machine_stmt =
-               ( KW_Machine TK_Word @store_word ';' ) @handle_machine
-               <>err mach_err <>eof mach_err;
-
-       action handle_include
-       {
-               if ( active() ) {
-                       char *inclSectionName = word;
-                       char *inclFileName = 0;
+                       char *test = new char[strlen(fileName)+1];
+                       strcpy( test, fileName );
 
-                       /* Implement defaults for the input file and section name. */
-                       if ( inclSectionName == 0 )
-                               inclSectionName = parser->sectionName;
+                       inclFileName = new char*[2];
 
-                       if ( lit != 0 ) 
-                               inclFileName = prepareFileName( lit, lit_len );
-                       else
-                               inclFileName = fileName;
+                       inclFileName[0] = test;
+                       inclFileName[1] = 0;
+               }
 
+               long found = 0;
+               ifstream *inFile = tryOpenInclude( inclFileName, found );
+               if ( inFile == 0 )
+                       scan_error() << "include: failed to locate file" << endl;
+               else {
                        /* Check for a recursive include structure. Add the current file/section
                         * name then check if what we are including is already in the stack. */
                        includeStack.append( IncludeStackItem( fileName, parser->sectionName ) );
 
-                       if ( recursiveInclude( inclFileName, inclSectionName ) )
+                       if ( recursiveInclude( inclFileName[found], inclSectionName ) )
                                scan_error() << "include: this is a recursive include operation" << endl;
                        else {
-                               /* Open the input file for reading. */
-                               ifstream *inFile = new ifstream( inclFileName );
-                               if ( ! inFile->is_open() ) {
-                                       scan_error() << "include: could not open " << 
-                                                       inclFileName << " for reading" << endl;
-                               }
-
-                               Scanner scanner( inclFileName, *inFile, output, parser,
+                               Scanner scanner( inclFileName[found], *inFile, output, parser,
                                                inclSectionName, includeDepth+1, false );
                                scanner.do_scan( );
                                delete inFile;
@@ -350,6 +342,52 @@ void Scanner::updateCol()
                        includeStack.remove( -1 );
                }
        }
+}
+
+void Scanner::handleImport()
+{
+       if ( active() ) {
+               char **importFileName = makeIncludePathChecks( fileName, lit, lit_len );
+
+               /* Open the input file for reading. */
+               long found = 0;
+               ifstream *inFile = tryOpenInclude( importFileName, found );
+               if ( inFile == 0 ) {
+                       scan_error() << "import: could not open import file " <<
+                                       "for reading" << endl;
+               }
+
+               Scanner scanner( importFileName[found], *inFile, output, parser,
+                               0, includeDepth+1, true );
+               scanner.do_scan( );
+               scanner.importToken( 0, 0, 0 );
+               scanner.flushImport();
+               delete inFile;
+       }
+}
+
+%%{
+       machine section_parse;
+
+       # Need the defines representing tokens.
+       import "rlparse.h"; 
+
+       action clear_words { word = lit = 0; word_len = lit_len = 0; }
+       action store_word { word = tokdata; word_len = toklen; }
+       action store_lit { lit = tokdata; lit_len = toklen; }
+
+       action mach_err { scan_error() << "bad machine statement" << endl; }
+       action incl_err { scan_error() << "bad include statement" << endl; }
+       action import_err { scan_error() << "bad import statement" << endl; }
+       action write_err { scan_error() << "bad write statement" << endl; }
+
+       action handle_machine { handleMachine(); }
+       action handle_include { handleInclude(); }
+       action handle_import { handleImport(); }
+
+       machine_stmt =
+               ( KW_Machine TK_Word @store_word ';' ) @handle_machine
+               <>err mach_err <>eof mach_err;
 
        include_names = (
                TK_Word @store_word ( TK_Literal @store_lit )? |
@@ -360,27 +398,6 @@ void Scanner::updateCol()
                ( KW_Include include_names ';' ) @handle_include
                <>err incl_err <>eof incl_err;
 
-       action handle_import
-       {
-               if ( active() ) {
-                       char *importFileName = prepareFileName( lit, lit_len );
-
-                       /* Open the input file for reading. */
-                       ifstream *inFile = new ifstream( importFileName );
-                       if ( ! inFile->is_open() ) {
-                               scan_error() << "import: could not open " << 
-                                               importFileName << " for reading" << endl;
-                       }
-
-                       Scanner scanner( importFileName, *inFile, output, parser,
-                                       0, includeDepth+1, true );
-                       scanner.do_scan( );
-                       scanner.importToken( 0, 0, 0 );
-                       scanner.flushImport();
-                       delete inFile;
-               }
-       }
-
        import_stmt =
                ( KW_Import TK_Literal @store_lit ';' ) @handle_import
                <>err import_err <>eof import_err;
@@ -520,6 +537,79 @@ void Scanner::endSection( )
        }
 }
 
+bool isAbsolutePath( const char *path )
+{
+#ifdef WIN32
+       return isalpha( path[0] ) && path[1] == ':' && path[2] == '\\';
+#else
+       return path[0] == '/';
+#endif
+}
+
+char **Scanner::makeIncludePathChecks( char *thisFileName, char *fileName, int fnlen )
+{
+       char **checks = new char*[2];
+       long nextCheck = 0;
+
+       bool caseInsensitive = false;
+       long length = 0;
+       char *data = prepareLitString( InputLoc(), fileName, fnlen, 
+                       length, caseInsensitive );
+
+       /* Absolute path? */
+       if ( isAbsolutePath( data ) )
+               checks[nextCheck++] = data;
+       else {
+               /* Search from the the location of the current file. */
+               const char *lastSlash = strrchr( thisFileName, PATH_SEP );
+               if ( lastSlash == 0 )
+                       checks[nextCheck++] = data;
+               else {
+                       long givenPathLen = (lastSlash - thisFileName) + 1;
+                       long checklen = givenPathLen + length;
+                       char *check = new char[checklen+1];
+                       memcpy( check, thisFileName, givenPathLen );
+                       memcpy( check+givenPathLen, data, length );
+                       check[checklen] = 0;
+                       checks[nextCheck++] = check;
+               }
+
+               /* Search from the include paths given on the command line. */
+               for ( ArgsVector::Iter incp = includePaths; incp.lte(); incp++ ) {
+                       long pathLen = strlen( *incp );
+                       long checkLen = pathLen + 1 + length;
+                       char *check = new char[checkLen+1];
+                       memcpy( check, *incp, pathLen );
+                       check[pathLen] = PATH_SEP;
+                       memcpy( check+pathLen+1, data, length );
+                       check[checkLen] = 0;
+                       checks[nextCheck++] = check;
+               }
+       }
+
+       checks[nextCheck] = 0;
+       return checks;
+}
+
+ifstream *Scanner::tryOpenInclude( char **pathChecks, long &found )
+{
+       char **check = pathChecks;
+       ifstream *inFile = new ifstream;
+       
+       while ( *check != 0 ) {
+               inFile->open( *check );
+               if ( inFile->is_open() ) {
+                       found = check - pathChecks;
+                       return inFile;
+               }
+               check += 1;
+       }
+
+       found = -1;
+       delete inFile;
+       return 0;
+}
+
 %%{
        machine rlscan;