|
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 } |