2 * main.c - a commandline frontend for the barcode library
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)
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.
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.
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.
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.
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...
49 {"ean13", BARCODE_EAN},
50 {"ean-13", BARCODE_EAN},
51 {"ean8", BARCODE_EAN},
52 {"ean-8", BARCODE_EAN},
54 {"upc-a", BARCODE_UPC},
55 {"upc-e", BARCODE_UPC},
56 {"isbn", BARCODE_ISBN},
58 {"code39", BARCODE_39},
59 {"128c", BARCODE_128C},
60 {"code128c", BARCODE_128C},
61 {"128b", BARCODE_128B},
62 {"code128b", BARCODE_128B},
64 {"code128", BARCODE_128},
65 {"128raw", BARCODE_128RAW},
67 {"interleaved 2 of 5", BARCODE_I25},
69 {"codabar", BARCODE_CBR},
72 {"plessey", BARCODE_PLS},
73 {"code93", BARCODE_93},
80 * Get encoding type from string rapresentation.
81 * Returns -1 on error.
83 #ifndef HAVE_STRCASECMP /* some libs (windows, for example) have stricmp */
84 # define strcasecmp stricmp
87 int encode_id(char *encode_name)
90 for (i = 0; encode_tab[i].name; i++)
91 if (!strcasecmp(encode_tab[i].name, encode_name))
92 return encode_tab[i].type;
96 int list_encodes(FILE *f) /* used in the help message */
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)
107 fprintf(f, "\"%s\"", encode_tab[i].name);
108 prev = encode_tab[i].type;
116 * Variables to hold cmdline arguments (or defaults)
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 */
131 char *prgname; /* used to print error msgs, initialized to argv[0] by main */
134 * Functions to handle command line arguments
139 struct encode_item *next;
140 } *list_head, *list_tail;
142 /* each "-b" option adds a string to the input pool allocating its space */
143 int get_input_string(void *arg)
145 struct encode_item *item = malloc(sizeof(*item));
147 fprintf(stderr, "%s: malloc: %s\n", prgname, strerror(errno));
150 item->string = strdup(arg);
152 list_head = list_tail = item;
154 list_tail->next = item;
161 /* and this function extracts strings from the pool */
162 unsigned char *retrieve_input_string(FILE *ifile)
165 static char fileline[128];
167 struct encode_item *item = list_head;
168 if (list_tail) { /* this means at least one "-b" was specified */
170 return NULL; /* the list is empty */
171 string = item->string;
172 list_head = item->next;
177 /* else, read from the file */
178 if (!fgets(fileline, 128, ifile))
180 if (fileline[strlen(fileline)-1]=='\n')
181 fileline[strlen(fileline)-1]= '\0';
182 return strdup(fileline);
185 /* accept a unit specification */
186 int get_unit(void *arg)
191 } *ptr, unittab[] = {
199 for (ptr = unittab; ptr->str && strcmp((char *)arg, ptr->str); ptr++)
202 if (ptr->str) return 0;
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");
212 /* convert an encoding name to an encoding integer code */
213 int get_encoding(void *arg)
215 encoding_type = encode_id((char *)arg);
216 if (encoding_type >=0) return 0;
217 fprintf(stderr, "%s: wrong encoding \"%s\"\n", prgname,
219 return -2; /* error, no help */
222 /* convert a geometry specification */
223 int get_geometry(void *arg)
225 double w = 0.0, h = 0.0;
226 double x = 0.0, y = 0.0;
229 if (((char *)arg)[0]=='+') {
230 n = sscanf((char *)arg, "+%lf+%lf%s", &x, &y, (char *)arg);
232 n = sscanf((char *)arg, "%lfx%lf+%lf+%lf%s", &w, &h, &x, &y,
236 fprintf(stderr, "%s: wrong geometry \"%s\"\n", prgname, (char *)arg);
239 /* convert to points */
240 code_width = w * unit;
241 code_height = h * unit;
247 /* convert a geometry specification */
248 int get_table(void *arg)
250 double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
253 n = sscanf((char *)arg, "%dx%d+%lf+%lf-%lf-%lf",
254 &columns, &lines, &x0, &y0, &x1, &y1);
256 if (n==1 || n==3) { /* error: 2, 4, 5, 6 are fine */
257 fprintf(stderr, "%s: wrong table specification \"%s\"\n", prgname,
261 if (n < 6) y1 = y0; /* symmetric by default */
264 /* convert and return */
265 xmargin0 = x0 * unit;
266 ymargin0 = y0 * unit;
267 xmargin1 = x1 * unit;
268 ymargin1 = y1 * unit;
272 /* convert an internal margin specification */
273 int get_margin(void *arg)
279 /* accept one number or two, separated by any char */
280 n = sscanf((char *)arg, "%lf%c%lf", &x, &separator, &y);
290 fprintf(stderr, "%s: wrong margin specification \"%s\"\n", prgname,
296 /* convert a page geometry specification */
297 int get_page_geometry(void *arg)
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 :) */
304 * try to decode a "mm" string (eg. "210mmx297mm" or "210x297mm")
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);
318 * try to decode an "in" string (eg. "8.5inx11in" or "8.5x11in")
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);
331 * try to decode a numeric specification
333 n = sscanf((char *)arg, "%lfx%lf", &dpw, &dph);
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 */
340 sprintf(page_name, "%dx%d\n", page_wid, page_hei);
347 * try to use libpaper, since it is available
350 const struct paper* paptr;
353 paptr = paperinfo(arg);
354 if (!paptr) { /* unknown name */
358 page_wid = (int)(paperpswidth(paptr) + 0.5);
359 page_hei = (int)(paperpsheight(paptr) + 0.5);
364 /* If we got here, the argument is undecipherable: fail */
365 fprintf(stderr, "%s: wrong page size specification \"%s\"\n", prgname,
371 * The table of possible arguments
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)"},
405 * A strerror replacement (thanks to Thad Floryan <thad@thadlabs.com>)
407 char *strerror(int error)
410 if (error >= 0 && error < sys_nerr)
411 return sys_errlist[error];
412 sprintf(msg, "Error %d", error);
420 int main(int argc, char **argv)
422 struct Barcode_Item * bc;
424 FILE *ofile = stdout;
426 int flags=0; /* for the library */
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);
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");
444 /* Otherwise, parse the commandline */
445 retval = commandline(option_table, argc, argv, "Use: %s [options]\n");
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);
454 /* If no paper size has been specified, use the default, if any */
456 page_wid = 595; page_hei = 842;
457 page_name = "A4"; /* I live in Europe :) */
459 get_page_geometry(systempapername()); /* or the system default */
463 /* FIXME: print warnings for incompatible options */
465 /* open the input stream if specified */
467 ifile = fopen(ifilename,"r");
469 fprintf(stderr, "%s: %s: %s\n", argv[0], ifilename,
474 /* open the output stream if specified */
476 ofile = fopen(ofilename,"w");
478 fprintf(stderr, "%s: %s: %s\n", argv[0], ofilename,
483 if (encoding_type < 0) { /* unknown type specified */
484 fprintf(stderr,"%s: Unknown endoding. Try \"%s --help\"\n",
488 flags |= encoding_type;
490 flags |= BARCODE_OUT_PCL;
492 ps = !eps; /* a shortcut */
494 flags |= BARCODE_OUT_EPS; /* print headers too */
496 flags |= BARCODE_OUT_PS | BARCODE_OUT_NOHEADERS;
499 flags |= BARCODE_NO_ASCII;
501 flags |= BARCODE_NO_CHECKSUM;
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]);
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");
516 fprintf(ofile, "%%%%DocumentPaperSizes: %s\n", page_name);
517 fprintf(ofile, "%%%%EndComments\n");
518 fprintf(ofile, "%%%%EndProlog\n\n");
522 * Here we are, ready to work. Handle the one-per-page case first,
525 if (!lines && !columns) {
527 while ( (line = retrieve_input_string(ifile)) ) {
530 fprintf(ofile, "%%%%Page: %i %i\n\n",page,page);
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);
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");
540 /* no more lines, print footers */
542 fprintf(ofile, "%%%%Trailer\n\n");
546 /* table mode, the header has been already printed */
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 */
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;
561 while ( (line = retrieve_input_string(ifile)) ) {
562 x++; /* fit x and y */
568 if (ps && page > 1) fprintf(ofile, "showpage\n");
569 if (pcl && page > 1) fprintf(ofile, "\f");
571 if (ps) fprintf(ofile, "%%%%Page: %i %i\n\n",page,page);
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
580 bc = Barcode_Create(line);
582 fprintf(stderr, "%s: Barcode_Create(): %s\n", argv[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));
597 if (ps) fprintf(ofile, "showpage\n\n%%%%Trailer\n\n");
598 if (pcl) fprintf(ofile, "\f");