1 /*
2 * cook - file construction tool
3 * Copyright (C) 1993-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 * The options may be set at various levels. The level with the highest
21 * precedence which has actually been set is used to determine the option
22 * value at any given time.
23 *
24 * Each level of an option is represented by 2 bits in the flag word. One bit
25 * is used to indicate that the option has been set for that level, the other
26 * bit indicates the state. Determining the least set bit in an expression is
27 * cheap (x&-x) so highest priority is the lowest numbered level.
28 *
29 * The COOK enviroment variable is basically a replacement for the defaults,
30 * so that users can change the default behaviour. The command line overrides
31 * almost everything. The error level is the only level with higher
32 * precedence than the command line, and it is used to prevent disasters
33 * after parse errors or interrupts have happened.
34 *
35 * -------------------------------------------------------------------------
36 *
37 *
38 * If you are going to add a new recipe flag (set by the "set" statement,
39 * or the "set" clause of a recipe) you need to change all of the
40 * following places:
41 *
42 * cook/option.h
43 * to define the OPTION_ value
44 * cook/option.c
45 * option_tidyup()
46 * if the option defaults to true
47 * option_set_errors()
48 * if the option should be turned off once cookbook errors
49 * are encountered.
50 * option_number_name()
51 * for the name of the option
52 * cook/flag.h
53 * to define the RF_ values (RF stands for Recipe Flag)
54 * cook/flag.c
55 * to define the RF_ names
56 * langu.flags.so
57 * to document the recipe flag
58 *
59 * If you choose to make it a command line option,
60 * you must also update these files:
61 *
62 * cook/main.c
63 * to define the new command line option and process it
64 * (only if it should also be a command line option)
65 * cook/builtin/options.c
66 * to access the option from within the cookbook (typically used
67 * for recursive cook invokations)
68 * lib/en/man1/cook.1
69 * to document it, if you added a new command line option
70 */
71
72 #include <common/ac/ctype.h>
73 #include <common/ac/limits.h>
74 #include <common/ac/stddef.h>
75 #include <common/ac/stdio.h>
76 #include <common/ac/stdlib.h>
77 #include <common/ac/string.h>
78 #include <common/ac/time.h>
79
80 #include <common/libdir.h>
81 #include <common/mem.h>
82 #include <common/progname.h>
83 #include <common/trace.h>
84 #include <cook/option.h>
85 #include <cook/os_interface.h>
86
87
88 typedef struct flag_ty flag_ty;
89 struct flag_ty
90 {
91 unsigned long o_flag[OPTION_max];
92 };
93
94 option_ty option;
95 static flag_ty flag;
96
97
98 /*
99 * NAME
100 * option_set - set an option
101 *
102 * SYNOPSIS
103 * void option_set(option_number_ty num, option_level_ty lvl, int state);
104 *
105 * DESCRIPTION
106 * The option_set function is used to set the given option at the given
107 * level to the given state.
108 *
109 * RETURNS
110 * void
111 */
112
113 void
option_set(option_number_ty o,option_level_ty level,int state)114 option_set(option_number_ty o, option_level_ty level, int state)
115 {
116 trace(("option_set(o = %s, level = %s, state = %d)\n{\n",
117 option_number_name(o), option_level_name(level), state));
118 assert((int)o >= 0 && (int)o < (int)OPTION_max);
119 flag.o_flag[(size_t) o] &= ~(3L << (2 * (int)level));
120 if (state)
121 flag.o_flag[(size_t) o] |= 3L << (2 * (int)level);
122 else
123 flag.o_flag[(size_t) o] |= 1L << (2 * (int)level);
124 trace(("}\n"));
125 }
126
127
128 /*
129 * NAME
130 * option_already - see if an option is already set
131 *
132 * SYNOPSIS
133 * int option_already(option_number_ty num, option_level_ty lvl);
134 *
135 * DESCRIPTION
136 * The option_already function is used to test if a given option at a
137 * given level has been set.
138 *
139 * RETURNS
140 * int: zero if the option has not been set, nonzero if it has.
141 */
142
143 int
option_already(option_number_ty o,option_level_ty level)144 option_already(option_number_ty o, option_level_ty level)
145 {
146 int result;
147
148 trace(("option_already(o = %s, level = %s)\n{\n",
149 option_number_name(o), option_level_name(level)));
150 assert((int)o >= 0 && (int)o < (int)OPTION_max);
151 result = (((flag.o_flag[(size_t) o] >> (2 * (int)level)) & 1) != 0);
152 trace(("return %d;\n", result));
153 trace(("}\n"));
154 return result;
155 }
156
157
158 /*
159 * NAME
160 * option_undo - remove option setting
161 *
162 * SYNOPSIS
163 * void option_undo(option_number_ty num, option_level_ty lvl);
164 *
165 * DESCRIPTION
166 * The option_undo function is used to is used to remove the option
167 * setting for the given option at the given level.
168 *
169 * RETURNS
170 * void
171 */
172
173 void
option_undo(option_number_ty o,option_level_ty level)174 option_undo(option_number_ty o, option_level_ty level)
175 {
176 trace(("option_undo(o = %s, level = %s)\n{\n", option_number_name(o),
177 option_level_name(level)));
178 assert((int)o >= 0 && (int)o < (int)OPTION_max);
179 flag.o_flag[(size_t) o] &= ~(3L << (2 * (int)level));
180 trace(("}\n"));
181 }
182
183
184 /*
185 * NAME
186 * option_undo_level - remove options settings
187 *
188 * SYNOPSIS
189 * void option_undo_level(option_level_ty lvl);
190 *
191 * DESCRIPTION
192 * The option_undo_level function is used to remove the settings for all
193 * options at a given level.
194 *
195 * RETURNS
196 * void
197 */
198
199 void
option_undo_level(option_level_ty level)200 option_undo_level(option_level_ty level)
201 {
202 int o;
203
204 trace(("option_undo_level(level = %s)\n{\n", option_level_name(level)));
205 for (o = 0; o < (int)OPTION_max; ++o)
206 option_undo((option_number_ty) o, level);
207 trace(("}\n"));
208 }
209
210
211 /*
212 * NAME
213 * option_test - test an option
214 *
215 * SYNOPSIS
216 * int option_test(option_number_ty num);
217 *
218 * DESCRIPTION
219 * The option_test function is used to test the setting of an option.
220 * The level of highest precedence which hash been set is used.
221 *
222 * RETURNS
223 * int: zero if the option is off, nonzero if the option is on.
224 */
225
226 int
option_test(option_number_ty o)227 option_test(option_number_ty o)
228 {
229 unsigned long *op;
230 unsigned long mask;
231 int result;
232
233 trace(("option_test(o = %s)\n{\n", option_number_name(o)));
234 assert((int)o >= 0 && (int)o < (int)OPTION_max);
235 op = &flag.o_flag[(size_t) o];
236 mask = *op & 0x55555555;
237 mask &= -mask; /* get LSB */
238 result = ((*op & (mask << 1)) != 0);
239 trace(("return %d;\n", result));
240 trace(("}\n"));
241 return result;
242 }
243
244
245 static string_ty *
Capitalize(string_ty * s)246 Capitalize(string_ty *s)
247 {
248 if (s->str_length < 1 || !islower((unsigned char)s->str_text[0]))
249 return str_copy(s);
250 return
251 str_format
252 (
253 "%c%s",
254 toupper((unsigned char)s->str_text[0]),
255 s->str_text + 1
256 );
257 }
258
259
260 /*
261 * NAME
262 * option_tidy_up - mother hen
263 *
264 * SYNOPSIS
265 * void option_tidy_up(void);
266 *
267 * DESCRIPTION
268 * The option_tidy_up function is used to set a few defaults, and tidy up
269 * after the command line.
270 *
271 * RETURNS
272 * void
273 *
274 * CAVEAT
275 * Must be called after the command line has been parsed.
276 */
277
278 void
option_tidy_up(void)279 option_tidy_up(void)
280 {
281 string_ty *s;
282 string_ty *s1;
283
284 /*
285 * Set the defaults before we do anything else,
286 * the rest of tidy_up depends on them.
287 */
288 trace(("option_tidy_up()\n{\n"));
289 option_set(OPTION_ACTION, OPTION_LEVEL_DEFAULT, 1);
290 option_set(OPTION_CASCADE, OPTION_LEVEL_DEFAULT, 1);
291 option_set(OPTION_FINGERPRINT_WRITE, OPTION_LEVEL_DEFAULT, 1);
292 option_set(OPTION_INCLUDE_COOKED, OPTION_LEVEL_DEFAULT, 1);
293 option_set(OPTION_INCLUDE_COOKED_WARNING, OPTION_LEVEL_DEFAULT, 1);
294 option_set(OPTION_LOGGING, OPTION_LEVEL_DEFAULT, 1);
295 option_set(OPTION_STRIP_DOT, OPTION_LEVEL_DEFAULT, 1);
296 option_set(OPTION_TERMINAL, OPTION_LEVEL_DEFAULT, 1);
297
298 /*
299 * user's library
300 */
301 s = os_accdir();
302 assert(s);
303 s1 = str_format("%s/.%s", s->str_text, progname_get());
304 str_free(s);
305 string_list_append_unique(&option.o_search_path, s1);
306 str_free(s1);
307
308 /*
309 * cook's library
310 * architecture-specific, then architecture-neutral
311 */
312 s = str_from_c(library_directory_get());
313 string_list_append_unique(&option.o_search_path, s);
314 str_free(s);
315 s = str_from_c(data_directory_get());
316 string_list_append_unique(&option.o_search_path, s);
317 str_free(s);
318
319 if (!option.o_book)
320 {
321 static char *name[] =
322 {
323 ".how.to.%s",
324 ".howto.%s",
325 "how.to.%s",
326 "howto.%s",
327 "%s.file",
328 "%sfile",
329 "%s.book",
330 "%sbook",
331 ".%s.rc",
332 ".%src",
333 };
334 size_t j;
335
336 /*
337 * A huge range of alternative default names is given.
338 * The first found will be used.
339 */
340 for (j = 0; j < SIZEOF(name); j++)
341 {
342 s = str_format(name[j], progname_get());
343 switch (os_exists(s))
344 {
345 case -1:
346 exit(1);
347
348 case 0:
349 s1 = Capitalize(s);
350 str_free(s);
351 s = s1;
352 switch (os_exists(s))
353 {
354 case -1:
355 exit(1);
356
357 case 0:
358 str_free(s);
359 continue;
360
361 case 1:
362 option.o_book = s;
363 break;
364 }
365 break;
366
367 case 1:
368 option.o_book = s;
369 break;
370 }
371 break;
372 }
373 }
374
375 if (!option.o_logfile && option.o_book)
376 {
377 char *sp;
378 char *cp;
379
380 sp = option.o_book->str_text;
381 /* skip first char in case it's a '.' */
382 cp = strrchr(sp + 1, '.');
383 if (cp)
384 s = str_n_from_c(sp, cp - sp);
385 else
386 s = str_copy(option.o_book);
387 sp = (option_test(OPTION_CMDFILE) ? "sh" : "list");
388 option.o_logfile = str_format("%s.%s", s->str_text, sp);
389 str_free(s);
390 }
391 trace(("}\n"));
392 }
393
394
395 /*
396 * NAME
397 * option_set_errors - set error flags
398 *
399 * SYNOPSIS
400 * void option_set_errors(void);
401 *
402 * DESCRIPTION
403 * The option_set_errors function is used to set the appropriate options
404 * to prevent undesirable side effects when errors occur.
405 *
406 * RETURNS
407 * void
408 */
409
410 void
option_set_errors(void)411 option_set_errors(void)
412 {
413 trace(("option_set_errors()\n{\n"));
414 option_set(OPTION_SILENT, OPTION_LEVEL_ERROR, 0);
415 option_set(OPTION_ACTION, OPTION_LEVEL_ERROR, 0);
416 option_set(OPTION_ERROK, OPTION_LEVEL_ERROR, 0);
417 option_set(OPTION_METER, OPTION_LEVEL_ERROR, 0);
418 option_set(OPTION_PERSEVERE, OPTION_LEVEL_ERROR, 0);
419 trace(("}\n"));
420 }
421
422
423 void *
option_flag_state_get(void)424 option_flag_state_get(void)
425 {
426 flag_ty *fp;
427
428 fp = mem_alloc(sizeof(flag_ty));
429 *fp = flag;
430 return fp;
431 }
432
433
434 void
option_flag_state_set(void * p)435 option_flag_state_set(void *p)
436 {
437 flag_ty *fp;
438
439 fp = p;
440 flag = *fp;
441 mem_free(p);
442 }
443
444
445 const char *
option_level_name(option_level_ty lvl)446 option_level_name(option_level_ty lvl)
447 {
448 switch (lvl)
449 {
450 case OPTION_LEVEL_ERROR:
451 return "OPTION_LEVEL_ERROR";
452
453 case OPTION_LEVEL_AUTO:
454 return "OPTION_LEVEL_AUTO";
455
456 case OPTION_LEVEL_COMMAND_LINE:
457 return "OPTION_LEVEL_COMMAND_LINE";
458
459 case OPTION_LEVEL_EXECUTE:
460 return "OPTION_LEVEL_EXECUTE";
461
462 case OPTION_LEVEL_RECIPE:
463 return "OPTION_LEVEL_RECIPE";
464
465 case OPTION_LEVEL_COOKBOOK:
466 return "OPTION_LEVEL_COOKBOOK";
467
468 case OPTION_LEVEL_ENVIRONMENT:
469 return "OPTION_LEVEL_ENVIRONMENT";
470
471 case OPTION_LEVEL_DEFAULT:
472 return "OPTION_LEVEL_DEFAULT";
473 }
474 return "option level unknown";
475 }
476
477
478 const char *
option_number_name(option_number_ty o)479 option_number_name(option_number_ty o)
480 {
481 switch (o)
482 {
483 case OPTION_ACTION:
484 return "OPTION_ACTION";
485
486 case OPTION_BOOK:
487 return "OPTION_BOOK";
488
489 case OPTION_CASCADE:
490 return "OPTION_CASCADE";
491
492 case OPTION_CMDFILE:
493 return "OPTION_CMDFILE";
494
495 case OPTION_DISASSEMBLE:
496 return "OPTION_DISASSEMBLE";
497
498 case OPTION_ERROK:
499 return "OPTION_ERROK";
500
501 case OPTION_FINGERPRINT:
502 return "OPTION_FINGERPRINT";
503
504 case OPTION_FINGERPRINT_WRITE:
505 return "OPTION_FINGERPRINT_WRITE";
506
507 case OPTION_FORCE:
508 return "OPTION_FORCE";
509
510 case OPTION_GATEFIRST:
511 return "OPTION_GATEFIRST";
512
513 case OPTION_IMPLICIT_ALLOWED:
514 return "OPTION_IMPLICIT_ALLOWED";
515
516 case OPTION_INCLUDE_COOKED:
517 return "OPTION_INCLUDE_COOKED";
518
519 case OPTION_INCLUDE_COOKED_WARNING:
520 return "OPTION_INCLUDE_COOKED_WARNING";
521
522 case OPTION_INGREDIENTS_FINGERPRINT:
523 return "OPTION_INGREDIENTS_FINGERPRINT";
524
525 case OPTION_INVALIDATE_STAT_CACHE:
526 return "OPTION_INVALIDATE_STAT_CACHE";
527
528 case OPTION_LOGGING:
529 return "OPTION_LOGGING";
530
531 case OPTION_METER:
532 return "OPTION_METER";
533
534 case OPTION_MKDIR:
535 return "OPTION_MKDIR";
536
537 case OPTION_PERSEVERE:
538 return "OPTION_PERSEVERE";
539
540 case OPTION_PRECIOUS:
541 return "OPTION_PRECIOUS";
542
543 case OPTION_REASON:
544 return "OPTION_REASON";
545
546 case OPTION_RECURSE:
547 return "OPTION_RECURSE";
548
549 case OPTION_SHALLOW:
550 return "OPTION_SHALLOW";
551
552 case OPTION_SILENT:
553 return "OPTION_SILENT";
554
555 case OPTION_STAR:
556 return "OPTION_STAR";
557
558 case OPTION_STRIP_DOT:
559 return "OPTION_STRIP_DOT";
560
561 case OPTION_SYMLINK_INGREDIENTS:
562 return "OPTION_SYMLINK_INGREDIENTS";
563
564 case OPTION_TERMINAL:
565 return "OPTION_TERMINAL";
566
567 case OPTION_TOUCH:
568 return "OPTION_TOUCH";
569
570 case OPTION_UNLINK:
571 return "OPTION_UNLINK";
572
573 case OPTION_UPDATE:
574 return "OPTION_UPDATE";
575
576 case OPTION_UPDATE_MAX:
577 return "OPTION_UPDATE_MAX";
578
579 case OPTION_MATCH_MODE_REGEX:
580 return "OPTION_MATCH_MODE_REGEX";
581
582 case OPTION_TELL_POSITION:
583 return "OPTION_TELL_POSITION";
584
585 case OPTION_max:
586 break;
587 }
588 return "option number unknown";
589 }
590