Skip to content

Commit e2bae69

Browse files
authored
Merge pull request #160 from ndevilla/quote-and-escape
Quote and escape
2 parents f00e027 + 8854c48 commit e2bae69

File tree

4 files changed

+375
-7
lines changed

4 files changed

+375
-7
lines changed

src/iniparser.c

+71-7
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,26 @@ void iniparser_dump(const dictionary * d, FILE * f)
247247
return ;
248248
}
249249

250+
static void escape_value(char *escaped, char *value) {
251+
char c;
252+
int v = 0;
253+
int e = 0;
254+
255+
if(!escaped || !value)
256+
return;
257+
258+
while((c = value[v]) != '\0') {
259+
if(c == '\\' || c == '"') {
260+
escaped[e] = '\\';
261+
e++;
262+
}
263+
escaped[e] = c;
264+
v++;
265+
e++;
266+
}
267+
escaped[e] = '\0';
268+
}
269+
250270
/*-------------------------------------------------------------------------*/
251271
/**
252272
@brief Save a dictionary to a loadable ini file
@@ -263,6 +283,7 @@ void iniparser_dump_ini(const dictionary * d, FILE * f)
263283
size_t i ;
264284
size_t nsec ;
265285
const char * secname ;
286+
char escaped[ASCIILINESZ+1] = "";
266287

267288
if (d==NULL || f==NULL) return ;
268289

@@ -272,7 +293,8 @@ void iniparser_dump_ini(const dictionary * d, FILE * f)
272293
for (i=0 ; i<d->size ; i++) {
273294
if (d->key[i]==NULL)
274295
continue ;
275-
fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
296+
escape_value(escaped, d->val[i]);
297+
fprintf(f, "%s = \"%s\"\n", d->key[i], escaped);
276298
}
277299
return ;
278300
}
@@ -301,6 +323,7 @@ void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
301323
size_t j ;
302324
char keym[ASCIILINESZ+1];
303325
int seclen ;
326+
char escaped[ASCIILINESZ+1] = "";
304327

305328
if (d==NULL || f==NULL) return ;
306329
if (! iniparser_find_entry(d, s)) return ;
@@ -312,10 +335,8 @@ void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
312335
if (d->key[j]==NULL)
313336
continue ;
314337
if (!strncmp(d->key[j], keym, seclen+1)) {
315-
fprintf(f,
316-
"%-30s = %s\n",
317-
d->key[j]+seclen+1,
318-
d->val[j] ? d->val[j] : "");
338+
escape_value(escaped, d->val[j]);
339+
fprintf(f, "%-30s = \"%s\"\n", d->key[j]+seclen+1, escaped);
319340
}
320341
}
321342
fprintf(f, "\n");
@@ -642,6 +663,44 @@ void iniparser_unset(dictionary * ini, const char * entry)
642663
dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
643664
}
644665

666+
static void parse_quoted_value(char *value, char quote) {
667+
char c;
668+
char *quoted;
669+
int q = 0, v = 0;
670+
int esc = 0;
671+
672+
if(!value)
673+
return;
674+
675+
quoted = xstrdup(value);
676+
677+
if(!quoted) {
678+
iniparser_error_callback("iniparser: memory allocation failure\n");
679+
goto end_of_value;
680+
}
681+
682+
while((c = quoted[q]) != '\0') {
683+
if(!esc) {
684+
if(c == '\\') {
685+
esc = 1;
686+
q++;
687+
continue;
688+
}
689+
690+
if(c == quote) {
691+
goto end_of_value;
692+
}
693+
}
694+
esc = 0;
695+
value[v] = c;
696+
v++;
697+
q++;
698+
}
699+
end_of_value:
700+
value[v] = '\0';
701+
free(quoted);
702+
}
703+
645704
/*-------------------------------------------------------------------------*/
646705
/**
647706
@brief Load a single line from an INI file
@@ -661,6 +720,7 @@ static line_status iniparser_line(
661720
line_status sta ;
662721
char * line = NULL;
663722
size_t len ;
723+
int d_quote;
664724

665725
line = xstrdup(input_line);
666726
len = strstrip(line);
@@ -678,11 +738,15 @@ static line_status iniparser_line(
678738
strstrip(section);
679739
strlwc(section, section, len);
680740
sta = LINE_SECTION ;
681-
} else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
682-
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) {
741+
} else if ((d_quote = sscanf (line, "%[^=] = \"%[^\n]\"", key, value)) == 2
742+
|| sscanf (line, "%[^=] = '%[^\n]'", key, value) == 2) {
683743
/* Usual key=value with quotes, with or without comments */
684744
strstrip(key);
685745
strlwc(key, key, len);
746+
if(d_quote == 2)
747+
parse_quoted_value(value, '"');
748+
else
749+
parse_quoted_value(value, '\'');
686750
/* Don't strip spaces from values surrounded with quotes */
687751
sta = LINE_VALUE ;
688752
} else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {

src/iniparser.h

+18
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ const char * iniparser_getsecname(const dictionary * d, int n);
8282
8383
This function dumps a given dictionary into a loadable ini file.
8484
It is Ok to specify @c stderr or @c stdout as output files.
85+
86+
All values are quoted these charecters are escaped:
87+
88+
” - the quote character (e.g. “String with ”Quotes””)
89+
90+
\ - the backslash character (e.g. “C:\tmp”)
91+
8592
*/
8693
/*--------------------------------------------------------------------------*/
8794

@@ -382,6 +389,17 @@ int iniparser_find_entry(const dictionary * ini, const char * entry) ;
382389
should not be accessed directly, but through accessor functions
383390
instead.
384391
392+
Iff the value is a quoted string it supports some escape sequences:
393+
394+
” - the quote character (e.g. “String with ”Quotes””)
395+
396+
\ - the backslash character (e.g. “C:\tmp”)
397+
398+
Escape sequences always start with a backslash. Additional escape sequences
399+
might be added in the future. Backslash characters must be escaped. Any other
400+
sequence then those outlined above is invalid and may lead to unpredictable
401+
results.
402+
385403
The returned dictionary must be freed using iniparser_freedict().
386404
*/
387405
/*--------------------------------------------------------------------------*/

test/ressources/quotes.ini

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[quotes]
2+
string0="str\"ing"
3+
string1="str;ing"
4+
string2="str#ing"
5+
string3=str"ing
6+
string4=str;ing
7+
string5=str#ing
8+
str"ing="str\"ing"
9+
"str;ing"="str;ing"
10+
"str#ing"="str#ing"
11+
str:ing="str\"ing"

0 commit comments

Comments
 (0)