| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 | /* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> * This file is part of the Linux-8086 C library and is distributed * under the GNU Library General Public License. *//* This is an implementation of the C standard IO package. */#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <malloc.h>#include <errno.h>#include <string.h>#undef STUB_FWRITEvoid __io_init_vars(void);extern FILE *__IO_list;			/* For fflush at exit */#define FIXED_BUFFERS 2struct fixed_buffer {	unsigned char data[BUFSIZ];	int used;};extern struct fixed_buffer _fixed_buffers[2];#define Inline_init __io_init_vars()#ifdef L__stdio_init#define buferr (stderr->unbuf)	/* Stderr is unbuffered */FILE *__IO_list = 0;			/* For fflush at exit */#if 0static char bufin[BUFSIZ];static char bufout[BUFSIZ];#ifndef buferrstatic char buferr[BUFSIZ];#endif#elsestatic char *bufin;static char *bufout;#ifndef buferrstatic char *buferr;#endif#endifFILE stdin[1] = {#if 0	{bufin, bufin, bufin, bufin, bufin + sizeof(bufin),#else	{0, 0, 0, 0, 0,#endif	 0, _IOFBF | __MODE_READ | __MODE_IOTRAN}};FILE stdout[1] = {#if 0	{bufout, bufout, bufout, bufout, bufout + sizeof(bufout),#else	{0, 0, 0, 0, 0,#endif	 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN}};FILE stderr[1] = {#if 0	{buferr, buferr, buferr, buferr, buferr + sizeof(buferr),#else	{0, 0, 0, 0, 0,#endif	 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN}};/* Call the stdio initiliser; it's main job it to call atexit */void __stdio_close_all(void){	FILE *fp;	fflush(stdout);	fflush(stderr);	for (fp = __IO_list; fp; fp = fp->next) {		fflush(fp);		close(fp->fd);		/* Note we're not de-allocating the memory */		/* There doesn't seem to be much point :-) */		fp->fd = -1;	}}static int first_time = 0;struct fixed_buffer _fixed_buffers[2];void __io_init_vars(void){	if (first_time)		return;	first_time = 1;	stdin->bufpos = bufin = _fixed_buffers[0].data;		/*(char *)malloc(BUFSIZ) */ ;	stdin->bufread = bufin;	stdin->bufwrite = bufin;	stdin->bufstart = bufin;	stdin->bufend = bufin + sizeof(bufin);	stdin->fd = 0;	stdin->mode = _IOFBF | __MODE_READ | __MODE_IOTRAN | __MODE_FREEBUF;	_fixed_buffers[0].used = 1;	stdout->bufpos = bufout = _fixed_buffers[1].data;	/*(char *)malloc(BUFSIZ); */	stdout->bufread = bufout;	stdout->bufwrite = bufout;	stdout->bufstart = bufout;	stdout->bufend = bufout + sizeof(bufout);	stdout->fd = 1;	stdout->mode = _IOFBF | __MODE_WRITE | __MODE_IOTRAN | __MODE_FREEBUF;	_fixed_buffers[1].used = 1;#if 0	stderr->bufpos = buferr = (char *) malloc(BUFSIZ);#else	stderr->bufpos = buferr;#endif	stderr->bufread = buferr;	stderr->bufwrite = buferr;	stderr->bufstart = buferr;	stderr->bufend = buferr + sizeof(buferr);	stderr->fd = 2;	stderr->mode = _IONBF | __MODE_WRITE | __MODE_IOTRAN;	if (isatty(1))		stdout->mode |= _IOLBF;	atexit(__stdio_close_all);}#endif#ifdef L_fputcint fputc(ch, fp)int ch;FILE *fp;{	register int v;	Inline_init;	v = fp->mode;	/* If last op was a read ... */	if ((v & __MODE_READING) && fflush(fp))		return EOF;	/* Can't write or there's been an EOF or error then return EOF */	if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)		return EOF;	/* In MSDOS translation mode */#if __MODE_IOTRAN	if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF)		return EOF;#endif	/* Buffer is full */	if (fp->bufpos >= fp->bufend && fflush(fp))		return EOF;	/* Right! Do it! */	*(fp->bufpos++) = ch;	fp->mode |= __MODE_WRITING;	/* Unbuffered or Line buffered and end of line */	if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF))		&& fflush(fp))		return EOF;	/* Can the macro handle this by itself ? */	if (v & (__MODE_IOTRAN | _IOLBF | _IONBF))		fp->bufwrite = fp->bufstart;	/* Nope */	else		fp->bufwrite = fp->bufend;	/* Yup */	/* Correct return val */	return (unsigned char) ch;}#endif#ifdef L_fgetcint fgetc(fp)FILE *fp;{	int ch;	Inline_init;	if (fp->mode & __MODE_WRITING)		fflush(fp);#if __MODE_IOTRAN  try_again:#endif	/* Can't read or there's been an EOF or error then return EOF */	if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) !=		__MODE_READ) return EOF;	/* Nothing in the buffer - fill it up */	if (fp->bufpos >= fp->bufread) {		fp->bufpos = fp->bufread = fp->bufstart;		ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp);		if (ch == 0)			return EOF;		fp->bufread += ch;		fp->mode |= __MODE_READING;		fp->mode &= ~__MODE_UNGOT;	}	ch = *(fp->bufpos++);#if __MODE_IOTRAN	/* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */	if (ch == '\r' && (fp->mode & __MODE_IOTRAN))		goto try_again;#endif	return ch;}#endif#ifdef L_fflushint fflush(fp)FILE *fp;{	int len, cc, rv = 0;	char *bstart;	if (fp == NULL) {			/* On NULL flush the lot. */		if (fflush(stdin))			return EOF;		if (fflush(stdout))			return EOF;		if (fflush(stderr))			return EOF;		for (fp = __IO_list; fp; fp = fp->next)			if (fflush(fp))				return EOF;		return 0;	}	/* If there's output data pending */	if (fp->mode & __MODE_WRITING) {		len = fp->bufpos - fp->bufstart;		if (len) {			bstart = fp->bufstart;			/*			 * The loop is so we don't get upset by signals or partial writes.			 */			do {				cc = write(fp->fd, bstart, len);				if (cc > 0) {					bstart += cc;					len -= cc;				}			}			while (cc > 0 || (cc == -1 && errno == EINTR));			/*			 * If we get here with len!=0 there was an error, exactly what to			 * do about it is another matter ...			 *			 * I'll just clear the buffer.			 */			if (len) {				fp->mode |= __MODE_ERR;				rv = EOF;			}		}	}	/* If there's data in the buffer sychronise the file positions */	else if (fp->mode & __MODE_READING) {		/* Humm, I think this means sync the file like fpurge() ... */		/* Anyway the user isn't supposed to call this function when reading */		len = fp->bufread - fp->bufpos;	/* Bytes buffered but unread */		/* If it's a file, make it good */		if (len > 0 && lseek(fp->fd, (long) -len, 1) < 0) {			/* Hummm - Not certain here, I don't think this is reported */			/*			 * fp->mode |= __MODE_ERR; return EOF;			 */		}	}	/* All done, no problem */	fp->mode &=		(~(__MODE_READING | __MODE_WRITING | __MODE_EOF | __MODE_UNGOT));	fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart;	return rv;}#endif#ifdef L_fgets/* Nothing special here ... */char *fgets(s, count, f)char *s;int count;FILE *f;{	char *ret;	register size_t i;	register int ch;	ret = s;	for (i = count; i > 0; i--) {		ch = getc(f);		if (ch == EOF) {			if (s == ret)				return 0;			break;		}		*s++ = (char) ch;		if (ch == '\n')			break;	}	*s = 0;	if (ferror(f))		return 0;	return ret;}#endif#ifdef L_getschar *gets(str) /* BAD function; DON'T use it! */char *str;{	/* Auwlright it will work but of course _your_ program will crash */	/* if it's given a too long line */	register char *p = str;	register int c;	while (((c = getc(stdin)) != EOF) && (c != '\n'))		*p++ = c;	*p = '\0';	return (((c == EOF) && (p == str)) ? NULL : str);	/* NULL == EOF */}#endif#ifdef L_fputsint fputs(str, fp)const char *str;FILE *fp;{	register int n = 0;	while (*str) {		if (putc(*str++, fp) == EOF)			return (EOF);		++n;	}	return (n);}#endif#ifdef L_putsint puts(str)const char *str;{	register int n;	if (((n = fputs(str, stdout)) == EOF)		|| (putc('\n', stdout) == EOF))		return (EOF);	return (++n);}#endif#ifdef L_fread/* * fread will often be used to read in large chunks of data calling read() * directly can be a big win in this case. Beware also fgetc calls this * function to fill the buffer. *  * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what * fgetc wants) */size_t fread(buf, size, nelm, fp)void *buf;size_t size;size_t nelm;FILE *fp;{	int len, v;	unsigned bytes, got = 0;	Inline_init;	v = fp->mode;	/* Want to do this to bring the file pointer up to date */	if (v & __MODE_WRITING)		fflush(fp);	/* Can't read or there's been an EOF or error then return zero */	if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ)		return 0;	/* This could be long, doesn't seem much point tho */	bytes = size * nelm;	len = fp->bufread - fp->bufpos;	if (len >= bytes) {			/* Enough buffered */		memcpy(buf, fp->bufpos, (unsigned) bytes);		fp->bufpos += bytes;		return bytes;	} else if (len > 0) {		/* Some buffered */		memcpy(buf, fp->bufpos, len);		got = len;	}	/* Need more; do it with a direct read */	len = read(fp->fd, buf + got, (unsigned) (bytes - got));	/* Possibly for now _or_ later */	if (len < 0) {		fp->mode |= __MODE_ERR;		len = 0;	} else if (len == 0)		fp->mode |= __MODE_EOF;	return (got + len) / size;}#endif#ifdef L_fwrite/* * Like fread, fwrite will often be used to write out large chunks of * data; calling write() directly can be a big win in this case. *  * But first we check to see if there's space in the buffer. *  * Again this ignores __MODE__IOTRAN. */size_t fwrite(buf, size, nelm, fp)const void *buf;size_t size;size_t nelm;FILE *fp;{	register int v;	int len;	unsigned bytes, put;#ifdef STUB_FWRITE	bytes = size * nelm;	while (bytes > 0) {		len = write(fp->fd, buf, bytes);		if (len <= 0) {			break;		}		bytes -= len;		buf += len;	}	return nelm;#else	v = fp->mode;	/* If last op was a read ... */	if ((v & __MODE_READING) && fflush(fp))		return 0;	/* Can't write or there's been an EOF or error then return 0 */	if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)		return 0;	/* This could be long, doesn't seem much point tho */	bytes = size * nelm;	len = fp->bufend - fp->bufpos;	/* Flush the buffer if not enough room */	if (bytes > len)		if (fflush(fp))			return 0;	len = fp->bufend - fp->bufpos;	if (bytes <= len) {			/* It'll fit in the buffer ? */		fp->mode |= __MODE_WRITING;		memcpy(fp->bufpos, buf, bytes);		fp->bufpos += bytes;		/* If we're not fully buffered */		if (v & (_IOLBF | _IONBF))			fflush(fp);		return nelm;	} else		/* Too big for the buffer */	{		put = bytes;		do {			len = write(fp->fd, buf, bytes);			if (len > 0) {				buf += len;				bytes -= len;			}		}		while (len > 0 || (len == -1 && errno == EINTR));		if (len < 0)			fp->mode |= __MODE_ERR;		put -= bytes;	}	return put / size;#endif}#endif#ifdef L_rewindvoid rewind(fp)FILE *fp;{	fseek(fp, (long) 0, 0);	clearerr(fp);}#endif#ifdef L_fseekint fseek(fp, offset, ref)FILE *fp;long offset;int ref;{#if 0	/* FIXME: this is broken!  BROKEN!!!! */	/* if __MODE_READING and no ungetc ever done can just move pointer */	/* This needs testing! */	if ((fp->mode & (__MODE_READING | __MODE_UNGOT)) == __MODE_READING &&		(ref == SEEK_SET || ref == SEEK_CUR)) {		long fpos = lseek(fp->fd, 0L, SEEK_CUR);		if (fpos == -1)			return EOF;		if (ref == SEEK_CUR) {			ref = SEEK_SET;			offset = fpos + offset + fp->bufpos - fp->bufread;		}		if (ref == SEEK_SET) {			if (offset < fpos				&& offset >= fpos + fp->bufstart - fp->bufread) {				fp->bufpos = offset - fpos + fp->bufread;				return 0;			}		}	}#endif	/* Use fflush to sync the pointers */	if (fflush(fp) == EOF)		return EOF;	if (lseek(fp->fd, offset, ref) < 0)		return EOF;	return 0;}#endif#ifdef L_ftelllong ftell(fp)FILE *fp;{	if (fflush(fp) == EOF)		return EOF;	return lseek(fp->fd, 0L, SEEK_CUR);}#endif#ifdef L_fopen/* * This Fopen is all three of fopen, fdopen and freopen. The macros in * stdio.h show the other names. */FILE *__fopen(fname, fd, fp, mode)const char *fname;int fd;FILE *fp;const char *mode;{	int open_mode = 0;#if __MODE_IOTRAN	int do_iosense = 1;#endif	int fopen_mode = 0;	FILE *nfp = 0;	/* If we've got an fp close the old one (freopen) */	if (fp) {		/* Careful, don't de-allocate it */		fopen_mode |=			(fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF));		fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF);		fclose(fp);	}	/* decode the new open mode */	while (*mode)		switch (*mode++) {		case 'r':			fopen_mode |= __MODE_READ;			break;		case 'w':			fopen_mode |= __MODE_WRITE;			open_mode = (O_CREAT | O_TRUNC);			break;		case 'a':			fopen_mode |= __MODE_WRITE;			open_mode = (O_CREAT | O_APPEND);			break;		case '+':			fopen_mode |= __MODE_RDWR;			break;#if __MODE_IOTRAN		case 'b':				/* Binary */			fopen_mode &= ~__MODE_IOTRAN;			do_iosense = 0;			break;		case 't':				/* Text */			fopen_mode |= __MODE_IOTRAN;			do_iosense = 0;			break;#endif		}	/* Add in the read/write options to mode for open() */	switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) {	case 0:		return 0;	case __MODE_READ:		open_mode |= O_RDONLY;		break;	case __MODE_WRITE:		open_mode |= O_WRONLY;		break;	default:		open_mode |= O_RDWR;		break;	}	/* Allocate the (FILE) before we do anything irreversable */	if (fp == 0) {		nfp = malloc(sizeof(FILE));		if (nfp == 0)			return 0;	}	/* Open the file itself */	if (fname)		fd = open(fname, open_mode, 0666);	if (fd < 0) {				/* Grrrr */		if (nfp)			free(nfp);		return 0;	}	/* If this isn't freopen create a (FILE) and buffer for it */	if (fp == 0) {		int i;		fp = nfp;		fp->next = __IO_list;		__IO_list = fp;		fp->mode = __MODE_FREEFIL;		if (isatty(fd)) {			fp->mode |= _IOLBF;#if __MODE_IOTRAN			if (do_iosense)				fopen_mode |= __MODE_IOTRAN;#endif		} else			fp->mode |= _IOFBF;		for (i = 0; i < FIXED_BUFFERS; i++)			if (!_fixed_buffers[i].used) {				fp->bufstart = _fixed_buffers[i].data;				_fixed_buffers[i].used = 1;				break;			}		if (i == FIXED_BUFFERS)			fp->bufstart = malloc(BUFSIZ);		if (fp->bufstart == 0) {	/* Oops, no mem *//* Humm, full buffering with a two(!) byte									   * buffer. */			fp->bufstart = fp->unbuf;			fp->bufend = fp->unbuf + sizeof(fp->unbuf);		} else {			fp->bufend = fp->bufstart + BUFSIZ;			fp->mode |= __MODE_FREEBUF;		}	}	/* Ok, file's ready clear the buffer and save important bits */	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;	fp->mode |= fopen_mode;	fp->fd = fd;	return fp;}#endif#ifdef L_fcloseint fclose(fp)FILE *fp;{	int rv = 0;	if (fp == 0) {		errno = EINVAL;		return EOF;	}	if (fflush(fp))		return EOF;	if (close(fp->fd))		rv = EOF;	fp->fd = -1;	if (fp->mode & __MODE_FREEBUF) {		int i;		for (i = 0; i < FIXED_BUFFERS; i++)			if (fp->bufstart == _fixed_buffers[i].data) {				_fixed_buffers[i].used = 0;				break;			}		if (i == FIXED_BUFFERS)			free(fp->bufstart);		fp->mode &= ~__MODE_FREEBUF;		fp->bufstart = fp->bufend = 0;	}	if (fp->mode & __MODE_FREEFIL) {		FILE *prev = 0, *ptr;		fp->mode = 0;		for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next);		if (ptr == fp) {			if (prev == 0)				__IO_list = fp->next;			else				prev->next = fp->next;		}		free(fp);	} else		fp->mode = 0;	return rv;}#endif#ifdef L_setbuffervoid setbuffer(fp, buf, size)FILE *fp;char *buf;int size;{	fflush(fp);	if ((fp->bufstart == (unsigned char *) buf)		&& (fp->bufend == ((unsigned char *) buf + size)))		return;	if (fp->mode & __MODE_FREEBUF) {		int i;		for (i = 0; i < FIXED_BUFFERS; i++)			if (fp->bufstart == _fixed_buffers[i].data) {				_fixed_buffers[i].used = 0;				break;			}		if (i == FIXED_BUFFERS)			free(fp->bufstart);	}	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF);	if (buf == 0) {		fp->bufstart = fp->unbuf;		fp->bufend = fp->unbuf + sizeof(fp->unbuf);		fp->mode |= _IONBF;	} else {		fp->bufstart = buf;		fp->bufend = buf + size;		fp->mode |= _IOFBF;	}	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;}#endif#ifdef L_setvbufint setvbuf(fp, buf, mode, size)FILE *fp;char *buf;int mode;size_t size;{	fflush(fp);	if (fp->mode & __MODE_FREEBUF) {		int i;		for (i = 0; i < FIXED_BUFFERS; i++)			if (fp->bufstart == _fixed_buffers[i].data) {				_fixed_buffers[i].used = 0;				break;			}		if (i == FIXED_BUFFERS)			free(fp->bufstart);	}	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF);	fp->bufstart = fp->unbuf;	fp->bufend = fp->unbuf + sizeof(fp->unbuf);	fp->mode |= _IONBF;	if (mode == _IOFBF || mode == _IOLBF) {		if (size <= 0) {			size = BUFSIZ;		}		if (buf == 0) {			if (size == BUFSIZ) {				int i;				for (i = 0; i < FIXED_BUFFERS; i++)					if (!_fixed_buffers[i].used) {						_fixed_buffers[i].used = 1;						buf = _fixed_buffers[i].data;						break;					}				if (i == FIXED_BUFFERS)					buf = malloc(size);			} else {				buf = malloc(size);			}		}		if (buf == 0)			return EOF;		fp->bufstart = buf;		fp->bufend = buf + size;		fp->mode |= mode;	}	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;	return 0;}#endif#ifdef L_ungetcint ungetc(c, fp)int c;FILE *fp;{	if (fp->mode & __MODE_WRITING)		fflush(fp);	/* Can't read or there's been an error then return EOF */	if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ)		return EOF;	/* Can't do fast fseeks */	fp->mode |= __MODE_UNGOT;	if (fp->bufpos > fp->bufstart)		return *--fp->bufpos = (unsigned char) c;	else if (fp->bufread == fp->bufstart)		return *fp->bufread++ = (unsigned char) c;	else		return EOF;}#endif
 |