Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/frontend/main.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* main.c - Command line handling routines for Zint */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com> | |
| 5 | |
| 6 This program is free software; you can redistribute it and/or modify | |
| 7 it under the terms of the GNU General Public License as published by | |
| 8 the Free Software Foundation; either version 3 of the License, or | |
| 9 (at your option) any later version. | |
| 10 | |
| 11 This program is distributed in the hope that it will be useful, | |
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 GNU General Public License for more details. | |
| 15 | |
| 16 You should have received a copy of the GNU General Public License along | |
| 17 with this program; if not, write to the Free Software Foundation, Inc., | |
| 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 19 */ | |
| 20 /* SPDX-License-Identifier: GPL-3.0-or-later */ | |
| 21 | |
| 22 #include <errno.h> | |
| 23 #include <limits.h> | |
| 24 #include <stdio.h> | |
| 25 #include <stdlib.h> | |
| 26 #include <string.h> | |
| 27 | |
| 28 #if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) | |
| 29 # include <getopt.h> | |
| 30 # include <zint.h> | |
| 31 #else | |
| 32 # include "../getopt/getopt.h" | |
| 33 # ifdef _MSC_VER | |
| 34 # include "zint.h" | |
| 35 # if _MSC_VER > 1200 /* VC6 */ | |
| 36 # pragma warning(disable: 4996) /* function or variable may be unsafe */ | |
| 37 # endif | |
| 38 # else | |
| 39 # include <zint.h> | |
| 40 # endif | |
| 41 #endif | |
| 42 | |
| 43 /* Following copied from "backend/library.c" */ | |
| 44 | |
| 45 /* It's assumed that int is at least 32 bits, the following will compile-time fail if not | |
| 46 * https://stackoverflow.com/a/1980056 */ | |
| 47 typedef char static_assert_int_at_least_32bits[sizeof(int) * CHAR_BIT < 32 ? -1 : 1]; | |
| 48 | |
| 49 /* Following copied from "backend/common.h" */ | |
| 50 | |
| 51 #define ARRAY_SIZE(x) ((int) (sizeof(x) / sizeof((x)[0]))) | |
| 52 | |
| 53 #ifdef _MSC_VER | |
| 54 # include <malloc.h> | |
| 55 # define z_alloca(nmemb) _alloca(nmemb) | |
| 56 #elif defined(__COMPCERT__) | |
| 57 # define z_alloca(nmemb) malloc(nmemb) /* So links - leads to loads of leaks obs */ | |
| 58 #else | |
| 59 # if (defined(__GNUC__) && !defined(alloca) && !defined(__NetBSD__)) || defined(__NuttX__) || defined(_AIX) \ | |
| 60 || (defined(__sun) && defined(__SVR4) /*Solaris*/) | |
| 61 # include <alloca.h> | |
| 62 # endif | |
| 63 # define z_alloca(nmemb) alloca(nmemb) | |
| 64 #endif | |
| 65 | |
| 66 /* Print list of supported symbologies */ | |
| 67 static void types(void) { | |
| 68 /* Breaking up strings so don't get too long (i.e. 500 or so) */ | |
| 69 fputs(" # Name Description # Name Description\n" | |
| 70 " 1 CODE11 Code 11 75 NVE18 NVE-18\n" | |
| 71 " 2 C25STANDARD Standard 2 of 5 76 JAPANPOST Japanese Post\n" | |
| 72 " 3 C25INTER Interleaved 2 of 5 77 KOREAPOST Korea Post\n" | |
| 73 " 4 C25IATA IATA 2 of 5 79 DBAR_STK GS1 DataBar Stacked\n", stdout); | |
| 74 fputs(" 6 C25LOGIC Data Logic 2 of 5 80 DBAR_OMNSTK GS1 DataBar Stack Omni\n" | |
| 75 " 7 C25IND Industrial 2 of 5 81 DBAR_EXPSTK GS1 DataBar Exp Stack\n" | |
| 76 " 8 CODE39 Code 39 82 PLANET USPS PLANET\n" | |
| 77 " 9 EXCODE39 Extended Code 39 84 MICROPDF417 MicroPDF417\n" | |
| 78 "13 EANX EAN-2 to EAN-13 85 USPS_IMAIL USPS Intelligent Mail\n", stdout); | |
| 79 fputs("14 EANX_CHK EAN + Check Digit 86 PLESSEY UK Plessey\n" | |
| 80 "16 GS1_128 GS1-128 87 TELEPEN_NUM Telepen Numeric\n" | |
| 81 "18 CODABAR Codabar 89 ITF14 ITF-14\n" | |
| 82 "20 CODE128 Code 128 90 KIX Dutch Post KIX Code\n" | |
| 83 "21 DPLEIT Deutsche Post Leitcode 92 AZTEC Aztec Code\n", stdout); | |
| 84 fputs("22 DPIDENT Deutsche Post Identcode 93 DAFT DAFT Code\n" | |
| 85 "23 CODE16K Code 16K 96 DPD DPD Parcel Code 128\n" | |
| 86 "24 CODE49 Code 49 97 MICROQR Micro QR Code\n" | |
| 87 "25 CODE93 Code 93 98 HIBC_128 HIBC Code 128\n" | |
| 88 "28 FLAT Flattermarken 99 HIBC_39 HIBC Code 39\n", stdout); | |
| 89 fputs("29 DBAR_OMN GS1 DataBar Omni 102 HIBC_DM HIBC Data Matrix\n" | |
| 90 "30 DBAR_LTD GS1 DataBar Limited 104 HIBC_QR HIBC QR Code\n" | |
| 91 "31 DBAR_EXP GS1 DataBar Expanded 106 HIBC_PDF HIBC PDF417\n" | |
| 92 "32 TELEPEN Telepen Alpha 108 HIBC_MICPDF HIBC MicroPDF417\n" | |
| 93 "34 UPCA UPC-A 110 HIBC_BLOCKF HIBC Codablock-F\n", stdout); | |
| 94 fputs("35 UPCA_CHK UPC-A + Check Digit 112 HIBC_AZTEC HIBC Aztec Code\n" | |
| 95 "37 UPCE UPC-E 115 DOTCODE DotCode\n" | |
| 96 "38 UPCE_CHK UPC-E + Check Digit 116 HANXIN Han Xin Code\n" | |
| 97 "40 POSTNET USPS POSTNET 119 MAILMARK_2D Royal Mail 2D Mailmark\n" | |
| 98 "47 MSI_PLESSEY MSI Plessey 120 UPU_S10 UPU S10\n", stdout); | |
| 99 fputs("49 FIM Facing Ident Mark 121 MAILMARK_4S RM 4-State Mailmark\n" | |
| 100 "50 LOGMARS LOGMARS Code 39 128 AZRUNE Aztec Runes\n" | |
| 101 "51 PHARMA Pharmacode One-Track 129 CODE32 Code 32\n" | |
| 102 "52 PZN Pharmazentralnummer 130 EANX_CC Composite EAN\n" | |
| 103 "53 PHARMA_TWO Pharmacode Two-Track 131 GS1_128_CC Composite GS1-128\n", stdout); | |
| 104 fputs("54 CEPNET Brazilian CEPNet 132 DBAR_OMN_CC Comp DataBar Omni\n" | |
| 105 "55 PDF417 PDF417 133 DBAR_LTD_CC Comp DataBar Limited\n" | |
| 106 "56 PDF417COMP Compact PDF417 134 DBAR_EXP_CC Comp DataBar Expanded\n" | |
| 107 "57 MAXICODE MaxiCode 135 UPCA_CC Composite UPC-A\n" | |
| 108 "58 QRCODE QR Code 136 UPCE_CC Composite UPC-E\n", stdout); | |
| 109 fputs("60 CODE128AB Code 128 (Suppress C) 137 DBAR_STK_CC Comp DataBar Stacked\n" | |
| 110 "63 AUSPOST AP Standard Customer 138 DBAR_OMNSTK_CC Comp DataBar Stack Omn\n" | |
| 111 "66 AUSREPLY AP Reply Paid 139 DBAR_EXPSTK_CC Comp DataBar Exp Stack\n" | |
| 112 "67 AUSROUTE AP Routing 140 CHANNEL Channel Code\n" | |
| 113 "68 AUSREDIRECT AP Redirection 141 CODEONE Code One\n", stdout); | |
| 114 fputs("69 ISBNX ISBN 142 GRIDMATRIX Grid Matrix\n" | |
| 115 "70 RM4SCC Royal Mail 4SCC 143 UPNQR UPN QR Code\n" | |
| 116 "71 DATAMATRIX Data Matrix 144 ULTRA Ultracode\n" | |
| 117 "72 EAN14 EAN-14 145 RMQR Rectangular Micro QR\n" | |
| 118 "73 VIN Vehicle Information No. 146 BC412 BC412\n", stdout); | |
| 119 fputs("74 CODABLOCKF Codablock-F 147 DXFILMEDGE DX Film Edge Barcode\n", stdout); | |
| 120 } | |
| 121 | |
| 122 /* Output version information */ | |
| 123 static void version(const int no_png) { | |
| 124 const char *no_png_lib = no_png ? " (no libpng)" : ""; | |
| 125 const int zint_version = ZBarcode_Version(); | |
| 126 const int version_major = zint_version / 10000; | |
| 127 const int version_minor = (zint_version % 10000) / 100; | |
| 128 int version_release = zint_version % 100; | |
| 129 int version_build; | |
| 130 | |
| 131 if (version_release >= 9) { | |
| 132 /* This is a test release */ | |
| 133 version_release = version_release / 10; | |
| 134 version_build = zint_version % 10; | |
| 135 printf("Zint version %d.%d.%d.%d (dev)%s\n", version_major, version_minor, version_release, version_build, | |
| 136 no_png_lib); | |
| 137 } else { | |
| 138 /* This is a stable release */ | |
| 139 printf("Zint version %d.%d.%d%s\n", version_major, version_minor, version_release, no_png_lib); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 /* Output usage information */ | |
| 144 static void usage(const int no_png) { | |
| 145 const char *no_png_type = no_png ? "" : "/PNG"; | |
| 146 const char *no_png_ext = no_png ? "gif" : "png"; | |
| 147 | |
| 148 version(no_png); | |
| 149 | |
| 150 /* Breaking up strings so don't get too long (i.e. 500 or so) */ | |
| 151 printf("Encode input data in a barcode and save as BMP/EMF/EPS/GIF/PCX%s/SVG/TIF/TXT\n\n", no_png_type); | |
| 152 fputs( " -b, --barcode=TYPE Number or name of barcode type. Default is 20 (CODE128)\n" | |
| 153 " --addongap=INTEGER Set add-on gap in multiples of X-dimension for EAN/UPC\n" | |
| 154 " --batch Treat each line of input file as a separate data set\n" | |
| 155 " --bg=COLOUR Specify a background colour (as RGB(A) or \"C,M,Y,K\")\n" | |
| 156 " --binary Treat input as raw binary data\n", stdout); | |
| 157 fputs( " --bind Add boundary bars\n" | |
| 158 " --bindtop Add top boundary bar only\n" | |
| 159 " --bold Use bold text (HRT)\n" | |
| 160 " --border=INTEGER Set width of border in multiples of X-dimension\n" | |
| 161 " --box Add a box around the symbol\n", stdout); | |
| 162 fputs( " --cmyk Use CMYK colour space in EPS/TIF symbols\n" | |
| 163 " --cols=INTEGER Set the number of data columns in symbol\n" | |
| 164 " --compliantheight Warn if height not compliant, and use standard default\n" | |
| 165 " -d, --data=DATA Set the symbol data content (segment 0)\n" | |
| 166 " --direct Send output to stdout\n", stdout); | |
| 167 fputs( " --dmiso144 Use ISO format for 144x144 Data Matrix symbols\n" | |
| 168 " --dmre Allow Data Matrix Rectangular Extended\n" | |
| 169 " --dotsize=NUMBER Set radius of dots in dotty mode\n" | |
| 170 " --dotty Use dots instead of squares for matrix symbols\n" | |
| 171 " --dump Dump hexadecimal representation to stdout\n", stdout); | |
| 172 fputs( " -e, --ecinos Display ECI (Extended Channel Interpretation) table\n" | |
| 173 " --eci=INTEGER Set the ECI code for the data (segment 0)\n" | |
| 174 " --embedfont Embed font in vector output (SVG only)\n" | |
| 175 " --esc Process escape sequences in input data\n" | |
| 176 " --extraesc Process symbology-specific escape sequences (Code 128)\n", stdout); | |
| 177 fputs( " --fast Use faster encodation or other shortcuts if available\n" | |
| 178 " --fg=COLOUR Specify a foreground colour (as RGB(A) or \"C,M,Y,K\")\n", stdout); | |
| 179 printf(" --filetype=TYPE Set output file type BMP/EMF/EPS/GIF/PCX%s/SVG/TIF/TXT\n", no_png_type); | |
| 180 fputs( " --fullmultibyte Use multibyte for binary/Latin (QR/Han Xin/Grid Matrix)\n" | |
| 181 " --gs1 Treat input as GS1 compatible data\n" | |
| 182 " --gs1nocheck Do not check validity of GS1 data\n" | |
| 183 " --gs1parens Process parentheses \"()\" as GS1 AI delimiters, not \"[]\"\n" | |
| 184 " --gssep Use separator GS for GS1 (Data Matrix)\n", stdout); | |
| 185 fputs( " --guarddescent=NUMBER Set height of guard bar descent in X-dims (EAN/UPC)\n" | |
| 186 " --guardwhitespace Add quiet zone indicators (\"<\"/\">\") to HRT (EAN/UPC)\n" | |
| 187 " -h, --help Display help message\n" | |
| 188 " --height=NUMBER Set height of symbol in multiples of X-dimension\n" | |
| 189 " --heightperrow Treat height as per-row\n", stdout); | |
| 190 fputs( " -i, --input=FILE Read input data from FILE\n" | |
| 191 " --init Create Reader Initialisation (Programming) symbol\n" | |
| 192 " --mask=INTEGER Set masking pattern to use (QR/Han Xin/DotCode)\n" | |
| 193 " --mirror Use batch data to determine filename\n" | |
| 194 " --mode=INTEGER Set encoding mode (MaxiCode/Composite)\n", stdout); | |
| 195 printf(" --nobackground Remove background (EMF/EPS/GIF%s/SVG/TIF only)\n", no_png_type); | |
| 196 fputs( " --noquietzones Disable default quiet zones\n" | |
| 197 " --notext Remove human readable text (HRT)\n", stdout); | |
| 198 printf(" -o, --output=FILE Send output to FILE. Default is out.%s\n", no_png_ext); | |
| 199 fputs( " --primary=STRING Set primary message (MaxiCode/Composite)\n" | |
| 200 " --quietzones Add compliant quiet zones\n" | |
| 201 " -r, --reverse Reverse colours (white on black)\n" | |
| 202 " --rotate=INTEGER Rotate symbol by INTEGER (0, 90, 180, 270) degrees\n" | |
| 203 " --rows=INTEGER Set number of rows (Codablock-F/PDF417)\n", stdout); | |
| 204 fputs( " --scale=NUMBER Adjust size of X-dimension\n" | |
| 205 " --scalexdimdp=X[,R] Adjust size to X-dimension X at resolution R\n" | |
| 206 " --scmvv=INTEGER Prefix SCM with \"[)>\\R01\\Gvv\" (vv is INTEGER) (MaxiCode)\n" | |
| 207 " --secure=INTEGER Set error correction level (ECC)\n" | |
| 208 " --segN=ECI,DATA Set the ECI & data content for segment N, where N 1 to 9\n", stdout); | |
| 209 fputs( " --separator=INTEGER Set height of row separator bars (stacked symbologies)\n" | |
| 210 " --small Use small text (HRT)\n" | |
| 211 " --square Force Data Matrix symbols to be square\n" | |
| 212 " --structapp=I,C[,ID] Set Structured Append info (I index, C count)\n" | |
| 213 " -t, --types Display table of barcode types\n", stdout); | |
| 214 fputs( " --textgap=NUMBER Adjust gap between barcode and HRT in multiples of X-dim\n" | |
| 215 " --vers=INTEGER Set symbol version (size, check digits, other options)\n" | |
| 216 " -v, --version Display Zint version\n" | |
| 217 " --vwhitesp=INTEGER Set height of vertical whitespace in multiples of X-dim\n" | |
| 218 " -w, --whitesp=INTEGER Set width of horizontal whitespace in multiples of X-dim\n", stdout); | |
| 219 fputs( " --werror Convert all warnings into errors\n", stdout); | |
| 220 } | |
| 221 | |
| 222 /* Display supported ECI codes */ | |
| 223 static void show_eci(void) { | |
| 224 /* Breaking up strings so don't get too long (i.e. 500 or so) */ | |
| 225 fputs(" 3: ISO/IEC 8859-1 - Latin alphabet No. 1 (default)\n" | |
| 226 " 4: ISO/IEC 8859-2 - Latin alphabet No. 2\n" | |
| 227 " 5: ISO/IEC 8859-3 - Latin alphabet No. 3\n" | |
| 228 " 6: ISO/IEC 8859-4 - Latin alphabet No. 4\n" | |
| 229 " 7: ISO/IEC 8859-5 - Latin/Cyrillic alphabet\n", stdout); | |
| 230 fputs(" 8: ISO/IEC 8859-6 - Latin/Arabic alphabet\n" | |
| 231 " 9: ISO/IEC 8859-7 - Latin/Greek alphabet\n" | |
| 232 " 10: ISO/IEC 8859-8 - Latin/Hebrew alphabet\n" | |
| 233 " 11: ISO/IEC 8859-9 - Latin alphabet No. 5 (Turkish)\n" | |
| 234 " 12: ISO/IEC 8859-10 - Latin alphabet No. 6 (Nordic)\n", stdout); | |
| 235 fputs(" 13: ISO/IEC 8859-11 - Latin/Thai alphabet\n" | |
| 236 " 15: ISO/IEC 8859-13 - Latin alphabet No. 7 (Baltic)\n" | |
| 237 " 16: ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic)\n" | |
| 238 " 17: ISO/IEC 8859-15 - Latin alphabet No. 9\n" | |
| 239 " 18: ISO/IEC 8859-16 - Latin alphabet No. 10\n", stdout); | |
| 240 fputs(" 20: Shift JIS (JIS X 0208 and JIS X 0201)\n" | |
| 241 " 21: Windows 1250 - Latin 2 (Central Europe)\n" | |
| 242 " 22: Windows 1251 - Cyrillic\n" | |
| 243 " 23: Windows 1252 - Latin 1\n" | |
| 244 " 24: Windows 1256 - Arabic\n", stdout); | |
| 245 fputs(" 25: UTF-16BE (High order byte first)\n" | |
| 246 " 26: UTF-8\n" | |
| 247 " 27: ASCII (ISO/IEC 646 IRV)\n" | |
| 248 " 28: Big5 (Taiwan) Chinese Character Set\n" | |
| 249 " 29: GB 2312 (PRC) Chinese Character Set\n", stdout); | |
| 250 fputs(" 30: Korean Character Set EUC-KR (KS X 1001:2002)\n" | |
| 251 " 31: GBK Chinese Character Set\n" | |
| 252 " 32: GB 18030 Chinese Character Set\n" | |
| 253 " 33: UTF-16LE (Low order byte first)\n" | |
| 254 " 34: UTF-32BE (High order bytes first)\n", stdout); | |
| 255 fputs(" 35: UTF-32LE (Low order bytes first)\n" | |
| 256 "170: ISO/IEC 646 Invariant (ASCII subset)\n" | |
| 257 "899: 8-bit binary data\n", stdout); | |
| 258 } | |
| 259 | |
| 260 /* Verifies that a string (length <= 9) only uses digits. On success returns value in arg */ | |
| 261 static int validate_int(const char source[], int len, int *p_val) { | |
| 262 int val = 0; | |
| 263 int i; | |
| 264 const int length = len == -1 ? (int) strlen(source) : len; | |
| 265 | |
| 266 if (length > 9) { /* Prevent overflow */ | |
| 267 return 0; | |
| 268 } | |
| 269 for (i = 0; i < length; i++) { | |
| 270 if (source[i] < '0' || source[i] > '9') { | |
| 271 return 0; | |
| 272 } | |
| 273 val *= 10; | |
| 274 val += source[i] - '0'; | |
| 275 } | |
| 276 *p_val = val; | |
| 277 | |
| 278 return 1; | |
| 279 } | |
| 280 | |
| 281 /* Verifies that a string is a simplified form of floating point, max 7 significant decimal digits with | |
| 282 optional decimal point. On success returns val in arg. On failure sets `errbuf` */ | |
| 283 static int validate_float(const char source[], const int allow_neg, float *p_val, char errbuf[64]) { | |
| 284 static const float fract_muls[7] = { 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f }; | |
| 285 int val = 0; | |
| 286 int neg = 0; | |
| 287 const char *dot = strchr(source, '.'); | |
| 288 int int_len; | |
| 289 | |
| 290 if (*source == '+' || *source == '-') { | |
| 291 if (*source == '-') { | |
| 292 if (!allow_neg) { | |
| 293 strcpy(errbuf, "negative value not permitted"); | |
| 294 return 0; | |
| 295 } | |
| 296 neg = 1; | |
| 297 } | |
| 298 source++; | |
| 299 } | |
| 300 | |
| 301 int_len = dot ? (int) (dot - source) : (int) strlen(source); | |
| 302 if (int_len > 9) { | |
| 303 strcpy(errbuf, "integer part must be 7 digits maximum"); /* Say 7 not 9 to "manage expections" */ | |
| 304 return 0; | |
| 305 } | |
| 306 if (int_len) { | |
| 307 int tmp_val; | |
| 308 if (!validate_int(source, int_len, &val)) { | |
| 309 strcpy(errbuf, "integer part must be digits only"); | |
| 310 return 0; | |
| 311 } | |
| 312 for (int_len = 0, tmp_val = val; tmp_val; tmp_val /= 10, int_len++); /* log10(val) */ | |
| 313 if (int_len > 7) { | |
| 314 strcpy(errbuf, "integer part must be 7 digits maximum"); | |
| 315 return 0; | |
| 316 } | |
| 317 } | |
| 318 if (dot && *++dot) { | |
| 319 int val2, fract_len; | |
| 320 const char *e; | |
| 321 for (e = dot + strlen(dot) - 1; e > dot && *e == '0'; e--); /* Ignore trailing zeroes */ | |
| 322 fract_len = (int) (e + 1 - dot); | |
| 323 if (fract_len) { | |
| 324 if (fract_len > 7) { | |
| 325 strcpy(errbuf, "fractional part must be 7 digits maximum"); | |
| 326 return 0; | |
| 327 } | |
| 328 if (!validate_int(dot, fract_len, &val2)) { | |
| 329 strcpy(errbuf, "fractional part must be digits only"); | |
| 330 return 0; | |
| 331 } | |
| 332 if (val2 && int_len + fract_len > 7) { | |
| 333 if (val) { | |
| 334 strcpy(errbuf, "7 significant digits maximum"); | |
| 335 } else { | |
| 336 strcpy(errbuf, "fractional part must be 7 digits maximum"); | |
| 337 } | |
| 338 return 0; | |
| 339 } | |
| 340 *p_val = val + val2 * fract_muls[fract_len - 1]; | |
| 341 } else { | |
| 342 *p_val = (float) val; | |
| 343 } | |
| 344 } else { | |
| 345 *p_val = (float) val; | |
| 346 } | |
| 347 if (neg) { | |
| 348 *p_val = -*p_val; | |
| 349 } | |
| 350 return 1; | |
| 351 } | |
| 352 | |
| 353 /* Converts upper case characters to lower case in a string source[] */ | |
| 354 static void to_lower(char source[]) { | |
| 355 int i; | |
| 356 const int src_len = (int) strlen(source); | |
| 357 | |
| 358 for (i = 0; i < src_len; i++) { | |
| 359 if ((source[i] >= 'A') && (source[i] <= 'Z')) { | |
| 360 source[i] |= 0x20; | |
| 361 } | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 /* Return symbology id if `barcode_name` a barcode name */ | |
| 366 static int get_barcode_name(const char *barcode_name) { | |
| 367 /* Must be sorted for binary search to work */ | |
| 368 static const struct { int symbology; const char *n; } names[] = { | |
| 369 { BARCODE_C25LOGIC, "2of5datalogic" }, /* Synonym */ | |
| 370 { BARCODE_C25IATA, "2of5iata" }, /* Synonym */ | |
| 371 { BARCODE_C25IND, "2of5ind" }, /* Synonym */ | |
| 372 { BARCODE_C25IND, "2of5industrial" }, /* Synonym */ | |
| 373 { BARCODE_C25INTER, "2of5inter" }, /* Synonym */ | |
| 374 { BARCODE_C25INTER, "2of5interleaved" }, /* Synonym */ | |
| 375 { BARCODE_C25LOGIC, "2of5logic" }, /* Synonym */ | |
| 376 { BARCODE_C25STANDARD, "2of5matrix" }, /* Synonym */ | |
| 377 { BARCODE_C25STANDARD, "2of5standard" }, /* Synonym */ | |
| 378 { BARCODE_AUSPOST, "auspost" }, | |
| 379 { BARCODE_AUSREDIRECT, "ausredirect" }, | |
| 380 { BARCODE_AUSREPLY, "ausreply" }, | |
| 381 { BARCODE_AUSROUTE, "ausroute" }, | |
| 382 { BARCODE_AZRUNE, "azrune" }, | |
| 383 { BARCODE_AZTEC, "aztec" }, | |
| 384 { BARCODE_AZTEC, "azteccode" }, /* Synonym */ | |
| 385 { BARCODE_AZRUNE, "aztecrune" }, /* Synonym */ | |
| 386 { BARCODE_AZRUNE, "aztecrunes" }, /* Synonym */ | |
| 387 { BARCODE_BC412, "bc412" }, | |
| 388 { BARCODE_C25LOGIC, "c25datalogic" }, /* Synonym */ | |
| 389 { BARCODE_C25IATA, "c25iata" }, | |
| 390 { BARCODE_C25IND, "c25ind" }, | |
| 391 { BARCODE_C25IND, "c25industrial" }, /* Synonym */ | |
| 392 { BARCODE_C25INTER, "c25inter" }, | |
| 393 { BARCODE_C25INTER, "c25interleaved" }, /* Synonym */ | |
| 394 { BARCODE_C25LOGIC, "c25logic" }, | |
| 395 { BARCODE_C25STANDARD, "c25matrix" }, | |
| 396 { BARCODE_C25STANDARD, "c25standard" }, | |
| 397 { BARCODE_CEPNET, "cepnet" }, | |
| 398 { BARCODE_CHANNEL, "channel" }, | |
| 399 { BARCODE_CHANNEL, "channelcode" }, /* Synonym */ | |
| 400 { BARCODE_CODABAR, "codabar" }, | |
| 401 { BARCODE_CODABLOCKF, "codablockf" }, | |
| 402 { BARCODE_CODE11, "code11" }, | |
| 403 { BARCODE_CODE128, "code128" }, | |
| 404 { BARCODE_CODE128AB, "code128ab" }, | |
| 405 { BARCODE_CODE128AB, "code128b" }, /* Synonym */ | |
| 406 { BARCODE_CODE16K, "code16k" }, | |
| 407 { BARCODE_C25LOGIC, "code2of5datalogic" }, /* Synonym */ | |
| 408 { BARCODE_C25IATA, "code2of5iata" }, /* Synonym */ | |
| 409 { BARCODE_C25IND, "code2of5ind" }, /* Synonym */ | |
| 410 { BARCODE_C25IND, "code2of5industrial" }, /* Synonym */ | |
| 411 { BARCODE_C25INTER, "code2of5inter" }, /* Synonym */ | |
| 412 { BARCODE_C25INTER, "code2of5interleaved" }, /* Synonym */ | |
| 413 { BARCODE_C25LOGIC, "code2of5logic" }, /* Synonym */ | |
| 414 { BARCODE_C25STANDARD, "code2of5matrix" }, /* Synonym */ | |
| 415 { BARCODE_C25STANDARD, "code2of5standard" }, /* Synonym */ | |
| 416 { BARCODE_CODE32, "code32" }, | |
| 417 { BARCODE_CODE39, "code39" }, | |
| 418 { BARCODE_CODE49, "code49" }, | |
| 419 { BARCODE_CODE93, "code93" }, | |
| 420 { BARCODE_CODEONE, "codeone" }, | |
| 421 { BARCODE_DAFT, "daft" }, | |
| 422 { BARCODE_DBAR_EXP, "databarexp" }, /* Synonym */ | |
| 423 { BARCODE_DBAR_EXP, "databarexpanded" }, /* Synonym */ | |
| 424 { BARCODE_DBAR_EXP_CC, "databarexpandedcc" }, /* Synonym */ | |
| 425 { BARCODE_DBAR_EXPSTK, "databarexpandedstacked" }, /* Synonym */ | |
| 426 { BARCODE_DBAR_EXPSTK_CC, "databarexpandedstackedcc" }, /* Synonym */ | |
| 427 { BARCODE_DBAR_EXPSTK, "databarexpandedstk" }, /* Synonym */ | |
| 428 { BARCODE_DBAR_EXPSTK_CC, "databarexpandedstkcc" }, /* Synonym */ | |
| 429 { BARCODE_DBAR_EXP_CC, "databarexpcc" }, /* Synonym */ | |
| 430 { BARCODE_DBAR_EXPSTK, "databarexpstk" }, /* Synonym */ | |
| 431 { BARCODE_DBAR_EXPSTK_CC, "databarexpstkcc" }, /* Synonym */ | |
| 432 { BARCODE_DBAR_LTD, "databarlimited" }, /* Synonym */ | |
| 433 { BARCODE_DBAR_LTD_CC, "databarlimitedcc" }, /* Synonym */ | |
| 434 { BARCODE_DBAR_LTD, "databarltd" }, /* Synonym */ | |
| 435 { BARCODE_DBAR_LTD_CC, "databarltdcc" }, /* Synonym */ | |
| 436 { BARCODE_DBAR_OMN, "databaromn" }, /* Synonym */ | |
| 437 { BARCODE_DBAR_OMN_CC, "databaromncc" }, /* Synonym */ | |
| 438 { BARCODE_DBAR_OMN, "databaromni" }, /* Synonym */ | |
| 439 { BARCODE_DBAR_OMN_CC, "databaromnicc" }, /* Synonym */ | |
| 440 { BARCODE_DBAR_OMNSTK, "databaromnstk" }, /* Synonym */ | |
| 441 { BARCODE_DBAR_OMNSTK_CC, "databaromnstkcc" }, /* Synonym */ | |
| 442 { BARCODE_DBAR_STK, "databarstacked" }, /* Synonym */ | |
| 443 { BARCODE_DBAR_STK_CC, "databarstackedcc" }, /* Synonym */ | |
| 444 { BARCODE_DBAR_OMNSTK, "databarstackedomn" }, /* Synonym */ | |
| 445 { BARCODE_DBAR_OMNSTK_CC, "databarstackedomncc" }, /* Synonym */ | |
| 446 { BARCODE_DBAR_OMNSTK, "databarstackedomni" }, /* Synonym */ | |
| 447 { BARCODE_DBAR_OMNSTK_CC, "databarstackedomnicc" }, /* Synonym */ | |
| 448 { BARCODE_DBAR_STK, "databarstk" }, /* Synonym */ | |
| 449 { BARCODE_DBAR_STK_CC, "databarstkcc" }, /* Synonym */ | |
| 450 { BARCODE_DATAMATRIX, "datamatrix" }, | |
| 451 { BARCODE_DBAR_EXP, "dbarexp" }, | |
| 452 { BARCODE_DBAR_EXP, "dbarexpanded" }, /* Synonym */ | |
| 453 { BARCODE_DBAR_EXP_CC, "dbarexpandedcc" }, /* Synonym */ | |
| 454 { BARCODE_DBAR_EXPSTK, "dbarexpandedstacked" }, /* Synonym */ | |
| 455 { BARCODE_DBAR_EXPSTK_CC, "dbarexpandedstackedcc" }, /* Synonym */ | |
| 456 { BARCODE_DBAR_EXPSTK, "dbarexpandedstk" }, /* Synonym */ | |
| 457 { BARCODE_DBAR_EXPSTK_CC, "dbarexpandedstkcc" }, /* Synonym */ | |
| 458 { BARCODE_DBAR_EXP_CC, "dbarexpcc" }, | |
| 459 { BARCODE_DBAR_EXPSTK, "dbarexpstk" }, | |
| 460 { BARCODE_DBAR_EXPSTK_CC, "dbarexpstkcc" }, | |
| 461 { BARCODE_DBAR_LTD, "dbarlimited" }, /* Synonym */ | |
| 462 { BARCODE_DBAR_LTD_CC, "dbarlimitedcc" }, /* Synonym */ | |
| 463 { BARCODE_DBAR_LTD, "dbarltd" }, | |
| 464 { BARCODE_DBAR_LTD_CC, "dbarltdcc" }, | |
| 465 { BARCODE_DBAR_OMN, "dbaromn" }, | |
| 466 { BARCODE_DBAR_OMN_CC, "dbaromncc" }, | |
| 467 { BARCODE_DBAR_OMN, "dbaromni" }, /* Synonym */ | |
| 468 { BARCODE_DBAR_OMN_CC, "dbaromnicc" }, /* Synonym */ | |
| 469 { BARCODE_DBAR_OMNSTK, "dbaromnstk" }, | |
| 470 { BARCODE_DBAR_OMNSTK_CC, "dbaromnstkcc" }, | |
| 471 { BARCODE_DBAR_STK, "dbarstacked" }, /* Synonym */ | |
| 472 { BARCODE_DBAR_STK_CC, "dbarstackedcc" }, /* Synonym */ | |
| 473 { BARCODE_DBAR_OMNSTK, "dbarstackedomn" }, /* Synonym */ | |
| 474 { BARCODE_DBAR_OMNSTK_CC, "dbarstackedomncc" }, /* Synonym */ | |
| 475 { BARCODE_DBAR_OMNSTK, "dbarstackedomni" }, /* Synonym */ | |
| 476 { BARCODE_DBAR_OMNSTK_CC, "dbarstackedomnicc" }, /* Synonym */ | |
| 477 { BARCODE_DBAR_STK, "dbarstk" }, | |
| 478 { BARCODE_DBAR_STK_CC, "dbarstkcc" }, | |
| 479 { BARCODE_DOTCODE, "dotcode" }, | |
| 480 { BARCODE_DPD, "dpd" }, | |
| 481 { BARCODE_DPIDENT, "dpident" }, | |
| 482 { BARCODE_DPLEIT, "dpleit" }, | |
| 483 { BARCODE_DXFILMEDGE, "dxfilmedge" }, | |
| 484 { BARCODE_EANX, "ean" }, /* Synonym */ | |
| 485 { BARCODE_GS1_128, "ean128" }, /* Synonym */ | |
| 486 { BARCODE_GS1_128_CC, "ean128cc" }, /* Synonym */ | |
| 487 { BARCODE_EAN14, "ean14" }, | |
| 488 { BARCODE_EANX_CC, "eancc" }, /* Synonym */ | |
| 489 { BARCODE_EANX_CHK, "eanchk" }, /* Synonym */ | |
| 490 { BARCODE_EANX, "eanx" }, | |
| 491 { BARCODE_EANX_CC, "eanxcc" }, | |
| 492 { BARCODE_EANX_CHK, "eanxchk" }, | |
| 493 { BARCODE_EXCODE39, "excode39" }, | |
| 494 { BARCODE_EXCODE39, "extendedcode39" }, /* Synonym */ | |
| 495 { BARCODE_FIM, "fim" }, | |
| 496 { BARCODE_FLAT, "flat" }, | |
| 497 { BARCODE_GRIDMATRIX, "gridmatrix" }, | |
| 498 { BARCODE_GS1_128, "gs1128" }, | |
| 499 { BARCODE_GS1_128_CC, "gs1128cc" }, | |
| 500 { BARCODE_HANXIN, "hanxin" }, | |
| 501 { BARCODE_HIBC_128, "hibc128" }, | |
| 502 { BARCODE_HIBC_39, "hibc39" }, | |
| 503 { BARCODE_HIBC_AZTEC, "hibcaztec" }, | |
| 504 { BARCODE_HIBC_BLOCKF, "hibcblockf" }, | |
| 505 { BARCODE_HIBC_BLOCKF, "hibccodablockf" }, /* Synonym */ | |
| 506 { BARCODE_HIBC_128, "hibccode128" }, /* Synonym */ | |
| 507 { BARCODE_HIBC_39, "hibccode39" }, /* Synonym */ | |
| 508 { BARCODE_HIBC_DM, "hibcdatamatrix" }, /* Synonym */ | |
| 509 { BARCODE_HIBC_DM, "hibcdm" }, | |
| 510 { BARCODE_HIBC_MICPDF, "hibcmicpdf" }, | |
| 511 { BARCODE_HIBC_MICPDF, "hibcmicropdf" }, /* Synonym */ | |
| 512 { BARCODE_HIBC_MICPDF, "hibcmicropdf417" }, /* Synonym */ | |
| 513 { BARCODE_HIBC_PDF, "hibcpdf" }, | |
| 514 { BARCODE_HIBC_PDF, "hibcpdf417" }, /* Synonym */ | |
| 515 { BARCODE_HIBC_QR, "hibcqr" }, | |
| 516 { BARCODE_HIBC_QR, "hibcqrcode" }, /* Synonym */ | |
| 517 { BARCODE_C25IATA, "iata2of5" }, /* Synonym */ | |
| 518 { BARCODE_C25IATA, "iatacode2of5" }, /* Synonym */ | |
| 519 { BARCODE_C25IND, "industrial2of5" }, /* Synonym */ | |
| 520 { BARCODE_C25IND, "industrialcode2of5" }, /* Synonym */ | |
| 521 { BARCODE_C25INTER, "interleaved2of5" }, /* Synonym */ | |
| 522 { BARCODE_C25INTER, "interleavedcode2of5" }, /* Synonym */ | |
| 523 { BARCODE_ISBNX, "isbn" }, /* Synonym */ | |
| 524 { BARCODE_ISBNX, "isbnx" }, | |
| 525 { BARCODE_ITF14, "itf14" }, | |
| 526 { BARCODE_JAPANPOST, "japanpost" }, | |
| 527 { BARCODE_KIX, "kix" }, | |
| 528 { BARCODE_KOREAPOST, "koreapost" }, | |
| 529 { BARCODE_LOGMARS, "logmars" }, | |
| 530 { BARCODE_MAILMARK_4S, "mailmark" }, /* Synonym */ | |
| 531 { BARCODE_MAILMARK_2D, "mailmark2d" }, | |
| 532 { BARCODE_MAILMARK_4S, "mailmark4s" }, | |
| 533 { BARCODE_MAILMARK_4S, "mailmark4state" }, /* Synonym */ | |
| 534 { BARCODE_MAXICODE, "maxicode" }, | |
| 535 { BARCODE_MICROPDF417, "micropdf417" }, | |
| 536 { BARCODE_MICROQR, "microqr" }, | |
| 537 { BARCODE_MICROQR, "microqrcode" }, /* Synonym */ | |
| 538 { BARCODE_MSI_PLESSEY, "msi" }, /* Synonym */ | |
| 539 { BARCODE_MSI_PLESSEY, "msiplessey" }, | |
| 540 { BARCODE_NVE18, "nve18" }, | |
| 541 { BARCODE_USPS_IMAIL, "onecode" }, /* Synonym */ | |
| 542 { BARCODE_PDF417, "pdf417" }, | |
| 543 { BARCODE_PDF417COMP, "pdf417comp" }, | |
| 544 { BARCODE_PDF417COMP, "pdf417trunc" }, /* Synonym */ | |
| 545 { BARCODE_PHARMA, "pharma" }, | |
| 546 { BARCODE_PHARMA_TWO, "pharmatwo" }, | |
| 547 { BARCODE_PLANET, "planet" }, | |
| 548 { BARCODE_PLESSEY, "plessey" }, | |
| 549 { BARCODE_POSTNET, "postnet" }, | |
| 550 { BARCODE_PZN, "pzn" }, | |
| 551 { BARCODE_QRCODE, "qr" }, /* Synonym */ | |
| 552 { BARCODE_QRCODE, "qrcode" }, | |
| 553 { BARCODE_RM4SCC, "rm4scc" }, | |
| 554 { BARCODE_RMQR, "rmqr" }, | |
| 555 { BARCODE_DBAR_OMN, "rss14" }, /* Synonym */ | |
| 556 { BARCODE_DBAR_OMN_CC, "rss14cc" }, /* Synonym */ | |
| 557 { BARCODE_DBAR_OMNSTK_CC, "rss14omnicc" }, /* Synonym */ | |
| 558 { BARCODE_DBAR_STK, "rss14stack" }, /* Synonym */ | |
| 559 { BARCODE_DBAR_STK_CC, "rss14stackcc" }, /* Synonym */ | |
| 560 { BARCODE_DBAR_OMNSTK, "rss14stackomni" }, /* Synonym */ | |
| 561 { BARCODE_DBAR_EXP, "rssexp" }, /* Synonym */ | |
| 562 { BARCODE_DBAR_EXP_CC, "rssexpcc" }, /* Synonym */ | |
| 563 { BARCODE_DBAR_EXPSTK, "rssexpstack" }, /* Synonym */ | |
| 564 { BARCODE_DBAR_EXPSTK_CC, "rssexpstackcc" }, /* Synonym */ | |
| 565 { BARCODE_DBAR_LTD, "rssltd" }, /* Synonym */ | |
| 566 { BARCODE_DBAR_LTD_CC, "rssltdcc" }, /* Synonym */ | |
| 567 { BARCODE_C25STANDARD, "standardcode2of5" }, /* Synonym */ | |
| 568 { BARCODE_TELEPEN, "telepen" }, | |
| 569 { BARCODE_TELEPEN_NUM, "telepennum" }, | |
| 570 { BARCODE_ULTRA, "ultra" }, | |
| 571 { BARCODE_ULTRA, "ultracode" }, /* Synonym */ | |
| 572 { BARCODE_UPCA, "upca" }, | |
| 573 { BARCODE_UPCA_CC, "upcacc" }, | |
| 574 { BARCODE_UPCA_CHK, "upcachk" }, | |
| 575 { BARCODE_UPCE, "upce" }, | |
| 576 { BARCODE_UPCE_CC, "upcecc" }, | |
| 577 { BARCODE_UPCE_CHK, "upcechk" }, | |
| 578 { BARCODE_UPNQR, "upnqr" }, | |
| 579 { BARCODE_UPNQR, "upnqrcode" }, /* Synonym */ | |
| 580 { BARCODE_UPU_S10, "upus10" }, | |
| 581 { BARCODE_USPS_IMAIL, "uspsimail" }, | |
| 582 { BARCODE_VIN, "vin" }, | |
| 583 }; | |
| 584 int s = 0, e = ARRAY_SIZE(names) - 1; | |
| 585 | |
| 586 char n[30] = {0}; | |
| 587 int i, j, length; | |
| 588 | |
| 589 /* Ignore case and any "BARCODE" prefix */ | |
| 590 strncpy(n, barcode_name, 29); | |
| 591 to_lower(n); | |
| 592 length = (int) strlen(n); | |
| 593 if (strncmp(n, "barcode", 7) == 0) { | |
| 594 memmove(n, n + 7, length - 7 + 1); /* Include NUL char */ | |
| 595 length = (int) strlen(n); | |
| 596 } | |
| 597 | |
| 598 /* Ignore any non-alphanumeric characters */ | |
| 599 for (i = 0, j = 0; i < length; i++) { | |
| 600 if ((n[i] >= 'a' && n[i] <= 'z') || (n[i] >= '0' && n[i] <= '9')) { | |
| 601 n[j++] = n[i]; | |
| 602 } | |
| 603 } | |
| 604 if (j == 0) { | |
| 605 return 0; | |
| 606 } | |
| 607 n[j] = '\0'; | |
| 608 | |
| 609 while (s <= e) { | |
| 610 const int m = (s + e) / 2; | |
| 611 const int cmp = strcmp(names[m].n, n); | |
| 612 if (cmp < 0) { | |
| 613 s = m + 1; | |
| 614 } else if (cmp > 0) { | |
| 615 e = m - 1; | |
| 616 } else { | |
| 617 return names[m].symbology; | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 return 0; | |
| 622 } | |
| 623 | |
| 624 /* Whether `filetype` supported by Zint. Sets `png_refused` if `no_png` and PNG requested */ | |
| 625 static int supported_filetype(const char *filetype, const int no_png, int *png_refused) { | |
| 626 static const char filetypes[][4] = { | |
| 627 "bmp", "emf", "eps", "gif", "pcx", "png", "svg", "tif", "txt", | |
| 628 }; | |
| 629 char lc_filetype[4] = {0}; | |
| 630 int i; | |
| 631 | |
| 632 if (png_refused) { | |
| 633 *png_refused = 0; | |
| 634 } | |
| 635 strncpy(lc_filetype, filetype, 3); | |
| 636 to_lower(lc_filetype); | |
| 637 | |
| 638 if (no_png && strcmp(lc_filetype, "png") == 0) { | |
| 639 if (png_refused) { | |
| 640 *png_refused = 1; | |
| 641 } | |
| 642 return 0; | |
| 643 } | |
| 644 | |
| 645 for (i = 0; i < ARRAY_SIZE(filetypes); i++) { | |
| 646 if (strcmp(lc_filetype, filetypes[i]) == 0) { | |
| 647 return 1; | |
| 648 } | |
| 649 } | |
| 650 return 0; | |
| 651 } | |
| 652 | |
| 653 /* Get file extension, excluding those of 4 or more letters */ | |
| 654 static char *get_extension(const char *file) { | |
| 655 char *dot; | |
| 656 | |
| 657 dot = strrchr(file, '.'); | |
| 658 if (dot && strlen(file) - (dot - file) <= 4) { /* Only recognize up to 3 letter extensions */ | |
| 659 return dot + 1; | |
| 660 } | |
| 661 return NULL; | |
| 662 } | |
| 663 | |
| 664 /* Set extension of `file` to `filetype`, replacing existing extension if any. | |
| 665 * Does nothing if file already has `filetype` extension */ | |
| 666 static void set_extension(char *file, const char *filetype) { | |
| 667 char lc_filetype[4] = {0}; | |
| 668 char *extension; | |
| 669 char lc_extension[4]; | |
| 670 | |
| 671 strncpy(lc_filetype, filetype, 3); | |
| 672 to_lower(lc_filetype); | |
| 673 | |
| 674 extension = get_extension(file); | |
| 675 if (extension) { | |
| 676 strcpy(lc_extension, extension); | |
| 677 to_lower(lc_extension); | |
| 678 if (strcmp(lc_filetype, lc_extension) == 0) { | |
| 679 return; | |
| 680 } | |
| 681 *(extension - 1) = '\0'; /* Cut off at dot */ | |
| 682 } | |
| 683 if (strlen(file) > 251) { | |
| 684 file[251] = '\0'; | |
| 685 } | |
| 686 strcat(file, "."); | |
| 687 strncat(file, filetype, 3); | |
| 688 } | |
| 689 | |
| 690 /* Whether `filetype` is raster type */ | |
| 691 static int is_raster(const char *filetype, const int no_png) { | |
| 692 static const char raster_filetypes[][4] = { | |
| 693 "bmp", "gif", "pcx", "png", "tif", | |
| 694 }; | |
| 695 int i; | |
| 696 char lc_filetype[4] = {0}; | |
| 697 | |
| 698 if (filetype == NULL) { | |
| 699 return 0; | |
| 700 } | |
| 701 strcpy(lc_filetype, filetype); | |
| 702 to_lower(lc_filetype); | |
| 703 | |
| 704 if (no_png && strcmp(lc_filetype, "png") == 0) { | |
| 705 return 0; | |
| 706 } | |
| 707 | |
| 708 for (i = 0; i < ARRAY_SIZE(raster_filetypes); i++) { | |
| 709 if (strcmp(lc_filetype, raster_filetypes[i]) == 0) { | |
| 710 return 1; | |
| 711 } | |
| 712 } | |
| 713 return 0; | |
| 714 } | |
| 715 | |
| 716 /* Helper for `validate_scalexdimdp()` to search for units, returning -2 on error, -1 if not found, else index */ | |
| 717 static int validate_units(char *buf, const char units[][5], int units_size) { | |
| 718 int i; | |
| 719 char *unit; | |
| 720 | |
| 721 to_lower(buf); | |
| 722 for (i = 0; i < units_size; i++) { | |
| 723 if ((unit = strstr(buf, units[i])) != NULL) { | |
| 724 if (strlen(units[i]) != strlen(unit)) { | |
| 725 return -2; | |
| 726 } | |
| 727 *unit = '\0'; | |
| 728 break; | |
| 729 } | |
| 730 } | |
| 731 if (i == units_size) { | |
| 732 i = -1; | |
| 733 } | |
| 734 return i; | |
| 735 } | |
| 736 | |
| 737 /* Parse and validate argument "xdim[,resolution]" to "--scalexdimdp" */ | |
| 738 static int validate_scalexdimdp(const char *arg, float *p_x_dim_mm, float *p_dpmm) { | |
| 739 static const char x_units[][5] = { "mm", "in" }; | |
| 740 static const char r_units[][5] = { "dpmm", "dpi" }; | |
| 741 char x_buf[7 + 1 + 4 + 1] = {0}; /* Allow for 7 digits + dot + 4-char unit + NUL */ | |
| 742 char r_buf[7 + 1 + 4 + 1] = {0}; /* As above */ | |
| 743 int units_i; /* For `validate_units()` */ | |
| 744 char errbuf[64]; /* For `validate_float()` */ | |
| 745 const char *comma = strchr(arg, ','); | |
| 746 if (comma) { | |
| 747 if (comma == arg || comma - arg >= ARRAY_SIZE(x_buf)) { | |
| 748 fprintf(stderr, "Error 174: scalexdimdp X-dim too %s\n", comma == arg ? "short" : "long"); | |
| 749 return 0; | |
| 750 } | |
| 751 strncpy(x_buf, arg, comma - arg); | |
| 752 comma++; | |
| 753 if (!*comma || strlen(comma) >= ARRAY_SIZE(r_buf)) { | |
| 754 fprintf(stderr, "Error 175: scalexdimdp resolution too %s\n", !*comma ? "short" : "long"); | |
| 755 return 0; | |
| 756 } | |
| 757 strcpy(r_buf, comma); | |
| 758 } else { | |
| 759 if (!*arg || strlen(arg) >= ARRAY_SIZE(x_buf)) { | |
| 760 fprintf(stderr, "Error 176: scalexdimdp X-dim too %s\n", !*arg ? "short" : "long"); | |
| 761 return 0; | |
| 762 } | |
| 763 strcpy(x_buf, arg); | |
| 764 } | |
| 765 if ((units_i = validate_units(x_buf, x_units, ARRAY_SIZE(x_units))) == -2) { | |
| 766 fprintf(stderr, "Error 177: scalexdimdp X-dim units must occur at end\n"); | |
| 767 return 0; | |
| 768 } | |
| 769 if (!validate_float(x_buf, 0 /*allow_neg*/, p_x_dim_mm, errbuf)) { | |
| 770 fprintf(stderr, "Error 178: scalexdimdp X-dim invalid floating point (%s)\n", errbuf); | |
| 771 return 0; | |
| 772 } | |
| 773 if (units_i > 0) { /* Ignore mm */ | |
| 774 *p_x_dim_mm /= 25.4f /*in*/; | |
| 775 } | |
| 776 *p_dpmm = 0.0f; | |
| 777 if (comma) { | |
| 778 if ((units_i = validate_units(r_buf, r_units, ARRAY_SIZE(r_units))) == -2) { | |
| 779 fprintf(stderr, "Error 179: scalexdimdp resolution units must occur at end\n"); | |
| 780 return 0; | |
| 781 } | |
| 782 if (!validate_float(r_buf, 0 /*allow_neg*/, p_dpmm, errbuf)) { | |
| 783 fprintf(stderr, "Error 180: scalexdimdp resolution invalid floating point (%s)\n", errbuf); | |
| 784 return 0; | |
| 785 } | |
| 786 if (units_i > 0) { /* Ignore dpmm */ | |
| 787 *p_dpmm /= 25.4f /*dpi*/; | |
| 788 } | |
| 789 } | |
| 790 if (*p_dpmm == 0.0f) { | |
| 791 *p_dpmm = 12.0f; /* 300 dpi */ | |
| 792 } | |
| 793 | |
| 794 return 1; | |
| 795 } | |
| 796 | |
| 797 /* Parse and validate Structured Append argument "index,count[,ID]" to "--structapp" */ | |
| 798 static int validate_structapp(const char *arg, struct zint_structapp *structapp) { | |
| 799 char index[10] = {0}, count[10] = {0}; | |
| 800 const char *comma = strchr(arg, ','); | |
| 801 const char *comma2; | |
| 802 if (!comma) { | |
| 803 fprintf(stderr, "Error 155: Invalid Structured Append argument, expect \"index,count[,ID]\"\n"); | |
| 804 return 0; | |
| 805 } | |
| 806 if (comma == arg || comma - arg > 9) { | |
| 807 fprintf(stderr, "Error 156: Structured Append index too %s\n", comma == arg ? "short" : "long"); | |
| 808 return 0; | |
| 809 } | |
| 810 strncpy(index, arg, comma - arg); | |
| 811 comma++; | |
| 812 comma2 = strchr(comma, ','); | |
| 813 if (comma2) { | |
| 814 if (comma2 == comma || comma2 - comma > 9) { | |
| 815 fprintf(stderr, "Error 157: Structured Append count too %s\n", comma2 == comma ? "short" : "long"); | |
| 816 return 0; | |
| 817 } | |
| 818 strncpy(count, comma, comma2 - comma); | |
| 819 comma2++; | |
| 820 if (!*comma2 || strlen(comma2) > 32) { | |
| 821 fprintf(stderr, "Error 158: Structured Append ID too %s\n", !*comma2 ? "short" : "long"); | |
| 822 return 0; | |
| 823 } | |
| 824 strncpy(structapp->id, comma2, 32); | |
| 825 } else { | |
| 826 if (!*comma || strlen(comma) > 9) { | |
| 827 fprintf(stderr, "Error 159: Structured Append count too %s\n", !*comma ? "short" : "long"); | |
| 828 return 0; | |
| 829 } | |
| 830 strcpy(count, comma); | |
| 831 } | |
| 832 if (!validate_int(index, -1 /*len*/, &structapp->index)) { | |
| 833 fprintf(stderr, "Error 160: Invalid Structured Append index (digits only)\n"); | |
| 834 return 0; | |
| 835 } | |
| 836 if (!validate_int(count, -1 /*len*/, &structapp->count)) { | |
| 837 fprintf(stderr, "Error 161: Invalid Structured Append count (digits only)\n"); | |
| 838 return 0; | |
| 839 } | |
| 840 if (structapp->count < 2) { | |
| 841 fprintf(stderr, "Error 162: Invalid Structured Append count '%d', must be greater than or equal to 2\n", | |
| 842 structapp->count); | |
| 843 return 0; | |
| 844 } | |
| 845 if (structapp->index < 1 || structapp->index > structapp->count) { | |
| 846 fprintf(stderr, "Error 163: Structured Append index '%d' out of range (1 to count '%d')\n", structapp->index, | |
| 847 structapp->count); | |
| 848 return 0; | |
| 849 } | |
| 850 | |
| 851 return 1; | |
| 852 } | |
| 853 | |
| 854 /* Parse and validate the segment argument "ECI,DATA" to "--segN" */ | |
| 855 static int validate_seg(const char *arg, const int N, struct zint_seg segs[10]) { | |
| 856 char eci[10] = {0}; | |
| 857 const char *comma = strchr(arg, ','); | |
| 858 if (!comma || comma == arg || comma - arg > 9 || *(comma + 1) == '\0') { | |
| 859 fprintf(stderr, "Error 166: Invalid segment argument, expect \"ECI,DATA\"\n"); | |
| 860 return 0; | |
| 861 } | |
| 862 strncpy(eci, arg, comma - arg); | |
| 863 if (!validate_int(eci, -1 /*len*/, &segs[N].eci)) { | |
| 864 fprintf(stderr, "Error 167: Invalid segment ECI (digits only)\n"); | |
| 865 return 0; | |
| 866 } | |
| 867 if (segs[N].eci > 999999) { | |
| 868 fprintf(stderr, "Error 168: Segment ECI code '%d' out of range (0 to 999999)\n", segs[N].eci); | |
| 869 return 0; | |
| 870 } | |
| 871 segs[N].length = (int) strlen(comma + 1); | |
| 872 segs[N].source = (unsigned char *) (comma + 1); | |
| 873 return 1; | |
| 874 } | |
| 875 | |
| 876 #ifdef _WIN32 | |
| 877 static FILE *win_fopen(const char *filename, const char *mode); /* Forward ref */ | |
| 878 #endif | |
| 879 | |
| 880 /* Batch mode - output symbol for each line of text in `filename` */ | |
| 881 static int batch_process(struct zint_symbol *symbol, const char *filename, const int mirror_mode, | |
| 882 const char *filetype, const int output_given, const int rotate_angle) { | |
| 883 FILE *file; | |
| 884 unsigned char buffer[ZINT_MAX_DATA_LEN] = {0}; /* Maximum HanXin input */ | |
| 885 unsigned char character = 0; | |
| 886 int buf_posn = 0, error_number = 0, warn_number = 0, line_count = 1; | |
| 887 char output_file[256]; | |
| 888 char number[12], reverse_number[12]; | |
| 889 int inpos, local_line_count; | |
| 890 char format_string[256], reversed_string[256], format_char; | |
| 891 int format_len, i, o, mirror_start_o = 0; | |
| 892 char adjusted[2] = {0}; | |
| 893 const int from_stdin = strcmp(filename, "-") == 0; /* Suppress clang-19 warning clang-analyzer-unix.Stream */ | |
| 894 | |
| 895 if (mirror_mode) { | |
| 896 /* Use directory if any from outfile */ | |
| 897 if (output_given && symbol->outfile[0]) { | |
| 898 #ifndef _WIN32 | |
| 899 const char *dir = strrchr(symbol->outfile, '/'); | |
| 900 #else | |
| 901 const char *dir = strrchr(symbol->outfile, '\\'); | |
| 902 if (!dir) { | |
| 903 dir = strrchr(symbol->outfile, '/'); | |
| 904 } | |
| 905 #endif | |
| 906 if (dir) { | |
| 907 mirror_start_o = (int) (dir + 1 - symbol->outfile); | |
| 908 if (mirror_start_o > 221) { /* Insist on leaving at least ~30 chars for filename */ | |
| 909 fprintf(stderr, "Warning 188: directory for mirrored batch output too long (greater than 220)," | |
| 910 " ignoring\n"); | |
| 911 fflush(stderr); | |
| 912 warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning ZINT_WARN_INVALID_INPUT? */ | |
| 913 mirror_start_o = 0; | |
| 914 } else { | |
| 915 memcpy(output_file, symbol->outfile, mirror_start_o); | |
| 916 } | |
| 917 } | |
| 918 } | |
| 919 } else { | |
| 920 if (symbol->outfile[0] == '\0' || !output_given) { | |
| 921 strcpy(format_string, "~~~~~."); | |
| 922 strncat(format_string, filetype, 3); | |
| 923 } else { | |
| 924 strcpy(format_string, symbol->outfile); | |
| 925 set_extension(format_string, filetype); | |
| 926 } | |
| 927 } | |
| 928 | |
| 929 if (from_stdin) { | |
| 930 file = stdin; | |
| 931 } else { | |
| 932 #ifdef _WIN32 | |
| 933 file = win_fopen(filename, "rb"); | |
| 934 #else | |
| 935 file = fopen(filename, "rb"); | |
| 936 #endif | |
| 937 if (!file) { | |
| 938 fprintf(stderr, "Error 102: Unable to read input file '%s' (%d: %s)\n", filename, errno, strerror(errno)); | |
| 939 fflush(stderr); | |
| 940 return ZINT_ERROR_INVALID_DATA; | |
| 941 } | |
| 942 } | |
| 943 | |
| 944 do { | |
| 945 int intChar; | |
| 946 intChar = fgetc(file); | |
| 947 if (intChar == EOF) { | |
| 948 break; | |
| 949 } | |
| 950 character = (unsigned char) intChar; | |
| 951 if (character == '\n') { | |
| 952 if (buf_posn > 0 && buffer[buf_posn - 1] == '\r') { | |
| 953 /* CR+LF - assume Windows formatting and remove CR */ | |
| 954 buf_posn--; | |
| 955 buffer[buf_posn] = '\0'; | |
| 956 } | |
| 957 | |
| 958 if (mirror_mode == 0) { | |
| 959 inpos = 0; | |
| 960 local_line_count = line_count; | |
| 961 memset(number, 0, sizeof(number)); | |
| 962 memset(reverse_number, 0, sizeof(reverse_number)); | |
| 963 memset(reversed_string, 0, sizeof(reversed_string)); | |
| 964 memset(output_file, 0, sizeof(output_file)); | |
| 965 do { | |
| 966 number[inpos] = (local_line_count % 10) + '0'; | |
| 967 local_line_count /= 10; | |
| 968 inpos++; | |
| 969 } while (local_line_count > 0); | |
| 970 number[inpos] = '\0'; | |
| 971 | |
| 972 for (i = 0; i < inpos; i++) { | |
| 973 reverse_number[i] = number[inpos - i - 1]; | |
| 974 } | |
| 975 | |
| 976 format_len = (int) strlen(format_string); | |
| 977 for (i = format_len; i > 0; i--) { | |
| 978 format_char = format_string[i - 1]; | |
| 979 | |
| 980 switch (format_char) { | |
| 981 case '#': | |
| 982 if (inpos > 0) { | |
| 983 adjusted[0] = reverse_number[inpos - 1]; | |
| 984 inpos--; | |
| 985 } else { | |
| 986 adjusted[0] = ' '; | |
| 987 } | |
| 988 break; | |
| 989 case '~': | |
| 990 if (inpos > 0) { | |
| 991 adjusted[0] = reverse_number[inpos - 1]; | |
| 992 inpos--; | |
| 993 } else { | |
| 994 adjusted[0] = '0'; | |
| 995 } | |
| 996 break; | |
| 997 case '@': | |
| 998 if (inpos > 0) { | |
| 999 adjusted[0] = reverse_number[inpos - 1]; | |
| 1000 inpos--; | |
| 1001 } else { | |
| 1002 #ifndef _WIN32 | |
| 1003 adjusted[0] = '*'; | |
| 1004 #else | |
| 1005 adjusted[0] = '+'; | |
| 1006 #endif | |
| 1007 } | |
| 1008 break; | |
| 1009 default: | |
| 1010 adjusted[0] = format_string[i - 1]; | |
| 1011 break; | |
| 1012 } | |
| 1013 strcat(reversed_string, adjusted); | |
| 1014 } | |
| 1015 | |
| 1016 for (i = 0; i < format_len; i++) { | |
| 1017 output_file[i] = reversed_string[format_len - i - 1]; | |
| 1018 } | |
| 1019 } else { | |
| 1020 /* Name the output file from the data being processed */ | |
| 1021 i = 0; | |
| 1022 o = mirror_start_o; | |
| 1023 do { | |
| 1024 if (buffer[i] < 0x20) { | |
| 1025 output_file[o] = '_'; | |
| 1026 } else { | |
| 1027 switch (buffer[i]) { | |
| 1028 case '!': | |
| 1029 case '"': | |
| 1030 case '*': | |
| 1031 case '/': | |
| 1032 case ':': | |
| 1033 case '<': | |
| 1034 case '>': | |
| 1035 case '?': | |
| 1036 case '\\': | |
| 1037 case '|': | |
| 1038 case 0x7f: /* DEL */ | |
| 1039 output_file[o] = '_'; | |
| 1040 break; | |
| 1041 default: | |
| 1042 output_file[o] = buffer[i]; | |
| 1043 break; | |
| 1044 } | |
| 1045 } | |
| 1046 | |
| 1047 /* Skip escape characters */ | |
| 1048 if ((buffer[i] == '\\') && (symbol->input_mode & ESCAPE_MODE)) { | |
| 1049 i++; | |
| 1050 if (buffer[i] == 'x') { | |
| 1051 i += 2; | |
| 1052 } else if (buffer[i] == 'd' || buffer[i] == 'o') { | |
| 1053 i += 3; | |
| 1054 } else if (buffer[i] == 'u') { | |
| 1055 i += 4; | |
| 1056 } else if (buffer[i] == 'U') { | |
| 1057 i += 6; | |
| 1058 } | |
| 1059 } | |
| 1060 i++; | |
| 1061 o++; | |
| 1062 } while (i < buf_posn && o < 251); | |
| 1063 | |
| 1064 /* Add file extension */ | |
| 1065 output_file[o] = '.'; | |
| 1066 output_file[o + 1] = '\0'; | |
| 1067 | |
| 1068 strncat(output_file, filetype, 3); | |
| 1069 } | |
| 1070 | |
| 1071 strcpy(symbol->outfile, output_file); | |
| 1072 warn_number = ZBarcode_Encode_and_Print(symbol, buffer, buf_posn, rotate_angle); | |
| 1073 if (warn_number != 0) { | |
| 1074 fprintf(stderr, "On line %d: %s\n", line_count, symbol->errtxt); | |
| 1075 fflush(stderr); | |
| 1076 if (warn_number >= ZINT_ERROR) { | |
| 1077 error_number = warn_number; | |
| 1078 } | |
| 1079 } | |
| 1080 ZBarcode_Clear(symbol); | |
| 1081 memset(buffer, 0, sizeof(buffer)); | |
| 1082 buf_posn = 0; | |
| 1083 line_count++; | |
| 1084 } else { | |
| 1085 buffer[buf_posn] = character; | |
| 1086 buf_posn++; | |
| 1087 } | |
| 1088 if (buf_posn >= (int) sizeof(buffer)) { | |
| 1089 fprintf(stderr, "On line %d: Error 103: Input data too long\n", line_count); | |
| 1090 fflush(stderr); | |
| 1091 do { | |
| 1092 if ((intChar = fgetc(file)) == EOF) { | |
| 1093 break; | |
| 1094 } | |
| 1095 character = (unsigned char) intChar; | |
| 1096 } while ((!feof(file)) && (character != '\n')); | |
| 1097 } | |
| 1098 } while ((!feof(file)) && (line_count < 2000000000)); | |
| 1099 | |
| 1100 if (character != '\n') { | |
| 1101 fprintf(stderr, "Warning 104: No newline at end of file\n"); | |
| 1102 fflush(stderr); | |
| 1103 warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning e.g. ZINT_WARN_INVALID_INPUT? */ | |
| 1104 } | |
| 1105 | |
| 1106 if (!from_stdin) { | |
| 1107 if (fclose(file) != 0) { | |
| 1108 fprintf(stderr, "Warning 196: Failure on closing input file '%s' (%d: %s)\n", filename, errno, | |
| 1109 strerror(errno)); | |
| 1110 fflush(stderr); | |
| 1111 warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning e.g. ZINT_WARN_INVALID_INPUT? */ | |
| 1112 } | |
| 1113 } | |
| 1114 if (error_number == 0) { | |
| 1115 error_number = warn_number; | |
| 1116 } | |
| 1117 return error_number; | |
| 1118 } | |
| 1119 | |
| 1120 /* Stuff to convert args on Windows command line to UTF-8 */ | |
| 1121 #ifdef _WIN32 | |
| 1122 #include <windows.h> | |
| 1123 | |
| 1124 #ifndef WC_ERR_INVALID_CHARS | |
| 1125 #define WC_ERR_INVALID_CHARS 0x00000080 | |
| 1126 #endif | |
| 1127 | |
| 1128 static int win_argc = 0; | |
| 1129 static char **win_argv = NULL; | |
| 1130 | |
| 1131 /* Free Windows args */ | |
| 1132 static void win_free_args(void) { | |
| 1133 int i; | |
| 1134 if (!win_argv) { | |
| 1135 return; | |
| 1136 } | |
| 1137 for (i = 0; i < win_argc; i++) { | |
| 1138 if (!win_argv[i]) { | |
| 1139 break; | |
| 1140 } | |
| 1141 free(win_argv[i]); | |
| 1142 win_argv[i] = NULL; | |
| 1143 } | |
| 1144 free(win_argv); | |
| 1145 win_argv = NULL; | |
| 1146 } | |
| 1147 | |
| 1148 /* Using Wine version of `CommandLineToArgvW()` (slightly adapted) to avoid loading shell32.dll - see | |
| 1149 https://source.winehq.org/git/wine.git/blob/5a66eab72:/dlls/shcore/main.c#l264 | |
| 1150 and https://news.ycombinator.com/item?id=18596841 */ | |
| 1151 /* | |
| 1152 * Copyright 2002 Jon Griffiths | |
| 1153 * Copyright 2016 Sebastian Lackner | |
| 1154 * | |
| 1155 * This library is free software; you can redistribute it and/or | |
| 1156 * modify it under the terms of the GNU Lesser General Public | |
| 1157 * License as published by the Free Software Foundation; either | |
| 1158 * version 2.1 of the License, or (at your option) any later version. | |
| 1159 * | |
| 1160 * This library is distributed in the hope that it will be useful, | |
| 1161 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 1162 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 1163 * Lesser General Public License for more details. | |
| 1164 * | |
| 1165 * You should have received a copy of the GNU Lesser General Public | |
| 1166 * License along with this library; if not, write to the Free Software | |
| 1167 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| 1168 */ | |
| 1169 static WCHAR **win_CommandLineToArgvW(const WCHAR *cmdline, int *numargs) { | |
| 1170 int qcount, bcount; | |
| 1171 const WCHAR *s; | |
| 1172 WCHAR **argv; | |
| 1173 DWORD argc; | |
| 1174 WCHAR *d; | |
| 1175 | |
| 1176 /* Adapted to require non-empty command line */ | |
| 1177 if (*cmdline == 0) { | |
| 1178 return NULL; | |
| 1179 } | |
| 1180 | |
| 1181 /* --- First count the arguments */ | |
| 1182 argc = 1; | |
| 1183 s = cmdline; | |
| 1184 /* The first argument, the executable path, follows special rules */ | |
| 1185 if (*s == '"') { | |
| 1186 /* The executable path ends at the next quote, no matter what */ | |
| 1187 s++; | |
| 1188 while (*s) | |
| 1189 if (*s++ == '"') | |
| 1190 break; | |
| 1191 } else { | |
| 1192 /* The executable path ends at the next space, no matter what */ | |
| 1193 while (*s && *s != ' ' && *s != '\t') | |
| 1194 s++; | |
| 1195 } | |
| 1196 /* Skip to the first argument, if any */ | |
| 1197 while (*s == ' ' || *s == '\t') | |
| 1198 s++; | |
| 1199 if (*s) | |
| 1200 argc++; | |
| 1201 | |
| 1202 /* Analyze the remaining arguments */ | |
| 1203 qcount = bcount = 0; | |
| 1204 while (*s) { | |
| 1205 if ((*s == ' ' || *s == '\t') && qcount == 0) { | |
| 1206 /* Skip to the next argument and count it if any */ | |
| 1207 while (*s == ' ' || *s == '\t') | |
| 1208 s++; | |
| 1209 if (*s) | |
| 1210 argc++; | |
| 1211 bcount = 0; | |
| 1212 } else if (*s == '\\') { | |
| 1213 /* '\', count them */ | |
| 1214 bcount++; | |
| 1215 s++; | |
| 1216 } else if (*s == '"') { | |
| 1217 /* '"' */ | |
| 1218 if ((bcount & 1) == 0) | |
| 1219 qcount++; /* Unescaped '"' */ | |
| 1220 s++; | |
| 1221 bcount = 0; | |
| 1222 /* Consecutive quotes, see comment in copying code below */ | |
| 1223 while (*s == '"') { | |
| 1224 qcount++; | |
| 1225 s++; | |
| 1226 } | |
| 1227 qcount = qcount % 3; | |
| 1228 if (qcount == 2) | |
| 1229 qcount = 0; | |
| 1230 } else { | |
| 1231 /* A regular character */ | |
| 1232 bcount = 0; | |
| 1233 s++; | |
| 1234 } | |
| 1235 } | |
| 1236 | |
| 1237 /* Allocate in a single lump, the string array, and the strings that go | |
| 1238 * with it. This way the caller can make a single LocalFree() call to free | |
| 1239 * both, as per MSDN. | |
| 1240 */ | |
| 1241 argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); | |
| 1242 if (!argv) | |
| 1243 return NULL; | |
| 1244 | |
| 1245 /* --- Then split and copy the arguments */ | |
| 1246 argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline); | |
| 1247 argc = 1; | |
| 1248 /* The first argument, the executable path, follows special rules */ | |
| 1249 if (*d == '"') { | |
| 1250 /* The executable path ends at the next quote, no matter what */ | |
| 1251 s = d + 1; | |
| 1252 while (*s) { | |
| 1253 if (*s == '"') { | |
| 1254 s++; | |
| 1255 break; | |
| 1256 } | |
| 1257 *d++ = *s++; | |
| 1258 } | |
| 1259 } else { | |
| 1260 /* The executable path ends at the next space, no matter what */ | |
| 1261 while (*d && *d != ' ' && *d != '\t') | |
| 1262 d++; | |
| 1263 s = d; | |
| 1264 if (*s) | |
| 1265 s++; | |
| 1266 } | |
| 1267 /* Close the executable path */ | |
| 1268 *d++ = 0; | |
| 1269 /* Skip to the first argument and initialize it if any */ | |
| 1270 while (*s == ' ' || *s == '\t') | |
| 1271 s++; | |
| 1272 if (!*s) { | |
| 1273 /* There are no parameters so we are all done */ | |
| 1274 argv[argc] = NULL; | |
| 1275 *numargs = argc; | |
| 1276 return argv; | |
| 1277 } | |
| 1278 | |
| 1279 /* Split and copy the remaining arguments */ | |
| 1280 argv[argc++] = d; | |
| 1281 qcount = bcount = 0; | |
| 1282 while (*s) { | |
| 1283 if ((*s == ' ' || *s == '\t') && qcount == 0) { | |
| 1284 /* Close the argument */ | |
| 1285 *d++ = 0; | |
| 1286 bcount = 0; | |
| 1287 | |
| 1288 /* Skip to the next one and initialize it if any */ | |
| 1289 do { | |
| 1290 s++; | |
| 1291 } while (*s == ' ' || *s == '\t'); | |
| 1292 if (*s) | |
| 1293 argv[argc++] = d; | |
| 1294 } else if (*s == '\\') { | |
| 1295 *d++ = *s++; | |
| 1296 bcount++; | |
| 1297 } else if (*s == '"') { | |
| 1298 if ((bcount & 1) == 0) { | |
| 1299 /* Preceded by an even number of '\', this is half that | |
| 1300 * number of '\', plus a quote which we erase. | |
| 1301 */ | |
| 1302 d -= bcount / 2; | |
| 1303 qcount++; | |
| 1304 } else { | |
| 1305 /* Preceded by an odd number of '\', this is half that | |
| 1306 * number of '\' followed by a '"' | |
| 1307 */ | |
| 1308 d = d - bcount / 2 - 1; | |
| 1309 *d++ = '"'; | |
| 1310 } | |
| 1311 s++; | |
| 1312 bcount = 0; | |
| 1313 /* Now count the number of consecutive quotes. Note that qcount | |
| 1314 * already takes into account the opening quote if any, as well as | |
| 1315 * the quote that lead us here. | |
| 1316 */ | |
| 1317 while (*s == '"') { | |
| 1318 if (++qcount == 3) { | |
| 1319 *d++ = '"'; | |
| 1320 qcount = 0; | |
| 1321 } | |
| 1322 s++; | |
| 1323 } | |
| 1324 if (qcount == 2) | |
| 1325 qcount = 0; | |
| 1326 } else { | |
| 1327 /* A regular character */ | |
| 1328 *d++ = *s++; | |
| 1329 bcount = 0; | |
| 1330 } | |
| 1331 } | |
| 1332 *d = '\0'; | |
| 1333 argv[argc] = NULL; | |
| 1334 *numargs = argc; | |
| 1335 | |
| 1336 return argv; | |
| 1337 } | |
| 1338 | |
| 1339 /* For Windows replace args with UTF-8 versions */ | |
| 1340 static void win_args(int *p_argc, char ***p_argv) { | |
| 1341 int i; | |
| 1342 LPWSTR *szArgList = win_CommandLineToArgvW(GetCommandLineW(), &win_argc); | |
| 1343 if (szArgList) { | |
| 1344 if (!(win_argv = (char **) calloc(win_argc + 1, sizeof(char *)))) { | |
| 1345 LocalFree(szArgList); | |
| 1346 } else { | |
| 1347 for (i = 0; i < win_argc; i++) { | |
| 1348 const int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1, NULL, 0, | |
| 1349 NULL /*lpDefaultChar*/, NULL /*lpUsedDefaultChar*/); | |
| 1350 if (len == 0 || !(win_argv[i] = malloc(len + 1))) { | |
| 1351 win_free_args(); | |
| 1352 LocalFree(szArgList); | |
| 1353 return; | |
| 1354 } | |
| 1355 if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1, win_argv[i], len, | |
| 1356 NULL /*lpDefaultChar*/, NULL /*lpUsedDefaultChar*/) == 0) { | |
| 1357 win_free_args(); | |
| 1358 LocalFree(szArgList); | |
| 1359 return; | |
| 1360 } | |
| 1361 } | |
| 1362 for (i = 0; i < win_argc; i++) { | |
| 1363 (*p_argv)[i] = win_argv[i]; | |
| 1364 } | |
| 1365 *p_argc = win_argc; | |
| 1366 LocalFree(szArgList); | |
| 1367 } | |
| 1368 } | |
| 1369 } | |
| 1370 | |
| 1371 /* Convert UTF-8 to Windows wide chars. Ticket #288, props Marcel */ | |
| 1372 #define utf8_to_wide(u, w, r) \ | |
| 1373 { \ | |
| 1374 int lenW; /* Includes NUL terminator */ \ | |
| 1375 if ((lenW = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, NULL, 0)) == 0) return r; \ | |
| 1376 w = (wchar_t *) z_alloca(sizeof(wchar_t) * lenW); \ | |
| 1377 if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, w, lenW) == 0) return r; \ | |
| 1378 } | |
| 1379 | |
| 1380 /* Do `fopen()` on Windows, assuming `filename` is UTF-8 encoded. Ticket #288, props Marcel */ | |
| 1381 static FILE *win_fopen(const char *filename, const char *mode) { | |
| 1382 wchar_t *filenameW, *modeW; | |
| 1383 | |
| 1384 utf8_to_wide(filename, filenameW, NULL); | |
| 1385 utf8_to_wide(mode, modeW, NULL); | |
| 1386 | |
| 1387 return _wfopen(filenameW, modeW); | |
| 1388 } | |
| 1389 #endif /* _WIN32 */ | |
| 1390 | |
| 1391 /* Helper to free Windows args on exit */ | |
| 1392 static int do_exit(int error_number) { | |
| 1393 #ifdef _WIN32 | |
| 1394 win_free_args(); | |
| 1395 #endif | |
| 1396 exit(error_number); | |
| 1397 return error_number; /* Not reached */ | |
| 1398 } | |
| 1399 | |
| 1400 typedef struct { const char *arg; int opt; } arg_opt; | |
| 1401 | |
| 1402 int main(int argc, char **argv) { | |
| 1403 struct zint_symbol *my_symbol; | |
| 1404 struct zint_seg segs[10] = {{0}}; | |
| 1405 int error_number = 0; | |
| 1406 int warn_number = 0; | |
| 1407 int rotate_angle = 0; | |
| 1408 int help = 0; | |
| 1409 int data_cnt = 0; | |
| 1410 int input_cnt = 0; | |
| 1411 int batch_mode = 0; | |
| 1412 int mirror_mode = 0; | |
| 1413 int fullmultibyte = 0; | |
| 1414 int mask = 0; | |
| 1415 int separator = 0; | |
| 1416 int addon_gap = 0; | |
| 1417 int rows = 0; | |
| 1418 char filetype[4] = {0}; | |
| 1419 int output_given = 0; | |
| 1420 int png_refused; | |
| 1421 int val; | |
| 1422 int i; | |
| 1423 int ret; | |
| 1424 char *outfile_extension; | |
| 1425 int data_arg_num = 0; | |
| 1426 int seg_count = 0; | |
| 1427 float x_dim_mm = 0.0f, dpmm = 0.0f; | |
| 1428 float float_opt; | |
| 1429 char errbuf[64]; /* For `validate_float()` */ | |
| 1430 arg_opt *arg_opts = (arg_opt *) z_alloca(sizeof(arg_opt) * argc); | |
| 1431 | |
| 1432 const int no_png = ZBarcode_NoPng(); | |
| 1433 | |
| 1434 if (argc == 1) { | |
| 1435 usage(no_png); | |
| 1436 exit(ZINT_ERROR_INVALID_DATA); | |
| 1437 } | |
| 1438 | |
| 1439 my_symbol = ZBarcode_Create(); | |
| 1440 if (!my_symbol) { | |
| 1441 fprintf(stderr, "Error 151: Memory failure\n"); | |
| 1442 exit(ZINT_ERROR_MEMORY); | |
| 1443 } | |
| 1444 my_symbol->input_mode = UNICODE_MODE; | |
| 1445 | |
| 1446 #ifdef _WIN32 | |
| 1447 win_args(&argc, &argv); | |
| 1448 #endif | |
| 1449 | |
| 1450 opterr = 0; /* Disable `getopt_long_only()` printing errors */ | |
| 1451 while (1) { | |
| 1452 enum options { | |
| 1453 OPT_ADDONGAP = 128, OPT_BATCH, OPT_BINARY, OPT_BG, OPT_BIND, OPT_BIND_TOP, OPT_BOLD, OPT_BORDER, OPT_BOX, | |
| 1454 OPT_CMYK, OPT_COLS, OPT_COMPLIANTHEIGHT, | |
| 1455 OPT_DIRECT, OPT_DMISO144, OPT_DMRE, OPT_DOTSIZE, OPT_DOTTY, OPT_DUMP, | |
| 1456 OPT_ECI, OPT_EMBEDFONT, OPT_ESC, OPT_EXTRAESC, OPT_FAST, OPT_FG, OPT_FILETYPE, OPT_FULLMULTIBYTE, | |
| 1457 OPT_GS1, OPT_GS1NOCHECK, OPT_GS1PARENS, OPT_GSSEP, OPT_GUARDDESCENT, OPT_GUARDWHITESPACE, | |
| 1458 OPT_HEIGHT, OPT_HEIGHTPERROW, OPT_INIT, OPT_MIRROR, OPT_MASK, OPT_MODE, | |
| 1459 OPT_NOBACKGROUND, OPT_NOQUIETZONES, OPT_NOTEXT, OPT_PRIMARY, OPT_QUIETZONES, | |
| 1460 OPT_ROTATE, OPT_ROWS, OPT_SCALE, OPT_SCALEXDIM, OPT_SCMVV, OPT_SECURE, | |
| 1461 OPT_SEG1, OPT_SEG2, OPT_SEG3, OPT_SEG4, OPT_SEG5, OPT_SEG6, OPT_SEG7, OPT_SEG8, OPT_SEG9, | |
| 1462 OPT_SEPARATOR, OPT_SMALL, OPT_SQUARE, OPT_STRUCTAPP, OPT_TEXTGAP, | |
| 1463 OPT_VERBOSE, OPT_VERS, OPT_VWHITESP, OPT_WERROR | |
| 1464 }; | |
| 1465 static const struct option long_options[] = { | |
| 1466 {"addongap", 1, NULL, OPT_ADDONGAP}, | |
| 1467 {"barcode", 1, NULL, 'b'}, | |
| 1468 {"batch", 0, NULL, OPT_BATCH}, | |
| 1469 {"binary", 0, NULL, OPT_BINARY}, | |
| 1470 {"bg", 1, 0, OPT_BG}, | |
| 1471 {"bgcolor", 1, 0, OPT_BG}, /* Synonym */ | |
| 1472 {"bgcolour", 1, 0, OPT_BG}, /* Synonym */ | |
| 1473 {"bind", 0, NULL, OPT_BIND}, | |
| 1474 {"bindtop", 0, NULL, OPT_BIND_TOP}, | |
| 1475 {"bold", 0, NULL, OPT_BOLD}, | |
| 1476 {"border", 1, NULL, OPT_BORDER}, | |
| 1477 {"box", 0, NULL, OPT_BOX}, | |
| 1478 {"cmyk", 0, NULL, OPT_CMYK}, | |
| 1479 {"cols", 1, NULL, OPT_COLS}, | |
| 1480 {"compliantheight", 0, NULL, OPT_COMPLIANTHEIGHT}, | |
| 1481 {"data", 1, NULL, 'd'}, | |
| 1482 {"direct", 0, NULL, OPT_DIRECT}, | |
| 1483 {"dmiso144", 0, NULL, OPT_DMISO144}, | |
| 1484 {"dmre", 0, NULL, OPT_DMRE}, | |
| 1485 {"dotsize", 1, NULL, OPT_DOTSIZE}, | |
| 1486 {"dotty", 0, NULL, OPT_DOTTY}, | |
| 1487 {"dump", 0, NULL, OPT_DUMP}, | |
| 1488 {"eci", 1, NULL, OPT_ECI}, | |
| 1489 {"ecinos", 0, NULL, 'e'}, | |
| 1490 {"embedfont", 0, NULL, OPT_EMBEDFONT}, | |
| 1491 {"esc", 0, NULL, OPT_ESC}, | |
| 1492 {"extraesc", 0, NULL, OPT_EXTRAESC}, | |
| 1493 {"fast", 0, NULL, OPT_FAST}, | |
| 1494 {"fg", 1, 0, OPT_FG}, | |
| 1495 {"fgcolor", 1, 0, OPT_FG}, /* Synonym */ | |
| 1496 {"fgcolour", 1, 0, OPT_FG}, /* Synonym */ | |
| 1497 {"filetype", 1, NULL, OPT_FILETYPE}, | |
| 1498 {"fullmultibyte", 0, NULL, OPT_FULLMULTIBYTE}, | |
| 1499 {"gs1", 0, 0, OPT_GS1}, | |
| 1500 {"gs1nocheck", 0, NULL, OPT_GS1NOCHECK}, | |
| 1501 {"gs1parens", 0, NULL, OPT_GS1PARENS}, | |
| 1502 {"gssep", 0, NULL, OPT_GSSEP}, | |
| 1503 {"guarddescent", 1, NULL, OPT_GUARDDESCENT}, | |
| 1504 {"guardwhitespace", 0, NULL, OPT_GUARDWHITESPACE}, | |
| 1505 {"height", 1, NULL, OPT_HEIGHT}, | |
| 1506 {"heightperrow", 0, NULL, OPT_HEIGHTPERROW}, | |
| 1507 {"help", 0, NULL, 'h'}, | |
| 1508 {"init", 0, NULL, OPT_INIT}, | |
| 1509 {"input", 1, NULL, 'i'}, | |
| 1510 {"mirror", 0, NULL, OPT_MIRROR}, | |
| 1511 {"mask", 1, NULL, OPT_MASK}, | |
| 1512 {"mode", 1, NULL, OPT_MODE}, | |
| 1513 {"nobackground", 0, NULL, OPT_NOBACKGROUND}, | |
| 1514 {"noquietzones", 0, NULL, OPT_NOQUIETZONES}, | |
| 1515 {"notext", 0, NULL, OPT_NOTEXT}, | |
| 1516 {"output", 1, NULL, 'o'}, | |
| 1517 {"primary", 1, NULL, OPT_PRIMARY}, | |
| 1518 {"quietzones", 0, NULL, OPT_QUIETZONES}, | |
| 1519 {"reverse", 0, NULL, 'r'}, | |
| 1520 {"rotate", 1, NULL, OPT_ROTATE}, | |
| 1521 {"rows", 1, NULL, OPT_ROWS}, | |
| 1522 {"scale", 1, NULL, OPT_SCALE}, | |
| 1523 {"scalexdimdp", 1, NULL, OPT_SCALEXDIM}, | |
| 1524 {"scmvv", 1, NULL, OPT_SCMVV}, | |
| 1525 {"secure", 1, NULL, OPT_SECURE}, | |
| 1526 {"seg1", 1, NULL, OPT_SEG1}, | |
| 1527 {"seg2", 1, NULL, OPT_SEG2}, | |
| 1528 {"seg3", 1, NULL, OPT_SEG3}, | |
| 1529 {"seg4", 1, NULL, OPT_SEG4}, | |
| 1530 {"seg5", 1, NULL, OPT_SEG5}, | |
| 1531 {"seg6", 1, NULL, OPT_SEG6}, | |
| 1532 {"seg7", 1, NULL, OPT_SEG7}, | |
| 1533 {"seg8", 1, NULL, OPT_SEG8}, | |
| 1534 {"seg9", 1, NULL, OPT_SEG9}, | |
| 1535 {"separator", 1, NULL, OPT_SEPARATOR}, | |
| 1536 {"small", 0, NULL, OPT_SMALL}, | |
| 1537 {"square", 0, NULL, OPT_SQUARE}, | |
| 1538 {"structapp", 1, NULL, OPT_STRUCTAPP}, | |
| 1539 {"textgap", 1, NULL, OPT_TEXTGAP}, | |
| 1540 {"types", 0, NULL, 't'}, | |
| 1541 {"verbose", 0, NULL, OPT_VERBOSE}, /* Currently undocumented, output some debug info */ | |
| 1542 {"vers", 1, NULL, OPT_VERS}, | |
| 1543 {"version", 0, NULL, 'v'}, | |
| 1544 {"vwhitesp", 1, NULL, OPT_VWHITESP}, | |
| 1545 {"werror", 0, NULL, OPT_WERROR}, | |
| 1546 {"whitesp", 1, NULL, 'w'}, | |
| 1547 {NULL, 0, NULL, 0} | |
| 1548 }; | |
| 1549 const int c = getopt_long_only(argc, argv, "b:d:ehi:o:rtvw:", long_options, NULL); | |
| 1550 if (c == -1) break; | |
| 1551 | |
| 1552 switch (c) { | |
| 1553 case OPT_ADDONGAP: | |
| 1554 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1555 fprintf(stderr, "Error 139: Invalid add-on gap value (digits only)\n"); | |
| 1556 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1557 } | |
| 1558 if (val >= 7 && val <= 12) { | |
| 1559 addon_gap = val; | |
| 1560 } else { | |
| 1561 fprintf(stderr, "Warning 140: Add-on gap '%d' out of range (7 to 12), ignoring\n", val); | |
| 1562 fflush(stderr); | |
| 1563 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1564 } | |
| 1565 break; | |
| 1566 case OPT_BATCH: | |
| 1567 if (data_cnt == 0) { | |
| 1568 /* Switch to batch processing mode */ | |
| 1569 batch_mode = 1; | |
| 1570 } else { | |
| 1571 fprintf(stderr, "Warning 141: Can't use batch mode if data given, ignoring\n"); | |
| 1572 fflush(stderr); | |
| 1573 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1574 } | |
| 1575 break; | |
| 1576 case OPT_BG: | |
| 1577 strncpy(my_symbol->bgcolour, optarg, 15); /* Allow for "CCC,MMM,YYY,KKK" */ | |
| 1578 break; | |
| 1579 case OPT_BINARY: | |
| 1580 my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | DATA_MODE; | |
| 1581 break; | |
| 1582 case OPT_BIND: | |
| 1583 my_symbol->output_options |= BARCODE_BIND; | |
| 1584 break; | |
| 1585 case OPT_BIND_TOP: | |
| 1586 my_symbol->output_options |= BARCODE_BIND_TOP; | |
| 1587 break; | |
| 1588 case OPT_BOLD: | |
| 1589 my_symbol->output_options |= BOLD_TEXT; | |
| 1590 break; | |
| 1591 case OPT_BORDER: | |
| 1592 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1593 fprintf(stderr, "Error 107: Invalid border width value (digits only)\n"); | |
| 1594 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1595 } | |
| 1596 if (val <= 1000) { /* `val` >= 0 always */ | |
| 1597 my_symbol->border_width = val; | |
| 1598 } else { | |
| 1599 fprintf(stderr, "Warning 108: Border width '%d' out of range (0 to 1000), ignoring\n", val); | |
| 1600 fflush(stderr); | |
| 1601 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1602 } | |
| 1603 break; | |
| 1604 case OPT_BOX: | |
| 1605 my_symbol->output_options |= BARCODE_BOX; | |
| 1606 break; | |
| 1607 case OPT_CMYK: | |
| 1608 my_symbol->output_options |= CMYK_COLOUR; | |
| 1609 break; | |
| 1610 case OPT_COLS: | |
| 1611 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1612 fprintf(stderr, "Error 131: Invalid columns value (digits only)\n"); | |
| 1613 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1614 } | |
| 1615 if ((val >= 1) && (val <= 200)) { | |
| 1616 my_symbol->option_2 = val; | |
| 1617 } else { | |
| 1618 fprintf(stderr, "Warning 111: Number of columns '%d' out of range (1 to 200), ignoring\n", val); | |
| 1619 fflush(stderr); | |
| 1620 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1621 } | |
| 1622 break; | |
| 1623 case OPT_COMPLIANTHEIGHT: | |
| 1624 my_symbol->output_options |= COMPLIANT_HEIGHT; | |
| 1625 break; | |
| 1626 case OPT_DIRECT: | |
| 1627 my_symbol->output_options |= BARCODE_STDOUT; | |
| 1628 break; | |
| 1629 case OPT_DMISO144: | |
| 1630 my_symbol->option_3 |= DM_ISO_144; | |
| 1631 break; | |
| 1632 case OPT_DMRE: | |
| 1633 /* Square overwrites DMRE */ | |
| 1634 if ((my_symbol->option_3 & 0x7F) != DM_SQUARE) { | |
| 1635 my_symbol->option_3 = DM_DMRE | (my_symbol->option_3 & ~0x7F); | |
| 1636 } | |
| 1637 break; | |
| 1638 case OPT_DOTSIZE: | |
| 1639 if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { | |
| 1640 fprintf(stderr, "Error 181: Invalid dot radius floating point (%s)\n", errbuf); | |
| 1641 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1642 } | |
| 1643 if (float_opt >= 0.01f) { | |
| 1644 my_symbol->dot_size = float_opt; | |
| 1645 } else { | |
| 1646 fprintf(stderr, "Warning 106: Invalid dot radius value (less than 0.01), ignoring\n"); | |
| 1647 fflush(stderr); | |
| 1648 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1649 } | |
| 1650 break; | |
| 1651 case OPT_DOTTY: | |
| 1652 my_symbol->output_options |= BARCODE_DOTTY_MODE; | |
| 1653 break; | |
| 1654 case OPT_DUMP: | |
| 1655 my_symbol->output_options |= BARCODE_STDOUT; | |
| 1656 strcpy(my_symbol->outfile, "dummy.txt"); | |
| 1657 break; | |
| 1658 case OPT_ECI: | |
| 1659 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1660 fprintf(stderr, "Error 138: Invalid ECI code (digits only)\n"); | |
| 1661 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1662 } | |
| 1663 if (val <= 999999) { /* `val` >= 0 always */ | |
| 1664 my_symbol->eci = val; | |
| 1665 } else { | |
| 1666 fprintf(stderr, "Warning 118: ECI code '%d' out of range (0 to 999999), ignoring\n", val); | |
| 1667 fflush(stderr); | |
| 1668 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1669 } | |
| 1670 break; | |
| 1671 case OPT_EMBEDFONT: | |
| 1672 my_symbol->output_options |= EMBED_VECTOR_FONT; | |
| 1673 break; | |
| 1674 case OPT_ESC: | |
| 1675 my_symbol->input_mode |= ESCAPE_MODE; | |
| 1676 break; | |
| 1677 case OPT_EXTRAESC: | |
| 1678 my_symbol->input_mode |= EXTRA_ESCAPE_MODE; | |
| 1679 break; | |
| 1680 case OPT_FAST: | |
| 1681 my_symbol->input_mode |= FAST_MODE; | |
| 1682 break; | |
| 1683 case OPT_FG: | |
| 1684 strncpy(my_symbol->fgcolour, optarg, 15); /* Allow for "CCC,MMM,YYY,KKK" */ | |
| 1685 break; | |
| 1686 case OPT_FILETYPE: | |
| 1687 /* Select the type of output file */ | |
| 1688 if (supported_filetype(optarg, no_png, &png_refused)) { | |
| 1689 strncpy(filetype, optarg, (size_t) 3); | |
| 1690 } else { | |
| 1691 if (png_refused) { | |
| 1692 fprintf(stderr, "Warning 152: PNG format disabled at compile time, ignoring\n"); | |
| 1693 } else { | |
| 1694 fprintf(stderr, "Warning 142: File type '%s' not supported, ignoring\n", optarg); | |
| 1695 } | |
| 1696 fflush(stderr); | |
| 1697 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1698 } | |
| 1699 break; | |
| 1700 case OPT_FULLMULTIBYTE: | |
| 1701 fullmultibyte = 1; | |
| 1702 break; | |
| 1703 case OPT_GS1: | |
| 1704 my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | GS1_MODE; | |
| 1705 break; | |
| 1706 case OPT_GS1NOCHECK: | |
| 1707 my_symbol->input_mode |= GS1NOCHECK_MODE; | |
| 1708 break; | |
| 1709 case OPT_GS1PARENS: | |
| 1710 my_symbol->input_mode |= GS1PARENS_MODE; | |
| 1711 break; | |
| 1712 case OPT_GSSEP: | |
| 1713 my_symbol->output_options |= GS1_GS_SEPARATOR; | |
| 1714 break; | |
| 1715 case OPT_GUARDDESCENT: | |
| 1716 if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { | |
| 1717 fprintf(stderr, "Error 182: Invalid guard bar descent floating point (%s)\n", errbuf); | |
| 1718 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1719 } | |
| 1720 if (float_opt >= 0.0f && float_opt <= 50.0f) { | |
| 1721 my_symbol->guard_descent = float_opt; | |
| 1722 } else { | |
| 1723 fprintf(stderr, "Warning 135: Guard bar descent '%g' out of range (0 to 50), ignoring\n", | |
| 1724 float_opt); | |
| 1725 fflush(stderr); | |
| 1726 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1727 } | |
| 1728 break; | |
| 1729 case OPT_GUARDWHITESPACE: | |
| 1730 my_symbol->output_options |= EANUPC_GUARD_WHITESPACE; | |
| 1731 break; | |
| 1732 case OPT_HEIGHT: | |
| 1733 if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { | |
| 1734 fprintf(stderr, "Error 183: Invalid symbol height floating point (%s)\n", errbuf); | |
| 1735 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1736 } | |
| 1737 if (float_opt >= 0.5f && float_opt <= 2000.0f) { | |
| 1738 my_symbol->height = float_opt; | |
| 1739 } else { | |
| 1740 fprintf(stderr, "Warning 110: Symbol height '%g' out of range (0.5 to 2000), ignoring\n", | |
| 1741 float_opt); | |
| 1742 fflush(stderr); | |
| 1743 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1744 } | |
| 1745 break; | |
| 1746 case OPT_HEIGHTPERROW: | |
| 1747 my_symbol->input_mode |= HEIGHTPERROW_MODE; | |
| 1748 break; | |
| 1749 case OPT_INIT: | |
| 1750 my_symbol->output_options |= READER_INIT; | |
| 1751 break; | |
| 1752 case OPT_MIRROR: | |
| 1753 /* Use filenames which reflect content */ | |
| 1754 mirror_mode = 1; | |
| 1755 break; | |
| 1756 case OPT_MASK: | |
| 1757 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1758 fprintf(stderr, "Error 148: Invalid mask value (digits only)\n"); | |
| 1759 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1760 } | |
| 1761 if (val <= 7) { /* `val` >= 0 always */ | |
| 1762 mask = val + 1; | |
| 1763 } else { | |
| 1764 /* mask pattern >= 0 and <= 7 (i.e. values >= 1 and <= 8) only permitted */ | |
| 1765 fprintf(stderr, "Warning 147: Mask value '%d' out of range (0 to 7), ignoring\n", val); | |
| 1766 fflush(stderr); | |
| 1767 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1768 } | |
| 1769 break; | |
| 1770 case OPT_MODE: | |
| 1771 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1772 fprintf(stderr, "Error 136: Invalid mode value (digits only)\n"); | |
| 1773 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1774 } | |
| 1775 if (val <= 6) { /* `val` >= 0 always */ | |
| 1776 my_symbol->option_1 = val; | |
| 1777 } else { | |
| 1778 fprintf(stderr, "Warning 116: Mode value '%d' out of range (0 to 6), ignoring\n", val); | |
| 1779 fflush(stderr); | |
| 1780 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1781 } | |
| 1782 break; | |
| 1783 case OPT_NOBACKGROUND: | |
| 1784 strcpy(my_symbol->bgcolour, "ffffff00"); | |
| 1785 break; | |
| 1786 case OPT_NOQUIETZONES: | |
| 1787 my_symbol->output_options |= BARCODE_NO_QUIET_ZONES; | |
| 1788 break; | |
| 1789 case OPT_NOTEXT: | |
| 1790 my_symbol->show_hrt = 0; | |
| 1791 break; | |
| 1792 case OPT_PRIMARY: | |
| 1793 if (strlen(optarg) <= 127) { | |
| 1794 strcpy(my_symbol->primary, optarg); | |
| 1795 } else { | |
| 1796 strncpy(my_symbol->primary, optarg, 127); | |
| 1797 fprintf(stderr, | |
| 1798 "Warning 115: Primary data string too long (127 character maximum), truncating\n"); | |
| 1799 fflush(stderr); | |
| 1800 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1801 } | |
| 1802 break; | |
| 1803 case OPT_QUIETZONES: | |
| 1804 my_symbol->output_options |= BARCODE_QUIET_ZONES; | |
| 1805 break; | |
| 1806 case OPT_ROTATE: | |
| 1807 /* Only certain inputs allowed */ | |
| 1808 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1809 fprintf(stderr, "Error 117: Invalid rotation value (digits only)\n"); | |
| 1810 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1811 } | |
| 1812 switch (val) { | |
| 1813 case 0: | |
| 1814 case 90: | |
| 1815 case 180: | |
| 1816 case 270: | |
| 1817 rotate_angle = val; | |
| 1818 break; | |
| 1819 default: | |
| 1820 fprintf(stderr, "Warning 137: Rotation value '%d' out of range (0, 90, 180 or 270 only)," | |
| 1821 " ignoring\n", val); | |
| 1822 fflush(stderr); | |
| 1823 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1824 break; | |
| 1825 } | |
| 1826 break; | |
| 1827 case OPT_ROWS: | |
| 1828 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1829 fprintf(stderr, "Error 132: Invalid rows value (digits only)\n"); | |
| 1830 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1831 } | |
| 1832 if ((val >= 1) && (val <= 90)) { | |
| 1833 rows = val; | |
| 1834 } else { | |
| 1835 fprintf(stderr, "Warning 112: Number of rows '%d' out of range (1 to 90), ignoring\n", val); | |
| 1836 fflush(stderr); | |
| 1837 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1838 } | |
| 1839 break; | |
| 1840 case OPT_SCALE: | |
| 1841 if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { | |
| 1842 fprintf(stderr, "Error 184: Invalid scale floating point (%s)\n", errbuf); | |
| 1843 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1844 } | |
| 1845 if (float_opt >= 0.01f) { | |
| 1846 my_symbol->scale = float_opt; | |
| 1847 } else { | |
| 1848 fprintf(stderr, "Warning 105: Invalid scale value '%g' (less than 0.01), ignoring\n", float_opt); | |
| 1849 fflush(stderr); | |
| 1850 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1851 } | |
| 1852 break; | |
| 1853 case OPT_SCALEXDIM: | |
| 1854 if (!validate_scalexdimdp(optarg, &x_dim_mm, &dpmm)) { | |
| 1855 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1856 } | |
| 1857 if (x_dim_mm > 10.0f || dpmm > 1000.0f) { | |
| 1858 if (x_dim_mm > 10.0f) { | |
| 1859 fprintf(stderr, "Warning 185: scalexdimdp X-dim '%g' out of range (greater than 10)," | |
| 1860 " ignoring\n", x_dim_mm); | |
| 1861 } else { | |
| 1862 fprintf(stderr, "Warning 186: scalexdimdp resolution '%g' out of range (greater than 1000)," | |
| 1863 " ignoring\n", dpmm); | |
| 1864 } | |
| 1865 fflush(stderr); | |
| 1866 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1867 x_dim_mm = dpmm = 0.0f; | |
| 1868 } | |
| 1869 break; | |
| 1870 case OPT_SCMVV: | |
| 1871 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1872 fprintf(stderr, "Error 149: Invalid Structured Carrier Message version value (digits only)\n"); | |
| 1873 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1874 } | |
| 1875 if (val <= 99) { /* `val` >= 0 always */ | |
| 1876 my_symbol->option_2 = val + 1; | |
| 1877 } else { | |
| 1878 /* Version 00-99 only */ | |
| 1879 fprintf(stderr, "Warning 150: Structured Carrier Message version '%d' out of range (0 to 99)," | |
| 1880 " ignoring\n", val); | |
| 1881 fflush(stderr); | |
| 1882 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1883 } | |
| 1884 break; | |
| 1885 case OPT_SECURE: | |
| 1886 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1887 fprintf(stderr, "Error 134: Invalid ECC value (digits only)\n"); | |
| 1888 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1889 } | |
| 1890 if (val <= 8) { /* `val` >= 0 always */ | |
| 1891 my_symbol->option_1 = val; | |
| 1892 } else { | |
| 1893 fprintf(stderr, "Warning 114: ECC level '%d' out of range (0 to 8), ignoring\n", val); | |
| 1894 fflush(stderr); | |
| 1895 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1896 } | |
| 1897 break; | |
| 1898 case OPT_SEG1: | |
| 1899 case OPT_SEG2: | |
| 1900 case OPT_SEG3: | |
| 1901 case OPT_SEG4: | |
| 1902 case OPT_SEG5: | |
| 1903 case OPT_SEG6: | |
| 1904 case OPT_SEG7: | |
| 1905 case OPT_SEG8: | |
| 1906 case OPT_SEG9: | |
| 1907 if (batch_mode == 0) { | |
| 1908 val = c - OPT_SEG1 + 1; /* Segment number */ | |
| 1909 if (segs[val].source) { | |
| 1910 fprintf(stderr, "Error 164: Duplicate segment %d\n", val); | |
| 1911 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1912 } | |
| 1913 if (!validate_seg(optarg, c - OPT_SEG1 + 1, segs)) { | |
| 1914 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1915 } | |
| 1916 if (val >= seg_count) { | |
| 1917 seg_count = val + 1; | |
| 1918 } | |
| 1919 } else { | |
| 1920 fprintf(stderr, "Warning 165: Can't define segments in batch mode, ignoring '%s'\n", optarg); | |
| 1921 fflush(stderr); | |
| 1922 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1923 } | |
| 1924 break; | |
| 1925 case OPT_SEPARATOR: | |
| 1926 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1927 fprintf(stderr, "Error 128: Invalid separator value (digits only)\n"); | |
| 1928 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1929 } | |
| 1930 if (val <= 4) { /* `val` >= 0 always */ | |
| 1931 separator = val; | |
| 1932 } else { | |
| 1933 /* Greater than 4 values are not permitted */ | |
| 1934 fprintf(stderr, "Warning 127: Separator value '%d' out of range (0 to 4), ignoring\n", val); | |
| 1935 fflush(stderr); | |
| 1936 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1937 } | |
| 1938 break; | |
| 1939 case OPT_SMALL: | |
| 1940 my_symbol->output_options |= SMALL_TEXT; | |
| 1941 break; | |
| 1942 case OPT_SQUARE: | |
| 1943 my_symbol->option_3 = DM_SQUARE | (my_symbol->option_3 & ~0x7F); | |
| 1944 break; | |
| 1945 case OPT_STRUCTAPP: | |
| 1946 memset(&my_symbol->structapp, 0, sizeof(my_symbol->structapp)); | |
| 1947 if (!validate_structapp(optarg, &my_symbol->structapp)) { | |
| 1948 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1949 } | |
| 1950 break; | |
| 1951 case OPT_TEXTGAP: | |
| 1952 if (!validate_float(optarg, 1 /*allow_neg*/, &float_opt, errbuf)) { | |
| 1953 fprintf(stderr, "Error 194: Invalid text gap floating point (%s)\n", errbuf); | |
| 1954 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1955 } | |
| 1956 if (float_opt >= -5.0f && float_opt <= 10.0f) { | |
| 1957 my_symbol->text_gap = float_opt; | |
| 1958 } else { | |
| 1959 fprintf(stderr, "Warning 195: Text gap '%g' out of range (-5 to 10), ignoring\n", | |
| 1960 float_opt); | |
| 1961 fflush(stderr); | |
| 1962 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1963 } | |
| 1964 break; | |
| 1965 case OPT_VERBOSE: | |
| 1966 my_symbol->debug = 1; | |
| 1967 break; | |
| 1968 case OPT_VERS: | |
| 1969 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1970 fprintf(stderr, "Error 133: Invalid version value (digits only)\n"); | |
| 1971 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1972 } | |
| 1973 if ((val >= 1) && (val <= 999)) { | |
| 1974 my_symbol->option_2 = val; | |
| 1975 } else { | |
| 1976 fprintf(stderr, "Warning 113: Version value '%d' out of range (1 to 999), ignoring\n", val); | |
| 1977 fflush(stderr); | |
| 1978 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1979 } | |
| 1980 break; | |
| 1981 case OPT_VWHITESP: | |
| 1982 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 1983 fprintf(stderr, "Error 153: Invalid vertical whitespace value '%s' (digits only)\n", optarg); | |
| 1984 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 1985 } | |
| 1986 if (val <= 1000) { /* `val` >= 0 always */ | |
| 1987 my_symbol->whitespace_height = val; | |
| 1988 } else { | |
| 1989 fprintf(stderr, | |
| 1990 "Warning 154: Vertical whitespace value '%d' out of range (0 to 1000), ignoring\n", val); | |
| 1991 fflush(stderr); | |
| 1992 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 1993 } | |
| 1994 break; | |
| 1995 case OPT_WERROR: | |
| 1996 my_symbol->warn_level = WARN_FAIL_ALL; | |
| 1997 break; | |
| 1998 | |
| 1999 case 'h': | |
| 2000 usage(no_png); | |
| 2001 help = 1; | |
| 2002 break; | |
| 2003 case 'v': | |
| 2004 version(no_png); | |
| 2005 help = 1; | |
| 2006 break; | |
| 2007 case 't': | |
| 2008 types(); | |
| 2009 help = 1; | |
| 2010 break; | |
| 2011 case 'e': | |
| 2012 show_eci(); | |
| 2013 help = 1; | |
| 2014 break; | |
| 2015 | |
| 2016 case 'b': | |
| 2017 if (!validate_int(optarg, -1 /*len*/, &val) && !(val = get_barcode_name(optarg))) { | |
| 2018 fprintf(stderr, "Error 119: Invalid barcode type '%s'\n", optarg); | |
| 2019 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2020 } | |
| 2021 my_symbol->symbology = val; | |
| 2022 break; | |
| 2023 | |
| 2024 case 'w': | |
| 2025 if (!validate_int(optarg, -1 /*len*/, &val)) { | |
| 2026 fprintf(stderr, "Error 120: Invalid horizontal whitespace value '%s' (digits only)\n", optarg); | |
| 2027 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2028 } | |
| 2029 if (val <= 1000) { /* `val` >= 0 always */ | |
| 2030 my_symbol->whitespace_width = val; | |
| 2031 } else { | |
| 2032 fprintf(stderr, | |
| 2033 "Warning 121: Horizontal whitespace value '%d' out of range (0 to 1000), ignoring\n", | |
| 2034 val); | |
| 2035 fflush(stderr); | |
| 2036 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2037 } | |
| 2038 break; | |
| 2039 | |
| 2040 case 'd': /* we have some data! */ | |
| 2041 if (batch_mode == 0) { | |
| 2042 arg_opts[data_arg_num].arg = optarg; | |
| 2043 arg_opts[data_arg_num].opt = c; | |
| 2044 data_arg_num++; | |
| 2045 data_cnt++; | |
| 2046 } else { | |
| 2047 fprintf(stderr, "Warning 122: Can't define data in batch mode, ignoring '%s'\n", optarg); | |
| 2048 fflush(stderr); | |
| 2049 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2050 } | |
| 2051 break; | |
| 2052 | |
| 2053 case 'i': /* Take data from file */ | |
| 2054 if (batch_mode == 0 || input_cnt == 0) { | |
| 2055 arg_opts[data_arg_num].arg = optarg; | |
| 2056 arg_opts[data_arg_num].opt = c; | |
| 2057 data_arg_num++; | |
| 2058 input_cnt++; | |
| 2059 } else { | |
| 2060 fprintf(stderr, "Warning 143: Can only define one input file in batch mode, ignoring '%s'\n", | |
| 2061 optarg); | |
| 2062 fflush(stderr); | |
| 2063 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2064 } | |
| 2065 break; | |
| 2066 | |
| 2067 case 'o': | |
| 2068 strncpy(my_symbol->outfile, optarg, 255); | |
| 2069 output_given = 1; | |
| 2070 break; | |
| 2071 | |
| 2072 case 'r': | |
| 2073 strcpy(my_symbol->fgcolour, "ffffff"); | |
| 2074 strcpy(my_symbol->bgcolour, "000000"); | |
| 2075 break; | |
| 2076 | |
| 2077 case '?': | |
| 2078 if (optopt) { | |
| 2079 for (i = 0; i < ARRAY_SIZE(long_options) && long_options[i].val != optopt; i++); | |
| 2080 if (i == ARRAY_SIZE(long_options)) { /* Shouldn't happen */ | |
| 2081 fprintf(stderr, "Error 125: ?? unknown optopt '%d'\n", optopt); /* Not reached */ | |
| 2082 return do_exit(ZINT_ERROR_ENCODING_PROBLEM); | |
| 2083 } | |
| 2084 if (long_options[i].has_arg) { | |
| 2085 fprintf(stderr, "Error 109: option '%s' requires an argument\n", argv[optind - 1]); | |
| 2086 } else { | |
| 2087 const char *eqs = strchr(argv[optind - 1], '='); | |
| 2088 const int optlen = eqs ? (int) (eqs - argv[optind - 1]) : (int) strlen(argv[optind - 1]); | |
| 2089 fprintf(stderr, "Error 126: option '%.*s' does not take an argument\n", optlen, | |
| 2090 argv[optind - 1]); | |
| 2091 } | |
| 2092 } else { | |
| 2093 fprintf(stderr, "Error 101: unknown option '%s'\n", argv[optind - 1]); | |
| 2094 } | |
| 2095 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2096 break; | |
| 2097 | |
| 2098 default: /* Shouldn't happen */ | |
| 2099 fprintf(stderr, "Error 123: ?? getopt error 0%o\n", c); /* Not reached */ | |
| 2100 return do_exit(ZINT_ERROR_ENCODING_PROBLEM); | |
| 2101 break; | |
| 2102 } | |
| 2103 } | |
| 2104 if (optind != argc) { | |
| 2105 if (optind + 1 == argc) { | |
| 2106 fprintf(stderr, "Warning 191: extra argument '%s' ignoring\n", argv[optind]); | |
| 2107 } else { | |
| 2108 fprintf(stderr, "Warning 192: extra arguments beginning with '%s' ignoring\n", argv[optind]); | |
| 2109 } | |
| 2110 fflush(stderr); | |
| 2111 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2112 } | |
| 2113 | |
| 2114 if (data_arg_num) { | |
| 2115 const int symbology = my_symbol->symbology; | |
| 2116 const unsigned int cap = ZBarcode_Cap(symbology, ZINT_CAP_STACKABLE | ZINT_CAP_EXTENDABLE | | |
| 2117 ZINT_CAP_FULL_MULTIBYTE | ZINT_CAP_MASK); | |
| 2118 if (fullmultibyte && (cap & ZINT_CAP_FULL_MULTIBYTE)) { | |
| 2119 my_symbol->option_3 = ZINT_FULL_MULTIBYTE; | |
| 2120 } | |
| 2121 if (mask && (cap & ZINT_CAP_MASK)) { | |
| 2122 my_symbol->option_3 |= mask << 8; | |
| 2123 } | |
| 2124 if (separator && (cap & ZINT_CAP_STACKABLE)) { | |
| 2125 my_symbol->option_3 = separator; | |
| 2126 } | |
| 2127 if (addon_gap && (cap & ZINT_CAP_EXTENDABLE)) { | |
| 2128 my_symbol->option_2 = addon_gap; | |
| 2129 } | |
| 2130 if (rows) { | |
| 2131 if (symbology == BARCODE_PDF417 || symbology == BARCODE_PDF417COMP || symbology == BARCODE_HIBC_PDF | |
| 2132 || symbology == BARCODE_DBAR_EXPSTK || symbology == BARCODE_DBAR_EXPSTK_CC) { | |
| 2133 my_symbol->option_3 = rows; | |
| 2134 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF | |
| 2135 || symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) { | |
| 2136 my_symbol->option_1 = rows; | |
| 2137 } | |
| 2138 } | |
| 2139 | |
| 2140 if (output_given && (my_symbol->output_options & BARCODE_STDOUT)) { | |
| 2141 my_symbol->output_options &= ~BARCODE_STDOUT; | |
| 2142 fprintf(stderr, "Warning 193: Output file given, ignoring '--direct' option\n"); | |
| 2143 fflush(stderr); | |
| 2144 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2145 } | |
| 2146 if (batch_mode) { | |
| 2147 /* Take each line of text as a separate data set */ | |
| 2148 if (data_arg_num > 1) { | |
| 2149 fprintf(stderr, "Warning 144: Processing first input file '%s' only\n", arg_opts[0].arg); | |
| 2150 fflush(stderr); | |
| 2151 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2152 } | |
| 2153 if (seg_count) { | |
| 2154 fprintf(stderr, "Warning 169: Ignoring segment arguments\n"); | |
| 2155 fflush(stderr); | |
| 2156 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2157 } | |
| 2158 if (filetype[0] == '\0') { | |
| 2159 outfile_extension = get_extension(my_symbol->outfile); | |
| 2160 if (outfile_extension && supported_filetype(outfile_extension, no_png, NULL)) { | |
| 2161 strcpy(filetype, outfile_extension); | |
| 2162 } else { | |
| 2163 strcpy(filetype, no_png ? "gif" : "png"); | |
| 2164 } | |
| 2165 } | |
| 2166 if (dpmm) { /* Allow `x_dim_mm` to be zero */ | |
| 2167 if (x_dim_mm == 0.0f) { | |
| 2168 x_dim_mm = ZBarcode_Default_Xdim(symbology); | |
| 2169 } | |
| 2170 float_opt = ZBarcode_Scale_From_XdimDp(symbology, x_dim_mm, dpmm, filetype); | |
| 2171 if (float_opt > 0.0f) { | |
| 2172 my_symbol->scale = float_opt; | |
| 2173 my_symbol->dpmm = dpmm; | |
| 2174 } else { | |
| 2175 fprintf(stderr, "Warning 187: Invalid scalexdimdp X-dim '%g', resolution '%g' combo, ignoring\n", | |
| 2176 x_dim_mm, dpmm); | |
| 2177 fflush(stderr); | |
| 2178 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2179 } | |
| 2180 } | |
| 2181 if (((symbology != BARCODE_MAXICODE && my_symbol->scale < 0.5f) || my_symbol->scale < 0.2f) | |
| 2182 && is_raster(filetype, no_png)) { | |
| 2183 const int min = symbology != BARCODE_MAXICODE ? 5 : 2; | |
| 2184 fprintf(stderr, "Warning 145: Scaling less than 0.%d will be set to 0.%d for '%s' output\n", min, min, | |
| 2185 filetype); | |
| 2186 fflush(stderr); | |
| 2187 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2188 } | |
| 2189 error_number = batch_process(my_symbol, arg_opts[0].arg, mirror_mode, filetype, output_given, | |
| 2190 rotate_angle); | |
| 2191 } else { | |
| 2192 if (seg_count) { | |
| 2193 if (data_arg_num > 1) { | |
| 2194 fprintf(stderr, "Error 170: Cannot specify segments and multiple data arguments together\n"); | |
| 2195 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2196 } | |
| 2197 if (arg_opts[0].opt != 'd') { /* For simplicity disallow input args for now */ | |
| 2198 fprintf(stderr, "Error 171: Cannot use input argument with segment arguments\n"); | |
| 2199 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2200 } | |
| 2201 segs[0].eci = my_symbol->eci; | |
| 2202 segs[0].source = (unsigned char *) arg_opts[0].arg; | |
| 2203 segs[0].length = (int) strlen(arg_opts[0].arg); | |
| 2204 for (i = 0; i < seg_count; i++) { | |
| 2205 if (segs[i].source == NULL) { | |
| 2206 fprintf(stderr, "Error 172: Segments must be consecutive - segment %d missing\n", i); | |
| 2207 return do_exit(ZINT_ERROR_INVALID_OPTION); | |
| 2208 } | |
| 2209 } | |
| 2210 } | |
| 2211 if (filetype[0] != '\0') { | |
| 2212 set_extension(my_symbol->outfile, filetype); | |
| 2213 } | |
| 2214 if (dpmm) { /* Allow `x_dim_mm` to be zero */ | |
| 2215 if (x_dim_mm == 0.0f) { | |
| 2216 x_dim_mm = ZBarcode_Default_Xdim(symbology); | |
| 2217 } | |
| 2218 float_opt = ZBarcode_Scale_From_XdimDp(symbology, x_dim_mm, dpmm, get_extension(my_symbol->outfile)); | |
| 2219 if (float_opt > 0.0f) { | |
| 2220 my_symbol->scale = float_opt; | |
| 2221 my_symbol->dpmm = dpmm; | |
| 2222 } else { | |
| 2223 fprintf(stderr, "Warning 190: Invalid scalexdimdp X-dim '%g', resolution '%g' combo, ignoring\n", | |
| 2224 x_dim_mm, dpmm); | |
| 2225 fflush(stderr); | |
| 2226 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2227 } | |
| 2228 } | |
| 2229 if (((symbology != BARCODE_MAXICODE && my_symbol->scale < 0.5f) || my_symbol->scale < 0.2f) | |
| 2230 && is_raster(get_extension(my_symbol->outfile), no_png)) { | |
| 2231 const int min = symbology != BARCODE_MAXICODE ? 5 : 2; | |
| 2232 fprintf(stderr, "Warning 146: Scaling less than 0.%d will be set to 0.%d for '%s' output\n", min, min, | |
| 2233 get_extension(my_symbol->outfile)); | |
| 2234 fflush(stderr); | |
| 2235 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2236 } | |
| 2237 for (i = 0; i < data_arg_num; i++) { | |
| 2238 if (arg_opts[i].opt == 'd') { | |
| 2239 if (seg_count) { | |
| 2240 ret = ZBarcode_Encode_Segs(my_symbol, segs, seg_count); | |
| 2241 } else { | |
| 2242 if (i == 1 && (ZBarcode_Cap(symbology, ZINT_CAP_STACKABLE) & ZINT_CAP_STACKABLE) == 0) { | |
| 2243 fprintf(stderr, | |
| 2244 "Error 173: Symbology must be stackable if multiple data arguments given\n"); | |
| 2245 fflush(stderr); | |
| 2246 error_number = ZINT_ERROR_INVALID_DATA; | |
| 2247 break; | |
| 2248 } | |
| 2249 ret = ZBarcode_Encode(my_symbol, (unsigned char *) arg_opts[i].arg, | |
| 2250 (int) strlen(arg_opts[i].arg)); | |
| 2251 } | |
| 2252 } else { | |
| 2253 ret = ZBarcode_Encode_File(my_symbol, arg_opts[i].arg); | |
| 2254 } | |
| 2255 if (ret != 0) { | |
| 2256 fprintf(stderr, "%s\n", my_symbol->errtxt); | |
| 2257 fflush(stderr); | |
| 2258 if (error_number < ZINT_ERROR) { | |
| 2259 error_number = ret; | |
| 2260 } | |
| 2261 } | |
| 2262 } | |
| 2263 if (error_number < ZINT_ERROR) { | |
| 2264 error_number = ZBarcode_Print(my_symbol, rotate_angle); | |
| 2265 | |
| 2266 if (error_number != 0) { | |
| 2267 fprintf(stderr, "%s\n", my_symbol->errtxt); | |
| 2268 fflush(stderr); | |
| 2269 } | |
| 2270 } | |
| 2271 } | |
| 2272 } else if (help == 0) { | |
| 2273 fprintf(stderr, "Warning 124: No data received, no symbol generated\n"); | |
| 2274 fflush(stderr); | |
| 2275 warn_number = ZINT_WARN_INVALID_OPTION; | |
| 2276 } | |
| 2277 | |
| 2278 ZBarcode_Delete(my_symbol); | |
| 2279 | |
| 2280 return do_exit(error_number ? error_number : warn_number); | |
| 2281 } | |
| 2282 | |
| 2283 /* vim: set ts=4 sw=4 et : */ |
