]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ****************************************************************************** | |
3 | * | |
4 | * Copyright (C) 1998-2003, International Business Machines | |
5 | * Corporation and others. All Rights Reserved. | |
6 | * | |
7 | ****************************************************************************** | |
8 | * | |
9 | * File ustdio.c | |
10 | * | |
11 | * Modification History: | |
12 | * | |
13 | * Date Name Description | |
14 | * 11/18/98 stephen Creation. | |
15 | * 03/12/99 stephen Modified for new C API. | |
16 | * 07/19/99 stephen Fixed read() and gets() | |
17 | ****************************************************************************** | |
18 | */ | |
19 | ||
20 | #include "unicode/ustdio.h" | |
21 | #include "unicode/putil.h" | |
22 | #include "cmemory.h" | |
23 | #include "ufile.h" | |
24 | #include "ufmt_cmn.h" | |
25 | #include "unicode/ucnv.h" | |
26 | #include "unicode/ustring.h" | |
27 | ||
28 | #include <string.h> | |
29 | ||
30 | #define DELIM_CR 0x000D | |
31 | #define DELIM_LF 0x000A | |
32 | ||
33 | /* Leave this copyright notice here! */ | |
34 | static const char copyright[] = U_COPYRIGHT_STRING; | |
35 | ||
36 | #ifdef WIN32 | |
37 | static const UChar DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 }; | |
38 | static const uint32_t DELIMITERS_LEN = 2; | |
39 | #else | |
40 | static const UChar DELIMITERS [] = { DELIM_LF, 0x0000 }; | |
41 | static const uint32_t DELIMITERS_LEN = 1; | |
42 | #endif | |
43 | ||
44 | #define IS_STRING_DELIMITER(s) (UBool)( (s) == DELIM_CR || \ | |
45 | (s) == DELIM_LF ) | |
46 | ||
47 | #if !UCONFIG_NO_TRANSLITERATION | |
48 | ||
49 | U_CAPI UTransliterator* U_EXPORT2 | |
50 | u_fsettransliterator(UFILE *file, UFileDirection direction, | |
51 | UTransliterator *adopt, UErrorCode *status) | |
52 | { | |
53 | UTransliterator *old = NULL; | |
54 | ||
55 | if(file==NULL || U_FAILURE(*status)) | |
56 | { | |
57 | return adopt; | |
58 | } | |
59 | ||
60 | if(!file) | |
61 | { | |
62 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
63 | return adopt; | |
64 | } | |
65 | ||
66 | if(direction & U_READ) | |
67 | { | |
68 | /** TODO: implement */ | |
69 | *status = U_UNSUPPORTED_ERROR; | |
70 | return adopt; | |
71 | } | |
72 | ||
73 | if(adopt == NULL) /* they are clearing it */ | |
74 | { | |
75 | if(file->fTranslit != NULL) | |
76 | { | |
77 | /* TODO: Check side */ | |
78 | old = file->fTranslit->translit; | |
79 | uprv_free(file->fTranslit->buffer); | |
80 | file->fTranslit->buffer=NULL; | |
81 | uprv_free(file->fTranslit); | |
82 | file->fTranslit=NULL; | |
83 | } | |
84 | } | |
85 | else | |
86 | { | |
87 | if(file->fTranslit == NULL) | |
88 | { | |
89 | file->fTranslit = (UFILETranslitBuffer*) uprv_malloc(sizeof(UFILETranslitBuffer)); | |
90 | if(!file->fTranslit) | |
91 | { | |
92 | *status = U_MEMORY_ALLOCATION_ERROR; | |
93 | return adopt; | |
94 | } | |
95 | file->fTranslit->capacity = 0; | |
96 | file->fTranslit->length = 0; | |
97 | file->fTranslit->pos = 0; | |
98 | file->fTranslit->buffer = NULL; | |
99 | } | |
100 | else | |
101 | { | |
102 | old = file->fTranslit->translit; | |
103 | ufile_flush_translit(file); | |
104 | } | |
105 | ||
106 | file->fTranslit->translit = adopt; | |
107 | } | |
108 | ||
109 | return old; | |
110 | } | |
111 | ||
112 | static const UChar * u_file_translit(UFILE *f, const UChar *src, int32_t *count, UBool flush) | |
113 | { | |
114 | int32_t newlen; | |
115 | int32_t junkCount = 0; | |
116 | int32_t textLength; | |
117 | int32_t textLimit; | |
118 | UTransPosition pos; | |
119 | UErrorCode status = U_ZERO_ERROR; | |
120 | ||
121 | if(count == NULL) | |
122 | { | |
123 | count = &junkCount; | |
124 | } | |
125 | ||
126 | if ((!f)||(!f->fTranslit)||(!f->fTranslit->translit)) | |
127 | { | |
128 | /* fast path */ | |
129 | return src; | |
130 | } | |
131 | ||
132 | /* First: slide over everything */ | |
133 | if(f->fTranslit->length > f->fTranslit->pos) | |
134 | { | |
135 | memmove(f->fTranslit->buffer, f->fTranslit->buffer + f->fTranslit->pos, | |
136 | (f->fTranslit->length - f->fTranslit->pos)*sizeof(UChar)); | |
137 | } | |
138 | f->fTranslit->length -= f->fTranslit->pos; /* always */ | |
139 | f->fTranslit->pos = 0; | |
140 | ||
141 | /* Calculate new buffer size needed */ | |
142 | newlen = (*count + f->fTranslit->length) * 4; | |
143 | ||
144 | if(newlen > f->fTranslit->capacity) | |
145 | { | |
146 | if(f->fTranslit->buffer == NULL) | |
147 | { | |
148 | f->fTranslit->buffer = (UChar*)uprv_malloc(newlen * sizeof(UChar)); | |
149 | } | |
150 | else | |
151 | { | |
152 | f->fTranslit->buffer = (UChar*)uprv_realloc(f->fTranslit->buffer, newlen * sizeof(UChar)); | |
153 | } | |
154 | f->fTranslit->capacity = newlen; | |
155 | } | |
156 | ||
157 | /* Now, copy any data over */ | |
158 | u_strncpy(f->fTranslit->buffer + f->fTranslit->length, | |
159 | src, | |
160 | *count); | |
161 | f->fTranslit->length += *count; | |
162 | ||
163 | /* Now, translit in place as much as we can */ | |
164 | if(flush == FALSE) | |
165 | { | |
166 | textLength = f->fTranslit->length; | |
167 | pos.contextStart = 0; | |
168 | pos.contextLimit = textLength; | |
169 | pos.start = 0; | |
170 | pos.limit = textLength; | |
171 | ||
172 | utrans_transIncrementalUChars(f->fTranslit->translit, | |
173 | f->fTranslit->buffer, /* because we shifted */ | |
174 | &textLength, | |
175 | f->fTranslit->capacity, | |
176 | &pos, | |
177 | &status); | |
178 | ||
179 | #ifdef _DEBUG | |
180 | if(U_FAILURE(status)) | |
181 | { | |
182 | fprintf(stderr, " Gack. Translit blew up with a %s\n", u_errorName(status)); | |
183 | return src; | |
184 | } | |
185 | #endif | |
186 | ||
187 | /* now: start/limit point to the transliterated text */ | |
188 | /* Transliterated is [buffer..pos.start) */ | |
189 | *count = pos.start; | |
190 | f->fTranslit->pos = pos.start; | |
191 | f->fTranslit->length = pos.limit; | |
192 | ||
193 | return f->fTranslit->buffer; | |
194 | } | |
195 | else | |
196 | { | |
197 | textLength = f->fTranslit->length; | |
198 | textLimit = f->fTranslit->length; | |
199 | ||
200 | utrans_transUChars(f->fTranslit->translit, | |
201 | f->fTranslit->buffer, | |
202 | &textLength, | |
203 | f->fTranslit->capacity, | |
204 | 0, | |
205 | &textLimit, | |
206 | &status); | |
207 | ||
208 | #ifdef _DEBUG | |
209 | if(U_FAILURE(status)) | |
210 | { | |
211 | fprintf(stderr, " Gack. Translit(flush) blew up with a %s\n", u_errorName(status)); | |
212 | return src; | |
213 | } | |
214 | #endif | |
215 | ||
216 | /* out: converted len */ | |
217 | *count = textLimit; | |
218 | ||
219 | /* Set pointers to 0 */ | |
220 | f->fTranslit->pos = 0; | |
221 | f->fTranslit->length = 0; | |
222 | ||
223 | return f->fTranslit->buffer; | |
224 | } | |
225 | } | |
226 | ||
227 | #endif | |
228 | ||
229 | void | |
230 | ufile_flush_translit(UFILE *f) | |
231 | { | |
232 | #if !UCONFIG_NO_TRANSLITERATION | |
233 | if((!f)||(!f->fTranslit)) | |
234 | return; | |
235 | #endif | |
236 | ||
237 | u_file_write_flush(NULL, 0, f, TRUE); | |
238 | } | |
239 | ||
240 | ||
241 | void | |
242 | ufile_close_translit(UFILE *f) | |
243 | { | |
244 | #if !UCONFIG_NO_TRANSLITERATION | |
245 | if((!f)||(!f->fTranslit)) | |
246 | return; | |
247 | #endif | |
248 | ||
249 | ufile_flush_translit(f); | |
250 | ||
251 | #if !UCONFIG_NO_TRANSLITERATION | |
252 | if(f->fTranslit->translit) | |
253 | utrans_close(f->fTranslit->translit); | |
254 | ||
255 | if(f->fTranslit->buffer) | |
256 | { | |
257 | uprv_free(f->fTranslit->buffer); | |
258 | } | |
259 | ||
260 | uprv_free(f->fTranslit); | |
261 | f->fTranslit = NULL; | |
262 | #endif | |
263 | } | |
264 | ||
265 | ||
266 | /* Input/output */ | |
267 | ||
268 | U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
269 | u_fputs(const UChar *s, | |
270 | UFILE *f) | |
271 | { | |
272 | int32_t count = u_file_write(s, u_strlen(s), f); | |
273 | count += u_file_write(DELIMITERS, DELIMITERS_LEN, f); | |
274 | return count; | |
275 | } | |
276 | ||
277 | U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
278 | u_fputc(UChar uc, | |
279 | UFILE *f) | |
280 | { | |
281 | return u_file_write(&uc, 1, f) == 1 ? uc : EOF; | |
282 | } | |
283 | ||
284 | ||
285 | U_CAPI int32_t U_EXPORT2 | |
286 | u_file_write_flush( const UChar *chars, | |
287 | int32_t count, | |
288 | UFILE *f, | |
289 | UBool flush) | |
290 | { | |
291 | /* Set up conversion parameters */ | |
292 | UErrorCode status = U_ZERO_ERROR; | |
293 | const UChar *mySource = chars; | |
294 | const UChar *sourceAlias = chars; | |
295 | const UChar *mySourceEnd = chars + count; | |
296 | char *myTarget = f->fCharBuffer; | |
297 | int32_t bufferSize = UFILE_CHARBUFFER_SIZE; | |
298 | int32_t written = 0; | |
299 | int32_t numConverted = 0; | |
300 | ||
301 | #if !UCONFIG_NO_TRANSLITERATION | |
302 | if((f->fTranslit) && (f->fTranslit->translit)) | |
303 | { | |
304 | /* Do the transliteration */ | |
305 | mySource = u_file_translit(f, chars, &count, flush); | |
306 | sourceAlias = mySource; | |
307 | mySourceEnd = mySource + count; | |
308 | } | |
309 | #endif | |
310 | ||
311 | /* Perform the conversion in a loop */ | |
312 | do { | |
313 | status = U_ZERO_ERROR; | |
314 | sourceAlias = mySource; | |
315 | if(f->fConverter != NULL) { /* We have a valid converter */ | |
316 | ucnv_fromUnicode(f->fConverter, | |
317 | &myTarget, | |
318 | f->fCharBuffer + bufferSize, | |
319 | &mySource, | |
320 | mySourceEnd, | |
321 | NULL, | |
322 | flush, | |
323 | &status); | |
324 | } else { /*weiv: do the invariant conversion */ | |
325 | u_UCharsToChars(mySource, myTarget, count); | |
326 | myTarget += count; | |
327 | } | |
328 | numConverted = (int32_t)(myTarget - f->fCharBuffer); | |
329 | ||
330 | if (numConverted > 0) { | |
331 | /* write the converted bytes */ | |
332 | fwrite(f->fCharBuffer, | |
333 | sizeof(char), | |
334 | numConverted, | |
335 | f->fFile); | |
336 | ||
337 | written += numConverted; | |
338 | } | |
339 | myTarget = f->fCharBuffer; | |
340 | } | |
341 | while(status == U_BUFFER_OVERFLOW_ERROR); | |
342 | ||
343 | /* return # of chars written */ | |
344 | return written; | |
345 | } | |
346 | ||
347 | U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
348 | u_file_write( const UChar *chars, | |
349 | int32_t count, | |
350 | UFILE *f) | |
351 | { | |
352 | return u_file_write_flush(chars,count,f,FALSE); | |
353 | } | |
354 | ||
355 | ||
356 | /* private function used for buffering input */ | |
357 | void | |
358 | ufile_fill_uchar_buffer(UFILE *f) | |
359 | { | |
360 | UErrorCode status; | |
361 | const char *mySource; | |
362 | const char *mySourceEnd; | |
363 | UChar *myTarget; | |
364 | int32_t bufferSize; | |
365 | int32_t maxCPBytes; | |
366 | int32_t bytesRead; | |
367 | int32_t availLength; | |
368 | int32_t dataSize; | |
369 | ||
370 | ||
371 | /* shift the buffer if it isn't empty */ | |
372 | dataSize = (int32_t)(f->fUCLimit - f->fUCPos); | |
373 | if(dataSize != 0) { | |
374 | memmove(f->fUCBuffer, | |
375 | f->fUCPos, | |
376 | dataSize * sizeof(UChar)); | |
377 | } | |
378 | ||
379 | ||
380 | /* record how much buffer space is available */ | |
381 | availLength = UFILE_UCHARBUFFER_SIZE - dataSize; | |
382 | ||
383 | /* Determine the # of codepage bytes needed to fill our UChar buffer */ | |
384 | /* weiv: if converter is NULL, we use invariant converter with charwidth = 1)*/ | |
385 | maxCPBytes = availLength / (f->fConverter!=NULL?(2*ucnv_getMinCharSize(f->fConverter)):1); | |
386 | ||
387 | /* Read in the data to convert */ | |
388 | bytesRead = (int32_t)fread(f->fCharBuffer, | |
389 | sizeof(char), | |
390 | ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), | |
391 | f->fFile); | |
392 | ||
393 | /* Set up conversion parameters */ | |
394 | status = U_ZERO_ERROR; | |
395 | mySource = f->fCharBuffer; | |
396 | mySourceEnd = f->fCharBuffer + bytesRead; | |
397 | myTarget = f->fUCBuffer + dataSize; | |
398 | bufferSize = UFILE_UCHARBUFFER_SIZE; | |
399 | ||
400 | if(f->fConverter != NULL) { /* We have a valid converter */ | |
401 | /* Perform the conversion */ | |
402 | ucnv_toUnicode(f->fConverter, | |
403 | &myTarget, | |
404 | f->fUCBuffer + bufferSize, | |
405 | &mySource, | |
406 | mySourceEnd, | |
407 | NULL, | |
408 | (UBool)(feof(f->fFile) != 0), | |
409 | &status); | |
410 | ||
411 | } else { /*weiv: do the invariant conversion */ | |
412 | u_charsToUChars(mySource, myTarget, bytesRead); | |
413 | myTarget += bytesRead; | |
414 | } | |
415 | ||
416 | /* update the pointers into our array */ | |
417 | f->fUCPos = f->fUCBuffer; | |
418 | f->fUCLimit = myTarget; | |
419 | } | |
420 | ||
421 | U_CAPI UChar* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
422 | u_fgets(UFILE *f, | |
423 | int32_t n, | |
424 | UChar *s) | |
425 | { | |
426 | int32_t dataSize; | |
427 | int32_t count; | |
428 | UChar *alias; | |
429 | UChar *limit; | |
430 | UChar *sItr; | |
431 | ||
432 | if (n <= 0) { | |
433 | /* Caller screwed up. We need to write the null terminatior. */ | |
434 | return NULL; | |
435 | } | |
436 | ||
437 | /* fill the buffer if needed */ | |
438 | if (f->fUCPos >= f->fUCLimit) { | |
439 | ufile_fill_uchar_buffer(f); | |
440 | } | |
441 | ||
442 | /* subtract 1 from n to compensate for the terminator */ | |
443 | --n; | |
444 | ||
445 | /* determine the amount of data in the buffer */ | |
446 | dataSize = (int32_t)(f->fUCLimit - f->fUCPos); | |
447 | ||
448 | /* if 0 characters were left, return 0 */ | |
449 | if (dataSize == 0) | |
450 | return NULL; | |
451 | ||
452 | /* otherwise, iteratively fill the buffer and copy */ | |
453 | count = 0; | |
454 | sItr = s; | |
455 | while (dataSize > 0 && count < n) { | |
456 | alias = f->fUCPos; | |
457 | ||
458 | /* Find how much to copy */ | |
459 | if (dataSize < n) { | |
460 | limit = f->fUCLimit; | |
461 | } | |
462 | else { | |
463 | limit = alias + n; | |
464 | } | |
465 | ||
466 | /* Copy UChars until we find the first occurrence of a delimiter character */ | |
467 | while (alias < limit && !IS_STRING_DELIMITER(*alias)) { | |
468 | count++; | |
469 | *(sItr++) = *(alias++); | |
470 | } | |
471 | /* Preserve the newline */ | |
472 | if (alias < limit && IS_STRING_DELIMITER(*alias)) { | |
473 | count++; | |
474 | *(sItr++) = *(alias++); | |
475 | } | |
476 | ||
477 | /* update the current buffer position */ | |
478 | f->fUCPos = alias; | |
479 | ||
480 | /* if we found a delimiter */ | |
481 | if (alias < f->fUCLimit) { | |
482 | ||
483 | /* break out */ | |
484 | break; | |
485 | } | |
486 | ||
487 | /* refill the buffer */ | |
488 | ufile_fill_uchar_buffer(f); | |
489 | ||
490 | /* determine the amount of data in the buffer */ | |
491 | dataSize = (int32_t)(f->fUCLimit - f->fUCPos); | |
492 | } | |
493 | ||
494 | /* add the terminator and return s */ | |
495 | *sItr = 0x0000; | |
496 | return s; | |
497 | } | |
498 | ||
499 | U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
500 | u_fgetc(UFILE *f) | |
501 | { | |
502 | /* if we have an available character in the buffer, return it */ | |
503 | if(f->fUCPos < f->fUCLimit) | |
504 | return *(f->fUCPos)++; | |
505 | /* otherwise, fill the buffer and return the next character */ | |
506 | else { | |
507 | ufile_fill_uchar_buffer(f); | |
508 | if(f->fUCPos < f->fUCLimit) | |
509 | return *(f->fUCPos)++; | |
510 | else | |
511 | return 0xFFFF; | |
512 | } | |
513 | } | |
514 | ||
515 | /* u_unescapeAt() callback to return a UChar from a UFILE */ | |
516 | static UChar U_CALLCONV | |
517 | _charAt(int32_t offset, void *context) { | |
518 | return ((UFILE*) context)->fUCPos[offset]; | |
519 | } | |
520 | ||
521 | /* Read a UChar from a UFILE and process escape sequences */ | |
522 | U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
523 | u_fgetcx(UFILE *f) | |
524 | { | |
525 | int32_t length; | |
526 | int32_t offset; | |
527 | UChar32 c32; | |
528 | UChar c16; | |
529 | ||
530 | /* Fill the buffer if it is empty */ | |
531 | if (f->fUCPos >= f->fUCLimit) { | |
532 | ufile_fill_uchar_buffer(f); | |
533 | } | |
534 | ||
535 | /* Get the next character in the buffer */ | |
536 | if (f->fUCPos < f->fUCLimit) { | |
537 | c16 = *(f->fUCPos)++; | |
538 | } else { | |
539 | c16 = U_EOF; | |
540 | } | |
541 | ||
542 | /* If it isn't a backslash, return it */ | |
543 | if (c16 != 0x005C /*'\\'*/) { | |
544 | return c16; | |
545 | } | |
546 | ||
547 | /* Determine the amount of data in the buffer */ | |
548 | length = (int32_t)(f->fUCLimit - f->fUCPos); | |
549 | ||
550 | /* The longest escape sequence is \Uhhhhhhhh; make sure | |
551 | we have at least that many characters */ | |
552 | if (length < 10) { | |
553 | /* fill the buffer */ | |
554 | ufile_fill_uchar_buffer(f); | |
555 | length = (int32_t)(f->fUCLimit - f->fUCPos); | |
556 | } | |
557 | ||
558 | /* Process the escape */ | |
559 | offset = 0; | |
560 | c32 = u_unescapeAt(_charAt, &offset, length, (void*)f); | |
561 | ||
562 | /* Update the current buffer position */ | |
563 | f->fUCPos += offset; | |
564 | ||
565 | return c32; | |
566 | } | |
567 | ||
568 | U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
569 | u_fungetc(UChar c, | |
570 | UFILE *f) | |
571 | { | |
572 | /* if we're at the beginning of the buffer, sorry! */ | |
573 | if(f->fUCPos == f->fUCBuffer) | |
574 | return 0xFFFF; | |
575 | /* otherwise, put the character back */ | |
576 | else { | |
577 | *--(f->fUCPos) = c; | |
578 | return c; | |
579 | } | |
580 | } | |
581 | ||
582 | U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ | |
583 | u_file_read( UChar *chars, | |
584 | int32_t count, | |
585 | UFILE *f) | |
586 | { | |
587 | int32_t dataSize; | |
588 | int32_t read; | |
589 | ||
590 | /* fill the buffer */ | |
591 | ufile_fill_uchar_buffer(f); | |
592 | ||
593 | /* determine the amount of data in the buffer */ | |
594 | dataSize = (int32_t)(f->fUCLimit - f->fUCPos); | |
595 | ||
596 | /* if the buffer contains the amount requested, just copy */ | |
597 | if(dataSize > count) { | |
598 | memcpy(chars, f->fUCPos, count * sizeof(UChar)); | |
599 | ||
600 | /* update the current buffer position */ | |
601 | f->fUCPos += count; | |
602 | ||
603 | /* return # of chars read */ | |
604 | return count; | |
605 | } | |
606 | ||
607 | /* otherwise, iteratively fill the buffer and copy */ | |
608 | read = 0; | |
609 | do { | |
610 | ||
611 | /* determine the amount of data in the buffer */ | |
612 | dataSize = (int32_t)(f->fUCLimit - f->fUCPos); | |
613 | ||
614 | /* copy the current data in the buffer */ | |
615 | memcpy(chars + read, f->fUCPos, dataSize * sizeof(UChar)); | |
616 | ||
617 | /* update number of items read */ | |
618 | read += dataSize; | |
619 | ||
620 | /* update the current buffer position */ | |
621 | f->fUCPos += dataSize; | |
622 | ||
623 | /* refill the buffer */ | |
624 | ufile_fill_uchar_buffer(f); | |
625 | ||
626 | } while(dataSize != 0 && read < count); | |
627 | ||
628 | return read; | |
629 | } |