1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1999-2011, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * file name: toolutil.c 9 * encoding: US-ASCII 10 * tab size: 8 (not used) 11 * indentation:4 12 * 13 * created on: 1999nov19 14 * created by: Markus W. Scherer 15 * 16 * 6/25/08 - Added Cygwin specific code in uprv_mkdir - Brian Rower 17 * 18 * This file contains utility functions for ICU tools like genccode. 19 */ 20 21 #include <stdio.h> 22 #include <sys/stat.h> 23 #include "unicode/utypes.h" 24 25 #ifndef U_TOOLUTIL_IMPLEMENTATION 26 #error U_TOOLUTIL_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see http://userguide.icu-project.org/howtouseicu 27 #endif 28 29 #if U_PLATFORM_USES_ONLY_WIN32_API 30 # define VC_EXTRALEAN 31 # define WIN32_LEAN_AND_MEAN 32 # define NOUSER 33 # define NOSERVICE 34 # define NOIME 35 # define NOMCX 36 # include <windows.h> 37 # include <direct.h> 38 #else 39 # include <sys/stat.h> 40 # include <sys/types.h> 41 #endif 42 43 /* In MinGW environment, io.h needs to be included for _mkdir() */ 44 #if U_PLATFORM == U_PF_MINGW 45 #include <io.h> 46 #endif 47 48 #include <errno.h> 49 50 #include "unicode/errorcode.h" 51 #include "unicode/putil.h" 52 #include "cmemory.h" 53 #include "cstring.h" 54 #include "toolutil.h" 55 #include "unicode/ucal.h" 56 57 U_NAMESPACE_BEGIN 58 59 IcuToolErrorCode::~IcuToolErrorCode() { 60 // Safe because our handleFailure() does not throw exceptions. 61 if(isFailure()) { handleFailure(); } 62 } 63 64 void IcuToolErrorCode::handleFailure() const { 65 fprintf(stderr, "error at %s: %s\n", location, errorName()); 66 exit(errorCode); 67 } 68 69 U_NAMESPACE_END 70 71 static int32_t currentYear = -1; 72 73 U_CAPI int32_t U_EXPORT2 getCurrentYear() { 74 #if !UCONFIG_NO_FORMATTING 75 UErrorCode status=U_ZERO_ERROR; 76 UCalendar *cal = NULL; 77 78 if(currentYear == -1) { 79 cal = ucal_open(NULL, -1, NULL, UCAL_TRADITIONAL, &status); 80 ucal_setMillis(cal, ucal_getNow(), &status); 81 currentYear = ucal_get(cal, UCAL_YEAR, &status); 82 ucal_close(cal); 83 } 84 #else 85 /* No formatting- no way to set the current year. */ 86 #endif 87 return currentYear; 88 } 89 90 91 U_CAPI const char * U_EXPORT2 92 getLongPathname(const char *pathname) { 93 #if U_PLATFORM_USES_ONLY_WIN32_API 94 /* anticipate problems with "short" pathnames */ 95 static WIN32_FIND_DATAA info; 96 HANDLE file=FindFirstFileA(pathname, &info); 97 if(file!=INVALID_HANDLE_VALUE) { 98 if(info.cAlternateFileName[0]!=0) { 99 /* this file has a short name, get and use the long one */ 100 const char *basename=findBasename(pathname); 101 if(basename!=pathname) { 102 /* prepend the long filename with the original path */ 103 uprv_memmove(info.cFileName+(basename-pathname), info.cFileName, uprv_strlen(info.cFileName)+1); 104 uprv_memcpy(info.cFileName, pathname, basename-pathname); 105 } 106 pathname=info.cFileName; 107 } 108 FindClose(file); 109 } 110 #endif 111 return pathname; 112 } 113 114 U_CAPI const char * U_EXPORT2 115 findDirname(const char *path, char *buffer, int32_t bufLen, UErrorCode* status) { 116 if(U_FAILURE(*status)) return NULL; 117 const char *resultPtr = NULL; 118 int32_t resultLen = 0; 119 120 const char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR); 121 #if U_FILE_ALT_SEP_CHAR!=U_FILE_SEP_CHAR 122 const char *basenameAlt=uprv_strrchr(path, U_FILE_ALT_SEP_CHAR); 123 if(basenameAlt && (!basename || basename<basenameAlt)) { 124 basename = basenameAlt; 125 } 126 #endif 127 if(!basename) { 128 /* no basename - return ''. */ 129 resultPtr = ""; 130 resultLen = 0; 131 } else { 132 resultPtr = path; 133 resultLen = basename - path; 134 if(resultLen<1) { 135 resultLen = 1; /* '/' or '/a' -> '/' */ 136 } 137 } 138 139 if((resultLen+1) <= bufLen) { 140 uprv_strncpy(buffer, resultPtr, resultLen); 141 buffer[resultLen]=0; 142 return buffer; 143 } else { 144 *status = U_BUFFER_OVERFLOW_ERROR; 145 return NULL; 146 } 147 } 148 149 U_CAPI const char * U_EXPORT2 150 findBasename(const char *filename) { 151 const char *basename=uprv_strrchr(filename, U_FILE_SEP_CHAR); 152 153 #if U_FILE_ALT_SEP_CHAR!=U_FILE_SEP_CHAR 154 if(basename==NULL) { 155 /* Use lenient matching on Windows, which can accept either \ or / 156 This is useful for environments like Win32+CygWin which have both. 157 */ 158 basename=uprv_strrchr(filename, U_FILE_ALT_SEP_CHAR); 159 } 160 #endif 161 162 if(basename!=NULL) { 163 return basename+1; 164 } else { 165 return filename; 166 } 167 } 168 169 U_CAPI void U_EXPORT2 170 uprv_mkdir(const char *pathname, UErrorCode *status) { 171 172 int retVal = 0; 173 #if U_PLATFORM_USES_ONLY_WIN32_API 174 retVal = _mkdir(pathname); 175 #else 176 retVal = mkdir(pathname, S_IRWXU | (S_IROTH | S_IXOTH) | (S_IROTH | S_IXOTH)); 177 #endif 178 if (retVal && errno != EEXIST) { 179 #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN 180 /*if using Cygwin and the mkdir says it failed...check if the directory already exists..*/ 181 /* if it does...don't give the error, if it does not...give the error - Brian Rower - 6/25/08 */ 182 struct stat st; 183 184 if(stat(pathname,&st) != 0) 185 { 186 *status = U_FILE_ACCESS_ERROR; 187 } 188 #else 189 *status = U_FILE_ACCESS_ERROR; 190 #endif 191 } 192 } 193 194 /*U_CAPI UDate U_EXPORT2 195 uprv_getModificationDate(const char *pathname, UErrorCode *status) 196 { 197 if(U_FAILURE(*status)) { 198 return; 199 } 200 // TODO: handle case where stat is not available 201 struct stat st; 202 203 if(stat(pathname,&st) != 0) 204 { 205 *status = U_FILE_ACCESS_ERROR; 206 } else { 207 return st.st_mtime; 208 } 209 } 210 */ 211 212 /* tool memory helper ------------------------------------------------------- */ 213 214 struct UToolMemory { 215 char name[64]; 216 int32_t capacity, maxCapacity, size, idx; 217 void *array; 218 UAlignedMemory staticArray[1]; 219 }; 220 221 U_CAPI UToolMemory * U_EXPORT2 222 utm_open(const char *name, int32_t initialCapacity, int32_t maxCapacity, int32_t size) { 223 UToolMemory *mem; 224 225 if(maxCapacity<initialCapacity) { 226 maxCapacity=initialCapacity; 227 } 228 229 mem=(UToolMemory *)uprv_malloc(sizeof(UToolMemory)+initialCapacity*size); 230 if(mem==NULL) { 231 fprintf(stderr, "error: %s - out of memory\n", name); 232 exit(U_MEMORY_ALLOCATION_ERROR); 233 } 234 mem->array=mem->staticArray; 235 236 uprv_strcpy(mem->name, name); 237 mem->capacity=initialCapacity; 238 mem->maxCapacity=maxCapacity; 239 mem->size=size; 240 mem->idx=0; 241 return mem; 242 } 243 244 U_CAPI void U_EXPORT2 245 utm_close(UToolMemory *mem) { 246 if(mem!=NULL) { 247 if(mem->array!=mem->staticArray) { 248 uprv_free(mem->array); 249 } 250 uprv_free(mem); 251 } 252 } 253 254 255 U_CAPI void * U_EXPORT2 256 utm_getStart(UToolMemory *mem) { 257 return (char *)mem->array; 258 } 259 260 U_CAPI int32_t U_EXPORT2 261 utm_countItems(UToolMemory *mem) { 262 return mem->idx; 263 } 264 265 266 static UBool 267 utm_hasCapacity(UToolMemory *mem, int32_t capacity) { 268 if(mem->capacity<capacity) { 269 int32_t newCapacity; 270 271 if(mem->maxCapacity<capacity) { 272 fprintf(stderr, "error: %s - trying to use more than maxCapacity=%ld units\n", 273 mem->name, (long)mem->maxCapacity); 274 exit(U_MEMORY_ALLOCATION_ERROR); 275 } 276 277 /* try to allocate a larger array */ 278 if(capacity>=2*mem->capacity) { 279 newCapacity=capacity; 280 } else if(mem->capacity<=mem->maxCapacity/3) { 281 newCapacity=2*mem->capacity; 282 } else { 283 newCapacity=mem->maxCapacity; 284 } 285 286 if(mem->array==mem->staticArray) { 287 mem->array=uprv_malloc(newCapacity*mem->size); 288 if(mem->array!=NULL) { 289 uprv_memcpy(mem->array, mem->staticArray, mem->idx*mem->size); 290 } 291 } else { 292 mem->array=uprv_realloc(mem->array, newCapacity*mem->size); 293 } 294 295 if(mem->array==NULL) { 296 fprintf(stderr, "error: %s - out of memory\n", mem->name); 297 exit(U_MEMORY_ALLOCATION_ERROR); 298 } 299 mem->capacity=newCapacity; 300 } 301 302 return TRUE; 303 } 304 305 U_CAPI void * U_EXPORT2 306 utm_alloc(UToolMemory *mem) { 307 char *p=NULL; 308 int32_t oldIndex=mem->idx; 309 int32_t newIndex=oldIndex+1; 310 if(utm_hasCapacity(mem, newIndex)) { 311 p=(char *)mem->array+oldIndex*mem->size; 312 mem->idx=newIndex; 313 uprv_memset(p, 0, mem->size); 314 } 315 return p; 316 } 317 318 U_CAPI void * U_EXPORT2 319 utm_allocN(UToolMemory *mem, int32_t n) { 320 char *p=NULL; 321 int32_t oldIndex=mem->idx; 322 int32_t newIndex=oldIndex+n; 323 if(utm_hasCapacity(mem, newIndex)) { 324 p=(char *)mem->array+oldIndex*mem->size; 325 mem->idx=newIndex; 326 uprv_memset(p, 0, n*mem->size); 327 } 328 return p; 329 } 330