Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

ParseImports.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Created on Mon Jul 14 10:52:08 PDT 1997 by heydon
00020 
00021 #include <sys/types.h> // for stat(2)
00022 #include <sys/stat.h>  // for stat(2)
00023 #if defined(__digital__)
00024 #include <sys/mode.h>  // for testing if a path is a directory
00025 #endif
00026 #include <strings.h>   // for index(3)
00027 #include <errno.h>
00028 
00029 #include <Basics.H>
00030 #include <Sequence.H>
00031 #include <FS.H>
00032 #include "ParseImports.H"
00033 
00034 using std::ostream;
00035 
00036 // Char_Buff
00037 
00038 // An efficient character buffer.  Attempts to strike a balance
00039 // between the use of a fixed array for efficiency during lexical
00040 // analysis and allowing arbitrarily long strings to be collected.
00041 // (Implemented in order to alleviate a buffer overrun with a fixed
00042 // length buffer with no mechanism for overflow.)
00043 
00044 struct Char_Buff
00045 {
00046   // A fixed-length array which allows fast appending of individual
00047   // characaters.
00048   static const unsigned int len = 100;
00049   char chars[len+1];
00050 
00051   // The current position in appending to the array.
00052   unsigned int pos;
00053 
00054   // Text previously flushed from the fixed-length buffer (due to
00055   // overflows, etc.)
00056   Text content;
00057 
00058   inline Char_Buff()
00059     : pos(0)
00060   {
00061   }
00062 
00063   // Flush characters written to the fixed-length array to variable
00064   // length storage (possibly due to an overflow).
00065   inline void flush()
00066   {
00067     if(pos > 0)
00068       {
00069         chars[pos] = 0;
00070         content += chars;
00071         pos = 0;
00072       }
00073   }
00074 
00075   // Discard whetever characters have been accumulated and start over.
00076   inline void reset()
00077   {
00078     content = "";
00079     pos = 0;
00080   }
00081 
00082   // Make sure that we can append n characters to the fixed-length
00083   // array.
00084   inline void expect(unsigned int n)
00085   {
00086     // If this would push us past the limit of the fixed-length
00087     // array...
00088     if((pos + n) >= len)
00089       {
00090         // Flush to variable size storage.
00091         flush();
00092       }
00093   }
00094 
00095   // Return the total number of characters buffered, avoiding a call
00096   // to strlen when possible.
00097   inline unsigned int length()
00098   {
00099     return pos + (content.Empty() ? 0 : content.Length());
00100   }
00101 
00102   // Append a character to the buffer.
00103   inline Char_Buff &operator +=(char c)
00104   {
00105     expect(1);
00106     chars[pos++] = c;
00107     return *this;
00108   }
00109 
00110   // Remove and return the last character appended (think "ungetc").
00111   inline char pop()
00112   {
00113     // If there are characters in the fixed-length array, take the
00114     // last of those.
00115     if(pos > 0)
00116       {
00117         return chars[--pos];
00118       }
00119     // If we have no characters at all, return 0.
00120     else if(content.Empty())
00121       {
00122         // We should really throw an exception here.
00123         return 0;
00124       }
00125     // Extract and remove the last character from the variable size
00126     // storage.
00127     else
00128       {
00129         unsigned int clen = content.Length();
00130         char c = content[clen-1];
00131         content = content.Sub(0, clen-1);
00132         return c;
00133       }
00134   }
00135 
00136   // Provide equality and inequality operators which can avoid the
00137   // cost of an allocation when there are a small number of characters
00138   // in the buffer.
00139   inline bool operator ==(const char *text)
00140   {
00141     if(content.Empty())
00142       {
00143         chars[pos] = 0;
00144         return (strcmp(text, chars) == 0);
00145       }
00146     else
00147       {
00148         flush();
00149         return (content == text);
00150       }
00151   }
00152   inline bool operator !=(const char *text)
00153   {
00154     if(content.Empty())
00155       {
00156         chars[pos] = 0;
00157         return (strcmp(text, chars) != 0);
00158       }
00159     else
00160       {
00161         flush();
00162         return (content != text);
00163       }
00164   }
00165 
00166   // Return the first character in the buffer.  Used to test for
00167   // one-chacater tokens.
00168   inline char first() const throw()
00169   {
00170     return (content.Empty() ? chars[0] : content[0]);
00171   }
00172 };
00173 
00174 ostream&
00175 operator<<(ostream &os, const ParseImports::Error &err) throw ()
00176 {
00177     return (os << err.msg);
00178 }
00179 
00180 // Implementation of ParseImports::LocalModelSpace
00181 
00182 char
00183 ParseImports::LocalModelSpace::getC()
00184   throw (ParseImports::Error, FS::EndOfFile)
00185 /* Read and return the next character. Throws "Error" in the event
00186    of a read error, and "FS::EndOfFile" if EOF is encountered. */
00187 {
00188     int c = ifs.get();
00189     if (c == EOF || ifs.eof()) throw FS::EndOfFile();
00190     if (ifs.fail()) throw ParseImports::Error("failure reading model");
00191     return (char)c;
00192 }
00193 
00194 ParseImports::ModelSpace*
00195 ParseImports::LocalModelSpace::open(const Text &modelname) const
00196   throw(ParseImports::Error, FS::Failure, FS::DoesNotExist)
00197 {
00198   return NEW_CONSTR(LocalModelSpace, (modelname));
00199 }
00200 
00201 ParseImports::LocalModelSpace::LocalModelSpace(const Text &modelname)
00202   throw(FS::Failure, FS::DoesNotExist)
00203 {
00204   try
00205     {
00206       FS::OpenReadOnly(modelname, /*OUT*/ this->ifs);
00207     }
00208   catch (FS::DoesNotExist)
00209     {
00210       errno = ENOENT; // set errno to indicate non-existent file
00211       throw FS::DoesNotExist();
00212     }
00213 }
00214 
00215 ParseImports::ModelSpace::type
00216 ParseImports::LocalModelSpace::getType(const Text &name) const throw()
00217 {
00218     struct stat stat_buff;
00219     int stat_res = stat(name.cchars(), &stat_buff);
00220     if (stat_res == 0) {
00221       if (S_ISDIR(stat_buff.st_mode)) {
00222         return ParseImports::ModelSpace::directory;
00223       }
00224       if (S_ISREG(stat_buff.st_mode)) {
00225         return ParseImports::ModelSpace::file;
00226       }
00227     }
00228     return ParseImports::ModelSpace::none;
00229 }
00230 
00231 // end of LocalModelSpace implementation
00232 
00233 static void
00234 SkipOneLineComment(ParseImports::ModelSpace &model) throw (ParseImports::Error)
00235 /* Skip characters in model up to and including the next newline. */
00236 {
00237     try {
00238         while (model.getC() != '\n') /* SKIP */;
00239     } catch (FS::EndOfFile) {
00240         throw ParseImports::Error("premature EOF in // comment");
00241     }
00242 }
00243 
00244 static Text
00245 SkipBracketedComment(ParseImports::ModelSpace &model)
00246      throw (ParseImports::Error)
00247 /* Skip characters in model until end-of-comment bracket characters
00248    are read. If the first character of the comment is '*', then the
00249    comment is assumed to be a pragma, and the contents of the pragma
00250    are returned; otherwise, returns the empty string. */
00251 {
00252     try {
00253         bool inPragma = false;
00254         Char_Buff pragma;
00255         char last = model.getC(), c;
00256         if (last == '*') inPragma = true;
00257         while ((c = model.getC()) != '/' || last != '*') {
00258             if (inPragma) {
00259                 pragma += c;
00260             }
00261             last = c;
00262         }
00263         if (inPragma) {
00264             if (pragma.length() < 1) {
00265                 // comment of the form "/**/"; not a pragma
00266                 inPragma = false;
00267             } else {
00268                 pragma.flush();
00269                 int len = pragma.content.Length();
00270                 int i = len;
00271                 while (i > 0 && pragma.content[i-1] == '*') i--;
00272                 assert(i < len);
00273                 pragma.content = pragma.content.Sub(0, i);
00274             }
00275         }
00276         // NOTE: The following can produce a dangling pointer if this
00277         // program is not linked with the garbage collector!
00278         return (inPragma ? pragma.content : Text(""));
00279     }
00280     catch (FS::EndOfFile) {
00281         throw ParseImports::Error("premature EOF in /*...*/ comment");
00282     }
00283 }
00284 
00285 static Text
00286 SkipWhite(ParseImports::ModelSpace &model, Char_Buff &buff)
00287   throw (ParseImports::Error, FS::EndOfFile)
00288 /* Skip whitespace and comments in model, storing the first meaningful
00289    character read into "buff" and setting "pos" to 1. The the white space
00290    ends in a pragma, the contents of the pragma are returned; otherwise,
00291    returns NULL. */
00292 {
00293     Text res("");
00294     char c;
00295     while (true) {
00296         while ((c = model.getC()) == ' ' || c == '\n' || c == '\t') /*SKIP*/;
00297         buff.reset();
00298         buff += c;
00299         if (c != '/') break;
00300         c = model.getC();
00301         buff += c;
00302         switch (c) {
00303           case '/':
00304             SkipOneLineComment(model);
00305             res = "";
00306             break;
00307           case '*':
00308             res = SkipBracketedComment(model);
00309             break;
00310           default:
00311             model.ungetC(buff.pop());
00312             return res;
00313         }
00314     }
00315     return res;
00316 }
00317 
00318 static void
00319 Scan(ParseImports::ModelSpace &model, Char_Buff &buff,
00320      const char *stopChars) throw (ParseImports::Error)
00321 /* Read characters from model into "buff" starting at position "pos" until one
00322    of the characters in "stopChars" is read or EOF is encountered. If one of
00323    the characters in "stopChars" is read, it is returned to the stream. It is
00324    a checked run-time error to try to put more than "buffLen" characters into
00325    "buff". Set "pos" on exit to the total number of characters in "buff". */
00326 {
00327     char c;
00328     try {
00329         while (true) {
00330             c = model.getC();
00331             if (index(stopChars, c) != (char *)NULL) {
00332                 model.ungetC(c);
00333                 break;
00334             }
00335             buff += c;
00336         }
00337     }
00338     catch (FS::EndOfFile) {
00339         /* SKIP */
00340     }
00341 }
00342 
00343 // an interval
00344 class Intv {
00345 public:
00346   int start, end;
00347   Text pragma;
00348 };
00349 
00350 static Intv
00351 Lex(ParseImports::ModelSpace &model, Char_Buff &buff)
00352   throw (ParseImports::Error, FS::EndOfFile)
00353 /* Read the next lexeme from model, and return it in "buff" as a
00354    null-terminated string. Any initial whitespace and comments are skipped.
00355    Returns the position in model of the first non-whitespace character read
00356    into "buff". "buffLen" specifies the length of the buffer "buff"; it a
00357    checked run-time error to read a lexeme that is too long to fit in the
00358    buffer. */
00359 {
00360     Intv res;
00361     res.pragma = SkipWhite(model, buff);
00362     assert(buff.length() == 1);
00363     try {
00364         res.start = model.tell() - 1;
00365         if (index("=;,{}[]", buff.first()) == (char *)NULL) {
00366             // not a one-character lexeme; scan rest of lexeme
00367             Scan(model, buff, "=;,[]{} \t\n");
00368         }
00369         buff.flush();
00370         res.end = model.tell();
00371     }
00372     catch (FS::Failure) {
00373         throw ParseImports::Error("failure reading model");
00374     }
00375     return res;
00376 }
00377 
00378 // remove double-quotes from a string.  (Note that this doesn't check
00379 // for balanced quotes or any sort of escaping, it simply removes all
00380 // double-quote characters from the string.)
00381 static Text StripQuotes(const Text &in)
00382 {
00383   Text result = in;
00384 
00385   int start = 0, match;
00386   while ((match = result.FindChar('"', start)) >= 0) {
00387     result = result.Sub(0, match) + result.Sub(match+1);
00388     start = match;
00389   }
00390 
00391   return result;
00392 }
00393 
00394 Text
00395 ParseImports::ResolvePath(const Text &path, const Text &wd,
00396                           const ParseImports::ModelSpace *ms)
00397   throw (ParseImports::Error, FS::Failure, SRPC::failure)
00398 {
00399     if (ms == NULL) {
00400       ms = NEW(LocalModelSpace);
00401     }
00402     Text fullPath(path);
00403 
00404     // remove double-quotes from "fullPath"
00405     fullPath = StripQuotes(fullPath);
00406 
00407     // make "fullPath" absolute
00408     if (fullPath[0] != '/') {
00409         fullPath = wd + fullPath;
00410     }
00411 
00412     switch (ms->getType(fullPath)) {
00413     case ParseImports::ModelSpace::directory:
00414       // "fullPath" is a directory; append "/build.ves"
00415       fullPath += (fullPath[fullPath.Length()-1] == '/')
00416         ? "build.ves" : "/build.ves";
00417       break;
00418 
00419     case ParseImports::ModelSpace::file:
00420     default:
00421       break;
00422 
00423     case ParseImports::ModelSpace::none:
00424       // Try appending .ves if not already there
00425       if (fullPath.Sub(fullPath.Length()-4) != Text(".ves")) {
00426         Text fullPath2(fullPath); fullPath2 += ".ves";  
00427         if (ms->getType(fullPath2) == ParseImports::ModelSpace::file) {
00428           fullPath = fullPath2;
00429         }
00430       }
00431       break;
00432     }
00433 
00434     return fullPath;
00435 }
00436 
00437 static void
00438 AddPath(/*INOUT*/ ImportSeq &seq, const Text &orig,
00439         const Text &path, const ImportID &id, const Text &wd, const Intv &bounds, 
00440         const ParseImports::ModelSpace &ms, bool fromForm=false)
00441   throw (ParseImports::Error, FS::Failure, SRPC::failure)
00442 {
00443     // form full pathname
00444     // Also, allow pathname to be entirely in quotes, 
00445     // as in from "/vesta/foo.bar.net/project/" import ...
00446     bool local = !((path[0] == '"' && path[1] == '/') || (path[0] == '/'));
00447     Text fullPath(ParseImports::ResolvePath(path, wd, &ms));
00448 
00449     // allocate new "Import" object with proper parameters
00450     bool noUpdate = ((bounds.pragma == "NOUPDATE") ||
00451                      (bounds.pragma == "noupdate"));
00452     Import *imp = NEW_CONSTR(Import, (fullPath, orig, id, bounds.start, bounds.end,
00453                                       local, fromForm, noUpdate));
00454 
00455     // add "fullPath" to "seq"
00456     seq.addhi(imp);
00457 }
00458 
00459 static void
00460 AddFromPath(/*INOUT*/ ImportSeq &seq, const Text &orig, const Text &path, 
00461             const ImportID &id, const Text &wd, const Intv &bounds,
00462             const ParseImports::ModelSpace &ms)
00463   throw (ParseImports::Error, FS::Failure, SRPC::failure)
00464 {
00465     AddPath(/*INOUT*/ seq, orig, path, id, wd, bounds, ms, /*fromForm=*/ true);
00466 }
00467 
00468 static void
00469 ExpectToken(const char *expected, Char_Buff &found)
00470   throw (ParseImports::Error)
00471 {
00472   if (found != expected)
00473     {
00474       Text msg("expecting '");
00475       msg += expected;
00476       msg += "'; found '";
00477       // Note that found is non-const as we need to flush it.
00478       found.flush();
00479       msg += found.content;
00480       msg += "'";
00481       throw ParseImports::Error(msg);
00482     }
00483 }
00484 
00485 static void
00486 ReadIncIdReq(ParseImports::ModelSpace &model, Char_Buff &buff,
00487              const Text &wd, /*INOUT*/ ImportSeq &seq)
00488      throw (ParseImports::Error, FS::EndOfFile, FS::Failure, SRPC::failure)
00489 /* Grammar to process:
00490 |    IncIdReq  ::= import IncItemR*;
00491 |    IncItemR  ::= IncSpecR | IncListR
00492 |    IncSpecR  ::= Id = DelimPath
00493 |    IncListR  ::= Id = `[' IncSpecR*, `]'
00494 */
00495 {
00496     // skip "import"
00497     ExpectToken("import", buff);
00498     (void)Lex(model, buff);
00499     buff.flush();
00500     Text id(StripQuotes(buff.content));
00501     ImportID import_id;
00502     import_id.addhi(id);
00503 
00504     // read IncItemR's
00505     while ((buff != "import") && (buff != "from") &&
00506            (buff != "{")) {
00507         // skip initial Id
00508         (void)Lex(model, buff);
00509 
00510         // skip "="
00511         ExpectToken("=", buff);
00512         Intv bounds = Lex(model, buff);
00513 
00514         // determine if this is a IncSpecR or an IncListR
00515         if (buff != "[") {
00516           // IncSpecR
00517           buff.flush();
00518           Text orig(buff.content);
00519           AddPath(/*INOUT*/ seq, orig, orig, import_id, wd, bounds, model);
00520         } else {
00521             // IncListR
00522             (void)Lex(model, buff);
00523             buff.flush();
00524             id = StripQuotes(buff.content);
00525             import_id.addhi(id);
00526             while (buff != "]") {
00527                 // skip Id
00528                 (void)Lex(model, buff);
00529 
00530                 // skip "="
00531                 ExpectToken("=", buff);
00532                 Intv bounds = Lex(model, buff);
00533 
00534                 // process path
00535                 buff.flush();
00536                 Text orig(buff.content);
00537                 AddPath(/*INOUT*/ seq, orig, orig, import_id, wd, bounds, model);
00538                 (void)Lex(model, buff);
00539 
00540                 // skip trailing "," if present
00541                 if (buff == ",") {
00542                     (void)Lex(model, buff);
00543                     buff.flush();
00544                     import_id.remhi();
00545                     id = StripQuotes(buff.content);
00546                     import_id.addhi(id);
00547                 } else {
00548                     ExpectToken("]", buff);
00549                 }
00550             }
00551             import_id.remhi();
00552         }
00553         (void)Lex(model, buff);
00554 
00555         // skip trailing ";" if present
00556         if (buff == ";") {
00557             (void)Lex(model, buff);
00558             buff.flush();
00559             import_id.remhi();
00560             id = StripQuotes(buff.content);
00561             import_id.addhi(id);
00562         } else {
00563             // last element -- exit loop
00564             break;
00565         }
00566     }
00567     import_id.remhi();
00568 }
00569 
00570 static void
00571 ReadIncIdOpt(ParseImports::ModelSpace &model, Char_Buff &buff,
00572   const Text &wd, /*INOUT*/ ImportSeq &seq)
00573   throw (ParseImports::Error, FS::EndOfFile)
00574 /* Grammar to process:
00575 |    IncIdOpt ::= from DelimPath import IncItemO*;
00576 |    IncItemO ::= IncSpecO | IncListO
00577 |    IncSpecO ::= [ Id = ] Path [ Delim ]
00578 |    IncListO ::= Id = `[' IncSpecO*, `]'
00579 */
00580 {
00581     // skip "from"
00582     ExpectToken("from", buff);
00583     (void)Lex(model, buff);
00584 
00585     // remember DelimPath
00586     buff.flush();
00587     Text rootPath(buff.content);
00588     if (rootPath[rootPath.Length()-1] != '/') {
00589         rootPath += '/';
00590     }
00591     (void)Lex(model, buff);
00592 
00593     // skip "import"
00594     ExpectToken("import", buff);
00595     Intv bounds = Lex(model, buff);
00596 
00597     ImportID import_id;
00598     
00599     while ((buff != "import") && (buff != "from") &&
00600            (buff != "{")) {
00601 
00602         // save current lexeme in case we are in IncSpecO case w/ no "Id ="
00603         buff.flush();
00604         Text path(buff.content);
00605         (void)Lex(model, buff);
00606 
00607         // test for "="
00608         if (buff != "=") {
00609           // we were in the IncSpecO case with no leading "Id =". The
00610           // id is the the first segment of path.
00611           int first_slash = path.FindChar('/');
00612           Text id = StripQuotes((first_slash>0)
00613                                 ?path.Sub(0, first_slash)
00614                                 :path);
00615           import_id.addhi(id);
00616 
00617           AddFromPath(/*INOUT*/ seq, path, rootPath+path, import_id,
00618                       wd, bounds, model);
00619         } else {
00620             // we could now be in either the IncSpecO or IncListO case
00621             bounds = Lex(model, buff); // read token after "="
00622             if (buff != "[") {
00623                 Text id(StripQuotes(path));
00624                 import_id.addhi(id);
00625                 // IncSpecO case with leading "Id ="
00626                 buff.flush();
00627                 Text path(buff.content);
00628                 AddFromPath(/*INOUT*/ seq, path, rootPath+path, import_id, 
00629                             wd, bounds, model);
00630             } else {
00631                 // IncListO case
00632               Text id(StripQuotes(path));
00633               import_id.addhi(id);
00634                 bounds = Lex(model, buff); // read token after "["
00635                 while (buff != "]") {
00636                     // remember lexeme
00637                     buff.flush();
00638                     Text path(buff.content);
00639                     (void)Lex(model, buff); // read "=", ",", or "]"
00640 
00641                     // determine if we are in "Id =" case or not
00642                     if (buff != "=") {
00643                       int first_slash = path.FindChar('/');
00644                       Text id = StripQuotes((first_slash>0)
00645                                             ?path.Sub(0, first_slash)
00646                                             :path);
00647                       import_id.addhi(id);
00648                       AddFromPath(/*INOUT*/ seq, path, rootPath+path, import_id,
00649                                   wd, bounds, model);
00650                     } else {
00651                         Text id(StripQuotes(path));
00652                         import_id.addhi(id);
00653                         // read path
00654                         bounds = Lex(model, buff);
00655                         buff.flush();
00656                         Text path(buff.content);
00657                         AddFromPath(/*INOUT*/ seq,  path, rootPath+path, import_id, 
00658                                     wd, bounds, model);
00659                         (void)Lex(model, buff); // read "," or "]"
00660                     }
00661 
00662                     import_id.remhi();
00663                     // skip trailing "," if present
00664                     if (buff == ",") {
00665                         bounds = Lex(model, buff);
00666                     } else {
00667                         ExpectToken("]", buff);
00668                     }
00669                 }
00670                 import_id.remhi();
00671             }
00672             (void)Lex(model, buff);
00673         }
00674 
00675         // skip trailing ";" if present
00676         if (buff == ";") {
00677             bounds = Lex(model, buff);
00678         } else {
00679             // last element -- exit loop
00680             break;
00681         }
00682     }
00683 }
00684 
00685 static void
00686 ScanImports(ParseImports::ModelSpace &model, const Text &wd,
00687   /*INOUT*/ ImportSeq &seq) throw (ParseImports::Error, FS::Failure, SRPC::failure)
00688 /* Scan the model "model" for imports, and add the names of any models
00689    it imports to "seq". Relative model names are resolved relative
00690    to the directory named "wd", which ends in a "/". */
00691 {
00692   Char_Buff buff;
00693     try {
00694         Lex(model, buff);
00695         while (true) {
00696             if (buff == "{") {
00697                 // start of Block clause
00698                 break;
00699             } else if (buff == "import") {
00700                 // IncIdReq clause
00701                 ReadIncIdReq(model, buff, wd, /*INOUT*/ seq);
00702             } else if (buff == "from") {
00703                 // IncIdOpt clause
00704                 ReadIncIdOpt(model, buff, wd, /*INOUT*/ seq);
00705             } else {
00706                 // skip this lexeme and read the next one
00707                 Lex(model, buff);
00708             }
00709         }
00710     }
00711     catch (FS::EndOfFile) {
00712         throw ParseImports::Error("premature end-of-file");
00713     }
00714 }
00715 
00716 void
00717 ParseImports::P(const Text &modelname, /*INOUT*/ ImportSeq &seq,
00718                 const ParseImports::ModelSpace* ms)
00719   throw(FS::DoesNotExist, FS::Failure, ParseImports::Error, SRPC::failure)
00720 /* Read the imports in the model named by the absolute pathname "model", and
00721    append the names of any such models to "seq". */
00722 {
00723     // open the file for reading
00724     ParseImports::ModelSpace *model;
00725     if (ms == NULL) {
00726       model = NEW_CONSTR(LocalModelSpace, (modelname));
00727     } else {
00728         model = ms->open(modelname);
00729     }
00730 
00731     // form name of directory in which "model" resides
00732     int last_slash = modelname.FindCharR('/'); assert(last_slash >= 0);
00733     Text wd = modelname.Sub(0, last_slash+1);
00734 
00735     // parse the file
00736     ScanImports(*model, wd, /*INOUT*/ seq);
00737 
00738     // close the file
00739     delete(model);
00740 }

Generated on Mon May 8 00:48:58 2006 for Vesta by  doxygen 1.4.2