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 68U_NAMESPACE_BEGIN 69 70IcuToolErrorCode::~IcuToolErrorCode() { 71 // Safe because our handleFailure() does not throw exceptions. 72 if(isFailure()) { handleFailure(); } 73} 74 75void IcuToolErrorCode::handleFailure() const { 76 fprintf(stderr, "error at %s: %s\n", location, errorName()); 77 exit(errorCode); 78} 79 80U_NAMESPACE_END 81 82static int32_t currentYear = -1; 83 84U_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 102U_CAPI const char * U_EXPORT2 103getLongPathname(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 125U_CAPI const char * U_EXPORT2 126findDirname(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 160U_CAPI const char * U_EXPORT2 161findBasename(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 183U_CAPI void U_EXPORT2 184uprv_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 209U_CAPI UBool U_EXPORT2 210uprv_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 221uprv_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 240struct UToolMemory { 241 char name[64]; 242 int32_t capacity, maxCapacity, size, idx; 243 void *array; 244 UAlignedMemory staticArray[1]; 245}; 246 247U_CAPI UToolMemory * U_EXPORT2 248utm_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 270U_CAPI void U_EXPORT2 271utm_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 281U_CAPI void * U_EXPORT2 282utm_getStart(UToolMemory *mem) { 283 return (char *)mem->array; 284} 285 286U_CAPI int32_t U_EXPORT2 287utm_countItems(UToolMemory *mem) { 288 return mem->idx; 289} 290 291 292static UBool 293utm_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 331U_CAPI void * U_EXPORT2 332utm_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 344U_CAPI void * U_EXPORT2 345utm_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