32
32
#include "config.h"
33
33
#include "debug.h"
34
34
35
+ struct CFG_buffered_obj
36
+ {
37
+ void * parsed_cfg ;
38
+ char * buff ;
39
+ size_t len ;
40
+ struct CFG_ParseValue val ;
41
+ };
42
+
35
43
static char gConfigPath [PATH_MAX + 1 ] = "" ;
36
44
37
45
const char * CFG_getPath ()
@@ -82,6 +90,11 @@ int CFG_locateConfigFile(const char *name)
82
90
struct CFG_Context {
83
91
FILE * file ;
84
92
int lineNum ;
93
+ char * accum ;
94
+ size_t used , len ;
95
+ char * replay ;
96
+ int stop ;
97
+ int allow_buffering ;
85
98
char buff [1024 * 4 ];
86
99
};
87
100
@@ -97,6 +110,22 @@ static int NextLine(struct CFG_Context *ctx)
97
110
{
98
111
int len , start , i ;
99
112
int skipFlag = 0 ; //If full line is not read in, skip last bit of junk
113
+ char * sep ;
114
+
115
+ if (ctx -> replay ) {
116
+ sep = strchr (ctx -> replay , '\n' );
117
+ if (sep )
118
+ * sep ++ = 0 ;
119
+ strncpy (ctx -> buff , ctx -> replay , sizeof (ctx -> buff ));
120
+ ctx -> buff [sizeof (ctx -> buff ) - 1 ] = 0 ;
121
+ ctx -> replay = sep ;
122
+ if (!sep )
123
+ ctx -> stop = 1 ;
124
+ ctx -> lineNum ++ ;
125
+ return 1 ;
126
+ }
127
+ if (ctx -> stop )
128
+ return 1 ;
100
129
101
130
for ( ; NULL != fgets (ctx -> buff , sizeof (ctx -> buff ), ctx -> file );
102
131
++ ctx -> lineNum ) {
@@ -145,7 +174,7 @@ static void *processKeyValueLine(struct CFG_Context *ctx,
145
174
for (curr = keys ; curr && curr -> name ; curr ++ ) {
146
175
if (!strcasecmp (curr -> name , key )) {
147
176
found = 1 ;
148
- if (curr -> subObj ) {
177
+ if (curr -> lookup_cb ) {
149
178
DBG_print (DBG_LEVEL_WARN , "Warning: Option name '%s' can not be a "
150
179
"sub-object at line %d\n" , key , ctx -> lineNum );
151
180
} else {
@@ -162,6 +191,27 @@ static void *processKeyValueLine(struct CFG_Context *ctx,
162
191
return data ;
163
192
}
164
193
194
+ static void accumulate_line (struct CFG_Context * ctx )
195
+ {
196
+ int len = strlen (ctx -> buff );
197
+
198
+ if (!ctx -> accum || !ctx -> len ) {
199
+ ctx -> len = 1024 ;
200
+ ctx -> accum = malloc (ctx -> len );
201
+ ctx -> used = 0 ;
202
+ }
203
+
204
+ if (len >= ctx -> len - ctx -> used - 3 ) {
205
+ ctx -> len *= 2 ;
206
+ ctx -> accum = realloc (ctx -> accum , ctx -> len );
207
+ }
208
+
209
+ memcpy (& ctx -> accum [ctx -> used ], ctx -> buff , len );
210
+ ctx -> used += len ;
211
+ ctx -> accum [ctx -> used ++ ] = '\n' ;
212
+ ctx -> accum [ctx -> used ] = 0 ;
213
+ }
214
+
165
215
static void * ParseObject (struct CFG_Context * ctx , struct CFG_ParseObj * parObj ,
166
216
void * parData )
167
217
{
@@ -170,9 +220,11 @@ static void *ParseObject(struct CFG_Context *ctx, struct CFG_ParseObj *parObj,
170
220
char * objLcl , * paramsLcl = NULL ;
171
221
int more ;
172
222
struct CFG_ParseValue * curr = NULL ;
173
- struct CFG_ParseObj * child = NULL , * * itr = NULL ;
223
+ struct CFG_ParseObj * child = NULL ;
174
224
void * data = NULL ;
175
225
char subobj_type_buff [256 ];
226
+ int buffer_obj = ctx -> allow_buffering ;
227
+ struct CFG_buffered_obj * obj_buff = NULL ;
176
228
177
229
subobj_type_buff [0 ] = 0 ;
178
230
if (obj [strlen (obj )- 1 ] != '>' ) {
@@ -203,69 +255,84 @@ static void *ParseObject(struct CFG_Context *ctx, struct CFG_ParseObj *parObj,
203
255
}
204
256
}
205
257
206
-
207
- if (parObj ) {
258
+ if (parObj && !ctx -> accum ) {
208
259
for (curr = parObj -> keys ; curr -> name ; curr ++ ) {
209
260
if (!strcasecmp (obj , curr -> name ))
210
261
break ;
211
262
}
212
263
if (!curr -> name )
213
264
curr = NULL ;
214
- if (curr && !curr -> subObj && ! curr -> subObjArr ) {
265
+ if (curr && !curr -> lookup_cb ) {
215
266
DBG_print (DBG_LEVEL_WARN , "Warning: Option %s not a sub"
216
267
"-object ,line %d\n" , obj , ctx -> lineNum );
217
268
curr = NULL ;
218
- } else if (curr && curr -> subObj ) {
219
- child = curr -> subObj ;
220
269
}
221
- else if (curr && ! curr -> subObj && curr -> subObjArr ) {
270
+ else if (curr && curr -> lookup_cb ) {
222
271
snprintf (subobj_type_buff , sizeof (subobj_type_buff ), "__type_%s" , obj );
223
272
subobj_type_buff [sizeof (subobj_type_buff )- 1 ] = 0 ;
224
-
225
- child = NULL ;
226
- itr = curr -> subObjArr ;
227
- while (* itr ) {
228
- if (!strcasecmp ((* itr )-> subtype , paramsLcl )) {
229
- child = * itr ;
230
- break ;
231
- }
232
- itr ++ ;
273
+ child = curr -> lookup_cb (paramsLcl , curr -> lookup_arg , & buffer_obj );
274
+ if (buffer_obj ) {
275
+ obj_buff = (struct CFG_buffered_obj * ) malloc (sizeof (* obj_buff ));
276
+ memset (obj_buff , 0 , sizeof (* obj_buff ));
277
+ obj_buff -> val = * curr ;
233
278
}
234
279
}
235
280
}
236
281
237
- if (!child )
282
+ if (ctx -> accum || (!child && obj_buff )) {
283
+ char * oterm = & obj [strlen (obj )];
284
+ if (params ) {
285
+ * oterm = ' ' ;
286
+ params [strlen (params )] = '>' ;
287
+ }
288
+ else
289
+ * oterm = '>' ;
290
+
291
+ accumulate_line (ctx );
292
+ * oterm = 0 ;
293
+ if (params )
294
+ params [strlen (params ) - 1 ] = 0 ;
295
+ }
296
+
297
+ if (!child && !ctx -> accum )
238
298
DBG_print (DBG_LEVEL_WARN , "Warning: Description for '%s/%s' not found, "
239
299
"line %d\n" , obj , paramsLcl , ctx -> lineNum );
240
300
241
301
if (child && child -> initCb .cb )
242
302
data = (* child -> initCb .cb )(objLcl , paramsLcl , data ,
243
303
child -> initCb .p1 , child -> initCb .p2 );
244
304
245
- if (child && paramsLcl ) {
305
+ if (paramsLcl ) {
246
306
struct CFG_ParseValue * currLine = NULL ;
247
- for (currLine = parObj -> keys ; currLine && currLine -> name ; currLine ++ ) {
248
- if (!strcasecmp (currLine -> name , subobj_type_buff )) {
249
- if (currLine -> cb .cb )
250
- (* currLine -> cb .cb )(subobj_type_buff , paramsLcl , parData ,
251
- currLine -> cb .p1 , currLine -> cb .p2 );
252
- break ;
307
+ if (parObj ) {
308
+ for (currLine = parObj -> keys ; currLine && currLine -> name ; currLine ++ ) {
309
+ if (!strcasecmp (currLine -> name , subobj_type_buff )) {
310
+ if (currLine -> cb .cb )
311
+ (* currLine -> cb .cb )(subobj_type_buff , paramsLcl , parData ,
312
+ currLine -> cb .p1 , currLine -> cb .p2 );
313
+ break ;
314
+ }
253
315
}
254
316
}
255
317
256
- for (currLine = child -> keys ; currLine && currLine -> name ; currLine ++ ) {
257
- if (!strcasecmp (currLine -> name , "__type" )) {
258
- if (currLine -> cb .cb )
259
- (* currLine -> cb .cb )("__type" , paramsLcl , data ,
260
- currLine -> cb .p1 , currLine -> cb .p2 );
261
- break ;
318
+ if (child ) {
319
+ for (currLine = child -> keys ; currLine && currLine -> name ; currLine ++ ) {
320
+ if (!strcasecmp (currLine -> name , "__type" )) {
321
+ if (currLine -> cb .cb )
322
+ (* currLine -> cb .cb )("__type" , paramsLcl , data ,
323
+ currLine -> cb .p1 , currLine -> cb .p2 );
324
+ break ;
325
+ }
262
326
}
263
327
}
264
328
}
265
329
266
330
while ((more = NextLine (ctx )) ) {
267
331
obj = ctx -> buff ;
332
+
268
333
if (obj [0 ] == '<' && obj [1 ] == '/' ) {
334
+ if (ctx -> accum )
335
+ accumulate_line (ctx );
269
336
obj [strlen (obj ) - 1 ] = 0 ;
270
337
if (strlen (obj ) < 3 || strcasecmp (& obj [2 ], objLcl )) {
271
338
DBG_print (DBG_LEVEL_WARN , "Warning: Malformed end object line in "
@@ -276,11 +343,17 @@ static void *ParseObject(struct CFG_Context *ctx, struct CFG_ParseObj *parObj,
276
343
}
277
344
278
345
if (obj [0 ] == '<' ) {
346
+ buffer_obj = ctx -> allow_buffering ;
347
+ ctx -> allow_buffering = 1 ;
279
348
data = ParseObject (ctx , child , data );
349
+ ctx -> allow_buffering = buffer_obj ;
280
350
continue ;
281
351
}
282
352
283
- data = processKeyValueLine (ctx , child ? child -> keys : NULL , data );
353
+ if (!ctx -> accum )
354
+ data = processKeyValueLine (ctx , child ? child -> keys : NULL , data );
355
+ else
356
+ accumulate_line (ctx );
284
357
}
285
358
if (!more ) {
286
359
DBG_print (DBG_LEVEL_WARN , "Warning: permature end of config file\n" );
@@ -290,11 +363,23 @@ static void *ParseObject(struct CFG_Context *ctx, struct CFG_ParseObj *parObj,
290
363
data = (* child -> finiCb .cb )(objLcl , paramsLcl , data ,
291
364
child -> finiCb .p1 , child -> finiCb .p2 );
292
365
366
+ if (obj_buff ) {
367
+ if (child )
368
+ obj_buff -> parsed_cfg = data ;
369
+ else {
370
+ obj_buff -> len = ctx -> used ;
371
+ obj_buff -> buff = ctx -> accum ;
372
+ ctx -> accum = NULL ;
373
+ ctx -> len = ctx -> used = 0 ;
374
+ }
375
+ data = obj_buff ;
376
+ }
377
+
293
378
free (objLcl );
294
379
if (paramsLcl )
295
380
free (paramsLcl );
296
381
297
- if (child && curr && curr -> cb .cb )
382
+ if (curr && curr -> cb .cb )
298
383
data = (* curr -> cb .cb )(curr -> name , data , parData ,
299
384
curr -> cb .p1 , curr -> cb .p2 );
300
385
else
@@ -303,16 +388,52 @@ static void *ParseObject(struct CFG_Context *ctx, struct CFG_ParseObj *parObj,
303
388
return data ;
304
389
}
305
390
391
+ void * CFG_cfg_for_object_buffer (struct CFG_buffered_obj * obj )
392
+ {
393
+ struct CFG_ParseObj fake_root ;
394
+ struct CFG_ParseValue fake_keys [2 ];
395
+ struct CFG_Context ctx ;
396
+
397
+ if (!obj )
398
+ return NULL ;
399
+
400
+ if (obj -> parsed_cfg )
401
+ return obj -> parsed_cfg ;
402
+
403
+ memset (& ctx , 0 , sizeof (ctx ));
404
+ memset (& fake_root , 0 , sizeof (fake_root ));
405
+ memset (& fake_keys , 0 , sizeof (fake_keys ));
406
+ fake_keys [0 ] = obj -> val ;
407
+ fake_root .keys = fake_keys ;
408
+
409
+ fake_keys [0 ].cb .cb = & CFG_PtrCpyCB ;
410
+ fake_keys [0 ].cb .p1 = NULL ;
411
+ fake_keys [0 ].cb .p2 = NULL ;
412
+
413
+ ctx .replay = obj -> buff ;
414
+
415
+ if (NextLine (& ctx )) {
416
+ ParseObject (& ctx , & fake_root , & obj -> parsed_cfg );
417
+ }
418
+ if (obj -> buff )
419
+ free (obj -> buff );
420
+ obj -> buff = NULL ;
421
+
422
+ return obj -> parsed_cfg ;
423
+ }
424
+
306
425
void * CFG_parseFile (struct CFG_ParseObj * rootObj )
307
426
{
308
427
return CFG_parseFileAtPath (rootObj , gConfigPath );
309
428
}
310
429
311
430
void * CFG_parseFileAtPath (struct CFG_ParseObj * rootObj , const char * path )
312
431
{
313
- struct CFG_Context ctx = { NULL , 0 } ;
432
+ struct CFG_Context ctx ;
314
433
void * data = NULL ;
315
434
435
+ memset (& ctx , 0 , sizeof (ctx ));
436
+ ctx .allow_buffering = 1 ;
316
437
if ( !(ctx .file = fopen (path , "r" )) ){
317
438
ERRNO_WARN ("Failed to fdopen config file '%s'" , path );
318
439
return NULL ;
@@ -513,3 +634,29 @@ void CFG_freeArray(struct CFG_Array *arr, CFG_objFreeCb_t freeCb)
513
634
arr -> len = 0 ;
514
635
}
515
636
}
637
+
638
+ struct CFG_ParseObj * CFG_static_obj (
639
+ const char * params , void * arg , int * buffer_obj )
640
+ {
641
+ * buffer_obj = 0 ;
642
+ return (struct CFG_ParseObj * )arg ;
643
+ }
644
+
645
+ struct CFG_ParseObj * CFG_static_arr_obj (
646
+ const char * params , void * arg , int * buffer_obj )
647
+ {
648
+ * buffer_obj = 0 ;
649
+ struct CFG_ParseObj * result = NULL , * * itr ;
650
+
651
+ itr = (struct CFG_ParseObj * * )arg ;
652
+
653
+ while (* itr ) {
654
+ if (!strcasecmp ((* itr )-> subtype , params )) {
655
+ result = * itr ;
656
+ break ;
657
+ }
658
+ itr ++ ;
659
+ }
660
+
661
+ return result ;
662
+ }
0 commit comments