intl/icu/source/tools/icupkg/icupkg.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 2005-2013, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 *******************************************************************************
michael@0 8 * file name: icupkg.cpp
michael@0 9 * encoding: US-ASCII
michael@0 10 * tab size: 8 (not used)
michael@0 11 * indentation:4
michael@0 12 *
michael@0 13 * created on: 2005jul29
michael@0 14 * created by: Markus W. Scherer
michael@0 15 *
michael@0 16 * This tool operates on ICU data (.dat package) files.
michael@0 17 * It takes one as input, or creates an empty one, and can remove, add, and
michael@0 18 * extract data pieces according to command-line options.
michael@0 19 * At the same time, it swaps each piece to a consistent set of platform
michael@0 20 * properties as desired.
michael@0 21 * Useful as an install-time tool for shipping only one flavor of ICU data
michael@0 22 * and preparing data files for the target platform.
michael@0 23 * Also for customizing ICU data (pruning, augmenting, replacing) and for
michael@0 24 * taking it apart.
michael@0 25 * Subsumes functionality and implementation code from
michael@0 26 * gencmn, decmn, and icuswap tools.
michael@0 27 * Will not work with data DLLs (shared libraries).
michael@0 28 */
michael@0 29
michael@0 30 #include "unicode/utypes.h"
michael@0 31 #include "unicode/putil.h"
michael@0 32 #include "cstring.h"
michael@0 33 #include "toolutil.h"
michael@0 34 #include "uoptions.h"
michael@0 35 #include "uparse.h"
michael@0 36 #include "filestrm.h"
michael@0 37 #include "package.h"
michael@0 38 #include "pkg_icu.h"
michael@0 39
michael@0 40 #include <stdio.h>
michael@0 41 #include <stdlib.h>
michael@0 42 #include <string.h>
michael@0 43
michael@0 44 U_NAMESPACE_USE
michael@0 45
michael@0 46 // TODO: add --matchmode=regex for using the ICU regex engine for item name pattern matching?
michael@0 47
michael@0 48 // general definitions ----------------------------------------------------- ***
michael@0 49
michael@0 50 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
michael@0 51
michael@0 52 // main() ------------------------------------------------------------------ ***
michael@0 53
michael@0 54 static void
michael@0 55 printUsage(const char *pname, UBool isHelp) {
michael@0 56 FILE *where=isHelp ? stdout : stderr;
michael@0 57
michael@0 58 fprintf(where,
michael@0 59 "%csage: %s [-h|-?|--help ] [-tl|-tb|-te] [-c] [-C comment]\n"
michael@0 60 "\t[-a list] [-r list] [-x list] [-l [-o outputListFileName]]\n"
michael@0 61 "\t[-s path] [-d path] [-w] [-m mode]\n"
michael@0 62 "\t[--auto_toc_prefix] [--auto_toc_prefix_with_type] [--toc_prefix]\n"
michael@0 63 "\tinfilename [outfilename]\n",
michael@0 64 isHelp ? 'U' : 'u', pname);
michael@0 65 if(isHelp) {
michael@0 66 fprintf(where,
michael@0 67 "\n"
michael@0 68 "Read the input ICU .dat package file, modify it according to the options,\n"
michael@0 69 "swap it to the desired platform properties (charset & endianness),\n"
michael@0 70 "and optionally write the resulting ICU .dat package to the output file.\n"
michael@0 71 "Items are removed, then added, then extracted and listed.\n"
michael@0 72 "An ICU .dat package is written if items are removed or added,\n"
michael@0 73 "or if the input and output filenames differ,\n"
michael@0 74 "or if the --writepkg (-w) option is set.\n");
michael@0 75 fprintf(where,
michael@0 76 "\n"
michael@0 77 "If the input filename is \"new\" then an empty package is created.\n"
michael@0 78 "If the output filename is missing, then it is automatically generated\n"
michael@0 79 "from the input filename: If the input filename ends with an l, b, or e\n"
michael@0 80 "matching its platform properties, then the output filename will\n"
michael@0 81 "contain the letter from the -t (--type) option.\n");
michael@0 82 fprintf(where,
michael@0 83 "\n"
michael@0 84 "This tool can also be used to just swap a single ICU data file, replacing the\n"
michael@0 85 "former icuswap tool. For this mode, provide the infilename (and optional\n"
michael@0 86 "outfilename) for a non-package ICU data file.\n"
michael@0 87 "Allowed options include -t, -w, -s and -d.\n"
michael@0 88 "The filenames can be absolute, or relative to the source/dest dir paths.\n"
michael@0 89 "Other options are not allowed in this mode.\n");
michael@0 90 fprintf(where,
michael@0 91 "\n"
michael@0 92 "Options:\n"
michael@0 93 "\t(Only the last occurrence of an option is used.)\n"
michael@0 94 "\n"
michael@0 95 "\t-h or -? or --help print this message and exit\n");
michael@0 96 fprintf(where,
michael@0 97 "\n"
michael@0 98 "\t-tl or --type l output for little-endian/ASCII charset family\n"
michael@0 99 "\t-tb or --type b output for big-endian/ASCII charset family\n"
michael@0 100 "\t-te or --type e output for big-endian/EBCDIC charset family\n"
michael@0 101 "\t The output type defaults to the input type.\n"
michael@0 102 "\n"
michael@0 103 "\t-c or --copyright include the ICU copyright notice\n"
michael@0 104 "\t-C comment or --comment comment include a comment string\n");
michael@0 105 fprintf(where,
michael@0 106 "\n"
michael@0 107 "\t-a list or --add list add items to the package\n"
michael@0 108 "\t-r list or --remove list remove items from the package\n"
michael@0 109 "\t-x list or --extract list extract items from the package\n"
michael@0 110 "\tThe list can be a single item's filename,\n"
michael@0 111 "\tor a .txt filename with a list of item filenames,\n"
michael@0 112 "\tor an ICU .dat package filename.\n");
michael@0 113 fprintf(where,
michael@0 114 "\n"
michael@0 115 "\t-w or --writepkg write the output package even if no items are removed\n"
michael@0 116 "\t or added (e.g., for only swapping the data)\n");
michael@0 117 fprintf(where,
michael@0 118 "\n"
michael@0 119 "\t-m mode or --matchmode mode set the matching mode for item names with\n"
michael@0 120 "\t wildcards\n"
michael@0 121 "\t noslash: the '*' wildcard does not match the '/' tree separator\n");
michael@0 122 fprintf(where,
michael@0 123 "\n"
michael@0 124 "\tIn the .dat package, the Table of Contents (ToC) contains an entry\n"
michael@0 125 "\tfor each item of the form prefix/tree/itemname .\n"
michael@0 126 "\tThe prefix normally matches the package basename, and icupkg checks that,\n"
michael@0 127 "\tbut this is not necessary when ICU need not find and load the package by filename.\n"
michael@0 128 "\tICU package names end with the platform type letter, and thus differ\n"
michael@0 129 "\tbetween platform types. This is not required for user data packages.\n");
michael@0 130 fprintf(where,
michael@0 131 "\n"
michael@0 132 "\t--auto_toc_prefix automatic ToC entries prefix\n"
michael@0 133 "\t Uses the prefix of the first entry of the\n"
michael@0 134 "\t input package, rather than its basename.\n"
michael@0 135 "\t Requires a non-empty input package.\n"
michael@0 136 "\t--auto_toc_prefix_with_type auto_toc_prefix + adjust platform type\n"
michael@0 137 "\t Same as auto_toc_prefix but also checks that\n"
michael@0 138 "\t the prefix ends with the input platform\n"
michael@0 139 "\t type letter, and modifies it to the output\n"
michael@0 140 "\t platform type letter.\n"
michael@0 141 "\t At most one of the auto_toc_prefix options\n"
michael@0 142 "\t can be used at a time.\n"
michael@0 143 "\t--toc_prefix prefix ToC prefix to be used in the output package\n"
michael@0 144 "\t Overrides the package basename\n"
michael@0 145 "\t and --auto_toc_prefix.\n"
michael@0 146 "\t Cannot be combined with --auto_toc_prefix_with_type.\n");
michael@0 147 /*
michael@0 148 * Usage text columns, starting after the initial TAB.
michael@0 149 * 1 2 3 4 5 6 7 8
michael@0 150 * 901234567890123456789012345678901234567890123456789012345678901234567890
michael@0 151 */
michael@0 152 fprintf(where,
michael@0 153 "\n"
michael@0 154 "\tList file syntax: Items are listed on one or more lines and separated\n"
michael@0 155 "\tby whitespace (space+tab).\n"
michael@0 156 "\tComments begin with # and are ignored. Empty lines are ignored.\n"
michael@0 157 "\tLines where the first non-whitespace character is one of %s\n"
michael@0 158 "\tare also ignored, to reserve for future syntax.\n",
michael@0 159 U_PKG_RESERVED_CHARS);
michael@0 160 fprintf(where,
michael@0 161 "\tItems for removal or extraction may contain a single '*' wildcard\n"
michael@0 162 "\tcharacter. The '*' matches zero or more characters.\n"
michael@0 163 "\tIf --matchmode noslash (-m noslash) is set, then the '*'\n"
michael@0 164 "\tdoes not match '/'.\n");
michael@0 165 fprintf(where,
michael@0 166 "\n"
michael@0 167 "\tItems must be listed relative to the package, and the --sourcedir or\n"
michael@0 168 "\tthe --destdir path will be prepended.\n"
michael@0 169 "\tThe paths are only prepended to item filenames while adding or\n"
michael@0 170 "\textracting items, not to ICU .dat package or list filenames.\n"
michael@0 171 "\t\n"
michael@0 172 "\tPaths may contain '/' instead of the platform's\n"
michael@0 173 "\tfile separator character, and are converted as appropriate.\n");
michael@0 174 fprintf(where,
michael@0 175 "\n"
michael@0 176 "\t-s path or --sourcedir path directory for the --add items\n"
michael@0 177 "\t-d path or --destdir path directory for the --extract items\n"
michael@0 178 "\n"
michael@0 179 "\t-l or --list list the package items\n"
michael@0 180 "\t (after modifying the package)\n"
michael@0 181 "\t to stdout or to output list file\n"
michael@0 182 "\t-o path or --outlist path path/filename for the --list output\n");
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 static UOption options[]={
michael@0 187 UOPTION_HELP_H,
michael@0 188 UOPTION_HELP_QUESTION_MARK,
michael@0 189 UOPTION_DEF("type", 't', UOPT_REQUIRES_ARG),
michael@0 190
michael@0 191 UOPTION_COPYRIGHT,
michael@0 192 UOPTION_DEF("comment", 'C', UOPT_REQUIRES_ARG),
michael@0 193
michael@0 194 UOPTION_SOURCEDIR,
michael@0 195 UOPTION_DESTDIR,
michael@0 196
michael@0 197 UOPTION_DEF("writepkg", 'w', UOPT_NO_ARG),
michael@0 198
michael@0 199 UOPTION_DEF("matchmode", 'm', UOPT_REQUIRES_ARG),
michael@0 200
michael@0 201 UOPTION_DEF("add", 'a', UOPT_REQUIRES_ARG),
michael@0 202 UOPTION_DEF("remove", 'r', UOPT_REQUIRES_ARG),
michael@0 203 UOPTION_DEF("extract", 'x', UOPT_REQUIRES_ARG),
michael@0 204
michael@0 205 UOPTION_DEF("list", 'l', UOPT_NO_ARG),
michael@0 206 UOPTION_DEF("outlist", 'o', UOPT_REQUIRES_ARG),
michael@0 207
michael@0 208 UOPTION_DEF("auto_toc_prefix", '\1', UOPT_NO_ARG),
michael@0 209 UOPTION_DEF("auto_toc_prefix_with_type", '\1', UOPT_NO_ARG),
michael@0 210 UOPTION_DEF("toc_prefix", '\1', UOPT_REQUIRES_ARG)
michael@0 211 };
michael@0 212
michael@0 213 enum {
michael@0 214 OPT_HELP_H,
michael@0 215 OPT_HELP_QUESTION_MARK,
michael@0 216 OPT_OUT_TYPE,
michael@0 217
michael@0 218 OPT_COPYRIGHT,
michael@0 219 OPT_COMMENT,
michael@0 220
michael@0 221 OPT_SOURCEDIR,
michael@0 222 OPT_DESTDIR,
michael@0 223
michael@0 224 OPT_WRITEPKG,
michael@0 225
michael@0 226 OPT_MATCHMODE,
michael@0 227
michael@0 228 OPT_ADD_LIST,
michael@0 229 OPT_REMOVE_LIST,
michael@0 230 OPT_EXTRACT_LIST,
michael@0 231
michael@0 232 OPT_LIST_ITEMS,
michael@0 233 OPT_LIST_FILE,
michael@0 234
michael@0 235 OPT_AUTO_TOC_PREFIX,
michael@0 236 OPT_AUTO_TOC_PREFIX_WITH_TYPE,
michael@0 237 OPT_TOC_PREFIX,
michael@0 238
michael@0 239 OPT_COUNT
michael@0 240 };
michael@0 241
michael@0 242 static UBool
michael@0 243 isPackageName(const char *filename) {
michael@0 244 int32_t len;
michael@0 245
michael@0 246 len=(int32_t)strlen(filename)-4; /* -4: subtract the length of ".dat" */
michael@0 247 return (UBool)(len>0 && 0==strcmp(filename+len, ".dat"));
michael@0 248 }
michael@0 249 /*
michael@0 250 This line is required by MinGW because it incorrectly globs the arguments.
michael@0 251 So when \* is used, it turns into a list of files instead of a literal "*"
michael@0 252 */
michael@0 253 int _CRT_glob = 0;
michael@0 254
michael@0 255 extern int
michael@0 256 main(int argc, char *argv[]) {
michael@0 257 const char *pname, *sourcePath, *destPath, *inFilename, *outFilename, *outComment;
michael@0 258 char outType;
michael@0 259 UBool isHelp, isModified, isPackage;
michael@0 260 int result = 0;
michael@0 261
michael@0 262 Package *pkg, *listPkg, *addListPkg;
michael@0 263
michael@0 264 U_MAIN_INIT_ARGS(argc, argv);
michael@0 265
michael@0 266 /* get the program basename */
michael@0 267 pname=findBasename(argv[0]);
michael@0 268
michael@0 269 argc=u_parseArgs(argc, argv, LENGTHOF(options), options);
michael@0 270 isHelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur;
michael@0 271 if(isHelp) {
michael@0 272 printUsage(pname, TRUE);
michael@0 273 return U_ZERO_ERROR;
michael@0 274 }
michael@0 275
michael@0 276 pkg=new Package;
michael@0 277 if(pkg==NULL) {
michael@0 278 fprintf(stderr, "icupkg: not enough memory\n");
michael@0 279 return U_MEMORY_ALLOCATION_ERROR;
michael@0 280 }
michael@0 281 isModified=FALSE;
michael@0 282
michael@0 283 int autoPrefix=0;
michael@0 284 if(options[OPT_AUTO_TOC_PREFIX].doesOccur) {
michael@0 285 pkg->setAutoPrefix();
michael@0 286 ++autoPrefix;
michael@0 287 }
michael@0 288 if(options[OPT_AUTO_TOC_PREFIX_WITH_TYPE].doesOccur) {
michael@0 289 if(options[OPT_TOC_PREFIX].doesOccur) {
michael@0 290 fprintf(stderr, "icupkg: --auto_toc_prefix_with_type and also --toc_prefix\n");
michael@0 291 printUsage(pname, FALSE);
michael@0 292 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 293 }
michael@0 294 pkg->setAutoPrefixWithType();
michael@0 295 ++autoPrefix;
michael@0 296 }
michael@0 297 if(argc<2 || 3<argc || autoPrefix>1) {
michael@0 298 printUsage(pname, FALSE);
michael@0 299 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 300 }
michael@0 301
michael@0 302 if(options[OPT_SOURCEDIR].doesOccur) {
michael@0 303 sourcePath=options[OPT_SOURCEDIR].value;
michael@0 304 } else {
michael@0 305 // work relative to the current working directory
michael@0 306 sourcePath=NULL;
michael@0 307 }
michael@0 308 if(options[OPT_DESTDIR].doesOccur) {
michael@0 309 destPath=options[OPT_DESTDIR].value;
michael@0 310 } else {
michael@0 311 // work relative to the current working directory
michael@0 312 destPath=NULL;
michael@0 313 }
michael@0 314
michael@0 315 if(0==strcmp(argv[1], "new")) {
michael@0 316 if(autoPrefix) {
michael@0 317 fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but no input package\n");
michael@0 318 printUsage(pname, FALSE);
michael@0 319 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 320 }
michael@0 321 inFilename=NULL;
michael@0 322 isPackage=TRUE;
michael@0 323 } else {
michael@0 324 inFilename=argv[1];
michael@0 325 if(isPackageName(inFilename)) {
michael@0 326 pkg->readPackage(inFilename);
michael@0 327 isPackage=TRUE;
michael@0 328 } else {
michael@0 329 /* swap a single file (icuswap replacement) rather than work on a package */
michael@0 330 pkg->addFile(sourcePath, inFilename);
michael@0 331 isPackage=FALSE;
michael@0 332 }
michael@0 333 }
michael@0 334
michael@0 335 if(argc>=3) {
michael@0 336 outFilename=argv[2];
michael@0 337 if(0!=strcmp(argv[1], argv[2])) {
michael@0 338 isModified=TRUE;
michael@0 339 }
michael@0 340 } else if(isPackage) {
michael@0 341 outFilename=NULL;
michael@0 342 } else /* !isPackage */ {
michael@0 343 outFilename=inFilename;
michael@0 344 isModified=(UBool)(sourcePath!=destPath);
michael@0 345 }
michael@0 346
michael@0 347 /* parse the output type option */
michael@0 348 if(options[OPT_OUT_TYPE].doesOccur) {
michael@0 349 const char *type=options[OPT_OUT_TYPE].value;
michael@0 350 if(type[0]==0 || type[1]!=0) {
michael@0 351 /* the type must be exactly one letter */
michael@0 352 printUsage(pname, FALSE);
michael@0 353 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 354 }
michael@0 355 outType=type[0];
michael@0 356 switch(outType) {
michael@0 357 case 'l':
michael@0 358 case 'b':
michael@0 359 case 'e':
michael@0 360 break;
michael@0 361 default:
michael@0 362 printUsage(pname, FALSE);
michael@0 363 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 364 }
michael@0 365
michael@0 366 /*
michael@0 367 * Set the isModified flag if the output type differs from the
michael@0 368 * input package type.
michael@0 369 * If we swap a single file, just assume that we are modifying it.
michael@0 370 * The Package class does not give us access to the item and its type.
michael@0 371 */
michael@0 372 isModified|=(UBool)(!isPackage || outType!=pkg->getInType());
michael@0 373 } else if(isPackage) {
michael@0 374 outType=pkg->getInType(); // default to input type
michael@0 375 } else /* !isPackage: swap single file */ {
michael@0 376 outType=0; /* tells extractItem() to not swap */
michael@0 377 }
michael@0 378
michael@0 379 if(options[OPT_WRITEPKG].doesOccur) {
michael@0 380 isModified=TRUE;
michael@0 381 }
michael@0 382
michael@0 383 if(!isPackage) {
michael@0 384 /*
michael@0 385 * icuswap tool replacement: Only swap a single file.
michael@0 386 * Check that irrelevant options are not set.
michael@0 387 */
michael@0 388 if( options[OPT_COMMENT].doesOccur ||
michael@0 389 options[OPT_COPYRIGHT].doesOccur ||
michael@0 390 options[OPT_MATCHMODE].doesOccur ||
michael@0 391 options[OPT_REMOVE_LIST].doesOccur ||
michael@0 392 options[OPT_ADD_LIST].doesOccur ||
michael@0 393 options[OPT_EXTRACT_LIST].doesOccur ||
michael@0 394 options[OPT_LIST_ITEMS].doesOccur
michael@0 395 ) {
michael@0 396 printUsage(pname, FALSE);
michael@0 397 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 398 }
michael@0 399 if(isModified) {
michael@0 400 pkg->extractItem(destPath, outFilename, 0, outType);
michael@0 401 }
michael@0 402
michael@0 403 delete pkg;
michael@0 404 return result;
michael@0 405 }
michael@0 406
michael@0 407 /* Work with a package. */
michael@0 408
michael@0 409 if(options[OPT_COMMENT].doesOccur) {
michael@0 410 outComment=options[OPT_COMMENT].value;
michael@0 411 } else if(options[OPT_COPYRIGHT].doesOccur) {
michael@0 412 outComment=U_COPYRIGHT_STRING;
michael@0 413 } else {
michael@0 414 outComment=NULL;
michael@0 415 }
michael@0 416
michael@0 417 if(options[OPT_MATCHMODE].doesOccur) {
michael@0 418 if(0==strcmp(options[OPT_MATCHMODE].value, "noslash")) {
michael@0 419 pkg->setMatchMode(Package::MATCH_NOSLASH);
michael@0 420 } else {
michael@0 421 printUsage(pname, FALSE);
michael@0 422 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 /* remove items */
michael@0 427 if(options[OPT_REMOVE_LIST].doesOccur) {
michael@0 428 listPkg=new Package();
michael@0 429 if(listPkg==NULL) {
michael@0 430 fprintf(stderr, "icupkg: not enough memory\n");
michael@0 431 exit(U_MEMORY_ALLOCATION_ERROR);
michael@0 432 }
michael@0 433 if(readList(NULL, options[OPT_REMOVE_LIST].value, FALSE, listPkg)) {
michael@0 434 pkg->removeItems(*listPkg);
michael@0 435 delete listPkg;
michael@0 436 isModified=TRUE;
michael@0 437 } else {
michael@0 438 printUsage(pname, FALSE);
michael@0 439 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 440 }
michael@0 441 }
michael@0 442
michael@0 443 /*
michael@0 444 * add items
michael@0 445 * use a separate Package so that its memory and items stay around
michael@0 446 * as long as the main Package
michael@0 447 */
michael@0 448 addListPkg=NULL;
michael@0 449 if(options[OPT_ADD_LIST].doesOccur) {
michael@0 450 addListPkg=new Package();
michael@0 451 if(addListPkg==NULL) {
michael@0 452 fprintf(stderr, "icupkg: not enough memory\n");
michael@0 453 exit(U_MEMORY_ALLOCATION_ERROR);
michael@0 454 }
michael@0 455 if(readList(sourcePath, options[OPT_ADD_LIST].value, TRUE, addListPkg)) {
michael@0 456 pkg->addItems(*addListPkg);
michael@0 457 // delete addListPkg; deferred until after writePackage()
michael@0 458 isModified=TRUE;
michael@0 459 } else {
michael@0 460 printUsage(pname, FALSE);
michael@0 461 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 462 }
michael@0 463 }
michael@0 464
michael@0 465 /* extract items */
michael@0 466 if(options[OPT_EXTRACT_LIST].doesOccur) {
michael@0 467 listPkg=new Package();
michael@0 468 if(listPkg==NULL) {
michael@0 469 fprintf(stderr, "icupkg: not enough memory\n");
michael@0 470 exit(U_MEMORY_ALLOCATION_ERROR);
michael@0 471 }
michael@0 472 if(readList(NULL, options[OPT_EXTRACT_LIST].value, FALSE, listPkg)) {
michael@0 473 pkg->extractItems(destPath, *listPkg, outType);
michael@0 474 delete listPkg;
michael@0 475 } else {
michael@0 476 printUsage(pname, FALSE);
michael@0 477 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 478 }
michael@0 479 }
michael@0 480
michael@0 481 /* list items */
michael@0 482 if(options[OPT_LIST_ITEMS].doesOccur) {
michael@0 483 int32_t i;
michael@0 484 if (options[OPT_LIST_FILE].doesOccur) {
michael@0 485 FileStream *out;
michael@0 486 out = T_FileStream_open(options[OPT_LIST_FILE].value, "w");
michael@0 487 if (out != NULL) {
michael@0 488 for(i=0; i<pkg->getItemCount(); ++i) {
michael@0 489 T_FileStream_writeLine(out, pkg->getItem(i)->name);
michael@0 490 T_FileStream_writeLine(out, "\n");
michael@0 491 }
michael@0 492 T_FileStream_close(out);
michael@0 493 } else {
michael@0 494 return U_ILLEGAL_ARGUMENT_ERROR;
michael@0 495 }
michael@0 496 } else {
michael@0 497 for(i=0; i<pkg->getItemCount(); ++i) {
michael@0 498 fprintf(stdout, "%s\n", pkg->getItem(i)->name);
michael@0 499 }
michael@0 500 }
michael@0 501 }
michael@0 502
michael@0 503 /* check dependencies between items */
michael@0 504 if(!pkg->checkDependencies()) {
michael@0 505 /* some dependencies are not fulfilled */
michael@0 506 return U_MISSING_RESOURCE_ERROR;
michael@0 507 }
michael@0 508
michael@0 509 /* write the output .dat package if there are any modifications */
michael@0 510 if(isModified) {
michael@0 511 char outFilenameBuffer[1024]; // for auto-generated output filename, if necessary
michael@0 512
michael@0 513 if(outFilename==NULL || outFilename[0]==0) {
michael@0 514 if(inFilename==NULL || inFilename[0]==0) {
michael@0 515 fprintf(stderr, "icupkg: unable to auto-generate an output filename if there is no input filename\n");
michael@0 516 exit(U_ILLEGAL_ARGUMENT_ERROR);
michael@0 517 }
michael@0 518
michael@0 519 /*
michael@0 520 * auto-generate a filename:
michael@0 521 * copy the inFilename,
michael@0 522 * and if the last basename character matches the input file's type,
michael@0 523 * then replace it with the output file's type
michael@0 524 */
michael@0 525 char suffix[6]="?.dat";
michael@0 526 char *s;
michael@0 527
michael@0 528 suffix[0]=pkg->getInType();
michael@0 529 strcpy(outFilenameBuffer, inFilename);
michael@0 530 s=strchr(outFilenameBuffer, 0);
michael@0 531 if((s-outFilenameBuffer)>5 && 0==memcmp(s-5, suffix, 5)) {
michael@0 532 *(s-5)=outType;
michael@0 533 }
michael@0 534 outFilename=outFilenameBuffer;
michael@0 535 }
michael@0 536 if(options[OPT_TOC_PREFIX].doesOccur) {
michael@0 537 pkg->setPrefix(options[OPT_TOC_PREFIX].value);
michael@0 538 }
michael@0 539 result = writePackageDatFile(outFilename, outComment, NULL, NULL, pkg, outType);
michael@0 540 }
michael@0 541
michael@0 542 delete addListPkg;
michael@0 543 delete pkg;
michael@0 544 return result;
michael@0 545 }
michael@0 546
michael@0 547 /*
michael@0 548 * Hey, Emacs, please set the following:
michael@0 549 *
michael@0 550 * Local Variables:
michael@0 551 * indent-tabs-mode: nil
michael@0 552 * End:
michael@0 553 *
michael@0 554 */

mercurial