]> git.saurik.com Git - apple/icu.git/blame - icuSources/extra/ustdio/ustdio.c
ICU-3.13.tar.gz
[apple/icu.git] / icuSources / extra / ustdio / ustdio.c
CommitLineData
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! */
34static const char copyright[] = U_COPYRIGHT_STRING;
35
36#ifdef WIN32
37static const UChar DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 };
38static const uint32_t DELIMITERS_LEN = 2;
39#else
40static const UChar DELIMITERS [] = { DELIM_LF, 0x0000 };
41static 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
49U_CAPI UTransliterator* U_EXPORT2
50u_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
112static 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
229void
230ufile_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
241void
242ufile_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
268U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
269u_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
277U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
278u_fputc(UChar uc,
279 UFILE *f)
280{
281 return u_file_write(&uc, 1, f) == 1 ? uc : EOF;
282}
283
284
285U_CAPI int32_t U_EXPORT2
286u_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
347U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
348u_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 */
357void
358ufile_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
421U_CAPI UChar* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
422u_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
499U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
500u_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 */
516static 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 */
522U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
523u_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
568U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
569u_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
582U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
583u_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}