aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorChristopher Page2008-07-21 22:46:39 +0000
committerChristopher Page2008-07-21 22:46:39 +0000
commit09f4fd946ee4b3fd6d9780e080b9bc95fbcd0a69 (patch)
treee4aae52f4e6872f8cd6bed9ddab5de6d0521f7d2 /common
parent0cae5552db214a7e11c552205e03fd5c0c38f6fd (diff)
parente09eb75ef77d6e76b763b3a47540a530013a887f (diff)
downloadscummvm-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.cpp68
-rw-r--r--common/file.cpp2
-rw-r--r--common/str.cpp58
-rw-r--r--common/str.h19
-rw-r--r--common/stream.cpp55
-rw-r--r--common/stream.h27
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);
};
/**