diff options
author | Christopher Page | 2008-07-21 22:46:39 +0000 |
---|---|---|
committer | Christopher Page | 2008-07-21 22:46:39 +0000 |
commit | 09f4fd946ee4b3fd6d9780e080b9bc95fbcd0a69 (patch) | |
tree | e4aae52f4e6872f8cd6bed9ddab5de6d0521f7d2 /common | |
parent | 0cae5552db214a7e11c552205e03fd5c0c38f6fd (diff) | |
parent | e09eb75ef77d6e76b763b3a47540a530013a887f (diff) | |
download | scummvm-rg350-09f4fd946ee4b3fd6d9780e080b9bc95fbcd0a69.tar.gz scummvm-rg350-09f4fd946ee4b3fd6d9780e080b9bc95fbcd0a69.tar.bz2 scummvm-rg350-09f4fd946ee4b3fd6d9780e080b9bc95fbcd0a69.zip |
Merged revisions 33052-33053,33056-33058,33061-33064,33068,33070,33072,33075,33078-33079,33083,33086-33087,33089,33094-33096,33098-33099,33104,33108-33109,33114-33117,33120,33135-33146,33160,33162,33165,33167-33169 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
svn-id: r33183
Diffstat (limited to 'common')
-rw-r--r-- | common/config-manager.cpp | 68 | ||||
-rw-r--r-- | common/file.cpp | 2 | ||||
-rw-r--r-- | common/str.cpp | 58 | ||||
-rw-r--r-- | common/str.h | 19 | ||||
-rw-r--r-- | common/stream.cpp | 55 | ||||
-rw-r--r-- | common/stream.h | 27 |
6 files changed, 186 insertions, 43 deletions
diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 5afbbad4ae..59855cf6c9 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -176,7 +176,6 @@ void ConfigManager::loadFile(const String &filename) { if (!cfg_file.open(filename)) { printf("Creating configuration file: %s\n", filename.c_str()); } else { - char buf[MAXLINELEN]; String domain; String comment; int lineno = 0; @@ -184,20 +183,28 @@ void ConfigManager::loadFile(const String &filename) { // TODO: Detect if a domain occurs multiple times (or likewise, if // a key occurs multiple times inside one domain). - while (!cfg_file.eof()) { + while (!cfg_file.eof() && !cfg_file.ioFailed()) { lineno++; - if (!cfg_file.readLine(buf, MAXLINELEN)) - break; - if (buf[0] == '#') { + // Read a line + String line; + while (line.lastChar() != '\n') { + char buf[MAXLINELEN]; + if (!cfg_file.readLine_NEW(buf, MAXLINELEN)) + break; + line += buf; + } + + if (line.size() == 0) { + // Do nothing + } else if (line[0] == '#') { // Accumulate comments here. Once we encounter either the start // of a new domain, or a key-value-pair, we associate the value // of the 'comment' variable with that entity. - comment += buf; - comment += '\n'; - } else if (buf[0] == '[') { + comment += line; + } else if (line[0] == '[') { // It's a new domain which begins here. - char *p = buf + 1; + const char *p = line.c_str() + 1; // Get the domain name, and check whether it's valid (that // is, verify that it only consists of alphanumerics, // dashes and underscores). @@ -209,8 +216,8 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: missing ] in line %d", lineno); break; case ']': - *p = 0; - domain = buf + 1; + domain = String(line.c_str() + 1, p - (line.c_str() + 1)); + //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes break; default: error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno); @@ -226,10 +233,14 @@ void ConfigManager::loadFile(const String &filename) { _domainSaveOrder.push_back(domain); } else { - // Skip leading & trailing whitespaces - char *t = rtrim(ltrim(buf)); - - // Skip empty lines + // This line should be a line with a 'key=value' pair, or an empty one. + + // Skip leading whitespaces + const char *t = line.c_str(); + while (isspace(*t)) + t++; + + // Skip empty lines / lines with only whitespace if (*t == 0) continue; @@ -238,13 +249,30 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: Key/value pair found outside a domain in line %d", lineno); } - // Split string at '=' into 'key' and 'value'. - char *p = strchr(t, '='); + // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. + const char *p = strchr(t, '='); if (!p) error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); - *p = 0; - String key = rtrim(t); - String value = ltrim(p + 1); + + // Trim spaces before the '=' to obtain the key + const char *p2 = p; + while (p2 > t && isspace(*(p2-1))) + p2--; + String key(t, p2 - t); + + // Skip spaces after the '=' + t = p + 1; + while (isspace(*t)) + t++; + + // Trim trailing spaces + p2 = t + strlen(t); + while (p2 > t && isspace(*(p2-1))) + p2--; + + String value(t, p2 - t); + + // Finally, store the key/value pair in the active domain set(key, value, domain); // Store comment diff --git a/common/file.cpp b/common/file.cpp index 386777e2c5..a1ea1aff77 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -452,10 +452,12 @@ bool File::isOpen() const { } bool File::ioFailed() const { + // TODO/FIXME: Just use ferror() here? return _ioFailed != 0; } void File::clearIOFailed() { + // TODO/FIXME: Just use clearerr() here? _ioFailed = false; } diff --git a/common/str.cpp b/common/str.cpp index ad48ef6087..a2e6e0c66d 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -43,32 +43,43 @@ static int computeCapacity(int len) { return ((len + 32 - 1) & ~0x1F) - 1; } -String::String(const char *str, uint32 len) -: _len(0), _str(_storage) { +String::String(const char *str) : _len(0), _str(_storage) { + if (str == 0) { + _storage[0] = 0; + _len = 0; + } else + initWithCStr(str, strlen(str)); +} + +String::String(const char *str, uint32 len) : _len(0), _str(_storage) { + initWithCStr(str, len); +} + +String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) { + assert(endP >= beginP); + initWithCStr(beginP, endP - beginP); +} + +void String::initWithCStr(const char *str, uint32 len) { + assert(str); // Init _storage member explicitly (ie. without calling its constructor) // for GCC 2.95.x compatibility (see also tracker item #1602879). _storage[0] = 0; - if (str && *str) { - const uint32 tmp = strlen(str); - assert(len <= tmp); - if (len <= 0) - len = tmp; - _len = len; - - if (len >= _builtinCapacity) { - // Not enough internal storage, so allocate more - _extern._capacity = computeCapacity(len); - _extern._refCount = 0; - _str = (char *)malloc(_extern._capacity+1); - assert(_str != 0); - } - - // Copy the string into the storage area - memcpy(_str, str, len); - _str[len] = 0; + _len = len; + + if (len >= _builtinCapacity) { + // Not enough internal storage, so allocate more + _extern._capacity = computeCapacity(len); + _extern._refCount = 0; + _str = (char *)malloc(_extern._capacity+1); + assert(_str != 0); } + + // Copy the string into the storage area + memmove(_str, str, len); + _str[len] = 0; } String::String(const String &str) @@ -91,6 +102,8 @@ String::String(char c) _storage[0] = c; _storage[1] = 0; + // TODO/FIXME: There is no reason for the following check -- we *do* + // allow strings to contain 0 bytes! _len = (c == 0) ? 0 : 1; } @@ -130,11 +143,14 @@ String& String::operator =(const char *str) { uint32 len = strlen(str); ensureCapacity(len, false); _len = len; - memcpy(_str, str, len + 1); + memmove(_str, str, len + 1); return *this; } String &String::operator =(const String &str) { + if (&str == this) + return *this; + if (str.isStorageIntern()) { decRefCount(_extern._refCount); _len = str._len; diff --git a/common/str.h b/common/str.h index a92ec34fff..ae9cb992b6 100644 --- a/common/str.h +++ b/common/str.h @@ -96,10 +96,24 @@ public: static const char *emptyString; #endif + /** Construct a new empty string. */ String() : _len(0), _str(_storage) { _storage[0] = 0; } - String(const char *str, uint32 len = 0); + + /** Construct a new string from the given NULL-terminated C string. */ + String(const char *str); + + /** Construct a new string containing exactly len characters read from address str. */ + String(const char *str, uint32 len); + + /** Construct a new string containing the characters between beginP (including) and endP (excluding). */ + String(const char *beginP, const char *endP); + + /** Construct a copy of the given string. */ String(const String &str); + + /** Construct a string consisting of the given character. */ String(char c); + ~String(); String &operator =(const char *str); @@ -162,7 +176,7 @@ public: void toLowercase(); void toUppercase(); - + uint hash() const; public: @@ -189,6 +203,7 @@ protected: void ensureCapacity(uint32 new_len, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); + void initWithCStr(const char *str, uint32 len); }; // Append two strings to form a new (temp) string diff --git a/common/stream.cpp b/common/stream.cpp index ab9804d7b6..61166fd451 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -148,6 +148,61 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) { return buf; } +char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { + assert(buf != 0 && bufSize > 1); + char *p = buf; + size_t len = 0; + char c = 0; + + // If end-of-file occurs before any characters are read, return NULL + // and the buffer contents remain unchanged. + if (eos() || ioFailed()) { + return 0; + } + + // Loop as long as the stream has not ended, there is still free + // space in the buffer, and the line has not ended + while (!eos() && len + 1 < bufSize && c != LF) { + c = readByte(); + + // If end-of-file occurs before any characters are read, return + // NULL and the buffer contents remain unchanged. If an error + /// occurs, return NULL and the buffer contents are indeterminate. + if (ioFailed() || (len == 0 && eos())) + return 0; + + // Check for CR or CR/LF + // * DOS and Windows use CRLF line breaks + // * Unix and OS X use LF line breaks + // * Macintosh before OS X used CR line breaks + if (c == CR) { + // Look at the next char -- is it LF? If not, seek back + c = readByte(); + if (c != LF && !eos()) + seek(-1, SEEK_CUR); + // Treat CR & CR/LF as plain LF + c = LF; + } + + *p++ = c; + len++; + } + + // FIXME: + // This should fix a bug while using readLine with Common::File + // it seems that it sets the eos flag after an invalid read + // and at the same time the ioFailed flag + // the config file parser fails out of that reason for the new themes + if (eos()) { + clearIOFailed(); + } + + // We always terminate the buffer if no error occured + *p = 0; + return buf; +} + + uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) { dataSize = MIN(dataSize, _end - _pos); diff --git a/common/stream.h b/common/stream.h index 313a695e82..4cf5fae114 100644 --- a/common/stream.h +++ b/common/stream.h @@ -304,13 +304,40 @@ public: * Read one line of text from a CR or CR/LF terminated plain text file. * This method is a rough analog of the (f)gets function. * + * @bug A main difference (and flaw) in this function is that there is no + * way to detect that a line exceeeds the length of the buffer. + * Code which needs this should use the new readLine_NEW() method instead. + * * @param buf the buffer to store into * @param bufSize the size of the buffer * @return a pointer to the read string, or NULL if an error occurred + * * @note The line terminator (CR or CR/LF) is stripped and not inserted * into the buffer. */ virtual char *readLine(char *buf, size_t bufSize); + + /** + * Reads at most one less than the number of characters specified + * by bufSize from the and stores them in the string buf. Reading + * stops when the end of a line is reached (CR, CR/LF or LF), at + * end-of-file or error. The newline, if any, is retained (CR and + * CR/LF are translated to LF = 0xA = '\n'). If any characters are + * read and there is no error, a `\0' character is appended to end + * the string. + * + * Upon successful completion, return a pointer to the string. If + * end-of-file occurs before any characters are read, returns NULL + * and the buffer contents remain unchanged. If an error occurs, + * returns NULL and the buffer contents are indeterminate. + * This method does not distinguish between end-of-file and error; + * callers muse use ioFailed() or eos() to determine which occurred. + * + * @param buf the buffer to store into + * @param bufSize the size of the buffer + * @return a pointer to the read string, or NULL if an error occurred + */ + virtual char *readLine_NEW(char *s, size_t bufSize); }; /** |