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