@@ -76,6 +76,7 @@ static void _show_help(void) {
7676 pizza_io_printf ("{cyan} sort Sort tests by specified criteria{reset}\n" );
7777 pizza_io_printf ("{cyan} shuffle Shuffle tests with optional parameters{reset}\n" );
7878 pizza_io_printf ("{cyan} color=<mode> Set color mode (enable, disable, auto){reset}\n" );
79+ pizza_io_printf ("{cyan} config=<file> Specify a configuration file (must be pizza_test.ini){reset}\n" );
7980 pizza_io_printf ("{cyan} theme=<name> Set the theme (fossil, catch, doctest, etc.){reset}\n" );
8081 pizza_io_printf ("{cyan} verbose=<level> Set verbosity level (plain, ci, doge){reset}\n" );
8182 pizza_io_printf ("{cyan} timeout=<seconds> Set the timeout for commands (default: 60 seconds){reset}\n" );
@@ -343,6 +344,26 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
343344 if (i + 1 < argc && pizza_io_cstr_compare (argv [i + 1 ], "--help" ) == 0 ) {
344345 _show_subhelp_color ();
345346 }
347+ } else if (strncmp (argv [i ], "config=" , 7 ) == 0 ) {
348+ const char * config_file = argv [i ] + 7 ;
349+ const char * basename = strrchr (config_file , '/' );
350+ if (!basename ) {
351+ basename = config_file ; // No '/' found, use the entire filename
352+ } else {
353+ basename ++ ; // Skip the '/'
354+ }
355+
356+ if (pizza_io_cstr_compare (basename , "pizza_test.ini" ) == 0 ) {
357+ pallet .config_file = config_file ;
358+ } else {
359+ pizza_io_printf ("{red}Error: Invalid configuration file name. Must be 'pizza_test.ini'.{reset}\n" );
360+ exit (EXIT_FAILURE );
361+ }
362+ } else if (pizza_io_cstr_compare (argv [i ], "config" ) == 0 ) {
363+ if (i + 1 < argc && pizza_io_cstr_compare (argv [i + 1 ], "--help" ) == 0 ) {
364+ _show_help ();
365+ }
366+
346367 } else if (strncmp (argv [i ], "theme=" , 6 ) == 0 ) {
347368 const char * theme_str = argv [i ] + 6 ;
348369 if (pizza_io_cstr_compare (theme_str , "fossil" ) == 0 ) {
@@ -404,6 +425,169 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
404425 return pallet ;
405426}
406427
428+ // *****************************************************************************
429+ // INI Parser
430+ // *****************************************************************************
431+
432+ int fossil_pizza_ini_parse (const char * filename , fossil_pizza_pallet_t * pallet ) {
433+ pizza_io_printf ("{yellow}Warning: INI parser is experimental and in development.{reset}\n" );
434+ const char * basename = strrchr (filename , '/' );
435+ if (!basename ) {
436+ basename = filename ; // No '/' found, use the entire filename
437+ } else {
438+ basename ++ ; // Skip the '/'
439+ }
440+
441+ if (pizza_io_cstr_compare (basename , "pizza_test.ini" ) != 0 ) {
442+ fprintf (stderr , "Error: INI file must be named 'pizza_test.ini'.\n" );
443+ return -1 ;
444+ }
445+
446+ FILE * file = fopen (filename , "r" );
447+ if (!file ) {
448+ fprintf (stderr , "Error: Unable to open INI file: %s\n" , basename );
449+ return -1 ;
450+ }
451+
452+ char line [256 ];
453+ char section [64 ] = "" ;
454+ while (fgets (line , sizeof (line ), file )) {
455+ // Trim whitespace
456+ char * start = line ;
457+ while (isspace ((unsigned char )* start )) start ++ ;
458+ char * end = start + strlen (start ) - 1 ;
459+ while (end > start && isspace ((unsigned char )* end )) * end -- = '\0' ;
460+
461+ // Skip comments and empty lines
462+ if (* start == ';' || * start == '#' || * start == '\0' ) continue ;
463+
464+ // Handle section headers
465+ if (* start == '[' ) {
466+ char * close = strchr (start , ']' );
467+ if (close ) {
468+ * close = '\0' ;
469+ strncpy (section , start + 1 , sizeof (section ) - 1 );
470+ section [sizeof (section ) - 1 ] = '\0' ;
471+ }
472+ continue ;
473+ }
474+
475+ // Handle key-value pairs
476+ char * equals = strchr (start , '=' );
477+ if (equals ) {
478+ * equals = '\0' ;
479+ char * key = start ;
480+ char * value = equals + 1 ;
481+
482+ // Trim whitespace around key and value
483+ while (isspace ((unsigned char )* key )) key ++ ;
484+ end = key + strlen (key ) - 1 ;
485+ while (end > key && isspace ((unsigned char )* end )) * end -- = '\0' ;
486+
487+ while (isspace ((unsigned char )* value )) value ++ ;
488+ end = value + strlen (value ) - 1 ;
489+ while (end > value && isspace ((unsigned char )* end )) * end -- = '\0' ;
490+
491+ // Handle inline comments
492+ char * comment = strchr (value , ';' );
493+ if (!comment ) comment = strchr (value , '#' );
494+ if (comment ) * comment = '\0' ;
495+
496+ // Trim whitespace again after removing comments
497+ end = value + strlen (value ) - 1 ;
498+ while (end > value && isspace ((unsigned char )* end )) * end -- = '\0' ;
499+
500+ // Populate the pallet structure based on the section and key
501+ if (pizza_io_cstr_compare (section , "general" ) == 0 ) {
502+ if (pizza_io_cstr_compare (key , "theme" ) == 0 ) {
503+ if (pizza_io_cstr_compare (value , "fossil" ) == 0 ) {
504+ pallet -> theme = PIZZA_THEME_FOSSIL ;
505+ } else if (pizza_io_cstr_compare (value , "catch" ) == 0 ) {
506+ pallet -> theme = PIZZA_THEME_CATCH ;
507+ } else if (pizza_io_cstr_compare (value , "doctest" ) == 0 ) {
508+ pallet -> theme = PIZZA_THEME_DOCTEST ;
509+ } else if (pizza_io_cstr_compare (value , "cpputest" ) == 0 ) {
510+ pallet -> theme = PIZZA_THEME_CPPUTEST ;
511+ } else if (pizza_io_cstr_compare (value , "tap" ) == 0 ) {
512+ pallet -> theme = PIZZA_THEME_TAP ;
513+ } else if (pizza_io_cstr_compare (value , "gtest" ) == 0 ) {
514+ pallet -> theme = PIZZA_THEME_GOOGLETEST ;
515+ } else if (pizza_io_cstr_compare (value , "unity" ) == 0 ) {
516+ pallet -> theme = PIZZA_THEME_UNITY ;
517+ }
518+ } else if (pizza_io_cstr_compare (key , "verbose" ) == 0 ) {
519+ if (pizza_io_cstr_compare (value , "plain" ) == 0 ) {
520+ pallet -> verbose = PIZZA_VERBOSE_PLAIN ;
521+ } else if (pizza_io_cstr_compare (value , "ci" ) == 0 ) {
522+ pallet -> verbose = PIZZA_VERBOSE_CI ;
523+ } else if (pizza_io_cstr_compare (value , "doge" ) == 0 ) {
524+ pallet -> verbose = PIZZA_VERBOSE_DOGE ;
525+ }
526+ }
527+ } else if (pizza_io_cstr_compare (section , "test" ) == 0 ) {
528+ if (pizza_io_cstr_compare (key , "run.fail_fast" ) == 0 ) {
529+ pallet -> run .fail_fast = atoi (value );
530+ } else if (pizza_io_cstr_compare (key , "run.only" ) == 0 ) {
531+ pallet -> run .only = pizza_io_cstr_dup (value );
532+ } else if (pizza_io_cstr_compare (key , "run.repeat" ) == 0 ) {
533+ pallet -> run .repeat = atoi (value );
534+ } else if (pizza_io_cstr_compare (key , "filter.test_name" ) == 0 ) {
535+ pallet -> filter .test_name = pizza_io_cstr_dup (value );
536+ } else if (pizza_io_cstr_compare (key , "filter.suite_name" ) == 0 ) {
537+ pallet -> filter .suite_name = pizza_io_cstr_dup (value );
538+ } else if (pizza_io_cstr_compare (key , "filter.tag" ) == 0 ) {
539+ int is_valid_tag = 0 ;
540+ for (int i = 0 ; VALID_TAGS [i ] != null ; i ++ ) {
541+ if (pizza_io_cstr_compare (value , VALID_TAGS [i ]) == 0 ) {
542+ is_valid_tag = 1 ;
543+ break ;
544+ }
545+ }
546+ if (is_valid_tag ) {
547+ pallet -> filter .tag = pizza_io_cstr_dup (value );
548+ } else {
549+ fprintf (stderr , "Error: Invalid tag '%s'.\n" , value );
550+ fclose (file );
551+ return -1 ;
552+ }
553+ } else if (pizza_io_cstr_compare (key , "sort.by" ) == 0 ) {
554+ int is_valid_criteria = 0 ;
555+ for (int i = 0 ; VALID_CRITERIA [i ] != null ; i ++ ) {
556+ if (pizza_io_cstr_compare (value , VALID_CRITERIA [i ]) == 0 ) {
557+ is_valid_criteria = 1 ;
558+ break ;
559+ }
560+ }
561+ if (is_valid_criteria ) {
562+ pallet -> sort .by = pizza_io_cstr_dup (value );
563+ } else {
564+ fprintf (stderr , "Error: Invalid sort criteria '%s'.\n" , value );
565+ fclose (file );
566+ return -1 ;
567+ }
568+ } else if (pizza_io_cstr_compare (key , "sort.order" ) == 0 ) {
569+ pallet -> sort .order = pizza_io_cstr_dup (value );
570+ } else if (pizza_io_cstr_compare (key , "shuffle.seed" ) == 0 ) {
571+ pallet -> shuffle .seed = pizza_io_cstr_dup (value );
572+ } else if (pizza_io_cstr_compare (key , "shuffle.count" ) == 0 ) {
573+ pallet -> shuffle .count = atoi (value );
574+ } else if (pizza_io_cstr_compare (key , "shuffle.by" ) == 0 ) {
575+ pallet -> shuffle .by = pizza_io_cstr_dup (value );
576+ }
577+ } else if (pizza_io_cstr_compare (section , "mock" ) == 0 ) {
578+ // Add mock-related parsing logic here
579+ } else if (pizza_io_cstr_compare (section , "mark" ) == 0 ) {
580+ // Add mark-related parsing logic here
581+ } else if (pizza_io_cstr_compare (section , "sanity" ) == 0 ) {
582+ // Add sanity-related parsing logic here
583+ }
584+ }
585+ }
586+
587+ fclose (file );
588+ return 0 ;
589+ }
590+
407591// *****************************************************************************
408592// Host information
409593// *****************************************************************************
0 commit comments