Tue, 01 Jan 2002 06:17:39 +0000
eliminate shift/reduce conflicts in output file attributes.
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
5 #include "type.h"
6 #include "semantics.h"
7 #include "parser.tab.h"
8 #include "tiff2pdf.h"
11 typedef struct
12 {
13 boolean has_size;
14 page_size_t size;
16 boolean has_rotation;
17 int rotation;
19 boolean has_crop;
20 crop_t crop;
21 } input_modifiers_t;
24 typedef struct input_context_t
25 {
26 struct input_context_t *parent;
27 struct input_context_t *next;
29 int image_count; /* how many pages reference this context,
30 including those from subcontexts */
32 char *input_file;
34 input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
35 } input_context_t;
38 typedef struct input_image_t
39 {
40 struct input_image_t *next;
41 input_context_t *input_context;
42 range_t range;
43 } input_image_t;
46 typedef struct output_context_t
47 {
48 struct output_context_t *parent;
49 struct output_context_t *next;
51 int page_count; /* how many pages reference this context,
52 including those from subcontexts */
54 char *output_file;
55 pdf_file_attributes_t file_attributes;
57 bookmark_t *first_bookmark;
58 bookmark_t *last_bookmark;
60 boolean has_page_label;
61 page_label_t page_label;
62 } output_context_t;
65 typedef struct output_page_t
66 {
67 struct output_page_t *next;
68 output_context_t *output_context;
69 range_t range;
70 bookmark_t *bookmark_list;
71 } output_page_t;
74 #define SEMANTIC_DEBUG
75 #ifdef SEMANTIC_DEBUG
76 #define SDBG(x) printf x
77 #else
78 #define SDBG(x)
79 #endif
82 FILE *yyin;
83 int line; /* line number in spec file */
85 int bookmark_level;
87 input_context_t *first_input_context;
88 input_context_t *last_input_context;
90 input_modifier_type_t current_modifier_context;
92 input_image_t *first_input_image;
93 input_image_t *last_input_image;
95 output_context_t *first_output_context;
96 output_context_t *last_output_context;
98 output_page_t *first_output_page;
99 output_page_t *last_output_page;
102 void input_push_context (void)
103 {
104 input_context_t *new_input_context;
106 new_input_context = malloc (sizeof (input_context_t));
107 if (! new_input_context)
108 {
109 fprintf (stderr, "failed to malloc an input context\n");
110 return;
111 }
113 if (last_input_context)
114 {
115 memcpy (new_input_context, last_input_context, sizeof (input_context_t));
116 new_input_context->image_count = 0;
117 }
118 else
119 {
120 memset (new_input_context, 0, sizeof (input_context_t));
121 first_input_context = new_input_context;
122 }
124 new_input_context->parent = last_input_context;
125 last_input_context = new_input_context;
126 };
128 void input_pop_context (void)
129 {
130 if (! last_input_context)
131 {
132 fprintf (stderr, "failed to pop an input context\n");
133 return;
134 }
136 last_input_context = last_input_context->parent;
137 };
139 void input_set_modifier_context (input_modifier_type_t type)
140 {
141 current_modifier_context = type;
142 #ifdef SEMANTIC_DEBUG
143 SDBG(("modifier type "));
144 switch (type)
145 {
146 case INPUT_MODIFIER_ALL: SDBG(("all")); break;
147 case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
148 case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
149 default: SDBG(("unknown %d", type));
150 }
151 SDBG(("\n"));
152 #endif /* SEMANTIC_DEBUG */
153 }
155 static void input_clone (void)
156 {
157 input_context_t *new_input_context;
159 if (! last_input_context->image_count)
160 return;
162 new_input_context = malloc (sizeof (input_context_t));
163 if (! new_input_context)
164 {
165 fprintf (stderr, "failed to malloc an input context\n");
166 return;
167 }
169 memcpy (new_input_context, last_input_context, sizeof (input_context_t));
170 new_input_context->image_count = 0;
171 last_input_context->next = new_input_context;
172 }
174 void input_set_file (char *name)
175 {
176 input_clone ();
177 last_input_context->input_file = name;
178 };
180 void input_set_rotation (int rotation)
181 {
182 last_input_context->modifiers [current_modifier_context].has_rotation = 1;
183 last_input_context->modifiers [current_modifier_context].rotation = rotation;
184 SDBG(("rotation %d\n", rotation));
185 }
187 static void increment_input_image_count (int count)
188 {
189 input_context_t *context;
191 for (context = last_input_context; context; context = context->parent)
192 context->image_count += count;
193 }
195 void input_images (range_t range)
196 {
197 input_image_t *new_image;
198 int count = ((range.last - range.first) + 1);
200 #ifdef SEMANTIC_DEBUG
201 if (range.first == range.last)
202 SDBG(("image %d\n", range.first));
203 else
204 SDBG(("images %d..%d\n", range.first, range.last));
205 #endif /* SEMANTIC_DEBUG */
207 new_image = calloc (1, sizeof (input_image_t));
208 if (! new_image)
209 {
210 fprintf (stderr, "failed to malloc an input image struct\n");
211 return;
212 }
213 if (first_input_image)
214 {
215 last_input_image->next = new_image;
216 last_input_image = new_image;
217 }
218 else
219 {
220 first_input_image = last_input_image = new_image;
221 }
222 new_image->range = range;
223 new_image->input_context = last_input_context;
224 increment_input_image_count (count);
225 }
228 void output_push_context (void)
229 {
230 output_context_t *new_output_context;
232 new_output_context = malloc (sizeof (output_context_t));
233 if (! new_output_context)
234 {
235 fprintf (stderr, "failed to malloc an output context\n");
236 return;
237 }
239 if (last_output_context)
240 {
241 memcpy (new_output_context, last_output_context, sizeof (output_context_t));
242 new_output_context->page_count = 0;
243 new_output_context->first_bookmark = NULL;
244 new_output_context->last_bookmark = NULL;
245 }
246 else
247 {
248 memset (new_output_context, 0, sizeof (output_context_t));
249 first_output_context = new_output_context;
250 }
252 new_output_context->parent = last_output_context;
253 last_output_context = new_output_context;
254 };
256 void output_pop_context (void)
257 {
258 if (! last_output_context)
259 {
260 fprintf (stderr, "failed to pop an output context\n");
261 return;
262 }
264 last_output_context = last_output_context->parent;
265 };
267 static void output_clone (void)
268 {
269 output_context_t *new_output_context;
271 if (! last_output_context->page_count)
272 return;
274 new_output_context = malloc (sizeof (output_context_t));
275 if (! new_output_context)
276 {
277 fprintf (stderr, "failed to malloc an output context\n");
278 return;
279 }
281 memcpy (new_output_context, last_output_context, sizeof (output_context_t));
282 new_output_context->page_count = 0;
283 last_output_context->next = new_output_context;
284 }
286 void output_set_file (char *name)
287 {
288 output_clone ();
289 last_output_context->output_file = name;
290 last_output_context->file_attributes.author = NULL;
291 last_output_context->file_attributes.creator = NULL;
292 last_output_context->file_attributes.title = NULL;
293 last_output_context->file_attributes.subject = NULL;
294 last_output_context->file_attributes.keywords = NULL;
295 };
297 void output_set_author (char *author)
298 {
299 last_output_context->file_attributes.author = author;
300 }
302 void output_set_creator (char *creator)
303 {
304 last_output_context->file_attributes.creator = creator;
305 }
307 void output_set_title (char *title)
308 {
309 last_output_context->file_attributes.title = title;
310 }
312 void output_set_subject (char *subject)
313 {
314 last_output_context->file_attributes.subject = subject;
315 }
317 void output_set_keywords (char *keywords)
318 {
319 last_output_context->file_attributes.keywords = keywords;
320 }
322 void output_set_bookmark (char *name)
323 {
324 bookmark_t *new_bookmark;
326 /* As the language is defined (parser.y), a bookmark can only appear
327 at the beginning of a context! */
328 if (last_output_context->page_count)
329 {
330 fprintf (stderr, "internal error, bookmark not at beginning of context\n");
331 exit (2);
332 }
334 new_bookmark = calloc (1, sizeof (bookmark_t));
335 if (! new_bookmark)
336 {
337 fprintf (stderr, "failed to calloc a bookmark\n");
338 return;
339 }
341 new_bookmark->level = bookmark_level;
342 new_bookmark->name = name;
343 if (last_output_context->first_bookmark)
344 last_output_context->last_bookmark->next = new_bookmark;
345 else
346 last_output_context->first_bookmark = new_bookmark;
347 last_output_context->last_bookmark = new_bookmark;
348 }
350 void output_set_page_label (page_label_t label)
351 {
352 output_clone ();
353 last_output_context->has_page_label = 1;
354 last_output_context->page_label = label;
355 }
357 static void increment_output_page_count (int count)
358 {
359 output_context_t *context;
361 for (context = last_output_context; context; context = context->parent)
362 context->page_count += count;
363 }
366 void output_pages (range_t range)
367 {
368 output_page_t *new_page;
369 output_context_t *context;
370 int count = ((range.last - range.first) + 1);
372 #ifdef SEMANTIC_DEBUG
373 if (range.first == range.last)
374 SDBG(("page %d\n", range.first));
375 else
376 SDBG(("pages %d..%d\n", range.first, range.last));
377 #endif /* SEMANTIC_DEBUG */
379 new_page = calloc (1, sizeof (output_page_t));
380 if (! new_page)
381 {
382 fprintf (stderr, "failed to malloc an output page struct\n");
383 return;
384 }
385 if (first_output_page)
386 {
387 last_output_page->next = new_page;
388 last_output_page = new_page;
389 }
390 else
391 {
392 first_output_page = last_output_page = new_page;
393 }
394 new_page->range = range;
395 new_page->output_context = last_output_context;
397 /* transfer bookmarks from context(s) to page */
398 for (context = last_output_context; context; context = context->parent)
399 if (context->first_bookmark)
400 {
401 context->last_bookmark->next = new_page->bookmark_list;
402 new_page->bookmark_list = context->first_bookmark;
403 context->first_bookmark = NULL;
404 context->last_bookmark = NULL;
405 }
407 increment_output_page_count (count);
408 }
411 void yyerror (char *s)
412 {
413 fprintf (stderr, "%d: %s\n", line, s);
414 }
417 static char *get_input_file (input_context_t *context)
418 {
419 for (; context; context = context->parent)
420 if (context->input_file)
421 return (context->input_file);
422 fprintf (stderr, "no input file name found\n");
423 exit (2);
424 }
426 static int get_input_rotation (input_context_t *context, input_modifier_type_t type)
427 {
428 for (; context; context = context->parent)
429 {
430 if (context->modifiers [type].has_rotation)
431 return (context->modifiers [type].rotation);
432 if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
433 return (context->modifiers [INPUT_MODIFIER_ALL].rotation);
434 }
435 return (0); /* default */
436 }
438 static char *get_output_file (output_context_t *context)
439 {
440 for (; context; context = context->parent)
441 if (context->output_file)
442 return (context->output_file);
443 fprintf (stderr, "no output file found\n");
444 exit (2);
445 }
447 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
448 {
449 for (; context; context = context->parent)
450 if (context->output_file)
451 return (& context->file_attributes);
452 fprintf (stderr, "no output file found\n");
453 exit (2);
454 }
456 static page_label_t *get_output_page_label (output_context_t *context)
457 {
458 for (; context; context = context->parent)
459 if (context->has_page_label)
460 return (& context->page_label);
461 return (NULL); /* default */
462 }
465 #ifdef SEMANTIC_DEBUG
466 void dump_input_tree (void)
467 {
468 input_image_t *image;
469 int i;
471 printf ("input images:\n");
472 for (image = first_input_image; image; image = image->next)
473 for (i = image->range.first; i <= image->range.last; i++)
474 {
475 input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
476 printf ("file '%s' image %d, rotation %d\n",
477 get_input_file (image->input_context),
478 i,
479 get_input_rotation (image->input_context, parity));
480 }
481 }
483 void dump_output_tree (void)
484 {
485 int i;
486 output_page_t *page;
487 bookmark_t *bookmark;
489 printf ("output pages:\n");
490 for (page = first_output_page; page; page = page->next)
491 {
492 if (page->bookmark_list)
493 {
494 for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
495 printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
496 }
497 for (i = page->range.first; i <= page->range.last; i++)
498 {
499 page_label_t *label = get_output_page_label (page->output_context);
500 printf ("file \"%s\" ", get_output_file (page->output_context));
501 if (label)
502 {
503 printf ("label ");
504 if (label->prefix)
505 printf ("\"%s\" ", label->prefix);
506 if (label->style)
507 printf ("'%c' ", label->style);
508 }
509 printf ("page %d\n", i);
510 }
511 }
512 }
513 #endif /* SEMANTIC_DEBUG */
516 static inline int range_count (range_t range)
517 {
518 return ((range.last - range.first) + 1);
519 }
522 boolean parse_spec_file (char *fn)
523 {
524 boolean result = 0;
526 yyin = fopen (fn, "r");
527 if (! yyin)
528 {
529 fprintf (stderr, "can't open spec file '%s'\n", fn);
530 goto fail;
531 }
533 line = 1;
535 input_push_context (); /* create root input context */
536 input_push_context (); /* create inital input context */
538 output_push_context (); /* create root output context */
539 output_push_context (); /* create initial output context */
541 yyparse ();
543 if (first_input_context->image_count != first_output_context->page_count)
544 {
545 fprintf (stderr, "input image count %d != output page count %d\n",
546 first_input_context->image_count,
547 first_output_context->page_count);
548 goto fail;
549 }
551 fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
553 result = 1;
555 #ifdef SEMANTIC_DEBUG
556 dump_input_tree ();
557 dump_output_tree ();
558 #endif /* SEMANTIC_DEBUG */
560 fail:
561 if (yyin)
562 fclose (yyin);
564 return (result);
565 }
568 boolean process_specs (void)
569 {
570 input_image_t *image = NULL;
571 output_page_t *page = NULL;
572 int i = 0;
573 int p = 0;
574 int page_index = 0;
575 input_attributes_t input_attributes;
576 input_modifier_type_t parity;
577 page_label_t *page_label;
579 for (;;)
580 {
581 if ((! image) || (i >= range_count (image->range)))
582 {
583 if (image)
584 image = image->next;
585 else
586 image = first_input_image;
587 if (! image)
588 return (0);
589 i = 0;
590 if (! open_tiff_input_file (get_input_file (image->input_context)))
591 return (0);
592 }
594 if ((! page) || (p >= range_count (page->range)))
595 {
596 if (page)
597 page = page->next;
598 else
599 page = first_output_page;
600 p = 0;
601 if (! open_pdf_output_file (get_output_file (page->output_context),
602 get_output_file_attributes (page->output_context)))
603 return (0);
604 page_label = get_output_page_label (page->output_context);
605 process_page_numbers (page_index,
606 range_count (page->range),
607 page->range.first,
608 page_label);
609 }
611 parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
613 memset (& input_attributes, 0, sizeof (input_attributes));
614 input_attributes.rotation = get_input_rotation (image->input_context,
615 parity);;
617 process_page (image->range.first + i,
618 input_attributes,
619 page->bookmark_list);
620 i++;
621 p++;
622 page_index++;
623 }
625 return (1);
626 }