From a05544211a45dfa1d2036bff2a232a3269c6491b Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Thu, 18 Nov 1999 22:48:30 +0000 Subject: [PATCH] ICU-87 improve u_[get|set]DataDirectory() - find better & always end with '/' X-SVN-Rev: 183 --- icu4c/source/common/putil.c | 505 +++++++++++++++++++++++++++++------- 1 file changed, 409 insertions(+), 96 deletions(-) diff --git a/icu4c/source/common/putil.c b/icu4c/source/common/putil.c index a05e359f703..09e69f3a445 100644 --- a/icu4c/source/common/putil.c +++ b/icu4c/source/common/putil.c @@ -38,6 +38,30 @@ ******************************************************************************* */ +/* include system headers */ +#ifdef WIN32 +# include +# include +# include "locmap.h" +#elif defined(OS2) +# define INCL_DOSMISC +# define INCL_DOSERRORS +# include +#elif defined(OS400) +# include +#elif defined(XP_MAC) +# include +# include +# include +#elif defined(AIX) +# include +#elif defined(SOLARIS) || defined(LINUX) +# include +#elif defined(HPUX) +# include +#endif + +/* include standard headers */ #include #include #include @@ -45,28 +69,14 @@ #include #include +/* include ICU headers */ #include "utypes.h" - #include "umutex.h" #include "cmemory.h" #include "cstring.h" +#include "filestrm.h" -#ifdef OS400 -#include -#endif - -#ifdef XP_MAC -#include "Files.h" -#include "IntlResources.h" -#include "Script.h" -#endif - - -#ifdef WIN32 -#include "locmap.h" -#include -#include -#endif +/* floating point implementations ------------------------------------------- */ /* We return QNAN rather than SNAN*/ #ifdef IEEE_754 @@ -644,89 +654,392 @@ icu_tzname(int index) #endif } -const char* -icu_getDefaultDataDirectory() -{ -#ifdef POSIX - static char *PATH = 0; -#ifndef OS390 - if(PATH == 0) { - umtx_lock(NULL); - if(PATH == 0) { -#endif - /* Normally, the locale and converter data will be installed in - the same tree as the ICU libraries - typically /usr/local/lib - for the libraries, /usr/local/include for the headers, and - /usr/local/share for the binary data. However, the directory - where the ICU looks for the binary data can be overridden by - setting the environment variable ICU_DATA */ - char *dir = getenv("ICU_DATA"); +/* Get and set the ICU data directory --------------------------------------- */ - /* If the environment variable is set, use it */ - if(dir != 0) { - PATH = dir; - } - /* Otherwise, use the compiled in default */ - else { - PATH = ICU_DATA_DIR; - } +static bool_t +gHaveDataDirectory=FALSE; + +static char +gDataDirectory[1024]; + +/* + * 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. + */ +U_CAPI void U_EXPORT2 +u_setDataDirectory(const char *directory) { + if(directory!=NULL) { + int length=icu_strlen(directory); + + if(length0) { + /* convert the Pascal string to a C string */ + icu_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; +} + +/* + * 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=icu_strrchr(path, U_FILE_SEP_CHAR); + if(lastSep!=NULL) { + *lastSep=0; + return lastSep-path; + } + } + } +# elif defined(OS2) +# elif defined(OS390) +# elif defined(OS400) +# elif defined(XP_MAC) +# elif defined(SOLARIS) + void *handle=dlopen("libicuuc.so", RTLD_LAZY); + 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=icu_strstr(p->l_name, "libicuuc.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(0l_name, length); + path[length]=0; + } else { + length=0; + } + } + break; + } + p=p->l_next; + } + } + dlclose(handle); + return length; + } +# elif defined(LINUX) +# elif defined(AIX) + void *handle=load("libicuuc.a", L_LIBPATH_EXEC, "."); + 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=icu_strstr(p->ldinfo_filename, "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(0ldinfo_filename, length); + path[length]=0; + } else { + length=0; + } + } + break; + } + p=p->l_next; + } + } + unload(handle); + return length; + } +# elif defined(HPUX) + 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=icu_strstr(p->filename, "libicuuc.sl"); + 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(0l_name, length); + path[length]=0; + } else { + length=0; + } + } + break; + } + ++i; + } + return length; +# elif defined(TANDEM) +# elif defined(POSIX) +# endif + return 0; +} + +/* + * 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) { +# ifdef WIN32 +# define LIB_PATH_VAR "PATH" +# define LIB_FILENAME "icuuc.dll" +# 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(OS400) +# elif defined(XP_MAC) +# elif defined(SOLARIS) +# elif defined(LINUX) +# define LIB_PATH_VAR "LD_LIBRARY_PATH" +# define LIB_FILENAME "libicuuc.so" +# elif defined(AIX) +# elif defined(HPUX) +# elif defined(TANDEM) +# define LIB_PATH_VAR "LIBPATH" +# define LIB_FILENAME "libicuuc.a" +# elif defined(POSIX) +# define LIB_PATH_VAR "LIBPATH" +# define LIB_FILENAME "libicuuc.so" +# endif + + /* 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 */ + icu_memcpy(path, libPath, length); + icu_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; +} + +U_CAPI const char * U_EXPORT2 +u_getDataDirectory(void) { + /* if we have the directory, then return it immediately */ + if(!gHaveDataDirectory) { + /* we need to look for it */ + char pathBuffer[1024]; + char *path; + int length; + +# if !defined(OS400) && !defined(XP_MAC) + /* first try to get the environment variable */ + path=getenv("ICU_DATA"); +# 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\\IBM\\Unicode\\Data", 0, KEY_QUERY_VALUE, &key)) { + DWORD type=REG_EXPAND_SZ, size=sizeof(pathBuffer); + + if(ERROR_SUCCESS==RegQueryValueEx(key, "Path", NULL, &type, 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 */ + icu_memcpy(temporaryPath, pathBuffer, size); + + /* do the replacement and store it in the pathBuffer */ + size=ExpandEnvironmentStrings(temporaryPath, pathBuffer, sizeof(pathBuffer)); + if(size>0 && size0) { + icu_strcpy(pathBuffer+length, U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING "data" U_FILE_SEP_STRING); + path=pathBuffer; + } + } + + /* next, search for the ICU dynamic library */ + if(path==NULL || *path==0) { + length=findLibraryPath(pathBuffer, sizeof(pathBuffer)); + if(length>0) { + icu_strcpy(pathBuffer+length, U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING "data" U_FILE_SEP_STRING); + 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) { + icu_strcpy(pathBuffer+length, U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING "data" U_FILE_SEP_STRING); + path=pathBuffer; + } else { + path=U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; + } +# endif + } + + u_setDataDirectory(path); + } + + /* we did set the directory if necessary */ + return gDataDirectory; +} + +/* Macintosh-specific locale information ------------------------------------ */ #ifdef XP_MAC struct mac_lc_rec {