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(basename==NULL) { 166 /* Use lenient matching on Windows, which can accept either \ or / 167 This is useful for environments like Win32+CygWin which have both. 168 */ 169 basename=uprv_strrchr(filename, U_FILE_ALT_SEP_CHAR); 170 } 171 #endif 172 173 if(basename!=NULL) { 174 return basename+1; 175 } else { 176 return filename; 177 } 178 } 179 180 U_CAPI void U_EXPORT2 181 uprv_mkdir(const char *pathname, UErrorCode *status) { 182 183 int retVal = 0; 184 #if U_PLATFORM_USES_ONLY_WIN32_API 185 retVal = _mkdir(pathname); 186 #else 187 retVal = mkdir(pathname, S_IRWXU | (S_IROTH | S_IXOTH) | (S_IROTH | S_IXOTH)); 188 #endif 189 if (retVal && errno != EEXIST) { 190 #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN 191 /*if using Cygwin and the mkdir says it failed...check if the directory already exists..*/ 192 /* if it does...don't give the error, if it does not...give the error - Brian Rower - 6/25/08 */ 193 struct stat st; 194 195 if(stat(pathname,&st) != 0) 196 { 197 *status = U_FILE_ACCESS_ERROR; 198 } 199 #else 200 *status = U_FILE_ACCESS_ERROR; 201 #endif 202 } 203 } 204 205 #if !UCONFIG_NO_FILE_IO 206 U_CAPI UBool U_EXPORT2 207 uprv_fileExists(const char *file) { 208 struct stat stat_buf; 209 if (stat(file, &stat_buf) == 0) { 210 return TRUE; 211 } else { 212 return FALSE; 213 } 214 } 215 #endif 216 217 /*U_CAPI UDate U_EXPORT2 218 uprv_getModificationDate(const char *pathname, UErrorCode *status) 219 { 220 if(U_FAILURE(*status)) { 221 return; 222 } 223 // TODO: handle case where stat is not available 224 struct stat st; 225 226 if(stat(pathname,&st) != 0) 227 { 228 *status = U_FILE_ACCESS_ERROR; 229 } else { 230 return st.st_mtime; 231 } 232 } 233 */ 234 235 /* tool memory helper ------------------------------------------------------- */ 236 237 struct UToolMemory { 238 char name[64]; 239 int32_t capacity, maxCapacity, size, idx; 240 void *array; 241 UAlignedMemory staticArray[1]; 242 }; 243 244 U_CAPI UToolMemory * U_EXPORT2 245 utm_open(const char *name, int32_t initialCapacity, int32_t maxCapacity, int32_t size) { 246 UToolMemory *mem; 247 248 if(maxCapacity<initialCapacity) { 249 maxCapacity=initialCapacity; 250 } 251 252 mem=(UToolMemory *)uprv_malloc(sizeof(UToolMemory)+initialCapacity*size); 253 if(mem==NULL) { 254 fprintf(stderr, "error: %s - out of memory\n", name); 255 exit(U_MEMORY_ALLOCATION_ERROR); 256 } 257 mem->array=mem->staticArray; 258 259 uprv_strcpy(mem->name, name); 260 mem->capacity=initialCapacity; 261 mem->maxCapacity=maxCapacity; 262 mem->size=size; 263 mem->idx=0; 264 return mem; 265 } 266 267 U_CAPI void U_EXPORT2 268 utm_close(UToolMemory *mem) { 269 if(mem!=NULL) { 270 if(mem->array!=mem->staticArray) { 271 uprv_free(mem->array); 272 } 273 uprv_free(mem); 274 } 275 } 276 277 278 U_CAPI void * U_EXPORT2 279 utm_getStart(UToolMemory *mem) { 280 return (char *)mem->array; 281 } 282 283 U_CAPI int32_t U_EXPORT2 284 utm_countItems(UToolMemory *mem) { 285 return mem->idx; 286 } 287 288 289 static UBool 290 utm_hasCapacity(UToolMemory *mem, int32_t capacity) { 291 if(mem->capacity<capacity) { 292 int32_t newCapacity; 293 294 if(mem->maxCapacity<capacity) { 295 fprintf(stderr, "error: %s - trying to use more than maxCapacity=%ld units\n", 296 mem->name, (long)mem->maxCapacity); 297 exit(U_MEMORY_ALLOCATION_ERROR); 298 } 299 300 /* try to allocate a larger array */ 301 if(capacity>=2*mem->capacity) { 302 newCapacity=capacity; 303 } else if(mem->capacity<=mem->maxCapacity/3) { 304 newCapacity=2*mem->capacity; 305 } else { 306 newCapacity=mem->maxCapacity; 307 } 308 309 if(mem->array==mem->staticArray) { 310 mem->array=uprv_malloc(newCapacity*mem->size); 311 if(mem->array!=NULL) { 312 uprv_memcpy(mem->array, mem->staticArray, mem->idx*mem->size); 313 } 314 } else { 315 mem->array=uprv_realloc(mem->array, newCapacity*mem->size); 316 } 317 318 if(mem->array==NULL) { 319 fprintf(stderr, "error: %s - out of memory\n", mem->name); 320 exit(U_MEMORY_ALLOCATION_ERROR); 321 } 322 mem->capacity=newCapacity; 323 } 324 325 return TRUE; 326 } 327 328 U_CAPI void * U_EXPORT2 329 utm_alloc(UToolMemory *mem) { 330 char *p=NULL; 331 int32_t oldIndex=mem->idx; 332 int32_t newIndex=oldIndex+1; 333 if(utm_hasCapacity(mem, newIndex)) { 334 p=(char *)mem->array+oldIndex*mem->size; 335 mem->idx=newIndex; 336 uprv_memset(p, 0, mem->size); 337 } 338 return p; 339 } 340 341 U_CAPI void * U_EXPORT2 342 utm_allocN(UToolMemory *mem, int32_t n) { 343 char *p=NULL; 344 int32_t oldIndex=mem->idx; 345 int32_t newIndex=oldIndex+n; 346 if(utm_hasCapacity(mem, newIndex)) { 347 p=(char *)mem->array+oldIndex*mem->size; 348 mem->idx=newIndex; 349 uprv_memset(p, 0, n*mem->size); 350 } 351 return p; 352 } 353