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