diff --git a/Makefile b/Makefile index 5832125..ed6931f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # tiff2pdf: build a PDF file out of one or more TIFF Class F Group 4 files # Makefile -# $Id: Makefile,v 1.6 2001/12/29 20:16:46 eric Exp $ +# $Id: Makefile,v 1.7 2001/12/30 23:24:50 eric Exp $ # Copyright 2001 Eric Smith # # This program is free software; you can redistribute it and/or modify @@ -24,8 +24,8 @@ LDLIBS = -g -ltiff -lm -L/usr/local/lib/panda -lpanda -lpng YACC = bison YFLAGS = -d -v -SRCS = bitblt.c bitblt_test.c tiff2pdf.c -HDRS = type.h bitblt.h tiff2pdf.h +SRCS = bitblt.c bitblt_test.c tiff2pdf.c semantics.c +HDRS = type.h bitblt.h tiff2pdf.h semantics.h MISC = Makefile scanner.l parser.y TARGETS = tiff2pdf bitblt_test @@ -34,7 +34,7 @@ AUTO_SRCS = scanner.c parser.tab.c AUTO_HDRS = parser.tab.h AUTO_MISC = parser.output -tiff2pdf: tiff2pdf.o scanner.o parser.tab.o +tiff2pdf: tiff2pdf.o scanner.o semantics.o parser.tab.o bitblt_test: bitblt_test.o bitblt.o @@ -42,6 +42,12 @@ bitblt_test: bitblt_test.o bitblt.o clean: rm -f *.o *.d $(TARGETS) $(AUTO_SRCS) $(AUTO_HDRS) $(AUTO_MISC) +wc: + wc -l $(SRCS) $(HDRS) $(MISC) + +ls-lt: + ls -lt $(SRCS) $(HDRS) $(MISC) + %.tab.c %.tab.h %.output: %.y $(YACC) $(YFLAGS) $< diff --git a/parser.y b/parser.y index ef9d410..ec8d5bf 100644 --- a/parser.y +++ b/parser.y @@ -38,6 +38,7 @@ %token RESOLUTION %token INPUT +%token FORMAT %token PAGE %token PAGES %token BOOKMARK @@ -69,21 +70,21 @@ range: | INTEGER { $$.first = $1; $$.last = $1; } ; image_ranges: - range { input_images ($1.first, $1.last); } - | image_ranges ',' range { input_images ($3.first, $3.last); } ; + range { input_images ($1); } + | image_ranges ',' range { input_images ($3); } ; input_file_clause: FILE_KEYWORD STRING ';' { input_set_file ($2) } ; image_clause: - IMAGE INTEGER ';' { input_images ($2, $2); } ; + IMAGE INTEGER ';' { range_t range = { $2, $2 }; input_images (range); } ; images_clause: IMAGES image_ranges ';' ; rotate_clause: - ROTATE INTEGER ';' { input_set_rotation ($2) }; + ROTATE INTEGER ';' { input_set_rotation ($2) } ; unit: /* empty */ /* default to INCH */ { $$ = 25.4; } @@ -125,7 +126,7 @@ part_clause: ODD { input_set_modifier_context (INPUT_MODIFIER_ODD); } modifier_clause_list ';' { input_set_modifier_context (INPUT_MODIFIER_ALL); } - | EVEN { input_set_modifier_context (INPUT_MODIFIER_ODD); } + | EVEN { input_set_modifier_context (INPUT_MODIFIER_EVEN); } modifier_clause_list ';' { input_set_modifier_context (INPUT_MODIFIER_ALL); } ; @@ -150,24 +151,34 @@ input_statement: output_file_clause: FILE_KEYWORD STRING ';' { output_set_file ($2) } ; +format_clause: + FORMAT STRING ';' { output_set_page_number_format ($2) } ; + page_ranges: - range { output_pages ($1.first, $1.last); } - | page_ranges ',' range { output_pages ($3.first, $3.last); } ; + range { output_pages ($1); } + | page_ranges ',' range { output_pages ($3); } ; page_clause: - PAGE INTEGER ';' { output_pages ($2, $2); } - | PAGE STRING ',' INTEGER ';' { output_pages ($4, $4); } ; + PAGE INTEGER ';' { range_t range = { $2, $2 }; output_pages (range); } ; pages_clause: - PAGES page_ranges ';' - | PAGES STRING ',' page_ranges ';' ; + PAGES page_ranges ';' ; + +bookmark_name: + STRING { output_set_bookmark ($1); } ; + +bookmark_name_list: + bookmark_name + | bookmark_name_list ',' bookmark_name ; bookmark_clause: - BOOKMARK INTEGER ',' STRING ';' - | BOOKMARK STRING ';' ; + BOOKMARK { output_push_context (); } + bookmark_name_list + output_clause_list ';' { output_pop_context (); } ; output_clause: output_file_clause + | format_clause | page_clause | pages_clause | bookmark_clause | output_clause_list ; @@ -177,7 +188,8 @@ output_clauses: | output_clauses output_clause ; output_clause_list: - '{' output_clauses '}' ; + '{' { output_push_context (); } + output_clauses '}' { output_pop_context (); } ; output_statement: OUTPUT output_clauses ; diff --git a/scanner.l b/scanner.l index 1227f6e..c618ee7 100644 --- a/scanner.l +++ b/scanner.l @@ -1,5 +1,5 @@ /* -$Id: scanner.l,v 1.10 2001/12/30 09:09:08 eric Exp $ +$Id: scanner.l,v 1.11 2001/12/30 23:25:08 eric Exp $ */ %option case-insensitive @@ -54,6 +54,7 @@ cm { return (CM); } crop { return (CROP); } even { return (EVEN); } file { return (FILE_KEYWORD); } +format { return (FORMAT); } image { return (IMAGE); } images { return (IMAGES); } inch { return (INCH); } @@ -68,7 +69,7 @@ resolution { return (RESOLUTION) ; } rotate { return (ROTATE); } size { return (SIZE); } -\".*\" { +\"[^\n"]*\" { int len = strlen (yytext) - 2; yylval.string = malloc (len + 1); memcpy (yylval.string, yytext + 1, len); diff --git a/semantics.c b/semantics.c index 7660d7f..05289d2 100644 --- a/semantics.c +++ b/semantics.c @@ -19,13 +19,20 @@ FILE *yyin; int line; /* line number in spec file */ -int input_page_count; /* total input pages in spec */ -int output_page_count; /* total output pages in spec */ +input_context_t *first_input_context; +input_context_t *last_input_context; - -input_context_t *current_input_context; input_modifier_type_t current_modifier_context; +input_image_t *first_input_image; +input_image_t *last_input_image; + +output_context_t *first_output_context; +output_context_t *last_output_context; + +output_page_t *first_output_page; +output_page_t *last_output_page; + void input_push_context (void) { @@ -34,31 +41,34 @@ void input_push_context (void) new_input_context = malloc (sizeof (input_context_t)); if (! new_input_context) { - fprintf (stderr, "failed to calloc an input context\n"); + fprintf (stderr, "failed to malloc an input context\n"); return; } - if (current_input_context) + if (last_input_context) { - memcpy (new_input_context, current_input_context, sizeof (input_context_t)); - new_input_context->page_count = 0; + memcpy (new_input_context, last_input_context, sizeof (input_context_t)); + new_input_context->image_count = 0; } else - memset (new_input_context, 0, sizeof (input_context_t)); + { + memset (new_input_context, 0, sizeof (input_context_t)); + first_input_context = new_input_context; + } - new_input_context->parent_input_context = current_input_context; - current_input_context = new_input_context; + new_input_context->parent = last_input_context; + last_input_context = new_input_context; }; void input_pop_context (void) { - if (! current_input_context) + if (! last_input_context) { fprintf (stderr, "failed to pop an input context\n"); return; } - current_input_context = current_input_context->parent_input_context; + last_input_context = last_input_context->parent; }; void input_set_modifier_context (input_modifier_type_t type) @@ -77,46 +87,218 @@ void input_set_modifier_context (input_modifier_type_t type) #endif /* SEMANTIC_DEBUG */ } +void input_clone (void) +{ + input_context_t *new_input_context; + + if (! last_input_context->image_count) + return; + + new_input_context = malloc (sizeof (input_context_t)); + if (! new_input_context) + { + fprintf (stderr, "failed to malloc an input context\n"); + return; + } + + memcpy (new_input_context, last_input_context, sizeof (input_context_t)); + new_input_context->image_count = 0; + last_input_context->next = new_input_context; +} + void input_set_file (char *name) { + input_clone (); + last_input_context->input_file = name; }; void input_set_rotation (int rotation) { - current_input_context->modifiers [current_modifier_context].has_rotation = 1; - current_input_context->modifiers [current_modifier_context].rotation = rotation; + last_input_context->modifiers [current_modifier_context].has_rotation = 1; + last_input_context->modifiers [current_modifier_context].rotation = rotation; SDBG(("rotation %d\n", rotation)); } -void input_images (int first, int last) +void increment_input_image_count (int count) +{ + input_context_t *context; + + for (context = last_input_context; context; context = context->parent) + context->image_count += count; +} + +void input_images (range_t range) { - input_page_count += ((last - first) + 1); + input_image_t *new_image; + int count = ((range.last - range.first) + 1); + #ifdef SEMANTIC_DEBUG - if (first == last) - SDBG(("image %d\n", first)); + if (range.first == range.last) + SDBG(("image %d\n", range.first)); else - SDBG(("images %d..%d\n", first, last)); + SDBG(("images %d..%d\n", range.first, range.last)); #endif /* SEMANTIC_DEBUG */ + + new_image = calloc (1, sizeof (input_image_t)); + if (! new_image) + { + fprintf (stderr, "failed to malloc an input image struct\n"); + return; + } + if (first_input_image) + { + last_input_image->next = new_image; + last_input_image = new_image; + } + else + { + first_input_image = last_input_image = new_image; + } + new_image->range = range; + new_image->input_context = last_input_context; + increment_input_image_count (count); } void output_push_context (void) { + output_context_t *new_output_context; + + new_output_context = malloc (sizeof (output_context_t)); + if (! new_output_context) + { + fprintf (stderr, "failed to malloc an output context\n"); + return; + } + + if (last_output_context) + { + memcpy (new_output_context, last_output_context, sizeof (output_context_t)); + new_output_context->page_count = 0; + } + else + { + memset (new_output_context, 0, sizeof (output_context_t)); + first_output_context = new_output_context; + } + + new_output_context->parent = last_output_context; + last_output_context = new_output_context; +}; + +void output_pop_context (void) +{ + if (! last_output_context) + { + fprintf (stderr, "failed to pop an output context\n"); + return; + } + + last_output_context = last_output_context->parent; }; +void output_clone (void) +{ + output_context_t *new_output_context; + + if (! last_output_context->page_count) + return; + + new_output_context = malloc (sizeof (output_context_t)); + if (! new_output_context) + { + fprintf (stderr, "failed to malloc an output context\n"); + return; + } + + memcpy (new_output_context, last_output_context, sizeof (output_context_t)); + new_output_context->page_count = 0; + last_output_context->next = new_output_context; +} + void output_set_file (char *name) { + output_clone (); + last_output_context->output_file = name; }; -void output_pages (int first, int last) +void output_set_bookmark (char *name) +{ + bookmark_t *new_bookmark; + + /* As the language is defined (parser.y), a bookmark can only appear + at the beginning of a context! */ + if (last_output_context->page_count) + { + fprintf (stderr, "internal error, bookmark not at beginning of context\n"); + exit (2); + } + + new_bookmark = calloc (1, sizeof (bookmark_t)); + if (! new_bookmark) + { + fprintf (stderr, "failed to calloc a bookmark\n"); + return; + } + + new_bookmark->name = name; + if (last_output_context->first_bookmark) + last_output_context->last_bookmark->next = new_bookmark; + else + last_output_context->first_bookmark = new_bookmark; + last_output_context->last_bookmark = new_bookmark; +} + +void output_set_page_number_format (char *format) +{ + output_clone (); + last_output_context->page_number_format = format; +} + +void increment_output_page_count (int count) +{ + output_context_t *context; + + for (context = last_output_context; context; context = context->parent) + context->page_count += count; +} + +void output_pages (range_t range) { - output_page_count += ((last - first) + 1); + output_page_t *new_page; + int count = ((range.last - range.first) + 1); + #ifdef SEMANTIC_DEBUG - if (first == last) - SDBG(("page %d\n", first)); + if (range.first == range.last) + SDBG(("page %d\n", range.first)); else - SDBG(("pages %d..%d\n", first, last)); + SDBG(("pages %d..%d\n", range.first, range.last)); #endif /* SEMANTIC_DEBUG */ + + new_page = calloc (1, sizeof (output_page_t)); + if (! new_page) + { + fprintf (stderr, "failed to malloc an output page struct\n"); + return; + } + if (first_output_page) + { + last_output_page->next = new_page; + last_output_page = new_page; + } + else + { + first_output_page = last_output_page = new_page; + } + new_page->range = range; + new_page->output_context = last_output_context; + + /* transfer bookmarks from context to page */ + new_page->bookmark_list = last_output_context->first_bookmark; + last_output_context->first_bookmark = NULL; + last_output_context->last_bookmark = NULL; + + increment_output_page_count (count); } @@ -126,6 +308,88 @@ void yyerror (char *s) } +char *get_input_file (input_context_t *context) +{ + for (; context; context = context->parent) + if (context->input_file) + return (context->input_file); + fprintf (stderr, "no input file name found\n"); + exit (2); +} + +int get_input_rotation (input_context_t *context, input_modifier_type_t type) +{ + for (; context; context = context->parent) + { + if (context->modifiers [type].has_rotation) + return (context->modifiers [type].rotation); + if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation) + return (context->modifiers [INPUT_MODIFIER_ALL].rotation); + } + return (0); /* default */ +} + +char *get_output_file (output_context_t *context) +{ + for (; context; context = context->parent) + if (context->output_file) + return (context->output_file); + fprintf (stderr, "no output file name found\n"); + exit (2); +} + +char *get_output_page_number_format (output_context_t *context) +{ + for (; context; context = context->parent) + if (context->page_number_format) + return (context->page_number_format); + return (NULL); /* default */ +} + + +#ifdef SEMANTIC_DEBUG +void dump_input_tree (void) +{ + input_image_t *image; + int i; + + printf ("input images:\n"); + for (image = first_input_image; image; image = image->next) + for (i = image->range.first; i <= image->range.last; i++) + { + input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN; + printf ("file '%s' image %d, rotation %d\n", + get_input_file (image->input_context), + i, + get_input_rotation (image->input_context, parity)); + } +} + +void dump_output_tree (void) +{ + int i; + output_page_t *page; + bookmark_t *bookmark; + + printf ("output pages:\n"); + for (page = first_output_page; page; page = page->next) + { + if (page->bookmark_list) + { + for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next) + printf ("bookmark '%s' ", bookmark->name); + printf ("\n"); + } + for (i = page->range.first; i <= page->range.last; i++) + { + printf ("file '%s' ", get_output_file (page->output_context)); + printf ("format '%s' ", get_output_page_number_format (page->output_context)); + printf ("page %d\n", i); + } + } +} +#endif /* SEMANTIC_DEBUG */ + boolean parse_spec_file (char *fn) { boolean result = 0; @@ -139,22 +403,31 @@ boolean parse_spec_file (char *fn) line = 1; - input_push_context (); /* create initial input context */ + input_push_context (); /* create root input context */ + input_push_context (); /* create inital input context */ + + output_push_context (); /* create root output context */ output_push_context (); /* create initial output context */ yyparse (); - if (input_page_count != output_page_count) + if (first_input_context->image_count != first_output_context->page_count) { - fprintf (stderr, "input page count %d != output page count %d\n", - input_page_count, output_page_count); + fprintf (stderr, "input image count %d != output page count %d\n", + first_input_context->image_count, + first_output_context->page_count); goto fail; } - fprintf (stderr, "%d pages specified\n", input_page_count); + fprintf (stderr, "%d pages specified\n", first_input_context->image_count); result = 1; +#ifdef SEMANTIC_DEBUG + dump_input_tree (); + dump_output_tree (); +#endif /* SEMANTIC_DEBUG */ + fail: if (yyin) fclose (yyin); diff --git a/semantics.h b/semantics.h index c91c38e..e70e680 100644 --- a/semantics.h +++ b/semantics.h @@ -42,20 +42,58 @@ typedef enum typedef struct input_context_t { - struct input_context_t *parent_input_context; + struct input_context_t *parent; + struct input_context_t *next; - int page_count; /* how many pages reference this context, + int image_count; /* how many pages reference this context, including those from subcontexts */ + char *input_file; + input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT]; } input_context_t; -extern int line; /* line number in spec file */ +typedef struct input_image_t +{ + struct input_image_t *next; + input_context_t *input_context; + range_t range; +} input_image_t; + + +typedef struct bookmark_t +{ + struct bookmark_t *next; + char *name; +} bookmark_t; + + +typedef struct output_context_t +{ + struct output_context_t *parent; + struct output_context_t *next; + + int page_count; /* how many pages reference this context, + including those from subcontexts */ + + char *output_file; + bookmark_t *first_bookmark; + bookmark_t *last_bookmark; + char *page_number_format; +} output_context_t; -extern int input_page_count; /* total input pages in spec */ -extern int output_page_count; /* total output pages in spec */ +typedef struct output_page_t +{ + struct output_page_t *next; + output_context_t *output_context; + range_t range; + bookmark_t *bookmark_list; +} output_page_t; + + +extern int line; /* line number in spec file */ boolean parse_spec_file (char *fn); @@ -67,8 +105,10 @@ void input_pop_context (void); void input_set_modifier_context (input_modifier_type_t type); void input_set_file (char *name); void input_set_rotation (int rotation); -void input_images (int first, int last); +void input_images (range_t range); /* semantic routines for output statements */ void output_set_file (char *name); -void output_pages (int first, int last); +void output_set_bookmark (char *name); +void output_set_page_number_format (char *format); +void output_pages (range_t range);