IFileStream::IFileStream(const UCS2String& name) : IStream(name), f(NULL) { if(pov_stricmp(UCS2toASCIIString(name).c_str(), "stdin") == 0) { f = stdin; } else if((pov_stricmp(UCS2toASCIIString(name).c_str(), "stdout") == 0) || (pov_stricmp(UCS2toASCIIString(name).c_str(), "stderr") == 0)) { f = NULL; } else { f = POV_UCS2_FOPEN(name, "rb"); } fail = (f == NULL); }
int InferFileTypeFromExt(const UCS2String& ext) // TODO FIXME - belongs in backend { // TODO FIXME - better compare in the string domain string str = UCS2toASCIIString(ext); for (int i = 0; i < POV_File_Count; i++) { // TODO - checking whether extension matches is required at other places, too for (int j = 0; j < POV_FILE_EXTENSIONS_PER_TYPE; j ++) { if ( (strlen(gPOV_File_Extensions[i].ext[j]) > 0) && (pov_stricmp (gPOV_File_Extensions[i].ext[j], str.c_str()) == 0) ) { return (i); } } } return NO_FILE; }
bool ProcessOptions::Parse_INI_String_Smartmode(ITextStream *file) { ITextStream::FilePos backtrackpos = file->tellg(); bool result = false; // false - end string here, true - continue parsing string struct INI_Parser_Table *table = parse_ini_table; char *key = NULL; (void)Parse_INI_Skip_Space(file, false); switch(file->getchar()) { // end of file case EOF: break; // return false, parsing more of the string simply is not possible // INI file comment case ';': case '#': break; // return false, this is a comment which terminates the string // INI value list separator case ',': break; // return false, this is a value list of unquoted strings // POV-Ray-style INI file with command-line switch case '+': case '-': // POV-Ray-style INI file with system specific command-line switch on some systems (i.e. Windos) #if(FILENAME_SEPARATOR != '/') case '/': #endif if(isalpha(file->getchar())) break; // return false, this is most likely a command-line else file->seekg(backtrackpos); // most likely an unquoted string, so allow parsing it as a whole // INI file option default: // read the key string key = Parse_INI_String(file); if(key != NULL) { // find the keyword while(table->keyword != NULL) { if(pov_stricmp(table->keyword, key) == 0) break; table++; } // if no valid keyword has been found if(table->keyword == NULL) { result = true; // return true, this is most likely an unquoted path ParseErrorAt(file, "Most likely detected an unquoted string with spaces in INI file. Assuming string ends at the of the line.\n" "Make sure all strings with spaces are properly quoted in the INI file.\n" "Use either \" or \' to quote strings. For details, please check the user manual!"); } delete[] key; key = NULL; } break; // return false, unless the code above did not find a valid keyword } file->seekg(backtrackpos); return result; }
int ProcessOptions::Parse_INI_Option(ITextStream *file, POVMSObjectPtr obj) { struct INI_Parser_Table *table = parse_ini_table; char *value = NULL; char *key = NULL; char chr = 0; int err = kNoErr; // read the key string key = Parse_INI_String(file); if(key == NULL) { ParseErrorAt(file, "Expected key in INI file, no key was found."); return kParseErr; } // find the keyword while(table->keyword != NULL) { if(pov_stricmp(table->keyword, key) == 0) break; table++; } // return if no valid keyword has been found if(table->keyword == NULL) { ParseErrorAt(file, "Unknown key '%s' in INI file.", key); delete[] key; return kParseErr; } else { delete[] key; key = NULL; } // skip any spaces (void)Parse_INI_Skip_Space(file, false); // expect the equal sign if(file->getchar() != '=') return kParseErr; // skip any spaces (void)Parse_INI_Skip_Space(file, false); // if the string is quoted, parse it matching quotes chr = file->getchar(); if((chr == '\"') || (chr == '\'')) value = Parse_INI_String(file, chr); // if there were no quotes, just read up to the next space or newline else { file->ungetchar(chr); value = Parse_INI_String(file, -2, true); } if(value == NULL) { ParseErrorAt(file, "Expected value in INI file, no value was found."); return kParseErr; } err = Process_INI_Option(table, value, obj); delete[] value; value = NULL; // skip any spaces (void)Parse_INI_Skip_Space(file, false); // if there is a comma, parse more values and append them chr = file->getchar(); if(chr == ',') { // read more value strings while((file->eof() == false) && (err == kNoErr)) { // skip any spaces (void)Parse_INI_Skip_Space(file, false); // if the string is quoted, parse it matching quotes chr = file->getchar(); if((chr == '\"') || (chr == '\'')) value = Parse_INI_String(file, chr); // if there were no quotes, just read up to the next space or newline else { file->ungetchar(chr); value = Parse_INI_String(file, -2); } if(value == NULL) { ParseErrorAt(file, "Expected value in INI file, no value was found."); return kParseErr; } err = Process_INI_Option(table, value, obj); delete[] value; value = NULL; // skip any spaces (void)Parse_INI_Skip_Space(file, false); // if there is no other comma, stop parsing values chr = file->getchar(); if(chr != ',') { file->ungetchar(chr); break; } } } else file->ungetchar(chr); return err; }
int ProcessOptions::ParseFile(const char *filespec, POVMSObjectPtr obj) { ITextStream *file = NULL; const char *currentsection = NULL; char *sectionname = NULL; char *filename = NULL; int err = kNoErr; POVMSObjectPtr section = NULL; int currentline = 1; // split the INI files specification into filename and optional section name err = Parse_INI_Specification(filespec, filename, sectionname); if(err == kNoErr) { file = OpenFileForRead(filename, obj); if(file == NULL) { // all errors here are non-fatal, the calling code has to decide if an error is fatal ParseError("Cannot open INI file '%s'.", filename); err= kCannotOpenFileErr; } } if(err == kNoErr) { int token = 0; // apply options prior to any named section section = obj; // read the whole file to the end while((file->eof() == false) && (err == kNoErr)) { currentline += Parse_INI_Skip_Space(file, true); token = file->getchar(); // INI file section name if(token == '[') { // free old section name, if any if(currentsection != NULL) delete[] currentsection; // read until the section name end marker currentsection = Parse_INI_String(file, ']'); // if the user specified a section name, compare the two and enable reading if((sectionname != NULL) && (currentsection != NULL)) { if(pov_stricmp(currentsection, sectionname) == 0) section = obj; // named section matches specified section name, apply options else section = NULL; // named section does not match specified section name, ignore options } // if there was no user specified section name, ignore all named sections else section = NULL; // no section name was specified, ignore options in named section } // skip lines that do not belong to the desired sections else if(section == NULL) { currentline += Parse_INI_Skip_Line(file); } // fully process lines in desired sections else { switch(token) { // end of file case EOF: break; // quoted string case '\"': case '\'': err = kFalseErr; break; // POV-Ray-style INI file with command-line switch case '+': case '-': // POV-Ray-style INI file with system specific command-line switch on some systems (i.e. Windos) #if(FILENAME_SEPARATOR != '/') case '/': #endif err = Parse_INI_Switch(file, token, section); break; // INI file comment case ';': case '#': currentline += Parse_INI_Skip_Line(file); break; // INI file option default: if(isalnum(token) || (token == '_')) { file->ungetchar(token); ITextStream::FilePos backtrackpos = file->tellg(); err = Parse_INI_Option(file, section); // only one option is allowed per line if(err == kNoErr) currentline += Parse_INI_Skip_Line(file); else if(err == kParseErr) { file->seekg(backtrackpos); err = kFalseErr; } } else err = kFalseErr; break; } // if nothing else was appropriate, assume it is some other kind of string requiring special attention if(err == kFalseErr) { char *plainstring = NULL; if((token == '\"') || (token == '\'')) plainstring = Parse_INI_String(file, token, true); // if there were no quotes, just read up to the next space or newline else plainstring = Parse_INI_String(file, -1, true); err = ProcessUnknownString(plainstring, obj); if(plainstring != NULL) delete[] plainstring; } } } // all errors here are non-fatal, the calling code has to decide if an error is fatal if(err != kNoErr) { if(currentsection != NULL) { ParseErrorAt(file, "Cannot continue to process INI file '%s' due to a parse error in line %d section '%s'.\n" "This is not a valid INI file. Check the file for syntax errors, correct them, and try again!\n" "Valid options in INI files are explained in detail in the reference part of the documentation.", filename, currentline, currentsection); } else { ParseErrorAt(file, "Cannot continue to process INI file '%s' due to a parse error in line %d.\n" "This is not a valid INI file. Check the file for syntax errors, correct them, and try again!\n" "Valid options in INI files are explained in detail in the reference part of the documentation.", filename, currentline); } } if(currentsection != NULL) delete[] currentsection; } if(filename != NULL) delete[] filename; if(sectionname != NULL) delete[] sectionname; if(file != NULL) delete file; return err; }
int ProcessOptions::Parse_CL_Option(const char *&commandline, POVMSObjectPtr obj, bool singleswitch) { struct INI_Parser_Table *table = parse_ini_table; char *value = NULL; char *key = NULL; char chr = 0; int err = kNoErr; // read the key string key = Parse_CL_String(commandline); if(key == NULL) { ParseError("Expected INI file key on command-line, no key was found."); return kParseErr; } // find the keyword while(table->keyword != NULL) { if(pov_stricmp(table->keyword, key) == 0) break; table++; } // return false if no valid keyword has been found if(table->keyword == NULL) { delete[] key; return kParseErr; } else { delete[] key; key = NULL; } // expect the equal sign if(*commandline != '=') return kParseErr; commandline++; // if the string is quoted, parse it matching quotes chr = *commandline; if((chr == '\"') || (chr == '\'')) { commandline++; value = Parse_CL_String(commandline, chr); } // if there were no quotes, just read up to the next space or newline else if(singleswitch == false) // see if quotes had been stripped outside POV-Ray value = Parse_CL_String(commandline, -2); else value = Parse_CL_String(commandline, 0); if(value == NULL) { ParseError("Expected value on command-line, no value was found."); return kParseErr; } err = Process_INI_Option(table, value, obj); delete[] value; value = NULL; return err; }
bool IOBase::open(const char *Name, unsigned int Flags /* = 0 */) { char mode[8]; close(); if((Flags & append) == 0) { switch(direction) { case input: strcpy(mode, "r"); break; case output: strcpy(mode, "w"); break; case io: strcpy(mode, "w+"); break; default: return false; } } else { // we cannot use append mode here, since "a" mode is totally incompatible with any // output file format that requires in-place updates(i.e. writing to any location // other than the end of the file). BMP files are in this category. In theory, "r+" // can do anything "a" can do(with appropriate use of seek()) so append mode should // not be needed. strcpy(mode, "r+"); } strcat(mode, "b"); f = NULL; if(pov_stricmp(Name, "stdin") == 0) { if(direction != input ||(Flags & append) != 0) return false; f = stdin; } else if(pov_stricmp(Name, "stdout") == 0) { if(direction != output ||(Flags & append) != 0) return false; f = stdout; } else { if((f = fopen(Name, mode)) == NULL) { if((Flags & append) == 0) return false; // to maintain traditional POV +c(continue) mode compatibility, if // the open for append of an existing file fails, we allow a new file // to be created. mode [0] = 'w'; if((f = fopen(Name, mode)) == NULL) return false; } } fail = false; if((Flags & append) != 0) { if(!seekg(0, seek_end)) { close(); return false; } } return true; }
int ProcessRenderOptions::ProcessUnknownString(char *str, POVMSObjectPtr obj) { POVMSAttributeList list; POVMSAttribute attr; int state = 0; // INI file int err = kNoErr; if(str == NULL) { ParseError("Expected filename, nothing was found."); return kParseErr; } // add filename or path // see if it is a POV file if(state == 0) { char *ptr = strrchr(str, '.'); if(ptr != NULL) { if(pov_stricmp(ptr, ".pov") == 0) state = 1; // POV file } } // see if it is a path if(state == 0) { if(strlen(str) > 0) { if(str[strlen(str) - 1] == FILENAME_SEPARATOR) state = 2; // library path } } switch(state) { // INI file case 0: // parse INI file (recursive) err = ParseFile(str, obj); if(err == kNoErr) { // create list if it isn't there if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) == kFalseErr) err = POVMSAttrList_New(&list); else if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) != kNoErr) err = kObjectAccessErr; else err = POVMSObject_Get(obj, &list, kPOVAttrib_IncludeIni); } // add INI file to list if(err == kNoErr) err = POVMSAttr_New(&attr); if(err == kNoErr) { err = POVMSAttr_Set(&attr, kPOVMSType_CString, str, strlen(str) + 1); if(err == kNoErr) err = POVMSAttrList_Append(&list, &attr); else err = POVMSAttr_Delete(&attr); } if(err == kNoErr) err = POVMSObject_Set(obj, &list, kPOVAttrib_IncludeIni); break; // POV file case 1: // set POV file err = POVMSUtil_SetString(obj, kPOVAttrib_InputFile, str); break; // library path case 2: // create list if it isn't there if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) == kFalseErr) err = POVMSAttrList_New(&list); else if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) != kNoErr) err = kObjectAccessErr; else err = POVMSObject_Get(obj, &list, kPOVAttrib_LibraryPath); // add librarypath to list if(err == kNoErr) err = POVMSAttr_New(&attr); if(err == kNoErr) { err = POVMSAttr_Set(&attr, kPOVMSType_CString, str, strlen(str) + 1); if(err == kNoErr) err = POVMSAttrList_Append(&list, &attr); else err = POVMSAttr_Delete(&attr); } if(err == kNoErr) err = POVMSObject_Set(obj, &list, kPOVAttrib_LibraryPath); break; } return err; }
OStream::OStream(const UCS2String& name, unsigned int Flags) : IOBase(name), f(NULL) { const char* mode; if((Flags & append) == 0) { mode = "wb"; } else { // we cannot use append mode here, since "a" mode is totally incompatible with any // output file format that requires in-place updates(i.e. writing to any location // other than the end of the file). BMP files are in this category. In theory, "r+" // can do anything "a" can do(with appropriate use of seek()) so append mode should // not be needed. mode = "r+b"; } if(pov_stricmp(UCS2toASCIIString(name).c_str(), "stdin") == 0) { f = NULL; } else if(pov_stricmp(UCS2toASCIIString(name).c_str(), "stdout") == 0) { if((Flags & append) != 0) f = NULL; else f = stdout; } else if(pov_stricmp(UCS2toASCIIString(name).c_str(), "stderr") == 0) { if((Flags & append) != 0) f = NULL; else f = stdout; } else { f = POV_UCS2_FOPEN(name, mode); if (f == NULL) { if((Flags & append) == 0) f = NULL; else { // to maintain traditional POV +c(continue) mode compatibility, if // the open for append of an existing file fails, we allow a new file // to be created. mode = "wb"; f = POV_UCS2_FOPEN(name, mode); } } if (f != NULL) { if((Flags & append) != 0) { if(!seekg(0, seek_end)) { fclose(f); f = NULL; } } } } fail = (f == NULL); }