ICU-1075 Yet more data loading changes

X-SVN-Rev: 5523
This commit is contained in:
Andy Heninger 2001-08-17 21:34:07 +00:00
parent a84135e73e
commit fc61c83aa2
2 changed files with 231 additions and 708 deletions

View File

@ -863,475 +863,33 @@ uprv_tzname(int n)
static UBool
gHaveDataDirectory=FALSE;
static char
gDataDirectory[1024];
static const char *gDataDirectory = "";
/*
* Here, we use a mutex to make sure that setting the data directory
* is thread-safe; however, reading it after calling u_getDataDirectory()
* may still occur while it is (re)set and is therefore not thread-safe.
* The best is to not call it after the initialization.
* Set the data directory.
* Make a copy of the passed string, and set the global data dir to point to it.
* Deliberately leak any previously set string, on the chance that some code
* may have called getDataDirectory() and still be using the old string.
*/
U_CAPI void U_EXPORT2
u_setDataDirectory(const char *directory) {
if(directory!=NULL) {
char *newDataDir;
if(directory!=NULL && *directory != 0) {
int length=uprv_strlen(directory);
if(length<sizeof(gDataDirectory)-1) {
umtx_lock(NULL);
if(length==0) {
*gDataDirectory=0;
} else {
uprv_memcpy(gDataDirectory, directory, length);
/* terminate the directory with a separator (/ or \) */
if(gDataDirectory[length-1]!=U_FILE_SEP_CHAR) {
gDataDirectory[length++]=U_FILE_SEP_CHAR;
}
/* zero-terminate it */
gDataDirectory[length]=0;
}
gHaveDataDirectory=TRUE;
umtx_unlock(NULL);
newDataDir = (char *)uprv_malloc(length + 2);
uprv_strcpy(newDataDir, directory);
if(newDataDir[length-1]!=U_FILE_SEP_CHAR) {
newDataDir[length++]=U_FILE_SEP_CHAR;
newDataDir[length] = 0;
}
gDataDirectory = newDataDir;
gHaveDataDirectory=TRUE;
}
}
#ifndef ICU_DATA_DIR
# if defined(XP_MAC)
/* Kouichi added the following internal functions for MAC porting */
pascal OSErr FSMakeFSSpecCompat(short vRefNum,
long dirID,
ConstStr255Param fileName,
FSSpec *spec)
{
OSErr result;
/* Let the file system create the FSSpec if it can since it does the job */
/* much more efficiently than I can. */
result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
/* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
/* returned in the parID field when making an FSSpec to the volume's */
/* root directory by passing a full pathname in MakeFSSpec's */
/* fileName parameter. Fixed in Mac OS 8.1 */
if ( (result == noErr) && (spec->parID == 0) )
spec->parID = fsRtParID;
return ( result );
}
/* FSpGetFullPath */
pascal OSErr FSpGetFullPath(const FSSpec *spec,
short *fullPathLength,
Handle *fullPath)
{
OSErr result;
OSErr realResult;
FSSpec tempSpec;
CInfoPBRec pb;
*fullPathLength = 0;
*fullPath = NULL;
/* Default to noErr */
realResult = result = noErr;
/* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */
if ( spec->name[0] == 0 )
{
result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);
}
else
{
/* Make a copy of the input FSSpec that can be modified */
BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
}
if ( result == noErr )
{
if ( tempSpec.parID == fsRtParID )
{
/* The object is a volume */
/* Add a colon to make it a full pathname */
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
/* We're done */
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
}
else
{
/* The object isn't a volume */
/* Is the object a file or a directory? */
pb.dirInfo.ioNamePtr = tempSpec.name;
pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
pb.dirInfo.ioDrDirID = tempSpec.parID;
pb.dirInfo.ioFDirIndex = 0;
result = PBGetCatInfoSync(&pb);
/* Allow file/directory name at end of path to not exist. */
realResult = result;
if ( (result == noErr) || (result == fnfErr) )
{
/* if the object is a directory, append a colon so full pathname ends with colon */
if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
{
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
}
/* Put the object name in first */
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
if ( result == noErr )
{
/* Get the ancestor directory names */
pb.dirInfo.ioNamePtr = tempSpec.name;
pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
pb.dirInfo.ioDrParID = tempSpec.parID;
do /* loop until we have an error or find the root directory */
{
pb.dirInfo.ioFDirIndex = -1;
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
result = PBGetCatInfoSync(&pb);
if ( result == noErr )
{
/* Append colon to directory name */
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
/* Add directory name to beginning of fullPath */
(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
result = MemError();
}
} while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
}
}
}
}
if ( result == noErr )
{
/* Return the length */
*fullPathLength = GetHandleSize(*fullPath);
result = realResult; /* return realResult in case it was fnfErr */
}
else
{
/* Dispose of the handle and return NULL and zero length */
if ( *fullPath != NULL )
{
DisposeHandle(*fullPath);
}
}
return result;
}
# endif /* XP_MAC */
/*
* get the system drive or volume path
* (Windows: e.g. "C:" or "D:")
* do not terminate with a U_FILE_SEP_CHAR separator
* return the length of the path, or 0 if none
*/
static int
getSystemPath(char *path, int size) {
#if defined(XP_MAC)
int32_t dirID;
OSErr err;
int16_t volNum;
path[0]=0;
err=HGetVol((unsigned char*)path, &volNum, &dirID);
if(err==noErr) {
int length=(uint8_t)path[0];
if(length>0) {
/* convert the Pascal string to a C string */
uprv_memmove(path, path+1, length);
path[length]=0;
}
return length;
}
#elif defined(WIN32)
if(GetSystemDirectory(path, size)>=2 && path[1]==':') {
/* remove the rest of the path - "\\winnt\\system32" or similar */
path[2]=0;
return 2;
}
#elif defined(OS2)
APIRET rc;
ULONG bootDrive=0; /* 1=A, 2=B, 3=C, ... */
rc=DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&bootDrive, sizeof(ULONG));
if(rc==NO_ERROR) {
/* convert the numeric boot drive to a string */
path[0]='A'+bootDrive-1;
path[1]=':';
path[2]=0;
return 2;
}
#endif
return 0;
}
#endif /* ICU_DATA_DIR not defined */
/*
* get the path to the ICU dynamic library
* do not terminate with a U_FILE_SEP_CHAR separator
* return the length of the path, or 0 if none
*/
static int
getLibraryPath(char *path, int size) {
#ifdef WIN32
HINSTANCE mod=GetModuleHandle("icuuc.dll");
if(mod!=NULL) {
if(GetModuleFileName(mod, path, size)>0) {
/* remove the basename and the last file separator */
char *lastSep=uprv_strrchr(path, U_FILE_SEP_CHAR);
if(lastSep!=NULL) {
*lastSep=0;
return lastSep-path;
}
}
}
#elif defined(OS2)
HMODULE mod=NULLHANDLE;
APIRET rc=DosQueryModuleHandle("icuuc.dll", &mod);
if(rc==NO_ERROR) {
rc=DosQueryModuleName(mod, (LONG)size, path);
if(rc==NO_ERROR) {
/* remove the basename and the last file separator */
char *lastSep=uprv_strrchr(path, U_FILE_SEP_CHAR);
if(lastSep!=NULL) {
*lastSep=0;
return lastSep-path;
}
}
}
#elif defined(U_SOLARIS)
void *handle=dlopen(U_COMMON_LIBNAME, RTLD_LAZY); /* "libicu-uc.so" */
if(handle!=NULL) {
Link_map *p=NULL;
char *s;
int rc, length=0;
/* get the Link_map list */
rc=dlinfo(handle, RTLD_DI_LINKMAP, (void *)&p);
if(rc>=0) {
/* search for the list item for the library itself */
while(p!=NULL) {
s=uprv_strstr(p->l_name, U_COMMON_LIBNAME); /* "libicu-uc.so" */
if(s!=NULL) {
if(s>p->l_name) {
/* copy the path, without the basename and the last separator */
length=(s-p->l_name)-1;
if(0<length && length<size) {
uprv_memcpy(path, p->l_name, length);
path[length]=0;
} else {
length=0;
}
}
break;
}
p=p->l_next;
}
}
dlclose(handle);
return length;
}
#elif defined(AIX)
void *handle=(void*)load(U_COMMON_LIBNAME, L_LIBPATH_EXEC, "."); /* "libicu-uc.a" */
if(handle!=NULL) {
uint8_t buffer[4096];
struct ld_info *p=NULL;
char *s;
int rc, length=0;
/* copy the linked list of loaded libraries into the buffer */
rc=loadquery(L_GETINFO, buffer, sizeof(buffer));
if(rc>=0) {
/* search for the list item for the library itself */
p=(struct ld_info *)buffer;
for(;;) {
/* advance (ignore the first list item) */
if(p->ldinfo_next==0) {
break;
}
p=(struct ld_info *)((uint8_t *)p+p->ldinfo_next);
s=uprv_strstr(p->ldinfo_filename, U_COMMON_LIBNAME); /* "libicuuc.a" */
if(s!=NULL) {
if(s>p->ldinfo_filename) {
/* copy the path, without the basename and the last separator */
length=(s-p->ldinfo_filename)-1;
if(0<length && length<size) {
uprv_memcpy(path, p->ldinfo_filename, length);
path[length]=0;
} else {
length=0;
}
}
break;
}
/* p=p->l_next; */
}
}
unload(handle);
return length;
}
#elif defined(HPUX)
{
struct shl_descriptor *p=NULL;
char *s;
int i=1, rc, length=0;
/* walk the list of shared libraries */
/* search for the list item for the library itself */
for(;;) {
rc=shl_get(i, &p);
if(rc<0) {
break;
}
s=uprv_strstr(p->filename, U_COMMON_LIBNAME);
if(s!=NULL) {
if(s>p->filename) {
/* copy the path, without the basename and the last separator */
length=(s-p->filename)-1;
if(0<length && length<size) {
uprv_memcpy(path, p->filename, length);
path[length]=0;
} else {
length=0;
}
}
break;
}
++i;
}
return length;
}
#elif defined(OS390)
#elif defined(OS400)
#elif defined(XP_MAC)
#elif defined(U_LINUX)
#elif defined(TANDEM)
#elif defined(U_POSIX)
#endif
return 0;
}
#ifdef WIN32
# define LIB_PATH_VAR "PATH"
# define LIB_FILENAME "icuuc.dll"
#elif defined(U_LINUX)
# define LIB_PATH_VAR "LD_LIBRARY_PATH"
# define LIB_FILENAME U_COMMON_LIBNAME
#elif defined(OS2)
# define LIB_PATH_VAR "LIBPATH"
# define LIB_FILENAME "icuuc.dll"
#elif defined(OS390)
# define LIB_PATH_VAR "LIBPATH"
# define LIB_FILENAME "libicuuc.a"
#elif defined(TANDEM)
# define LIB_PATH_VAR "LIBPATH"
# define LIB_FILENAME "libicuuc.a"
#elif defined(OS400)
#elif defined(XP_MAC)
#elif defined(U_SOLARIS)
#elif defined(AIX)
#elif defined(HPUX)
#elif defined(U_POSIX)
# define LIB_PATH_VAR "LIBPATH"
# define LIB_FILENAME U_COMMON_LIBNAME
#endif
/*
* search for the ICU dynamic library and set the path
* do not terminate with a U_FILE_SEP_CHAR separator
* return the length of the path, or 0 if none
*/
static int
findLibraryPath(char *path, int size) {
/* common implementation for searching the library path */
#ifdef LIB_FILENAME
const char *libPath=getenv(LIB_PATH_VAR);
if(libPath!=NULL) {
/* loop over all paths */
FileStream *f;
const char *end;
int length;
for(;;) {
/* find the end of the path */
end=libPath;
while(*end!=0 && *end!=U_PATH_SEP_CHAR) {
++end;
}
if(end!=libPath) {
/* try this non-empty path */
length=end-libPath;
/* do not terminate the path */
if(*(end-1)==U_FILE_SEP_CHAR) {
--length;
}
/* copy the path and add the library filename */
uprv_memcpy(path, libPath, length);
uprv_strcpy(path+length, U_FILE_SEP_STRING LIB_FILENAME);
/* does this file exist in this path? */
f=T_FileStream_open(path, "rb");
if(f!=NULL) {
/* yes, clean up and return */
T_FileStream_close(f);
path[length]=0;
return length;
}
}
if(*end==0) {
break; /* no more path */
}
/* *end==U_PATH_SEP_CHAR, go to the next path */
libPath=end+1;
}
}
#endif
return 0;
}
/* define a path for fallbacks */
#ifdef WIN32
# define FALLBACK_PATH U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data"
#elif defined(XP_MAC)
# define FALLBACK_PATH U_FILE_SEP_STRING "ICU" U_FILE_SEP_STRING U_ICU_VERSION U_FILE_SEP_STRING
#else
# define FALLBACK_PATH U_FILE_SEP_STRING "lib" U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING U_ICU_VERSION U_FILE_SEP_STRING
#endif
/* #include <stdio.h> */
/* #include <unistd.h> */
@ -1344,171 +902,109 @@ findLibraryPath(char *path, int size) {
U_CAPI const char * U_EXPORT2
u_getDataDirectory(void) {
const char *path = NULL;
char pathBuffer[1024];
/* if we have the directory, then return it immediately */
if(!gHaveDataDirectory) {
/* we need to look for it */
char pathBuffer[1024];
const char *path = NULL;
int length;
# if !defined(XP_MAC)
/* first try to get the environment variable */
path=getenv("ICU_DATA");
# else /* XP_MAC */
{
OSErr myErr;
short vRef;
long dir,newDir;
int16_t volNum;
Str255 xpath;
FSSpec spec;
short len;
Handle full;
xpath[0]=0;
myErr = HGetVol(xpath, &volNum, &dir);
if(myErr == noErr) {
myErr = FindFolder(volNum, kApplicationSupportFolderType, TRUE, &vRef, &dir);
newDir=-1;
if (myErr == noErr) {
myErr = DirCreate(volNum,
dir,
"\pICU",
&newDir);
if( (myErr == noErr) || (myErr == dupFNErr) ) {
spec.vRefNum = volNum;
spec.parID = dir;
uprv_memcpy(spec.name, "\pICU", 4);
myErr = FSpGetFullPath(&spec, &len, &full);
if(full != NULL)
{
HLock(full);
uprv_memcpy(pathBuffer, ((char*)(*full)), len);
pathBuffer[len] = 0;
path = pathBuffer;
DisposeHandle(full);
}
}
}
}
}
# endif
# ifdef WIN32
/* next, try to read the path from the registry */
if(path==NULL || *path==0) {
HKEY key;
if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ICU\\Unicode\\Data", 0, KEY_QUERY_VALUE, &key)) {
DWORD type=REG_EXPAND_SZ, size=sizeof(pathBuffer);
if(ERROR_SUCCESS==RegQueryValueEx(key, "Path", NULL, &type, (unsigned char *)pathBuffer, &size) && size>1) {
if(type==REG_EXPAND_SZ) {
/* replace environment variable references by their values */
char temporaryPath[1024];
/* copy the path with variables to the temporary one */
uprv_memcpy(temporaryPath, pathBuffer, size);
/* do the replacement and store it in the pathBuffer */
size=ExpandEnvironmentStrings(temporaryPath, pathBuffer, sizeof(pathBuffer));
if(size>0 && size<sizeof(pathBuffer)) {
path=pathBuffer;
}
} else if(type==REG_SZ) {
path=pathBuffer;
}
}
RegCloseKey(key);
}
}
# endif
/* before being fancy, check if we can find the right kind of
data in the hardcoded path */
if(path==NULL || *path==0) {
char fileBuffer[1024]; /* XXX sloppy, should be FILE_MAX. */
FileStream *f;
/* ICU_DATA_DIR may be set as a compile option */
# ifdef ICU_DATA_DIR
path=ICU_DATA_DIR;
# else
length=getSystemPath(pathBuffer, sizeof(pathBuffer));
if(length>0) {
uprv_strcpy(pathBuffer+length, FALLBACK_PATH);
path=pathBuffer;
} else {
path=FALLBACK_PATH;
}
# endif
length = uprv_strlen(path);
uprv_memcpy(fileBuffer, path, length);
/* produce the path of a file that should be here given the way
that ICU was compiled; if it's here in the hardcoded location,
we should just use the hardcoded path without further
guessing */
# if defined(UDATA_DLL)
uprv_strcpy(fileBuffer + length, U_FILE_SEP_STRING LIB_PREFIX U_ICUDATA_NAME UDATA_SO_SUFFIX);
# elif defined(UDATA_MAP)
uprv_strcpy(fileBuffer + length, U_FILE_SEP_STRING U_ICUDATA_NAME "." DATA_TYPE); /* XXX Sloppy, won't be good enough on OS390 probably. */
# elif defined(UDATA_FILES)
uprv_strcpy(fileBuffer + length, U_FILE_SEP_STRING "uprops.dat");
# endif
f = T_FileStream_open(fileBuffer, "rb"); /* XXX Sloppy, use stat(). */
if (f) {
T_FileStream_close(f); /* found it, keep path */
} else {
path = NULL; /* not found, reset path */
}
}
/* next, try to get the path to the ICU dynamic library */
if(path==NULL || *path==0) {
length=getLibraryPath(pathBuffer, sizeof(pathBuffer));
if(length>0) {
uprv_strcpy(pathBuffer+length, U_FILE_SEP_STRING ".." FALLBACK_PATH);
path=pathBuffer;
}
}
/* next, search for the ICU dynamic library */
if(path==NULL || *path==0) {
length=findLibraryPath(pathBuffer, sizeof(pathBuffer));
if(length>0) {
uprv_strcpy(pathBuffer+length, U_FILE_SEP_STRING ".." FALLBACK_PATH);
path=pathBuffer;
}
}
/* last resort: use hardcoded path */
if(path==NULL || *path==0) {
/* ICU_DATA_DIR may be set as a compile option */
# ifdef ICU_DATA_DIR
path=ICU_DATA_DIR;
# else
length=getSystemPath(pathBuffer, sizeof(pathBuffer));
if(length>0) {
uprv_strcpy(pathBuffer+length, FALLBACK_PATH);
path=pathBuffer;
} else {
path=FALLBACK_PATH;
}
# endif
}
u_setDataDirectory(path);
if(gHaveDataDirectory) {
return gDataDirectory;
}
/* we did set the directory if necessary */
/* we need to look for it */
pathBuffer[0] = 0; /* Shuts up compiler warnings about unreferenced */
/* variables when the code using it is ifdefed out */
# if !defined(XP_MAC)
/* first try to get the environment variable */
path=getenv("ICU_DATA");
# else /* XP_MAC */
{
OSErr myErr;
short vRef;
long dir,newDir;
int16_t volNum;
Str255 xpath;
FSSpec spec;
short len;
Handle full;
xpath[0]=0;
myErr = HGetVol(xpath, &volNum, &dir);
if(myErr == noErr) {
myErr = FindFolder(volNum, kApplicationSupportFolderType, TRUE, &vRef, &dir);
newDir=-1;
if (myErr == noErr) {
myErr = DirCreate(volNum,
dir,
"\pICU",
&newDir);
if( (myErr == noErr) || (myErr == dupFNErr) ) {
spec.vRefNum = volNum;
spec.parID = dir;
uprv_memcpy(spec.name, "\pICU", 4);
myErr = FSpGetFullPath(&spec, &len, &full);
if(full != NULL)
{
HLock(full);
uprv_memcpy(pathBuffer, ((char*)(*full)), len);
pathBuffer[len] = 0;
path = pathBuffer;
DisposeHandle(full);
}
}
}
}
}
# endif
# if defined WIN32 && defined ICU_ENABLE_DEPRECATED_WIN_REGISTRY
/* next, try to read the path from the registry */
if(path==NULL || *path==0) {
HKEY key;
if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ICU\\Unicode\\Data", 0, KEY_QUERY_VALUE, &key)) {
DWORD type=REG_EXPAND_SZ, size=sizeof(pathBuffer);
if(ERROR_SUCCESS==RegQueryValueEx(key, "Path", NULL, &type, (unsigned char *)pathBuffer, &size) && size>1) {
if(type==REG_EXPAND_SZ) {
/* replace environment variable references by their values */
char temporaryPath[1024];
/* copy the path with variables to the temporary one */
uprv_memcpy(temporaryPath, pathBuffer, size);
/* do the replacement and store it in the pathBuffer */
size=ExpandEnvironmentStrings(temporaryPath, pathBuffer, sizeof(pathBuffer));
if(size>0 && size<sizeof(pathBuffer)) {
path=pathBuffer;
}
} else if(type==REG_SZ) {
path=pathBuffer;
}
}
RegCloseKey(key);
}
}
# endif
/* ICU_DATA_DIR may be set as a compile option */
# ifdef ICU_DATA_DIR
if(path==NULL || *path==0) {
path=ICU_DATA_DIR;
}
# endif
u_setDataDirectory(path);
return gDataDirectory;
}
/* Macintosh-specific locale information ------------------------------------ */
#ifdef XP_MAC

View File

@ -141,13 +141,40 @@ U_CAPI char* U_EXPORT2 uprv_tzname(int n);
U_CAPI int32_t U_EXPORT2 uprv_getUTCtime(void);
/**
* Return the data directory for this platform.
* Return the ICU data directory.
* The data directory is where common format ICU data files (.dat files)
* are loaded from. Note that normal use of the built-in ICU
* facilities does not require loading of an external data file;
* unless you are adding custom data to ICU, the data directory
* does not need to be set.
*
* The data directory is determined as follows:
* If u_setDataDirectory() has been called, that is it, otherwise
* if the ICU_DATA environment variable is set, use that, otherwise
* On Windows, if the SOFTWARE\ICU\Unicode\Data registry entry exists, use that
* (use of the registry in this way is not recommended.) otherwise
* If a data directory was specifed at ICU build time, use that
* otherwise no data directory is available.
*
*@return the data directory, or an empty string ("") if no data directory has
* been specified.
*
* @draft
*/
U_CAPI const char* U_EXPORT2 u_getDataDirectory(void);
/**
* Set the data directory.
* Set the ICU data directory.
* The data directory is where common format ICU data files (.dat files)
* are loaded from. Note that normal use of the built-in ICU
* facilities does not require loading of an external data file;
* unless you are adding custom data to ICU, the data directory
* does not need to be set.
*
* This function should be called at most once in a process, before the
* first ICU operation that will require the loading of an ICU data file.
*
* @draft
*/
U_CAPI void U_EXPORT2 u_setDataDirectory(const char *directory);