_CODE_ACCESS int fseek(register FILE *_fp, long _offset, int _ptrname) { /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to the file stream. In this case, _fp may be updated, so we must */ /* ensure that the local copy of _fp is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_file_lock(_fp); /*------------------------------------------------------------------------*/ /* If the current stream is not associated with a file, return an error. */ /*------------------------------------------------------------------------*/ if (_fp->fd == -1) { __TI_data_synch_INV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } /*------------------------------------------------------------------------*/ /* When positioning to a location relative to the current location, */ /* adjust for the fact that there may be something in the buffer. */ /*------------------------------------------------------------------------*/ if(_ptrname == SEEK_CUR && _STCHK(_fp, _MODER) && _fp->pos) _offset -= (_fp->buff_stop - _fp->pos); __TI_doflush(_fp); _UNSET(_fp, (_STATEOF | _UNGETC)); if ((lseek(_fp->fd, _offset, _ptrname)) == -1) { __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (0); }
_CODE_ACCESS int __TI_doflush(FILE *_fp) { /*------------------------------------------------------------------------*/ /* Local variables */ /* */ /* num_write - The number of bytes to be written to the file */ /* errchk - An indicator to see if WRITE was successful */ /*------------------------------------------------------------------------*/ unsigned num_write = _fp->pos - _fp->buf; int errchk = 0; /*------------------------------------------------------------------------*/ /* If the current stream is not associated with a file, return an error. */ /*------------------------------------------------------------------------*/ if (_fp->fd == -1) return (EOF); /*------------------------------------------------------------------------*/ /* If the stream is writable, and it has a buffer, call WRITE, and store */ /* its return value in errchk */ /*------------------------------------------------------------------------*/ if (_STCHK(_fp, _MODEW) && _fp->buf != NULL && num_write != 0) errchk = write(_fp->fd, (char *)_fp->buf, num_write); /*------------------------------------------------------------------------*/ /* If WRITE fails, set the error flag in the stream pointer, and return */ /* an EOF */ /*------------------------------------------------------------------------*/ if (errchk < 0) { _SET(_fp, _STATERR); return (EOF); } /*------------------------------------------------------------------------*/ /* Reset the buffer pointer, make files opened with the "+" flag */ /* available for wither reading or writing, and return a 0, indicating */ /* a success */ /*------------------------------------------------------------------------*/ _fp->pos = _fp->buff_stop = _fp->buf; if (_STCHK(_fp, _MODERW)) _UNSET(_fp, (_MODER | _MODEW)); return 0; }
_CODE_ACCESS size_t fread(void *_ptr, size_t _size, size_t _count, FILE *_fp) { /*------------------------------------------------------------------------*/ /* Local variables */ /*------------------------------------------------------------------------*/ unsigned char *fpos = (unsigned char *)_ptr; size_t num_left = _size * _count, num_read = 0, num_to_read = 0; /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to the file stream. In this case, _fp may be updated, so we must */ /* ensure that the local copy of _fp is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_file_lock(_fp); /*------------------------------------------------------------------------*/ /* Make sure that the file is readable. */ /*------------------------------------------------------------------------*/ if (!__TI_rd_ok(_fp) || _size == 0 || _count == 0) { __TI_data_synch_INV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (0); } /*------------------------------------------------------------------------*/ /* If the stream is non-buffered, call the lowlevel READ function. */ /*------------------------------------------------------------------------*/ if (_BUFFMODE(_fp) == _IONBF) { int num_read = 0; while (num_left > 0) { int read_return; if (_STCHK(_fp, _UNGETC)) { *fpos = *(_fp->pos++); _UNSET(_fp, _UNGETC); read_return = 1; } else read_return = (size_t)(read(_fp->fd, (char *)fpos + num_read, num_left)); if (read_return < 0) { _SET(_fp, _STATERR); break; } else if (read_return == 0) { _SET(_fp, _STATEOF); break; } else { num_read += read_return; num_left -= read_return; } } __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (num_read / _size); } while (num_left > 0) { /*---------------------------------------------------------------------*/ /* If the buffer has been completely read, fill it up. Exit the loop */ /* if an I/O error occurs, or the end of the file is reached. */ /*---------------------------------------------------------------------*/ if(_fp->pos == _fp->buff_stop) __TI_buff_read(_fp); if(_STCHK(_fp, (_STATERR | _STATEOF))) break; /*---------------------------------------------------------------------*/ /* Determine how many characters can fit in the buffer, and read them */ /* in. */ /*---------------------------------------------------------------------*/ num_to_read = (num_left < (_fp->buff_stop - _fp->pos)) ? num_left : (_fp->buff_stop - _fp->pos); memcpy(fpos, _fp->pos, num_to_read); /*---------------------------------------------------------------------*/ /* Update pointers and counters. */ /*---------------------------------------------------------------------*/ fpos += num_to_read; _fp->pos += num_to_read; num_read += num_to_read; num_left -= num_to_read; } /*------------------------------------------------------------------------*/ /* Clear the _UNGETC flag in the stream, and return the number of blocks */ /* read. */ /*------------------------------------------------------------------------*/ _UNSET(_fp, _UNGETC); __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (num_read / _size); }
_CODE_ACCESS int fgetc(register FILE *_fp) { int retval = EOF; /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to __TI_LOCK_FILE_TBL shared resources (_ftable[], _ft_end, and */ /* _tmpnams[]). In this case, _ftable[] may be updated, so we must ensure */ /* that the local copy of _ftable[] is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); /*------------------------------------------------------------------------*/ /* Make sure that it is OK to read from this stream. */ /*------------------------------------------------------------------------*/ if (!_rd_ok(_fp)) goto fgetc_exit; /*------------------------------------------------------------------------*/ /* For non-buffered streams, call the lowlevel READ function. */ /*------------------------------------------------------------------------*/ if (_BUFFMODE(_fp) == _IONBF) { int errchk; char result; if (_STCHK(_fp, _UNGETC)) { _UNSET(_fp, _UNGETC); retval = (int)*(_fp->pos++); goto fgetc_exit; } errchk = read(_fp->fd, &result, 1); if (errchk <= 0) { _SET(_fp, (errchk == 0) ? _STATEOF : _STATERR); goto fgetc_exit; } retval = (int)result; goto fgetc_exit; } /*------------------------------------------------------------------------*/ /* If the buffer has been entirely read, or is empty, call _BUFF_READ to */ /* fill the buffer. */ /*------------------------------------------------------------------------*/ if (_fp->pos == _fp->buff_stop) _buff_read(_fp); /*------------------------------------------------------------------------*/ /* If the buffer read was unsuccessful, return an EOF. Otherwise, clear */ /* the _UNGETC flag in the stream, and return the next character. */ /*------------------------------------------------------------------------*/ if (_STCHK(_fp, (_STATERR | _STATEOF))) goto fgetc_exit; _UNSET(_fp, _UNGETC); retval = *(_fp->pos++); fgetc_exit: __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (retval); }
_CODE_ACCESS int setvbuf(register FILE *_fp, register char *_buf, register int _type, register size_t _size) { /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to the file stream. In this case, _fp may be updated, so we must */ /* ensure that the local copy of _fp is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_file_lock(_fp); /*------------------------------------------------------------------------*/ /* If the current stream is not associated with a file, return an error. */ /*------------------------------------------------------------------------*/ if (_fp->fd == -1 || (_type != _IONBF && _size <= 0)) { __TI_data_synch_INV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } /*------------------------------------------------------------------------*/ /* If a buffer already exists, free it if it was malloc'd, and reset all */ /* of the stream's buffer pointers. */ /*------------------------------------------------------------------------*/ if (_fp->buf) { if(_STCHK(_fp, _BUFFALOC)) free((_fp->buf)-1); _UNSET(_fp, _BUFFALOC); _fp->buf = NULL; _fp->pos = NULL; _fp->bufend = NULL; _fp->buff_stop = NULL; } /*------------------------------------------------------------------------*/ /* If NULL was used for the buffering mode, default to fully-buffered. */ /*------------------------------------------------------------------------*/ if (!_type) _type = _IOFBF; /*------------------------------------------------------------------------*/ /* Clear any previous buffering flags, and set the new one. */ /*------------------------------------------------------------------------*/ _UNSET(_fp, (_IOLBF | _IOFBF | _IONBF)); _SET(_fp, _type); /*------------------------------------------------------------------------*/ /* If a buffer was provided, but its size is only one byte, allocate a */ /* different one. Also, do not allow a buffer size greater than BUFSIZ. */ /* The buffer will always have one space at the beginning that is */ /* for UNGETC, in the event that an UNGETC is performed on an empty file, */ /* or when the buffer is full, but unread. */ /*------------------------------------------------------------------------*/ if (_size == 1) _buf = NULL; if (_size > BUFSIZ) _size = BUFSIZ; if (_buf) _fp->buf = (unsigned char*)_buf+1; else { /*---------------------------------------------------------------------*/ /* If allocating a buffer, provide _size bytes of usable space by */ /* incrementing _size, unless it is greater than BUFSIZ. */ /*---------------------------------------------------------------------*/ if (_size <= BUFSIZ) _size++; if (! (_fp->buf = (unsigned char*)malloc(_size))) { _SET(_fp, _STATERR); __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } _fp->buf++; _SET(_fp, _BUFFALOC); } _fp->pos = _fp->buff_stop = _fp->buf; _fp->bufend = _fp->buf + _size -1; __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); /*------------------------------------------------------------------------*/ /* SETUP _CLEANUP_PTR SO ALL BUFFERS WILL BE FLUSHED AT EXIT. */ /*------------------------------------------------------------------------*/ /* __TI_cleanup_ptr is also a shared resource in multi-threaded */ /* applications, so accesses to it are also protected by the */ /* __TI_LOCK_FILE_TBL mutex. The current thread will also invalidate any */ /* local copy of __TI_cleanup_ptr in the data cache of the core that it */ /* is running on before leaving the critical section. */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); __TI_cleanup_ptr = __TI_cleanup; __TI_data_synch_WBINV(&__TI_cleanup_ptr, sizeof(__TI_cleanup_ptr)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (0); }