michael@0: /* michael@0: ****************************************************************************** michael@0: * michael@0: * Copyright (C) 1998-2011, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ****************************************************************************** michael@0: * michael@0: * File ustdio.c michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 11/18/98 stephen Creation. michael@0: * 03/12/99 stephen Modified for new C API. michael@0: * 07/19/99 stephen Fixed read() and gets() michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/ustdio.h" michael@0: #include "unicode/putil.h" michael@0: #include "cmemory.h" michael@0: #include "cstring.h" michael@0: #include "ufile.h" michael@0: #include "ufmt_cmn.h" michael@0: #include "unicode/ucnv.h" michael@0: #include "unicode/ustring.h" michael@0: michael@0: #include michael@0: michael@0: #define DELIM_LF 0x000A michael@0: #define DELIM_VT 0x000B michael@0: #define DELIM_FF 0x000C michael@0: #define DELIM_CR 0x000D michael@0: #define DELIM_NEL 0x0085 michael@0: #define DELIM_LS 0x2028 michael@0: #define DELIM_PS 0x2029 michael@0: michael@0: /* TODO: is this correct for all codepages? Should we just use \n and let the converter handle it? */ michael@0: #if U_PLATFORM_USES_ONLY_WIN32_API michael@0: static const UChar DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 }; michael@0: static const uint32_t DELIMITERS_LEN = 2; michael@0: /* TODO: Default newline writing should be detected based upon the converter being used. */ michael@0: #else michael@0: static const UChar DELIMITERS [] = { DELIM_LF, 0x0000 }; michael@0: static const uint32_t DELIMITERS_LEN = 1; michael@0: #endif michael@0: michael@0: #define IS_FIRST_STRING_DELIMITER(c1) \ michael@0: (UBool)((DELIM_LF <= (c1) && (c1) <= DELIM_CR) \ michael@0: || (c1) == DELIM_NEL \ michael@0: || (c1) == DELIM_LS \ michael@0: || (c1) == DELIM_PS) michael@0: #define CAN_HAVE_COMBINED_STRING_DELIMITER(c1) (UBool)((c1) == DELIM_CR) michael@0: #define IS_COMBINED_STRING_DELIMITER(c1, c2) \ michael@0: (UBool)((c1) == DELIM_CR && (c2) == DELIM_LF) michael@0: michael@0: michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: michael@0: U_CAPI UTransliterator* U_EXPORT2 michael@0: u_fsettransliterator(UFILE *file, UFileDirection direction, michael@0: UTransliterator *adopt, UErrorCode *status) michael@0: { michael@0: UTransliterator *old = NULL; michael@0: michael@0: if(U_FAILURE(*status)) michael@0: { michael@0: return adopt; michael@0: } michael@0: michael@0: if(!file) michael@0: { michael@0: *status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return adopt; michael@0: } michael@0: michael@0: if(direction & U_READ) michael@0: { michael@0: /** TODO: implement */ michael@0: *status = U_UNSUPPORTED_ERROR; michael@0: return adopt; michael@0: } michael@0: michael@0: if(adopt == NULL) /* they are clearing it */ michael@0: { michael@0: if(file->fTranslit != NULL) michael@0: { michael@0: /* TODO: Check side */ michael@0: old = file->fTranslit->translit; michael@0: uprv_free(file->fTranslit->buffer); michael@0: file->fTranslit->buffer=NULL; michael@0: uprv_free(file->fTranslit); michael@0: file->fTranslit=NULL; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if(file->fTranslit == NULL) michael@0: { michael@0: file->fTranslit = (UFILETranslitBuffer*) uprv_malloc(sizeof(UFILETranslitBuffer)); michael@0: if(!file->fTranslit) michael@0: { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return adopt; michael@0: } michael@0: file->fTranslit->capacity = 0; michael@0: file->fTranslit->length = 0; michael@0: file->fTranslit->pos = 0; michael@0: file->fTranslit->buffer = NULL; michael@0: } michael@0: else michael@0: { michael@0: old = file->fTranslit->translit; michael@0: ufile_flush_translit(file); michael@0: } michael@0: michael@0: file->fTranslit->translit = adopt; michael@0: } michael@0: michael@0: return old; michael@0: } michael@0: michael@0: static const UChar * u_file_translit(UFILE *f, const UChar *src, int32_t *count, UBool flush) michael@0: { michael@0: int32_t newlen; michael@0: int32_t junkCount = 0; michael@0: int32_t textLength; michael@0: int32_t textLimit; michael@0: UTransPosition pos; michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: michael@0: if(count == NULL) michael@0: { michael@0: count = &junkCount; michael@0: } michael@0: michael@0: if ((!f)||(!f->fTranslit)||(!f->fTranslit->translit)) michael@0: { michael@0: /* fast path */ michael@0: return src; michael@0: } michael@0: michael@0: /* First: slide over everything */ michael@0: if(f->fTranslit->length > f->fTranslit->pos) michael@0: { michael@0: memmove(f->fTranslit->buffer, f->fTranslit->buffer + f->fTranslit->pos, michael@0: (f->fTranslit->length - f->fTranslit->pos)*sizeof(UChar)); michael@0: } michael@0: f->fTranslit->length -= f->fTranslit->pos; /* always */ michael@0: f->fTranslit->pos = 0; michael@0: michael@0: /* Calculate new buffer size needed */ michael@0: newlen = (*count + f->fTranslit->length) * 4; michael@0: michael@0: if(newlen > f->fTranslit->capacity) michael@0: { michael@0: if(f->fTranslit->buffer == NULL) michael@0: { michael@0: f->fTranslit->buffer = (UChar*)uprv_malloc(newlen * sizeof(UChar)); michael@0: } michael@0: else michael@0: { michael@0: f->fTranslit->buffer = (UChar*)uprv_realloc(f->fTranslit->buffer, newlen * sizeof(UChar)); michael@0: } michael@0: /* Check for malloc/realloc failure. */ michael@0: if (f->fTranslit->buffer == NULL) { michael@0: return NULL; michael@0: } michael@0: f->fTranslit->capacity = newlen; michael@0: } michael@0: michael@0: /* Now, copy any data over */ michael@0: u_strncpy(f->fTranslit->buffer + f->fTranslit->length, michael@0: src, michael@0: *count); michael@0: f->fTranslit->length += *count; michael@0: michael@0: /* Now, translit in place as much as we can */ michael@0: if(flush == FALSE) michael@0: { michael@0: textLength = f->fTranslit->length; michael@0: pos.contextStart = 0; michael@0: pos.contextLimit = textLength; michael@0: pos.start = 0; michael@0: pos.limit = textLength; michael@0: michael@0: utrans_transIncrementalUChars(f->fTranslit->translit, michael@0: f->fTranslit->buffer, /* because we shifted */ michael@0: &textLength, michael@0: f->fTranslit->capacity, michael@0: &pos, michael@0: &status); michael@0: michael@0: /* now: start/limit point to the transliterated text */ michael@0: /* Transliterated is [buffer..pos.start) */ michael@0: *count = pos.start; michael@0: f->fTranslit->pos = pos.start; michael@0: f->fTranslit->length = pos.limit; michael@0: michael@0: return f->fTranslit->buffer; michael@0: } michael@0: else michael@0: { michael@0: textLength = f->fTranslit->length; michael@0: textLimit = f->fTranslit->length; michael@0: michael@0: utrans_transUChars(f->fTranslit->translit, michael@0: f->fTranslit->buffer, michael@0: &textLength, michael@0: f->fTranslit->capacity, michael@0: 0, michael@0: &textLimit, michael@0: &status); michael@0: michael@0: /* out: converted len */ michael@0: *count = textLimit; michael@0: michael@0: /* Set pointers to 0 */ michael@0: f->fTranslit->pos = 0; michael@0: f->fTranslit->length = 0; michael@0: michael@0: return f->fTranslit->buffer; michael@0: } michael@0: } michael@0: michael@0: #endif michael@0: michael@0: void michael@0: ufile_flush_translit(UFILE *f) michael@0: { michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: if((!f)||(!f->fTranslit)) michael@0: return; michael@0: #endif michael@0: michael@0: u_file_write_flush(NULL, 0, f, FALSE, TRUE); michael@0: } michael@0: michael@0: michael@0: void michael@0: ufile_flush_io(UFILE *f) michael@0: { michael@0: if((!f) || (!f->fFile)) { michael@0: return; /* skip if no file */ michael@0: } michael@0: michael@0: u_file_write_flush(NULL, 0, f, TRUE, FALSE); michael@0: } michael@0: michael@0: michael@0: void michael@0: ufile_close_translit(UFILE *f) michael@0: { michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: if((!f)||(!f->fTranslit)) michael@0: return; michael@0: #endif michael@0: michael@0: ufile_flush_translit(f); michael@0: michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: if(f->fTranslit->translit) michael@0: utrans_close(f->fTranslit->translit); michael@0: michael@0: if(f->fTranslit->buffer) michael@0: { michael@0: uprv_free(f->fTranslit->buffer); michael@0: } michael@0: michael@0: uprv_free(f->fTranslit); michael@0: f->fTranslit = NULL; michael@0: #endif michael@0: } michael@0: michael@0: michael@0: /* Input/output */ michael@0: michael@0: U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fputs(const UChar *s, michael@0: UFILE *f) michael@0: { michael@0: int32_t count = u_file_write(s, u_strlen(s), f); michael@0: count += u_file_write(DELIMITERS, DELIMITERS_LEN, f); michael@0: return count; michael@0: } michael@0: michael@0: U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fputc(UChar32 uc, michael@0: UFILE *f) michael@0: { michael@0: UChar buf[2]; michael@0: int32_t idx = 0; michael@0: UBool isError = FALSE; michael@0: michael@0: U16_APPEND(buf, idx, sizeof(buf)/sizeof(*buf), uc, isError); michael@0: if (isError) { michael@0: return U_EOF; michael@0: } michael@0: return u_file_write(buf, idx, f) == idx ? uc : U_EOF; michael@0: } michael@0: michael@0: michael@0: U_CFUNC int32_t U_EXPORT2 michael@0: u_file_write_flush(const UChar *chars, michael@0: int32_t count, michael@0: UFILE *f, michael@0: UBool flushIO, michael@0: UBool flushTranslit) michael@0: { michael@0: /* Set up conversion parameters */ michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: const UChar *mySource = chars; michael@0: const UChar *mySourceBegin; michael@0: const UChar *mySourceEnd; michael@0: char charBuffer[UFILE_CHARBUFFER_SIZE]; michael@0: char *myTarget = charBuffer; michael@0: int32_t written = 0; michael@0: int32_t numConverted = 0; michael@0: michael@0: if (count < 0) { michael@0: count = u_strlen(chars); michael@0: } michael@0: michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: if((f->fTranslit) && (f->fTranslit->translit)) michael@0: { michael@0: /* Do the transliteration */ michael@0: mySource = u_file_translit(f, chars, &count, flushTranslit); michael@0: } michael@0: #endif michael@0: michael@0: /* Write to a string. */ michael@0: if (!f->fFile) { michael@0: int32_t charsLeft = (int32_t)(f->str.fLimit - f->str.fPos); michael@0: if (flushIO && charsLeft > count) { michael@0: count++; michael@0: } michael@0: written = ufmt_min(count, charsLeft); michael@0: u_strncpy(f->str.fPos, mySource, written); michael@0: f->str.fPos += written; michael@0: return written; michael@0: } michael@0: michael@0: mySourceEnd = mySource + count; michael@0: michael@0: /* Perform the conversion in a loop */ michael@0: do { michael@0: mySourceBegin = mySource; /* beginning location for this loop */ michael@0: status = U_ZERO_ERROR; michael@0: if(f->fConverter != NULL) { /* We have a valid converter */ michael@0: ucnv_fromUnicode(f->fConverter, michael@0: &myTarget, michael@0: charBuffer + UFILE_CHARBUFFER_SIZE, michael@0: &mySource, michael@0: mySourceEnd, michael@0: NULL, michael@0: flushIO, michael@0: &status); michael@0: } else { /*weiv: do the invariant conversion */ michael@0: int32_t convertChars = (int32_t) (mySourceEnd - mySource); michael@0: if (convertChars > UFILE_CHARBUFFER_SIZE) { michael@0: convertChars = UFILE_CHARBUFFER_SIZE; michael@0: status = U_BUFFER_OVERFLOW_ERROR; michael@0: } michael@0: u_UCharsToChars(mySource, myTarget, convertChars); michael@0: mySource += convertChars; michael@0: myTarget += convertChars; michael@0: } michael@0: numConverted = (int32_t)(myTarget - charBuffer); michael@0: michael@0: if (numConverted > 0) { michael@0: /* write the converted bytes */ michael@0: fwrite(charBuffer, michael@0: sizeof(char), michael@0: numConverted, michael@0: f->fFile); michael@0: michael@0: written += (int32_t) (mySource - mySourceBegin); michael@0: } michael@0: myTarget = charBuffer; michael@0: } michael@0: while(status == U_BUFFER_OVERFLOW_ERROR); michael@0: michael@0: /* return # of chars written */ michael@0: return written; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_file_write( const UChar *chars, michael@0: int32_t count, michael@0: UFILE *f) michael@0: { michael@0: return u_file_write_flush(chars,count,f,FALSE,FALSE); michael@0: } michael@0: michael@0: michael@0: /* private function used for buffering input */ michael@0: void michael@0: ufile_fill_uchar_buffer(UFILE *f) michael@0: { michael@0: UErrorCode status; michael@0: const char *mySource; michael@0: const char *mySourceEnd; michael@0: UChar *myTarget; michael@0: int32_t bufferSize; michael@0: int32_t maxCPBytes; michael@0: int32_t bytesRead; michael@0: int32_t availLength; michael@0: int32_t dataSize; michael@0: char charBuffer[UFILE_CHARBUFFER_SIZE]; michael@0: u_localized_string *str; michael@0: michael@0: if (f->fFile == NULL) { michael@0: /* There is nothing to do. It's a string. */ michael@0: return; michael@0: } michael@0: michael@0: str = &f->str; michael@0: dataSize = (int32_t)(str->fLimit - str->fPos); michael@0: if (f->fFileno == 0 && dataSize > 0) { michael@0: /* Don't read from stdin too many times. There is still some data. */ michael@0: return; michael@0: } michael@0: michael@0: /* shift the buffer if it isn't empty */ michael@0: if(dataSize != 0) { michael@0: uprv_memmove(f->fUCBuffer, str->fPos, dataSize * sizeof(UChar)); /* not accessing beyond memory */ michael@0: } michael@0: michael@0: michael@0: /* record how much buffer space is available */ michael@0: availLength = UFILE_UCHARBUFFER_SIZE - dataSize; michael@0: michael@0: /* Determine the # of codepage bytes needed to fill our UChar buffer */ michael@0: /* weiv: if converter is NULL, we use invariant converter with charwidth = 1)*/ michael@0: maxCPBytes = availLength / (f->fConverter!=NULL?(2*ucnv_getMinCharSize(f->fConverter)):1); michael@0: michael@0: /* Read in the data to convert */ michael@0: if (f->fFileno == 0) { michael@0: /* Special case. Read from stdin one line at a time. */ michael@0: char *retStr = fgets(charBuffer, ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), f->fFile); michael@0: bytesRead = (int32_t)(retStr ? uprv_strlen(charBuffer) : 0); michael@0: } michael@0: else { michael@0: /* A normal file */ michael@0: bytesRead = (int32_t)fread(charBuffer, michael@0: sizeof(char), michael@0: ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), michael@0: f->fFile); michael@0: } michael@0: michael@0: /* Set up conversion parameters */ michael@0: status = U_ZERO_ERROR; michael@0: mySource = charBuffer; michael@0: mySourceEnd = charBuffer + bytesRead; michael@0: myTarget = f->fUCBuffer + dataSize; michael@0: bufferSize = UFILE_UCHARBUFFER_SIZE; michael@0: michael@0: if(f->fConverter != NULL) { /* We have a valid converter */ michael@0: /* Perform the conversion */ michael@0: ucnv_toUnicode(f->fConverter, michael@0: &myTarget, michael@0: f->fUCBuffer + bufferSize, michael@0: &mySource, michael@0: mySourceEnd, michael@0: NULL, michael@0: (UBool)(feof(f->fFile) != 0), michael@0: &status); michael@0: michael@0: } else { /*weiv: do the invariant conversion */ michael@0: u_charsToUChars(mySource, myTarget, bytesRead); michael@0: myTarget += bytesRead; michael@0: } michael@0: michael@0: /* update the pointers into our array */ michael@0: str->fPos = str->fBuffer; michael@0: str->fLimit = myTarget; michael@0: } michael@0: michael@0: U_CAPI UChar* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fgets(UChar *s, michael@0: int32_t n, michael@0: UFILE *f) michael@0: { michael@0: int32_t dataSize; michael@0: int32_t count; michael@0: UChar *alias; michael@0: const UChar *limit; michael@0: UChar *sItr; michael@0: UChar currDelim = 0; michael@0: u_localized_string *str; michael@0: michael@0: if (n <= 0) { michael@0: /* Caller screwed up. We need to write the null terminatior. */ michael@0: return NULL; michael@0: } michael@0: michael@0: /* fill the buffer if needed */ michael@0: str = &f->str; michael@0: if (str->fPos >= str->fLimit) { michael@0: ufile_fill_uchar_buffer(f); michael@0: } michael@0: michael@0: /* subtract 1 from n to compensate for the terminator */ michael@0: --n; michael@0: michael@0: /* determine the amount of data in the buffer */ michael@0: dataSize = (int32_t)(str->fLimit - str->fPos); michael@0: michael@0: /* if 0 characters were left, return 0 */ michael@0: if (dataSize == 0) michael@0: return NULL; michael@0: michael@0: /* otherwise, iteratively fill the buffer and copy */ michael@0: count = 0; michael@0: sItr = s; michael@0: currDelim = 0; michael@0: while (dataSize > 0 && count < n) { michael@0: alias = str->fPos; michael@0: michael@0: /* Find how much to copy */ michael@0: if (dataSize < (n - count)) { michael@0: limit = str->fLimit; michael@0: } michael@0: else { michael@0: limit = alias + (n - count); michael@0: } michael@0: michael@0: if (!currDelim) { michael@0: /* Copy UChars until we find the first occurrence of a delimiter character */ michael@0: while (alias < limit && !IS_FIRST_STRING_DELIMITER(*alias)) { michael@0: count++; michael@0: *(sItr++) = *(alias++); michael@0: } michael@0: /* Preserve the newline */ michael@0: if (alias < limit && IS_FIRST_STRING_DELIMITER(*alias)) { michael@0: if (CAN_HAVE_COMBINED_STRING_DELIMITER(*alias)) { michael@0: currDelim = *alias; michael@0: } michael@0: else { michael@0: currDelim = 1; /* This isn't a newline, but it's used to say michael@0: that we should break later. We've checked all michael@0: possible newline combinations even across buffer michael@0: boundaries. */ michael@0: } michael@0: count++; michael@0: *(sItr++) = *(alias++); michael@0: } michael@0: } michael@0: /* If we have a CRLF combination, preserve that too. */ michael@0: if (alias < limit) { michael@0: if (currDelim && IS_COMBINED_STRING_DELIMITER(currDelim, *alias)) { michael@0: count++; michael@0: *(sItr++) = *(alias++); michael@0: } michael@0: currDelim = 1; /* This isn't a newline, but it's used to say michael@0: that we should break later. We've checked all michael@0: possible newline combinations even across buffer michael@0: boundaries. */ michael@0: } michael@0: michael@0: /* update the current buffer position */ michael@0: str->fPos = alias; michael@0: michael@0: /* if we found a delimiter */ michael@0: if (currDelim == 1) { michael@0: /* break out */ michael@0: break; michael@0: } michael@0: michael@0: /* refill the buffer */ michael@0: ufile_fill_uchar_buffer(f); michael@0: michael@0: /* determine the amount of data in the buffer */ michael@0: dataSize = (int32_t)(str->fLimit - str->fPos); michael@0: } michael@0: michael@0: /* add the terminator and return s */ michael@0: *sItr = 0x0000; michael@0: return s; michael@0: } michael@0: michael@0: U_CFUNC UBool U_EXPORT2 michael@0: ufile_getch(UFILE *f, UChar *ch) michael@0: { michael@0: UBool isValidChar = FALSE; michael@0: michael@0: *ch = U_EOF; michael@0: /* if we have an available character in the buffer, return it */ michael@0: if(f->str.fPos < f->str.fLimit){ michael@0: *ch = *(f->str.fPos)++; michael@0: isValidChar = TRUE; michael@0: } michael@0: else { michael@0: /* otherwise, fill the buffer and return the next character */ michael@0: if(f->str.fPos >= f->str.fLimit) { michael@0: ufile_fill_uchar_buffer(f); michael@0: } michael@0: if(f->str.fPos < f->str.fLimit) { michael@0: *ch = *(f->str.fPos)++; michael@0: isValidChar = TRUE; michael@0: } michael@0: } michael@0: return isValidChar; michael@0: } michael@0: michael@0: U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fgetc(UFILE *f) michael@0: { michael@0: UChar ch; michael@0: ufile_getch(f, &ch); michael@0: return ch; michael@0: } michael@0: michael@0: U_CFUNC UBool U_EXPORT2 michael@0: ufile_getch32(UFILE *f, UChar32 *c32) michael@0: { michael@0: UBool isValidChar = FALSE; michael@0: u_localized_string *str; michael@0: michael@0: *c32 = U_EOF; michael@0: michael@0: /* Fill the buffer if it is empty */ michael@0: str = &f->str; michael@0: if (f && str->fPos + 1 >= str->fLimit) { michael@0: ufile_fill_uchar_buffer(f); michael@0: } michael@0: michael@0: /* Get the next character in the buffer */ michael@0: if (str->fPos < str->fLimit) { michael@0: *c32 = *(str->fPos)++; michael@0: if (U_IS_LEAD(*c32)) { michael@0: if (str->fPos < str->fLimit) { michael@0: UChar c16 = *(str->fPos)++; michael@0: *c32 = U16_GET_SUPPLEMENTARY(*c32, c16); michael@0: isValidChar = TRUE; michael@0: } michael@0: else { michael@0: *c32 = U_EOF; michael@0: } michael@0: } michael@0: else { michael@0: isValidChar = TRUE; michael@0: } michael@0: } michael@0: michael@0: return isValidChar; michael@0: } michael@0: michael@0: U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fgetcx(UFILE *f) michael@0: { michael@0: UChar32 ch; michael@0: ufile_getch32(f, &ch); michael@0: return ch; michael@0: } michael@0: michael@0: U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_fungetc(UChar32 ch, michael@0: UFILE *f) michael@0: { michael@0: u_localized_string *str; michael@0: michael@0: str = &f->str; michael@0: michael@0: /* if we're at the beginning of the buffer, sorry! */ michael@0: if (str->fPos == str->fBuffer michael@0: || (U_IS_LEAD(ch) && (str->fPos - 1) == str->fBuffer)) michael@0: { michael@0: ch = U_EOF; michael@0: } michael@0: else { michael@0: /* otherwise, put the character back */ michael@0: /* Remember, read them back on in the reverse order. */ michael@0: if (U_IS_LEAD(ch)) { michael@0: if (*--(str->fPos) != U16_TRAIL(ch) michael@0: || *--(str->fPos) != U16_LEAD(ch)) michael@0: { michael@0: ch = U_EOF; michael@0: } michael@0: } michael@0: else if (*--(str->fPos) != ch) { michael@0: ch = U_EOF; michael@0: } michael@0: } michael@0: return ch; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ michael@0: u_file_read( UChar *chars, michael@0: int32_t count, michael@0: UFILE *f) michael@0: { michael@0: int32_t dataSize; michael@0: int32_t read = 0; michael@0: u_localized_string *str = &f->str; michael@0: michael@0: do { michael@0: michael@0: /* determine the amount of data in the buffer */ michael@0: dataSize = (int32_t)(str->fLimit - str->fPos); michael@0: if (dataSize <= 0) { michael@0: /* fill the buffer */ michael@0: ufile_fill_uchar_buffer(f); michael@0: dataSize = (int32_t)(str->fLimit - str->fPos); michael@0: } michael@0: michael@0: /* Make sure that we don't read too much */ michael@0: if (dataSize > (count - read)) { michael@0: dataSize = count - read; michael@0: } michael@0: michael@0: /* copy the current data in the buffer */ michael@0: memcpy(chars + read, str->fPos, dataSize * sizeof(UChar)); michael@0: michael@0: /* update number of items read */ michael@0: read += dataSize; michael@0: michael@0: /* update the current buffer position */ michael@0: str->fPos += dataSize; michael@0: } michael@0: while (dataSize != 0 && read < count); michael@0: michael@0: return read; michael@0: }