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