summaryrefslogtreecommitdiff
path: root/src/common/strlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/strlib.c')
-rw-r--r--src/common/strlib.c136
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;
}