Skip to content

Commit

Permalink
Support for reporting current line
Browse files Browse the repository at this point in the history
This is @MaG21's PR #56 but solved a different way, using compile-time flags so it's zero-overhead if you don't need it.
  • Loading branch information
benhoyt committed Dec 29, 2016
1 parent 18a67c5 commit 30a8592
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 6 deletions.
10 changes: 8 additions & 2 deletions ini.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
}
#endif

#if INI_HANDLER_LINENO
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
#else
#define HANDLER(u, s, n, v) handler(u, s, n, v)
#endif

/* Scan through stream line by line */
while (reader(line, INI_MAX_LINE, stream) != NULL) {
lineno++;
Expand All @@ -118,7 +124,7 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
else if (*prev_name && *start && start > line) {
/* Non-blank line with leading whitespace, treat as continuation
of previous name's value (as per Python configparser). */
if (!handler(user, section, prev_name, start) && !error)
if (!HANDLER(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
Expand Down Expand Up @@ -152,7 +158,7 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,

/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
if (!HANDLER(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
Expand Down
11 changes: 11 additions & 0 deletions ini.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,20 @@ extern "C" {

#include <stdio.h>

/* Nonzero if ini_handler callback should accept lineno parameter. */
#ifndef INI_HANDLER_LINENO
#define INI_HANDLER_LINENO 0
#endif

/* Typedef for prototype of handler function. */
#if INI_HANDLER_LINENO
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value,
int lineno);
#else
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value);
#endif

/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
Expand Down
53 changes: 53 additions & 0 deletions tests/baseline_handler_lineno.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
no_file.ini: e=-1 user=0
... [section1]
... one=This is a test; line 3
... two=1234; line 4
... [ section 2 ]
... happy=4; line 8
... sad=; line 9
... [comment_test]
... test1=1;2;3; line 15
... test2=2;3;4;this won't be a comment, needs whitespace before ';'; line 16
... test;3=345; line 17
... test4=4#5#6; line 18
... test7=; line 21
... test8=; not a comment, needs whitespace before ';'; line 22
... [colon_tests]
... Content-Type=text/html; line 25
... foo=bar; line 26
... adams=42; line 27
... funny1=with = equals; line 28
... funny2=with : colons; line 29
... funny3=two = equals; line 30
... funny4=two : colons; line 31
normal.ini: e=0 user=101
... [section1]
... name1=value1; line 2
... name2=value2; line 5
bad_section.ini: e=3 user=102
bad_comment.ini: e=1 user=102
... [section]
... a=b; line 2
... user=parse_error; line 3
... c=d; line 4
user_error.ini: e=3 user=104
... [section1]
... single1=abc; line 2
... multi=this is a; line 3
... multi=multi-line value; line 4
... single2=xyz; line 5
... [section2]
... multi=a; line 7
... multi=b; line 8
... multi=c; line 9
... [section3]
... single=ghi; line 11
... multi=the quick; line 12
... multi=brown fox; line 13
... name=bob smith; line 14
multi_line.ini: e=0 user=105
bad_multi.ini: e=1 user=105
... [bom_section]
... bom_name=bom_value; line 2
... key“=value“; line 3
bom.ini: e=0 user=107
1 change: 1 addition & 0 deletions tests/unittest.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
@call tcc ..\ini.c -I..\ -DINI_ALLOW_MULTILINE=0 -run unittest.c > baseline_single.txt
@call tcc ..\ini.c -I..\ -DINI_ALLOW_INLINE_COMMENTS=0 -run unittest.c > baseline_disallow_inline_comments.txt
@call tcc ..\ini.c -I..\ -DINI_STOP_ON_FIRST_ERROR=1 -run unittest.c > baseline_stop_on_first_error.txt
@call tcc ..\ini.c -I..\ -DINI_HANDLER_LINENO=1 -run unittest.c > baseline_handler_lineno.txt
16 changes: 12 additions & 4 deletions tests/unittest.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ redirected to an output file (baseline_*.txt) and checked into the Subversion
repository. This baseline file is the test output, so the idea is to check it
once, and if it changes -- look at the diff and see which tests failed.
Here's how I produced the two baseline files (with Tiny C Compiler):
tcc -DINI_ALLOW_MULTILINE=1 ../ini.c -run unittest.c > baseline_multi.txt
tcc -DINI_ALLOW_MULTILINE=0 ../ini.c -run unittest.c > baseline_single.txt
See unittest.bat and unittest.sh for how to run this (with tcc and gcc,
respectively).
*/

Expand All @@ -20,16 +18,26 @@ tcc -DINI_ALLOW_MULTILINE=0 ../ini.c -run unittest.c > baseline_single.txt
int User;
char Prev_section[50];

#if INI_HANDLER_LINENO
int dumper(void* user, const char* section, const char* name,
const char* value, int lineno)
#else
int dumper(void* user, const char* section, const char* name,
const char* value)
#endif
{
User = *((int*)user);
if (strcmp(section, Prev_section)) {
printf("... [%s]\n", section);
strncpy(Prev_section, section, sizeof(Prev_section));
Prev_section[sizeof(Prev_section) - 1] = '\0';
}

#if INI_HANDLER_LINENO
printf("... %s=%s; line %d\n", name, value, lineno);
#else
printf("... %s=%s;\n", name, value);
#endif

return strcmp(name, "user")==0 && strcmp(value, "parse_error")==0 ? 0 : 1;
}
Expand Down
4 changes: 4 additions & 0 deletions tests/unittest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ rm -f unittest_disallow_inline_comments
gcc ../ini.c -DINI_STOP_ON_FIRST_ERROR=1 unittest.c -o unittest_stop_on_first_error
./unittest_stop_on_first_error > baseline_stop_on_first_error.txt
rm -f unittest_stop_on_first_error

gcc ../ini.c -DINI_HANDLER_LINENO=1 unittest.c -o unittest_handler_lineno
./unittest_handler_lineno > baseline_handler_lineno.txt
rm -f unittest_handler_lineno

0 comments on commit 30a8592

Please sign in to comment.