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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/tools/icupkg/icupkg.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,554 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +*
     1.7 +*   Copyright (C) 2005-2013, International Business Machines
     1.8 +*   Corporation and others.  All Rights Reserved.
     1.9 +*
    1.10 +*******************************************************************************
    1.11 +*   file name:  icupkg.cpp
    1.12 +*   encoding:   US-ASCII
    1.13 +*   tab size:   8 (not used)
    1.14 +*   indentation:4
    1.15 +*
    1.16 +*   created on: 2005jul29
    1.17 +*   created by: Markus W. Scherer
    1.18 +*
    1.19 +*   This tool operates on ICU data (.dat package) files.
    1.20 +*   It takes one as input, or creates an empty one, and can remove, add, and
    1.21 +*   extract data pieces according to command-line options.
    1.22 +*   At the same time, it swaps each piece to a consistent set of platform
    1.23 +*   properties as desired.
    1.24 +*   Useful as an install-time tool for shipping only one flavor of ICU data
    1.25 +*   and preparing data files for the target platform.
    1.26 +*   Also for customizing ICU data (pruning, augmenting, replacing) and for
    1.27 +*   taking it apart.
    1.28 +*   Subsumes functionality and implementation code from
    1.29 +*   gencmn, decmn, and icuswap tools.
    1.30 +*   Will not work with data DLLs (shared libraries).
    1.31 +*/
    1.32 +
    1.33 +#include "unicode/utypes.h"
    1.34 +#include "unicode/putil.h"
    1.35 +#include "cstring.h"
    1.36 +#include "toolutil.h"
    1.37 +#include "uoptions.h"
    1.38 +#include "uparse.h"
    1.39 +#include "filestrm.h"
    1.40 +#include "package.h"
    1.41 +#include "pkg_icu.h"
    1.42 +
    1.43 +#include <stdio.h>
    1.44 +#include <stdlib.h>
    1.45 +#include <string.h>
    1.46 +
    1.47 +U_NAMESPACE_USE
    1.48 +
    1.49 +// TODO: add --matchmode=regex for using the ICU regex engine for item name pattern matching?
    1.50 +
    1.51 +// general definitions ----------------------------------------------------- ***
    1.52 +
    1.53 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
    1.54 +
    1.55 +// main() ------------------------------------------------------------------ ***
    1.56 +
    1.57 +static void
    1.58 +printUsage(const char *pname, UBool isHelp) {
    1.59 +    FILE *where=isHelp ? stdout : stderr;
    1.60 +
    1.61 +    fprintf(where,
    1.62 +            "%csage: %s [-h|-?|--help ] [-tl|-tb|-te] [-c] [-C comment]\n"
    1.63 +            "\t[-a list] [-r list] [-x list] [-l [-o outputListFileName]]\n"
    1.64 +            "\t[-s path] [-d path] [-w] [-m mode]\n"
    1.65 +            "\t[--auto_toc_prefix] [--auto_toc_prefix_with_type] [--toc_prefix]\n"
    1.66 +            "\tinfilename [outfilename]\n",
    1.67 +            isHelp ? 'U' : 'u', pname);
    1.68 +    if(isHelp) {
    1.69 +        fprintf(where,
    1.70 +            "\n"
    1.71 +            "Read the input ICU .dat package file, modify it according to the options,\n"
    1.72 +            "swap it to the desired platform properties (charset & endianness),\n"
    1.73 +            "and optionally write the resulting ICU .dat package to the output file.\n"
    1.74 +            "Items are removed, then added, then extracted and listed.\n"
    1.75 +            "An ICU .dat package is written if items are removed or added,\n"
    1.76 +            "or if the input and output filenames differ,\n"
    1.77 +            "or if the --writepkg (-w) option is set.\n");
    1.78 +        fprintf(where,
    1.79 +            "\n"
    1.80 +            "If the input filename is \"new\" then an empty package is created.\n"
    1.81 +            "If the output filename is missing, then it is automatically generated\n"
    1.82 +            "from the input filename: If the input filename ends with an l, b, or e\n"
    1.83 +            "matching its platform properties, then the output filename will\n"
    1.84 +            "contain the letter from the -t (--type) option.\n");
    1.85 +        fprintf(where,
    1.86 +            "\n"
    1.87 +            "This tool can also be used to just swap a single ICU data file, replacing the\n"
    1.88 +            "former icuswap tool. For this mode, provide the infilename (and optional\n"
    1.89 +            "outfilename) for a non-package ICU data file.\n"
    1.90 +            "Allowed options include -t, -w, -s and -d.\n"
    1.91 +            "The filenames can be absolute, or relative to the source/dest dir paths.\n"
    1.92 +            "Other options are not allowed in this mode.\n");
    1.93 +        fprintf(where,
    1.94 +            "\n"
    1.95 +            "Options:\n"
    1.96 +            "\t(Only the last occurrence of an option is used.)\n"
    1.97 +            "\n"
    1.98 +            "\t-h or -? or --help    print this message and exit\n");
    1.99 +        fprintf(where,
   1.100 +            "\n"
   1.101 +            "\t-tl or --type l   output for little-endian/ASCII charset family\n"
   1.102 +            "\t-tb or --type b   output for big-endian/ASCII charset family\n"
   1.103 +            "\t-te or --type e   output for big-endian/EBCDIC charset family\n"
   1.104 +            "\t                  The output type defaults to the input type.\n"
   1.105 +            "\n"
   1.106 +            "\t-c or --copyright include the ICU copyright notice\n"
   1.107 +            "\t-C comment or --comment comment   include a comment string\n");
   1.108 +        fprintf(where,
   1.109 +            "\n"
   1.110 +            "\t-a list or --add list      add items to the package\n"
   1.111 +            "\t-r list or --remove list   remove items from the package\n"
   1.112 +            "\t-x list or --extract list  extract items from the package\n"
   1.113 +            "\tThe list can be a single item's filename,\n"
   1.114 +            "\tor a .txt filename with a list of item filenames,\n"
   1.115 +            "\tor an ICU .dat package filename.\n");
   1.116 +        fprintf(where,
   1.117 +            "\n"
   1.118 +            "\t-w or --writepkg  write the output package even if no items are removed\n"
   1.119 +            "\t                  or added (e.g., for only swapping the data)\n");
   1.120 +        fprintf(where,
   1.121 +            "\n"
   1.122 +            "\t-m mode or --matchmode mode  set the matching mode for item names with\n"
   1.123 +            "\t                             wildcards\n"
   1.124 +            "\t        noslash: the '*' wildcard does not match the '/' tree separator\n");
   1.125 +        fprintf(where,
   1.126 +            "\n"
   1.127 +            "\tIn the .dat package, the Table of Contents (ToC) contains an entry\n"
   1.128 +            "\tfor each item of the form prefix/tree/itemname .\n"
   1.129 +            "\tThe prefix normally matches the package basename, and icupkg checks that,\n"
   1.130 +            "\tbut this is not necessary when ICU need not find and load the package by filename.\n"
   1.131 +            "\tICU package names end with the platform type letter, and thus differ\n"
   1.132 +            "\tbetween platform types. This is not required for user data packages.\n");
   1.133 +        fprintf(where,
   1.134 +            "\n"
   1.135 +            "\t--auto_toc_prefix            automatic ToC entries prefix\n"
   1.136 +            "\t                             Uses the prefix of the first entry of the\n"
   1.137 +            "\t                             input package, rather than its basename.\n"
   1.138 +            "\t                             Requires a non-empty input package.\n"
   1.139 +            "\t--auto_toc_prefix_with_type  auto_toc_prefix + adjust platform type\n"
   1.140 +            "\t                             Same as auto_toc_prefix but also checks that\n"
   1.141 +            "\t                             the prefix ends with the input platform\n"
   1.142 +            "\t                             type letter, and modifies it to the output\n"
   1.143 +            "\t                             platform type letter.\n"
   1.144 +            "\t                At most one of the auto_toc_prefix options\n"
   1.145 +            "\t                can be used at a time.\n"
   1.146 +            "\t--toc_prefix prefix          ToC prefix to be used in the output package\n"
   1.147 +            "\t                             Overrides the package basename\n"
   1.148 +            "\t                             and --auto_toc_prefix.\n"
   1.149 +            "\t                             Cannot be combined with --auto_toc_prefix_with_type.\n");
   1.150 +        /*
   1.151 +         * Usage text columns, starting after the initial TAB.
   1.152 +         *      1         2         3         4         5         6         7         8
   1.153 +         *     901234567890123456789012345678901234567890123456789012345678901234567890
   1.154 +         */
   1.155 +        fprintf(where,
   1.156 +            "\n"
   1.157 +            "\tList file syntax: Items are listed on one or more lines and separated\n"
   1.158 +            "\tby whitespace (space+tab).\n"
   1.159 +            "\tComments begin with # and are ignored. Empty lines are ignored.\n"
   1.160 +            "\tLines where the first non-whitespace character is one of %s\n"
   1.161 +            "\tare also ignored, to reserve for future syntax.\n",
   1.162 +            U_PKG_RESERVED_CHARS);
   1.163 +        fprintf(where,
   1.164 +            "\tItems for removal or extraction may contain a single '*' wildcard\n"
   1.165 +            "\tcharacter. The '*' matches zero or more characters.\n"
   1.166 +            "\tIf --matchmode noslash (-m noslash) is set, then the '*'\n"
   1.167 +            "\tdoes not match '/'.\n");
   1.168 +        fprintf(where,
   1.169 +            "\n"
   1.170 +            "\tItems must be listed relative to the package, and the --sourcedir or\n"
   1.171 +            "\tthe --destdir path will be prepended.\n"
   1.172 +            "\tThe paths are only prepended to item filenames while adding or\n"
   1.173 +            "\textracting items, not to ICU .dat package or list filenames.\n"
   1.174 +            "\t\n"
   1.175 +            "\tPaths may contain '/' instead of the platform's\n"
   1.176 +            "\tfile separator character, and are converted as appropriate.\n");
   1.177 +        fprintf(where,
   1.178 +            "\n"
   1.179 +            "\t-s path or --sourcedir path  directory for the --add items\n"
   1.180 +            "\t-d path or --destdir path    directory for the --extract items\n"
   1.181 +            "\n"
   1.182 +            "\t-l or --list                 list the package items\n"
   1.183 +            "\t                             (after modifying the package)\n"
   1.184 +            "\t                             to stdout or to output list file\n"
   1.185 +            "\t-o path or --outlist path    path/filename for the --list output\n");
   1.186 +    }
   1.187 +}
   1.188 +
   1.189 +static UOption options[]={
   1.190 +    UOPTION_HELP_H,
   1.191 +    UOPTION_HELP_QUESTION_MARK,
   1.192 +    UOPTION_DEF("type", 't', UOPT_REQUIRES_ARG),
   1.193 +
   1.194 +    UOPTION_COPYRIGHT,
   1.195 +    UOPTION_DEF("comment", 'C', UOPT_REQUIRES_ARG),
   1.196 +
   1.197 +    UOPTION_SOURCEDIR,
   1.198 +    UOPTION_DESTDIR,
   1.199 +
   1.200 +    UOPTION_DEF("writepkg", 'w', UOPT_NO_ARG),
   1.201 +
   1.202 +    UOPTION_DEF("matchmode", 'm', UOPT_REQUIRES_ARG),
   1.203 +
   1.204 +    UOPTION_DEF("add", 'a', UOPT_REQUIRES_ARG),
   1.205 +    UOPTION_DEF("remove", 'r', UOPT_REQUIRES_ARG),
   1.206 +    UOPTION_DEF("extract", 'x', UOPT_REQUIRES_ARG),
   1.207 +
   1.208 +    UOPTION_DEF("list", 'l', UOPT_NO_ARG),
   1.209 +    UOPTION_DEF("outlist", 'o', UOPT_REQUIRES_ARG),
   1.210 +
   1.211 +    UOPTION_DEF("auto_toc_prefix", '\1', UOPT_NO_ARG),
   1.212 +    UOPTION_DEF("auto_toc_prefix_with_type", '\1', UOPT_NO_ARG),
   1.213 +    UOPTION_DEF("toc_prefix", '\1', UOPT_REQUIRES_ARG)
   1.214 +};
   1.215 +
   1.216 +enum {
   1.217 +    OPT_HELP_H,
   1.218 +    OPT_HELP_QUESTION_MARK,
   1.219 +    OPT_OUT_TYPE,
   1.220 +
   1.221 +    OPT_COPYRIGHT,
   1.222 +    OPT_COMMENT,
   1.223 +
   1.224 +    OPT_SOURCEDIR,
   1.225 +    OPT_DESTDIR,
   1.226 +
   1.227 +    OPT_WRITEPKG,
   1.228 +
   1.229 +    OPT_MATCHMODE,
   1.230 +
   1.231 +    OPT_ADD_LIST,
   1.232 +    OPT_REMOVE_LIST,
   1.233 +    OPT_EXTRACT_LIST,
   1.234 +
   1.235 +    OPT_LIST_ITEMS,
   1.236 +    OPT_LIST_FILE,
   1.237 +
   1.238 +    OPT_AUTO_TOC_PREFIX,
   1.239 +    OPT_AUTO_TOC_PREFIX_WITH_TYPE,
   1.240 +    OPT_TOC_PREFIX,
   1.241 +
   1.242 +    OPT_COUNT
   1.243 +};
   1.244 +
   1.245 +static UBool
   1.246 +isPackageName(const char *filename) {
   1.247 +    int32_t len;
   1.248 +
   1.249 +    len=(int32_t)strlen(filename)-4; /* -4: subtract the length of ".dat" */
   1.250 +    return (UBool)(len>0 && 0==strcmp(filename+len, ".dat"));
   1.251 +}
   1.252 +/*
   1.253 +This line is required by MinGW because it incorrectly globs the arguments.
   1.254 +So when \* is used, it turns into a list of files instead of a literal "*"
   1.255 +*/
   1.256 +int _CRT_glob = 0;
   1.257 +
   1.258 +extern int
   1.259 +main(int argc, char *argv[]) {
   1.260 +    const char *pname, *sourcePath, *destPath, *inFilename, *outFilename, *outComment;
   1.261 +    char outType;
   1.262 +    UBool isHelp, isModified, isPackage;
   1.263 +    int result = 0;
   1.264 +
   1.265 +    Package *pkg, *listPkg, *addListPkg;
   1.266 +
   1.267 +    U_MAIN_INIT_ARGS(argc, argv);
   1.268 +
   1.269 +    /* get the program basename */
   1.270 +    pname=findBasename(argv[0]);
   1.271 +
   1.272 +    argc=u_parseArgs(argc, argv, LENGTHOF(options), options);
   1.273 +    isHelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur;
   1.274 +    if(isHelp) {
   1.275 +        printUsage(pname, TRUE);
   1.276 +        return U_ZERO_ERROR;
   1.277 +    }
   1.278 +
   1.279 +    pkg=new Package;
   1.280 +    if(pkg==NULL) {
   1.281 +        fprintf(stderr, "icupkg: not enough memory\n");
   1.282 +        return U_MEMORY_ALLOCATION_ERROR;
   1.283 +    }
   1.284 +    isModified=FALSE;
   1.285 +
   1.286 +    int autoPrefix=0;
   1.287 +    if(options[OPT_AUTO_TOC_PREFIX].doesOccur) {
   1.288 +        pkg->setAutoPrefix();
   1.289 +        ++autoPrefix;
   1.290 +    }
   1.291 +    if(options[OPT_AUTO_TOC_PREFIX_WITH_TYPE].doesOccur) {
   1.292 +        if(options[OPT_TOC_PREFIX].doesOccur) {
   1.293 +            fprintf(stderr, "icupkg: --auto_toc_prefix_with_type and also --toc_prefix\n");
   1.294 +            printUsage(pname, FALSE);
   1.295 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.296 +        }
   1.297 +        pkg->setAutoPrefixWithType();
   1.298 +        ++autoPrefix;
   1.299 +    }
   1.300 +    if(argc<2 || 3<argc || autoPrefix>1) {
   1.301 +        printUsage(pname, FALSE);
   1.302 +        return U_ILLEGAL_ARGUMENT_ERROR;
   1.303 +    }
   1.304 +
   1.305 +    if(options[OPT_SOURCEDIR].doesOccur) {
   1.306 +        sourcePath=options[OPT_SOURCEDIR].value;
   1.307 +    } else {
   1.308 +        // work relative to the current working directory
   1.309 +        sourcePath=NULL;
   1.310 +    }
   1.311 +    if(options[OPT_DESTDIR].doesOccur) {
   1.312 +        destPath=options[OPT_DESTDIR].value;
   1.313 +    } else {
   1.314 +        // work relative to the current working directory
   1.315 +        destPath=NULL;
   1.316 +    }
   1.317 +
   1.318 +    if(0==strcmp(argv[1], "new")) {
   1.319 +        if(autoPrefix) {
   1.320 +            fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but no input package\n");
   1.321 +            printUsage(pname, FALSE);
   1.322 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.323 +        }
   1.324 +        inFilename=NULL;
   1.325 +        isPackage=TRUE;
   1.326 +    } else {
   1.327 +        inFilename=argv[1];
   1.328 +        if(isPackageName(inFilename)) {
   1.329 +            pkg->readPackage(inFilename);
   1.330 +            isPackage=TRUE;
   1.331 +        } else {
   1.332 +            /* swap a single file (icuswap replacement) rather than work on a package */
   1.333 +            pkg->addFile(sourcePath, inFilename);
   1.334 +            isPackage=FALSE;
   1.335 +        }
   1.336 +    }
   1.337 +
   1.338 +    if(argc>=3) {
   1.339 +        outFilename=argv[2];
   1.340 +        if(0!=strcmp(argv[1], argv[2])) {
   1.341 +            isModified=TRUE;
   1.342 +        }
   1.343 +    } else if(isPackage) {
   1.344 +        outFilename=NULL;
   1.345 +    } else /* !isPackage */ {
   1.346 +        outFilename=inFilename;
   1.347 +        isModified=(UBool)(sourcePath!=destPath);
   1.348 +    }
   1.349 +
   1.350 +    /* parse the output type option */
   1.351 +    if(options[OPT_OUT_TYPE].doesOccur) {
   1.352 +        const char *type=options[OPT_OUT_TYPE].value;
   1.353 +        if(type[0]==0 || type[1]!=0) {
   1.354 +            /* the type must be exactly one letter */
   1.355 +            printUsage(pname, FALSE);
   1.356 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.357 +        }
   1.358 +        outType=type[0];
   1.359 +        switch(outType) {
   1.360 +        case 'l':
   1.361 +        case 'b':
   1.362 +        case 'e':
   1.363 +            break;
   1.364 +        default:
   1.365 +            printUsage(pname, FALSE);
   1.366 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.367 +        }
   1.368 +
   1.369 +        /*
   1.370 +         * Set the isModified flag if the output type differs from the
   1.371 +         * input package type.
   1.372 +         * If we swap a single file, just assume that we are modifying it.
   1.373 +         * The Package class does not give us access to the item and its type.
   1.374 +         */
   1.375 +        isModified|=(UBool)(!isPackage || outType!=pkg->getInType());
   1.376 +    } else if(isPackage) {
   1.377 +        outType=pkg->getInType(); // default to input type
   1.378 +    } else /* !isPackage: swap single file */ {
   1.379 +        outType=0; /* tells extractItem() to not swap */
   1.380 +    }
   1.381 +
   1.382 +    if(options[OPT_WRITEPKG].doesOccur) {
   1.383 +        isModified=TRUE;
   1.384 +    }
   1.385 +
   1.386 +    if(!isPackage) {
   1.387 +        /*
   1.388 +         * icuswap tool replacement: Only swap a single file.
   1.389 +         * Check that irrelevant options are not set.
   1.390 +         */
   1.391 +        if( options[OPT_COMMENT].doesOccur ||
   1.392 +            options[OPT_COPYRIGHT].doesOccur ||
   1.393 +            options[OPT_MATCHMODE].doesOccur ||
   1.394 +            options[OPT_REMOVE_LIST].doesOccur ||
   1.395 +            options[OPT_ADD_LIST].doesOccur ||
   1.396 +            options[OPT_EXTRACT_LIST].doesOccur ||
   1.397 +            options[OPT_LIST_ITEMS].doesOccur
   1.398 +        ) {
   1.399 +            printUsage(pname, FALSE);
   1.400 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.401 +        }
   1.402 +        if(isModified) {
   1.403 +            pkg->extractItem(destPath, outFilename, 0, outType);
   1.404 +        }
   1.405 +
   1.406 +        delete pkg;
   1.407 +        return result;
   1.408 +    }
   1.409 +
   1.410 +    /* Work with a package. */
   1.411 +
   1.412 +    if(options[OPT_COMMENT].doesOccur) {
   1.413 +        outComment=options[OPT_COMMENT].value;
   1.414 +    } else if(options[OPT_COPYRIGHT].doesOccur) {
   1.415 +        outComment=U_COPYRIGHT_STRING;
   1.416 +    } else {
   1.417 +        outComment=NULL;
   1.418 +    }
   1.419 +
   1.420 +    if(options[OPT_MATCHMODE].doesOccur) {
   1.421 +        if(0==strcmp(options[OPT_MATCHMODE].value, "noslash")) {
   1.422 +            pkg->setMatchMode(Package::MATCH_NOSLASH);
   1.423 +        } else {
   1.424 +            printUsage(pname, FALSE);
   1.425 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.426 +        }
   1.427 +    }
   1.428 +
   1.429 +    /* remove items */
   1.430 +    if(options[OPT_REMOVE_LIST].doesOccur) {
   1.431 +        listPkg=new Package();
   1.432 +        if(listPkg==NULL) {
   1.433 +            fprintf(stderr, "icupkg: not enough memory\n");
   1.434 +            exit(U_MEMORY_ALLOCATION_ERROR);
   1.435 +        }
   1.436 +        if(readList(NULL, options[OPT_REMOVE_LIST].value, FALSE, listPkg)) {
   1.437 +            pkg->removeItems(*listPkg);
   1.438 +            delete listPkg;
   1.439 +            isModified=TRUE;
   1.440 +        } else {
   1.441 +            printUsage(pname, FALSE);
   1.442 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.443 +        }
   1.444 +    }
   1.445 +
   1.446 +    /*
   1.447 +     * add items
   1.448 +     * use a separate Package so that its memory and items stay around
   1.449 +     * as long as the main Package
   1.450 +     */
   1.451 +    addListPkg=NULL;
   1.452 +    if(options[OPT_ADD_LIST].doesOccur) {
   1.453 +        addListPkg=new Package();
   1.454 +        if(addListPkg==NULL) {
   1.455 +            fprintf(stderr, "icupkg: not enough memory\n");
   1.456 +            exit(U_MEMORY_ALLOCATION_ERROR);
   1.457 +        }
   1.458 +        if(readList(sourcePath, options[OPT_ADD_LIST].value, TRUE, addListPkg)) {
   1.459 +            pkg->addItems(*addListPkg);
   1.460 +            // delete addListPkg; deferred until after writePackage()
   1.461 +            isModified=TRUE;
   1.462 +        } else {
   1.463 +            printUsage(pname, FALSE);
   1.464 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.465 +        }
   1.466 +    }
   1.467 +
   1.468 +    /* extract items */
   1.469 +    if(options[OPT_EXTRACT_LIST].doesOccur) {
   1.470 +        listPkg=new Package();
   1.471 +        if(listPkg==NULL) {
   1.472 +            fprintf(stderr, "icupkg: not enough memory\n");
   1.473 +            exit(U_MEMORY_ALLOCATION_ERROR);
   1.474 +        }
   1.475 +        if(readList(NULL, options[OPT_EXTRACT_LIST].value, FALSE, listPkg)) {
   1.476 +            pkg->extractItems(destPath, *listPkg, outType);
   1.477 +            delete listPkg;
   1.478 +        } else {
   1.479 +            printUsage(pname, FALSE);
   1.480 +            return U_ILLEGAL_ARGUMENT_ERROR;
   1.481 +        }
   1.482 +    }
   1.483 +
   1.484 +    /* list items */
   1.485 +    if(options[OPT_LIST_ITEMS].doesOccur) {
   1.486 +        int32_t i;
   1.487 +        if (options[OPT_LIST_FILE].doesOccur) {
   1.488 +            FileStream *out;
   1.489 +            out = T_FileStream_open(options[OPT_LIST_FILE].value, "w");
   1.490 +            if (out != NULL) {
   1.491 +                for(i=0; i<pkg->getItemCount(); ++i) {
   1.492 +                    T_FileStream_writeLine(out, pkg->getItem(i)->name);
   1.493 +                    T_FileStream_writeLine(out, "\n");
   1.494 +                }
   1.495 +                T_FileStream_close(out);
   1.496 +            } else {
   1.497 +                return U_ILLEGAL_ARGUMENT_ERROR;
   1.498 +            }
   1.499 +        } else {
   1.500 +            for(i=0; i<pkg->getItemCount(); ++i) {
   1.501 +                fprintf(stdout, "%s\n", pkg->getItem(i)->name);
   1.502 +            }
   1.503 +        }
   1.504 +    }
   1.505 +
   1.506 +    /* check dependencies between items */
   1.507 +    if(!pkg->checkDependencies()) {
   1.508 +        /* some dependencies are not fulfilled */
   1.509 +        return U_MISSING_RESOURCE_ERROR;
   1.510 +    }
   1.511 +
   1.512 +    /* write the output .dat package if there are any modifications */
   1.513 +    if(isModified) {
   1.514 +        char outFilenameBuffer[1024]; // for auto-generated output filename, if necessary
   1.515 +
   1.516 +        if(outFilename==NULL || outFilename[0]==0) {
   1.517 +            if(inFilename==NULL || inFilename[0]==0) {
   1.518 +                fprintf(stderr, "icupkg: unable to auto-generate an output filename if there is no input filename\n");
   1.519 +                exit(U_ILLEGAL_ARGUMENT_ERROR);
   1.520 +            }
   1.521 +
   1.522 +            /*
   1.523 +             * auto-generate a filename:
   1.524 +             * copy the inFilename,
   1.525 +             * and if the last basename character matches the input file's type,
   1.526 +             * then replace it with the output file's type
   1.527 +             */
   1.528 +            char suffix[6]="?.dat";
   1.529 +            char *s;
   1.530 +
   1.531 +            suffix[0]=pkg->getInType();
   1.532 +            strcpy(outFilenameBuffer, inFilename);
   1.533 +            s=strchr(outFilenameBuffer, 0);
   1.534 +            if((s-outFilenameBuffer)>5 && 0==memcmp(s-5, suffix, 5)) {
   1.535 +                *(s-5)=outType;
   1.536 +            }
   1.537 +            outFilename=outFilenameBuffer;
   1.538 +        }
   1.539 +        if(options[OPT_TOC_PREFIX].doesOccur) {
   1.540 +            pkg->setPrefix(options[OPT_TOC_PREFIX].value);
   1.541 +        }
   1.542 +        result = writePackageDatFile(outFilename, outComment, NULL, NULL, pkg, outType);
   1.543 +    }
   1.544 +
   1.545 +    delete addListPkg;
   1.546 +    delete pkg;
   1.547 +    return result;
   1.548 +}
   1.549 +
   1.550 +/*
   1.551 + * Hey, Emacs, please set the following:
   1.552 + *
   1.553 + * Local Variables:
   1.554 + * indent-tabs-mode: nil
   1.555 + * End:
   1.556 + *
   1.557 + */

mercurial