semantics.c

Tue, 21 Jan 2003 18:30:49 +0000

author
eric
date
Tue, 21 Jan 2003 18:30:49 +0000
changeset 49
be20d7e8466f
parent 48
3d0be1c1c1b2
child 55
43a9b9f27403
permissions
-rw-r--r--

added command-line mode

     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.16 2003/01/21 10:30:49 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 */
    26 #include <stdbool.h>
    27 #include <stdint.h>
    28 #include <stdlib.h>
    29 #include <string.h>
    30 #include <stdio.h>
    32 #include "semantics.h"
    33 #include "parser.tab.h"
    34 #include "t2p.h"
    37 typedef struct
    38 {
    39   bool has_page_size;
    40   page_size_t page_size;
    42   bool has_rotation;
    43   int rotation;
    45   bool has_crop;
    46   crop_t crop;
    47 } input_modifiers_t;
    50 typedef struct input_context_t
    51 {
    52   struct input_context_t *parent;
    53   struct input_context_t *next;
    55   int image_count;  /* how many pages reference this context,
    56 		      including those from subcontexts */
    58   char *input_file;
    60   input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
    61 } input_context_t;
    64 typedef struct input_image_t
    65 {
    66   struct input_image_t *next;
    67   input_context_t *input_context;
    68   range_t range;
    69 } input_image_t;
    72 typedef struct output_context_t
    73 {
    74   struct output_context_t *parent;
    75   struct output_context_t *next;
    77   int page_count;  /* how many pages reference this context,
    78 		      including those from subcontexts */
    80   char *output_file;
    81   pdf_file_attributes_t file_attributes;
    83   bookmark_t *first_bookmark;
    84   bookmark_t *last_bookmark;
    86   bool has_page_label;
    87   page_label_t page_label;
    88 } output_context_t;
    91 typedef struct output_page_t
    92 {
    93   struct output_page_t *next;
    94   output_context_t *output_context;
    95   range_t range;
    96   bookmark_t *bookmark_list;
    97 } output_page_t;
   100 #undef SEMANTIC_DEBUG
   102 #ifdef SEMANTIC_DEBUG
   103 #define SDBG(x) printf x
   104 #else
   105 #define SDBG(x)
   106 #endif
   109 FILE *yyin;
   110 int line;  /* line number in spec file */
   112 int bookmark_level;
   114 input_context_t *first_input_context;
   115 input_context_t *last_input_context;
   117 input_modifier_type_t current_modifier_context;
   119 input_image_t *first_input_image;
   120 input_image_t *last_input_image;
   122 output_context_t *first_output_context;
   123 output_context_t *last_output_context;
   125 output_page_t *first_output_page;
   126 output_page_t *last_output_page;
   129 void input_push_context (void)
   130 {
   131   input_context_t *new_input_context;
   133   new_input_context = malloc (sizeof (input_context_t));
   134   if (! new_input_context)
   135     {
   136       fprintf (stderr, "failed to malloc an input context\n");
   137       return;
   138     }
   140   if (last_input_context)
   141     {
   142       memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   143       new_input_context->image_count = 0;
   144     }
   145   else
   146     {
   147       memset (new_input_context, 0, sizeof (input_context_t));
   148       first_input_context = new_input_context;
   149     }
   151   new_input_context->parent = last_input_context;
   152   last_input_context = new_input_context;
   153 };
   155 void input_pop_context (void)
   156 {
   157   if (! last_input_context)
   158     {
   159       fprintf (stderr, "failed to pop an input context\n");
   160       return;
   161     }
   163   last_input_context = last_input_context->parent;
   164 };
   166 void input_set_modifier_context (input_modifier_type_t type)
   167 {
   168   current_modifier_context = type;
   169 #ifdef SEMANTIC_DEBUG
   170   SDBG(("modifier type "));
   171   switch (type)
   172     {
   173     case INPUT_MODIFIER_ALL: SDBG(("all")); break;
   174     case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
   175     case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
   176     default: SDBG(("unknown %d", type));
   177     }
   178   SDBG(("\n"));
   179 #endif /* SEMANTIC_DEBUG */
   180 }
   182 static void input_clone (void)
   183 {
   184   input_context_t *new_input_context;
   186   if (! last_input_context->image_count)
   187     return;
   189   new_input_context = malloc (sizeof (input_context_t));
   190   if (! new_input_context)
   191     {
   192       fprintf (stderr, "failed to malloc an input context\n");
   193       return;
   194     }
   196   memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   197   new_input_context->image_count = 0;
   198   last_input_context->next = new_input_context;
   199   last_input_context = new_input_context;
   200 }
   202 void input_set_file (char *name)
   203 {
   204   input_clone ();
   205   last_input_context->input_file = name;
   206 };
   208 void input_set_rotation (int rotation)
   209 {
   210   last_input_context->modifiers [current_modifier_context].has_rotation = 1;
   211   last_input_context->modifiers [current_modifier_context].rotation = rotation;
   212   SDBG(("rotation %d\n", rotation));
   213 }
   215 void input_set_page_size (page_size_t size)
   216 {
   217   last_input_context->modifiers [current_modifier_context].has_page_size = 1;
   218   last_input_context->modifiers [current_modifier_context].page_size = size;
   219   SDBG(("page size %f, %f\n", size.width, size.height));
   220 }
   222 static void increment_input_image_count (int count)
   223 {
   224   input_context_t *context;
   226   for (context = last_input_context; context; context = context->parent)
   227     context->image_count += count;
   228 }
   230 void input_images (range_t range)
   231 {
   232   input_image_t *new_image;
   233   int count = ((range.last - range.first) + 1);
   235 #ifdef SEMANTIC_DEBUG
   236   if (range.first == range.last)
   237     SDBG(("image %d\n", range.first));
   238   else
   239     SDBG(("images %d..%d\n", range.first, range.last));
   240 #endif /* SEMANTIC_DEBUG */
   242   new_image = calloc (1, sizeof (input_image_t));
   243   if (! new_image)
   244     {
   245       fprintf (stderr, "failed to malloc an input image struct\n");
   246       return;
   247     }
   248   if (first_input_image)
   249     {
   250       last_input_image->next = new_image;
   251       last_input_image = new_image;
   252     }
   253   else
   254     {
   255       first_input_image = last_input_image = new_image;
   256     }
   257   new_image->range = range;
   258   new_image->input_context = last_input_context;
   259   increment_input_image_count (count);
   260 }
   263 void output_push_context (void)
   264 {
   265   output_context_t *new_output_context;
   267   new_output_context = malloc (sizeof (output_context_t));
   268   if (! new_output_context)
   269     {
   270       fprintf (stderr, "failed to malloc an output context\n");
   271       return;
   272     }
   274   if (last_output_context)
   275     {
   276       memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   277       new_output_context->page_count = 0;
   278       new_output_context->first_bookmark = NULL;
   279       new_output_context->last_bookmark = NULL;
   280     }
   281   else
   282     {
   283       memset (new_output_context, 0, sizeof (output_context_t));
   284       first_output_context = new_output_context;
   285     }
   287   new_output_context->parent = last_output_context;
   288   last_output_context = new_output_context;
   289 };
   291 void output_pop_context (void)
   292 {
   293   if (! last_output_context)
   294     {
   295       fprintf (stderr, "failed to pop an output context\n");
   296       return;
   297     }
   299   last_output_context = last_output_context->parent;
   300 };
   302 static void output_clone (void)
   303 {
   304   output_context_t *new_output_context;
   306   if (! last_output_context->page_count)
   307     return;
   309   new_output_context = malloc (sizeof (output_context_t));
   310   if (! new_output_context)
   311     {
   312       fprintf (stderr, "failed to malloc an output context\n");
   313       return;
   314     }
   316   memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   317   new_output_context->page_count = 0;
   318   last_output_context->next = new_output_context;
   319 }
   321 void output_set_file (char *name)
   322 {
   323   output_clone ();
   324   last_output_context->output_file = name;
   325   last_output_context->file_attributes.author = NULL;
   326   last_output_context->file_attributes.creator = NULL;
   327   last_output_context->file_attributes.title = NULL;
   328   last_output_context->file_attributes.subject = NULL;
   329   last_output_context->file_attributes.keywords = NULL;
   330 };
   332 void output_set_author (char *author)
   333 {
   334   last_output_context->file_attributes.author = author;
   335 }
   337 void output_set_creator (char *creator)
   338 {
   339   last_output_context->file_attributes.creator = creator;
   340 }
   342 void output_set_title (char *title)
   343 {
   344   last_output_context->file_attributes.title = title;
   345 }
   347 void output_set_subject (char *subject)
   348 {
   349   last_output_context->file_attributes.subject = subject;
   350 }
   352 void output_set_keywords (char *keywords)
   353 {
   354   last_output_context->file_attributes.keywords = keywords;
   355 }
   357 void output_set_bookmark (char *name)
   358 {
   359   bookmark_t *new_bookmark;
   361   /* As the language is defined (parser.y), a bookmark can only appear
   362      at the beginning of a context! */
   363   if (last_output_context->page_count)
   364     {
   365       fprintf (stderr, "internal error, bookmark not at beginning of context\n");
   366       exit (2);
   367     }
   369   new_bookmark = calloc (1, sizeof (bookmark_t));
   370   if (! new_bookmark)
   371     {
   372       fprintf (stderr, "failed to calloc a bookmark\n");
   373       return;
   374     }
   376   new_bookmark->level = bookmark_level;
   377   new_bookmark->name = name;
   378   if (last_output_context->first_bookmark)
   379     last_output_context->last_bookmark->next = new_bookmark;
   380   else
   381     last_output_context->first_bookmark = new_bookmark;
   382   last_output_context->last_bookmark = new_bookmark;
   383 }
   385 void output_set_page_label (page_label_t label)
   386 {
   387   output_clone ();
   388   last_output_context->has_page_label = 1;
   389   last_output_context->page_label = label;
   390 }
   392 static void increment_output_page_count (int count)
   393 {
   394   output_context_t *context;
   396   for (context = last_output_context; context; context = context->parent)
   397     context->page_count += count;
   398 }
   401 void output_pages (range_t range)
   402 {
   403   output_page_t *new_page;
   404   output_context_t *context;
   405   int count = ((range.last - range.first) + 1);
   407 #ifdef SEMANTIC_DEBUG
   408   if (range.first == range.last)
   409     SDBG(("page %d\n", range.first));
   410   else
   411     SDBG(("pages %d..%d\n", range.first, range.last));
   412 #endif /* SEMANTIC_DEBUG */
   414   new_page = calloc (1, sizeof (output_page_t));
   415   if (! new_page)
   416     {
   417       fprintf (stderr, "failed to malloc an output page struct\n");
   418       return;
   419     }
   420   if (first_output_page)
   421     {
   422       last_output_page->next = new_page;
   423       last_output_page = new_page;
   424     }
   425   else
   426     {
   427       first_output_page = last_output_page = new_page;
   428     }
   429   new_page->range = range;
   430   new_page->output_context = last_output_context;
   432   /* transfer bookmarks from context(s) to page */
   433   for (context = last_output_context; context; context = context->parent)
   434     if (context->first_bookmark)
   435       {
   436 	context->last_bookmark->next = new_page->bookmark_list;
   437 	new_page->bookmark_list = context->first_bookmark;
   438 	context->first_bookmark = NULL;
   439 	context->last_bookmark = NULL;
   440       }
   442   increment_output_page_count (count);
   443 }
   446 void yyerror (char *s)
   447 {
   448   fprintf (stderr, "%d: %s\n", line, s);
   449 }
   452 static char *get_input_file (input_context_t *context)
   453 {
   454   for (; context; context = context->parent)
   455     if (context->input_file)
   456       return (context->input_file);
   457   fprintf (stderr, "no input file name found\n");
   458   exit (2);
   459 }
   461 static bool get_input_rotation (input_context_t *context,
   462 				input_modifier_type_t type,
   463 				int *rotation)
   464 {
   465   for (; context; context = context->parent)
   466     {
   467       if (context->modifiers [type].has_rotation)
   468 	{
   469 	  * rotation = context->modifiers [type].rotation;
   470 	  return (1);
   471 	}
   472       if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
   473 	{
   474 	  * rotation = context->modifiers [INPUT_MODIFIER_ALL].rotation;
   475 	  return (1);
   476 	}
   477     }
   478   return (0);  /* default */
   479 }
   481 static bool get_input_page_size (input_context_t *context,
   482 				 input_modifier_type_t type,
   483 				 page_size_t *page_size)
   484 {
   485   for (; context; context = context->parent)
   486     {
   487       if (context->modifiers [type].has_page_size)
   488 	{
   489 	  * page_size = context->modifiers [type].page_size;
   490 	  return (1);
   491 	}
   492       if (context->modifiers [INPUT_MODIFIER_ALL].has_page_size)
   493 	{
   494 	  * page_size = context->modifiers [INPUT_MODIFIER_ALL].page_size;
   495 	  return (1);
   496 	}
   497     }
   498   return (0);  /* default */
   499 }
   501 static char *get_output_file (output_context_t *context)
   502 {
   503   for (; context; context = context->parent)
   504     if (context->output_file)
   505       return (context->output_file);
   506   fprintf (stderr, "no output file found\n");
   507   exit (2);
   508 }
   510 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
   511 {
   512   for (; context; context = context->parent)
   513     if (context->output_file)
   514       return (& context->file_attributes);
   515   fprintf (stderr, "no output file found\n");
   516   exit (2);
   517 }
   519 static page_label_t *get_output_page_label (output_context_t *context)
   520 {
   521   for (; context; context = context->parent)
   522     if (context->has_page_label)
   523       return (& context->page_label);
   524   return (NULL);  /* default */
   525 }
   528 #ifdef SEMANTIC_DEBUG
   529 void dump_input_tree (void)
   530 {
   531   input_image_t *image;
   532   int i;
   534   printf ("input images:\n");
   535   for (image = first_input_image; image; image = image->next)
   536     for (i = image->range.first; i <= image->range.last; i++)
   537       {
   538 	input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   539 	bool has_rotation, has_page_size;
   540 	int rotation;
   541 	page_size_t page_size;
   543 	has_rotation = get_input_rotation (image->input_context,
   544 					   parity,
   545 					   & rotation);
   546 	has_page_size = get_input_page_size (image->input_context,
   547 					     parity,
   548 					     & page_size);
   549 	printf ("file '%s' image %d",
   550 	        get_input_file (image->input_context),
   551 		i);
   552 	if (has_rotation)
   553 	  printf (" rotation %d", rotation);
   554 	if (has_page_size)
   555 	  printf (" size %f, %f", page_size.width, page_size.height);
   556 	printf ("\n");
   557 	printf ("context: %08x\n", image->input_context);
   558       }
   559 }
   561 void dump_output_tree (void)
   562 {
   563   int i;
   564   output_page_t *page;
   565   bookmark_t *bookmark;
   567   printf ("output pages:\n");
   568   for (page = first_output_page; page; page = page->next)
   569     {
   570       if (page->bookmark_list)
   571 	{
   572 	  for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
   573 	    printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
   574 	}
   575       for (i = page->range.first; i <= page->range.last; i++)
   576 	{
   577 	  page_label_t *label = get_output_page_label (page->output_context);
   578 	  printf ("file \"%s\" ", get_output_file (page->output_context));
   579 	  if (label)
   580 	    {
   581 	      printf ("label ");
   582 	      if (label->prefix)
   583 		printf ("\"%s\" ", label->prefix);
   584 	      if (label->style)
   585 		printf ("'%c' ", label->style);
   586 	    }
   587 	  printf ("page %d\n", i);
   588 	}
   589     }
   590 }
   591 #endif /* SEMANTIC_DEBUG */
   594 static inline int range_count (range_t range)
   595 {
   596   return ((range.last - range.first) + 1);
   597 }
   600 bool parse_spec_file (char *fn)
   601 {
   602   bool result = 0;
   604   yyin = fopen (fn, "r");
   605   if (! yyin)
   606     {
   607       fprintf (stderr, "can't open spec file '%s'\n", fn);
   608       goto fail;
   609     }
   611   line = 1;
   613   input_push_context ();  /* create root input context */
   614   input_push_context ();  /* create inital input context */
   616   output_push_context ();  /* create root output context */
   617   output_push_context ();  /* create initial output context */
   619   yyparse ();
   621   if (first_input_context->image_count != first_output_context->page_count)
   622     {
   623       fprintf (stderr, "input image count %d != output page count %d\n",
   624 	       first_input_context->image_count,
   625 	       first_output_context->page_count);
   626       goto fail;
   627     }
   629   fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
   631   result = 1;
   633 #ifdef SEMANTIC_DEBUG
   634   dump_input_tree ();
   635   dump_output_tree ();
   636 #endif /* SEMANTIC_DEBUG */
   638  fail:
   639   if (yyin)
   640     fclose (yyin);
   642   return (result);
   643 }
   646 bool process_specs (void)
   647 {
   648   input_image_t *image = NULL;
   649   output_page_t *page = NULL;
   650   int i = 0;
   651   int p = 0;
   652   int page_index = 0;
   653   input_attributes_t input_attributes;
   654   input_modifier_type_t parity;
   655   page_label_t *page_label;
   657   for (;;)
   658     {
   659       if ((! image) || (i >= range_count (image->range)))
   660 	{
   661 	  if (image)
   662 	    image = image->next;
   663 	  else
   664 	    image = first_input_image;
   665 	  if (! image)
   666 	    return (0);
   667 	  i = 0;
   668 	  if (! open_tiff_input_file (get_input_file (image->input_context)))
   669 	    return (0);
   670 	}
   672       if ((! page) || (p >= range_count (page->range)))
   673 	{
   674 	  if (page)
   675 	    page = page->next;
   676 	  else
   677 	    page = first_output_page;
   678 	  p = 0;
   679 	  if (! open_pdf_output_file (get_output_file (page->output_context),
   680 				      get_output_file_attributes (page->output_context)))
   681 	    return (0);
   682 	  page_label = get_output_page_label (page->output_context);
   683 	  process_page_numbers (page_index,
   684 				range_count (page->range),
   685 				page->range.first,
   686 				page_label);
   687 	}
   689       parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   691       memset (& input_attributes, 0, sizeof (input_attributes));
   693       input_attributes.rotation = 0;
   694       input_attributes.has_rotation = get_input_rotation (image->input_context,
   695 							  parity,
   696 							  & input_attributes.rotation);
   698       input_attributes.has_page_size = get_input_page_size (image->input_context,
   699 							    parity,
   700 							    & input_attributes.page_size);
   702       if (! process_page (image->range.first + i,
   703 			  input_attributes,
   704 			  page->bookmark_list))
   705 	return (0);
   706       i++;
   707       p++;
   708       page_index++;
   709     }
   711   return (1);
   712 }