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