// Copyright 2009, Andreas Biegert #ifndef CS_IO_H_ #define CS_IO_H_ #include #include #include #include #include #include #include #include #include namespace cs { // Removes the newline and other control characters at the end of a string (if // present) and returns the new length of the string (-1 if str is NULL) inline int chomp(char* str) { if (!str) return -1; int l = 0; for (l = strlen(str) - 1; l >= 0 && str[l] < 32; --l) /* do nothing */; str[++l] = '\0'; return l; } // Emulates the ifstream::getline method; similar to fgets(str,maxlen,FILE*), // but removes the newline at the end and returns NULL if at end of file or read // error inline char* fgetline(char* str, int maxlen, FILE* file) { if (!fgets(str, maxlen, file)) return NULL; if (chomp(str) + 1 >= maxlen) // if line is cut after maxlen characters... while (fgetc(file) != '\n') // ... read in rest of line /* do nothing */; return(str); } // Returns leftmost integer in ptr and sets the pointer to first char after // the integer. If no integer is found, returns INT_MIN and sets ptr to NULL inline int strtoi(const char*& ptr) { int i; const char* ptr0 = ptr; if (!ptr) return INT_MIN; while (*ptr != '\0' && !(*ptr >= '0' && *ptr <= '9')) ++ptr; if (*ptr == '\0') { ptr = NULL; return INT_MIN; } if (ptr > ptr0 && *(ptr-1) == '-') i = -atoi(ptr); else i = atoi(ptr); while (*ptr >= '0' && *ptr <= '9') ++ptr; return i; } // Same as strtoi, but interpretes '*' as default inline int strastoi(const char*& ptr, int deflt = INT_MAX) { int i; const char* ptr0 = ptr; if (!ptr) return INT_MIN; while (*ptr != '\0' && !(*ptr >= '0' && *ptr <= '9') && *ptr != '*') ++ptr; if (*ptr == '\0') { ptr = NULL; return INT_MIN; } if (*ptr == '*') { ++ptr; return deflt; } if (ptr > ptr0 && *(ptr-1) == '-') i = -atoi(ptr); else i = atoi(ptr); while (*ptr >= '0' && *ptr <= '9') ++ptr; return i; } // Returns leftmost double in ptr and sets the pointer to first non-whitespace char // after the double. If no integer is found, returns zero and sets ptr to NULL inline double strtof(const char*& ptr) { double rv = 0.0; if (!ptr) return 0.0; while (*ptr != '\0' && isspace(*ptr)) ++ptr; if (*ptr == '\0') { ptr = NULL; return 0.0; } rv = atof(ptr); while (!isspace(*ptr)) ++ptr; return rv; } // Returns pointer to first non-white-space character in str OR to NULL if none // found inline const char* strscn(const char* str) { if (!str) return NULL; const char* ptr = str; while (*ptr != '\0' && isspace(*ptr)) ++ptr; return (*ptr == '\0') ? NULL : ptr; } // Parse serialization record and return integer value following label 'str' in // line read from file pointer 'fp'. inline int ReadInt(const char* line, const char* label, const char* errmsg = NULL) { int rv = INT_MIN; if (strstr(line, label)) { const char* ptr = line + strlen(label); rv = strtoi(ptr); } else if (errmsg) { throw Exception(errmsg); } return rv; } // Parse serialization record and return double value following label 'label' in // line read from file pointer 'fp'. inline double ReadDouble(const char* line, const char* label, const char* errmsg = NULL) { double rv = DBL_MIN; if (strstr(line, label)) { rv = atof(line + strlen(label)); } else if (errmsg) { throw Exception(errmsg); } return rv; } // Parse serialization record and return string following label 'label' in // line read from file pointer 'fp'. inline std::string ReadString(const char* line, const char* label, const char* errmsg = NULL) { std::string rv; if (strstr(line, label)) { const char* ptr = strscn(line + strlen(label)); rv = ptr; } else if (errmsg) { throw Exception(errmsg); } return rv; } // Parse serialization record and return bool value following label 'str' in // line read from file pointer 'fp'. inline bool ReadBool(const char* line, const char* label, const char* errmsg = NULL) { bool rv = false; if (strstr(line, label)) { const char* ptr = line + strlen(label); if (strchr(ptr, 'T') != NULL || strchr(ptr, '1') != NULL) rv = true; else if (strchr(ptr, 'F') != NULL || strchr(ptr, '0') != NULL) rv = false; else if (errmsg) throw Exception(errmsg); } else if (errmsg) { throw Exception(errmsg); } return rv; } // Returns true iff next non-blank line in file 'fp' contains string 'id'. inline bool StreamStartsWith(FILE* fp, const char* id) { char buffer[KB]; while (fgetline(buffer, KB, fp)) if (strscn(buffer)) break; return strstr(buffer, id) == buffer; } // Reads all serialized records of class type 'T' from stream 'fin' into vector. template void ReadAll(FILE* fin, std::vector& vec) { while (!feof(fin)) { // Parse next record vec.push_back(T(fin)); // Check for EOF int c = getc(fin); if (c == EOF) break; ungetc(c, fin); } } // Writes all serialized records of class type 'T' from vector to stream 'fout' template void WriteAll(const std::vector& vec, FILE* fout) { typedef typename std::vector::const_iterator ConstIter; for (ConstIter iter = vec.begin(); iter != vec.end(); ++iter) iter->Write(fout); } } // namespace cs #endif // CS_IO_H_