1 /*
2  *      cook - file construction tool
3  *      Copyright (C) 1994-1999, 2001, 2003, 2004, 2006, 2007 Peter Miller;
4  *      All rights reserved.
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 3 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, see
18  *      <http://www.gnu.org/licenses/>.
19  *
20  *
21  * If you are going to add a new recipe flag (set by the "set" statement,
22  * or the "set" clause of a recipe) you need to change all of the
23  * following places:
24  *
25  * cook/option.h
26  *     to define the OPTION_ value
27  * cook/option.c
28  *     option_tidyup()
29  *         if the option defaults to true
30  *     option_set_errors()
31  *         if the option should be turned off once cookbook errors
32  *         are encountered.
33  *     option_number_name()
34  *         for the name of the option
35  * cook/flag.h
36  *     to define the RF_ values (RF stands for Recipe Flag)
37  * cook/flag.c
38  *     to define the RF_ names
39  * lib/en/user-guide/langu.flags.so
40  *     to document the recipe flag
41  *
42  * If you choose to make it a command line option,
43  * you must also update these files:
44  *
45  * cook/main.c
46  *     to define the new command line option and process it
47  *     (only if it should also be a command line option)
48  * cook/builtin/options.c
49  *     to access the option from within the cookbook (typically used
50  *     for recursive cook invokations)
51  * lib/en/man1/cook.1
52  *     to document it, if you added a new command line option
53  */
54 
55 #include <common/ac/stddef.h>
56 #include <common/ac/string.h>
57 #include <common/ac/stdio.h>
58 #include <common/ac/stdlib.h>
59 #include <common/ac/signal.h>
60 
61 #include <common/arglex.h>
62 #include <common/error_intl.h>
63 #include <common/fflush_slow.h>
64 #include <common/help.h>
65 #include <common/progname.h>
66 #include <common/quit.h>
67 #include <common/star.h>
68 #include <common/trace.h>
69 #include <common/version.h>
70 #include <cook/builtin.h>
71 #include <cook/cook.h>
72 #include <cook/fingerprint.h>
73 #include <cook/id.h>
74 #include <cook/id/variable.h>
75 #include <cook/lex.h>
76 #include <cook/listing.h>
77 #include <cook/opcode/context.h>
78 #include <cook/option.h>
79 #include <cook/parse.h>
80 
81 
82 enum
83 {
84     arglex_token_action,
85     arglex_token_action_not,
86     arglex_token_book,
87     arglex_token_book_not,
88     arglex_token_cascade,
89     arglex_token_cascade_not,
90     arglex_token_disassemble,
91     arglex_token_disassemble_not,
92     arglex_token_errok,
93     arglex_token_errok_not,
94     arglex_token_fingerprint,
95     arglex_token_fingerprint_not,
96     arglex_token_fingerprint_update,
97     arglex_token_force,
98     arglex_token_force_not,
99     arglex_token_include,
100     arglex_token_include_cooked,
101     arglex_token_include_cooked_not,
102     arglex_token_include_cooked_warning,
103     arglex_token_include_cooked_warning_not,
104     arglex_token_log,
105     arglex_token_log_not,
106     arglex_token_metering,
107     arglex_token_metering_not,
108     arglex_token_pairs,
109     arglex_token_parallel,
110     arglex_token_parallel_not,
111     arglex_token_pedantic,
112     arglex_token_pedantic_not,
113     arglex_token_persevere,
114     arglex_token_persevere_not,
115     arglex_token_precious,
116     arglex_token_precious_not,
117     arglex_token_reason,
118     arglex_token_reason_not,
119     arglex_token_script,
120     arglex_token_shallow,
121     arglex_token_shallow_not,
122     arglex_token_silent,
123     arglex_token_silent_not,
124     arglex_token_star,
125     arglex_token_star_not,
126     arglex_token_strip_dot,
127     arglex_token_strip_dot_not,
128     arglex_token_symlink_ingredients,
129     arglex_token_symlink_ingredients_not,
130     arglex_token_tell_position,
131     arglex_token_tell_position_not,
132     arglex_token_touch,
133     arglex_token_touch_not,
134     arglex_token_tty,
135     arglex_token_tty_not,
136     arglex_token_update,
137     arglex_token_update_not,
138     arglex_token_web
139         /*
140          * When you add an option to this list, you must
141          * also add it to the list in cook/builtin/options.c
142          */
143 };
144 
145 static arglex_table_ty argtab[] =
146 {
147     { "-Action", (arglex_token_ty) arglex_token_action },
148     { "-No_Action", (arglex_token_ty) arglex_token_action_not },
149     { "-Book", (arglex_token_ty) arglex_token_book },
150     { "-No_Book", (arglex_token_ty) arglex_token_book_not },
151     { "-CAScade", (arglex_token_ty) arglex_token_cascade },
152     { "-No_CAScade", (arglex_token_ty) arglex_token_cascade_not },
153     { "-Continue", (arglex_token_ty) arglex_token_persevere },
154     { "-No_Continue", (arglex_token_ty) arglex_token_persevere_not },
155     { "-DISassemble", (arglex_token_ty) arglex_token_disassemble },
156     { "-No_DISassemble", (arglex_token_ty) arglex_token_disassemble_not },
157     { "-Errok", (arglex_token_ty) arglex_token_errok },
158     { "-No_Errok", (arglex_token_ty) arglex_token_errok_not },
159     { "-FingerPrint", (arglex_token_ty) arglex_token_fingerprint },
160     { "-No_FingerPrint", (arglex_token_ty) arglex_token_fingerprint_not },
161     { "-FingerPrint_Update",
162         (arglex_token_ty) arglex_token_fingerprint_update },
163     { "-Forced", (arglex_token_ty) arglex_token_force },
164     { "-No_Forced", (arglex_token_ty) arglex_token_force_not },
165     { "-HyperText_Markup_Language", (arglex_token_ty) arglex_token_web },
166     { "-Include", (arglex_token_ty) arglex_token_include },
167     { "-\\I*", (arglex_token_ty) arglex_token_include },
168     { "-Include_Cooked", (arglex_token_ty) arglex_token_include_cooked },
169     { "-Include_Cooked_Warning",
170         (arglex_token_ty) arglex_token_include_cooked_warning },
171     { "-Jobs", (arglex_token_ty) arglex_token_parallel },
172     { "-No_Include_Cooked", (arglex_token_ty) arglex_token_include_cooked_not },
173     { "-No_Include_Cooked_Warning",
174         (arglex_token_ty) arglex_token_include_cooked_warning_not },
175     { "-LOg", (arglex_token_ty) arglex_token_log },
176     { "-List", (arglex_token_ty) arglex_token_log },
177     { "-No_LOg", (arglex_token_ty) arglex_token_log_not },
178     { "-No_List", (arglex_token_ty) arglex_token_log_not },
179     { "-Meter", (arglex_token_ty) arglex_token_metering },
180     { "-No_Meter", (arglex_token_ty) arglex_token_metering_not },
181     { "-PAirs", (arglex_token_ty) arglex_token_pairs },
182     { "-PARallel", (arglex_token_ty) arglex_token_parallel },
183     { "-No_PARallel", (arglex_token_ty) arglex_token_parallel_not },
184     { "-Precious", (arglex_token_ty) arglex_token_precious },
185     { "-No_Precious", (arglex_token_ty) arglex_token_precious_not },
186     { "-Reason", (arglex_token_ty) arglex_token_reason },
187     { "-No_Reason", (arglex_token_ty) arglex_token_reason_not },
188     { "-SCript", (arglex_token_ty) arglex_token_script },
189     { "-Silent", (arglex_token_ty) arglex_token_silent },
190     { "-No_Silent", (arglex_token_ty) arglex_token_silent_not },
191     { "-SHallow", (arglex_token_ty) arglex_token_shallow },
192     { "-No_SHallow", (arglex_token_ty) arglex_token_shallow_not },
193     { "-STar", (arglex_token_ty) arglex_token_star },
194     { "-No_STar", (arglex_token_ty) arglex_token_star_not },
195     { "-Strip_Dot", (arglex_token_ty) arglex_token_strip_dot },
196     { "-No_Strip_Dot", (arglex_token_ty) arglex_token_strip_dot_not },
197     { "-Symbolic_Link_Ingredients",
198         (arglex_token_ty)arglex_token_symlink_ingredients },
199     { "-Not_Symbolic_Link_Ingredients",
200         (arglex_token_ty)arglex_token_symlink_ingredients_not },
201     { "-Tell_Position", (arglex_token_ty) arglex_token_tell_position },
202     { "-No_Tell_Position", (arglex_token_ty) arglex_token_tell_position_not},
203     { "-TErminal", (arglex_token_ty) arglex_token_tty },
204     { "-No_TErminal", (arglex_token_ty) arglex_token_tty_not },
205     { "-Touch", (arglex_token_ty) arglex_token_touch },
206     { "-No_Touch", (arglex_token_ty) arglex_token_touch_not },
207     { "-TRace", (arglex_token_ty) arglex_token_reason },
208     { "-No_TRace", (arglex_token_ty) arglex_token_reason_not },
209     { "-Update", (arglex_token_ty) arglex_token_update },
210     { "-Time_Adjust", (arglex_token_ty) arglex_token_update },
211     { "-No_Update", (arglex_token_ty) arglex_token_update_not },
212     { "-No_Time_Adjust", (arglex_token_ty) arglex_token_update_not },
213     { "-Web", (arglex_token_ty) arglex_token_web },
214     { 0, (arglex_token_ty)0 },  /* end marker */
215 };
216 
217 
218 /*
219  *  NAME
220  *      usage - options diagnostic
221  *
222  *  SYNOPSIS
223  *      void usage(void);
224  *
225  *  DESCRIPTION
226  *      Usage is called when the user has made a syntactic or semantic error
227  *      on the command line.
228  *
229  *  CAVEAT
230  *      This function does NOT return.
231  */
232 
233 static void
usage(void)234 usage(void)
235 {
236     char            *progname;
237 
238     progname = progname_get();
239     fprintf(stderr, "usage: %s [ <option>... ][ <filename>... ]\n", progname);
240     fprintf(stderr, "       %s -Help\n", progname);
241     fprintf(stderr, "       %s -VERSion\n", progname);
242     quit(1);
243     trace(("to silence warnings\n"));
244 }
245 
246 
247 /*
248  * NAME
249  *      argparse - parse command line
250  *
251  * SYNOPSIS
252  *      void argparse(option_level_ty);
253  *
254  * DESCRIPTION
255  *      The argparse function is used to parse command lines.
256  *
257  * RETURNS
258  *      void
259  */
260 
261 static void
argparse(option_level_ty level)262 argparse(option_level_ty level)
263 {
264     option_number_ty type;
265     string_ty       *s;
266     sub_context_ty  *scp;
267     int             fingerprint_update;
268 
269     type = -1;
270     fingerprint_update = 0;
271     switch (arglex())
272     {
273     case arglex_token_help:
274         if (level != OPTION_LEVEL_COMMAND_LINE)
275         {
276           not_in_env:
277             scp = sub_context_new();
278             sub_var_set(scp, "Name", "%s", arglex_value.alv_string);
279             fatal_intl(scp, i18n("may not use $name in environment variable"));
280             /* NOTREACHED */
281         }
282         help((char *)0, usage);
283         quit(0);
284 
285     case arglex_token_version:
286         if (level != OPTION_LEVEL_COMMAND_LINE)
287             goto not_in_env;
288         version();
289         quit(0);
290 
291     default:
292         break;
293     }
294     while (arglex_token != arglex_token_eoln)
295     {
296         switch (arglex_token)
297         {
298         default:
299             generic_argument(usage);
300             continue;
301 
302         case arglex_token_include:
303             if (arglex() != arglex_token_string)
304             {
305                 arg_needs_string(arglex_token_include, usage);
306                 /* NOTREACHED */
307             }
308             s = str_from_c(arglex_value.alv_string);
309             string_list_append_unique(&option.o_search_path, s);
310             str_free(s);
311             break;
312 
313         case arglex_token_reason:
314             type = OPTION_REASON;
315           normal_on:
316             if (option_already(type, level))
317             {
318               too_many:
319                 arg_duplicate_cur(usage);
320                 /* NOTREACHED */
321             }
322             option_set(type, level, 1);
323             break;
324 
325         case arglex_token_reason_not:
326             type = OPTION_REASON;
327           normal_off:
328             if (option_already(type, level))
329                 goto too_many;
330             option_set(type, level, 0);
331             break;
332 
333         case arglex_token_cascade:
334             type = OPTION_CASCADE;
335             goto normal_on;
336 
337         case arglex_token_cascade_not:
338             type = OPTION_CASCADE;
339             goto normal_off;
340 
341         case arglex_token_disassemble:
342             type = OPTION_DISASSEMBLE;
343             goto normal_on;
344 
345         case arglex_token_disassemble_not:
346             type = OPTION_DISASSEMBLE;
347             goto normal_off;
348 
349         case arglex_token_tty:
350             type = OPTION_TERMINAL;
351             goto normal_on;
352 
353         case arglex_token_tty_not:
354             type = OPTION_TERMINAL;
355             goto normal_off;
356 
357         case arglex_token_precious:
358             type = OPTION_PRECIOUS;
359             goto normal_on;
360 
361         case arglex_token_precious_not:
362             type = OPTION_PRECIOUS;
363             goto normal_off;
364 
365         case arglex_token_log:
366             if (option_already(OPTION_LOGGING, level))
367                 goto too_many;
368             option_set(OPTION_LOGGING, level, 1);
369             if (arglex() != arglex_token_string)
370                 continue;
371             if (option.o_logfile)
372                 str_free(option.o_logfile);
373             option.o_logfile = str_from_c(arglex_value.alv_string);
374             break;
375 
376         case arglex_token_log_not:
377             type = OPTION_LOGGING;
378             goto normal_off;
379 
380         case arglex_token_book:
381             if (option_already(OPTION_BOOK, level))
382                 goto too_many;
383             option_set(OPTION_BOOK, level, 1);
384             if (arglex() != arglex_token_string)
385                 continue;
386             if (option.o_book)
387                 str_free(option.o_book);
388             option.o_book = str_from_c(arglex_value.alv_string);
389             break;
390 
391         case arglex_token_book_not:
392             type = OPTION_BOOK;
393             goto normal_off;
394 
395         case arglex_token_include_cooked:
396             type = OPTION_INCLUDE_COOKED;
397             goto normal_on;
398 
399         case arglex_token_include_cooked_not:
400             type = OPTION_INCLUDE_COOKED;
401             goto normal_off;
402 
403         case arglex_token_include_cooked_warning:
404             type = OPTION_INCLUDE_COOKED_WARNING;
405             goto normal_on;
406 
407         case arglex_token_include_cooked_warning_not:
408             type = OPTION_INCLUDE_COOKED_WARNING;
409             goto normal_off;
410 
411         case arglex_token_silent:
412             type = OPTION_SILENT;
413             goto normal_on;
414 
415         case arglex_token_silent_not:
416             type = OPTION_SILENT;
417             goto normal_off;
418 
419         case arglex_token_tell_position:
420             type = OPTION_TELL_POSITION;
421             goto normal_on;
422 
423         case arglex_token_tell_position_not:
424             type = OPTION_TELL_POSITION;
425             goto normal_off;
426 
427         case arglex_token_metering:
428             type = OPTION_METER;
429             goto normal_on;
430 
431         case arglex_token_metering_not:
432             type = OPTION_METER;
433             goto normal_off;
434 
435         case arglex_token_touch:
436             type = OPTION_TOUCH;
437             goto normal_on;
438 
439         case arglex_token_touch_not:
440             type = OPTION_TOUCH;
441             goto normal_off;
442 
443         case arglex_token_action:
444             type = OPTION_ACTION;
445             goto normal_on;
446 
447         case arglex_token_action_not:
448             type = OPTION_ACTION;
449             goto normal_off;
450 
451         case arglex_token_persevere:
452             type = OPTION_PERSEVERE;
453             goto normal_on;
454 
455         case arglex_token_persevere_not:
456             type = OPTION_PERSEVERE;
457             goto normal_off;
458 
459         case arglex_token_errok:
460             type = OPTION_ERROK;
461             goto normal_on;
462 
463         case arglex_token_errok_not:
464             type = OPTION_ERROK;
465             goto normal_off;
466 
467         case arglex_token_force:
468             type = OPTION_FORCE;
469             goto normal_on;
470 
471         case arglex_token_force_not:
472             type = OPTION_FORCE;
473             goto normal_off;
474 
475         case arglex_token_fingerprint:
476             type = OPTION_FINGERPRINT;
477             goto normal_on;
478 
479         case arglex_token_fingerprint_not:
480             type = OPTION_FINGERPRINT;
481             goto normal_off;
482 
483         case arglex_token_fingerprint_update:
484             if (level != OPTION_LEVEL_COMMAND_LINE)
485                 goto not_in_env;
486             if (option.fingerprint_update)
487                 goto too_many;
488             option.fingerprint_update++;
489             break;
490 
491         case arglex_token_pairs:
492             if (level != OPTION_LEVEL_COMMAND_LINE)
493                 goto not_in_env;
494             if (option.pairs)
495                 goto too_many;
496             option.pairs++;
497             break;
498 
499         case arglex_token_script:
500             if (level != OPTION_LEVEL_COMMAND_LINE)
501                 goto not_in_env;
502             if (option.script)
503                 goto too_many;
504             option.script++;
505             break;
506 
507         case arglex_token_web:
508             if (level != OPTION_LEVEL_COMMAND_LINE)
509                 goto not_in_env;
510             if (option.web)
511                 goto too_many;
512             option.web++;
513             break;
514 
515         case arglex_token_string:
516             if (level != OPTION_LEVEL_COMMAND_LINE)
517             {
518                 if (strchr(arglex_value.alv_string, '='))
519                 {
520                     fatal_intl
521                     (
522                         0,
523                         i18n("may not assign variables in environment variable")
524                     );
525                 }
526                 else
527                 {
528                     fatal_intl
529                     (
530                         0,
531                         i18n("may not name targets in environment variable")
532                     );
533                 }
534             }
535             else
536             {
537                 char            *cp;
538 
539                 cp = strchr(arglex_value.alv_string, '=');
540                 if (!cp)
541                 {
542                     s = str_from_c(arglex_value.alv_string);
543                     string_list_append(&option.o_target, s);
544                     str_free(s);
545                 }
546                 else
547                 {
548                     s = str_from_c(arglex_value.alv_string);
549                     string_list_append(&option.o_vardef, s);
550                     str_free(s);
551                 }
552             }
553             break;
554 
555         case arglex_token_star:
556             type = OPTION_STAR;
557             goto normal_on;
558 
559         case arglex_token_star_not:
560             type = OPTION_STAR;
561             goto normal_off;
562 
563         case arglex_token_strip_dot:
564             type = OPTION_STRIP_DOT;
565             goto normal_on;
566 
567         case arglex_token_strip_dot_not:
568             type = OPTION_STRIP_DOT;
569             goto normal_off;
570 
571         case arglex_token_symlink_ingredients:
572             type = OPTION_SYMLINK_INGREDIENTS;
573             goto normal_on;
574 
575         case arglex_token_symlink_ingredients_not:
576             type = OPTION_SYMLINK_INGREDIENTS;
577             goto normal_off;
578 
579         case arglex_token_update:
580             type = OPTION_UPDATE;
581             goto normal_on;
582 
583         case arglex_token_update_not:
584             type = OPTION_UPDATE;
585             goto normal_off;
586 
587         case arglex_token_parallel:
588             if (arglex() != arglex_token_number)
589             {
590                 s = str_from_c("parallel_jobs=4");
591                 string_list_append(&option.o_vardef, s);
592                 str_free(s);
593                 continue;
594             }
595             s = str_format("parallel_jobs=%d", (int)arglex_value.alv_number);
596             string_list_append(&option.o_vardef, s);
597             str_free(s);
598             break;
599 
600         case arglex_token_parallel_not:
601             s = str_from_c("parallel_jobs=1");
602             string_list_append(&option.o_vardef, s);
603             str_free(s);
604             break;
605 
606         case arglex_token_shallow:
607             type = OPTION_SHALLOW;
608             goto normal_on;
609 
610         case arglex_token_shallow_not:
611             type = OPTION_SHALLOW;
612             goto normal_off;
613         }
614         arglex();
615     }
616 }
617 
618 
619 static void
set_command_line_goals(void)620 set_command_line_goals(void)
621 {
622     string_ty       *name;
623     opcode_context_ty *ocp;
624 
625     name = str_from_c("command-line-goals");
626     ocp = opcode_context_new(0, 0);
627     opcode_context_id_assign(ocp, name, id_variable_new(&option.o_target), 0);
628     opcode_context_delete(ocp);
629     str_free(name);
630 }
631 
632 
633 /*
634  * NAME
635  *      main - initial entry point for cook
636  *
637  * SYNOPSIS
638  *      void main(int argc, char **argv);
639  *
640  * DESCRIPTION
641  *      Main is the initial entry point for cook.
642  *
643  * RETURNS
644  *      Exit is always through exit().
645  *      The exit code will be 0 for success, or 1 for some error.
646  */
647 
648 int
main(int argc,char ** argv)649 main(int argc, char **argv)
650 {
651     int             retval;
652 
653     /*
654      * Some versions of cron(8) and at(1) set SIGCHLD to SIG_IGN.
655      * This is kinda dumb, because it breaks assumprions made in
656      * libc (like pclose, for instance).  It also blows away most
657      * of Cook's process handling.  We explicitly set the SIGCHLD
658      * signal handling to SIG_DFL to make sure this signal does what
659      * we expect no matter how we are invoked.
660      */
661 #ifdef SIGCHLD
662     signal(SIGCHLD, SIG_DFL);
663 #else
664     signal(SIGCLD, SIG_DFL);
665 #endif
666 
667     /*
668      * initialize things
669      * (order is critical here)
670      */
671     progname_set(argv[0]);
672     str_initialize();
673     id_initialize();
674     lex_initialize();
675 
676     /*
677      * parse the COOK environment variable
678      */
679     arglex_init_from_env(argv[0], argtab);
680     argparse(OPTION_LEVEL_ENVIRONMENT);
681 
682     /*
683      * parse the command line
684      */
685     arglex_init(argc, argv, argtab);
686     argparse(OPTION_LEVEL_COMMAND_LINE);
687 
688     option_tidy_up();
689 
690     log_open();
691 
692     /*
693      * turn on progress stars if they asked for them
694      */
695     if (option_test(OPTION_STAR))
696         star_enable();
697 
698     /*
699      * If we were asked to update the fingerprints, do it here.
700      * We don't actually ant to read in the cookbook.
701      */
702     if (option.fingerprint_update)
703     {
704         fp_tweak();
705         quit(0);
706     }
707 
708     /*
709      * read in the cook book
710      *
711      * If there are #include-cooked directives,
712      * we may need to do it more than once.
713      */
714     if (!option.o_book)
715         fatal_intl(0, i18n("no book found"));
716     for (;;)
717     {
718         int             status;
719         size_t          j;
720 
721         builtin_initialize();
722 
723         /*
724          * instanciate the command line variable assignments
725          */
726         for (j = 0; j < option.o_vardef.nstrings; ++j)
727         {
728             char            *s;
729             char            *cp;
730             string_ty       *name;
731             string_ty       *value;
732             string_list_ty  wl;
733             opcode_context_ty *ocp;
734 
735             s = option.o_vardef.string[j]->str_text;
736             cp = strchr(s, '=');
737             assert(cp);
738             if (!cp)
739                 continue;
740             name = str_n_from_c(s, cp - s);
741             value = str_from_c(cp + 1);
742             str2wl(&wl, value, (char *)0, 0);
743             str_free(value);
744             ocp = opcode_context_new(0, 0);
745             opcode_context_id_assign(ocp, name, id_variable_new(&wl), 0);
746             opcode_context_delete(ocp);
747             str_free(name);
748             string_list_destructor(&wl);
749         }
750 
751         set_command_line_goals();
752 
753         parse(option.o_book);
754         status = cook_auto_required();
755         if (status < 0)
756             quit(1);
757         if (!status)
758             break;
759         id_reset();
760         cook_reset();
761     }
762 
763     /*
764      * work out what to cook.
765      * If no targets have been given, use the first explicit recipe.
766      */
767     set_command_line_goals();
768     if (!option.o_target.nstrings)
769         cook_find_default(&option.o_target);
770     assert(option.o_target.nstrings);
771 
772     /*
773      * cook the target
774      */
775     if (option.pairs)
776         retval = cook_pairs(&option.o_target);
777     else if (option.script)
778         retval = cook_script(&option.o_target);
779     else if (option.web)
780         retval = cook_web(&option.o_target);
781     else
782         retval = cook(&option.o_target);
783 
784 #ifdef DEBUG
785     fflush_slowly_report();
786 #endif
787 
788     quit(retval);
789     /*NOTREACHED*/
790     return 0;
791 }
792