michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 1999-2013, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: toolutil.c michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:4 michael@0: * michael@0: * created on: 1999nov19 michael@0: * created by: Markus W. Scherer michael@0: * michael@0: * 6/25/08 - Added Cygwin specific code in uprv_mkdir - Brian Rower michael@0: * michael@0: * This file contains utility functions for ICU tools like genccode. michael@0: */ michael@0: michael@0: #if U_PLATFORM == U_PF_MINGW michael@0: // *cough* - for struct stat michael@0: #ifdef __STRICT_ANSI__ michael@0: #undef __STRICT_ANSI__ michael@0: #endif michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: #include "unicode/utypes.h" michael@0: michael@0: #ifndef U_TOOLUTIL_IMPLEMENTATION michael@0: #error U_TOOLUTIL_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see http://userguide.icu-project.org/howtouseicu michael@0: #endif michael@0: michael@0: #if U_PLATFORM_USES_ONLY_WIN32_API michael@0: # define VC_EXTRALEAN michael@0: # define WIN32_LEAN_AND_MEAN michael@0: # define NOUSER michael@0: # define NOSERVICE michael@0: # define NOIME michael@0: # define NOMCX michael@0: # if U_PLATFORM == U_PF_MINGW michael@0: # define __NO_MINGW_LFS /* gets around missing 'off64_t' */ michael@0: # endif michael@0: # include michael@0: # include michael@0: #else michael@0: # include michael@0: # include michael@0: #endif michael@0: michael@0: /* In MinGW environment, io.h needs to be included for _mkdir() */ michael@0: #if U_PLATFORM == U_PF_MINGW michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: michael@0: #include "unicode/errorcode.h" michael@0: #include "unicode/putil.h" michael@0: #include "cmemory.h" michael@0: #include "cstring.h" michael@0: #include "toolutil.h" michael@0: #include "unicode/ucal.h" michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: IcuToolErrorCode::~IcuToolErrorCode() { michael@0: // Safe because our handleFailure() does not throw exceptions. michael@0: if(isFailure()) { handleFailure(); } michael@0: } michael@0: michael@0: void IcuToolErrorCode::handleFailure() const { michael@0: fprintf(stderr, "error at %s: %s\n", location, errorName()); michael@0: exit(errorCode); michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: static int32_t currentYear = -1; michael@0: michael@0: U_CAPI int32_t U_EXPORT2 getCurrentYear() { michael@0: #if !UCONFIG_NO_FORMATTING michael@0: UErrorCode status=U_ZERO_ERROR; michael@0: UCalendar *cal = NULL; michael@0: michael@0: if(currentYear == -1) { michael@0: cal = ucal_open(NULL, -1, NULL, UCAL_TRADITIONAL, &status); michael@0: ucal_setMillis(cal, ucal_getNow(), &status); michael@0: currentYear = ucal_get(cal, UCAL_YEAR, &status); michael@0: ucal_close(cal); michael@0: } michael@0: #else michael@0: /* No formatting- no way to set the current year. */ michael@0: #endif michael@0: return currentYear; michael@0: } michael@0: michael@0: michael@0: U_CAPI const char * U_EXPORT2 michael@0: getLongPathname(const char *pathname) { michael@0: #if U_PLATFORM_USES_ONLY_WIN32_API michael@0: /* anticipate problems with "short" pathnames */ michael@0: static WIN32_FIND_DATAA info; michael@0: HANDLE file=FindFirstFileA(pathname, &info); michael@0: if(file!=INVALID_HANDLE_VALUE) { michael@0: if(info.cAlternateFileName[0]!=0) { michael@0: /* this file has a short name, get and use the long one */ michael@0: const char *basename=findBasename(pathname); michael@0: if(basename!=pathname) { michael@0: /* prepend the long filename with the original path */ michael@0: uprv_memmove(info.cFileName+(basename-pathname), info.cFileName, uprv_strlen(info.cFileName)+1); michael@0: uprv_memcpy(info.cFileName, pathname, basename-pathname); michael@0: } michael@0: pathname=info.cFileName; michael@0: } michael@0: FindClose(file); michael@0: } michael@0: #endif michael@0: return pathname; michael@0: } michael@0: michael@0: U_CAPI const char * U_EXPORT2 michael@0: findDirname(const char *path, char *buffer, int32_t bufLen, UErrorCode* status) { michael@0: if(U_FAILURE(*status)) return NULL; michael@0: const char *resultPtr = NULL; michael@0: int32_t resultLen = 0; michael@0: michael@0: const char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR); michael@0: #if U_FILE_ALT_SEP_CHAR!=U_FILE_SEP_CHAR michael@0: const char *basenameAlt=uprv_strrchr(path, U_FILE_ALT_SEP_CHAR); michael@0: if(basenameAlt && (!basename || basename '/' */ michael@0: } michael@0: } michael@0: michael@0: if((resultLen+1) <= bufLen) { michael@0: uprv_strncpy(buffer, resultPtr, resultLen); michael@0: buffer[resultLen]=0; michael@0: return buffer; michael@0: } else { michael@0: *status = U_BUFFER_OVERFLOW_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: U_CAPI const char * U_EXPORT2 michael@0: findBasename(const char *filename) { michael@0: const char *basename=uprv_strrchr(filename, U_FILE_SEP_CHAR); michael@0: michael@0: #if U_FILE_ALT_SEP_CHAR!=U_FILE_SEP_CHAR michael@0: if(basename==NULL) { michael@0: /* Use lenient matching on Windows, which can accept either \ or / michael@0: This is useful for environments like Win32+CygWin which have both. michael@0: */ michael@0: basename=uprv_strrchr(filename, U_FILE_ALT_SEP_CHAR); michael@0: } michael@0: #endif michael@0: michael@0: if(basename!=NULL) { michael@0: return basename+1; michael@0: } else { michael@0: return filename; michael@0: } michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: uprv_mkdir(const char *pathname, UErrorCode *status) { michael@0: michael@0: int retVal = 0; michael@0: #if U_PLATFORM_USES_ONLY_WIN32_API michael@0: retVal = _mkdir(pathname); michael@0: #else michael@0: retVal = mkdir(pathname, S_IRWXU | (S_IROTH | S_IXOTH) | (S_IROTH | S_IXOTH)); michael@0: #endif michael@0: if (retVal && errno != EEXIST) { michael@0: #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN michael@0: /*if using Cygwin and the mkdir says it failed...check if the directory already exists..*/ michael@0: /* if it does...don't give the error, if it does not...give the error - Brian Rower - 6/25/08 */ michael@0: struct stat st; michael@0: michael@0: if(stat(pathname,&st) != 0) michael@0: { michael@0: *status = U_FILE_ACCESS_ERROR; michael@0: } michael@0: #else michael@0: *status = U_FILE_ACCESS_ERROR; michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: #if !UCONFIG_NO_FILE_IO michael@0: U_CAPI UBool U_EXPORT2 michael@0: uprv_fileExists(const char *file) { michael@0: struct stat stat_buf; michael@0: if (stat(file, &stat_buf) == 0) { michael@0: return TRUE; michael@0: } else { michael@0: return FALSE; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: /*U_CAPI UDate U_EXPORT2 michael@0: uprv_getModificationDate(const char *pathname, UErrorCode *status) michael@0: { michael@0: if(U_FAILURE(*status)) { michael@0: return; michael@0: } michael@0: // TODO: handle case where stat is not available michael@0: struct stat st; michael@0: michael@0: if(stat(pathname,&st) != 0) michael@0: { michael@0: *status = U_FILE_ACCESS_ERROR; michael@0: } else { michael@0: return st.st_mtime; michael@0: } michael@0: } michael@0: */ michael@0: michael@0: /* tool memory helper ------------------------------------------------------- */ michael@0: michael@0: struct UToolMemory { michael@0: char name[64]; michael@0: int32_t capacity, maxCapacity, size, idx; michael@0: void *array; michael@0: UAlignedMemory staticArray[1]; michael@0: }; michael@0: michael@0: U_CAPI UToolMemory * U_EXPORT2 michael@0: utm_open(const char *name, int32_t initialCapacity, int32_t maxCapacity, int32_t size) { michael@0: UToolMemory *mem; michael@0: michael@0: if(maxCapacityarray=mem->staticArray; michael@0: michael@0: uprv_strcpy(mem->name, name); michael@0: mem->capacity=initialCapacity; michael@0: mem->maxCapacity=maxCapacity; michael@0: mem->size=size; michael@0: mem->idx=0; michael@0: return mem; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utm_close(UToolMemory *mem) { michael@0: if(mem!=NULL) { michael@0: if(mem->array!=mem->staticArray) { michael@0: uprv_free(mem->array); michael@0: } michael@0: uprv_free(mem); michael@0: } michael@0: } michael@0: michael@0: michael@0: U_CAPI void * U_EXPORT2 michael@0: utm_getStart(UToolMemory *mem) { michael@0: return (char *)mem->array; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: utm_countItems(UToolMemory *mem) { michael@0: return mem->idx; michael@0: } michael@0: michael@0: michael@0: static UBool michael@0: utm_hasCapacity(UToolMemory *mem, int32_t capacity) { michael@0: if(mem->capacitymaxCapacityname, (long)mem->maxCapacity); michael@0: exit(U_MEMORY_ALLOCATION_ERROR); michael@0: } michael@0: michael@0: /* try to allocate a larger array */ michael@0: if(capacity>=2*mem->capacity) { michael@0: newCapacity=capacity; michael@0: } else if(mem->capacity<=mem->maxCapacity/3) { michael@0: newCapacity=2*mem->capacity; michael@0: } else { michael@0: newCapacity=mem->maxCapacity; michael@0: } michael@0: michael@0: if(mem->array==mem->staticArray) { michael@0: mem->array=uprv_malloc(newCapacity*mem->size); michael@0: if(mem->array!=NULL) { michael@0: uprv_memcpy(mem->array, mem->staticArray, mem->idx*mem->size); michael@0: } michael@0: } else { michael@0: mem->array=uprv_realloc(mem->array, newCapacity*mem->size); michael@0: } michael@0: michael@0: if(mem->array==NULL) { michael@0: fprintf(stderr, "error: %s - out of memory\n", mem->name); michael@0: exit(U_MEMORY_ALLOCATION_ERROR); michael@0: } michael@0: mem->capacity=newCapacity; michael@0: } michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: U_CAPI void * U_EXPORT2 michael@0: utm_alloc(UToolMemory *mem) { michael@0: char *p=NULL; michael@0: int32_t oldIndex=mem->idx; michael@0: int32_t newIndex=oldIndex+1; michael@0: if(utm_hasCapacity(mem, newIndex)) { michael@0: p=(char *)mem->array+oldIndex*mem->size; michael@0: mem->idx=newIndex; michael@0: uprv_memset(p, 0, mem->size); michael@0: } michael@0: return p; michael@0: } michael@0: michael@0: U_CAPI void * U_EXPORT2 michael@0: utm_allocN(UToolMemory *mem, int32_t n) { michael@0: char *p=NULL; michael@0: int32_t oldIndex=mem->idx; michael@0: int32_t newIndex=oldIndex+n; michael@0: if(utm_hasCapacity(mem, newIndex)) { michael@0: p=(char *)mem->array+oldIndex*mem->size; michael@0: mem->idx=newIndex; michael@0: uprv_memset(p, 0, n*mem->size); michael@0: } michael@0: return p; michael@0: }