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