X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..f3c0d7a59d99c2a94c6b8822291f0e42be3773c9:/icuSources/tools/icupkg/icupkg.cpp?ds=sidebyside diff --git a/icuSources/tools/icupkg/icupkg.cpp b/icuSources/tools/icupkg/icupkg.cpp index 93c488dd..ea7be4a9 100644 --- a/icuSources/tools/icupkg/icupkg.cpp +++ b/icuSources/tools/icupkg/icupkg.cpp @@ -1,12 +1,14 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* * -* Copyright (C) 2005-2006, International Business Machines +* Copyright (C) 2005-2014, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: icupkg.cpp -* encoding: US-ASCII +* encoding: UTF-8 * tab size: 8 (not used) * indentation:4 * @@ -33,145 +35,20 @@ #include "toolutil.h" #include "uoptions.h" #include "uparse.h" +#include "filestrm.h" #include "package.h" +#include "pkg_icu.h" #include #include #include +U_NAMESPACE_USE + // TODO: add --matchmode=regex for using the ICU regex engine for item name pattern matching? // general definitions ----------------------------------------------------- *** -#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) - -// read a file list -------------------------------------------------------- *** - -static const char *reservedChars="\"%&'()*+,-./:;<=>?_"; - -static const struct { - const char *suffix; - int32_t length; -} listFileSuffixes[]={ - { ".txt", 4 }, - { ".lst", 4 }, - { ".tmp", 4 } -}; - -/* check for multiple text file suffixes to see if this list name is a text file name */ -static UBool -isListTextFile(const char *listname) { - const char *listNameEnd=strchr(listname, 0); - const char *suffix; - int32_t i, length; - for(i=0; ilength && 0==memcmp(listNameEnd-length, suffix, length)) { - return TRUE; - } - } - return FALSE; -} - -/* - * Read a file list. - * If the listname ends with ".txt", then read the list file - * (in the system/ invariant charset). - * If the listname ends with ".dat", then read the ICU .dat package file. - * Otherwise, read the file itself as a single-item list. - */ -static Package * -readList(const char *filesPath, const char *listname, UBool readContents) { - Package *listPkg; - FILE *file; - const char *listNameEnd; - - if(listname==NULL || listname[0]==0) { - fprintf(stderr, "missing list file\n"); - return NULL; - } - - listPkg=new Package(); - if(listPkg==NULL) { - fprintf(stderr, "icupkg: not enough memory\n"); - exit(U_MEMORY_ALLOCATION_ERROR); - } - - listNameEnd=strchr(listname, 0); - if(isListTextFile(listname)) { - // read the list file - char line[1024]; - char *end; - const char *start; - - file=fopen(listname, "r"); - if(file==NULL) { - fprintf(stderr, "icupkg: unable to open list file \"%s\"\n", listname); - delete listPkg; - exit(U_FILE_ACCESS_ERROR); - } - - while(fgets(line, sizeof(line), file)) { - // remove comments - end=strchr(line, '#'); - if(end!=NULL) { - *end=0; - } else { - // remove trailing CR LF - end=strchr(line, 0); - while(lineaddFile(filesPath, start); - } else { - listPkg->addItem(start); - } - - // find the start of the next item or exit the loop - if(end==NULL || *(start=u_skipWhitespace(end+1))==0) { - break; - } - } - } - fclose(file); - } else if((listNameEnd-listname)>4 && 0==memcmp(listNameEnd-4, ".dat", 4)) { - // read the ICU .dat package - listPkg->readPackage(listname); - } else { - // list the single file itself - if(readContents) { - listPkg->addFile(filesPath, listname); - } else { - listPkg->addItem(listname); - } - } - - return listPkg; -} - // main() ------------------------------------------------------------------ *** static void @@ -180,8 +57,9 @@ printUsage(const char *pname, UBool isHelp) { fprintf(where, "%csage: %s [-h|-?|--help ] [-tl|-tb|-te] [-c] [-C comment]\n" - "\t[-a list] [-r list] [-x list] [-l]\n" + "\t[-a list] [-r list] [-x list] [-l [-o outputListFileName]]\n" "\t[-s path] [-d path] [-w] [-m mode]\n" + "\t[--auto_toc_prefix] [--auto_toc_prefix_with_type] [--toc_prefix]\n" "\tinfilename [outfilename]\n", isHelp ? 'U' : 'u', pname); if(isHelp) { @@ -241,6 +119,31 @@ printUsage(const char *pname, UBool isHelp) { "\t-m mode or --matchmode mode set the matching mode for item names with\n" "\t wildcards\n" "\t noslash: the '*' wildcard does not match the '/' tree separator\n"); + fprintf(where, + "\n" + "\tIn the .dat package, the Table of Contents (ToC) contains an entry\n" + "\tfor each item of the form prefix/tree/itemname .\n" + "\tThe prefix normally matches the package basename, and icupkg checks that,\n" + "\tbut this is not necessary when ICU need not find and load the package by filename.\n" + "\tICU package names end with the platform type letter, and thus differ\n" + "\tbetween platform types. This is not required for user data packages.\n"); + fprintf(where, + "\n" + "\t--auto_toc_prefix automatic ToC entries prefix\n" + "\t Uses the prefix of the first entry of the\n" + "\t input package, rather than its basename.\n" + "\t Requires a non-empty input package.\n" + "\t--auto_toc_prefix_with_type auto_toc_prefix + adjust platform type\n" + "\t Same as auto_toc_prefix but also checks that\n" + "\t the prefix ends with the input platform\n" + "\t type letter, and modifies it to the output\n" + "\t platform type letter.\n" + "\t At most one of the auto_toc_prefix options\n" + "\t can be used at a time.\n" + "\t--toc_prefix prefix ToC prefix to be used in the output package\n" + "\t Overrides the package basename\n" + "\t and --auto_toc_prefix.\n" + "\t Cannot be combined with --auto_toc_prefix_with_type.\n"); /* * Usage text columns, starting after the initial TAB. * 1 2 3 4 5 6 7 8 @@ -253,7 +156,7 @@ printUsage(const char *pname, UBool isHelp) { "\tComments begin with # and are ignored. Empty lines are ignored.\n" "\tLines where the first non-whitespace character is one of %s\n" "\tare also ignored, to reserve for future syntax.\n", - reservedChars); + U_PKG_RESERVED_CHARS); fprintf(where, "\tItems for removal or extraction may contain a single '*' wildcard\n" "\tcharacter. The '*' matches zero or more characters.\n" @@ -273,8 +176,10 @@ printUsage(const char *pname, UBool isHelp) { "\t-s path or --sourcedir path directory for the --add items\n" "\t-d path or --destdir path directory for the --extract items\n" "\n" - "\t-l or --list list the package items to stdout\n" - "\t (after modifying the package)\n"); + "\t-l or --list list the package items\n" + "\t (after modifying the package)\n" + "\t to stdout or to output list file\n" + "\t-o path or --outlist path path/filename for the --list output\n"); } } @@ -297,7 +202,12 @@ static UOption options[]={ UOPTION_DEF("remove", 'r', UOPT_REQUIRES_ARG), UOPTION_DEF("extract", 'x', UOPT_REQUIRES_ARG), - UOPTION_DEF("list", 'l', UOPT_NO_ARG) + UOPTION_DEF("list", 'l', UOPT_NO_ARG), + UOPTION_DEF("outlist", 'o', UOPT_REQUIRES_ARG), + + UOPTION_DEF("auto_toc_prefix", '\1', UOPT_NO_ARG), + UOPTION_DEF("auto_toc_prefix_with_type", '\1', UOPT_NO_ARG), + UOPTION_DEF("toc_prefix", '\1', UOPT_REQUIRES_ARG) }; enum { @@ -320,6 +230,11 @@ enum { OPT_EXTRACT_LIST, OPT_LIST_ITEMS, + OPT_LIST_FILE, + + OPT_AUTO_TOC_PREFIX, + OPT_AUTO_TOC_PREFIX_WITH_TYPE, + OPT_TOC_PREFIX, OPT_COUNT }; @@ -331,30 +246,32 @@ isPackageName(const char *filename) { len=(int32_t)strlen(filename)-4; /* -4: subtract the length of ".dat" */ return (UBool)(len>0 && 0==strcmp(filename+len, ".dat")); } +/* +This line is required by MinGW because it incorrectly globs the arguments. +So when \* is used, it turns into a list of files instead of a literal "*" +*/ +int _CRT_glob = 0; extern int main(int argc, char *argv[]) { const char *pname, *sourcePath, *destPath, *inFilename, *outFilename, *outComment; char outType; UBool isHelp, isModified, isPackage; + int result = 0; - Package *pkg, *listPkg; + Package *pkg, *listPkg, *addListPkg; U_MAIN_INIT_ARGS(argc, argv); /* get the program basename */ pname=findBasename(argv[0]); - argc=u_parseArgs(argc, argv, LENGTHOF(options), options); + argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); isHelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur; if(isHelp) { printUsage(pname, TRUE); return U_ZERO_ERROR; } - if(argc<2 || 3setAutoPrefix(); + ++autoPrefix; + } + if(options[OPT_AUTO_TOC_PREFIX_WITH_TYPE].doesOccur) { + if(options[OPT_TOC_PREFIX].doesOccur) { + fprintf(stderr, "icupkg: --auto_toc_prefix_with_type and also --toc_prefix\n"); + printUsage(pname, FALSE); + return U_ILLEGAL_ARGUMENT_ERROR; + } + pkg->setAutoPrefixWithType(); + ++autoPrefix; + } + if(argc<2 || 31) { + printUsage(pname, FALSE); + return U_ILLEGAL_ARGUMENT_ERROR; + } + if(options[OPT_SOURCEDIR].doesOccur) { sourcePath=options[OPT_SOURCEDIR].value; } else { @@ -377,6 +313,11 @@ main(int argc, char *argv[]) { } if(0==strcmp(argv[1], "new")) { + if(autoPrefix) { + fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but no input package\n"); + printUsage(pname, FALSE); + return U_ILLEGAL_ARGUMENT_ERROR; + } inFilename=NULL; isPackage=TRUE; } else { @@ -428,7 +369,7 @@ main(int argc, char *argv[]) { * If we swap a single file, just assume that we are modifying it. * The Package class does not give us access to the item and its type. */ - isModified=(UBool)(!isPackage || outType!=pkg->getInType()); + isModified|=(UBool)(!isPackage || outType!=pkg->getInType()); } else if(isPackage) { outType=pkg->getInType(); // default to input type } else /* !isPackage: swap single file */ { @@ -460,7 +401,7 @@ main(int argc, char *argv[]) { } delete pkg; - return 0; + return result; } /* Work with a package. */ @@ -484,8 +425,12 @@ main(int argc, char *argv[]) { /* remove items */ if(options[OPT_REMOVE_LIST].doesOccur) { - listPkg=readList(NULL, options[OPT_REMOVE_LIST].value, FALSE); - if(listPkg!=NULL) { + listPkg=new Package(); + if(listPkg==NULL) { + fprintf(stderr, "icupkg: not enough memory\n"); + exit(U_MEMORY_ALLOCATION_ERROR); + } + if(readList(NULL, options[OPT_REMOVE_LIST].value, FALSE, listPkg)) { pkg->removeItems(*listPkg); delete listPkg; isModified=TRUE; @@ -500,11 +445,16 @@ main(int argc, char *argv[]) { * use a separate Package so that its memory and items stay around * as long as the main Package */ + addListPkg=NULL; if(options[OPT_ADD_LIST].doesOccur) { - listPkg=readList(sourcePath, options[OPT_ADD_LIST].value, TRUE); - if(listPkg!=NULL) { - pkg->addItems(*listPkg); - delete listPkg; + addListPkg=new Package(); + if(addListPkg==NULL) { + fprintf(stderr, "icupkg: not enough memory\n"); + exit(U_MEMORY_ALLOCATION_ERROR); + } + if(readList(sourcePath, options[OPT_ADD_LIST].value, TRUE, addListPkg)) { + pkg->addItems(*addListPkg); + // delete addListPkg; deferred until after writePackage() isModified=TRUE; } else { printUsage(pname, FALSE); @@ -514,8 +464,12 @@ main(int argc, char *argv[]) { /* extract items */ if(options[OPT_EXTRACT_LIST].doesOccur) { - listPkg=readList(NULL, options[OPT_EXTRACT_LIST].value, FALSE); - if(listPkg!=NULL) { + listPkg=new Package(); + if(listPkg==NULL) { + fprintf(stderr, "icupkg: not enough memory\n"); + exit(U_MEMORY_ALLOCATION_ERROR); + } + if(readList(NULL, options[OPT_EXTRACT_LIST].value, FALSE, listPkg)) { pkg->extractItems(destPath, *listPkg, outType); delete listPkg; } else { @@ -526,7 +480,24 @@ main(int argc, char *argv[]) { /* list items */ if(options[OPT_LIST_ITEMS].doesOccur) { - pkg->listItems(stdout); + int32_t i; + if (options[OPT_LIST_FILE].doesOccur) { + FileStream *out; + out = T_FileStream_open(options[OPT_LIST_FILE].value, "w"); + if (out != NULL) { + for(i=0; igetItemCount(); ++i) { + T_FileStream_writeLine(out, pkg->getItem(i)->name); + T_FileStream_writeLine(out, "\n"); + } + T_FileStream_close(out); + } else { + return U_ILLEGAL_ARGUMENT_ERROR; + } + } else { + for(i=0; igetItemCount(); ++i) { + fprintf(stdout, "%s\n", pkg->getItem(i)->name); + } + } } /* check dependencies between items */ @@ -562,11 +533,15 @@ main(int argc, char *argv[]) { } outFilename=outFilenameBuffer; } - pkg->writePackage(outFilename, outType, outComment); + if(options[OPT_TOC_PREFIX].doesOccur) { + pkg->setPrefix(options[OPT_TOC_PREFIX].value); + } + result = writePackageDatFile(outFilename, outComment, NULL, NULL, pkg, outType); } + delete addListPkg; delete pkg; - return 0; + return result; } /*