]> git.sur5r.net Git - glabels/blob - barcode-0.98/main.c
Imported Upstream version 2.2.8
[glabels] / barcode-0.98 / main.c
1 /*
2  * main.c - a commandline frontend for the barcode library
3  *
4  * Copyright (c) 1999 Michele Comitini (mcm@glisco.it)
5  * Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
6  * Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
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 as published by
10  *   the Free Software Foundation; either version 2 of the License, or
11  *   (at your option) any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21  */
22         
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "cmdline.h"
29 #include "barcode.h"
30
31 #ifndef NO_LIBPAPER
32 #include <paper.h>
33 #endif
34
35 /*
36  * Most of this file deals with command line options, by exploiting
37  * the cmdline.[ch] engine to offer defaults via environment variables
38  * and handling functions for complex options.
39  *
40  * In order to offer a friendly interface (for those who feel the
41  * cmdline *is* friendly, like me), we have to convert names to enums...
42  */
43
44 struct {
45     char *name;
46     int type;
47 } encode_tab[] = {
48     {"ean",      BARCODE_EAN},
49     {"ean13",    BARCODE_EAN},
50     {"ean-13",   BARCODE_EAN},
51     {"ean8",     BARCODE_EAN},
52     {"ean-8",    BARCODE_EAN},
53     {"upc",      BARCODE_UPC},
54     {"upc-a",    BARCODE_UPC},
55     {"upc-e",    BARCODE_UPC},
56     {"isbn",     BARCODE_ISBN},
57     {"39",       BARCODE_39},
58     {"code39",   BARCODE_39},
59     {"128c",     BARCODE_128C},
60     {"code128c", BARCODE_128C},
61     {"128b",     BARCODE_128B},
62     {"code128b", BARCODE_128B},
63     {"128",      BARCODE_128},
64     {"code128",  BARCODE_128},
65     {"128raw",   BARCODE_128RAW},
66     {"i25",      BARCODE_I25},
67     {"interleaved 2 of 5", BARCODE_I25},
68     {"cbr",      BARCODE_CBR},
69     {"codabar",  BARCODE_CBR},
70     {"msi",     BARCODE_MSI},
71     {"pls",      BARCODE_PLS},
72     {"plessey",  BARCODE_PLS},
73     {"code93",   BARCODE_93},
74     {"93",       BARCODE_93},
75
76     {NULL, 0}
77 };
78
79 /*
80  * Get encoding type from string rapresentation.
81  * Returns -1 on error.
82  */
83 #ifndef HAVE_STRCASECMP /* some libs (windows, for example) have stricmp */
84 #  define strcasecmp stricmp
85 #endif
86
87 int encode_id(char *encode_name)
88 {
89     int i;
90     for (i = 0;  encode_tab[i].name; i++)
91         if (!strcasecmp(encode_tab[i].name, encode_name))
92             return encode_tab[i].type;
93     return -1;
94 }
95
96 int list_encodes(FILE *f) /* used in the help message */
97 {
98     int prev = -1;
99     int i;
100
101     fprintf(f, "Known encodings are (synonyms appear on the same line):");
102     for (i = 0;  encode_tab[i].name; i++) {
103         if (encode_tab[i].type != prev)
104             fprintf(f, "\n\t");
105         else
106             fprintf(f, ", ");
107         fprintf(f, "\"%s\"", encode_tab[i].name);
108         prev = encode_tab[i].type;
109     }
110     fprintf(f, "\n");
111     return 0;
112 }
113
114
115 /*
116  * Variables to hold cmdline arguments (or defaults)
117  */
118
119 char *ifilename, *ofilename;
120 int encoding_type;                    /* filled by get_encoding() */
121 int code_width, code_height;          /* "-g" for standalone codes */
122 int lines, columns;                   /* "-t" for tables */
123 int xmargin0, ymargin0;               /* both for "-g" and "-t" */
124 int xmargin1, ymargin1;               /* same, but right and top */
125 int ximargin, yimargin;               /* "-m": internal margins */
126 int eps, pcl, ps, noascii, nochecksum; /* boolean flags */
127 int page_wid, page_hei;               /* page size in points */
128 char *page_name;                      /* name of the media */
129 double unit = 1.0;                    /* unit specification */
130
131 char *prgname;  /* used to print error msgs, initialized to argv[0] by main */
132
133 /*
134  * Functions to handle command line arguments
135  */
136
137 struct encode_item {
138     char *string;
139     struct encode_item *next;
140 } *list_head, *list_tail;
141
142 /* each "-b" option adds a string to the input pool allocating its space */
143 int get_input_string(void *arg)
144 {
145     struct encode_item *item = malloc(sizeof(*item));
146     if (!item) {
147         fprintf(stderr, "%s: malloc: %s\n", prgname, strerror(errno));
148         return -2;
149     }
150     item->string = strdup(arg);
151     if (!list_head) {
152         list_head = list_tail = item;
153     } else {
154         list_tail->next = item;
155         list_tail = item;
156     }
157     item->next = NULL;
158     return 0;
159 }
160
161 /* and this function extracts strings from the pool */
162 unsigned char *retrieve_input_string(FILE *ifile)
163 {
164     char *string;
165     static char fileline[128];
166
167     struct encode_item *item = list_head;
168     if (list_tail) { /* this means at least one "-b" was specified */
169         if (!item)
170             return NULL; /* the list is empty */
171         string = item->string;
172         list_head = item->next;
173         free(item);
174         return string;
175     }
176
177     /* else,  read from the file */
178     if (!fgets(fileline, 128, ifile))
179         return NULL;
180     if (fileline[strlen(fileline)-1]=='\n')
181         fileline[strlen(fileline)-1]= '\0';
182     return strdup(fileline);
183 }
184
185 /* accept a unit specification */
186 int get_unit(void *arg)
187 {
188     static struct {
189         char *str;
190         double unit;
191     } *ptr, unittab[] = {
192         {"pt",  1.0},
193         {"in",  72.0},
194         {"cm",  72.0/2.54},
195         {"mm",  72.0/25.4},
196         {NULL, 0.0}
197     };
198
199     for (ptr = unittab; ptr->str && strcmp((char *)arg, ptr->str); ptr++)
200         ;
201     unit = ptr->unit;
202     if (ptr->str) return 0;
203
204     fprintf(stderr, "%s: incorrect unit \"%s\" (use one of",
205             prgname, (char *)arg);
206     for (ptr = unittab; ptr->str; ptr++)
207         fprintf(stderr, " \"%s\"", ptr->str);
208     fprintf(stderr, ")\n");
209     return -2;
210 }
211
212 /* convert an encoding name to an encoding integer code */
213 int get_encoding(void *arg)
214 {
215     encoding_type = encode_id((char *)arg);
216     if (encoding_type >=0) return 0;
217     fprintf(stderr, "%s: wrong encoding \"%s\"\n", prgname,
218             (char *)arg);
219     return -2; /* error, no help */
220 }
221
222 /* convert a geometry specification */
223 int get_geometry(void *arg)
224 {
225     double w = 0.0, h = 0.0;
226     double x = 0.0, y = 0.0;
227     int n;
228
229     if (((char *)arg)[0]=='+') {
230         n = sscanf((char *)arg, "+%lf+%lf%s", &x, &y, (char *)arg);
231     } else {
232         n = sscanf((char *)arg, "%lfx%lf+%lf+%lf%s", &w, &h, &x, &y,
233                    (char *)arg);
234     }
235     if (n!=4 && n!=2) {
236         fprintf(stderr, "%s: wrong geometry \"%s\"\n", prgname, (char *)arg);
237         return -2;
238     }
239     /* convert to points */
240     code_width  = w * unit;
241     code_height = h * unit;
242     xmargin0 = x * unit;
243     ymargin0 = y * unit;
244     return 0;
245 }
246
247 /* convert a geometry specification */
248 int get_table(void *arg)
249 {
250     double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
251     int n;
252
253     n = sscanf((char *)arg, "%dx%d+%lf+%lf-%lf-%lf",
254                &columns, &lines, &x0, &y0, &x1, &y1);
255
256     if (n==1 || n==3) { /* error: 2, 4, 5, 6 are fine */
257         fprintf(stderr, "%s: wrong table specification \"%s\"\n", prgname,
258                 (char *)arg);
259         return -2;
260     }
261     if (n < 6) y1 = y0; /* symmetric by default */
262     if (n < 5) x1 = x0;
263
264     /* convert and return */
265     xmargin0 = x0 * unit;
266     ymargin0 = y0 * unit;
267     xmargin1 = x1 * unit;
268     ymargin1 = y1 * unit;
269     return 0;
270 }
271
272 /* convert an internal margin specification */
273 int get_margin(void *arg)
274 {
275     char separator;
276     double x,y;
277     int n;
278
279     /* accept one number or two, separated by any char */
280     n = sscanf((char *)arg, "%lf%c%lf", &x, &separator, &y);
281
282     if (n==1) {
283         n=3; y = x;
284     }
285     if (n==3) {
286         ximargin = x * unit;
287         yimargin = y * unit;
288         return 0;
289     }
290     fprintf(stderr, "%s: wrong margin specification \"%s\"\n", prgname,
291             (char *)arg);
292         return -2;
293     return 0;
294 }
295
296 /* convert a page geometry specification */
297 int get_page_geometry(void *arg)
298 {
299     int n;
300     double dpw, dph; /* page width, height in mm or inches */
301     static char tmpstr[20];
302     page_name = arg; /* if undecipherable, we won't run the program :) */
303     /*
304      * try to decode a "mm" string (eg. "210mmx297mm" or "210x297mm")
305      */
306     n = sscanf((char *)arg, "%lfmmx%lf", &dpw, &dph);
307     if (n != 2 && strlen(arg)<20) {
308         n =  sscanf((char *)arg, "%lfx%lf%s", &dpw, &dph, tmpstr);
309         if (n == 3 && !strcmp(tmpstr, "mm")) {
310             /* Ok, convert to points: 1in is 25.4mm, 1in is also 72p */
311             page_wid = (int)(dpw / 25.4 * 72.0 + 0.5);
312             page_hei = (int)(dph / 25.4 * 72.0 + 0.5);
313             return 0;
314         }
315     }
316
317     /*
318      * try to decode an "in" string (eg. "8.5inx11in" or "8.5x11in")
319      */
320     n = sscanf((char *)arg, "%lfinx%lf", &dpw, &dph);
321     if (n != 2 && strlen(arg)<20) {
322         n =  sscanf((char *)arg, "%lfx%lf%s", &dpw, &dph, tmpstr);
323         if (n == 3 && !strcmp(tmpstr, "in")) {
324             page_wid = (int)(dpw * 72.0 + 0.5); /* round to points */
325             page_hei = (int)(dph * 72.0 + 0.5);
326             return 0;
327         }
328     }
329
330     /*
331      * try to decode a numeric specification
332      */
333     n = sscanf((char *)arg, "%lfx%lf", &dpw, &dph);
334     if (n == 2) {
335         page_wid = dpw * unit;
336         page_hei = dph * unit;
337         if (unit != 1.0) { /* rebuild the page name */
338             page_name = malloc(32); /* big, to avoid snprintf, missing on HP */
339             if (page_name)
340                 sprintf(page_name, "%dx%d\n", page_wid, page_hei);
341         }
342         return 0;
343     }
344
345 #ifndef NO_LIBPAPER
346     /*
347      * try to use libpaper, since it is available
348      */
349     {
350     const struct paper* paptr;
351
352     paperinit();
353     paptr = paperinfo(arg);
354     if (!paptr) { /* unknown name */
355         paperdone();
356         return -1;
357     }
358     page_wid = (int)(paperpswidth(paptr) + 0.5);
359     page_hei = (int)(paperpsheight(paptr) + 0.5);
360     paperdone();
361     return 0;
362     }
363 #endif
364     /* If we got here, the argument is undecipherable: fail */
365     fprintf(stderr, "%s: wrong page size specification \"%s\"\n", prgname,
366             (char *)arg);
367     return -2;
368 }
369
370 /*
371  * The table of possible arguments
372  */
373 struct commandline option_table[] = {
374     {'i', CMDLINE_S, &ifilename, NULL, NULL, NULL,
375                    "input file (strings to encode), default is stdin"},
376     {'o', CMDLINE_S, &ofilename, NULL, NULL, NULL,
377                     "output file, default is stdout"},
378     {'b', CMDLINE_S, NULL, get_input_string, NULL, NULL,
379                    "string to encode (use input file if missing)"},
380     {'e', CMDLINE_S, NULL, get_encoding, "BARCODE_ENCODING", NULL,
381                    "encoding type (default is best fit for first string)"},
382     {'u', CMDLINE_S, NULL, get_unit, "BARCODE_UNIT", NULL,
383                     "unit (\"mm\", \"in\", ...) used to decode -g, -t, -p"},
384     {'g', CMDLINE_S, NULL, get_geometry, "BARCODE_GEOMETRY", NULL,
385                     "geometry on the page: [<wid>x<hei>][+<margin>+<margin>]"},
386     {'t', CMDLINE_S, NULL, get_table, "BARCODE_TABLE", NULL,
387                     "table geometry: <cols>x<lines>[+<margin>+<margin>]"},
388     {'m', CMDLINE_S, NULL, get_margin, "BARCODE_MARGIN", "10",
389                     "internal margin for each item in a table: <xm>[,<ym>]"},
390     {'n', CMDLINE_NONE, &noascii, NULL, NULL, NULL,
391                     "\"numeric\": avoid printing text along with the bars"},
392     {'c', CMDLINE_NONE, &nochecksum, NULL, NULL, NULL,
393                     "no Checksum character, if the chosen encoding allows it"},
394     {'E', CMDLINE_NONE, &eps, NULL, NULL, NULL,
395                     "print one code as eps file (default: multi-page ps)"},
396     {'P', CMDLINE_NONE, &pcl, NULL, NULL, NULL,
397                     "create PCL output instead of postscript"},
398     {'p', CMDLINE_S, NULL, get_page_geometry, NULL, NULL,
399                     "page size (refer to the man page)"},
400     {0,}
401 };
402
403 #ifdef NO_STRERROR
404 /*
405  * A strerror replacement (thanks to Thad Floryan <thad@thadlabs.com>)
406  */
407 char *strerror(int error)
408 {
409     static char msg[16];
410     if (error >= 0 && error < sys_nerr)
411         return sys_errlist[error];
412     sprintf(msg, "Error %d", error);
413     return msg;
414 }
415 #endif
416          
417 /*
418  * The main function
419  */
420 int main(int argc, char **argv)
421 {
422     struct Barcode_Item * bc;
423     FILE *ifile = stdin;
424     FILE *ofile = stdout;
425     char *line;
426     int flags=0; /* for the library */
427     int page, retval;
428
429     prgname = argv[0];
430
431     /* First of all, accept "--help" and "-h" as a special case */
432     if (argc == 2 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h"))) {
433         commandline_errormsg(stderr, option_table, argv[0], "Options:\n");
434         fprintf(stderr,"\n");
435         list_encodes(stderr);
436         exit(1);
437     }
438     /* Also, accept "--version" as a special case */
439     if (argc == 2 && (!strcmp(argv[1],"--version"))) {
440         printf("barcode frontend (GNU barcode) " BARCODE_VERSION "\n");
441         exit(0);
442     }
443
444     /* Otherwise, parse the commandline */
445     retval = commandline(option_table, argc, argv, "Use: %s [options]\n");
446     if (retval) {
447         if (retval == -1) /* help printed, complete it */
448             list_encodes(stderr);
449         else /* no help printed, suggest it */
450             fprintf(stderr, "%s: try \"%s --help\"\n", prgname, prgname);
451         exit(1);
452     }
453
454     /* If no paper size has been specified, use the default, if any */
455     if (!page_name) {
456         page_wid = 595; page_hei = 842;
457         page_name = "A4"; /* I live in Europe :) */
458 #ifndef NO_LIBPAPER
459         get_page_geometry(systempapername()); /* or the system default */
460 #endif
461     }
462
463     /* FIXME: print warnings for incompatible options */
464
465     /* open the input stream if specified */
466     if (ifilename)
467         ifile = fopen(ifilename,"r");
468     if (!ifile) {
469         fprintf(stderr, "%s: %s: %s\n", argv[0], ifilename,
470                 strerror(errno));
471         exit(1);
472     }
473
474     /* open the output stream if specified */
475     if (ofilename)
476         ofile = fopen(ofilename,"w");
477     if (!ofile) {
478         fprintf(stderr, "%s: %s: %s\n", argv[0], ofilename,
479                 strerror(errno));
480         exit(1);
481     }
482
483     if (encoding_type < 0) { /* unknown type specified */
484         fprintf(stderr,"%s: Unknown endoding. Try \"%s --help\"\n",
485                 argv[0], argv[0]);
486         exit(1);
487     }
488     flags |= encoding_type;  
489     if (pcl) {
490         flags |= BARCODE_OUT_PCL;
491     } else {
492         ps = !eps; /* a shortcut */
493         if (eps)
494             flags |= BARCODE_OUT_EPS; /* print headers too */
495         else
496             flags |= BARCODE_OUT_PS | BARCODE_OUT_NOHEADERS;
497     }
498     if (noascii)
499         flags |= BARCODE_NO_ASCII;
500     if (nochecksum)
501         flags |= BARCODE_NO_CHECKSUM;
502
503     /* the table is not available in eps mode */
504     if (eps && (lines>1 || columns>1)) {
505         fprintf(stderr, "%s: can't print tables in EPS format\n",argv[0]);
506         exit(1);
507     }
508
509     if (ps) { /* The header is independent of single/table mode */
510         /* Headers. Don't let the library do it, we may need multi-page */
511         fprintf(ofile, "%%!PS-Adobe-2.0\n");
512         /* It would be nice to know the bounding box. Leave it alone */
513         fprintf(ofile, "%%%%Creator: \"barcode\", "
514                 "libbarcode sample frontend\n");
515         if (page_name)
516             fprintf(ofile, "%%%%DocumentPaperSizes: %s\n", page_name);
517         fprintf(ofile, "%%%%EndComments\n");
518         fprintf(ofile, "%%%%EndProlog\n\n");
519     }
520
521     /*
522      * Here we are, ready to work. Handle the one-per-page case first,
523      * as it is shorter.
524      */
525     if (!lines && !columns) {
526         page = 0;
527         while ( (line = retrieve_input_string(ifile)) ) {
528             page++;
529             if (ps) {
530                 fprintf(ofile, "%%%%Page: %i %i\n\n",page,page);
531             }
532             if (Barcode_Encode_and_Print(line, ofile, code_width, code_height,
533                                          xmargin0, ymargin0, flags) < 0) {
534                 fprintf(stderr, "%s: can't encode \"%s\"\n", argv[0], line);
535             }
536             if (eps) break; /* if output is eps, do it once only */
537             if (ps) fprintf(ofile, "showpage\n");
538             if (pcl) fprintf(ofile, "\f");
539         }
540         /* no more lines, print footers */
541         if (ps) {
542             fprintf(ofile, "%%%%Trailer\n\n");
543         }
544     } else {
545
546         /* table mode, the header has been already printed */
547         
548         int xstep = (page_wid - xmargin0 - xmargin1)/columns;
549         int ystep = (page_hei - ymargin0 - ymargin1)/lines;
550         int x = columns, y = -1; /* position in the table, start off-page */
551
552         if (!ximargin) ximargin = BARCODE_DEFAULT_MARGIN;
553         if (!yimargin) yimargin = BARCODE_DEFAULT_MARGIN;
554         /* Assign default size unless -g did it (Joachim Reichelt) */
555         if ( !code_width && !code_height) {
556             code_width = xstep - 2*ximargin;
557             code_height = ystep - 2*yimargin;
558         }
559
560         page=0;
561         while ( (line = retrieve_input_string(ifile)) ) {
562             x++;  /* fit x and y */
563             if (x >= columns) {
564                 x=0; y--;
565                 if (y<0) {
566                     y = lines-1; page++;
567                     /* flush page */
568                     if (ps && page > 1) fprintf(ofile, "showpage\n");
569                     if (pcl && page > 1) fprintf(ofile, "\f");
570                     /* new page */
571                     if (ps) fprintf(ofile, "%%%%Page: %i %i\n\n",page,page);
572                 }
573             }
574
575             /*
576              * Create a barcode item. This allows to set the margin to 0, as
577              * we have [xy]imargin to use. But don't use Encode_and_Print(),
578              * unroll it here instead
579              */
580             bc = Barcode_Create(line);
581             if (!bc) {
582                 fprintf(stderr, "%s: Barcode_Create(): %s\n", argv[0],
583                         strerror(errno));
584                 exit(1);
585             }
586             bc->margin = 0;
587             if ( (Barcode_Position(bc, code_width, code_height,
588                                    xmargin0 + ximargin + x * xstep,
589                                    ymargin0 + yimargin + y * ystep, 0.0) < 0)
590                  || (Barcode_Encode(bc, flags) < 0)
591                  || (Barcode_Print(bc, ofile, flags) < 0) ) {
592                 fprintf(stderr, "%s: can't encode \"%s\": %s\n", argv[0],
593                         line, strerror(bc->error));
594             }
595             Barcode_Delete(bc);
596         }
597         if (ps) fprintf(ofile, "showpage\n\n%%%%Trailer\n\n");
598         if (pcl) fprintf(ofile, "\f");
599     }
600     return 0;
601 }
602
603
604