/* * NIST Utils Class Library * clutils/Str.cc * April 1997 * K. C. Morris * David Sauder * Development of this software was funded by the United States Government, * and is not subject to copyright. */ /* $Id: Str.cc,v 1.5 2003/06/06 17:07:35 gcosmo Exp $ */ #include /****************************************************************** ** Procedure: string functions ** Description: These functions take a character or a string and return ** a temporary copy of the string with the function applied to it. ** Parameters: ** Returns: temporary copy of characters ** Side Effects: ** Status: complete ******************************************************************/ char ToLower (const char c) { if (isupper (c)) return (tolower (c)); else return (c); } char ToUpper (const char c) { if (islower (c)) return (toupper (c)); else return (c); } char * StrToLower (const char *strOld, char *strNew) /* * Place in strNew a lowercase version of strOld. */ { int i = 0; while ( strOld[i] != '\0' ) { strNew[i] = ToLower( strOld[i] ); i++; } strNew[i] = '\0'; return strNew; } const char * StrToLower (const char * word, SCLstring &s) { char newword [BUFSIZ]; int i =0; // char ToLower (char c); while (word [i] != '\0') { newword [i] = ToLower (word [i]); ++i; } newword [i] = '\0'; s = newword; return s.chars(); } const char * StrToUpper (const char * word, SCLstring &s) { char newword [BUFSIZ]; int i =0; // char ToUpper (char c); while (word [i] != '\0') { newword [i] = ToUpper (word [i]); ++i; } newword [i] = '\0'; s = newword; return s.chars(); } const char * StrToConstant (const char * word, SCLstring &s) { char newword [BUFSIZ]; int i =0; // char ToUpper (char c); while (word [i] != '\0') { if (word [i] == '/' || word [i] == '.') newword [i] = '_'; else newword [i] = ToUpper (word [i]); ++i; } newword [i] = '\0'; s = newword; return s.chars(); } /****************************************************************** ** Procedure: PrettyName (char * oldname) ** Parameters: oldname ** Returns: a new capitalized name ** Description: creates a new name with first character's in caps ** Side Effects: PrettyNewName allocates memory for the new name PrettyTmpName returns new name in a static buffer ** Status: OK 7-Oct-1992 kcm ******************************************************************/ const char * PrettyTmpName (const char * oldname) { int i= 0; static char newname [BUFSIZ]; newname [0] = '\0'; while (( oldname [i] != '\0') && (i < BUFSIZ)) { newname [i] = ToLower (oldname [i]); if (oldname [i] == '_') /* character is '_' */ { ++i; newname [i] = ToUpper (oldname [i]); } if (oldname [i] != '\0') ++i; } newname [0] = ToUpper (oldname [0]); newname [i] = '\0'; return newname; } char * PrettyNewName (const char * oldname) { char * name = new char [strlen (oldname) +1]; strcpy (name, PrettyTmpName (oldname)); return name; } int StrCmpIns( const char *strA, const char *strB ) /* * An insensitive string compare function. Used most often to compare * names of objects where case is not known and not significant. * * NOTE - cygnus does not define strcmpi/stricmp. I'm sure there's a nifty * way to add preprocessor commands to check if it exists, and if so to * use it, but I didn't bother. */ { char str1[BUFSIZ], str2[BUFSIZ]; strncpy( str1, PrettyTmpName( strA ), BUFSIZ-1 ); strncpy( str2, PrettyTmpName( strB ), BUFSIZ-1 ); return ( strcmp( str1, str2 ) ); } // This function is used to check an input stream following a read. It writes // error messages in the 'ErrorDescriptor &err' argument as appropriate. // 'const char *tokenList' argument contains a string made up of delimiters // that are used to move the file pointer in the input stream to the end of // the value you are reading (i.e. the ending marked by the presence of the // delimiter). The file pointer is moved just prior to the delimiter. If the // tokenList argument is a null pointer then this function expects to find EOF. // // If input is being read from a stream then a tokenList should be provided so // this function can push the file pointer up to but not past the delimiter // (i.e. not removing the delimiter from the input stream). If you have a // string containing a single value and you expect the whole string to contain // a valid value, you can change the string to an std::istrstream, read the value // then send the std::istrstream to this function with tokenList set to null // and this function will set an error for you if any input remains following // the value. // If the input stream can be readable again then // - any error states set for the the stream are cleared. // - white space skipped in the input stream // - if EOF is encountered it returns // otherwise it peeks at the next character // - if the tokenList argument exists (i.e. is not null) // then if looks to see if the char peeked at is in the tokenList string // if it is then no error is set in the ErrorDescriptor // if the char peeked at is not in the tokenList string that implies // that there is garbage following the value that was successfully // or unsuccessfully read. The garbage is read until EOF or a // delimiter in the tokenList is found. // - EOF is found you did not recover -> SEVERITY_INPUT_ERROR // - delimiter found you recovered successfully => SEVERITY_WARNING // - if tokenList does not exist then it expects to find EOF, if it does // not then it is an error but the bad chars are not read since you have // no way to know when to stop. Severity CheckRemainingInput(std::istream &in, ErrorDescriptor *err, const char *typeName, // used in error message const char *tokenList) // e.g. ",)" { SCLstring skipBuf; char name[64]; name[0] = 0; // 1. CHECK to see if there is invalid input following what you read. // good or fail means you can still read from the input stream. if( in.good() || in.fail() ) // fail means that the input did not match the expected input. { // check for bad input following what you read (or tried to read) but // preceding a delimiter if you are expecting one. in.clear(); // clear the istreams error in >> std::ws; // skip whitespace if(in.eof()) // no input following the desired input (or following the { // missing desired input) return err->severity(); } char c; c = in.peek(); if( tokenList ) // are expecting a delim so read till you find it { // 3. FIND a delimiter if( strchr(tokenList, c) ) { // next char peeked at was delim expected => success return err->severity(); } else // next character was not a delim and thus is garbage { // read bad input until you find the delim in.get(c); while(in && !strchr(tokenList, c) ) { // this could chew up the remainder of the input unless you // give it the delim to end an entity value and it knows // about strings skipBuf.Append(c); in.get(c); } // ENHANCEMENT may want to add the bad data to the err msg. if(strchr(tokenList, c)) { // congratulations you recovered err->GreaterSeverity(SEVERITY_WARNING); sprintf(name, "\tFound invalid %s value...\n", typeName); err->AppendToUserMsg(name); err->AppendToDetailMsg(name); err->AppendToDetailMsg( "\tdata lost looking for end of attribute: "); err->AppendToDetailMsg( skipBuf.chars() ); err->AppendToDetailMsg( "\n" ); in.putback(c); // invalid input // (though a valid value may have been assigned) return err->severity(); } else { // could not recover (of course) err->GreaterSeverity(SEVERITY_INPUT_ERROR); sprintf(name, "Unable to recover from input error while reading %s %s", typeName, "value.\n"); err->AppendToUserMsg(name); err->AppendToDetailMsg(name); // invalid input // (though a valid value may have been assigned) return err->severity(); } } } else if(in.good()) // found a char => error // i.e. skipping whitespace did not cause EOF so must have hit a char { // remember we are not expecting more input since no tokenList // or 3. since not expecting a delimiter and there is input there // is an error err->GreaterSeverity(SEVERITY_WARNING); sprintf(name, "Invalid %s value.\n", typeName); err->AppendToUserMsg(name); err->AppendToDetailMsg(name); // invalid input // (though a valid value may have been assigned) return err->severity(); } } else if (in.eof()) { // hit EOF when reading for a value // don\'t set any error return err->severity(); } else { // badbit set (in.bad()) means there was a problem when reading std::istream // this is bad news... it means the input stream is hopelessly messed up err->GreaterSeverity(SEVERITY_INPUT_ERROR); sprintf(name, "Invalid %s value.\n", typeName); err->AppendToUserMsg(name); err->AppendToDetailMsg(name); // invalid input // (though a valid value may have been assigned) return err->severity(); } return err->severity(); }