1 /* ANSI-C code produced by gperf version 2.7.1 (19981006 egcs) */
2 /* Command-line: gperf -t -D -L ANSI-C confg.gperf */ /* -*- C -*- */
3 /*
4 * confg.c
5 *
6 * Read and understanding everything about the options
7 * & (dynamic) configuration of a2ps.
8 * Copyright (c) 1988-1993 Miguel Santana
9 * Copyright (c) 1995-1999 Akim Demaille, Miguel Santana
10 */
11
12 /*
13 * This file is part of a2ps.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
18 * any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; see the file COPYING. If not, write to
27 * the Free Software Foundation, 59 Temple Place - Suite 330,
28 * Boston, MA 02111-1307, USA.
29 */
30
31 /************************************************************************/
32 /* */
33 /* I n c l u d e f i l e s */
34 /* */
35 /************************************************************************/
36 #include "a2ps.h"
37 #include "routines.h"
38 #include "message.h"
39 #include "media.h"
40 #include "jobs.h"
41 #include "getshline.h"
42 #include "pathwalk.h"
43 #include "confg.h"
44 #include "useropt.h"
45 #include "path-concat.h"
46 #include "printers.h"
47 #include "options.h"
48 #include "metaseq.h"
49 #include "quotearg.h"
50 #include "dirname.h"
51
52 extern char *program_name;
53
54 /*
55 * Hooks used
56 */
57 config_hook delegation_hook = NULL;
58 config_hook toc_entry_hook = NULL;
59
60 enum keyword_e
61 {
62 AppendLibraryPath,
63 DefaultPPD,
64 DefaultPrinter,
65 Delegation,
66 FileCommand,
67 Include,
68 LibraryPath,
69 Medium,
70 Obsolete,
71 Options,
72 OutputFirstLine,
73 PageLabelFormat,
74 PrependLibraryPath,
75 Printer,
76 UnknownPrinter,
77 UserOption,
78 Variable
79 };
80
81 struct keyword_s
82 {
83 const char *name;
84 enum keyword_e code;
85 /* Number of arguments. */
86 int argc;
87 /* If true, the last argument composed of the rest of the line,
88 otherwise separated by spaces. */
89 bool line_token;
90 };
91
92 #define TOTAL_KEYWORDS 21
93 #define MIN_WORD_LENGTH 6
94 #define MAX_WORD_LENGTH 19
95 #define MIN_HASH_VALUE 6
96 #define MAX_HASH_VALUE 36
97 /* maximum key range = 31, duplicates = 2 */
98
99 #ifdef __GNUC__
100 __inline
101 #endif
102 static unsigned int
hash(register const char * str,register unsigned int len)103 hash (register const char *str, register unsigned int len)
104 {
105 static unsigned char asso_values[] =
106 {
107 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
108 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
109 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
110 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
111 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
112 37, 37, 37, 37, 37, 37, 37, 37, 0, 37,
113 37, 37, 37, 37, 37, 5, 37, 37, 0, 37,
114 5, 37, 37, 5, 37, 37, 10, 0, 37, 20,
115 0, 37, 37, 37, 5, 10, 0, 37, 37, 37,
116 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
117 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
118 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
119 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
120 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
121 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
122 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
123 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
124 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
125 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
126 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
127 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
128 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
129 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
130 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
131 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
132 37, 37, 37, 37, 37, 37
133 };
134 return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
135 }
136
137 #ifdef __GNUC__
138 __inline
139 #endif
140 struct keyword_s *
in_word_set(register const char * str,register unsigned int len)141 in_word_set (register const char *str, register unsigned int len)
142 {
143 static struct keyword_s wordlist[] =
144 {
145 {"Media:", Medium, 2, true},
146 {"Medium:", Medium, 2, true},
147 {"Pattern:", Obsolete, 1, true},
148 {"Printer:", Printer, 2, true},
149 {"Variable:", Variable, 2, true},
150 {"DefaultPPD:", DefaultPPD, 1, false},
151 {"Delegation:", Delegation, 1, true},
152 {"PassThrough:", Obsolete, 1, true},
153 {"Include:", Include, 1, false},
154 {"DefaultPrinter:", DefaultPrinter, 1, true},
155 {"PageLabelFormat:", PageLabelFormat, 1, true},
156 {"FileCommand:", FileCommand, 1, true},
157 {"MacroMetaSequence:", Variable, 2, true},
158 {"PrependLibraryPath:", PrependLibraryPath, 1, true},
159 {"UserOption:", UserOption, 2, true},
160 {"LibraryPath:", LibraryPath, 1, false},
161 {"AppendLibraryPath:", AppendLibraryPath, 1, true},
162 {"TemporaryDirectory:", Obsolete, 1, true},
163 {"UnknownPrinter:", UnknownPrinter, 1, true},
164 {"Options:", Options, 1, true},
165 {"OutputFirstLine:", OutputFirstLine, 1, true}
166 };
167
168 static short lookup[] =
169 {
170 -1, -1, -1, -1, -1, -1, 0, 1, -51, 4,
171 -1, -48, 7, 8, -1, 9, 10, 11, 12, 13,
172 -1, 14, 15, 16, 17, 18, -16, -2, 19, -19,
173 -2, -1, -1, -1, -1, -1, 20
174 };
175
176 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
177 {
178 register int key = hash (str, len);
179
180 if (key <= MAX_HASH_VALUE && key >= 0)
181 {
182 register int index = lookup[key];
183
184 if (index >= 0)
185 {
186 register const char *s = wordlist[index].name;
187
188 if (*str == *s && !strcmp (str + 1, s + 1))
189 return &wordlist[index];
190 }
191 else if (index < -TOTAL_KEYWORDS)
192 {
193 register int offset = - 1 - TOTAL_KEYWORDS - index;
194 register struct keyword_s *wordptr = &wordlist[TOTAL_KEYWORDS + lookup[offset]];
195 register struct keyword_s *wordendptr = wordptr + -lookup[offset + 1];
196
197 while (wordptr < wordendptr)
198 {
199 register const char *s = wordptr->name;
200
201 if (*str == *s && !strcmp (str + 1, s + 1))
202 return wordptr;
203 wordptr++;
204 }
205 }
206 }
207 }
208 return 0;
209 }
210 /*
211 * Read the configuration file
212 */
213 int
a2_read_config(a2ps_job * job,const char * path,const char * file)214 a2_read_config (a2ps_job * job, const char *path, const char *file)
215 {
216 /* The maximum number of args for an entry. */
217 #define MAX_ARGC 10
218 FILE *fp;
219 char * fname;
220 char *buf = NULL;
221 size_t bufsiz = 0;
222 int firstline = 0, lastline = 0;
223
224 fname = xpath_concat (path, file, NULL);
225
226 fp = fopen (fname, "r");
227 if (fp == NULL)
228 {
229 free (fname);
230 return 0;
231 }
232
233 message (msg_opt | msg_file,
234 (stderr, "Reading configuration file `%s'\n", fname));
235
236 while (getshline_numbered (&firstline, &lastline, &buf, &bufsiz, fp) != -1)
237 {
238 struct keyword_s *keyword;
239 /* An array of the arguments. The first argument ARGV[0] is the
240 name of the entry, eg 'Options:'. */
241 int argc;
242 char *argv [MAX_ARGC];
243
244 argv[0] = strtok (buf, " \t\n");
245
246 /* Blank line, but not empty */
247 if (!argv[0])
248 continue;
249
250 keyword = in_word_set (argv[0], strlen (argv[0]));
251 if (!keyword)
252 error_at_line (1, 0, fname, firstline,
253 _("invalid option `%s'"), quotearg (argv[0]));
254
255 /* Fetch the arguments */
256 for (argc = 1 ; argc <= keyword->argc ; argc++)
257 {
258 if (keyword->line_token && argc == keyword->argc)
259 argv [argc] = strtok (NULL, "\n");
260 else
261 argv [argc] = strtok (NULL, " \t\n");
262 if (argv [argc] == NULL)
263 error_at_line (1, 0, fname, firstline,
264 _("missing argument for `%s'"), quotearg (argv[0]));
265 }
266 /* Check that there is no extra argument. */
267 if (strtok (NULL, "\n"))
268 error_at_line (1, 0, fname, firstline,
269 "extra argument for `%s'", quotearg (argv[0]));
270
271 /* Process the entry. */
272 switch (keyword->code)
273 {
274 case Include: /* At this point, read another config file. */
275 {
276 char * dir;
277 if (*argv[1] == DIRECTORY_SEPARATOR)
278 /* Path is absolute */
279 dir = NULL;
280 else
281 /* Relative. Give its root. */
282 dir = dir_name (fname);
283
284 if (!a2_read_config (job, dir, argv[1]))
285 {
286 char *included_file = xpath_concat (dir, argv[1], NULL);
287 error_at_line (0, errno, fname, firstline,
288 _("cannot open file `%s'"),
289 quotearg (included_file));
290 free (included_file);
291 }
292 XFREE (dir);
293 }
294 break;
295
296 case Options:
297 {
298 /* Set PROGRAM_NAME so that the error messages report the
299 file name and line. */
300 char *old_program_name = program_name;
301 program_name = ALLOCA (char,
302 strlen (program_name)
303 + strlen (fname)
304 + strlen ("%:%:999990"));
305 sprintf (program_name, "%s:%s:%d",
306 old_program_name, fname, firstline);
307 a2ps_handle_string_options (job, argv[1]);
308 program_name = old_program_name;
309 }
310 break;
311
312 case DefaultPPD: /* Default PPD file */
313 a2ps_printers_default_ppdkey_set (job->printers, argv[1]);
314 break;
315
316 /* Handling of the printers */
317 case Printer:
318 if (!a2ps_printers_add (job->printers, argv[1], argv[2]))
319 error_at_line (1, 0, fname, firstline,
320 _("invalid definition for printer `%s': %s"),
321 argv[1], quotearg (argv[2]));
322 break;
323
324 case UnknownPrinter:
325 if (!a2ps_printers_add (job->printers, _("Unknown Printer"), argv[1]))
326 error_at_line (1, 0, fname, firstline,
327 _("invalid definition for printer `%s': %s"),
328 _("Unknown Printer"), quotearg (argv[1]));
329 break;
330
331 case DefaultPrinter:
332 if (!a2ps_printers_add (job->printers, _("Default Printer"), argv[1]))
333 error_at_line (1, 0, fname, firstline,
334 _("invalid definition for printer `%s': %s"),
335 _("Default Printer"), quotearg (argv[1]));
336 break;
337
338 case Delegation:
339 /* This is only for a2ps the program. Read this only if
340 there's a reader */
341 if (delegation_hook)
342 (*delegation_hook) (fname, firstline, argv[1]);
343 break;
344
345 case UserOption:
346 user_option_add (job, argv[1], argv[2]);
347 break;
348
349 case OutputFirstLine:
350 xustrcpy (job->status->magic_number, argv[1]);
351 break;
352
353 case PageLabelFormat:
354 xustrcpy (job->status->page_label_format, argv[1]);
355 break;
356
357 case Medium:
358 {
359 int w, h, llx, lly, urx, ury;
360
361 switch (sscanf (argv[2], "%d %d %d %d %d %d",
362 &w, &h, &llx, &lly, &urx, &ury))
363 {
364 case 6:
365 /* BBox is also given */
366 break;
367
368 case 2:
369 /* A short hand has been used: use 24 points as a
370 margin all around */
371 llx = lly = 24;
372 urx = w - 24;
373 ury = h - 24;
374 break;
375
376 default:
377 error_at_line (1, 0, fname, firstline,
378 "invalid number of arguments for `%s'",
379 quotearg (argv[0]));
380 }
381 add_medium (job, argv[1], w, h, llx, lly, urx, ury);
382 }
383 break;
384
385 case Variable:
386 if (!macro_meta_sequence_add (job, argv[1], argv[2]))
387 error_at_line (1, 0, fname, firstline,
388 _("invalid variable identifier `%s'"),
389 quotearg (argv[1]));
390 break;
391
392 /* Handling of the library path */
393 case LibraryPath:
394 XFREE (job->common.path);
395 job->common.path = pw_string_to_path (argv[1]);
396 break;
397
398 case AppendLibraryPath:
399 job->common.path = pw_append_string_to_path (job->common.path,
400 argv[1]);
401 break;
402
403 case PrependLibraryPath:
404 job->common.path = pw_prepend_string_to_path (job->common.path,
405 argv[1]);
406 break;
407
408 case FileCommand: /* How to call file */
409 xstrcpy (job->file_command, argv[1]);
410 break;
411
412 case Obsolete:
413 /* TRANS: The following message says that in a2ps.cfg there
414 is an entry (such as `Pattern:', or `PassThrough:') which
415 is no longer used. */
416 error_at_line (0, 0, fname, firstline,
417 _("obsolete `%s' entry. Ignored"), argv[0]);
418 break;
419 }
420 }
421 XFREE (fname);
422 fclose (fp);
423 /* BUF was allocated by getshlinenumbered. */
424 free (buf);
425 return 1;
426 }
427
428 /* Global config.
429 * This is really not an easy thing because, people may want
430 * to check the package before the installation. The worst
431 * case is when an older a2ps is yet installed. So we _must_
432 * have a special way to deal with the tests. This is why
433 * I introduced an env-var: A2PS_CONFIG, which
434 * points to a2ps.cfg.
435 * Note that it also improves the robustness of `make distcheck'.
436 */
437 void
a2_read_sys_config(a2ps_job * job)438 a2_read_sys_config (a2ps_job * job)
439 {
440 const char *config_file;
441
442 config_file = getenv ("A2PS_CONFIG");
443 if (!config_file)
444 config_file = SYSCONFFILE;
445
446 /* I see no reason to end a2ps here if the file is not found: other
447 files follow. Just say it. */
448 if (a2_read_config (job, NULL, config_file))
449 return;
450 error (0, errno,
451 _("cannot open file `%s'"), quotearg (config_file));
452 }
453