1999-11-22 17:56:30 +00:00
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1999-12-13 22:28:37 +00:00
*
2006-02-24 19:47:47 +00:00
* Copyright ( C ) 1999 - 2006 , International Business Machines
1999-12-13 22:28:37 +00:00
* Corporation and others . All Rights Reserved .
*
1999-11-22 17:56:30 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* file name : gencmn . c
* encoding : US - ASCII
* tab size : 8 ( not used )
* indentation : 4
*
* created on : 1999 nov01
* created by : Markus W . Scherer
*
* This program reads a list of data files and combines them
* into one common , memory - mappable file .
*/
# include <stdio.h>
# include <stdlib.h>
1999-12-28 23:57:50 +00:00
# include "unicode/utypes.h"
2001-01-03 00:18:57 +00:00
# include "unicode/putil.h"
1999-11-22 17:56:30 +00:00
# include "cmemory.h"
# include "cstring.h"
# include "filestrm.h"
1999-11-23 04:49:35 +00:00
# include "toolutil.h"
2003-08-14 21:34:54 +00:00
# include "unicode/uclean.h"
1999-11-23 04:49:35 +00:00
# include "unewdata.h"
2000-04-18 20:31:36 +00:00
# include "uoptions.h"
2006-08-15 23:27:31 +00:00
# include "putilimp.h"
1999-11-22 17:56:30 +00:00
# define STRING_STORE_SIZE 100000
# define MAX_FILE_COUNT 2000
2000-11-22 01:30:53 +00:00
# define COMMON_DATA_NAME U_ICUDATA_NAME
1999-11-22 17:56:30 +00:00
# define DATA_TYPE "dat"
2003-09-18 16:58:32 +00:00
/* ICU package data file format (.dat files) ------------------------------- ***
Description of the data format after the usual ICU data file header
( UDataInfo etc . ) .
Format version 1
A . dat package file contains a simple Table of Contents of item names ,
followed by the items themselves :
1. ToC table
uint32_t count ; - number of items
UDataOffsetTOCEntry entry [ count ] ; - pair of uint32_t values per item :
uint32_t nameOffset ; - offset of the item name
uint32_t dataOffset ; - offset of the item data
both are byte offsets from the beginning of the data
2. item name strings
All item names are stored as char * strings in one block between the ToC table
and the data items .
3. data items
The data items are stored following the item names block .
Each data item is 16 - aligned .
The data items are stored in the sorted order of their names .
Therefore , the top of the name strings block is the offset of the first item ,
the length of the last item is the difference between its offset and
the . dat file length , and the length of all previous items is the difference
between its offset and the next one .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1999-11-22 17:56:30 +00:00
/* UDataInfo cf. udata.h */
static const UDataInfo dataInfo = {
sizeof ( UDataInfo ) ,
0 ,
U_IS_BIG_ENDIAN ,
U_CHARSET_FAMILY ,
sizeof ( UChar ) ,
0 ,
2001-03-26 21:14:50 +00:00
{ 0x43 , 0x6d , 0x6e , 0x44 } , /* dataFormat="CmnD" */
{ 1 , 0 , 0 , 0 } , /* formatVersion */
{ 3 , 0 , 0 , 0 } /* dataVersion */
1999-11-22 17:56:30 +00:00
} ;
static uint32_t maxSize ;
static char stringStore [ STRING_STORE_SIZE ] ;
static uint32_t stringTop = 0 , basenameTotal = 0 ;
typedef struct {
char * pathname , * basename ;
uint32_t basenameLength , basenameOffset , fileSize , fileOffset ;
} File ;
static File files [ MAX_FILE_COUNT ] ;
static uint32_t fileCount = 0 ;
/* prototypes --------------------------------------------------------------- */
static void
2002-02-06 21:05:34 +00:00
addFile ( const char * filename , UBool sourceTOC , UBool verbose ) ;
1999-11-22 17:56:30 +00:00
static char *
allocString ( uint32_t length ) ;
static int
compareFiles ( const void * file1 , const void * file2 ) ;
2004-04-14 20:08:16 +00:00
static char *
pathToFullPath ( const char * path ) ;
2004-04-23 23:15:15 +00:00
/* map non-tree separator (such as '\') to tree separator ('/') inplace. */
static void
fixDirToTreePath ( char * s ) ;
1999-11-22 17:56:30 +00:00
/* -------------------------------------------------------------------------- */
2000-04-18 20:31:36 +00:00
static UOption options [ ] = {
2000-12-06 03:02:21 +00:00
/*0*/ UOPTION_HELP_H ,
/*1*/ UOPTION_HELP_QUESTION_MARK ,
/*2*/ UOPTION_VERBOSE ,
/*3*/ UOPTION_COPYRIGHT ,
/*4*/ UOPTION_DESTDIR ,
/*5*/ UOPTION_DEF ( " comment " , ' C ' , UOPT_REQUIRES_ARG ) ,
/*6*/ UOPTION_DEF ( " name " , ' n ' , UOPT_REQUIRES_ARG ) ,
/*7*/ UOPTION_DEF ( " type " , ' t ' , UOPT_REQUIRES_ARG ) ,
/*8*/ UOPTION_DEF ( " source " , ' S ' , UOPT_NO_ARG ) ,
2004-04-14 20:08:16 +00:00
/*9*/ UOPTION_DEF ( " entrypoint " , ' e ' , UOPT_REQUIRES_ARG ) ,
/*10*/ UOPTION_SOURCEDIR ,
2000-04-18 20:31:36 +00:00
} ;
2002-07-17 03:56:50 +00:00
static char * symPrefix = NULL ;
2000-08-30 23:58:24 +00:00
1999-11-22 17:56:30 +00:00
extern int
2000-09-21 21:49:32 +00:00
main ( int argc , char * argv [ ] ) {
2001-03-26 21:14:50 +00:00
static char buffer [ 4096 ] ;
1999-11-22 17:56:30 +00:00
char line [ 512 ] ;
FileStream * in , * file ;
char * s ;
UErrorCode errorCode = U_ZERO_ERROR ;
2002-02-06 21:05:34 +00:00
uint32_t i , fileOffset , basenameOffset , length , nread ;
UBool sourceTOC , verbose ;
2000-12-06 03:02:21 +00:00
const char * entrypointName = NULL ;
1999-11-22 17:56:30 +00:00
2002-03-15 23:47:04 +00:00
U_MAIN_INIT_ARGS ( argc , argv ) ;
2000-04-18 20:31:36 +00:00
/* preset then read command line options */
options [ 4 ] . value = u_getDataDirectory ( ) ;
options [ 6 ] . value = COMMON_DATA_NAME ;
options [ 7 ] . value = DATA_TYPE ;
2004-04-14 20:08:16 +00:00
options [ 10 ] . value = " . " ;
2000-04-18 20:31:36 +00:00
argc = u_parseArgs ( argc , argv , sizeof ( options ) / sizeof ( options [ 0 ] ) , options ) ;
/* error handling, printing usage message */
if ( argc < 0 ) {
fprintf ( stderr ,
" error in command line argument \" %s \" \n " ,
argv [ - argc ] ) ;
} else if ( argc < 2 ) {
argc = - 1 ;
}
2004-04-14 20:08:16 +00:00
2000-04-18 20:31:36 +00:00
if ( argc < 0 | | options [ 0 ] . doesOccur | | options [ 1 ] . doesOccur ) {
2002-02-12 20:04:52 +00:00
FILE * where = argc < 0 ? stderr : stdout ;
2001-11-20 02:46:46 +00:00
/*
* Broken into chucks because the C89 standard says the minimum
* required supported string length is 509 bytes .
*/
2002-02-12 20:04:52 +00:00
fprintf ( where ,
2004-07-18 06:22:21 +00:00
" %csage: %s [ -h, -?, --help ] [ -v, --verbose ] [ -c, --copyright ] [ -C, --comment comment ] [ -d, --destdir dir ] [ -n, --name filename ] [ -t, --type filetype ] [ -S, --source tocfile ] [ -e, --entrypoint name ] maxsize listfile \n " , argc < 0 ? ' u ' : ' U ' , * argv ) ;
2002-04-02 00:55:09 +00:00
if ( options [ 0 ] . doesOccur | | options [ 1 ] . doesOccur ) {
2002-02-12 20:04:52 +00:00
fprintf ( where , " \n "
2004-07-18 06:22:21 +00:00
" Read the list file (default: standard input) and create a common data \n "
" file from specified files. Omit any files larger than maxsize, if maxsize > 0. \n " ) ;
2002-02-12 20:04:52 +00:00
fprintf ( where , " \n "
2002-04-04 18:58:50 +00:00
" Options: \n "
" \t -h, -?, --help this usage text \n "
" \t -v, --verbose verbose output \n "
" \t -c, --copyright include the ICU copyright notice \n "
" \t -C, --comment comment include a comment string \n "
" \t -d, --destdir dir destination directory \n " ) ;
fprintf ( where ,
" \t -n, --name filename output filename, without .type extension \n "
" \t (default: " COMMON_DATA_NAME " ) \n "
" \t -t, --type filetype type of the destination file \n "
" \t (default: \" " DATA_TYPE " \" ) \n "
" \t -S, --source tocfile write a .c source file with the table of \n "
" \t contents \n "
" \t -e, --entrypoint name override the c entrypoint name \n "
2002-06-05 21:45:39 +00:00
" \t (default: \" <name>_<type> \" ) \n " ) ;
2002-02-12 20:04:52 +00:00
}
2000-04-18 20:31:36 +00:00
return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR ;
2000-02-29 18:34:21 +00:00
}
2000-05-03 23:08:50 +00:00
sourceTOC = options [ 8 ] . doesOccur ;
2002-02-06 21:05:34 +00:00
verbose = options [ 2 ] . doesOccur ;
2001-05-22 22:25:48 +00:00
maxSize = ( uint32_t ) uprv_strtoul ( argv [ 1 ] , NULL , 0 ) ;
1999-11-22 17:56:30 +00:00
if ( argc = = 2 ) {
in = T_FileStream_stdin ( ) ;
} else {
in = T_FileStream_open ( argv [ 2 ] , " r " ) ;
if ( in = = NULL ) {
fprintf ( stderr , " gencmn: unable to open input file %s \n " , argv [ 2 ] ) ;
exit ( U_FILE_ACCESS_ERROR ) ;
}
}
2002-02-06 21:05:34 +00:00
if ( verbose ) {
2002-01-04 23:48:46 +00:00
if ( sourceTOC ) {
2002-02-06 21:05:34 +00:00
printf ( " generating %s_%s.c (table of contents source file) \n " , options [ 6 ] . value , options [ 7 ] . value ) ;
2002-01-04 23:48:46 +00:00
} else {
2002-02-06 21:05:34 +00:00
printf ( " generating %s.%s (common data file with table of contents) \n " , options [ 6 ] . value , options [ 7 ] . value ) ;
2002-01-04 23:48:46 +00:00
}
2000-05-03 23:08:50 +00:00
}
1999-11-22 17:56:30 +00:00
/* read the list of files and get their lengths */
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 ;
}
2001-11-13 07:48:46 +00:00
/* check for comment */
2002-04-02 03:41:50 +00:00
if ( * line = = ' # ' ) {
2001-11-13 07:48:46 +00:00
continue ;
}
/* add the file */
2004-04-22 23:27:20 +00:00
# if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
{
char * t ;
while ( ( t = uprv_strchr ( line , U_FILE_ALT_SEP_CHAR ) ) ) {
* t = U_FILE_SEP_CHAR ;
}
}
# endif
2002-02-06 21:05:34 +00:00
addFile ( getLongPathname ( line ) , sourceTOC , verbose ) ;
1999-11-22 17:56:30 +00:00
}
if ( in ! = T_FileStream_stdin ( ) ) {
T_FileStream_close ( in ) ;
}
2000-05-04 15:36:17 +00:00
if ( fileCount = = 0 ) {
2002-01-04 23:48:46 +00:00
fprintf ( stderr , " gencmn: no files listed in %s \n " , argc = = 2 ? " <stdin> " : argv [ 2 ] ) ;
2000-05-04 15:36:17 +00:00
return 0 ;
}
1999-11-22 17:56:30 +00:00
/* sort the files by basename */
qsort ( files , fileCount , sizeof ( File ) , compareFiles ) ;
2000-05-03 23:08:50 +00:00
if ( ! sourceTOC ) {
2001-03-26 21:14:50 +00:00
UNewDataMemory * out ;
2000-05-03 23:08:50 +00:00
/* determine the offsets of all basenames and files in this common one */
basenameOffset = 4 + 8 * fileCount ;
2001-03-26 21:14:50 +00:00
fileOffset = ( basenameOffset + ( basenameTotal + 15 ) ) & ~ 0xf ;
2000-05-03 23:08:50 +00:00
for ( i = 0 ; i < fileCount ; + + i ) {
files [ i ] . fileOffset = fileOffset ;
fileOffset + = ( files [ i ] . fileSize + 15 ) & ~ 0xf ;
files [ i ] . basenameOffset = basenameOffset ;
basenameOffset + = files [ i ] . basenameLength ;
}
1999-11-22 17:56:30 +00:00
2000-05-03 23:08:50 +00:00
/* create the output file */
out = udata_create ( options [ 4 ] . value , options [ 7 ] . value , options [ 6 ] . value ,
& dataInfo ,
options [ 3 ] . doesOccur ? U_COPYRIGHT_STRING : options [ 5 ] . value ,
& errorCode ) ;
if ( U_FAILURE ( errorCode ) ) {
2000-05-04 15:36:17 +00:00
fprintf ( stderr , " gencmn: udata_create(-d %s -n %s -t %s) failed - %s \n " ,
options [ 4 ] . value , options [ 6 ] . value , options [ 7 ] . value ,
u_errorName ( errorCode ) ) ;
2000-05-03 23:08:50 +00:00
exit ( errorCode ) ;
}
1999-11-22 17:56:30 +00:00
2000-05-03 23:08:50 +00:00
/* write the table of contents */
udata_write32 ( out , fileCount ) ;
for ( i = 0 ; i < fileCount ; + + i ) {
udata_write32 ( out , files [ i ] . basenameOffset ) ;
udata_write32 ( out , files [ i ] . fileOffset ) ;
}
1999-11-22 17:56:30 +00:00
2000-05-03 23:08:50 +00:00
/* write the basenames */
for ( i = 0 ; i < fileCount ; + + i ) {
udata_writeString ( out , files [ i ] . basename , files [ i ] . basenameLength ) ;
1999-11-22 17:56:30 +00:00
}
2000-05-03 23:08:50 +00:00
length = 4 + 8 * fileCount + basenameTotal ;
/* copy the files */
for ( i = 0 ; i < fileCount ; + + i ) {
/* pad to 16-align the next file */
length & = 0xf ;
if ( length ! = 0 ) {
udata_writePadding ( out , 16 - length ) ;
}
1999-11-22 17:56:30 +00:00
2002-02-06 21:05:34 +00:00
if ( verbose ) {
2002-02-20 00:07:58 +00:00
printf ( " adding %s (%ld byte%s) \n " , files [ i ] . pathname , ( long ) files [ i ] . fileSize , files [ i ] . fileSize = = 1 ? " " : " s " ) ;
2002-02-06 21:05:34 +00:00
}
2000-05-03 23:08:50 +00:00
/* copy the next file */
file = T_FileStream_open ( files [ i ] . pathname , " rb " ) ;
if ( file = = NULL ) {
fprintf ( stderr , " gencmn: unable to open listed file %s \n " , files [ i ] . pathname ) ;
exit ( U_FILE_ACCESS_ERROR ) ;
}
2002-02-06 21:05:34 +00:00
for ( nread = 0 ; ; ) {
2000-05-03 23:08:50 +00:00
length = T_FileStream_read ( file , buffer , sizeof ( buffer ) ) ;
2002-02-06 21:05:34 +00:00
if ( length < = 0 ) {
2000-05-03 23:08:50 +00:00
break ;
}
2002-02-06 21:05:34 +00:00
nread + = length ;
2000-05-03 23:08:50 +00:00
udata_writeBlock ( out , buffer , length ) ;
}
T_FileStream_close ( file ) ;
length = files [ i ] . fileSize ;
2002-02-06 21:05:34 +00:00
if ( nread ! = files [ i ] . fileSize ) {
2004-04-14 20:08:16 +00:00
fprintf ( stderr , " gencmn: unable to read %s properly (got %ld/%ld byte%s) \n " , files [ i ] . pathname , ( long ) nread , ( long ) files [ i ] . fileSize , files [ i ] . fileSize = = 1 ? " " : " s " ) ;
2002-02-06 21:05:34 +00:00
exit ( U_FILE_ACCESS_ERROR ) ;
}
2000-05-03 23:08:50 +00:00
}
2003-09-23 22:25:13 +00:00
/* pad to 16-align the last file (cleaner, avoids growing .dat files in icuswap) */
length & = 0xf ;
if ( length ! = 0 ) {
udata_writePadding ( out , 16 - length ) ;
}
2000-05-03 23:08:50 +00:00
/* finish */
udata_finish ( out , & errorCode ) ;
if ( U_FAILURE ( errorCode ) ) {
2000-05-04 15:36:17 +00:00
fprintf ( stderr , " gencmn: udata_finish() failed - %s \n " , u_errorName ( errorCode ) ) ;
2000-05-03 23:08:50 +00:00
exit ( errorCode ) ;
}
} else {
/* write a .c source file with the table of contents */
2001-03-26 21:14:50 +00:00
char * filename ;
2000-05-03 23:08:50 +00:00
FileStream * out ;
/* create the output filename */
filename = s = buffer ;
uprv_strcpy ( filename , options [ 4 ] . value ) ;
s = filename + uprv_strlen ( filename ) ;
if ( s > filename & & * ( s - 1 ) ! = U_FILE_SEP_CHAR ) {
* s + + = U_FILE_SEP_CHAR ;
}
uprv_strcpy ( s , options [ 6 ] . value ) ;
if ( * ( options [ 7 ] . value ) ! = 0 ) {
s + = uprv_strlen ( s ) ;
* s + + = ' _ ' ;
uprv_strcpy ( s , options [ 7 ] . value ) ;
}
s + = uprv_strlen ( s ) ;
uprv_strcpy ( s , " .c " ) ;
/* open the output file */
out = T_FileStream_open ( filename , " w " ) ;
if ( out = = NULL ) {
2000-05-04 15:36:17 +00:00
fprintf ( stderr , " gencmn: unable to open .c output file %s \n " , filename ) ;
1999-11-22 17:56:30 +00:00
exit ( U_FILE_ACCESS_ERROR ) ;
}
2000-05-03 23:08:50 +00:00
2002-03-20 01:37:48 +00:00
/* If an entrypoint is specified, use it. */
if ( options [ 9 ] . doesOccur ) {
entrypointName = options [ 9 ] . value ;
} else {
entrypointName = options [ 6 ] . value ;
}
2002-07-17 03:56:50 +00:00
2000-05-03 23:08:50 +00:00
/* write the source file */
sprintf ( buffer ,
" /* \n "
" * ICU common data table of contents for %s.%s , \n "
" * Automatically generated by icu/source/tools/gencmn/gencmn . \n "
" */ \n \n "
" #include \" unicode/utypes.h \" \n "
" #include \" unicode/udata.h \" \n "
" \n "
" /* external symbol declarations for data */ \n " ,
options [ 6 ] . value , options [ 7 ] . value ) ;
T_FileStream_writeLine ( out , buffer ) ;
2002-07-17 03:56:50 +00:00
sprintf ( buffer , " extern const char \n %s%s[] " , symPrefix ? symPrefix : " " , files [ 0 ] . pathname ) ;
2000-05-04 15:36:17 +00:00
T_FileStream_writeLine ( out , buffer ) ;
for ( i = 1 ; i < fileCount ; + + i ) {
2002-07-17 03:56:50 +00:00
sprintf ( buffer , " , \n %s%s[] " , symPrefix ? symPrefix : " " , files [ i ] . pathname ) ;
2000-05-03 23:08:50 +00:00
T_FileStream_writeLine ( out , buffer ) ;
1999-11-22 17:56:30 +00:00
}
2000-05-03 23:08:50 +00:00
T_FileStream_writeLine ( out , " ; \n \n " ) ;
sprintf (
buffer ,
2003-08-08 23:18:34 +00:00
" U_EXPORT struct { \n "
2000-05-03 23:08:50 +00:00
" uint16_t headerSize; \n "
" uint8_t magic1, magic2; \n "
" UDataInfo info; \n "
" char padding[%lu]; \n "
" uint32_t count, reserved; \n "
" struct { \n "
" const char *name; \n "
" const void *data; \n "
" } toc[%lu]; \n "
2000-08-30 23:58:24 +00:00
" } U_EXPORT2 %s_dat = { \n "
2000-05-03 23:08:50 +00:00
" 32, 0xda, 0x27, { \n "
2001-02-02 17:55:32 +00:00
" %lu, 0, \n "
" %u, %u, %u, 0, \n "
" {0x54, 0x6f, 0x43, 0x50}, \n "
" {1, 0, 0, 0}, \n "
" {0, 0, 0, 0} \n "
2000-05-03 23:08:50 +00:00
" }, \n "
" \" \" , %lu, 0, { \n " ,
2001-03-27 21:38:04 +00:00
( unsigned long ) 32 - 4 - sizeof ( UDataInfo ) ,
( unsigned long ) fileCount ,
2000-12-06 03:02:21 +00:00
entrypointName ,
2001-03-27 21:38:04 +00:00
( unsigned long ) sizeof ( UDataInfo ) ,
2000-05-03 23:08:50 +00:00
U_IS_BIG_ENDIAN ,
U_CHARSET_FAMILY ,
U_SIZEOF_UCHAR ,
2001-03-27 21:38:04 +00:00
( unsigned long ) fileCount
2000-05-03 23:08:50 +00:00
) ;
T_FileStream_writeLine ( out , buffer ) ;
2002-07-17 03:56:50 +00:00
sprintf ( buffer , " { \" %s \" , %s%s } " , files [ 0 ] . basename , symPrefix ? symPrefix : " " , files [ 0 ] . pathname ) ;
2000-05-04 15:36:17 +00:00
T_FileStream_writeLine ( out , buffer ) ;
for ( i = 1 ; i < fileCount ; + + i ) {
2002-07-17 03:56:50 +00:00
sprintf ( buffer , " , \n { \" %s \" , %s%s } " , files [ i ] . basename , symPrefix ? symPrefix : " " , files [ i ] . pathname ) ;
2000-05-03 23:08:50 +00:00
T_FileStream_writeLine ( out , buffer ) ;
}
2001-03-21 23:22:16 +00:00
2000-05-04 15:36:17 +00:00
T_FileStream_writeLine ( out , " \n } \n }; \n " ) ;
2000-05-03 23:08:50 +00:00
T_FileStream_close ( out ) ;
2002-03-20 01:37:48 +00:00
uprv_free ( symPrefix ) ;
1999-11-22 17:56:30 +00:00
}
return 0 ;
}
static void
2002-02-06 21:05:34 +00:00
addFile ( const char * filename , UBool sourceTOC , UBool verbose ) {
1999-11-22 17:56:30 +00:00
char * s ;
uint32_t length ;
2004-04-14 20:08:16 +00:00
char * fullPath = NULL ;
1999-11-22 17:56:30 +00:00
if ( fileCount = = MAX_FILE_COUNT ) {
2000-05-04 15:36:17 +00:00
fprintf ( stderr , " gencmn: too many files, maximum is %d \n " , MAX_FILE_COUNT ) ;
1999-11-22 17:56:30 +00:00
exit ( U_BUFFER_OVERFLOW_ERROR ) ;
}
2000-05-03 23:08:50 +00:00
if ( ! sourceTOC ) {
FileStream * file ;
2004-04-14 20:08:16 +00:00
2006-08-14 22:59:10 +00:00
if ( uprv_pathIsAbsolute ( filename ) ) {
fprintf ( stderr , " gencmn: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'. \n \t Bad path: '%s' \n " , U_FILE_SEP_CHAR , filename ) ;
exit ( U_ILLEGAL_ARGUMENT_ERROR ) ;
}
2004-04-14 20:08:16 +00:00
fullPath = pathToFullPath ( filename ) ;
1999-11-22 17:56:30 +00:00
2000-05-03 23:08:50 +00:00
/* store the pathname */
2006-02-24 19:47:47 +00:00
length = ( uint32_t ) ( uprv_strlen ( filename ) + 1 + uprv_strlen ( options [ 6 ] . value ) + 1 ) ;
s = allocString ( length ) ;
uprv_strcpy ( s , options [ 6 ] . value ) ;
uprv_strcat ( s , U_TREE_ENTRY_SEP_STRING ) ;
uprv_strcat ( s , filename ) ;
2000-05-03 23:08:50 +00:00
/* get the basename */
2004-04-23 23:15:15 +00:00
fixDirToTreePath ( s ) ;
2000-05-03 23:08:50 +00:00
files [ fileCount ] . basename = s ;
files [ fileCount ] . basenameLength = length ;
2004-04-14 20:08:16 +00:00
files [ fileCount ] . pathname = fullPath ;
2000-05-03 23:08:50 +00:00
basenameTotal + = length ;
/* try to open the file */
2004-04-14 20:08:16 +00:00
file = T_FileStream_open ( fullPath , " rb " ) ;
2000-05-03 23:08:50 +00:00
if ( file = = NULL ) {
2004-04-14 20:08:16 +00:00
fprintf ( stderr , " gencmn: unable to open listed file %s \n " , fullPath ) ;
2000-05-03 23:08:50 +00:00
exit ( U_FILE_ACCESS_ERROR ) ;
}
/* get the file length */
length = T_FileStream_size ( file ) ;
if ( T_FileStream_error ( file ) | | length < = 20 ) {
2004-04-14 20:08:16 +00:00
fprintf ( stderr , " gencmn: unable to get length of listed file %s \n " , fullPath ) ;
2000-05-03 23:08:50 +00:00
exit ( U_FILE_ACCESS_ERROR ) ;
}
2004-04-14 20:08:16 +00:00
2000-05-03 23:08:50 +00:00
T_FileStream_close ( file ) ;
1999-11-22 17:56:30 +00:00
2000-05-03 23:08:50 +00:00
/* do not add files that are longer than maxSize */
2001-11-13 07:48:46 +00:00
if ( maxSize & & length > maxSize ) {
2002-02-06 21:05:34 +00:00
if ( verbose ) {
2004-04-14 20:08:16 +00:00
printf ( " %s ignored (size %ld > %ld) \n " , fullPath , ( long ) length , ( long ) maxSize ) ;
2002-02-06 21:05:34 +00:00
}
2000-05-03 23:08:50 +00:00
return ;
}
files [ fileCount ] . fileSize = length ;
} else {
char * t ;
/* get and store the basename */
2006-02-24 19:47:47 +00:00
/* need to include the package name */
length = ( uint32_t ) ( uprv_strlen ( filename ) + 1 + uprv_strlen ( options [ 6 ] . value ) + 1 ) ;
s = allocString ( length ) ;
uprv_strcpy ( s , options [ 6 ] . value ) ;
uprv_strcat ( s , U_TREE_ENTRY_SEP_STRING ) ;
uprv_strcat ( s , filename ) ;
2004-04-23 23:15:15 +00:00
fixDirToTreePath ( s ) ;
2000-05-03 23:08:50 +00:00
files [ fileCount ] . basename = s ;
2004-04-14 20:08:16 +00:00
2000-05-03 23:08:50 +00:00
/* turn the basename into an entry point name and store in the pathname field */
t = files [ fileCount ] . pathname = allocString ( length ) ;
while ( - - length > 0 ) {
2004-04-14 20:08:16 +00:00
if ( * s = = ' . ' | | * s = = ' - ' | | * s = = ' / ' ) {
2000-05-03 23:08:50 +00:00
* t = ' _ ' ;
} else {
* t = * s ;
}
+ + s ;
+ + t ;
}
* t = 0 ;
1999-11-22 17:56:30 +00:00
}
+ + fileCount ;
}
static char *
allocString ( uint32_t length ) {
uint32_t top = stringTop + length ;
char * p ;
if ( top > STRING_STORE_SIZE ) {
fprintf ( stderr , " gencmn: out of memory \n " ) ;
exit ( U_MEMORY_ALLOCATION_ERROR ) ;
}
p = stringStore + stringTop ;
stringTop = top ;
return p ;
}
2004-04-14 20:08:16 +00:00
static char *
pathToFullPath ( const char * path ) {
2004-11-04 21:51:57 +00:00
int32_t length ;
int32_t newLength ;
char * fullPath ;
int32_t n ;
length = ( uint32_t ) ( uprv_strlen ( path ) + 1 ) ;
newLength = ( length + 1 + ( int32_t ) uprv_strlen ( options [ 10 ] . value ) ) ;
fullPath = uprv_malloc ( newLength ) ;
if ( options [ 10 ] . doesOccur ) {
uprv_strcpy ( fullPath , options [ 10 ] . value ) ;
uprv_strcat ( fullPath , U_FILE_SEP_STRING ) ;
} else {
fullPath [ 0 ] = 0 ;
}
n = ( int32_t ) uprv_strlen ( fullPath ) ;
uprv_strcat ( fullPath , path ) ;
2004-04-29 17:40:48 +00:00
# if (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
# if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR)
2006-02-24 19:47:47 +00:00
/* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
for ( ; fullPath [ n ] ; n + + ) {
if ( fullPath [ n ] = = U_FILE_ALT_SEP_CHAR ) {
fullPath [ n ] = U_FILE_SEP_CHAR ;
2004-11-04 21:51:57 +00:00
}
2006-02-24 19:47:47 +00:00
}
2004-04-29 17:40:48 +00:00
# endif
# endif
# if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
2006-02-24 19:47:47 +00:00
/* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
for ( ; fullPath [ n ] ; n + + ) {
if ( fullPath [ n ] = = U_TREE_ENTRY_SEP_CHAR ) {
fullPath [ n ] = U_FILE_SEP_CHAR ;
2004-11-04 21:51:57 +00:00
}
}
2006-02-24 19:47:47 +00:00
# endif
2004-11-04 21:51:57 +00:00
return fullPath ;
2004-04-14 20:08:16 +00:00
}
1999-11-22 17:56:30 +00:00
static int
compareFiles ( const void * file1 , const void * file2 ) {
/* sort by basename */
1999-12-28 23:57:50 +00:00
return uprv_strcmp ( ( ( File * ) file1 ) - > basename , ( ( File * ) file2 ) - > basename ) ;
1999-11-22 17:56:30 +00:00
}
2000-02-29 18:34:21 +00:00
2004-04-23 23:15:15 +00:00
static void
fixDirToTreePath ( char * s )
{
2004-05-17 06:33:22 +00:00
# if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR) || ((U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR))
char * t ;
2004-04-23 23:15:15 +00:00
# endif
2004-05-17 06:33:22 +00:00
# if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
for ( t = s ; t = uprv_strchr ( t , U_FILE_SEP_CHAR ) ; ) {
* t = U_TREE_ENTRY_SEP_CHAR ;
}
2004-04-23 23:15:15 +00:00
# endif
2004-05-17 06:33:22 +00:00
# if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
for ( t = s ; t = uprv_strchr ( t , U_FILE_ALT_SEP_CHAR ) ; ) {
* t = U_TREE_ENTRY_SEP_CHAR ;
}
2004-04-23 23:15:15 +00:00
# endif
}
2000-02-29 18:34:21 +00:00
/*
* Hey , Emacs , please set the following :
*
* Local Variables :
* indent - tabs - mode : nil
* End :
*
*/