/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * "buffered" i/o functions for the standalone environment. (ugh). */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include enum { F_OPEN = 0x01, F_ERROR = 0x02, F_SEEKABLE = 0x04 }; FILE __iob[_NFILE] = { { F_OPEN, 0, 0, 0, "stdin" }, { F_OPEN, 1, 0, 0, "stdout" }, { F_OPEN, 2, 0, 0, "stderr" } }; static boolean_t fcheck(FILE *stream, int flags) { errno = 0; if ((stream->_flag & flags) != flags) { errno = EBADF; return (B_FALSE); } return (B_TRUE); } int fclose(FILE *stream) { if (!fcheck(stream, F_OPEN)) return (EOF); (void) close(stream->_file); stream->_flag = 0; stream->_file = -1; stream->_name[0] = '\0'; return (0); } int feof(FILE *stream) { if (!fcheck(stream, F_OPEN)) return (0); return (stream->_len == stream->_offset); } int ferror(FILE *stream) { if (!fcheck(stream, F_OPEN)) return (0); return ((stream->_flag & F_ERROR) != 0); } void clearerr(FILE *stream) { stream->_flag &= ~F_ERROR; } int fflush(FILE *stream) { if (!fcheck(stream, F_OPEN)) return (EOF); /* Currently, a nop */ return (0); } char * fgets(char *s, int n, FILE *stream) { int bytes; ssize_t cnt; if (!fcheck(stream, F_OPEN)) return (NULL); for (bytes = 0; bytes < (n - 1); ++bytes) { cnt = read(stream->_file, &s[bytes], 1); if (cnt < 0) { if (bytes != 0) { s[bytes] = '\0'; return (s); } else { stream->_flag |= F_ERROR; return (NULL); } } else if (cnt == 0) { /* EOF */ if (bytes != 0) { s[bytes] = '\0'; return (s); } else return (NULL); } else { stream->_offset++; if (s[bytes] == '\n') { s[bytes + 1] = '\0'; return (s); } } } s[bytes] = '\0'; return (s); } /* * We currently only support read-only ("r" mode) opens and unbuffered I/O. */ FILE * fopen(const char *filename, const char *mode) { FILE *stream; const char *t; int fd, i; errno = 0; /* * Make sure we have a filesystem underneath us before even trying. */ if (get_default_fs() == NULL) return (NULL); for (t = mode; t != NULL && *t != '\0'; t++) { switch (*t) { case 'b': /* We ignore this a'la ISO C standard conformance */ break; case 'r': /* We ignore this because we always open for reading */ break; case 'a': case 'w': case '+': errno = EROFS; return (NULL); default: errno = EINVAL; return (NULL); } } for (i = 0; i < _NFILE; i++) { stream = &__iob[i]; if ((stream->_flag & F_OPEN) == 0) { fd = open(filename, O_RDONLY); if (fd < 0) return (NULL); stream->_file = fd; stream->_flag |= F_OPEN; (void) strlcpy(stream->_name, filename, sizeof (stream->_name)); return (stream); } } errno = EMFILE; return (NULL); } /* PRINTFLIKE1 */ void printf(const char *fmt, ...) { va_list adx; va_start(adx, fmt); prom_vprintf(fmt, adx); va_end(adx); } /* * Only writing to stderr or stdout is permitted. */ /* PRINTFLIKE2 */ int fprintf(FILE *stream, const char *format, ...) { int nwritten; va_list va; if (!fcheck(stream, F_OPEN)) return (-1); /* * Since fopen() doesn't return writable streams, the only valid * writable streams are stdout and stderr. */ if (stream != stdout && stream != stderr) { errno = EBADF; return (-1); } va_start(va, format); printf(format, va); va_end(va); va_start(va, format); nwritten = vsnprintf(NULL, 0, format, va); va_end(va); return (nwritten); } size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream) { size_t items; ssize_t bytes, totbytes = 0; char *strp = ptr; if (!fcheck(stream, F_OPEN)) return (0); for (items = 0, bytes = 0; items < nitems; items++) { bytes = read(stream->_file, &strp[totbytes], size); if (bytes < 0) { stream->_flag |= F_ERROR; return (0); } else if (bytes == 0) { /* EOF */ return ((totbytes == 0) ? 0 : totbytes / size); } else if (bytes == size) { stream->_offset += bytes; totbytes += bytes; } else { (void) lseek(stream->_file, stream->_offset, SEEK_SET); return (totbytes / size); } } return (totbytes / size); } /* * We don't grow files. */ int fseek(FILE *stream, long offset, int whence) { off_t new_offset, result; if (!fcheck(stream, F_OPEN | F_SEEKABLE)) return (-1); switch (whence) { case SEEK_SET: new_offset = (off_t)offset; break; case SEEK_CUR: new_offset = stream->_offset + (off_t)offset; break; case SEEK_END: new_offset = (off_t)stream->_len + (off_t)offset; break; default: errno = EINVAL; return (-1); } if (new_offset > (off_t)stream->_len) { errno = EFBIG; } else if (new_offset < 0L) { errno = EOVERFLOW; } else { errno = 0; } result = lseek(stream->_file, new_offset, SEEK_SET); if (result >= 0) stream->_offset = result; else stream->_flag |= F_ERROR; return (result); } long ftell(FILE *stream) { if (!fcheck(stream, F_OPEN | F_SEEKABLE)) return (0); return ((long)stream->_offset); } size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream) { if (!fcheck(stream, F_OPEN)) return (0); /* * Since fopen() doesn't return writable streams, the only valid * writable streams are stdout and stderr. */ if (stream != stdout && stream != stderr) { errno = EBADF; return (0); } prom_writestr(ptr, size * nitems); return (nitems); } /*ARGSUSED*/ int setvbuf(FILE *stream, char *buf, int type, size_t size) { if (!fcheck(stream, F_OPEN)) return (-1); /* Currently a nop, probably always will be. */ return (0); }