semantics.c

Wed, 12 Mar 2003 10:59:09 +0000

author
eric
date
Wed, 12 Mar 2003 10:59:09 +0000
changeset 109
663da96ad2bc
parent 104
82cb954059c4
child 125
e2ef1c2f9eca
permissions
-rw-r--r--

changed word_type to word_t.

     1 /*
     2  * t2p: Create a PDF file from the contents of one or more TIFF
     3  *      bilevel image files.  The images in the resulting PDF file
     4  *      will be compressed using ITU-T T.6 (G4) fax encoding.
     5  *
     6  * Semantic routines for spec file parser
     7  * $Id: semantics.c,v 1.18 2003/03/12 00:38:04 eric Exp $
     8  * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
     9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License version 2 as
    12  * published by the Free Software Foundation.  Note that permission is
    13  * not granted to redistribute this program under the terms of any
    14  * other version of the General Public License.
    15  *
    16  * This program is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with this program; if not, write to the Free Software
    23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    24  */
    27 #include <stdbool.h>
    28 #include <stdint.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 #include <stdio.h>
    33 #include "semantics.h"
    34 #include "parser.tab.h"
    35 #include "t2p.h"
    38 typedef struct
    39 {
    40   bool has_page_size;
    41   page_size_t page_size;
    43   bool has_rotation;
    44   int rotation;
    46   bool has_crop;
    47   crop_t crop;
    48 } input_modifiers_t;
    51 typedef struct input_context_t
    52 {
    53   struct input_context_t *parent;
    54   struct input_context_t *next;
    56   int image_count;  /* how many pages reference this context,
    57 		      including those from subcontexts */
    59   char *input_file;
    61   input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
    62 } input_context_t;
    65 typedef struct input_image_t
    66 {
    67   struct input_image_t *next;
    68   input_context_t *input_context;
    69   range_t range;
    70 } input_image_t;
    73 typedef struct output_context_t
    74 {
    75   struct output_context_t *parent;
    76   struct output_context_t *next;
    78   int page_count;  /* how many pages reference this context,
    79 		      including those from subcontexts */
    81   char *output_file;
    82   pdf_file_attributes_t file_attributes;
    84   bookmark_t *first_bookmark;
    85   bookmark_t *last_bookmark;
    87   bool has_page_label;
    88   page_label_t page_label;
    89 } output_context_t;
    92 typedef struct output_page_t
    93 {
    94   struct output_page_t *next;
    95   output_context_t *output_context;
    96   range_t range;
    97   bookmark_t *bookmark_list;
    98 } output_page_t;
   101 #undef SEMANTIC_DEBUG
   103 #ifdef SEMANTIC_DEBUG
   104 #define SDBG(x) printf x
   105 #else
   106 #define SDBG(x)
   107 #endif
   110 FILE *yyin;
   111 int line;  /* line number in spec file */
   113 int bookmark_level;
   115 input_context_t *first_input_context;
   116 input_context_t *last_input_context;
   118 input_modifier_type_t current_modifier_context;
   120 input_image_t *first_input_image;
   121 input_image_t *last_input_image;
   123 output_context_t *first_output_context;
   124 output_context_t *last_output_context;
   126 output_page_t *first_output_page;
   127 output_page_t *last_output_page;
   130 void input_push_context (void)
   131 {
   132   input_context_t *new_input_context;
   134   new_input_context = malloc (sizeof (input_context_t));
   135   if (! new_input_context)
   136     {
   137       fprintf (stderr, "failed to malloc an input context\n");
   138       return;
   139     }
   141   if (last_input_context)
   142     {
   143       memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   144       new_input_context->image_count = 0;
   145     }
   146   else
   147     {
   148       memset (new_input_context, 0, sizeof (input_context_t));
   149       first_input_context = new_input_context;
   150     }
   152   new_input_context->parent = last_input_context;
   153   last_input_context = new_input_context;
   154 };
   156 void input_pop_context (void)
   157 {
   158   if (! last_input_context)
   159     {
   160       fprintf (stderr, "failed to pop an input context\n");
   161       return;
   162     }
   164   last_input_context = last_input_context->parent;
   165 };
   167 void input_set_modifier_context (input_modifier_type_t type)
   168 {
   169   current_modifier_context = type;
   170 #ifdef SEMANTIC_DEBUG
   171   SDBG(("modifier type "));
   172   switch (type)
   173     {
   174     case INPUT_MODIFIER_ALL: SDBG(("all")); break;
   175     case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
   176     case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
   177     default: SDBG(("unknown %d", type));
   178     }
   179   SDBG(("\n"));
   180 #endif /* SEMANTIC_DEBUG */
   181 }
   183 static void input_clone (void)
   184 {
   185   input_context_t *new_input_context;
   187   if (! last_input_context->image_count)
   188     return;
   190   new_input_context = malloc (sizeof (input_context_t));
   191   if (! new_input_context)
   192     {
   193       fprintf (stderr, "failed to malloc an input context\n");
   194       return;
   195     }
   197   memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   198   new_input_context->image_count = 0;
   199   last_input_context->next = new_input_context;
   200   last_input_context = new_input_context;
   201 }
   203 void input_set_file (char *name)
   204 {
   205   input_clone ();
   206   last_input_context->input_file = name;
   207 };
   209 void input_set_rotation (int rotation)
   210 {
   211   last_input_context->modifiers [current_modifier_context].has_rotation = 1;
   212   last_input_context->modifiers [current_modifier_context].rotation = rotation;
   213   SDBG(("rotation %d\n", rotation));
   214 }
   216 void input_set_page_size (page_size_t size)
   217 {
   218   last_input_context->modifiers [current_modifier_context].has_page_size = 1;
   219   last_input_context->modifiers [current_modifier_context].page_size = size;
   220   SDBG(("page size %f, %f\n", size.width, size.height));
   221 }
   223 static void increment_input_image_count (int count)
   224 {
   225   input_context_t *context;
   227   for (context = last_input_context; context; context = context->parent)
   228     context->image_count += count;
   229 }
   231 void input_images (range_t range)
   232 {
   233   input_image_t *new_image;
   234   int count = ((range.last - range.first) + 1);
   236 #ifdef SEMANTIC_DEBUG
   237   if (range.first == range.last)
   238     SDBG(("image %d\n", range.first));
   239   else
   240     SDBG(("images %d..%d\n", range.first, range.last));
   241 #endif /* SEMANTIC_DEBUG */
   243   new_image = calloc (1, sizeof (input_image_t));
   244   if (! new_image)
   245     {
   246       fprintf (stderr, "failed to malloc an input image struct\n");
   247       return;
   248     }
   249   if (first_input_image)
   250     {
   251       last_input_image->next = new_image;
   252       last_input_image = new_image;
   253     }
   254   else
   255     {
   256       first_input_image = last_input_image = new_image;
   257     }
   258   new_image->range = range;
   259   new_image->input_context = last_input_context;
   260   increment_input_image_count (count);
   261 }
   264 void output_push_context (void)
   265 {
   266   output_context_t *new_output_context;
   268   new_output_context = malloc (sizeof (output_context_t));
   269   if (! new_output_context)
   270     {
   271       fprintf (stderr, "failed to malloc an output context\n");
   272       return;
   273     }
   275   if (last_output_context)
   276     {
   277       memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   278       new_output_context->page_count = 0;
   279       new_output_context->first_bookmark = NULL;
   280       new_output_context->last_bookmark = NULL;
   281     }
   282   else
   283     {
   284       memset (new_output_context, 0, sizeof (output_context_t));
   285       first_output_context = new_output_context;
   286     }
   288   new_output_context->parent = last_output_context;
   289   last_output_context = new_output_context;
   290 };
   292 void output_pop_context (void)
   293 {
   294   if (! last_output_context)
   295     {
   296       fprintf (stderr, "failed to pop an output context\n");
   297       return;
   298     }
   300   last_output_context = last_output_context->parent;
   301 };
   303 static void output_clone (void)
   304 {
   305   output_context_t *new_output_context;
   307   if (! last_output_context->page_count)
   308     return;
   310   new_output_context = malloc (sizeof (output_context_t));
   311   if (! new_output_context)
   312     {
   313       fprintf (stderr, "failed to malloc an output context\n");
   314       return;
   315     }
   317   memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   318   new_output_context->page_count = 0;
   319   last_output_context->next = new_output_context;
   320 }
   322 void output_set_file (char *name)
   323 {
   324   output_clone ();
   325   last_output_context->output_file = name;
   326   last_output_context->file_attributes.author = NULL;
   327   last_output_context->file_attributes.creator = NULL;
   328   last_output_context->file_attributes.title = NULL;
   329   last_output_context->file_attributes.subject = NULL;
   330   last_output_context->file_attributes.keywords = NULL;
   331 };
   333 void output_set_author (char *author)
   334 {
   335   last_output_context->file_attributes.author = author;
   336 }
   338 void output_set_creator (char *creator)
   339 {
   340   last_output_context->file_attributes.creator = creator;
   341 }
   343 void output_set_title (char *title)
   344 {
   345   last_output_context->file_attributes.title = title;
   346 }
   348 void output_set_subject (char *subject)
   349 {
   350   last_output_context->file_attributes.subject = subject;
   351 }
   353 void output_set_keywords (char *keywords)
   354 {
   355   last_output_context->file_attributes.keywords = keywords;
   356 }
   358 void output_set_bookmark (char *name)
   359 {
   360   bookmark_t *new_bookmark;
   362   /* As the language is defined (parser.y), a bookmark can only appear
   363      at the beginning of a context! */
   364   if (last_output_context->page_count)
   365     {
   366       fprintf (stderr, "internal error, bookmark not at beginning of context\n");
   367       exit (2);
   368     }
   370   new_bookmark = calloc (1, sizeof (bookmark_t));
   371   if (! new_bookmark)
   372     {
   373       fprintf (stderr, "failed to calloc a bookmark\n");
   374       return;
   375     }
   377   new_bookmark->level = bookmark_level;
   378   new_bookmark->name = name;
   379   if (last_output_context->first_bookmark)
   380     last_output_context->last_bookmark->next = new_bookmark;
   381   else
   382     last_output_context->first_bookmark = new_bookmark;
   383   last_output_context->last_bookmark = new_bookmark;
   384 }
   386 void output_set_page_label (page_label_t label)
   387 {
   388   output_clone ();
   389   last_output_context->has_page_label = 1;
   390   last_output_context->page_label = label;
   391 }
   393 static void increment_output_page_count (int count)
   394 {
   395   output_context_t *context;
   397   for (context = last_output_context; context; context = context->parent)
   398     context->page_count += count;
   399 }
   402 void output_pages (range_t range)
   403 {
   404   output_page_t *new_page;
   405   output_context_t *context;
   406   int count = ((range.last - range.first) + 1);
   408 #ifdef SEMANTIC_DEBUG
   409   if (range.first == range.last)
   410     SDBG(("page %d\n", range.first));
   411   else
   412     SDBG(("pages %d..%d\n", range.first, range.last));
   413 #endif /* SEMANTIC_DEBUG */
   415   new_page = calloc (1, sizeof (output_page_t));
   416   if (! new_page)
   417     {
   418       fprintf (stderr, "failed to malloc an output page struct\n");
   419       return;
   420     }
   421   if (first_output_page)
   422     {
   423       last_output_page->next = new_page;
   424       last_output_page = new_page;
   425     }
   426   else
   427     {
   428       first_output_page = last_output_page = new_page;
   429     }
   430   new_page->range = range;
   431   new_page->output_context = last_output_context;
   433   /* transfer bookmarks from context(s) to page */
   434   for (context = last_output_context; context; context = context->parent)
   435     if (context->first_bookmark)
   436       {
   437 	context->last_bookmark->next = new_page->bookmark_list;
   438 	new_page->bookmark_list = context->first_bookmark;
   439 	context->first_bookmark = NULL;
   440 	context->last_bookmark = NULL;
   441       }
   443   increment_output_page_count (count);
   444 }
   447 void yyerror (char *s)
   448 {
   449   fprintf (stderr, "%d: %s\n", line, s);
   450 }
   453 static char *get_input_filename (input_context_t *context)
   454 {
   455   for (; context; context = context->parent)
   456     if (context->input_file)
   457       return (context->input_file);
   458   fprintf (stderr, "no input file name found\n");
   459   exit (2);
   460 }
   462 static bool get_input_rotation (input_context_t *context,
   463 				input_modifier_type_t type,
   464 				int *rotation)
   465 {
   466   for (; context; context = context->parent)
   467     {
   468       if (context->modifiers [type].has_rotation)
   469 	{
   470 	  * rotation = context->modifiers [type].rotation;
   471 	  return (1);
   472 	}
   473       if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
   474 	{
   475 	  * rotation = context->modifiers [INPUT_MODIFIER_ALL].rotation;
   476 	  return (1);
   477 	}
   478     }
   479   return (0);  /* default */
   480 }
   482 static bool get_input_page_size (input_context_t *context,
   483 				 input_modifier_type_t type,
   484 				 page_size_t *page_size)
   485 {
   486   for (; context; context = context->parent)
   487     {
   488       if (context->modifiers [type].has_page_size)
   489 	{
   490 	  * page_size = context->modifiers [type].page_size;
   491 	  return (1);
   492 	}
   493       if (context->modifiers [INPUT_MODIFIER_ALL].has_page_size)
   494 	{
   495 	  * page_size = context->modifiers [INPUT_MODIFIER_ALL].page_size;
   496 	  return (1);
   497 	}
   498     }
   499   return (0);  /* default */
   500 }
   502 static char *get_output_filename (output_context_t *context)
   503 {
   504   for (; context; context = context->parent)
   505     if (context->output_file)
   506       return (context->output_file);
   507   fprintf (stderr, "no output file found\n");
   508   exit (2);
   509 }
   511 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
   512 {
   513   for (; context; context = context->parent)
   514     if (context->output_file)
   515       return (& context->file_attributes);
   516   fprintf (stderr, "no output file found\n");
   517   exit (2);
   518 }
   520 static page_label_t *get_output_page_label (output_context_t *context)
   521 {
   522   for (; context; context = context->parent)
   523     if (context->has_page_label)
   524       return (& context->page_label);
   525   return (NULL);  /* default */
   526 }
   529 #ifdef SEMANTIC_DEBUG
   530 void dump_input_tree (void)
   531 {
   532   input_image_t *image;
   533   int i;
   535   printf ("input images:\n");
   536   for (image = first_input_image; image; image = image->next)
   537     for (i = image->range.first; i <= image->range.last; i++)
   538       {
   539 	input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   540 	bool has_rotation, has_page_size;
   541 	int rotation;
   542 	page_size_t page_size;
   544 	has_rotation = get_input_rotation (image->input_context,
   545 					   parity,
   546 					   & rotation);
   547 	has_page_size = get_input_page_size (image->input_context,
   548 					     parity,
   549 					     & page_size);
   550 	printf ("file '%s' image %d",
   551 	        get_input_filename (image->input_context),
   552 		i);
   553 	if (has_rotation)
   554 	  printf (" rotation %d", rotation);
   555 	if (has_page_size)
   556 	  printf (" size %f, %f", page_size.width, page_size.height);
   557 	printf ("\n");
   558 	printf ("context: %08x\n", image->input_context);
   559       }
   560 }
   562 void dump_output_tree (void)
   563 {
   564   int i;
   565   output_page_t *page;
   566   bookmark_t *bookmark;
   568   printf ("output pages:\n");
   569   for (page = first_output_page; page; page = page->next)
   570     {
   571       if (page->bookmark_list)
   572 	{
   573 	  for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
   574 	    printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
   575 	}
   576       for (i = page->range.first; i <= page->range.last; i++)
   577 	{
   578 	  page_label_t *label = get_output_page_label (page->output_context);
   579 	  printf ("file \"%s\" ", get_output_filename (page->output_context));
   580 	  if (label)
   581 	    {
   582 	      printf ("label ");
   583 	      if (label->prefix)
   584 		printf ("\"%s\" ", label->prefix);
   585 	      if (label->style)
   586 		printf ("'%c' ", label->style);
   587 	    }
   588 	  printf ("page %d\n", i);
   589 	}
   590     }
   591 }
   592 #endif /* SEMANTIC_DEBUG */
   595 static inline int range_count (range_t range)
   596 {
   597   return ((range.last - range.first) + 1);
   598 }
   601 bool parse_spec_file (char *fn)
   602 {
   603   bool result = 0;
   605   yyin = fopen (fn, "r");
   606   if (! yyin)
   607     {
   608       fprintf (stderr, "can't open spec file '%s'\n", fn);
   609       goto fail;
   610     }
   612   line = 1;
   614   input_push_context ();  /* create root input context */
   615   input_push_context ();  /* create inital input context */
   617   output_push_context ();  /* create root output context */
   618   output_push_context ();  /* create initial output context */
   620   yyparse ();
   622   if (first_input_context->image_count != first_output_context->page_count)
   623     {
   624       fprintf (stderr, "input image count %d != output page count %d\n",
   625 	       first_input_context->image_count,
   626 	       first_output_context->page_count);
   627       goto fail;
   628     }
   630   fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
   632   result = 1;
   634 #ifdef SEMANTIC_DEBUG
   635   dump_input_tree ();
   636   dump_output_tree ();
   637 #endif /* SEMANTIC_DEBUG */
   639  fail:
   640   if (yyin)
   641     fclose (yyin);
   643   return (result);
   644 }
   647 bool process_specs (void)
   648 {
   649   input_image_t *image = NULL;
   650   output_page_t *page = NULL;
   651   int i = 0;
   652   int p = 0;
   653   int page_index = 0;
   654   input_attributes_t input_attributes;
   655   input_modifier_type_t parity;
   656   page_label_t *page_label;
   658   for (;;)
   659     {
   660       if ((! image) || (i >= range_count (image->range)))
   661 	{
   662 	  char *input_fn;
   663 	  if (image)
   664 	    image = image->next;
   665 	  else
   666 	    image = first_input_image;
   667 	  if (! image)
   668 	    return (1);  /* done */
   669 	  i = 0;
   670 	  input_fn = get_input_filename (image->input_context);
   671 	  if (verbose)
   672 	    fprintf (stderr, "opening TIFF file '%s'\n", input_fn);
   673 	  if (! open_tiff_input_file (input_fn))
   674 	    {
   675 	      fprintf (stderr, "error opening TIFF file '%s'\n", input_fn);
   676 	      return (0);
   677 	    }
   678 	}
   680       if ((! page) || (p >= range_count (page->range)))
   681 	{
   682 	  char *output_fn;
   683 	  if (page)
   684 	    page = page->next;
   685 	  else
   686 	    page = first_output_page;
   687 	  p = 0;
   688 	  output_fn = get_output_filename (page->output_context);
   689 	  if (verbose)
   690 	    fprintf (stderr, "opening PDF file '%s'\n", output_fn);
   691 	  if (! open_pdf_output_file (output_fn,
   692 				      get_output_file_attributes (page->output_context)))
   693 	    {
   694 	      fprintf (stderr, "error opening PDF file '%s'\n", output_fn);
   695 	      return (0);
   696 	    }
   697 	  page_label = get_output_page_label (page->output_context);
   698 	  process_page_numbers (page_index,
   699 				range_count (page->range),
   700 				page->range.first,
   701 				page_label);
   702 	}
   704       parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   706       memset (& input_attributes, 0, sizeof (input_attributes));
   708       input_attributes.rotation = 0;
   709       input_attributes.has_rotation = get_input_rotation (image->input_context,
   710 							  parity,
   711 							  & input_attributes.rotation);
   713       input_attributes.has_page_size = get_input_page_size (image->input_context,
   714 							    parity,
   715 							    & input_attributes.page_size);
   717       if (verbose)
   718 	fprintf (stderr, "processing image %d\n", image->range.first + i);
   719       if (! process_page (image->range.first + i,
   720 			  input_attributes,
   721 			  page->bookmark_list))
   722 	{
   723 	  fprintf (stderr, "error processing image %d\n", image->range.first + i);
   724 	  return (0);
   725 	}
   726       i++;
   727       p++;
   728       page_index++;
   729     }
   730 }