From bc9b2693534e8f2dd39d92b2a6137a99a5fde9d7 Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Mon, 8 Apr 2013 21:31:58 +0000 Subject: [PATCH] ICU-7881 add icupkg options --auto_toc_prefix --auto_toc_prefix_with_type --toc_prefix X-SVN-Rev: 33500 --- icu4c/source/tools/icupkg/icupkg.cpp | 75 ++++++++++++++++--- icu4c/source/tools/toolutil/package.cpp | 99 +++++++++++++++++++------ icu4c/source/tools/toolutil/package.h | 19 ++++- 3 files changed, 160 insertions(+), 33 deletions(-) diff --git a/icu4c/source/tools/icupkg/icupkg.cpp b/icu4c/source/tools/icupkg/icupkg.cpp index 4ae7ac4983e..bba26586590 100644 --- a/icu4c/source/tools/icupkg/icupkg.cpp +++ b/icu4c/source/tools/icupkg/icupkg.cpp @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 2005-2012, International Business Machines +* Copyright (C) 2005-2013, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -118,6 +118,30 @@ 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"); /* * Usage text columns, starting after the initial TAB. * 1 2 3 4 5 6 7 8 @@ -150,8 +174,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 or to output list file\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"); } } @@ -175,8 +201,11 @@ static UOption options[]={ UOPTION_DEF("extract", 'x', UOPT_REQUIRES_ARG), UOPTION_DEF("list", 'l', UOPT_NO_ARG), - - UOPTION_DEF("outlist", 'o', UOPT_REQUIRES_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 { @@ -199,9 +228,12 @@ 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 }; @@ -238,10 +270,6 @@ main(int argc, char *argv[]) { 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 { @@ -264,6 +311,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 { @@ -479,6 +531,9 @@ main(int argc, char *argv[]) { } outFilename=outFilenameBuffer; } + if(options[OPT_TOC_PREFIX].doesOccur) { + pkg->setPrefix(options[OPT_TOC_PREFIX].value); + } result = writePackageDatFile(outFilename, outComment, NULL, NULL, pkg, outType); } diff --git a/icu4c/source/tools/toolutil/package.cpp b/icu4c/source/tools/toolutil/package.cpp index e470332ca6c..e8d7bf7d1ec 100644 --- a/icu4c/source/tools/toolutil/package.cpp +++ b/icu4c/source/tools/toolutil/package.cpp @@ -384,8 +384,10 @@ U_CDECL_END U_NAMESPACE_BEGIN -Package::Package() { +Package::Package() + : doAutoPrefix(FALSE), prefixEndsWithType(FALSE) { inPkgName[0]=0; + pkgPrefix[0]=0; inData=NULL; inLength=0; inCharset=U_CHARSET_FAMILY; @@ -432,6 +434,15 @@ Package::~Package() { uprv_free((void*)items); } +void +Package::setPrefix(const char *p) { + if(strlen(p)>=sizeof(pkgPrefix)) { + fprintf(stderr, "icupkg: --toc_prefix %s too long\n", p); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + strcpy(pkgPrefix, p); +} + void Package::readPackage(const char *filename) { UDataSwapper *ds; @@ -523,10 +534,14 @@ Package::readPackage(const char *filename) { } /* do not modify the package length variable until the last item's length is set */ - if(itemCount>0) { + if(itemCount<=0) { + if(doAutoPrefix) { + fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but the input package is empty\n"); + exit(U_INVALID_FORMAT_ERROR); + } + } else { char prefix[MAX_PKG_NAME_LENGTH+4]; char *s, *inItemStrings; - int32_t inPkgNameLength, prefixLength, stringsOffset; if(itemCount>itemMax) { fprintf(stderr, "icupkg: too many items, maximum is %d\n", itemMax); @@ -534,7 +549,7 @@ Package::readPackage(const char *filename) { } /* swap the item name strings */ - stringsOffset=4+8*itemCount; + int32_t stringsOffset=4+8*itemCount; itemLength=(int32_t)(ds->readUInt32(inEntries[0].dataOffset))-stringsOffset; // don't include padding bytes at the end of the item names @@ -558,10 +573,6 @@ Package::readPackage(const char *filename) { // reset the Item entries memset(items, 0, itemCount*sizeof(Item)); - inPkgNameLength=strlen(inPkgName); - memcpy(prefix, inPkgName, inPkgNameLength); - prefixLength=inPkgNameLength; - /* * Get the common prefix of the items. * New-style ICU .dat packages use tree separators ('/') between package names, @@ -570,18 +581,53 @@ Package::readPackage(const char *filename) { * use an underscore ('_') between package and item names. */ offset=(int32_t)ds->readUInt32(inEntries[0].nameOffset)-stringsOffset; - s=inItemStrings+offset; - if( (int32_t)strlen(s)>=(inPkgNameLength+2) && - 0==memcmp(s, inPkgName, inPkgNameLength) && - s[inPkgNameLength]=='_' - ) { - // old-style .dat package - prefix[prefixLength++]='_'; + s=inItemStrings+offset; // name of the first entry + int32_t prefixLength; + if(doAutoPrefix) { + // Use the first entry's prefix. Must be a new-style package. + const char *prefixLimit=strchr(s, U_TREE_ENTRY_SEP_CHAR); + if(prefixLimit==NULL) { + fprintf(stderr, + "icupkg: --auto_toc_prefix[_with_type] but " + "the first entry \"%s\" does not contain a '%c'\n", + s, U_TREE_ENTRY_SEP_CHAR); + exit(U_INVALID_FORMAT_ERROR); + } + prefixLength=(int32_t)(prefixLimit-s); + if(prefixLength==0 || prefixLength>=LENGTHOF(pkgPrefix)) { + fprintf(stderr, + "icupkg: --auto_toc_prefix[_with_type] but " + "the prefix of the first entry \"%s\" is empty or too long\n", + s); + exit(U_INVALID_FORMAT_ERROR); + } + if(prefixEndsWithType && s[prefixLength-1]!=type) { + fprintf(stderr, + "icupkg: --auto_toc_prefix_with_type but " + "the prefix of the first entry \"%s\" does not end with '%c'\n", + s, type); + exit(U_INVALID_FORMAT_ERROR); + } + memcpy(pkgPrefix, s, prefixLength); + memcpy(prefix, s, ++prefixLength); // include the / } else { - // new-style .dat package - prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; - // if it turns out to not contain U_TREE_ENTRY_SEP_CHAR - // then the test in the loop below will fail + // Use the package basename as prefix. + int32_t inPkgNameLength=strlen(inPkgName); + memcpy(prefix, inPkgName, inPkgNameLength); + prefixLength=inPkgNameLength; + + if( (int32_t)strlen(s)>=(inPkgNameLength+2) && + 0==memcmp(s, inPkgName, inPkgNameLength) && + s[inPkgNameLength]=='_' + ) { + // old-style .dat package + prefix[prefixLength++]='_'; + } else { + // new-style .dat package + prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; + // if it turns out to not contain U_TREE_ENTRY_SEP_CHAR + // then the test in the loop below will fail + } } prefix[prefixLength]=0; @@ -594,7 +640,7 @@ Package::readPackage(const char *filename) { if(0!=strncmp(s, prefix, prefixLength) || s[prefixLength]==0) { fprintf(stderr, "icupkg: input .dat item name \"%s\" does not start with \"%s\"\n", s, prefix); - exit(U_UNSUPPORTED_ERROR); + exit(U_INVALID_FORMAT_ERROR); } items[i].name=s+prefixLength; @@ -724,8 +770,17 @@ Package::writePackage(const char *filename, char outType, const char *comment) { // prepare and swap the package name with a tree separator // for prepending to item names - strcat(prefix, U_TREE_ENTRY_SEP_STRING); - prefixLength=(int32_t)strlen(prefix); + if(pkgPrefix[0]==0) { + prefixLength=(int32_t)strlen(prefix); + } else { + prefixLength=(int32_t)strlen(pkgPrefix); + memcpy(prefix, pkgPrefix, prefixLength); + if(prefixEndsWithType) { + prefix[prefixLength-1]=outType; + } + } + prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; + prefix[prefixLength]=0; if(dsLocalToOut!=NULL) { dsLocalToOut->swapInvChars(dsLocalToOut, prefix, prefixLength, prefix, &errorCode); if(U_FAILURE(errorCode)) { diff --git a/icu4c/source/tools/toolutil/package.h b/icu4c/source/tools/toolutil/package.h index 50ee72e656b..2cce5df0aa5 100644 --- a/icu4c/source/tools/toolutil/package.h +++ b/icu4c/source/tools/toolutil/package.h @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 2005-2010, International Business Machines +* Copyright (C) 2005-2013, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -51,6 +51,20 @@ public: /* Destructor. */ ~Package(); + /** + * Uses the prefix of the first entry of the package in readPackage(), + * rather than the package basename. + */ + void setAutoPrefix() { doAutoPrefix=TRUE; } + /** + * Same as setAutoPrefix(), plus the prefix must end with the platform type letter. + */ + void setAutoPrefixWithType() { + doAutoPrefix=TRUE; + prefixEndsWithType=TRUE; + } + void setPrefix(const char *p); + /* * Read an existing .dat package file. * The header and item name strings are swapped into this object, @@ -141,12 +155,15 @@ private: // data fields char inPkgName[MAX_PKG_NAME_LENGTH]; + char pkgPrefix[MAX_PKG_NAME_LENGTH]; uint8_t *inData; uint8_t header[1024]; int32_t inLength, headerLength; uint8_t inCharset; UBool inIsBigEndian; + UBool doAutoPrefix; + UBool prefixEndsWithType; int32_t itemCount; int32_t itemMax;