diff options
Diffstat (limited to 'src/common/strlib.c')
-rw-r--r-- | src/common/strlib.c | 1729 |
1 files changed, 848 insertions, 881 deletions
diff --git a/src/common/strlib.c b/src/common/strlib.c index dfacbf136..89aac3b40 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -14,360 +14,348 @@ #define J_MAX_MALLOC_SIZE 65535 // escapes a string in-place (' -> \' , \ -> \\ , % -> _) -char* jstrescape (char* pt) +char *jstrescape(char *pt) { - //copy from here - char *ptr; - int i = 0, j = 0; - - //copy string to temporary - CREATE(ptr, char, J_MAX_MALLOC_SIZE); - strcpy(ptr,pt); - - while (ptr[i] != '\0') { - switch (ptr[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = ptr[i++]; - } - } - pt[j++] = '\0'; - aFree(ptr); - return pt; + //copy from here + char *ptr; + int i = 0, j = 0; + + //copy string to temporary + CREATE(ptr, char, J_MAX_MALLOC_SIZE); + strcpy(ptr,pt); + + while (ptr[i] != '\0') { + switch (ptr[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = ptr[i++]; + } + } + pt[j++] = '\0'; + aFree(ptr); + return pt; } // escapes a string into a provided buffer -char* jstrescapecpy (char* pt, const char* spt) +char *jstrescapecpy(char *pt, const char *spt) { - //copy from here - //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time - //a escape character is found, the target's final length increases! [Skotlex] - int i =0, j=0; - - if (!spt) { //Return an empty string [Skotlex] - pt[0] = '\0'; - return &pt[0]; - } - - while (spt[i] != '\0') { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - pt[j++] = '\0'; - return &pt[0]; + //copy from here + //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time + //a escape character is found, the target's final length increases! [Skotlex] + int i =0, j=0; + + if (!spt) { //Return an empty string [Skotlex] + pt[0] = '\0'; + return &pt[0]; + } + + while (spt[i] != '\0') { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + pt[j++] = '\0'; + return &pt[0]; } // escapes exactly 'size' bytes of a string into a provided buffer -int jmemescapecpy (char* pt, const char* spt, int size) +int jmemescapecpy(char *pt, const char *spt, int size) { - //copy from here - int i =0, j=0; - - while (i < size) { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - // copy size is 0 ~ (j-1) - return j; + //copy from here + int i =0, j=0; + + while (i < size) { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + // copy size is 0 ~ (j-1) + return j; } // Function to suppress control characters in a string. -int remove_control_chars(char* str) +int remove_control_chars(char *str) { - int i; - int change = 0; + int i; + int change = 0; - for(i = 0; str[i]; i++) { - if (ISCNTRL(str[i])) { - str[i] = '_'; - change = 1; - } - } + for (i = 0; str[i]; i++) { + if (ISCNTRL(str[i])) { + str[i] = '_'; + change = 1; + } + } - return change; + return change; } // Removes characters identified by ISSPACE from the start and end of the string // NOTE: make sure the string is not const!! -char* trim(char* str) +char *trim(char *str) { - size_t start; - size_t end; - - if( str == NULL ) - return str; - - // get start position - for( start = 0; str[start] && ISSPACE(str[start]); ++start ) - ; - // get end position - for( end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end ) - ; - // trim - if( start == end ) - *str = '\0';// empty string - else - {// move string with nul terminator - str[end] = '\0'; - memmove(str,str+start,end-start+1); - } - return str; + size_t start; + size_t end; + + if (str == NULL) + return str; + + // get start position + for (start = 0; str[start] && ISSPACE(str[start]); ++start) + ; + // get end position + for (end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end) + ; + // trim + if (start == end) + *str = '\0';// empty string + else { + // move string with nul terminator + str[end] = '\0'; + memmove(str,str+start,end-start+1); + } + return str; } // Converts one or more consecutive occurences of the delimiters into a single space // and removes such occurences from the beginning and end of string // NOTE: make sure the string is not const!! -char* normalize_name(char* str,const char* delims) +char *normalize_name(char *str,const char *delims) { - char* in = str; - char* out = str; - int put_space = 0; - - if( str == NULL || delims == NULL ) - return str; - - // trim start of string - while( *in && strchr(delims,*in) ) - ++in; - while( *in ) - { - if( put_space ) - {// replace trim characters with a single space - *out = ' '; - ++out; - } - // copy non trim characters - while( *in && !strchr(delims,*in) ) - { - *out = *in; - ++out; - ++in; - } - // skip trim characters - while( *in && strchr(delims,*in) ) - ++in; - put_space = 1; - } - *out = '\0'; - return str; + char *in = str; + char *out = str; + int put_space = 0; + + if (str == NULL || delims == NULL) + return str; + + // trim start of string + while (*in && strchr(delims,*in)) + ++in; + while (*in) { + if (put_space) { + // replace trim characters with a single space + *out = ' '; + ++out; + } + // copy non trim characters + while (*in && !strchr(delims,*in)) { + *out = *in; + ++out; + ++in; + } + // skip trim characters + while (*in && strchr(delims,*in)) + ++in; + put_space = 1; + } + *out = '\0'; + return str; } -//stristr: Case insensitive version of strstr, code taken from +//stristr: Case insensitive version of strstr, code taken from //http://www.daniweb.com/code/snippet313.html, Dave Sinkula // -const char* stristr(const char* haystack, const char* needle) +const char *stristr(const char *haystack, const char *needle) { - if ( !*needle ) - { - return haystack; - } - for ( ; *haystack; ++haystack ) - { - if ( TOUPPER(*haystack) == TOUPPER(*needle) ) - { - // matched starting char -- loop through remaining chars - const char *h, *n; - for ( h = haystack, n = needle; *h && *n; ++h, ++n ) - { - if ( TOUPPER(*h) != TOUPPER(*n) ) - { - break; - } - } - if ( !*n ) // matched all of 'needle' to null termination - { - return haystack; // return the start of the match - } - } - } - return 0; + if (!*needle) { + return haystack; + } + for (; *haystack; ++haystack) { + if (TOUPPER(*haystack) == TOUPPER(*needle)) { + // matched starting char -- loop through remaining chars + const char *h, *n; + for (h = haystack, n = needle; *h && *n; ++h, ++n) { + if (TOUPPER(*h) != TOUPPER(*n)) { + break; + } + } + if (!*n) { // matched all of 'needle' to null termination + return haystack; // return the start of the match + } + } + } + return 0; } #ifdef __WIN32 -char* _strtok_r(char *s1, const char *s2, char **lasts) +char *_strtok_r(char *s1, const char *s2, char **lasts) { - char *ret; - - if (s1 == NULL) - s1 = *lasts; - while(*s1 && strchr(s2, *s1)) - ++s1; - if(*s1 == '\0') - return NULL; - ret = s1; - while(*s1 && !strchr(s2, *s1)) - ++s1; - if(*s1) - *s1++ = '\0'; - *lasts = s1; - return ret; + char *ret; + + if (s1 == NULL) + s1 = *lasts; + while (*s1 && strchr(s2, *s1)) + ++s1; + if (*s1 == '\0') + return NULL; + ret = s1; + while (*s1 && !strchr(s2, *s1)) + ++s1; + if (*s1) + *s1++ = '\0'; + *lasts = s1; + return ret; } #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ -size_t strnlen (const char* string, size_t maxlen) +size_t strnlen(const char *string, size_t maxlen) { - const char* end = (const char*)memchr(string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; + const char *end = (const char *)memchr(string, '\0', maxlen); + return end ? (size_t)(end - string) : maxlen; } #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base) +uint64 strtoull(const char *str, char **endptr, int base) { - uint64 result; - int count; - int n; - - if( base == 0 ) - { - if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) - base = 16; - else - if( str[0] == '0' ) - base = 8; - else - base = 10; - } - - if( base == 8 ) - count = sscanf(str, "%I64o%n", &result, &n); - else - if( base == 10 ) - count = sscanf(str, "%I64u%n", &result, &n); - else - if( base == 16 ) - count = sscanf(str, "%I64x%n", &result, &n); - else - count = 0; // fail - - if( count < 1 ) - { - errno = EINVAL; - result = 0; - n = 0; - } - - if( endptr ) - *endptr = (char*)str + n; - - return result; + uint64 result; + int count; + int n; + + if (base == 0) { + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + base = 16; + else if (str[0] == '0') + base = 8; + else + base = 10; + } + + if (base == 8) + count = sscanf(str, "%I64o%n", &result, &n); + else if (base == 10) + count = sscanf(str, "%I64u%n", &result, &n); + else if (base == 16) + count = sscanf(str, "%I64x%n", &result, &n); + else + count = 0; // fail + + if (count < 1) { + errno = EINVAL; + result = 0; + n = 0; + } + + if (endptr) + *endptr = (char *)str + n; + + return result; } #endif //---------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //---------------------------------------------------- -int e_mail_check(char* email) +int e_mail_check(char *email) { - char ch; - char* last_arobas; - size_t len = strlen(email); + char ch; + char *last_arobas; + size_t len = strlen(email); - // athena limits - if (len < 3 || len > 39) - return 0; + // athena limits + if (len < 3 || len > 39) + return 0; - // part of RFC limits (official reference of e-mail description) - if (strchr(email, '@') == NULL || email[len-1] == '@') - return 0; + // part of RFC limits (official reference of e-mail description) + if (strchr(email, '@') == NULL || email[len-1] == '@') + return 0; - if (email[len-1] == '.') - return 0; + if (email[len-1] == '.') + return 0; - last_arobas = strrchr(email, '@'); + last_arobas = strrchr(email, '@'); - if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) - return 0; + if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) + return 0; - for(ch = 1; ch < 32; ch++) - if (strchr(last_arobas, ch) != NULL) - return 0; + for (ch = 1; ch < 32; ch++) + if (strchr(last_arobas, ch) != NULL) + return 0; - if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) - return 0; + if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) + return 0; - // all correct - return 1; + // all correct + return 1; } //-------------------------------------------------- // Return numerical value of a switch configuration // on/off, english, français, deutsch, español //-------------------------------------------------- -int config_switch(const char* str) +int config_switch(const char *str) { - if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) - return 1; - if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) - return 0; + if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) + return 1; + if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) + return 0; - return (int)strtol(str, NULL, 0); + return (int)strtol(str, NULL, 0); } /// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n) +char *safestrncpy(char *dst, const char *src, size_t n) { - if( n > 0 ) - { - char* d = dst; - const char* s = src; - d[--n] = '\0';/* nul-terminate string */ - for( ; n > 0; --n ) - { - if( (*d++ = *s++) == '\0' ) - {/* nul-pad remaining bytes */ - while( --n > 0 ) - *d++ = '\0'; - break; - } - } - } - return dst; + if (n > 0) { + char *d = dst; + const char *s = src; + d[--n] = '\0';/* nul-terminate string */ + for (; n > 0; --n) { + if ((*d++ = *s++) == '\0') { + /* nul-pad remaining bytes */ + while (--n > 0) + *d++ = '\0'; + break; + } + } + } + return dst; } /// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen) +size_t safestrnlen(const char *string, size_t maxlen) { - return ( string != NULL ) ? strnlen(string, maxlen) : 0; + return (string != NULL) ? strnlen(string, maxlen) : 0; } /// Works like snprintf, but always nul-terminates the buffer. @@ -379,41 +367,40 @@ size_t safestrnlen(const char* string, size_t maxlen) /// @param fmt Format string /// @param ... Format arguments /// @return The size of the string or -1 if the buffer is too small -int safesnprintf(char* buf, size_t sz, const char* fmt, ...) +int safesnprintf(char *buf, size_t sz, const char *fmt, ...) { - va_list ap; - int ret; - - va_start(ap,fmt); - ret = vsnprintf(buf, sz, fmt, ap); - va_end(ap); - if( ret < 0 || (size_t)ret >= sz ) - {// overflow - buf[sz-1] = '\0';// always nul-terminate - return -1; - } - return ret; + va_list ap; + int ret; + + va_start(ap,fmt); + ret = vsnprintf(buf, sz, fmt, ap); + va_end(ap); + if (ret < 0 || (size_t)ret >= sz) { + // overflow + buf[sz-1] = '\0';// always nul-terminate + return -1; + } + return ret; } /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char* str, size_t pos) +int strline(const char *str, size_t pos) { - const char* target; - int line; - - if( str == NULL || pos == 0 ) - return 1; - - target = str+pos; - for( line = 1; ; ++line ) - { - str = strchr(str, '\n'); - if( str == NULL || target <= str ) - break;// found target line - ++str;// skip newline - } - return line; + const char *target; + int line; + + if (str == NULL || pos == 0) + return 1; + + target = str+pos; + for (line = 1; ; ++line) { + str = strchr(str, '\n'); + if (str == NULL || target <= str) + break;// found target line + ++str;// skip newline + } + return line; } /// Produces the hexadecimal representation of the given input. @@ -423,19 +410,18 @@ int strline(const char* str, size_t pos) /// @param output Output string /// @param input Binary input buffer /// @param count Number of bytes to convert -bool bin2hex(char* output, unsigned char* input, size_t count) +bool bin2hex(char *output, unsigned char *input, size_t count) { - char toHex[] = "0123456789abcdef"; - size_t i; - - for( i = 0; i < count; ++i ) - { - *output++ = toHex[(*input & 0xF0) >> 4]; - *output++ = toHex[(*input & 0x0F) >> 0]; - ++input; - } - *output = '\0'; - return true; + char toHex[] = "0123456789abcdef"; + size_t i; + + for (i = 0; i < count; ++i) { + *output++ = toHex[(*input & 0xF0) >> 4]; + *output++ = toHex[(*input & 0x0F) >> 0]; + ++input; + } + *output = '\0'; + return true; } @@ -446,146 +432,134 @@ bool bin2hex(char* output, unsigned char* input, size_t count) /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if already done, -1 on error. -int sv_parse_next(struct s_svstate* sv) +int sv_parse_next(struct s_svstate *sv) { - enum { - START_OF_FIELD, - PARSING_FIELD, - PARSING_C_ESCAPE, - END_OF_FIELD, - TERMINATE, - END - } state; - const char* str; - int len; - enum e_svopt opt; - char delim; - int i; - - if( sv == NULL ) - return -1;// error - - str = sv->str; - len = sv->len; - opt = sv->opt; - delim = sv->delim; - - // check opt - if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) ) - { - ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) ) - { - ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - - if( sv->done || str == NULL ) - { - sv->done = true; - return 0;// nothing to parse - } + enum { + START_OF_FIELD, + PARSING_FIELD, + PARSING_C_ESCAPE, + END_OF_FIELD, + TERMINATE, + END + } state; + const char *str; + int len; + enum e_svopt opt; + char delim; + int i; + + if (sv == NULL) + return -1;// error + + str = sv->str; + len = sv->len; + opt = sv->opt; + delim = sv->delim; + + // check opt + if (delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF))) { + ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + if (delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR))) { + ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + + if (sv->done || str == NULL) { + sv->done = true; + return 0;// nothing to parse + } #define IS_END() ( i >= len ) #define IS_DELIM() ( str[i] == delim ) #define IS_TERMINATOR() ( \ - ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ - ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ - ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) + ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ + ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ + ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' ) #define SET_FIELD_START() sv->start = i #define SET_FIELD_END() sv->end = i - i = sv->off; - state = START_OF_FIELD; - while( state != END ) - { - switch( state ) - { - case START_OF_FIELD:// record start of field and start parsing it - SET_FIELD_START(); - state = PARSING_FIELD; - break; - - case PARSING_FIELD:// skip field character - if( IS_END() || IS_DELIM() || IS_TERMINATOR() ) - state = END_OF_FIELD; - else if( IS_C_ESCAPE() ) - state = PARSING_C_ESCAPE; - else - ++i;// normal character - break; - - case PARSING_C_ESCAPE:// skip escape sequence (validates it too) - { - ++i;// '\\' - if( IS_END() ) - { - ShowError("sv_parse_next: empty escape sequence\n"); - return -1; - } - if( str[i] == 'x' ) - {// hex escape - ++i;// 'x' - if( IS_END() || !ISXDIGIT(str[i]) ) - { - ShowError("sv_parse_next: \\x with no following hex digits\n"); - return -1; - } - do{ - ++i;// hex digit - }while( !IS_END() && ISXDIGIT(str[i])); - } - else if( str[i] == '0' || str[i] == '1' || str[i] == '2' ) - {// octal escape - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - } - else if( strchr(SV_ESCAPE_C_SUPPORTED, str[i]) ) - {// supported escape character - ++i; - } - else - { - ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); - return -1; - } - state = PARSING_FIELD; - break; - } - - case END_OF_FIELD:// record end of field and stop - SET_FIELD_END(); - state = END; - if( IS_END() ) - ;// nothing else - else if( IS_DELIM() ) - ++i;// delim - else if( IS_TERMINATOR() ) - state = TERMINATE; - break; - - case TERMINATE: + i = sv->off; + state = START_OF_FIELD; + while (state != END) { + switch (state) { + case START_OF_FIELD:// record start of field and start parsing it + SET_FIELD_START(); + state = PARSING_FIELD; + break; + + case PARSING_FIELD:// skip field character + if (IS_END() || IS_DELIM() || IS_TERMINATOR()) + state = END_OF_FIELD; + else if (IS_C_ESCAPE()) + state = PARSING_C_ESCAPE; + else + ++i;// normal character + break; + + case PARSING_C_ESCAPE: { // skip escape sequence (validates it too) + ++i;// '\\' + if (IS_END()) { + ShowError("sv_parse_next: empty escape sequence\n"); + return -1; + } + if (str[i] == 'x') { + // hex escape + ++i;// 'x' + if (IS_END() || !ISXDIGIT(str[i])) { + ShowError("sv_parse_next: \\x with no following hex digits\n"); + return -1; + } + do { + ++i;// hex digit + } while (!IS_END() && ISXDIGIT(str[i])); + } else if (str[i] == '0' || str[i] == '1' || str[i] == '2') { + // octal escape + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + } else if (strchr(SV_ESCAPE_C_SUPPORTED, str[i])) { + // supported escape character + ++i; + } else { + ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); + return -1; + } + state = PARSING_FIELD; + break; + } + + case END_OF_FIELD:// record end of field and stop + SET_FIELD_END(); + state = END; + if (IS_END()) + ;// nothing else + else if (IS_DELIM()) + ++i;// delim + else if (IS_TERMINATOR()) + state = TERMINATE; + break; + + case TERMINATE: #if 0 - // skip line terminator - if( (opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n' ) - i += 2;// CRLF - else - ++i;// CR or LF + // skip line terminator + if ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') + i += 2;// CRLF + else + ++i;// CR or LF #endif - sv->done = true; - state = END; - break; - } - } - if( IS_END() ) - sv->done = true; - sv->off = i; + sv->done = true; + state = END; + break; + } + } + if (IS_END()) + sv->done = true; + sv->off = i; #undef IS_END #undef IS_DELIM @@ -594,7 +568,7 @@ int sv_parse_next(struct s_svstate* sv) #undef SET_FIELD_START #undef SET_FIELD_END - return 1; + return 1; } @@ -603,13 +577,13 @@ int sv_parse_next(struct s_svstate* sv) /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_pos can be NULL. /// If a line terminator is found, the end position is placed there. -/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] +/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] /// for the seconds field and so on. /// Unfilled positions are set to -1. -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -618,35 +592,34 @@ int sv_parse_next(struct s_svstate* sv) /// @param npos Size of the pos array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) +int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt) { - struct s_svstate sv; - int count; - - // initialize - if( out_pos == NULL ) npos = 0; - for( count = 0; count < npos; ++count ) - out_pos[count] = -1; - sv.str = str; - sv.len = len; - sv.off = startoff; - sv.opt = opt; - sv.delim = delim; - sv.done = false; - - // parse - count = 0; - if( npos > 0 ) out_pos[0] = startoff; - while( !sv.done ) - { - ++count; - if( sv_parse_next(&sv) <= 0 ) - return -1;// error - if( npos > count*2 ) out_pos[count*2] = sv.start; - if( npos > count*2+1 ) out_pos[count*2+1] = sv.end; - } - if( npos > 1 ) out_pos[1] = sv.off; - return count; + struct s_svstate sv; + int count; + + // initialize + if (out_pos == NULL) npos = 0; + for (count = 0; count < npos; ++count) + out_pos[count] = -1; + sv.str = str; + sv.len = len; + sv.off = startoff; + sv.opt = opt; + sv.delim = delim; + sv.done = false; + + // parse + count = 0; + if (npos > 0) out_pos[0] = startoff; + while (!sv.done) { + ++count; + if (sv_parse_next(&sv) <= 0) + return -1;// error + if (npos > count*2) out_pos[count*2] = sv.start; + if (npos > count*2+1) out_pos[count*2+1] = sv.end; + } + if (npos > 1) out_pos[1] = sv.off; + return count; } /// Splits a delim-separated string. @@ -655,11 +628,11 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_fields can be NULL. /// Fields that don't fit in out_fields are not nul-terminated. /// Extra entries in out_fields are filled with the end of the last field (empty string). -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -668,75 +641,64 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// @param nfields Size of the field array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) +int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt) { - int pos[1024]; - int i; - int done; - char* end; - int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); - - if( ret == -1 || out_fields == NULL || nfields <= 0 ) - return ret; // nothing to do - - // next line - end = str + pos[1]; - if( end[0] == '\0' ) - { - *out_fields = end; - } - else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = end[1] = '\0'; - *out_fields = end + 2; - } - else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else - { - ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); - return -1;// error - } - ++out_fields; - --nfields; - - // fields - i = 2; - done = 0; - while( done < ret && nfields > 0 ) - { - if( i < ARRAYLENGTH(pos) ) - {// split field - *out_fields = str + pos[i]; - end = str + pos[i+1]; - *end = '\0'; - // next field - i += 2; - ++done; - ++out_fields; - --nfields; - } - else - {// get more fields - sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); - i = 2; - } - } - // remaining fields - for( i = 0; i < nfields; ++i ) - out_fields[i] = end; - return ret; + int pos[1024]; + int i; + int done; + char *end; + int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); + + if (ret == -1 || out_fields == NULL || nfields <= 0) + return ret; // nothing to do + + // next line + end = str + pos[1]; + if (end[0] == '\0') { + *out_fields = end; + } else if ((opt&SV_TERMINATE_LF) && end[0] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else if ((opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = end[1] = '\0'; + *out_fields = end + 2; + } else if ((opt&SV_TERMINATE_CR) && end[0] == '\r') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else { + ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); + return -1;// error + } + ++out_fields; + --nfields; + + // fields + i = 2; + done = 0; + while (done < ret && nfields > 0) { + if (i < ARRAYLENGTH(pos)) { + // split field + *out_fields = str + pos[i]; + end = str + pos[i+1]; + *end = '\0'; + // next field + i += 2; + ++done; + ++out_fields; + --nfields; + } else { + // get more fields + sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); + i = 2; + } + } + // remaining fields + for (i = 0; i < nfields; ++i) + out_fields[i] = end; + return ret; } /// Escapes src to out_dest according to the format of the C compiler. @@ -748,69 +710,77 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in /// @param len Length of the source string /// @param escapes Extra characters to be escaped /// @return Length of the escaped string -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) +size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes) { - size_t i; - size_t j; - - if( out_dest == NULL ) - return 0;// nothing to do - if( src == NULL ) - {// nothing to escape - *out_dest = 0; - return 0; - } - if( escapes == NULL ) - escapes = ""; - - for( i = 0, j = 0; i < len; ++i ) - { - switch( src[i] ) - { - case '\0':// octal 0 - out_dest[j++] = '\\'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - break; - case '\r':// carriage return - out_dest[j++] = '\\'; - out_dest[j++] = 'r'; - break; - case '\n':// line feed - out_dest[j++] = '\\'; - out_dest[j++] = 'n'; - break; - case '\\':// escape character - out_dest[j++] = '\\'; - out_dest[j++] = '\\'; - break; - default: - if( strchr(escapes,src[i]) ) - {// escape - out_dest[j++] = '\\'; - switch( src[i] ) - { - case '\a': out_dest[j++] = 'a'; break; - case '\b': out_dest[j++] = 'b'; break; - case '\t': out_dest[j++] = 't'; break; - case '\v': out_dest[j++] = 'v'; break; - case '\f': out_dest[j++] = 'f'; break; - case '\?': out_dest[j++] = '?'; break; - default:// to octal - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); - break; - } - } - else - out_dest[j++] = src[i]; - break; - } - } - out_dest[j] = 0; - return j; + size_t i; + size_t j; + + if (out_dest == NULL) + return 0;// nothing to do + if (src == NULL) { + // nothing to escape + *out_dest = 0; + return 0; + } + if (escapes == NULL) + escapes = ""; + + for (i = 0, j = 0; i < len; ++i) { + switch (src[i]) { + case '\0':// octal 0 + out_dest[j++] = '\\'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + break; + case '\r':// carriage return + out_dest[j++] = '\\'; + out_dest[j++] = 'r'; + break; + case '\n':// line feed + out_dest[j++] = '\\'; + out_dest[j++] = 'n'; + break; + case '\\':// escape character + out_dest[j++] = '\\'; + out_dest[j++] = '\\'; + break; + default: + if (strchr(escapes,src[i])) { + // escape + out_dest[j++] = '\\'; + switch (src[i]) { + case '\a': + out_dest[j++] = 'a'; + break; + case '\b': + out_dest[j++] = 'b'; + break; + case '\t': + out_dest[j++] = 't'; + break; + case '\v': + out_dest[j++] = 'v'; + break; + case '\f': + out_dest[j++] = 'f'; + break; + case '\?': + out_dest[j++] = '?'; + break; + default:// to octal + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007))); + break; + } + } else + out_dest[j++] = src[i]; + break; + } + } + out_dest[j] = 0; + return j; } /// Unescapes src to out_dest according to the format of the C compiler. @@ -821,129 +791,135 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca /// @param src Source string /// @param len Length of the source string /// @return Length of the escaped string -size_t sv_unescape_c(char* out_dest, const char* src, size_t len) +size_t sv_unescape_c(char *out_dest, const char *src, size_t len) { - static unsigned char low2hex[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? - }; - size_t i; - size_t j; - - for( i = 0, j = 0; i < len; ) - { - if( src[i] == '\\' ) - { - ++i;// '\\' - if( i >= len ) - ShowWarning("sv_unescape_c: empty escape sequence\n"); - else if( src[i] == 'x' ) - {// hex escape sequence - unsigned char c = 0; - unsigned char inrange = 1; - - ++i;// 'x' - if( i >= len || !ISXDIGIT(src[i]) ) - { - ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); - continue; - } - do{ - if( c > 0x0F && inrange ) - { - ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); - inrange = 0; - } - c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit - ++i; - }while( i < len && ISXDIGIT(src[i]) ); - out_dest[j++] = (char)c; - } - else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) - {// octal escape sequence (255=0377) - unsigned char c = src[i]-'0'; - ++i;// '0', '1', '2' or '3' - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - out_dest[j++] = (char)c; - } - else - {// other escape sequence - if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL ) - ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); - switch( src[i] ) - { - case 'a': out_dest[j++] = '\a'; break; - case 'b': out_dest[j++] = '\b'; break; - case 't': out_dest[j++] = '\t'; break; - case 'n': out_dest[j++] = '\n'; break; - case 'v': out_dest[j++] = '\v'; break; - case 'f': out_dest[j++] = '\f'; break; - case 'r': out_dest[j++] = '\r'; break; - case '?': out_dest[j++] = '\?'; break; - default: out_dest[j++] = src[i]; break; - } - ++i;// escaped character - } - } - else - out_dest[j++] = src[i++];// normal character - } - out_dest[j] = 0; - return j; + static unsigned char low2hex[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? + }; + size_t i; + size_t j; + + for (i = 0, j = 0; i < len;) { + if (src[i] == '\\') { + ++i;// '\\' + if (i >= len) + ShowWarning("sv_unescape_c: empty escape sequence\n"); + else if (src[i] == 'x') { + // hex escape sequence + unsigned char c = 0; + unsigned char inrange = 1; + + ++i;// 'x' + if (i >= len || !ISXDIGIT(src[i])) { + ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); + continue; + } + do { + if (c > 0x0F && inrange) { + ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); + inrange = 0; + } + c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit + ++i; + } while (i < len && ISXDIGIT(src[i])); + out_dest[j++] = (char)c; + } else if (src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3') { + // octal escape sequence (255=0377) + unsigned char c = src[i]-'0'; + ++i;// '0', '1', '2' or '3' + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + out_dest[j++] = (char)c; + } else { + // other escape sequence + if (strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL) + ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); + switch (src[i]) { + case 'a': + out_dest[j++] = '\a'; + break; + case 'b': + out_dest[j++] = '\b'; + break; + case 't': + out_dest[j++] = '\t'; + break; + case 'n': + out_dest[j++] = '\n'; + break; + case 'v': + out_dest[j++] = '\v'; + break; + case 'f': + out_dest[j++] = '\f'; + break; + case 'r': + out_dest[j++] = '\r'; + break; + case '?': + out_dest[j++] = '\?'; + break; + default: + out_dest[j++] = src[i]; + break; + } + ++i;// escaped character + } + } else + out_dest[j++] = src[i++];// normal character + } + out_dest[j] = 0; + return j; } /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p) +const char *skip_escaped_c(const char *p) { - if( p && *p == '\\' ) - { - ++p; - switch( *p ) - { - case 'x':// hexadecimal - ++p; - while( ISXDIGIT(*p) ) - ++p; - break; - case '0': - case '1': - case '2': - case '3':// octal - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - break; - default: - if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) - ++p; - } - } - return p; + if (p && *p == '\\') { + ++p; + switch (*p) { + case 'x':// hexadecimal + ++p; + while (ISXDIGIT(*p)) + ++p; + break; + case '0': + case '1': + case '2': + case '3':// octal + ++p; + if (*p >= '0' && *p <= '7') + ++p; + if (*p >= '0' && *p <= '7') + ++p; + break; + default: + if (*p && strchr(SV_ESCAPE_C_SUPPORTED, *p)) + ++p; + } + } + return p; } @@ -958,78 +934,72 @@ const char* skip_escaped_c(const char* p) /// @param maxcols Maximum number of columns of a valid row /// @param parseproc User-supplied row processing function /// @return true on success, false if file could not be opened -bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)) +bool sv_readdb(const char *directory, const char *filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char *fields[], int columns, int current)) { - FILE* fp; - int lines = 0; - int entries = 0; - char** fields; // buffer for fields ([0] is reserved) - int columns, fields_length; - char path[1024], line[1024]; - char* match; - - snprintf(path, sizeof(path), "%s/%s", directory, filename); - - // open file - fp = fopen(path, "r"); - if( fp == NULL ) - { - ShowError("sv_readdb: can't read %s\n", path); - return false; - } - - // allocate enough memory for the maximum requested amount of columns plus the reserved one - fields_length = maxcols+1; - fields = (char**)aMalloc(fields_length*sizeof(char*)); - - // process rows one by one - while( fgets(line, sizeof(line), fp) ) - { - lines++; - - if( ( match = strstr(line, "//") ) != NULL ) - {// strip comments - match[0] = 0; - } - - //TODO: strip trailing whitespace - if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - - columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - - if( columns < mincols ) - { - ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); - continue; // not enough columns - } - if( columns > maxcols ) - { - ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols ); - continue; // too many columns - } - if( entries == maxrows ) - { - ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); - break; - } - - // parse this row - if( !parseproc(fields+1, columns, entries) ) - { - ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); - continue; // invalid row contents - } - - // success! - entries++; - } - - aFree(fields); - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); - - return true; + FILE *fp; + int lines = 0; + int entries = 0; + char **fields; // buffer for fields ([0] is reserved) + int columns, fields_length; + char path[1024], line[1024]; + char *match; + + snprintf(path, sizeof(path), "%s/%s", directory, filename); + + // open file + fp = fopen(path, "r"); + if (fp == NULL) { + ShowError("sv_readdb: can't read %s\n", path); + return false; + } + + // allocate enough memory for the maximum requested amount of columns plus the reserved one + fields_length = maxcols+1; + fields = (char **)aMalloc(fields_length*sizeof(char *)); + + // process rows one by one + while (fgets(line, sizeof(line), fp)) { + lines++; + + if ((match = strstr(line, "//")) != NULL) { + // strip comments + match[0] = 0; + } + + //TODO: strip trailing whitespace + if (line[0] == '\0' || line[0] == '\n' || line[0] == '\r') + continue; + + columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); + + if (columns < mincols) { + ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); + continue; // not enough columns + } + if (columns > maxcols) { + ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols); + continue; // too many columns + } + if (entries == maxrows) { + ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); + break; + } + + // parse this row + if (!parseproc(fields+1, columns, entries)) { + ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); + continue; // invalid row contents + } + + // success! + entries++; + } + + aFree(fields); + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); + + return true; } @@ -1039,129 +1009,126 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc // @author MouseJstr (original) /// Allocates a StringBuf -StringBuf* StringBuf_Malloc() +StringBuf *StringBuf_Malloc() { - StringBuf* self; - CREATE(self, StringBuf, 1); - StringBuf_Init(self); - return self; + StringBuf *self; + CREATE(self, StringBuf, 1); + StringBuf_Init(self); + return self; } /// Initializes a previously allocated StringBuf -void StringBuf_Init(StringBuf* self) +void StringBuf_Init(StringBuf *self) { - self->max_ = 1024; - self->ptr_ = self->buf_ = (char*)aMalloc(self->max_ + 1); + self->max_ = 1024; + self->ptr_ = self->buf_ = (char *)aMalloc(self->max_ + 1); } /// Appends the result of printf to the StringBuf -int StringBuf_Printf(StringBuf* self, const char* fmt, ...) +int StringBuf_Printf(StringBuf *self, const char *fmt, ...) { - int len; - va_list ap; + int len; + va_list ap; - va_start(ap, fmt); - len = StringBuf_Vprintf(self, fmt, ap); - va_end(ap); + va_start(ap, fmt); + len = StringBuf_Vprintf(self, fmt, ap); + va_end(ap); - return len; + return len; } /// Appends the result of vprintf to the StringBuf -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) +int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list ap) { - int n, size, off; - - for(;;) - { - va_list apcopy; - /* Try to print in the allocated space. */ - size = self->max_ - (self->ptr_ - self->buf_); - va_copy(apcopy, ap); - n = vsnprintf(self->ptr_, size, fmt, apcopy); - va_end(apcopy); - /* If that worked, return the length. */ - if( n > -1 && n < size ) - { - self->ptr_ += n; - return (int)(self->ptr_ - self->buf_); - } - /* Else try again with more space. */ - self->max_ *= 2; // twice the old size - off = (int)(self->ptr_ - self->buf_); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } + int n, size, off; + + for (;;) { + va_list apcopy; + /* Try to print in the allocated space. */ + size = self->max_ - (self->ptr_ - self->buf_); + va_copy(apcopy, ap); + n = vsnprintf(self->ptr_, size, fmt, apcopy); + va_end(apcopy); + /* If that worked, return the length. */ + if (n > -1 && n < size) { + self->ptr_ += n; + return (int)(self->ptr_ - self->buf_); + } + /* Else try again with more space. */ + self->max_ *= 2; // twice the old size + off = (int)(self->ptr_ - self->buf_); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } } /// Appends the contents of another StringBuf to the StringBuf -int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) +int StringBuf_Append(StringBuf *self, const StringBuf *sbuf) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)(sbuf->ptr_ - sbuf->buf_); - - if( needed >= available ) - { - int off = (int)(self->ptr_ - self->buf_); - self->max_ += needed; - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, sbuf->buf_, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)(sbuf->ptr_ - sbuf->buf_); + + if (needed >= available) { + int off = (int)(self->ptr_ - self->buf_); + self->max_ += needed; + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, sbuf->buf_, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Appends str to the StringBuf -int StringBuf_AppendStr(StringBuf* self, const char* str) +int StringBuf_AppendStr(StringBuf *self, const char *str) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)strlen(str); - - if( needed >= available ) - {// not enough space, expand the buffer (minimum expansion = 1024) - int off = (int)(self->ptr_ - self->buf_); - self->max_ += max(needed, 1024); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, str, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)strlen(str); + + if (needed >= available) { + // not enough space, expand the buffer (minimum expansion = 1024) + int off = (int)(self->ptr_ - self->buf_); + self->max_ += max(needed, 1024); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, str, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Returns the length of the data in the Stringbuf -int StringBuf_Length(StringBuf* self) +int StringBuf_Length(StringBuf *self) { - return (int)(self->ptr_ - self->buf_); + return (int)(self->ptr_ - self->buf_); } /// Returns the data in the StringBuf -char* StringBuf_Value(StringBuf* self) +char *StringBuf_Value(StringBuf *self) { - *self->ptr_ = '\0'; - return self->buf_; + *self->ptr_ = '\0'; + return self->buf_; } /// Clears the contents of the StringBuf -void StringBuf_Clear(StringBuf* self) +void StringBuf_Clear(StringBuf *self) { - self->ptr_ = self->buf_; + self->ptr_ = self->buf_; } /// Destroys the StringBuf -void StringBuf_Destroy(StringBuf* self) +void StringBuf_Destroy(StringBuf *self) { - aFree(self->buf_); - self->ptr_ = self->buf_ = 0; - self->max_ = 0; + aFree(self->buf_); + self->ptr_ = self->buf_ = 0; + self->max_ = 0; } // Frees a StringBuf returned by StringBuf_Malloc -void StringBuf_Free(StringBuf* self) +void StringBuf_Free(StringBuf *self) { - StringBuf_Destroy(self); - aFree(self); + StringBuf_Destroy(self); + aFree(self); } |