diff options
Diffstat (limited to 'src/common/strlib.c')
-rw-r--r-- | src/common/strlib.c | 136 |
1 files changed, 89 insertions, 47 deletions
diff --git a/src/common/strlib.c b/src/common/strlib.c index 66f281ffc..097f499e6 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -441,30 +441,13 @@ bool bin2hex(char* output, unsigned char* input, size_t count) ///////////////////////////////////////////////////////////////////// -/// Parses a delim-separated string. -/// Starts parsing at startoff and fills the pos array with position pairs. -/// 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] -/// 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 -/// @param delim Field delimiter -/// @param out_pos Array of resulting positions -/// @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) +/// Parses a single field in a delim-separated string. +/// The delimiter after the field is skipped. +/// +/// @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 i; - int count; enum { START_OF_FIELD, PARSING_FIELD, @@ -473,27 +456,37 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i TERMINATE, END } state; + const char* str; + int len; + enum e_svopt opt; + char delim; + int i; - // check pos/npos - if( out_pos == NULL ) npos = 0; - for( i = 0; i < npos; ++i ) - out_pos[i] = -1; + 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: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); + 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: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); + ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); return -1;// error } - // check str - if( str == NULL ) + if( sv->done || str == NULL ) + { + sv->done = true; return 0;// nothing to parse + } #define IS_END() ( i >= len ) #define IS_DELIM() ( str[i] == delim ) @@ -502,16 +495,13 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i ((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() if( npos > count*2+2 ) out_pos[count*2+2] = i -#define SET_FIELD_END() if( npos > count*2+3 ) out_pos[count*2+3] = i; ++count +#define SET_FIELD_START() sv->start = i +#define SET_FIELD_END() sv->end = i - i = startoff; - count = 0; + i = sv->off; state = START_OF_FIELD; - if( npos > 0 ) out_pos[0] = startoff;// start while( state != END ) { - if( npos > 1 ) out_pos[1] = i;// end switch( state ) { case START_OF_FIELD:// record start of field and start parsing it @@ -533,7 +523,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i ++i;// '\\' if( IS_END() ) { - ShowError("sv_parse: empty escape sequence\n"); + ShowError("sv_parse_next: empty escape sequence\n"); return -1; } if( str[i] == 'x' ) @@ -541,7 +531,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i ++i;// 'x' if( IS_END() || !ISXDIGIT(str[i]) ) { - ShowError("sv_parse: \\x with no following hex digits\n"); + ShowError("sv_parse_next: \\x with no following hex digits\n"); return -1; } do{ @@ -562,26 +552,22 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i } else { - ShowError("sv_parse: unknown escape sequence \\%c\n", str[i]); + 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 continue + case END_OF_FIELD:// record end of field and stop SET_FIELD_END(); + state = END; if( IS_END() ) - state = END; + ;// nothing else else if( IS_DELIM() ) - { ++i;// delim - state = START_OF_FIELD; - } else if( IS_TERMINATOR() ) state = TERMINATE; - else - state = START_OF_FIELD; break; case TERMINATE: @@ -592,10 +578,14 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i else ++i;// CR or LF #endif + sv->done = true; state = END; break; } } + if( IS_END() ) + sv->done = true; + sv->off = i; #undef IS_END #undef IS_DELIM @@ -604,6 +594,58 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i #undef SET_FIELD_START #undef SET_FIELD_END + return 1; +} + + +/// Parses a delim-separated string. +/// Starts parsing at startoff and fills the pos array with position pairs. +/// 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] +/// 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 +/// @param delim Field delimiter +/// @param out_pos Array of resulting positions +/// @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) +{ + 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; } |