/*
*******************************************************************************
*
-* Copyright (C) 2005-2012, International Business Machines
+* Copyright (C) 2005-2013, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
"\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
"\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");
}
}
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 {
OPT_EXTRACT_LIST,
OPT_LIST_ITEMS,
-
OPT_LIST_FILE,
+ OPT_AUTO_TOC_PREFIX,
+ OPT_AUTO_TOC_PREFIX_WITH_TYPE,
+ OPT_TOC_PREFIX,
+
OPT_COUNT
};
printUsage(pname, TRUE);
return U_ZERO_ERROR;
}
- if(argc<2 || 3<argc) {
- printUsage(pname, FALSE);
- return U_ILLEGAL_ARGUMENT_ERROR;
- }
pkg=new Package;
if(pkg==NULL) {
}
isModified=FALSE;
+ int autoPrefix=0;
+ if(options[OPT_AUTO_TOC_PREFIX].doesOccur) {
+ pkg->setAutoPrefix();
+ ++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 || 3<argc || autoPrefix>1) {
+ printUsage(pname, FALSE);
+ return U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
if(options[OPT_SOURCEDIR].doesOccur) {
sourcePath=options[OPT_SOURCEDIR].value;
} else {
}
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 {
}
outFilename=outFilenameBuffer;
}
+ if(options[OPT_TOC_PREFIX].doesOccur) {
+ pkg->setPrefix(options[OPT_TOC_PREFIX].value);
+ }
result = writePackageDatFile(outFilename, outComment, NULL, NULL, pkg, outType);
}
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;
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;
}
/* 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);
}
/* 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
// 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,
* 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;
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;
// 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)) {
/*
*******************************************************************************
*
-* Copyright (C) 2005-2010, International Business Machines
+* Copyright (C) 2005-2013, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
/* 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,
// 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;