tumble.c

Thu, 10 Apr 2003 09:02:12 +0000

author
eric
date
Thu, 10 Apr 2003 09:02:12 +0000
changeset 158
e5452e27f518
parent 157
160d624271cc
child 160
1f793b71ffff
permissions
-rw-r--r--

include tumble version in usage message.

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Main program
     5  * $Id: tumble.c,v 1.43 2003/04/10 01:02:12 eric Exp $
     6  * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdarg.h>
    26 #include <stdbool.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 #include <unistd.h>
    34 #include "semantics.h"
    35 #include "parser.tab.h"
    36 #include "tumble.h"
    37 #include "bitblt.h"
    38 #include "pdf.h"
    39 #include "tumble_input.h"
    42 #define MAX_INPUT_FILES 5000
    44 typedef struct output_file_t
    45 {
    46   struct output_file_t *next;
    47   char *name;
    48   pdf_file_handle pdf;
    49 } output_file_t;
    52 int verbose;
    55 output_file_t *output_files;
    56 output_file_t *out;
    59 char *progname;
    62 bool close_pdf_output_files (void);
    65 #define QMAKESTR(x) #x
    66 #define MAKESTR(x) QMAKESTR(x)
    69 void usage (void)
    70 {
    71   fprintf (stderr, "\n");
    72   fprintf (stderr, "tumble version " MAKESTR(TUMBLE_VERSION) " - Copyright 2001-2003 Eric Smith <eric@brouhaha.com>\n");
    73   fprintf (stderr, "http://tumble.brouhaha.com/\n");
    74   fprintf (stderr, "\n");
    75   fprintf (stderr, "usage:\n");
    76   fprintf (stderr, "    %s [options] -c <control.tum>\n", progname);
    77   fprintf (stderr, "    %s [options] <input.tif>... -o <output.pdf>\n", progname);
    78   fprintf (stderr, "options:\n");
    79   fprintf (stderr, "    -v        verbose\n");
    80   fprintf (stderr, "    -b <fmt>  create bookmarks\n");
    81   fprintf (stderr, "bookmark format:\n");
    82   fprintf (stderr, "    %%F  file name (sans suffix)\n");
    83   fprintf (stderr, "    %%p  page number\n");
    84 }
    87 /* generate fatal error message to stderr, doesn't return */
    88 void fatal (int ret, char *format, ...) __attribute__ ((noreturn));
    90 void fatal (int ret, char *format, ...)
    91 {
    92   va_list ap;
    94   fprintf (stderr, "fatal error");
    95   if (format)
    96     {
    97       fprintf (stderr, ": ");
    98       va_start (ap, format);
    99       vfprintf (stderr, format, ap);
   100       va_end (ap);
   101     }
   102   else
   103     fprintf (stderr, "\n");
   104   if (ret == 1)
   105     usage ();
   106   close_input_file ();
   107   close_pdf_output_files ();
   108   exit (ret);
   109 }
   112 bool close_pdf_output_files (void)
   113 {
   114   output_file_t *o, *n;
   116   for (o = output_files; o; o = n)
   117     {
   118       n = o->next;
   119       pdf_close (o->pdf, PDF_PAGE_MODE_USE_OUTLINES);
   120       free (o->name);
   121       free (o);
   122     }
   123   out = NULL;
   124   output_files = NULL;
   125   return (1);
   126 }
   128 bool open_pdf_output_file (char *name,
   129 			   pdf_file_attributes_t *attributes)
   130 {
   131   output_file_t *o;
   133   if (out && (strcmp (name, out->name) == 0))
   134     return (1);
   135   for (o = output_files; o; o = o->next)
   136     if (strcmp (name, o->name) == 0)
   137       {
   138 	out = o;
   139 	return (1);
   140       }
   141   o = calloc (1, sizeof (output_file_t));
   142   if (! o)
   143     {
   144       fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
   145       return (0);
   146    }
   148   o->name = strdup (name);
   149   if (! o->name)
   150     {
   151       fprintf (stderr, "can't strdup output filename '%s'\n", name);
   152       free (o);
   153       return (0);
   154     }
   156   o->pdf = pdf_create (name);
   157   if (! o->pdf)
   158     {
   159       fprintf (stderr, "can't open output file '%s'\n", name);
   160       free (o->name);
   161       free (o);
   162       return (0);
   163     }
   165   if (attributes->author)
   166     pdf_set_author (o->pdf, attributes->author);
   167   if (attributes->creator)
   168     pdf_set_creator (o->pdf, attributes->creator);
   169   if (attributes->title)
   170     pdf_set_title (o->pdf, attributes->title);
   171   if (attributes->subject)
   172     pdf_set_subject (o->pdf, attributes->subject);
   173   if (attributes->keywords)
   174     pdf_set_keywords (o->pdf, attributes->keywords);
   176   /* prepend new output file onto list */
   177   o->next = output_files;
   178   output_files = o;
   180   out = o;
   181   return (1);
   182 }
   185 #define MAX_BOOKMARK_LEVEL 20
   186 static pdf_bookmark_handle bookmark_vector [MAX_BOOKMARK_LEVEL + 1] = { NULL };
   189 bool process_page (int image,  /* range 1 .. n */
   190 		   input_attributes_t input_attributes,
   191 		   bookmark_t *bookmarks,
   192 		   page_label_t *page_label)
   193 {
   194   pdf_page_handle page;
   195   image_info_t image_info;
   197   if (! get_image_info (image, input_attributes, & image_info))
   198     return (0);
   200   page = pdf_new_page (out->pdf,
   201 		       image_info.width_points,
   202 		       image_info.height_points);
   204   if (! process_image (image, input_attributes, & image_info, page))
   205     return (0);
   207   while (bookmarks)
   208     {
   209       if (bookmarks->level <= MAX_BOOKMARK_LEVEL)
   210 	{
   211 	  pdf_bookmark_handle parent = bookmark_vector [bookmarks->level - 1];
   212 	  bookmark_vector [bookmarks->level] = pdf_new_bookmark (parent,
   213 								 bookmarks->name,
   214 								 0,
   215 								 page);
   216 	}
   217       else
   218 	{
   219 	  (void) pdf_new_bookmark (bookmark_vector [MAX_BOOKMARK_LEVEL],
   220 				   bookmarks->name,
   221 				   0,
   222 				   page);
   223 	}
   224       bookmarks = bookmarks->next;
   225     }
   227   if (page_label)
   228     pdf_new_page_label (out->pdf,
   229 			page_label->page_index,
   230 			page_label->base,
   231 			page_label->count,
   232 			page_label->style,
   233 			page_label->prefix);
   235   return (page != NULL);
   236 }
   239 #define MAX_BOOKMARK_NAME_LEN 500
   242 static int filename_length_without_suffix (char *in_fn)
   243 {
   244   char *p;
   245   int len = strlen (in_fn);
   247   p = strrchr (in_fn, '.');
   248   if (p && match_input_suffix (p))
   249     return (p - in_fn);
   250   return (len);
   251 }
   254 /* $$$ this function should ensure that it doesn't overflow the name string! */
   255 static void generate_bookmark_name (char *name,
   256 				    char *bookmark_fmt, 
   257 				    char *in_fn,
   258 				    int page)
   259 {
   260   bool meta = 0;
   261   int len;
   263   while (*bookmark_fmt)
   264     {
   265       if (meta)
   266 	{
   267 	  meta = 0;
   268 	  switch (*bookmark_fmt)
   269 	    {
   270 	    case '%':
   271 	      *(name++) = '%';
   272 	      break;
   273 	    case 'F':
   274 	      len = filename_length_without_suffix (in_fn);
   275 	      strncpy (name, in_fn, len);
   276 	      name += len;
   277 	      break;
   278 	    case 'p':
   279 	      sprintf (name, "%d", page);
   280 	      name += strlen (name);
   281 	      break;
   282 	    default:
   283 	      break;
   284 	    }
   285 	}
   286       else
   287 	switch (*bookmark_fmt)
   288 	  {
   289 	  case '%':
   290 	    meta = 1;
   291 	    break;
   292 	  default:
   293 	    *(name++) = *bookmark_fmt;
   294 	  }
   295       bookmark_fmt++;
   296     }
   297   *name = '\0';
   298 }
   301 void main_args (char *out_fn,
   302 		int inf_count,
   303 		char **in_fn,
   304 		char *bookmark_fmt)
   305 {
   306   int i, ip;
   307   input_attributes_t input_attributes;
   308   pdf_file_attributes_t output_attributes;
   309   bookmark_t bookmark;
   310   char bookmark_name [MAX_BOOKMARK_NAME_LEN];
   312   bookmark.next = NULL;
   313   bookmark.level = 1;
   314   bookmark.name = & bookmark_name [0];
   316   memset (& input_attributes, 0, sizeof (input_attributes));
   317   memset (& output_attributes, 0, sizeof (output_attributes));
   319   if (! open_pdf_output_file (out_fn, & output_attributes))
   320     fatal (3, "error opening output file \"%s\"\n", out_fn);
   321   for (i = 0; i < inf_count; i++)
   322     {
   323       if (! open_input_file (in_fn [i]))
   324 	fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
   325       for (ip = 1;; ip++)
   326 	{
   327 	  fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
   328 	  if (bookmark_fmt)
   329 	    generate_bookmark_name (& bookmark_name [0],
   330 				    bookmark_fmt, 
   331 				    in_fn [i],
   332 				    ip);
   333 	  if (! process_page (ip, input_attributes,
   334 			      bookmark_fmt ? & bookmark : NULL,
   335 			      NULL))
   336 	    fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
   337 	  if (last_input_page ())
   338 	    break;
   339 	}
   340       if (verbose)
   341 	fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
   342       if (! close_input_file ())
   343 	fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
   344     }
   345   if (! close_pdf_output_files ())
   346     fatal (3, "error closing output file \"%s\"\n", out_fn);
   347 }
   350 void main_control (char *control_fn)
   351 {
   352   if (! parse_control_file (control_fn))
   353     fatal (2, "error parsing control file\n");
   354   if (! process_controls ())
   355     fatal (3, "error processing control file\n");
   356 }
   359 int main (int argc, char *argv[])
   360 {
   361   char *control_fn = NULL;
   362   char *out_fn = NULL;
   363   char *bookmark_fmt = NULL;
   364   int inf_count = 0;
   365   char *in_fn [MAX_INPUT_FILES];
   367   progname = argv [0];
   369   pdf_init ();
   371   init_tiff_handler ();
   372   init_jpeg_handler ();
   373   init_pbm_handler ();
   375   while (--argc)
   376     {
   377       if (argv [1][0] == '-')
   378 	{
   379 	  if (strcmp (argv [1], "-v") == 0)
   380 	    verbose++;
   381 	  else if (strcmp (argv [1], "-o") == 0)
   382 	    {
   383 	      if (argc)
   384 		{
   385 		  argc--;
   386 		  argv++;
   387 		  out_fn = argv [1];
   388 		}
   389 	      else
   390 		fatal (1, "missing filename after \"-o\" option\n");
   391 	    }
   392 	  else if (strcmp (argv [1], "-c") == 0)
   393 	    {
   394 	      if (argc)
   395 		{
   396 		  argc--;
   397 		  argv++;
   398 		  control_fn = argv [1];
   399 		}
   400 	      else
   401 		fatal (1, "missing filename after \"-s\" option\n");
   402 	    }
   403 	  else if (strcmp (argv [1], "-b") == 0)
   404 	    {
   405 	      if (argc)
   406 		{
   407 		  argc--;
   408 		  argv++;
   409 		  bookmark_fmt = argv [1];
   410 		}
   411 	      else
   412 		fatal (1, "missing format string after \"-b\" option\n");
   413 	    }
   414 	  else
   415 	    fatal (1, "unrecognized option \"%s\"\n", argv [1]);
   416 	}
   417       else if (inf_count < MAX_INPUT_FILES)
   418 	in_fn [inf_count++] = argv [1];
   419       else
   420 	fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
   421       argv++;
   422     }
   424   if (! ((! out_fn) ^ (! control_fn)))
   425     fatal (1, "either a control file or an output file (but not both) must be specified\n");
   427   if (out_fn && ! inf_count)
   428     fatal (1, "no input files specified\n");
   430   if (control_fn && inf_count)
   431     fatal (1, "if control file is provided, input files can't be specified as arguments\n");
   433   if (control_fn)
   434     main_control (control_fn);
   435   else
   436     main_args (out_fn, inf_count, in_fn, bookmark_fmt);
   438   close_input_file ();
   439   close_pdf_output_files ();
   440   exit (0);
   441 }