60672112f741d27fc2c7a7824122bd7bbbf7b748
[robodoc.git] / Source / optioncheck.c
1 /*
2 Copyright (C) 1994-2007  Frans Slothouber, Jacco van Weert, Petteri Kettunen,
3 Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
4 Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
5
6 This file is part of ROBODoc
7
8 ROBODoc is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23 /* $Id: optioncheck.c,v 1.19 2007/07/10 19:13:52 gumpu Exp $*/
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "robodoc.h"
30 #include "optioncheck.h"
31 #include "roboconfig.h"
32 #include "util.h"
33
34
35 char                short_use[] =
36     "Usage:\n"
37     "   robodoc --src <directory> --doc <directory> --multidoc   [type] [options]\n"
38     "   robodoc --src <directory> --doc <file>      --singledoc  [type] [options]\n"
39     "   robodoc --src <file>      --doc <file>      --singlefile [type] [options]\n"
40     "\n" "Use robodoc --help for more information\n";
41
42
43 void Print_Short_Use(
44     void )
45 {
46     fprintf( stdout, "%s\n", short_use );
47 }
48
49 /****t* UserInterface/Option_Test_Kind
50  * FUNCTION
51  *   Enumeration for the kind of tests that are carried out on the 
52  *   options that the user specifies.
53  * SOURCE
54  */
55 typedef enum
56 {
57     TEST_INVALID = 0,
58     TEST_MUTUAL_EXCLUDE = 1,
59     TEST_SHOULD_EXISTS,         /* TODO Create this kind of test */
60     TEST_NO_EFFECT,             /* TODO Create this kind of test */
61     TEST_COUNT,                 /* TODO Create this kind of test */
62     TEST_SPELLING               /* TODO Create this kind of test */
63 } Option_Test_Kind;
64
65 /*****/
66
67 typedef enum
68 {
69     OPTION_FATAL = 1,
70     OPTION_WARNING
71 } Option_Error_Severity;
72
73 /****s* UserInterface/RB_Option_Name
74  * FUNCTION
75  *   Element in a list of option names.
76  *   Used in a RB_Option_Test to specify to what
77  *   options a test applies.
78  * SOURCE
79  */
80
81 struct RB_Option_Name
82 {
83     /* linked list administration */
84     struct RB_Option_Name *next;
85     /* name of the option */
86     char               *name;
87     /* use by the Count test */
88     int                 count;
89 };
90
91 /*****/
92
93 /****s* UserInterface/RB_Option_Test
94  * FUNCTION
95  *   A test specification for options. This
96  *   stores information about the kind of test and
97  *   the options it applies to, and the message that
98  *   is given to the user.
99  * SOURCE
100  */
101
102 struct RB_Option_Test
103 {
104     /* tests are stored in a linked list */
105     struct RB_Option_Test *next;
106     /* the group of options the test applies to. */
107     struct RB_Option_Name *option_group;
108     /* the kind of test */
109     Option_Test_Kind    kind;
110     /* More information for the user */
111     char               *more_information;       /* TODO Fill and use */
112
113     Option_Error_Severity severity;
114 };
115
116 /******/
117
118 /****v* UserInterface/ok_options
119  * FUNCTION
120  *   An list of all allowed command-line options.  If you add any
121  *   options add its name here too.  This list is used to verify
122  *   the options specified by the user.
123  * SOURCE
124  */
125
126 static char        *ok_options[] = {
127     "--rc",
128     "--src",
129     "--doc",
130     "--html",
131     "--latex",
132     "--ascii",
133     "--rtf",
134     "--troff",
135     "--dbxml",
136     "--doctype_name",
137     "--doctype_location",
138     "--singledoc",
139     "--singlefile",
140     "--multidoc",
141     "--one_file_per_header",
142     "--first_section_level",
143     "--sections",
144     "--internal",
145     "--internalonly",
146     "--ignore_case_when_linking",
147     "--toc",
148     "--index",
149     "--nosource",
150     "--tabsize",
151     "--tell",
152     "--debug",
153     "--test",                   /* Special output mode for testing */
154     "--nodesc",
155     "--nopre",
156     "--nogeneratedwith",
157     "--no_subdirectories",
158     "--cmode",
159     "--charset",
160     "--ext",
161     "--help",
162     "--css",
163     "--version",
164     "-c",
165     "--lock",
166     "--nosort",
167     "--headless",
168     "--footless",
169     "--sectionnameonly",
170     "--compress",
171     "--mansection",
172     "--verbal",                 /*FS TODO */
173     "--ms_errors",              /* TODO is this documented?? */
174     "--documenttitle",
175     "--altlatex",
176     "--latexparts",
177     "--tabstops",
178     "--syntaxcolors",
179     "--syntaxcolors_enable",
180     "--dotname",
181     "--masterindex",
182     "--sourceindex",
183     "--header_breaks",
184     ( char * ) NULL
185 };
186
187 /*****/
188
189
190 /****v* UserInterface/option_tests
191  * FUNCTION
192  *   A linked lists of tests that check the options specified
193  *   by the user.
194  * SOURCE
195  */
196 static struct RB_Option_Test *option_tests = NULL;
197
198 /*****/
199
200
201 /****f* UserInterface/Add_Option_Test
202  * FUNCTION
203  *   Add a test to the linked list of options tests.
204  * SYNOPSIS
205  */
206 static void Add_Option_Test(
207     struct RB_Option_Test *option_test )
208 /*
209  * INPUTS
210  *   option_test -- the test to be added.
211  * SOURCE
212  */
213 {
214     option_test->next = option_tests;
215     option_tests = option_test;
216 }
217
218 /*****/
219
220 /****f* UserInterface/Add_Option_Name
221  * FUNCTION
222  *   Add the name of an option to the group of option names an option
223  *   test applies to.
224  * SYNOPSIS
225  */
226 static void Add_Option_Name(
227     struct RB_Option_Test *option_test,
228     char *name )
229 /* 
230  * INPUTS
231  *   option_test -- the option test
232  *   name -- the name of the option
233  * SOURCE
234  */
235 {
236     struct RB_Option_Name *new_option_name =
237         malloc( sizeof( struct RB_Option_Name ) );
238     new_option_name->name = RB_StrDup( name );
239     new_option_name->next = option_test->option_group;
240     new_option_name->count = 0;
241     option_test->option_group = new_option_name;
242 }
243
244 /****/
245
246 /****f* UserInterface/Create_New_Option_Test
247  * FUNCTION
248  *   Allocate and initialize a new option test.
249  * SYNOPSIS
250  */
251 static struct RB_Option_Test *Create_New_Option_Test(
252     Option_Test_Kind kind,
253     Option_Error_Severity severity )
254 /*
255  * INPUTS
256  *   kind -- the kind of test that has to be created.
257  * SOURCE
258  */
259 {
260     struct RB_Option_Test *new_option_test =
261         malloc( sizeof( struct RB_Option_Test ) );
262     new_option_test->next = NULL;
263     new_option_test->option_group = NULL;
264     new_option_test->kind = kind;
265     new_option_test->severity = severity;
266     return new_option_test;
267 }
268
269 /*****/
270
271 /****f* UserInterface/Create_Test_Data
272  * FUNCTION
273  *   Create a linked list of tests.
274  * SYNOPSIS
275  */
276 static void Create_Test_Data(
277     void )
278 /*
279  * TODO
280  *   Generate this code automatically from a set
281  *   of high-level specifications.
282  * SOURCE
283  */
284 {
285     struct RB_Option_Test *cur_option_test = NULL;
286     int                 i;
287
288     cur_option_test =
289         Create_New_Option_Test( TEST_MUTUAL_EXCLUDE, OPTION_FATAL );
290     Add_Option_Name( cur_option_test, "--singledoc" );
291     Add_Option_Name( cur_option_test, "--multidoc" );
292     Add_Option_Name( cur_option_test, "--singlefile" );
293     Add_Option_Test( cur_option_test );
294
295     cur_option_test =
296         Create_New_Option_Test( TEST_MUTUAL_EXCLUDE, OPTION_FATAL );
297     Add_Option_Name( cur_option_test, "--html" );
298     Add_Option_Name( cur_option_test, "--rtf" );
299     Add_Option_Name( cur_option_test, "--ascii" );
300     Add_Option_Name( cur_option_test, "--dbxml" );
301     Add_Option_Name( cur_option_test, "--troff" );
302     Add_Option_Name( cur_option_test, "--latex" );
303     Add_Option_Name( cur_option_test, "--test" );
304     Add_Option_Test( cur_option_test );
305
306     /* Order is important here */
307     cur_option_test = Create_New_Option_Test( TEST_COUNT, OPTION_FATAL );
308     for ( i = 0; ok_options[i]; i++ )
309     {
310         Add_Option_Name( cur_option_test, ok_options[i] );
311     }
312     Add_Option_Test( cur_option_test );
313
314 }
315
316 /******/
317
318 static int Do_Count_Test(
319     struct RB_Option_Test *cur_option_test )
320 {
321     unsigned int        parameter_nr = 0;
322     int                 result = EXIT_SUCCESS;
323     struct RB_Option_Name *option_name;
324
325     assert( cur_option_test );
326
327     for ( parameter_nr = 0;
328           parameter_nr < configuration.options.number; parameter_nr++ )
329     {
330         for ( option_name = cur_option_test->option_group;
331               option_name; option_name = option_name->next )
332         {
333             if ( RB_Str_Case_Cmp
334                  ( configuration.options.names[parameter_nr],
335                    option_name->name ) == 0 )
336             {
337                 ( option_name->count )++;
338             }
339         }
340     }
341
342     for ( option_name = cur_option_test->option_group;
343           option_name; option_name = option_name->next )
344     {
345         if ( option_name->count > 1 )
346         {
347             fprintf( stderr, "The option %s is used more than once.\n",
348                      option_name->name );
349             result = EXIT_FAILURE;
350         }
351     }
352
353     return result;
354 }
355
356
357 /****f* UserInterface/Do_Mutual_Exlcude_Test
358  * FUNCTION
359  *   Check all the options to see if combinations of options
360  *   are used that mutually exclude each other, such as
361  *   --singledoc and --multidoc.
362  * SYNOPSIS
363  */
364 static int Do_Mutual_Exlcude_Test(
365     struct RB_Option_Test *cur_option_test )
366  /*
367   * INPUTS
368   *   * cur_option_test -- the test to be carried out.
369   * SOURCE
370   */
371 {
372     int                 n = 0;
373     unsigned int        parameter_nr = 0;
374     int                 result = EXIT_SUCCESS;
375
376     assert( cur_option_test );
377
378     for ( parameter_nr = 0;
379           parameter_nr < configuration.options.number; parameter_nr++ )
380     {
381         struct RB_Option_Name *option_name = cur_option_test->option_group;
382
383         for ( ; option_name; option_name = option_name->next )
384         {
385             if ( RB_Str_Case_Cmp
386                  ( configuration.options.names[parameter_nr],
387                    option_name->name ) == 0 )
388             {
389                 ++n;
390             }
391         }
392     }
393
394     /* Only one of the options in the group may be used */
395     if ( n > 1 )
396     {
397         fprintf( stderr, "The options: " );
398         for ( parameter_nr = 0;
399               parameter_nr < configuration.options.number; parameter_nr++ )
400         {
401             struct RB_Option_Name *option_name =
402                 cur_option_test->option_group;
403             for ( ; option_name; option_name = option_name->next )
404             {
405                 if ( RB_Str_Case_Cmp
406                      ( configuration.options.names[parameter_nr],
407                        option_name->name ) == 0 )
408                 {
409
410                     fprintf( stderr, "%s ",
411                              configuration.options.names[parameter_nr] );
412                 }
413             }
414         }
415         fprintf( stderr, "cannot be used together.\n" );
416         result = EXIT_FAILURE;
417     }
418
419     return result;
420 }
421
422 /*****/
423
424
425 /****f* UserInterface/Do_Option_Tests
426  * FUNCTION
427  *   Run a series of tests on the options that the user
428  *   specified.  These tests are specified in 
429  *   option_tests.
430  * SYNOPSIS
431  */
432 static int Do_Option_Tests(
433     void )
434 /*
435  * RESULT
436  *   * EXIT_FAILURE -- one of the tests failed.
437  *   * EXIT_SUCCESS -- all test completed successfully
438  * SOURCE
439  */
440 {
441     struct RB_Option_Test *cur_option_test = NULL;
442     int                 result = EXIT_SUCCESS;
443     int                 final_result = EXIT_SUCCESS;
444
445     RB_Say( "Checking the option semantics.\n", SAY_INFO );
446     Create_Test_Data(  );
447     cur_option_test = option_tests;
448
449     assert( cur_option_test );
450
451     for ( ; cur_option_test; cur_option_test = cur_option_test->next )
452     {
453         switch ( cur_option_test->kind )
454         {
455         case TEST_MUTUAL_EXCLUDE:
456             RB_Say( "Checking for mutual excluding options.\n", SAY_INFO );
457             result = Do_Mutual_Exlcude_Test( cur_option_test );
458             break;
459         case TEST_COUNT:       /* TODO Create */
460             RB_Say( "Checking for duplicate options.\n", SAY_INFO );
461             result = Do_Count_Test( cur_option_test );
462             break;
463         case TEST_SHOULD_EXISTS:       /* TODO Create */
464         case TEST_NO_EFFECT:   /* TODO Create */
465         case TEST_SPELLING:    /* TODO Create */
466         default:
467             assert( 0 );
468         }
469         /* If one of the tests fails the final result is a fail. */
470         if ( result == EXIT_FAILURE )
471         {
472             final_result = EXIT_FAILURE;
473             if ( cur_option_test->severity == OPTION_FATAL )
474             {
475                 break;
476             }
477         }
478     }
479
480     return final_result;
481 }
482
483 /****/
484
485 /****f* UserInterface/Check_Option_Spelling
486  * FUNCTION
487  *   Check for misspelled options specified by the user.
488  * SYNOPSIS
489  */
490
491 int Check_Option_Spelling(
492     void )
493 /*
494  * RESULT
495  *   * EXIT_SUCCESS -- all options are correctly spelled.
496  *   * EXIT_FAILURE -- one of more options are misspelled.
497  * SOURCE
498  */
499 {
500     char                ok;
501     char               *arg;
502     char              **opts;
503     unsigned int        parameter_nr;
504
505     RB_Say( "Checking the option syntax.\n", SAY_INFO );
506     for ( parameter_nr = 0;
507           parameter_nr < configuration.options.number; parameter_nr++ )
508     {
509         arg = configuration.options.names[parameter_nr];
510         if ( ( arg[0] == '-' ) && ( arg[1] == '-' ) )
511         {
512             /* this arg is an option */
513             ok = 0;
514             opts = ok_options;
515             while ( *opts )
516             {
517                 if ( strcmp( arg, *opts ) == 0 )
518                 {
519                     ok = 1;
520                     break;
521                 }
522                 opts++;
523             }
524             if ( !ok )
525             {
526                 fprintf( stderr, "Invalid argument: %s\n", arg );
527                 fprintf( stderr,
528                          "This might also be in your robodoc.rc file\n" );
529                 return EXIT_FAILURE;
530             }
531         }
532     }
533     return EXIT_SUCCESS;
534 }
535
536 /******/
537
538
539 static int Check_Item_Names(
540     struct Parameters *arg_parameters,
541     char *block_name )
542 {
543     unsigned int        parameter_nr_1;
544     unsigned int        parameter_nr_2;
545     int                 name_is_ok = TRUE;
546
547     RB_Say( "Checking the item names for %s block.\n", SAY_INFO, block_name );
548     for ( parameter_nr_1 = 0;
549           parameter_nr_1 < arg_parameters->number; parameter_nr_1++ )
550     {
551         name_is_ok = FALSE;
552         for ( parameter_nr_2 = 0;
553               parameter_nr_2 < configuration.items.number; parameter_nr_2++ )
554         {
555             if ( strcmp( configuration.items.names[parameter_nr_2],
556                          arg_parameters->names[parameter_nr_1] ) == 0 )
557             {
558                 name_is_ok = TRUE;
559             }
560         }
561         if ( !name_is_ok )
562         {
563             RB_Say( "!! block.\n", SAY_INFO );
564             fprintf( stderr, "Unknown item %s found in the\n",
565                      arg_parameters->names[parameter_nr_1] );
566             fprintf( stderr, "   %s block\nof your configuration file.\n",
567                      block_name );
568             break;
569         }
570     }
571
572     RB_Say( "Is %d block.\n", SAY_INFO, name_is_ok );
573     return name_is_ok;
574 }
575
576 /****f* UserInterface/Check_Item_Options
577  * FUNCTION
578  *   Check the validity of the item options.  Users can specify their
579  *   own items, item order, and items that ar to be ignored.  This all
580  *   should be consistent.
581  * SYNOPSIS
582  */
583 static int Check_Item_Options(
584     void )
585 /*
586  * RESULT
587  *   * EXIT_SUCCESS -- all options are correct.
588  *   * EXIT_FAILURE -- one of more options incorrect.
589  * SOURCE
590  */
591 {
592     int                 item_OK = TRUE;
593     int                 result = TRUE;
594
595     RB_Say( "Checking the item names.\n", SAY_INFO );
596     result = item_OK
597         && Check_Item_Names( &( configuration.ignore_items ),
598                              "ignore items:" );
599     item_OK = item_OK && result;
600     result =
601         Check_Item_Names( &( configuration.source_items ), "source items:" );
602     item_OK = item_OK && result;
603     result =
604         Check_Item_Names( &( configuration.preformatted_items ),
605                           "preformatted items:" );
606     item_OK = item_OK && result;
607     result =
608         Check_Item_Names( &( configuration.format_items ), "format items:" );
609     item_OK = item_OK && result;
610     result = Check_Item_Names( &( configuration.item_order ), "item order:" );
611     item_OK = item_OK && result;
612     if ( item_OK )
613     {
614         return EXIT_SUCCESS;
615     }
616     else
617     {
618         return EXIT_FAILURE;
619     }
620 }
621
622 /*****/
623
624
625 /****f* UserInterface/Check_Options
626  * FUNCTION
627  *   Check the validity of all the options in configuration.options[].
628  *   This runs a number of checks.
629  * SYNOPSIS
630  */
631
632 int Check_Options(
633     void )
634 /*
635  * RESULT
636  *   * EXIT_SUCCESS -- all options are correct.
637  *   * EXIT_FAILURE -- one of more options incorrect.
638  * SOURCE
639  */
640 {
641     int                 status;
642
643     RB_Say( "Checking the options.\n", SAY_INFO );
644     status = Check_Option_Spelling(  );
645     if ( status == EXIT_SUCCESS )
646     {
647         status = Do_Option_Tests(  );
648         if ( status == EXIT_SUCCESS )
649         {
650             status = Check_Item_Options(  );
651         }
652         else
653         {
654             Print_Short_Use(  );
655         }
656     }
657     else
658     {
659         Print_Short_Use(  );
660     }
661
662     /* TODO free option_tests */
663
664     return status;
665 }
666
667 /*****/