first public release of samba4 code
[ira/wip.git] / source / torture / genparm.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB test generator - load and parse test config
4    Copyright (C) James Myers 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "gentest.h"
23
24 static struct gentest_context_t *contextP;
25
26 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
27
28 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue);
29 static BOOL do_section(const char *pszSectionName);
30
31 /* prototypes for the special type handlers */
32 static BOOL handle_tests(const char *pszParmValue, char **ptr);
33
34 static BOOL handle_options(const char *pszParmValue, char **ptr);
35 static BOOL handle_fields(const char *pszParmValue, char **ptr);
36
37 static struct enum_list enum_command[] = {
38             {
39                 SMBunlink, "SMBunlink"
40             },
41             {SMBclose, "SMBclosex"},
42             {-1, NULL}
43         };
44 static struct enum_list enum_condition[] = {
45             {
46                 TEST_COND_NEGPROT, "TEST_COND_NEGPROT"
47             },
48             {TEST_COND_SESSION, "TEST_COND_SESSION"},
49             {TEST_COND_TCON, "TEST_COND_TCON"},
50             {TEST_COND_FID, "TEST_COND_FID"},
51             {-1, NULL}
52         };
53 static struct enum_list enum_test_type[] = {
54             {
55                 testTypeConnected, "Connected"
56             },
57             {testTypeFilename, "Filename"},
58             {testTypeFid, "FID"},
59             {-1, NULL}
60         };
61 static struct enum_list enum_options[] = {
62             {TEST_OPTION_FILE_EXISTS, "FILE_EXISTS"},
63             {TEST_OPTION_FILE_NOT_EXIST, "FILE_NOT_EXIST"},
64             {TEST_OPTION_FILE_HIDDEN, "FILE_HIDDEN"},
65             {TEST_OPTION_FILE_SYSTEM, "FILE_SYSTEM"},
66             {TEST_OPTION_FILE_INVISIBLE, "FILE_INVISIBLE"},
67             {TEST_OPTION_FILE_WILDCARD, "FILE_WILDCARD"},
68             {TEST_OPTION_FID_INVALID, "FID_INVALID"},
69             {TEST_OPTION_FID_VALID, "FID_VALID"},
70             {-1, NULL}
71         };
72 static struct enum_list enum_execute[] = {
73             {(int)gen_execute_unlink, "gen_execute_unlink"},
74             {(int)gen_execute_close, "gen_execute_close"},
75             {-1, NULL}
76         };
77 static struct enum_list enum_verify[] = {
78                                             {
79                                                 (int)gen_verify_unlink, "gen_verify_unlink"
80                                             },
81                                             {(int)gen_verify_close, "gen_verify_close"},
82                                             {-1, NULL}
83                                         };
84 static struct enum_list enum_field_type[] = {
85             {
86                 testFieldTypeFilename, "Filename"
87             },
88             {testFieldTypeFileAttr, "FileAttr"},
89             {testFieldTypeFid, "FID"},
90             {testFieldTypeMtime, "Mtime"},
91             {testFieldTypeTrans2, "Trans2"},
92             {-1, NULL}
93         };
94 static struct enum_list enum_function[] = {
95             {
96                 (int)test_field_get_filename, "test_field_get_filename"
97             },
98             {(int)test_field_get_file_attr, "test_field_get_file_attr"},
99             {-1, NULL}
100         };
101
102 /* Note: We do not initialise the defaults union - it is not allowed in ANSI C
103  */
104 #define GEN_FLAG_GLOBAL 0x0001 /* fundamental options */
105 #define GEN_FLAG_TEST   0x0002 /* test options */
106 #define GEN_FLAG_FIELD  0x0004 /* field options */
107
108 static struct {
109     int command;
110     char *name;
111     int debug;
112     int condition;
113     int type;
114     int options;
115     int words;
116     struct field_test_spec* fields;
117     int field_count;
118     void* execute;
119     void* verify;
120 }
121 test_section;
122
123 static struct {
124     char *name;
125     int type;
126     BOOL random;
127     int words;
128     void * function;
129 }
130 field_section;
131
132 static struct parm_struct parm_table[] = {
133             {"Base Options", P_SEP, P_SEPARATOR
134             },
135             /* global section parameters */
136             {"tests", P_LIST, P_GLOBAL, NULL, handle_tests, NULL, GEN_FLAG_GLOBAL},
137
138             /* test section parameters */
139             {"Test section", P_SEP, P_SEPARATOR},
140             {"command", P_ENUM, P_LOCAL, &test_section.command, NULL, enum_command, GEN_FLAG_TEST},
141             {"name", P_STRING, P_LOCAL, &test_section.name, NULL, NULL, GEN_FLAG_TEST},
142             {"debug", P_INTEGER, P_LOCAL, &test_section.debug, NULL, NULL, GEN_FLAG_TEST},
143             {"condition", P_ENUM, P_LOCAL, &test_section.condition, NULL, enum_condition, GEN_FLAG_TEST},
144             {"type", P_ENUM, P_LOCAL, &test_section.type, NULL, enum_test_type, GEN_FLAG_TEST},
145             {"options", P_LIST, P_LOCAL, &test_section.options, handle_options, NULL, GEN_FLAG_TEST},
146             {"word count", P_INTEGER, P_LOCAL, &test_section.words, NULL, NULL, GEN_FLAG_TEST},
147             {"fields", P_LIST, P_LOCAL, NULL, handle_fields, NULL, GEN_FLAG_TEST},
148             {"execute", P_ENUM, P_LOCAL, &test_section.execute, NULL, enum_execute, GEN_FLAG_TEST},
149             {"verify", P_ENUM, P_LOCAL, &test_section.verify, NULL, enum_verify, GEN_FLAG_TEST},
150
151             /* field section parameters */
152             {"Field section", P_SEP, P_SEPARATOR},
153             {"type", P_ENUM, P_LOCAL, &field_section.type, NULL, enum_field_type, GEN_FLAG_FIELD},
154             {"random", P_BOOL, P_LOCAL, &field_section.random, NULL, NULL, GEN_FLAG_FIELD},
155             {"word count", P_INTEGER, P_LOCAL, &field_section.words, NULL, NULL, GEN_FLAG_FIELD},
156             {"function", P_ENUM, P_LOCAL, &field_section.function, NULL, enum_function, GEN_FLAG_FIELD},
157
158             {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
159         };
160
161 static BOOL handle_tests(const char *pszParmValue, char **ptr) {
162     contextP->testNames = str_list_make(pszParmValue, NULL);
163     return True;
164 }
165 static BOOL handle_options(const char *pszParmValue, char **ptr) {
166     /* convert option names (in enum_options) to flags */
167     char **str_array;
168
169     str_array = str_list_make(pszParmValue, NULL);
170
171     if (str_array) {
172         size_t i, j;
173         for ( j = 0; str_array[j] != NULL; j++) {
174             BOOL optionValid = False;
175             for (i = 0; enum_options[i].name; i++) {
176                 if (strequal(str_array[j],
177                              enum_options[i].name)) {
178                     *(int *)ptr |= enum_options[i].value;
179                     optionValid = True;
180                     break;
181                 }
182             }
183             if (!optionValid)
184                 DEBUG(0,("handle_options: '%s' invalid option\n",
185                          str_array[j]));
186         }
187     }
188     DEBUG(9,("handle_options: %s -> %p\n", pszParmValue, *ptr));
189
190     return True;
191 }
192
193 static BOOL handle_fields(const char *pszParmValue, char **ptr) {
194     /* create initialized field structures for each name */
195     char **str_array;
196
197     str_array = str_list_make(pszParmValue, NULL);
198
199     if (str_array) {
200         size_t i;
201         for ( i = 0; str_array[i] != NULL; i++)
202             test_section.field_count++;
203         /* allocate new field array */
204         test_section.fields = talloc(contextP->mem_ctx,
205                                      test_section.field_count * sizeof(struct field_test_spec));
206         for ( i = 0; str_array[i] != NULL; i++)
207             test_section.fields[i].name = str_array[i];
208     }
209     return True;
210 }
211
212 /***************************************************************************
213  Map a parameter's string representation to something we can use. 
214  Returns False if the parameter string is not recognised, else TRUE.
215 ***************************************************************************/
216
217 static int map_parameter(const char *pszParmName, int section) {
218     int iIndex;
219     unsigned validFlags = 0;
220
221     if (*pszParmName == '-')
222         return (-1);
223
224     /* Check for section-specific parameters.
225      * This allows the same parameter name to be used in 
226      * different sections with different meanings.
227      */
228     if (section == GEN_SECTION_GLOBAL)
229         validFlags |= GEN_FLAG_GLOBAL;
230     if (section == GEN_SECTION_TEST)
231         validFlags |= GEN_FLAG_TEST;
232     if (section == GEN_SECTION_FIELD)
233         validFlags |= GEN_FLAG_FIELD;
234     for (iIndex = 0; parm_table[iIndex].label; iIndex++)
235         if ((parm_table[iIndex].flags & validFlags) &&
236                 strwicmp(parm_table[iIndex].label, pszParmName) == 0)
237             return (iIndex);
238
239     /* Warn only if it isn't parametric option */
240     if (strchr(pszParmName, ':') == NULL)
241         DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
242     /* We do return 'fail' for parametric options as well because they are
243        stored in different storage
244      */
245     return (-1);
246 }
247
248 /***************************************************************************
249  Set a boolean variable from the text value stored in the passed string.
250  Returns True in success, False if the passed string does not correctly 
251  represent a boolean.
252 ***************************************************************************/
253
254 static BOOL set_boolean(BOOL *pb, const char *pszParmValue) {
255     BOOL bRetval;
256
257     bRetval = True;
258     if (strwicmp(pszParmValue, "yes") == 0 ||
259             strwicmp(pszParmValue, "true") == 0 ||
260             strwicmp(pszParmValue, "1") == 0) {
261         *pb = True;
262     } else if (strwicmp(pszParmValue, "no") == 0 ||
263                strwicmp(pszParmValue, "False") == 0 ||
264                strwicmp(pszParmValue, "0") == 0) {
265         *pb = False;
266     } else {
267         DEBUG(0,
268               ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
269                pszParmValue));
270         bRetval = False;
271     }
272     return (bRetval);
273 }
274
275 /***************************************************************************
276  Process a parameter
277 ***************************************************************************/
278
279 static BOOL gen_do_parm(struct gentest_context_t *context,
280                  const char *pszParmName, const char *pszParmValue) {
281     int parmnum, i;
282     void *parm_ptr = NULL;      /* where we are going to store the result */
283     void *def_ptr = NULL;
284
285     parmnum = map_parameter(pszParmName, context->iCurrentSectionType);
286
287     if (parmnum < 0) {
288         DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
289         return (True);
290     }
291     DEBUG(19,("gen_do_parm: parm %s is valid\n", pszParmName));
292     def_ptr = parm_table[parmnum].ptr;
293
294     /* we might point at a test, a field or a global */
295     if (context->iCurrentSectionType == GEN_SECTION_GLOBAL) {
296         parm_ptr = def_ptr;
297     } else {
298         if (parm_table[parmnum].class == P_GLOBAL) {
299             DEBUG(0,
300                   ("Global parameter %s found in service section!\n",
301                    pszParmName));
302             return (True);
303         }
304         parm_ptr = def_ptr;
305     }
306
307     /* if it is a special case then go ahead */
308     if (parm_table[parmnum].special) {
309         parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
310         return (True);
311     }
312     DEBUG(19,("gen_do_parm: parm %s type=%d\n", pszParmName,
313               parm_table[parmnum].type));
314
315     /* now switch on the type of variable it is */
316     switch (parm_table[parmnum].type) {
317     case P_BOOL:
318         set_boolean(parm_ptr, pszParmValue);
319         break;
320
321     case P_INTEGER:
322         *(int *)parm_ptr = atoi(pszParmValue);
323         break;
324
325     case P_LIST:
326         *(char ***)parm_ptr = str_list_make(pszParmValue, NULL);
327         break;
328
329     case P_STRING:
330         parm_ptr = talloc_strdup(context->mem_ctx, pszParmValue);
331         break;
332
333     case P_ENUM:
334         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
335             if (strequal
336                     (pszParmValue,
337                      parm_table[parmnum].enum_list[i].name)) {
338                 *(int *)parm_ptr =
339                     parm_table[parmnum].
340                     enum_list[i].value;
341                 break;
342             }
343         }
344         break;
345     case P_SEP:
346         break;
347     default:
348         break;
349     }
350
351     return (True);
352 }
353 /***************************************************************************
354  Process a parameter.
355 ***************************************************************************/
356
357 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue) {
358     BOOL bRetval;
359
360     DEBUG(4, ("doing parameter %s = %s\n", pszParmName, pszParmValue));
361     bRetval = gen_do_parm(contextP, pszParmName, pszParmValue);
362
363     return bRetval;
364 }
365
366 /***************************************************************************
367 Check a test for consistency. Return False if the test is in any way
368 incomplete or faulty, else True.
369 ***************************************************************************/
370
371 static BOOL test_ok(struct gentest_context_t *context,int iTest) {
372     BOOL bRetval = True;
373
374     DEBUG(9,("test_ok: index=%d, tests@%p\n", iTest,
375              context->tests));
376     /* initialize new test section */
377     DEBUG(9,("test_ok: name=%s\n", test_section.name));
378     context->tests[iTest].name = test_section.name;
379     context->tests[iTest].debug = test_section.debug;
380     context->tests[iTest].type = test_section.type;
381     context->tests[iTest].command = test_section.command;
382     context->tests[iTest].initial_conditions = test_section.condition;
383     context->tests[iTest].options = test_section.options;
384     context->tests[iTest].word_count = test_section.words;
385     context->tests[iTest].fields = test_section.fields;
386     context->tests[iTest].field_count = test_section.field_count;
387     context->tests[iTest].execute = test_section.execute;
388     context->tests[iTest].verify = test_section.verify;
389
390     /* validate test entry */
391     DEBUG(9,("test_ok: validate name=%s\n", test_section.name));
392     if (context->tests[iTest].name[0] == '\0') {
393         DEBUG(0, ("The following message indicates an internal error:\n"));
394         DEBUG(0, ("No test name in test entry.\n"));
395         bRetval = False;
396     }
397     if (bRetval) {
398         context->tests[iTest].valid = True;
399         DEBUG(9,("added valid test %s\n",test_section.name));
400     }
401
402     return (bRetval);
403 }
404 /***************************************************************************
405 Check a field for consistency. Return False if the field is in any way
406 incomplete or faulty, else True.
407 ***************************************************************************/
408
409 static BOOL field_ok(struct gentest_context_t *context,int iField) {
410     BOOL bRetval = True;
411
412     /* setup new field entry */
413     DEBUG(9,("field_ok: index=%d, fields@%p\n", iField,
414              context->fields));
415     context->fields[iField].name = field_section.name;
416     context->fields[iField].type = field_section.type;
417     context->fields[iField].random = field_section.random;
418     context->fields[iField].word_count = field_section.words;
419     context->fields[iField].function = field_section.function;
420
421     /* validate field */
422     if (context->fields[iField].name[0] == '\0') {
423         DEBUG(0, ("The following message indicates an internal error:\n"));
424         DEBUG(0, ("No field name in field entry.\n"));
425         bRetval = False;
426     }
427     if (bRetval) {
428         context->fields[iField].valid = True;
429         DEBUG(9,("added valid field %s\n",field_section.name));
430     }
431     
432     return (bRetval);
433 }
434 /***************************************************************************
435 Find a test by name. Otherwise works like get_test.
436 ***************************************************************************/
437
438 static int gettestbyname(struct gentest_context_t *context,
439                          const char *pszTestName) {
440     int iTest;
441
442     for (iTest = context->iNumTests - 1; iTest >= 0; iTest--)
443         if (context->tests[iTest].valid &&
444                 strwicmp(context->tests[iTest].name, pszTestName) == 0) {
445             break;
446         }
447
448     return (iTest);
449 }
450 /***************************************************************************
451 Find a field by name. Otherwise works like get_field.
452 ***************************************************************************/
453
454 static int getfieldbyname(struct gentest_context_t *context,
455                           const char *pszFieldName) {
456     int iField;
457
458     for (iField = context->iNumFields - 1; iField >= 0; iField--)
459         if (context->fields[iField].valid &&
460                 strwicmp(context->fields[iField].name, pszFieldName) == 0) {
461             break;
462         }
463
464     return (iField);
465 }
466 /***************************************************************************
467  Add a new test to the tests array initialising it with the given 
468  test. 
469 ***************************************************************************/
470
471 static int add_a_test(struct gentest_context_t *context,
472                       const char *name) {
473     int i;
474     int num_to_alloc = context->iNumTests + 1;
475
476     DEBUG(3, ("add_a_test: %s at index %d\n", name, num_to_alloc-1));
477     /* it might already exist */
478     if (name) {
479         i = gettestbyname(context, name);
480         if (i >= 0)
481             return (i);
482     }
483
484     /* find an invalid one */
485     for (i = 0; i < context->iNumTests; i++)
486         if (!context->tests[i].valid)
487             break;
488
489     /* if not, then create one */
490     DEBUG(3, ("add_a_test: add %s at index %d\n", name, i));
491     if (i == context->iNumTests) {
492         struct enum_test *tsp;
493
494         tsp = talloc_realloc(context->mem_ctx, context->tests,
495                              sizeof(struct enum_test) *
496                              num_to_alloc);
497
498         if (!tsp) {
499             DEBUG(0,("add_a_test: failed to enlarge TestPtrs!\n"));
500             return (-1);
501         } else {
502             context->tests = tsp;
503         }
504
505         context->iNumTests++;
506         DEBUG(3, ("add_a_test: tests@%p\n", tsp));
507     } //else
508     //free_test(context->tests[i]);
509     /* reinitialize test section fields */
510     test_section.command = 0;
511     test_section.name = talloc_strdup(context->mem_ctx, name);
512     test_section.debug = 0;
513     test_section.condition = 0;
514     test_section.type = 0;
515     test_section.options = 0;
516     test_section.words = 0;
517     test_section.fields = NULL;
518     test_section.field_count = 0;
519     test_section.execute = NULL;
520     test_section.verify = NULL;
521     context->tests[i].valid = False;
522
523     if (name)
524         context->tests[i].name = test_section.name;
525     DEBUG(3, ("add_a_test: added %s at index %d\n", name, i));
526     return (i);
527 }
528 /***************************************************************************
529  Add a new field to the fields array initialising it with the given 
530  field. 
531 ***************************************************************************/
532
533 static int add_a_field(struct gentest_context_t *context,
534                        const char *name) {
535     int i;
536     int num_to_alloc = context->iNumFields + 1;
537
538     DEBUG(3, ("add_a_field: %s at index %d\n", name, num_to_alloc-1));
539     /* it might already exist */
540     if (name) {
541         i = getfieldbyname(context, name);
542         if (i >= 0)
543             return (i);
544     }
545
546     /* find an invalid one */
547     for (i = 0; i < context->iNumFields; i++)
548         if (!context->fields[i].valid)
549             break;
550
551     /* if not, then create one */
552     DEBUG(3, ("add_a_field: add %s at index %d\n", name, i));
553     if (i == context->iNumFields) {
554         field_test_spec *tsp;
555
556         tsp = talloc_realloc(context->mem_ctx, context->fields,
557                              sizeof(field_test_spec) *
558                              num_to_alloc);
559
560         if (!tsp) {
561             DEBUG(0,("add_a_field: failed to enlarge FieldPtrs!\n"));
562             return (-1);
563         } else {
564             context->fields = tsp;
565         }
566
567         context->iNumFields++;
568         DEBUG(3, ("add_a_field: fields@%p\n", tsp));
569     }
570
571     /* reinitialize field section fields */
572     field_section.name = NULL;
573     field_section.type = 0;
574     field_section.random = False;
575     field_section.words = 0;
576     field_section.function = NULL;
577     context->fields[i].valid = False;
578
579     if (name)
580         field_section.name = talloc_strdup(context->mem_ctx, name);
581     DEBUG(3, ("add_a_field: added %s at index %d\n", name, i));
582     return (i);
583 }
584 /***************************************************************************
585  Process a new section (test or field).
586  Returns True on success, False on failure. 
587 ***************************************************************************/
588
589 static BOOL do_section(const char *pszSectionName) {
590     BOOL bRetval;
591     BOOL isglobal = (strwicmp(pszSectionName, GLOBAL_NAME) == 0);
592     char *sectionType, *sectionName, *p;
593
594     bRetval = False;
595     DEBUG(4, ("doing section %s\n", pszSectionName));
596     /* if we've just struck a global section, note the fact. */
597     contextP->bInGlobalSection = isglobal;
598
599     /* check for multiple global sections */
600     if (contextP->bInGlobalSection) {
601         DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
602         contextP->iCurrentSectionType = GEN_SECTION_GLOBAL;
603         return (True);
604     } else if (contextP->iCurrentSectionType == GEN_SECTION_GLOBAL) {
605         /* just finished global section */
606         ;
607     }
608
609     /* parse section name (form <type:name> */
610     sectionType = talloc_strdup(contextP->mem_ctx, pszSectionName);
611     p = strchr_m(sectionType,':');
612     if (p) {
613         *p = 0;
614         sectionName = talloc_strdup(contextP->mem_ctx, p+1);
615     } else {
616         DEBUG(0, ("Invalid section name %s\n", pszSectionName));
617         return False;
618     }
619
620     /* if we have a current test or field, tidy it up before moving on */
621     bRetval = True;
622
623     if (contextP->iTestIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_TEST)
624         bRetval = test_ok(contextP, contextP->iTestIndex);
625     if (contextP->iFieldIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_FIELD)
626         bRetval = field_ok(contextP, contextP->iFieldIndex);
627
628     /* determine type of this section */
629     contextP->iCurrentSectionType = GEN_SECTION_INVALID;
630     if (strequal(sectionType, "test"))
631         contextP->iCurrentSectionType = GEN_SECTION_TEST;
632     if (strequal(sectionType, "field"))
633         contextP->iCurrentSectionType = GEN_SECTION_FIELD;
634     if (contextP->iCurrentSectionType == GEN_SECTION_INVALID) {
635         DEBUG(0, ("Invalid section type %s\n", sectionType));
636         return False;
637     }
638
639     /* if all is still well, move to the next record in the tests array */
640     if (bRetval) {
641         /* We put this here to avoid an odd message order if messages are */
642         /* issued by the post-processing of a previous section. */
643         DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
644
645         if (contextP->iCurrentSectionType == GEN_SECTION_TEST) {
646             if ((contextP->iTestIndex = add_a_test(contextP, sectionName))
647                     < 0) {
648                 DEBUG(0, ("Failed to add a new test\n"));
649                 return (False);
650             }
651         }
652         if (contextP->iCurrentSectionType == GEN_SECTION_FIELD) {
653             if ((contextP->iFieldIndex = add_a_field(contextP, sectionName))
654                     < 0) {
655                 DEBUG(0, ("Failed to add a new field\n"));
656                 return (False);
657             }
658         }
659     }
660
661     return (bRetval);
662 }
663
664 /***************************************************************************
665  Load the test configuration from the test config file. Return True on success, 
666  False on failure.
667 ***************************************************************************/
668
669 BOOL gen_load_config(struct gentest_context_t *contextPTR) {
670     char *n2;
671     BOOL bRetval;
672
673     contextP = contextPTR;
674     contextP->param_opt = NULL;
675
676     n2 = talloc_strdup(contextP->mem_ctx, contextP->config_filename);
677
678     /* We get sections first, so have to start 'behind' to make up */
679     contextP->iTestIndex = -1;
680     bRetval = pm_process(n2, do_section, do_parameter);
681
682     /* finish up the last section */
683     DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
684
685     /* if we have a current test or field, tidy it up before moving on */
686     if (contextP->iTestIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_TEST)
687         bRetval = test_ok(contextP, contextP->iTestIndex);
688     if (contextP->iFieldIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_FIELD)
689         bRetval = field_ok(contextP, contextP->iFieldIndex);
690
691     /* OK, we've parsed the configuration, now we need to match
692      * the field sections to fields required by tests */
693     if (bRetval) {
694         int i,j,k;
695         BOOL fieldValid;
696         for (i=0; i<contextP->iNumTests; i++) {
697             DEBUG(19,("gen_load_config: process test %d %s\n",
698                       i, contextP->tests[i].name));
699             for (j=0; j<contextP->tests[i].field_count; j++) {
700                 fieldValid = False;
701                 DEBUG(19,("gen_load_config: look for field %s\n",
702                           contextP->tests[i].fields[j].name));
703                 for (k=0; k<contextP->iNumFields; k++) {
704                     DEBUG(19,("gen_load_config: compare field %s\n",
705                               contextP->fields[k].name));
706                     if (strequal(contextP->tests[i].fields[j].name,
707                                  contextP->fields[k].name)) {
708                         /* matching field found */
709                         fieldValid = True;
710                         contextP->tests[i].fields[j].type = contextP->fields[k].type;
711                         contextP->tests[i].fields[j].word_count = contextP->fields[k].word_count;
712                         contextP->tests[i].fields[j].function = contextP->fields[k].function;
713                         contextP->tests[i].fields[j].valid = contextP->fields[k].valid;
714                         contextP->tests[i].fields[j].random = contextP->fields[k].random;
715                         contextP->tests[i].fields[j].parms = contextP->fields[k].parms;
716                         break;
717                     }
718                     if (fieldValid)
719                         break;
720                 }
721                 if (!fieldValid) {
722                         contextP->tests[i].fields[j].valid = False;
723                         contextP->tests[i].fields[j].function = test_field_get_null;
724                     DEBUG(0,("missing field section: %s\n",
725                              contextP->tests[i].fields[j].name));
726                 }
727             }
728         }
729     }
730
731     return (bRetval);
732 }