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(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 180U_CAPI void U_EXPORT2 181uprv_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 206U_CAPI UBool U_EXPORT2 207uprv_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 218uprv_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 237struct UToolMemory { 238 char name[64]; 239 int32_t capacity, maxCapacity, size, idx; 240 void *array; 241 UAlignedMemory staticArray[1]; 242}; 243 244U_CAPI UToolMemory * U_EXPORT2 245utm_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 267U_CAPI void U_EXPORT2 268utm_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 278U_CAPI void * U_EXPORT2 279utm_getStart(UToolMemory *mem) { 280 return (char *)mem->array; 281} 282 283U_CAPI int32_t U_EXPORT2 284utm_countItems(UToolMemory *mem) { 285 return mem->idx; 286} 287 288 289static UBool 290utm_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 328U_CAPI void * U_EXPORT2 329utm_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 341U_CAPI void * U_EXPORT2 342utm_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