/* * main.c - a commandline frontend for the barcode library * * Copyright (c) 1999 Michele Comitini (mcm@glisco.it) * Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org) * Copyright (c) 1999 Prosa Srl. (prosa@prosa.it) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "cmdline.h" #include "barcode.h" #ifndef NO_LIBPAPER #include #endif /* * Most of this file deals with command line options, by exploiting * the cmdline.[ch] engine to offer defaults via environment variables * and handling functions for complex options. * * In order to offer a friendly interface (for those who feel the * cmdline *is* friendly, like me), we have to convert names to enums... */ struct { char *name; int type; } encode_tab[] = { {"ean", BARCODE_EAN}, {"ean13", BARCODE_EAN}, {"ean-13", BARCODE_EAN}, {"ean8", BARCODE_EAN}, {"ean-8", BARCODE_EAN}, {"upc", BARCODE_UPC}, {"upc-a", BARCODE_UPC}, {"upc-e", BARCODE_UPC}, {"isbn", BARCODE_ISBN}, {"39", BARCODE_39}, {"code39", BARCODE_39}, {"128c", BARCODE_128C}, {"code128c", BARCODE_128C}, {"128b", BARCODE_128B}, {"code128b", BARCODE_128B}, {"128", BARCODE_128}, {"code128", BARCODE_128}, {"128raw", BARCODE_128RAW}, {"i25", BARCODE_I25}, {"interleaved 2 of 5", BARCODE_I25}, {"cbr", BARCODE_CBR}, {"codabar", BARCODE_CBR}, {"msi", BARCODE_MSI}, {"pls", BARCODE_PLS}, {"plessey", BARCODE_PLS}, {"code93", BARCODE_93}, {"93", BARCODE_93}, {NULL, 0} }; /* * Get encoding type from string rapresentation. * Returns -1 on error. */ #ifndef HAVE_STRCASECMP /* some libs (windows, for example) have stricmp */ # define strcasecmp stricmp #endif int encode_id(char *encode_name) { int i; for (i = 0; encode_tab[i].name; i++) if (!strcasecmp(encode_tab[i].name, encode_name)) return encode_tab[i].type; return -1; } int list_encodes(FILE *f) /* used in the help message */ { int prev = -1; int i; fprintf(f, "Known encodings are (synonyms appear on the same line):"); for (i = 0; encode_tab[i].name; i++) { if (encode_tab[i].type != prev) fprintf(f, "\n\t"); else fprintf(f, ", "); fprintf(f, "\"%s\"", encode_tab[i].name); prev = encode_tab[i].type; } fprintf(f, "\n"); return 0; } /* * Variables to hold cmdline arguments (or defaults) */ char *ifilename, *ofilename; int encoding_type; /* filled by get_encoding() */ int code_width, code_height; /* "-g" for standalone codes */ int lines, columns; /* "-t" for tables */ int xmargin0, ymargin0; /* both for "-g" and "-t" */ int xmargin1, ymargin1; /* same, but right and top */ int ximargin, yimargin; /* "-m": internal margins */ int eps, pcl, ps, noascii, nochecksum; /* boolean flags */ int page_wid, page_hei; /* page size in points */ char *page_name; /* name of the media */ double unit = 1.0; /* unit specification */ char *prgname; /* used to print error msgs, initialized to argv[0] by main */ /* * Functions to handle command line arguments */ struct encode_item { char *string; struct encode_item *next; } *list_head, *list_tail; /* each "-b" option adds a string to the input pool allocating its space */ int get_input_string(void *arg) { struct encode_item *item = malloc(sizeof(*item)); if (!item) { fprintf(stderr, "%s: malloc: %s\n", prgname, strerror(errno)); return -2; } item->string = strdup(arg); if (!list_head) { list_head = list_tail = item; } else { list_tail->next = item; list_tail = item; } item->next = NULL; return 0; } /* and this function extracts strings from the pool */ unsigned char *retrieve_input_string(FILE *ifile) { char *string; static char fileline[128]; struct encode_item *item = list_head; if (list_tail) { /* this means at least one "-b" was specified */ if (!item) return NULL; /* the list is empty */ string = item->string; list_head = item->next; free(item); return string; } /* else, read from the file */ if (!fgets(fileline, 128, ifile)) return NULL; if (fileline[strlen(fileline)-1]=='\n') fileline[strlen(fileline)-1]= '\0'; return strdup(fileline); } /* accept a unit specification */ int get_unit(void *arg) { static struct { char *str; double unit; } *ptr, unittab[] = { {"pt", 1.0}, {"in", 72.0}, {"cm", 72.0/2.54}, {"mm", 72.0/25.4}, {NULL, 0.0} }; for (ptr = unittab; ptr->str && strcmp((char *)arg, ptr->str); ptr++) ; unit = ptr->unit; if (ptr->str) return 0; fprintf(stderr, "%s: incorrect unit \"%s\" (use one of", prgname, (char *)arg); for (ptr = unittab; ptr->str; ptr++) fprintf(stderr, " \"%s\"", ptr->str); fprintf(stderr, ")\n"); return -2; } /* convert an encoding name to an encoding integer code */ int get_encoding(void *arg) { encoding_type = encode_id((char *)arg); if (encoding_type >=0) return 0; fprintf(stderr, "%s: wrong encoding \"%s\"\n", prgname, (char *)arg); return -2; /* error, no help */ } /* convert a geometry specification */ int get_geometry(void *arg) { double w = 0.0, h = 0.0; double x = 0.0, y = 0.0; int n; if (((char *)arg)[0]=='+') { n = sscanf((char *)arg, "+%lf+%lf%s", &x, &y, (char *)arg); } else { n = sscanf((char *)arg, "%lfx%lf+%lf+%lf%s", &w, &h, &x, &y, (char *)arg); } if (n!=4 && n!=2) { fprintf(stderr, "%s: wrong geometry \"%s\"\n", prgname, (char *)arg); return -2; } /* convert to points */ code_width = w * unit; code_height = h * unit; xmargin0 = x * unit; ymargin0 = y * unit; return 0; } /* convert a geometry specification */ int get_table(void *arg) { double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0; int n; n = sscanf((char *)arg, "%dx%d+%lf+%lf-%lf-%lf", &columns, &lines, &x0, &y0, &x1, &y1); if (n==1 || n==3) { /* error: 2, 4, 5, 6 are fine */ fprintf(stderr, "%s: wrong table specification \"%s\"\n", prgname, (char *)arg); return -2; } if (n < 6) y1 = y0; /* symmetric by default */ if (n < 5) x1 = x0; /* convert and return */ xmargin0 = x0 * unit; ymargin0 = y0 * unit; xmargin1 = x1 * unit; ymargin1 = y1 * unit; return 0; } /* convert an internal margin specification */ int get_margin(void *arg) { char separator; double x,y; int n; /* accept one number or two, separated by any char */ n = sscanf((char *)arg, "%lf%c%lf", &x, &separator, &y); if (n==1) { n=3; y = x; } if (n==3) { ximargin = x * unit; yimargin = y * unit; return 0; } fprintf(stderr, "%s: wrong margin specification \"%s\"\n", prgname, (char *)arg); return -2; return 0; } /* convert a page geometry specification */ int get_page_geometry(void *arg) { int n; double dpw, dph; /* page width, height in mm or inches */ static char tmpstr[20]; page_name = arg; /* if undecipherable, we won't run the program :) */ /* * try to decode a "mm" string (eg. "210mmx297mm" or "210x297mm") */ n = sscanf((char *)arg, "%lfmmx%lf", &dpw, &dph); if (n != 2 && strlen(arg)<20) { n = sscanf((char *)arg, "%lfx%lf%s", &dpw, &dph, tmpstr); if (n == 3 && !strcmp(tmpstr, "mm")) { /* Ok, convert to points: 1in is 25.4mm, 1in is also 72p */ page_wid = (int)(dpw / 25.4 * 72.0 + 0.5); page_hei = (int)(dph / 25.4 * 72.0 + 0.5); return 0; } } /* * try to decode an "in" string (eg. "8.5inx11in" or "8.5x11in") */ n = sscanf((char *)arg, "%lfinx%lf", &dpw, &dph); if (n != 2 && strlen(arg)<20) { n = sscanf((char *)arg, "%lfx%lf%s", &dpw, &dph, tmpstr); if (n == 3 && !strcmp(tmpstr, "in")) { page_wid = (int)(dpw * 72.0 + 0.5); /* round to points */ page_hei = (int)(dph * 72.0 + 0.5); return 0; } } /* * try to decode a numeric specification */ n = sscanf((char *)arg, "%lfx%lf", &dpw, &dph); if (n == 2) { page_wid = dpw * unit; page_hei = dph * unit; if (unit != 1.0) { /* rebuild the page name */ page_name = malloc(32); /* big, to avoid snprintf, missing on HP */ if (page_name) sprintf(page_name, "%dx%d\n", page_wid, page_hei); } return 0; } #ifndef NO_LIBPAPER /* * try to use libpaper, since it is available */ { const struct paper* paptr; paperinit(); paptr = paperinfo(arg); if (!paptr) { /* unknown name */ paperdone(); return -1; } page_wid = (int)(paperpswidth(paptr) + 0.5); page_hei = (int)(paperpsheight(paptr) + 0.5); paperdone(); return 0; } #endif /* If we got here, the argument is undecipherable: fail */ fprintf(stderr, "%s: wrong page size specification \"%s\"\n", prgname, (char *)arg); return -2; } /* * The table of possible arguments */ struct commandline option_table[] = { {'i', CMDLINE_S, &ifilename, NULL, NULL, NULL, "input file (strings to encode), default is stdin"}, {'o', CMDLINE_S, &ofilename, NULL, NULL, NULL, "output file, default is stdout"}, {'b', CMDLINE_S, NULL, get_input_string, NULL, NULL, "string to encode (use input file if missing)"}, {'e', CMDLINE_S, NULL, get_encoding, "BARCODE_ENCODING", NULL, "encoding type (default is best fit for first string)"}, {'u', CMDLINE_S, NULL, get_unit, "BARCODE_UNIT", NULL, "unit (\"mm\", \"in\", ...) used to decode -g, -t, -p"}, {'g', CMDLINE_S, NULL, get_geometry, "BARCODE_GEOMETRY", NULL, "geometry on the page: [x][++]"}, {'t', CMDLINE_S, NULL, get_table, "BARCODE_TABLE", NULL, "table geometry: x[++]"}, {'m', CMDLINE_S, NULL, get_margin, "BARCODE_MARGIN", "10", "internal margin for each item in a table: [,]"}, {'n', CMDLINE_NONE, &noascii, NULL, NULL, NULL, "\"numeric\": avoid printing text along with the bars"}, {'c', CMDLINE_NONE, &nochecksum, NULL, NULL, NULL, "no Checksum character, if the chosen encoding allows it"}, {'E', CMDLINE_NONE, &eps, NULL, NULL, NULL, "print one code as eps file (default: multi-page ps)"}, {'P', CMDLINE_NONE, &pcl, NULL, NULL, NULL, "create PCL output instead of postscript"}, {'p', CMDLINE_S, NULL, get_page_geometry, NULL, NULL, "page size (refer to the man page)"}, {0,} }; #ifdef NO_STRERROR /* * A strerror replacement (thanks to Thad Floryan ) */ char *strerror(int error) { static char msg[16]; if (error >= 0 && error < sys_nerr) return sys_errlist[error]; sprintf(msg, "Error %d", error); return msg; } #endif /* * The main function */ int main(int argc, char **argv) { struct Barcode_Item * bc; FILE *ifile = stdin; FILE *ofile = stdout; char *line; int flags=0; /* for the library */ int page, retval; prgname = argv[0]; /* First of all, accept "--help" and "-h" as a special case */ if (argc == 2 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h"))) { commandline_errormsg(stderr, option_table, argv[0], "Options:\n"); fprintf(stderr,"\n"); list_encodes(stderr); exit(1); } /* Also, accept "--version" as a special case */ if (argc == 2 && (!strcmp(argv[1],"--version"))) { printf("barcode frontend (GNU barcode) " BARCODE_VERSION "\n"); exit(0); } /* Otherwise, parse the commandline */ retval = commandline(option_table, argc, argv, "Use: %s [options]\n"); if (retval) { if (retval == -1) /* help printed, complete it */ list_encodes(stderr); else /* no help printed, suggest it */ fprintf(stderr, "%s: try \"%s --help\"\n", prgname, prgname); exit(1); } /* If no paper size has been specified, use the default, if any */ if (!page_name) { page_wid = 595; page_hei = 842; page_name = "A4"; /* I live in Europe :) */ #ifndef NO_LIBPAPER get_page_geometry(systempapername()); /* or the system default */ #endif } /* FIXME: print warnings for incompatible options */ /* open the input stream if specified */ if (ifilename) ifile = fopen(ifilename,"r"); if (!ifile) { fprintf(stderr, "%s: %s: %s\n", argv[0], ifilename, strerror(errno)); exit(1); } /* open the output stream if specified */ if (ofilename) ofile = fopen(ofilename,"w"); if (!ofile) { fprintf(stderr, "%s: %s: %s\n", argv[0], ofilename, strerror(errno)); exit(1); } if (encoding_type < 0) { /* unknown type specified */ fprintf(stderr,"%s: Unknown endoding. Try \"%s --help\"\n", argv[0], argv[0]); exit(1); } flags |= encoding_type; if (pcl) { flags |= BARCODE_OUT_PCL; } else { ps = !eps; /* a shortcut */ if (eps) flags |= BARCODE_OUT_EPS; /* print headers too */ else flags |= BARCODE_OUT_PS | BARCODE_OUT_NOHEADERS; } if (noascii) flags |= BARCODE_NO_ASCII; if (nochecksum) flags |= BARCODE_NO_CHECKSUM; /* the table is not available in eps mode */ if (eps && (lines>1 || columns>1)) { fprintf(stderr, "%s: can't print tables in EPS format\n",argv[0]); exit(1); } if (ps) { /* The header is independent of single/table mode */ /* Headers. Don't let the library do it, we may need multi-page */ fprintf(ofile, "%%!PS-Adobe-2.0\n"); /* It would be nice to know the bounding box. Leave it alone */ fprintf(ofile, "%%%%Creator: \"barcode\", " "libbarcode sample frontend\n"); if (page_name) fprintf(ofile, "%%%%DocumentPaperSizes: %s\n", page_name); fprintf(ofile, "%%%%EndComments\n"); fprintf(ofile, "%%%%EndProlog\n\n"); } /* * Here we are, ready to work. Handle the one-per-page case first, * as it is shorter. */ if (!lines && !columns) { page = 0; while ( (line = retrieve_input_string(ifile)) ) { page++; if (ps) { fprintf(ofile, "%%%%Page: %i %i\n\n",page,page); } if (Barcode_Encode_and_Print(line, ofile, code_width, code_height, xmargin0, ymargin0, flags) < 0) { fprintf(stderr, "%s: can't encode \"%s\"\n", argv[0], line); } if (eps) break; /* if output is eps, do it once only */ if (ps) fprintf(ofile, "showpage\n"); if (pcl) fprintf(ofile, "\f"); } /* no more lines, print footers */ if (ps) { fprintf(ofile, "%%%%Trailer\n\n"); } } else { /* table mode, the header has been already printed */ int xstep = (page_wid - xmargin0 - xmargin1)/columns; int ystep = (page_hei - ymargin0 - ymargin1)/lines; int x = columns, y = -1; /* position in the table, start off-page */ if (!ximargin) ximargin = BARCODE_DEFAULT_MARGIN; if (!yimargin) yimargin = BARCODE_DEFAULT_MARGIN; /* Assign default size unless -g did it (Joachim Reichelt) */ if ( !code_width && !code_height) { code_width = xstep - 2*ximargin; code_height = ystep - 2*yimargin; } page=0; while ( (line = retrieve_input_string(ifile)) ) { x++; /* fit x and y */ if (x >= columns) { x=0; y--; if (y<0) { y = lines-1; page++; /* flush page */ if (ps && page > 1) fprintf(ofile, "showpage\n"); if (pcl && page > 1) fprintf(ofile, "\f"); /* new page */ if (ps) fprintf(ofile, "%%%%Page: %i %i\n\n",page,page); } } /* * Create a barcode item. This allows to set the margin to 0, as * we have [xy]imargin to use. But don't use Encode_and_Print(), * unroll it here instead */ bc = Barcode_Create(line); if (!bc) { fprintf(stderr, "%s: Barcode_Create(): %s\n", argv[0], strerror(errno)); exit(1); } bc->margin = 0; if ( (Barcode_Position(bc, code_width, code_height, xmargin0 + ximargin + x * xstep, ymargin0 + yimargin + y * ystep, 0.0) < 0) || (Barcode_Encode(bc, flags) < 0) || (Barcode_Print(bc, ofile, flags) < 0) ) { fprintf(stderr, "%s: can't encode \"%s\": %s\n", argv[0], line, strerror(bc->error)); } Barcode_Delete(bc); } if (ps) fprintf(ofile, "showpage\n\n%%%%Trailer\n\n"); if (pcl) fprintf(ofile, "\f"); } return 0; }