blob: 58ec8c62c33608a0a2b718180132defd1323aeda [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2000-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: pkgdata.c
* encoding: ANSI X3.4 (1968)
* tab size: 8 (not used)
* indentation:4
*
* created on: 2000may15
* created by: Steven \u24C7 Loomis
*
* This program packages the ICU data into different forms
* (DLL, common data, etc.)
*/
#include <stdio.h>
#include <stdlib.h>
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "cmemory.h"
#include "cstring.h"
#include "filestrm.h"
#include "toolutil.h"
#include "unewdata.h"
#include "uoptions.h"
U_CDECL_BEGIN
#include "pkgtypes.h"
#include "makefile.h"
U_CDECL_END
static int executeMakefile(const UPKGOptions *o);
static void loadLists(UPKGOptions *o, UErrorCode *status);
/* This sets the modes that are available */
static struct
{
const char *name;
UPKGMODE *fcn;
const char *desc;
} modes[] =
{
{ "files", pkg_mode_files, "Uses raw data files (no effect). Installation copies all files to the target location." },
#ifdef WIN32
{ "dll", pkg_mode_windows, "Generates one common data file and one shared library, <package>.dll"},
{ "common", pkg_mode_windows, "Generates just the common file, <package>.dat"}
#else /*#ifdef WIN32*/
#ifdef UDATA_SO_SUFFIX
{ "dll", pkg_mode_dll, "Generates one shared library, <package>" UDATA_SO_SUFFIX },
#endif
{ "common", pkg_mode_common, "Generates one common data file, <package>.dat" }
#endif /*#ifdef WIN32*/
};
static UOption options[]={
/*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG),
/*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
/*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG),
/*03*/ UOPTION_HELP_H, /* -h */
/*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */
/*05*/ UOPTION_VERBOSE, /* -v */
/*06*/ UOPTION_COPYRIGHT, /* -c */
/*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
/*08*/ UOPTION_DESTDIR, /* -d */
/*09*/ UOPTION_DEF( "clean", 'k', UOPT_NO_ARG),
/*10*/ UOPTION_DEF( "nooutput",'n', UOPT_NO_ARG),
/*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
/*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
/*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
/*14*/ UOPTION_SOURCEDIR ,
/*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
};
const char options_help[][160]={
"Set the data name",
#ifdef WIN32
"R:icupath for release version or D:icupath for debug version, where icupath is the directory where ICU is located",
#else
"Specify options for the builder",
#endif
"Specify the mode of building (see below)",
"This usage text",
"This usage text",
"Make the output verbose",
"Use the standard ICU copyright",
"Use a custom comment (instead of the copyright)",
"Specify the destination directory for files",
"Clean out generated & temporary files",
"Suppress output of data, just list files to be created",
"Force rebuilding of all data",
"Specify temporary dir (default: output dir)",
"Install the data (specify target)",
"Specify a custom source directory",
"Specify a custom entrypoint name (default: short name)"
};
int
main(int argc, char* argv[]) {
FileStream *out;
UPKGOptions o;
CharList *tail;
const char *progname;
UBool needsHelp = FALSE;
UErrorCode status = U_ZERO_ERROR;
char tmp[1024];
int32_t i;
progname = argv[0];
/* read command line options */
argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
/* error handling, printing usage message */
/* I've decided to simply print an error and quit. This tool has too
many options to just display them all of the time. */
if(options[3].doesOccur || options[4].doesOccur) {
needsHelp = TRUE;
}
else {
if(!needsHelp && argc<0) {
fprintf(stderr,
"%s: error in command line argument \"%s\"\n",
progname,
argv[-argc]);
fprintf(stderr, "Run '%s --help' for help.\n", progname);
return 1;
}
if(! (options[0].doesOccur && options[1].doesOccur &&
options[2].doesOccur) ) {
fprintf(stderr, " required parameters are missing: -p AND -O AND -m \n");
fprintf(stderr, "Run '%s --help' for help.\n", progname);
return 1;
}
if(argc == 1) {
fprintf(stderr,
"No input files specified.\n"
"Run '%s --help' for help.\n", progname);
return 1;
}
} /* end !needsHelp */
if(argc<0 || needsHelp ) {
fprintf(stderr,
"usage: %s [-options] [-] [packageFile] \n"
"\tProduce packaged ICU data from the given list(s) of files.\n"
"\t'-' by itself means to read from stdin.\n"
"\tpackageFile is a text file containing the list of files to package.\n",
progname);
fprintf(stderr, "\n options:\n");
for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
fprintf(stderr, "%-5s -%c or --%-10s %s\n",
(i<3?"[REQ]":""),
options[i].shortName,
options[i].longName,
options_help[i]);
}
fprintf(stderr, "modes: (-m option)\n");
for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
fprintf(stderr, " %-10s %s\n", modes[i].name, modes[i].desc);
}
return 1;
}
/* OK, fill in the options struct */
uprv_memset(&o, 0, sizeof(o));
o.mode = options[2].value;
o.fcn = NULL;
for(i=0;i<sizeof(modes)/sizeof(modes[0]);i++) {
if(!uprv_strcmp(modes[i].name, o.mode)) {
o.fcn = modes[i].fcn;
break;
}
}
if(o.fcn == NULL) {
fprintf(stderr, "Error: invalid mode '%s' specified. Run '%s --help' to list valid modes.\n", o.mode, progname);
return 1;
}
o.shortName = options[0].value;
#ifdef WIN32 /* format is R:pathtoICU or D:pathtoICU */
{
char *pathstuff = (char *)options[1].value;
if(options[1].value[uprv_strlen(options[1].value)-1] == '\\') {
pathstuff[uprv_strlen(options[1].value)-1] = '\0';
}
if(*pathstuff == 'R' || *pathstuff == 'D') {
o.options = pathstuff;
pathstuff++;
if(*pathstuff == ':') {
*pathstuff = '\0';
pathstuff++;
} else {
fprintf(stderr, "Error: invalid windows build mode, should be R (release) or D (debug).\n", o.mode, progname);
return 1;
}
} else {
fprintf(stderr, "Error: invalid windows build mode, should be R (release) or D (debug).\n", o.mode, progname);
return 1;
}
o.icuroot = pathstuff;
}
#else /* on UNIX, we'll just include the file... */
o.options = options[1].value;
#endif
o.verbose = options[5].doesOccur;
if(options[6].doesOccur) {
o.comment = U_COPYRIGHT_STRING;
} else if (options[7].doesOccur) {
o.comment = options[7].value;
}
if( options[8].doesOccur ) {
o.targetDir = options[8].value;
} else {
o.targetDir = ""; /* cwd */
}
o.clean = options[9].doesOccur;
o.nooutput = options[10].doesOccur;
o.rebuild = options[11].doesOccur;
if( options[12].doesOccur ) {
o.tmpDir = options[12].value;
} else {
o.tmpDir = o.targetDir;
}
if( options[13].doesOccur ) {
o.install = options[13].value;
}
if( options[14].doesOccur ) {
o.srcDir = options[14].value;
} else {
o.srcDir = ".";
}
if( options[15].doesOccur ) {
o.entryName = options[15].value;
} else {
o.entryName = o.shortName;
}
/* OK options are set up. Now the file lists. */
tail = NULL;
for( i=1; i<argc; i++) {
if ( !uprv_strcmp(argv[i] , "-") ) {
/* stdin */
if( o.hadStdin == TRUE ) {
fprintf(stderr, "Error: can't specify '-' twice!\n"
"Run '%s --help' for help.\n", progname);
return 1;
}
o.hadStdin = TRUE;
}
o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[i]));
}
/* load the files */
loadLists(&o, &status);
if( U_FAILURE(status) ) {
fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
return 2;
}
/* Makefile pathname */
uprv_strcpy(tmp, o.tmpDir);
uprv_strcat(tmp, U_FILE_SEP_STRING);
uprv_strcat(tmp, o.shortName);
uprv_strcat(tmp, "_");
uprv_strcat(tmp, o.mode);
uprv_strcat(tmp, ".mak"); /* MAY NEED TO CHANGE PER PLATFORM */
o.makeFile = uprv_strdup(tmp);
out = T_FileStream_open(o.makeFile, "w");
pkg_mak_writeHeader(out, &o); /* need to take status */
o.fcn(&o, out, &status);
pkg_mak_writeFooter(out, &o);
T_FileStream_close(out);
if(U_FAILURE(status)) {
fprintf(stderr, "Error creating makefile [%s]: %s\n", o.mode,
u_errorName(status));
return 1;
}
if(o.nooutput == TRUE) {
return 0; /* nothing to do. */
}
return executeMakefile(&o);
}
/* POSIX - execute makefile */
static int executeMakefile(const UPKGOptions *o)
{
char cmd[1024];
/*char pwd[1024];*/
const char *make;
int rc;
make = getenv("MAKE");
if(!make || !make[0]) {
make = U_MAKE;
}
/*getcwd(pwd, 1024);*/
#ifdef WIN32
sprintf(cmd, "%s %s%s -f \"%s\" %s %s %s",
make,
o->install ? "INSTALLTO=" : "",
o->install ? o->install : "",
o->makeFile,
o->clean ? "clean" : "",
o->rebuild ? "rebuild" : "",
o->install ? "install" : "");
#elif OS400
sprintf(cmd, "CALL GNU/GMAKE PARM(%s%s%s '-f' '%s' %s %s %s)",
o->install ? "'INSTALLTO=" : "",
o->install ? o->install : "",
o->install ? "'" : "",
o->makeFile,
o->clean ? "'clean'" : "",
o->rebuild ? "'rebuild'" : "",
o->install ? "'install'" : "");
#else
sprintf(cmd, "%s %s%s -f %s %s %s %s",
make,
o->install ? "INSTALLTO=" : "",
o->install ? o->install : "",
o->makeFile,
o->clean ? "clean" : "",
o->rebuild ? "rebuild" : "",
o->install ? "install" : "");
#endif
if(o->verbose) {
puts(cmd);
}
rc = system(cmd);
if(rc < 0) {
fprintf(stderr, "# Failed, rc=%d\n", rc);
}
return rc < 128 ? rc : (rc >> 8);
}
static void loadLists(UPKGOptions *o, UErrorCode *status)
{
CharList *l, *tail = NULL, *tail2 = NULL;
FileStream *in;
char line[2048];
char tmp[1024];
const char* baseName;
char *s;
for(l = o->fileListFiles; l; l = l->next) {
if(o->verbose) {
fprintf(stdout, "# Reading %s..\n", l->str);
}
/* TODO: stdin */
in = T_FileStream_open(l->str, "r");
if(!in) {
fprintf(stderr, "Error opening <%s>.\n", l->str);
*status = U_FILE_ACCESS_ERROR;
return;
}
while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) {
/* remove trailing newline characters */
s=line;
while(*s!=0) {
if(*s=='\r' || *s=='\n') {
*s=0;
break;
}
++s;
}
if((*line == 0) || (*line == '#')) {
continue; /* comment or empty line */
}
/* add the file */
s = (char*)getLongPathname(line);
baseName = findBasename(s);
o->files = pkg_appendToList(o->files, &tail, uprv_strdup(baseName));
if(s != baseName) { /* s was something long, so we leave it as it is */
o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(s));
} else { /* s was just a basename, we want to prepend source dir*/
uprv_strcpy(tmp, o->srcDir);
uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1]==U_FILE_SEP_CHAR?"":U_FILE_SEP_STRING);
uprv_strcat(tmp, s);
o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
}
}
T_FileStream_close(in);
}
}