// Read the documentation to learn more about C++ code generator // versioning. // %X% %Q% %Z% %W% #ifndef XSPARSE_H #define XSPARSE_H 1 // Error #include #include "XSstreams.h" #include #include #include #include class XSparse { public: class SkipThis : public YellowAlert //## Inherits: %3A65FC6F016E { public: SkipThis (const std::string& diag = "... skipped\n"); protected: private: private: //## implementation }; class AbortLoop : public YellowAlert //## Inherits: %3A65FC6B02E8 { public: AbortLoop (const std::string& diag = "terminated at user request\n"); protected: private: private: //## implementation }; class SyntaxError : public YellowAlert //## Inherits: %3BAB4A170318 { public: SyntaxError (const std::string& diag); protected: private: private: //## implementation }; class InputError : public YellowAlert //## Inherits: %3BB4C0CD0072 { public: InputError (const std::string& diag); protected: private: private: //## implementation }; class InvalidRange : public YellowAlert //## Inherits: %3BB4C09E0249 { public: InvalidRange(); InvalidRange (const std::string& diag); protected: private: private: //## implementation }; // Takes a set of Tcl_Objs and finds where the command ends // and the subsequent input ("batch") begins. // // Returns the command truncated by the subsequent // batch strings, and a vector of strings representing the // batch information. static void findBatchString (const string& cmdLine, string& command, std::deque& batch); // getRanges takes a string and outputs an integer array of // indices in the range. // // In XSPEC 11 this was done using tcl's Regexp machinery, // but this won't be used here to keep tcl and xspec's // innards separate. // // The range should have the following forms: // // a) * : all the indices that are relevant. For this it // needs to be supplied the total number of relevant indices // // b) n : single number // // c) n - m : a simple range // // d) n1-m1,n2,n3-m3,... a comma delimited set of ranges // // e) n:* from index n to the last index. // // lastIndex = -1, is used to denote the presence of wild // cards in the range string. // // Remember C++ uses zero-based indices! static IntegerArray getRanges (const string& rangeString, int lastIndex); // For an input string representing a "range", returns the // beginning and ending numbers in that range. // // endRange is returned as -1 if there is a wildcard // character. If the range corresponds to just a '*', begin // Range is set to 1. // // a string xsdelimiters represents the delimiters used in // expressing the range, defaults to - and : static void oneRange (const string& inputRange, int& beginRange, int& endRange); // function for cutting a string at a delimiter. Returns a // newly constructed string containing the next delimited // argument and the input string, truncated to the remainder // after the first delimited argument is split off. static string returnDelimitedArgument (string& inString, const string& xsdelim); // Function for getting next line from file, with // leading/trailing blanks/tabs removed. // // Also, ignores lines that contain the '#' from that mark // forward (this is a little more generous than tcl, // functions like comment processing in make). static string getNextLine (std::ifstream& stream); // function for parsing XSPEC model commands. It processes // a string of the form // // model : // // [The commandString, an XSPEC model string, is processed // by the Expression class]. static void parseInputModelString (const string& inputString, string& stringPar, size_t& intPar, string& commandString); // determines whether a string is of the form :, for // integers n,m. Function returns true if it is of that // form, with the arguments first, second containing the // values of n,m. // // Error handling: // // a) If the string doesn't contain a colon, returns false // with first, second == -1. [This is expected to happen // quite often since it will be called to determine which // command line arguments are of this form]. // // b) : is acceptable: first is returned as 1, second // as m, and the function returns true. // // c) ":" or ": returns false with first,second // == -1 // // d) : or : returns true with first == // n, second ==1 // // e) : returns false with first, // second == -1 static bool integerPair (const string& arg, int& first, int& second); // Routine from Xspec11 which spaces out a string to aid // the parsing operation. Probably redundant, but at least // requires an overhaul. static void spaceString (char** inputString); // routine from Xspec11 for testing whether a string is an // exponential number. Probably obsolete. static int checkExponent (char* inputString); static void getFileNameFromUser (const string& oldName, string& newName, XSutility::fileType type); // Used in parsing model and parameter name/[source,index] // specifications. // // determines whether a string is of the form :, // for string word, integer m. Returns empty string // and -1 for arguments not present. // // If the input is has no ':' and starts with a string, it // returns // // string, -1 // // No colon and contains integer, returns "", integer // // colon and integer:integer, returns first integer as a // string // colon and string:string, returns string, -1 // // finally, integer:string, returns string, integer and // issues warning. // // // Error handling: // // a) If the string doesn't contain a colon, returns false // with first, second == -1. [This is expected to happen // quite often since it will be called to determine which // command line arguments are of this form]. // // b) : is acceptable: first is returned as 1, second // as m, and the function returns true. // // c) ":" or ": returns false with first,second // == -1 // // d) : or : returns true with first == // n, second ==1 // // e) : returns false with first, // second == -1 static bool stringIntPair (const string& arg, string& word, size_t& number); // return, from input string // // s_1[{r_1}],s_2[{r_2}],... // // tokens of the form s_i[{r_i}] where r_i is an optional // range // string. The complication is that the strings are // delimited // delimited by one or more commas [the case of > 1 // comma delimiter is dealt with by the calling routine] // and the range strings may contain them. // // returns the remainder of the string after the token has // been parsed off. static string processStringToken (const string& inputString, string& token, IntegerArray& spectrumRanges, XSutility::fileType defaultSuffix); static void stringRangePair (const string& arg, string& word, IntegerArray& range); static void catchSkips (const string& input, bool silent = true); // Used in parsing model source:name // specifications. // // determines whether a string is of the form :, // for string word, integer m. Returns empty string // and -1 for arguments not present. // // If the input is has no ':' and starts with , // the return value is // , it returns // 1, . The string is then passed to the component // name resolution // // // colon and integer:string, returns integer, string // colon and string:string, returns string, -1 (error) // . // // // Error handling: // // a) If the string doesn't contain a colon, returns false // with first, second == -1. [This is expected to happen // quite often since it will be called to determine which // command line arguments are of this form]. // // b) : is acceptable: first is returned as 1, second // as m, and the function returns true. // // c) ":" or ": returns false with first,second // == -1 // // d) : or : returns true with first == // n, second ==1 // // e) : returns false with first, // second == -1 static void intStringPair (const string& arg, size_t& number, string& word); static bool addToLibraryPath (const string& newDirectory, string& fullDirectory, int accessMode); static string expandDirectoryPath (const string& input); static void collectParams (std::vector& args, IntegerArray& iParams, StringArray& xsParams); static void basicPrompt (const string& promptMsg, string& result, std::deque* batchArgs = 0); static void promptResponseArf (string& responseName, const string& defaultName, string& arfName, size_t& arfRow, const size_t specNum, bool demand = true, bool doArf = true, std::deque* batchArgs = 0); static void changeExtension (string& fileName, const string& extName, const bool duplicate = true); static string promptFilename (const string& defaultName = "", std::deque* batchArgs = 0); static void collateByWhitespace (StringArray& outStrings, const string& inString); static void checkBrackets (StringArray& args); static string IntToString (size_t num); static bool promptReal (const string& prompt, Real& real, std::deque* batchArgs = 0); static void separate (string& operand, const string& separators); static IntegerArray expandRange (const IntegerArray& range); static string trimWhiteSpace (const string& value); static RangePair wildRange (const string& inputRange, const RangePair& maxRange, RangePair& prevRange); static IntegerArray getRanges (StringArray& inArgs, RangePair& prevRanges, const RangePair& rangeLimits); static bool promptRealPair (const string& prompt, std::pair& vals, std::deque* batchArgs); // Return a substring starting at the position given by p // Start, with size up to (but not including) the first // "\n", or the first n=length chars, whichever is // shorter. If stopping at n=length will break up a word // or number, break instead at the last whitespace prior to // it. pStart will be reset to the position after the end // of the returned segment (but not a "\n"), or npos if it // has reached the end. If pStart is initially out of // range, return a blank string. static string stringSegment (const string& fullString, const size_t length, string::size_type* pStart); // Looks for an extver specifier of the form "{n}" appended // to a file name. Returns the value n, and sets the "file // Name" arg to the substring preceding the first '{'. If // no brackets, returns 0. THROWS if anything other than a // single non-negative integer is found between brackets, // or if anything at all follows the '}'. static int getExtVerNumber (const string& fullName, string& fileName); static const size_t CommandLength (); static const string& NONE (); static const string& SKIP (); static const bool rangeIsReal (); static void rangeIsReal (bool value); static const string::size_type& NOTFOUND (); static const bool executingScript (); static void executingScript (bool value); static const string& USE_DEFAULT (); public: // Additional Public Declarations template static void getArg (std::istream& s, T& value, const T& defaultValue, const string& prompt); template static string ArrayToRange (const T& array); protected: // Additional Protected Declarations private: // returns true if a string has a range string, and // leaves first '{' and '}' index numbers in begin and end // arguments. end is return as strg.length() if the close // has been inadvertently left off. static bool hasRange (const string& strg, size_t& beginRng, size_t& endRng); static size_t validateRangeSpecifier (const string& rangeString); // Additional Private Declarations private: //## implementation // Data Members for Class Attributes static const string STRINGNULLS; static const string INPUT_DELIMITER; static const size_t XCM_LEN; static const string s_NONE; static const string s_SKIP; static bool s_rangeIsReal; static const string::size_type s_NOTFOUND; static char* s_augmentedLibraryPath; static bool s_executingScript; static const string s_USE_DEFAULT; // Additional Implementation Declarations }; template void XSparse::getArg (std::istream& s, T& value, const T& defaultValue, const string& prompt ) { string input(""); while (1) { *IosHolder::errHolder() << "re-enter ( \"/*\" to abort or \"/\" to use default value )\n"; XSstream* xscout = dynamic_cast(IosHolder::outHolder()); if (xscout) { XSstream::setPrompter(s,prompt); } else { *IosHolder::outHolder() << prompt; } s >> input; std::istringstream t(input); t.exceptions(std::ios_base::failbit); try { if ( t.str() == s_SKIP) throw AbortLoop(); if ( t.str() == "/") { value = defaultValue; break; } else { t >> value; break; } } catch ( std::exception& ) { continue; } } } template string XSparse::ArrayToRange (const T& array) { size_t count = array.size(), rangeStart = 0; int diff = 0; std::string range = (count > 0 ? IntToString(array[0]) : std::string("")); for(size_t i = 1; i <= count; ++i) { if(i == count || (diff = array[i] - array[i - 1]) >= 2 || diff < 0) { if(rangeStart != i - 1) range += '-' + IntToString(array[i - 1]); rangeStart = i; if(i != count) range += ',' + IntToString(array[i]); } } return range; } // Class XSparse::SkipThis // Class XSparse::AbortLoop // Class XSparse::SyntaxError // Class XSparse::InputError // Class XSparse::InvalidRange // Class Utility XSparse inline const size_t XSparse::CommandLength () { return XCM_LEN; } inline const string& XSparse::NONE () { return s_NONE; } inline const string& XSparse::SKIP () { return s_SKIP; } inline const bool XSparse::rangeIsReal () { return s_rangeIsReal; } inline void XSparse::rangeIsReal (bool value) { s_rangeIsReal = value; } inline const string::size_type& XSparse::NOTFOUND () { return s_NOTFOUND; } inline const bool XSparse::executingScript () { return s_executingScript; } inline void XSparse::executingScript (bool value) { s_executingScript = value; } inline const string& XSparse::USE_DEFAULT () { return s_USE_DEFAULT; } #endif