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

fileutils.cc

Go to the documentation of this file.
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal 00006 // 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 00037 00038 00039 /* ******************************************************* 00040 * $Id: fileutils.cc,v 1.47 2004/07/21 16:30:51 chrish42 Exp $ 00041 * AUTHORS: Pascal Vincent 00042 * This file is part of the PLearn library. 00043 ******************************************************* */ 00044 00045 #include <time.h> 00046 #include <sys/stat.h> 00047 //#include <sys/types.h> 00048 #if !defined(_MSC_VER) && !defined(_MINGW_) 00049 #include <sys/wait.h> 00050 #endif 00051 00052 // norman: added win32 specific declarations 00053 #ifdef WIN32 00054 #include <direct.h> 00055 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 00056 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 00057 00058 #define PL_MAX_FILE_SIZE 1000 00059 #define chdir _chdir 00060 #define stat _stat 00061 #include <Windows.h> 00062 00063 #else 00064 #include <dirent.h> 00065 #include <unistd.h> 00066 00067 #endif // WIN32 00068 00069 //#include <sstream> 00070 #include <strstream> 00071 00072 #include "fileutils.h" 00073 #include <plearn/base/stringutils.h> 00074 #include <plearn/base/plerror.h> 00075 #include <plearn/math/pl_math.h> 00076 #include "PStream.h" 00077 00078 namespace PLearn { 00079 using namespace std; 00080 00081 string getcwd() 00082 { 00083 char buf[2000]; 00084 // norman: added specific functions for win32 00085 // (cannot do the define because getcwd is also 00086 // the name of this function!) 00087 #ifdef WIN32 00088 _getcwd(buf, 2000); 00089 // norman: replace the ugly windows backslash with the forward slash 00090 for (int i = 0; buf[i] != 0 && i < 2000; ++i) { 00091 if (buf[i] == '\\') 00092 buf[i] = '/'; 00093 } 00094 #else 00095 ::getcwd(buf, 2000); 00096 #endif 00097 return string(buf); 00098 } 00099 00100 int chdir(const string& path) 00101 { 00102 int status = ::chdir(path.c_str()); 00103 if (status!=0) 00104 PLERROR("Could not chdir to %s\n",path.c_str()); 00105 return status; 00106 } 00107 00108 string abspath(const string& path) 00109 { 00110 string cwd = getcwd(); 00111 string result; 00112 if(isdir(path)) 00113 { 00114 chdir(path); 00115 result = append_slash(getcwd()); 00116 chdir(cwd); 00117 } 00118 else 00119 { 00120 string dirname = extract_directory(path); 00121 string filename = extract_filename(path); 00122 chdir(dirname); 00123 result = append_slash(getcwd()) + filename; 00124 chdir(cwd); 00125 } 00126 return result; 00127 } 00128 00129 bool pathexists(const string& path) 00130 { 00131 struct stat s; 00132 00133 int status = stat(path.c_str(),&s); 00134 if(status!=0) 00135 return false; 00136 return S_ISDIR(s.st_mode) | S_ISREG(s.st_mode); 00137 } 00138 00139 bool isdir(const string& path) 00140 { 00141 #if defined(_MINGW_) || defined(WIN32) 00142 if (path[path.size()-1] == ':') // c: or C: or r: or R: or... 00143 return true; 00144 #endif 00145 00146 struct stat s; 00147 int status = stat(path.c_str(),&s); 00148 if(status!=0) 00149 return false; 00150 return S_ISDIR(s.st_mode); 00151 } 00152 00153 bool isfile(const string& path) 00154 { 00155 struct stat s; 00156 int status = stat(path.c_str(),&s); 00157 if(status!=0) 00158 return false; 00159 return S_ISREG(s.st_mode); 00160 } 00161 00162 time_t mtime(const string& path) 00163 { 00164 struct stat s; 00165 int status = stat(path.c_str(),&s); 00166 if(status!=0) 00167 return 0; 00168 else 00169 return s.st_mtime; 00170 } 00171 00172 // Returns a list of all entries in the given directory (omitting entries "." and "..") 00173 // If the direcotry cannot be opened an error is issued. 00174 // The returned entries are not full paths. 00175 vector<string> lsdir(const string& dirpath) 00176 { 00177 vector<string> list; 00178 00179 #ifdef WIN32 00180 00181 // Experimental version of directory listing for WIN32 00182 00183 WIN32_FIND_DATA fileData; 00184 HANDLE hSearch; 00185 bool fFinished = false; 00186 char oldpath[PL_MAX_FILE_SIZE]; 00187 00188 GetCurrentDirectory(FILENAME_MAX, oldpath); 00189 00190 if (! SetCurrentDirectory(dirpath.c_str()) ) 00191 { 00192 SetCurrentDirectory(oldpath); 00193 PLERROR("In lsdir: could not open directory %s",dirpath.c_str()); 00194 } 00195 00196 hSearch = FindFirstFile("*", &fileData); 00197 if (hSearch == INVALID_HANDLE_VALUE) 00198 { 00199 SetCurrentDirectory(oldpath); 00200 PLERROR("In lsdir: could not open directory %s. Invalid Handle Value.",dirpath.c_str()); 00201 } 00202 00203 while (!fFinished) 00204 { 00205 string s = fileData.cFileName; 00206 if(s!="." && s!="..") 00207 list.push_back(s); 00208 00209 if (!FindNextFile(hSearch, &fileData)) 00210 { 00211 if (GetLastError() == ERROR_NO_MORE_FILES) 00212 { 00213 fFinished = true; 00214 } 00215 else 00216 { 00217 printf("Couldn't find next file."); 00218 // strange problem! :) 00219 } 00220 } 00221 } 00222 00223 SetCurrentDirectory(oldpath); 00224 00225 #else 00226 00227 DIR* d = opendir(dirpath.c_str()); 00228 if(!d) 00229 PLERROR("In lsdir: could not open directory %s",dirpath.c_str()); 00230 struct dirent* dent; 00231 while( (dent = readdir(d)) != 0) 00232 { 00233 string s = dent->d_name; 00234 if(s!="." && s!="..") 00235 list.push_back(s); 00236 } 00237 closedir(d); 00238 #endif 00239 return list; 00240 } 00241 00242 00243 // Same as lsdir, except dirpath is prepended to the entries' names. 00244 vector<string> lsdir_fullpath(const string& dirpath) 00245 { return addprefix(remove_trailing_slash(dirpath)+slash,lsdir(dirpath)); } 00246 00247 00248 // Forces directory creation if it doesn't already exist. 00249 // (also creates any missing directory along its path) 00250 // Return value indicates success (true) or failure (false). 00251 // If the directory already exists, true is returned. 00252 bool force_mkdir(const string& dirname) 00253 { 00254 string path = remove_trailing_slash(dirname); 00255 if(isdir(path)) 00256 return true; 00257 00258 #if !defined(_MINGW_) && !defined(WIN32) 00259 mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; 00260 #endif 00261 string pathpart; 00262 for (size_t pos = 1; pos != string::npos;) 00263 { 00264 // keep ++pos here! 00265 ++pos; 00266 pos = path.find(slash, pos); 00267 if( pos != string::npos ) 00268 pathpart = path.substr(0, pos); 00269 else 00270 pathpart = path; 00271 00272 if(!isdir(pathpart)) 00273 { 00274 #if !defined(_MINGW_) && !defined(WIN32) 00275 if(mkdir(pathpart.c_str(), mode)!=0) 00276 #else 00277 if(mkdir(pathpart.c_str())!=0) 00278 #endif 00279 return false; 00280 } 00281 } 00282 00283 return true; 00284 } 00285 00286 void force_mkdir_for_file(const string& filepath) 00287 { 00288 string dirpath = extract_directory(filepath); 00289 if(!force_mkdir(dirpath)) 00290 PLERROR("force_mkdir(%s) failed",dirpath.c_str()); 00291 } 00292 00293 // Forces removal of directory and all its content 00294 // Return value indicates success (true) or failure (false) 00295 // If the directory does not exist, false is returned. 00296 bool force_rmdir(const string& dirname) 00297 { 00298 system("pwd"); 00299 if(!isdir(dirname)) 00300 return false; 00301 vector<string> entries = lsdir_fullpath(dirname); 00302 vector<string>::const_iterator it = entries.begin(); 00303 while(it!=entries.end()) 00304 { 00305 if(isdir(*it)) 00306 { 00307 if(!force_rmdir(*it)) 00308 return false; 00309 } 00310 else 00311 { 00312 if(unlink(it->c_str())!=0) 00313 return false; 00314 } 00315 ++it; 00316 } 00317 if(rmdir(dirname.c_str())!=0) 00318 return false; 00319 return true; 00320 00321 } 00322 00323 long filesize(const string& filename) 00324 { 00325 FILE *f = fopen(filename.c_str(),"r"); 00326 long fsize; 00327 if (!f) 00328 PLERROR("In filesize(const string& filename): cannot open file %s.",filename.c_str()); 00329 fseek(f,0,SEEK_END); 00330 fsize = ftell(f); 00331 fclose(f); 00332 return fsize; 00333 } 00334 00335 string loadFileAsString(const string& filepath) 00336 { 00337 long l = filesize(filepath); 00338 char* buf = new char[l]; 00339 ifstream in(filepath.c_str()); 00340 if(in.bad()) 00341 PLERROR("Cannot load file %s",filepath.c_str()); 00342 in.read(buf, l); 00343 string text(buf,l); 00344 delete[] buf; 00345 return text; 00346 } 00347 00348 void saveStringInFile(const string& filepath, const string& text) 00349 { 00350 force_mkdir_for_file(filepath); 00351 ofstream out(filepath.c_str()); 00352 if(!out) 00353 PLERROR("Couldn't open file %s for writing", filepath.c_str()); 00354 out << text; 00355 } 00356 00357 00358 void cp(const string& srcpath, const string& destpath) 00359 { 00360 string command = "\\cp -R " + srcpath + " " + destpath; 00361 system(command.c_str()); 00362 } 00363 00364 void rm(const string& file) 00365 { 00366 #ifdef WIN32 00367 // For the moment works ONLY with files!!! 00368 if ( !DeleteFile(file.c_str()) ) 00369 { 00370 DWORD errorCode = GetLastError(); 00371 LPVOID lpMsgBuf; 00372 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 00373 FORMAT_MESSAGE_FROM_SYSTEM, 00374 NULL, errorCode, 00375 MAKELANGID(LANG_NEUTRAL, 00376 SUBLANG_DEFAULT), 00377 (LPTSTR) &lpMsgBuf, 0, 00378 NULL ); 00379 00380 // Comment because it works only with files.. 00381 //PLERROR("Cannot delete file %s. %s", file.c_str(), lpMsgBuf); 00382 LocalFree( lpMsgBuf ); 00383 } 00384 #else 00385 string command = "\\rm -rf " + file; 00386 system(command.c_str()); 00387 #endif 00388 } 00389 00390 void mv(const string& file) 00391 { 00392 string command = "\\mv " + file; 00393 system(command.c_str()); 00394 } 00395 00396 void mvforce(const string& file) 00397 { 00398 string command = "\\mv -f " + file; 00399 system(command.c_str()); 00400 } 00401 00402 00405 void readWhileMatches(istream& in, const string& s){ 00406 int i = 0; 00407 int c; 00408 c = in.get(); 00409 int n = (int)s.length(); 00410 while(c!=EOF) 00411 { 00412 if(s[i]!=c) 00413 { 00414 in.unget(); // match failed, unget that last character 00415 PLERROR("In readWhileMatches. Failure while matching %s: " 00416 "at position %d expected a '%c', but read a '%c'",s.c_str(),i,s[i],c); 00417 } 00418 ++i; 00419 if(i==n) // passed through the whole string 00420 return; 00421 c = in.get(); 00422 } 00423 PLERROR("In readWhileMatches, met EOF while matching %s", s.c_str()); 00424 } 00425 00426 // reads everything until '\n' (also consumes the '\n') 00427 void skipRestOfLine(istream& in) 00428 { 00429 int c=in.get(); 00430 while(c!='\n' && c!=EOF) 00431 c=in.get(); 00432 } 00433 00434 void skipBlanksAndComments(istream& in) 00435 { 00436 int c = in.get(); 00437 while(c!=EOF) 00438 { 00439 if(!isspace(c)) 00440 { 00441 if(c=='#') 00442 skipRestOfLine(in); 00443 else 00444 break; 00445 } 00446 c = in.get(); 00447 } 00448 in.unget(); 00449 } 00450 00451 void getNextNonBlankLine(istream& in, string& line) 00452 { 00453 for(;;) 00454 { 00455 getline(in,line); 00456 if(in.eof()) 00457 { 00458 line=""; 00459 return; 00460 } 00461 int l = (int)line.length(); 00462 for(int i=0; i<l; i++) 00463 { 00464 char c = line[i]; 00465 if(!isspace(c) && c!='#') 00466 return; 00467 } 00468 } 00469 } 00470 00471 int countNonBlankLinesOfFile(const string& filename) 00472 { 00473 ifstream in(filename.c_str()); 00474 if(!in) 00475 PLERROR("Could not open file %s for reading",filename.c_str()); 00476 int count = 0; 00477 int c = in.get(); 00478 while(c!=EOF) 00479 { 00480 while(c=='\n' || c==' ' || c=='\t' || c=='\r') 00481 c = in.get(); 00482 if(c!='\n' && c!='#' && c!=EOF) // We've found a non-blank, non-comment char. 00483 ++count; 00484 while(c!='\n' && c!=EOF) // read until end of line 00485 c = in.get(); 00486 c = in.get(); 00487 } 00488 return count; 00489 } 00490 00491 int smartReadUntilNext(istream& in, string stoppingsymbols, string& characters_read, bool ignore_brackets) 00492 { 00493 PStream pin(&in); 00494 return pin.smartReadUntilNext(stoppingsymbols, characters_read, ignore_brackets); 00495 } 00496 00498 string newFilename(const string directory, const string prefix, bool is_directory) 00499 { 00500 #if defined(_MINGW_) || defined(WIN32) 00501 PLERROR("This call is not yet implemented for this platform"); 00502 return ""; 00503 #else 00504 string tmpdirname = remove_trailing_slash(directory); 00505 int length = tmpdirname.length()+1+prefix.length()+6+1; 00506 char* tmpfilename = new char[length]; 00507 if (tmpdirname=="") 00508 sprintf(tmpfilename,"%sXXXXXX",prefix.c_str()); 00509 else 00510 sprintf(tmpfilename,"%s/%sXXXXXX",tmpdirname.c_str(),prefix.c_str()); 00511 mkstemp(tmpfilename); 00512 if (is_directory) { 00513 // Defeats the purpose of mktemp, but who cares? 00514 std::remove(tmpfilename); 00515 // see <sys/stat.h>, mode= 0666 00516 mode_t mode = (S_IRUSR|S_IWUSR|S_IXUSR) | S_IRWXG | S_IRWXO; 00517 mkdir(tmpfilename, mode); 00518 } 00519 if(!tmpfilename) 00520 PLERROR("In newFilename : could not make a new temporary filename"); 00521 return tmpfilename; 00522 #endif 00523 } 00524 00525 string makeFileNameValid(const string& path) 00526 { 00527 string dirname = extract_directory(path); 00528 string filename = extract_filename_without_extension(path); 00529 string ext= extract_extension(path); 00530 string ret=path; 00531 if(filename.length() + ext.length() > 256) 00532 { 00533 int j= 0; 00534 string rest= filename.substr(256-ext.length()-12); 00535 do 00536 { 00537 unsigned int n= j++; 00538 for(unsigned int i= 0; i < rest.length(); ++i) 00539 { 00540 int m=0; 00541 switch(i%4) 00542 { 00543 case 3: m= 1; break; 00544 case 2: m= 256; break; 00545 case 1: m= 65536; break; 00546 case 0: m= 256*65536; break; 00547 } 00548 n+= m*(unsigned char)rest[i]; 00549 } 00550 filename.resize(256-ext.length()-12); 00551 filename+= "-" + tostring(n); 00552 } while(pathexists(dirname + filename + ext)); 00553 PLWARNING("makeFileNameValid: Filename '%s' changed to '%s'.", 00554 path.c_str(), (dirname + filename + ext).c_str()); 00555 ret= dirname + filename + ext; 00556 } 00557 00558 // replace illegal characters 00559 char illegal[]="*?'\"${}[]@ ,()"; 00560 for(int i=0;i<(signed)ret.size();i++) 00561 for(int j=0;j<15;j++) 00562 if(ret[i]==illegal[j]) 00563 ret[i]='_'; 00564 return ret; 00565 } 00566 00567 void touch(const string& file) 00568 { 00569 string command = "touch "+file; 00570 system(command.c_str()); 00571 } 00572 00573 string makeExplicitPath(const string& filename) 00574 { 00575 string fn = removeblanks(filename); 00576 if(fn!="" && fn[0]!=slash_char && fn[0]!='.') 00577 { 00578 string dot = "."; 00579 return dot+slash+fn; 00580 } 00581 return fn; 00582 } 00583 00584 00585 string readFileAndMacroProcess(const string& filepath, map<string, string>& variables) 00586 { 00587 // Save old variables (to allow recursive calls) 00588 const char* OldVariables[] = { 00589 "FILEPATH", "DIRPATH", "FILENAME", "FILEBASE", "FILEEXT", "DATE", "TIME", "DATETIME" 00590 }; 00591 const int num_old = sizeof(OldVariables) / sizeof(OldVariables[0]); 00592 map<string,string> old_vars; 00593 for (int i=0; i<num_old; ++i) 00594 old_vars[OldVariables[i]] = variables[OldVariables[i]]; 00595 00596 // Define new local variables 00597 string fpath = abspath(filepath); 00598 variables["FILEPATH"] = fpath; 00599 variables["DIRPATH"] = remove_trailing_slash(extract_directory(fpath)); 00600 variables["FILENAME"] = extract_filename(fpath); 00601 variables["FILEBASE"] = remove_extension(extract_filename(fpath)); 00602 variables["FILEEXT"] = extract_extension(fpath); 00603 variables["HOME"] = getenv("HOME"); 00604 00605 // Compute DATE, TIME, and DATETIME variables 00606 time_t curtime = time(NULL); 00607 struct tm *broken_down_time = localtime(&curtime); 00608 const int SIZE = 100; 00609 char time_buffer[SIZE]; 00610 strftime(time_buffer,SIZE,"%Y%m%d:%H%M%S",broken_down_time); 00611 variables["DATETIME"] = time_buffer; 00612 strftime(time_buffer,SIZE,"%Y%m%d",broken_down_time); 00613 variables["DATE"] = time_buffer; 00614 strftime(time_buffer,SIZE,"%H%M%S",broken_down_time); 00615 variables["TIME"] = time_buffer; 00616 00617 // Perform actual parsing and macro processing... 00618 ifstream in(fpath.c_str()); 00619 if(!in) 00620 PLERROR("In readFileAndMacroProcess, could not open file %s for reading", fpath.c_str()); 00621 string text = readAndMacroProcess(in, variables); 00622 00623 // Restore previous variables 00624 for (int i=0; i<num_old; ++i) 00625 variables[OldVariables[i]] = old_vars[OldVariables[i]]; 00626 00627 return text; 00628 } 00629 00630 string readAndMacroProcess(istream& in, map<string, string>& variables) 00631 { 00632 string text; // the processed text to return 00633 bool inside_a_quoted_string=false; // inside a quoted string we don't skip characters following a # 00634 int c=EOF,last_c=EOF; 00635 while(in) 00636 { 00637 last_c = c; 00638 c = in.get(); 00639 if (last_c!='\\' && c=='"') // we find either the beginning or end of a quoted string 00640 inside_a_quoted_string = !inside_a_quoted_string; // flip status 00641 00642 if(!inside_a_quoted_string && c=='#') // It's a comment: skip rest of line 00643 { 00644 while(c!=EOF && c!='\n' && c!='\r') 00645 c = in.get(); 00646 } 00647 00648 if(c==EOF) 00649 break; 00650 else if(c!='$') 00651 text += c; 00652 else // We have a $ macro command 00653 { 00654 int c = in.peek(); 00655 switch(c) 00656 { 00657 case '{': // expand a defined variable ${varname} 00658 { 00659 string varname; // name of a variable 00660 in.get(); // skip '{' 00661 smartReadUntilNext(in, "}", varname, true); 00662 // Maybe there are macros to process to obtain the real name of the variable. 00663 istrstream varname_stream(varname.c_str()); 00664 varname = readAndMacroProcess(varname_stream, variables); 00665 varname = removeblanks(varname); 00666 map<string, string>::iterator it = variables.find(varname); 00667 if(it==variables.end()) 00668 PLERROR("Macro variable ${%s} undefined", varname.c_str()); 00669 istrstream varin(it->second.c_str()); 00670 text += readAndMacroProcess(varin, variables); 00671 } 00672 break; 00673 00674 case 'C': // it's a CHAR{expression} 00675 { 00676 string expr; 00677 readWhileMatches(in, "CHAR"); 00678 bool syntax_ok = true; 00679 int c = in.get(); 00680 if(c == '{') 00681 smartReadUntilNext(in, "}", expr, true); 00682 else 00683 syntax_ok = false; 00684 if (!syntax_ok) 00685 PLERROR("$CHAR syntax is: $CHAR{expr}"); 00686 istrstream expr_stream(expr.c_str()); 00687 char ch = (char) toint(readAndMacroProcess(expr_stream, variables)); 00688 text += ch; 00689 } 00690 break; 00691 00692 case 'D': 00693 { 00694 int next = in.get(); 00695 next = in.peek(); // Next character. 00696 switch(next) { 00697 00698 case 'E': // it's a DEFINE{varname}{expr} 00699 { 00700 string varname; // name of a variable 00701 string vardef; // definition of a variable 00702 readWhileMatches(in, "EFINE{"); 00703 getline(in,varname, '}'); 00704 varname = removeblanks(varname); 00705 skipBlanksAndComments(in); 00706 if(in.get()!='{') 00707 PLERROR("Bad syntax in .plearn DEFINE macro: correct syntax is $DEFINE{name}{definition}"); 00708 smartReadUntilNext(in, "}", vardef, true); 00709 variables[varname] = vardef; 00710 } 00711 break; 00712 00713 case 'I': // it's a DIVIDE{expr1}{expr2} 00714 { 00715 string expr1, expr2; 00716 readWhileMatches(in, "IVIDE"); 00717 bool syntax_ok = true; 00718 int c = in.get(); 00719 if (syntax_ok) { 00720 if(c == '{') 00721 smartReadUntilNext(in, "}", expr1, true); 00722 else 00723 syntax_ok = false; 00724 } 00725 if (syntax_ok) { 00726 c = in.get(); 00727 if(c == '{') 00728 smartReadUntilNext(in, "}", expr2, true); 00729 else 00730 syntax_ok = false; 00731 } 00732 if (!syntax_ok) 00733 PLERROR("$DIVIDE syntax is: $DIVIDE{expr1}{expr2}"); 00734 istrstream expr1_stream(expr1.c_str()); 00735 istrstream expr2_stream(expr2.c_str()); 00736 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 00737 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 00738 real e1, e2; 00739 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 00740 PLERROR("In $DIVIDE{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 00741 } 00742 text += tostring(e1 / e2); 00743 } 00744 break; 00745 00746 } 00747 break; 00748 } 00749 00750 case 'E': 00751 { 00752 int next = in.get(); 00753 next = in.peek(); // Next character. 00754 switch(next) { 00755 00756 case 'C': // it's an ECHO{expr} 00757 { 00758 string expr; 00759 readWhileMatches(in, "CHO"); 00760 bool syntax_ok = true; 00761 int c = in.get(); 00762 if(c == '{') 00763 smartReadUntilNext(in, "}", expr, true); 00764 else 00765 syntax_ok = false; 00766 if (!syntax_ok) 00767 PLERROR("$ECHO syntax is: $ECHO{expr}"); 00768 istrstream expr_stream(expr.c_str()); 00769 cout << readAndMacroProcess(expr_stream, variables) << endl; 00770 } 00771 break; 00772 00773 case 'V': // it's an EVALUATE{varname} 00774 { 00775 string expr; 00776 readWhileMatches(in, "VALUATE"); 00777 bool syntax_ok = true; 00778 int c = in.get(); 00779 if(c == '{') 00780 smartReadUntilNext(in, "}", expr, true); 00781 else 00782 syntax_ok = false; 00783 if (!syntax_ok) 00784 PLERROR("$EVALUATE syntax is: $EVALUATE{varname}"); 00785 istrstream expr_stream(expr.c_str()); 00786 string varname = readAndMacroProcess(expr_stream, variables); 00787 string to_evaluate = variables[varname]; 00788 istrstream to_evaluate_stream(to_evaluate.c_str()); 00789 string evaluated = readAndMacroProcess(to_evaluate_stream, variables); 00790 variables[varname] = evaluated; 00791 } 00792 break; 00793 } 00794 break; 00795 } 00796 00797 case 'I': 00798 { 00799 int next = in.get(); 00800 next = in.peek(); // Next character. 00801 switch(next) { 00802 00803 case 'F': // it's an IF{cond}{expr_cond_true}{expr_cond_false} 00804 { 00805 string cond, expr_cond_true, expr_cond_false, expr_evaluated; 00806 readWhileMatches(in, "F"); 00807 bool syntax_ok = true; 00808 int c = in.get(); 00809 if(c == '{') 00810 smartReadUntilNext(in, "}", cond, true); 00811 else 00812 syntax_ok = false; 00813 if (syntax_ok) { 00814 c = in.get(); 00815 if(c == '{') 00816 smartReadUntilNext(in, "}", expr_cond_true, true); 00817 else 00818 syntax_ok = false; 00819 } 00820 if (syntax_ok) { 00821 c = in.get(); 00822 if(c == '{') 00823 smartReadUntilNext(in, "}", expr_cond_false, true); 00824 else 00825 syntax_ok = false; 00826 } 00827 if (!syntax_ok) 00828 PLERROR("$IF syntax is: $IF{cond}{expr_cond_true}{expr_cond_false}"); 00829 00830 istrstream cond_stream(cond.c_str()); 00831 string evaluate_cond = readAndMacroProcess(cond_stream, variables); 00832 if (evaluate_cond == "1" ) { 00833 expr_evaluated = expr_cond_true; 00834 } else if (evaluate_cond == "0") { 00835 expr_evaluated = expr_cond_false; 00836 } else { 00837 PLERROR("$IF condition should be 0 or 1, but is %s", evaluate_cond.c_str()); 00838 } 00839 istrstream expr_stream(expr_evaluated.c_str()); 00840 text += readAndMacroProcess(expr_stream, variables); 00841 } 00842 break; 00843 00844 case 'N': 00845 { 00846 int next = in.get(); 00847 next = in.peek(); // Next character. 00848 switch(next) { 00849 00850 case 'C': // it's an INCLUDE{filepath} 00851 { 00852 string includefilepath; // path of the file in a $INCLUDE{...} directive 00853 readWhileMatches(in, "CLUDE"); 00854 int c = in.get(); 00855 if(c=='<') 00856 smartReadUntilNext(in, ">", includefilepath, true); 00857 else if(c=='{') 00858 smartReadUntilNext(in, "}", includefilepath, true); 00859 else 00860 PLERROR("$INCLUDE must be followed immediately by a { or <"); 00861 istringstream pathin(includefilepath); 00862 includefilepath = readAndMacroProcess(pathin,variables); 00863 includefilepath = removeblanks(includefilepath); 00864 string dirname = extract_directory(includefilepath); 00865 string filename = extract_filename(includefilepath); 00866 string olddir = getcwd(); 00867 chdir(dirname); 00868 text += readFileAndMacroProcess(filename, variables); 00869 chdir(olddir); 00870 } 00871 break; 00872 00873 case 'T': // it's an INT{val} 00874 { 00875 string expr; 00876 readWhileMatches(in, "T"); 00877 bool syntax_ok = true; 00878 int c = in.get(); 00879 if(c == '{') 00880 smartReadUntilNext(in, "}", expr, true); 00881 else 00882 syntax_ok = false; 00883 if (!syntax_ok) 00884 PLERROR("$INT syntax is: $INT{expr}"); 00885 istrstream expr_stream(expr.c_str()); 00886 string expr_eval = readAndMacroProcess(expr_stream, variables); 00887 real e; 00888 if (!pl_isnumber(expr_eval, &e)) { 00889 PLERROR("In $INT{expr}, 'expr' is not a number"); 00890 } 00891 text += tostring(int(e)); 00892 } 00893 } 00894 } 00895 break; 00896 00897 case 'S': 00898 { 00899 00900 int next = in.get(); 00901 next = in.peek(); // Next character. 00902 switch(next) { 00903 00904 case 'D': // it's an ISDEFINED{expr} 00905 { 00906 string expr; 00907 readWhileMatches(in, "DEFINED"); 00908 bool syntax_ok = true; 00909 int c = in.get(); 00910 if(c == '{') 00911 smartReadUntilNext(in, "}", expr, true); 00912 else 00913 syntax_ok = false; 00914 if (!syntax_ok) 00915 PLERROR("$ISDEFINED syntax is: $ISDEFINED{expr}"); 00916 istrstream expr_stream(expr.c_str()); 00917 string expr_eval = readAndMacroProcess(expr_stream, variables); 00918 map<string, string>::iterator it = variables.find(expr_eval); 00919 if(it==variables.end()) { 00920 // The variable is not defined. 00921 text += "0"; 00922 } else { 00923 text += "1"; 00924 } 00925 } 00926 break; 00927 00928 case 'E': // it's an ISEQUAL{expr1}{expr2} 00929 { 00930 string expr1, expr2; 00931 readWhileMatches(in, "EQUAL"); 00932 bool syntax_ok = true; 00933 int c = in.get(); 00934 if(c == '{') 00935 smartReadUntilNext(in, "}", expr1, true); 00936 else 00937 syntax_ok = false; 00938 if (syntax_ok) { 00939 c = in.get(); 00940 if(c == '{') 00941 smartReadUntilNext(in, "}", expr2, true); 00942 else 00943 syntax_ok = false; 00944 } 00945 if (!syntax_ok) 00946 PLERROR("$ISEQUAL syntax is: $ISEQUAL{expr1}{expr2}"); 00947 istrstream expr1_stream(expr1.c_str()); 00948 istrstream expr2_stream(expr2.c_str()); 00949 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 00950 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 00951 if (expr1_eval == expr2_eval) { 00952 text += "1"; 00953 } else { 00954 text += "0"; 00955 } 00956 } 00957 break; 00958 00959 case 'H': // it's an ISHIGHER{expr1}{expr2} 00960 { 00961 string expr1, expr2; 00962 readWhileMatches(in, "HIGHER"); 00963 bool syntax_ok = true; 00964 int c = in.get(); 00965 if(c == '{') 00966 smartReadUntilNext(in, "}", expr1, true); 00967 else 00968 syntax_ok = false; 00969 if (syntax_ok) { 00970 c = in.get(); 00971 if(c == '{') 00972 smartReadUntilNext(in, "}", expr2, true); 00973 else 00974 syntax_ok = false; 00975 } 00976 if (!syntax_ok) 00977 PLERROR("$ISHIGHER syntax is: $ISHIGHER{expr1}{expr2}"); 00978 istrstream expr1_stream(expr1.c_str()); 00979 istrstream expr2_stream(expr2.c_str()); 00980 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 00981 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 00982 real e1, e2; 00983 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 00984 PLERROR("In $ISHIGHER{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 00985 } 00986 if (e1 > e2) { 00987 text += "1"; 00988 } else { 00989 text += "0"; 00990 } 00991 } 00992 break; 00993 } 00994 } 00995 break; 00996 } 00997 } 00998 break; 00999 01000 case 'M': // it's a MINUS{expr1}{expr2} 01001 { 01002 string expr1, expr2; 01003 readWhileMatches(in, "MINUS"); 01004 bool syntax_ok = true; 01005 int c = in.get(); 01006 if (syntax_ok) { 01007 if(c == '{') 01008 smartReadUntilNext(in, "}", expr1,true); 01009 else 01010 syntax_ok = false; 01011 } 01012 if (syntax_ok) { 01013 c = in.get(); 01014 if(c == '{') 01015 smartReadUntilNext(in, "}", expr2,true); 01016 else 01017 syntax_ok = false; 01018 } 01019 if (!syntax_ok) 01020 PLERROR("$MINUS syntax is: $MINUS{expr1}{expr2}"); 01021 istrstream expr1_stream(expr1.c_str()); 01022 istrstream expr2_stream(expr2.c_str()); 01023 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 01024 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 01025 real e1, e2; 01026 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 01027 PLERROR("In $MINUS{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 01028 } 01029 text += tostring(e1 - e2); 01030 } 01031 break; 01032 01033 case 'O': // it's an OR{expr1}{expr2} 01034 { 01035 string expr1, expr2; 01036 readWhileMatches(in, "OR"); 01037 bool syntax_ok = true; 01038 int c = in.get(); 01039 if (syntax_ok) { 01040 if(c == '{') 01041 smartReadUntilNext(in, "}", expr1,true); 01042 else 01043 syntax_ok = false; 01044 } 01045 if (syntax_ok) { 01046 c = in.get(); 01047 if(c == '{') 01048 smartReadUntilNext(in, "}", expr2,true); 01049 else 01050 syntax_ok = false; 01051 } 01052 if (!syntax_ok) 01053 PLERROR("$OR syntax is: $OR{expr1}{expr2}"); 01054 istrstream expr1_stream(expr1.c_str()); 01055 istrstream expr2_stream(expr2.c_str()); 01056 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 01057 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 01058 real e1, e2; 01059 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 01060 PLERROR("In $OR{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 01061 } 01062 int i1 = toint(expr1_eval); 01063 int i2 = toint(expr2_eval); 01064 bool is_true = i1 || i2; 01065 text += tostring(is_true); 01066 } 01067 break; 01068 01069 case 'P': // it's a PLUS{expr1}{expr2} 01070 { 01071 string expr1, expr2; 01072 readWhileMatches(in, "PLUS"); 01073 bool syntax_ok = true; 01074 int c = in.get(); 01075 if (syntax_ok) { 01076 if(c == '{') 01077 smartReadUntilNext(in, "}", expr1,true); 01078 else 01079 syntax_ok = false; 01080 } 01081 if (syntax_ok) { 01082 c = in.get(); 01083 if(c == '{') 01084 smartReadUntilNext(in, "}", expr2,true); 01085 else 01086 syntax_ok = false; 01087 } 01088 if (!syntax_ok) 01089 PLERROR("$PLUS syntax is: $PLUS{expr1}{expr2}"); 01090 istrstream expr1_stream(expr1.c_str()); 01091 istrstream expr2_stream(expr2.c_str()); 01092 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 01093 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 01094 real e1, e2; 01095 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 01096 PLERROR("In $PLUS{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 01097 } 01098 text += tostring(e1 + e2); 01099 } 01100 break; 01101 01102 case 'S': // it's a SWITCH{expr}{cond1}{val1}{cond2}{val2}...{valdef} 01103 { 01104 string expr, valdef; 01105 vector<string> comp; 01106 vector<string> val; 01107 readWhileMatches(in, "SWITCH"); 01108 bool syntax_ok = true; 01109 // First read 'expr'. 01110 int c = in.get(); 01111 if (syntax_ok) { 01112 if(c == '{') 01113 smartReadUntilNext(in, "}", expr, true); 01114 else 01115 syntax_ok = false; 01116 } 01117 // Read the pairs {compx}{valx}, then {valdef} 01118 bool done_parsing = false; 01119 while (syntax_ok && !done_parsing) { 01120 c = getAfterSkipBlanksAndComments(in); 01121 string tmp_comp, tmp_val; 01122 if(c == '{') 01123 smartReadUntilNext(in, "}", tmp_comp, true); 01124 else 01125 syntax_ok = false; 01126 if (syntax_ok) { 01127 c = peekAfterSkipBlanksAndComments(in); 01128 if(c == '{') { 01129 c = getAfterSkipBlanksAndComments(in); 01130 smartReadUntilNext(in, "}", tmp_val, true); 01131 } 01132 else { 01133 // We must have read 'valdef' just before. 01134 valdef = tmp_comp; 01135 done_parsing = true; 01136 } 01137 } 01138 if (!done_parsing) { 01139 comp.push_back(tmp_comp); 01140 val.push_back(tmp_val); 01141 } 01142 } 01143 if (!syntax_ok) 01144 PLERROR("$SWITCH syntax is: $SWITCH{expr}{comp1}{val1}{comp2}{val2}...{valdef}"); 01145 istrstream expr_stream(expr.c_str()); 01146 string expr_eval = readAndMacroProcess(expr_stream, variables); 01147 bool not_done = true; 01148 for (unsigned int i = 0; i < comp.size() && not_done; i++) { 01149 istrstream comp_stream(comp[i].c_str()); 01150 string comp_eval = readAndMacroProcess(comp_stream, variables); 01151 if (expr_eval == comp_eval) { 01152 not_done = false; 01153 istrstream val_stream(val[i].c_str()); 01154 text += readAndMacroProcess(val_stream, variables); 01155 } 01156 } 01157 if (not_done) { 01158 // Default value needed. 01159 istrstream val_stream(valdef.c_str()); 01160 text += readAndMacroProcess(val_stream, variables); 01161 } 01162 } 01163 break; 01164 01165 case 'T': // it's a TIMES{expr1}{expr2} 01166 { 01167 string expr1, expr2; 01168 readWhileMatches(in, "TIMES"); 01169 bool syntax_ok = true; 01170 int c = in.get(); 01171 if (syntax_ok) { 01172 if(c == '{') 01173 smartReadUntilNext(in, "}", expr1, true); 01174 else 01175 syntax_ok = false; 01176 } 01177 if (syntax_ok) { 01178 c = in.get(); 01179 if(c == '{') 01180 smartReadUntilNext(in, "}", expr2, true); 01181 else 01182 syntax_ok = false; 01183 } 01184 if (!syntax_ok) 01185 PLERROR("$TIMES syntax is: $TIMES{expr1}{expr2}"); 01186 istrstream expr1_stream(expr1.c_str()); 01187 istrstream expr2_stream(expr2.c_str()); 01188 string expr1_eval = readAndMacroProcess(expr1_stream, variables); 01189 string expr2_eval = readAndMacroProcess(expr2_stream, variables); 01190 real e1, e2; 01191 if (!pl_isnumber(expr1_eval, &e1) || !pl_isnumber(expr2_eval, &e2)) { 01192 PLERROR("In $TIMES{expr1}{expr2}, either 'expr1' or 'expr2' is not a number"); 01193 } 01194 text += tostring(e1 * e2); 01195 } 01196 break; 01197 01198 case 'U': // it's an UNDEFINE{varname} 01199 { 01200 string expr; 01201 readWhileMatches(in, "UNDEFINE"); 01202 bool syntax_ok = true; 01203 int c = in.get(); 01204 if(c == '{') 01205 smartReadUntilNext(in, "}", expr, true); 01206 else 01207 syntax_ok = false; 01208 if (!syntax_ok) 01209 PLERROR("$UNDEFINE syntax is: $UNDEFINE{expr}"); 01210 istrstream expr_stream(expr.c_str()); 01211 string varname = readAndMacroProcess(expr_stream, variables); 01212 while (variables.count(varname) > 0) { 01213 // This loop is probably not necessary, but just in case... 01214 variables.erase(varname); 01215 } 01216 } 01217 break; 01218 01219 default: 01220 PLERROR("In readAndMacroProcess: only supported macro commands are \n" 01221 "${varname}, $CHAR, $DEFINE, $DIVIDE, $ECHO, $EVALUATE, $IF, $INCLUDE, $INT, $ISDEFINED, $ISEQUAL, $ISHIGHER, $MINUS, $PLUS, $OR, $SWITCH, $TIMES, $UNDEFINE." 01222 "But I read $%c !!",c); 01223 } 01224 } 01225 } 01226 01227 // cerr << "MACRO PROCESSEd TEXT: \n" << text << endl; 01228 01229 return text; 01230 } 01231 01232 #ifdef WIN32 01233 #undef S_ISDIR 01234 #undef S_ISREG 01235 #undef PL_MAX_FILE_SIZE 01236 #undef chdir 01237 #undef stat 01238 #endif 01239 01240 } // end of namespace PLearn 01241 01242 // int main() 01243 /* 01244 { 01245 using namespace PLearn; 01246 01247 map<string, string> variables; 01248 string text = readFileAndMacroProcess("essai.plearn", variables); 01249 01250 cout << "TEXT:" << endl; 01251 cout << text << endl; 01252 01253 cout << "\nVARIABLES:" << endl; 01254 01255 PStream pout(&cout); 01256 pout << variables << endl; 01257 01258 return 0; 01259 } 01260 */ 01261

Generated on Tue Aug 17 15:52:51 2004 for PLearn by doxygen 1.3.7