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