stdio.c

来自「简介:一个tcp/ip协议实现的完整源代码包.包括arp,ax25,icmp,t」· C语言 代码 · 共 1,249 行 · 第 1/2 页

C
1,249
字号
/* Standard I/O routines with socket support
 * Replaces those in Borland C++ library
 * Copyright 1992 Phil Karn, KA9Q
 */
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define __IN_OPEN	1	/* Less stringent open() proto in io.h */
#include <io.h>
#include "global.h"
#include "stdio.h"
#include "mbuf.h"
#include "proc.h"
#include "usock.h"
#include "socket.h"
#include "display.h"
#include "sb.h"
#include "asy.h"

#define	_CREAT(a,b)	creat((a),(b))
#define _OPEN(a,b)	_open((a),(b))
#define	_CLOSE(a)	_close((a))
#define	_READ(a,b,c)	_read((a),(b),(c))
#define	_WRITE(a,b,c)	_write((a),(b),(c))
#define	_LSEEK(a,b,c)	lseek((a),(b),(c))
#define	_DUP(a)		dup((a))

static void _fclose(FILE *fp);
static struct mbuf *_fillbuf(FILE *fp,int cnt);
static FILE *_fcreat(void);

FILE *_Files;
int _clrtmp = 1;
extern unsigned *Refcnt;

/* Defined in format.c */
int _format(void putter(char,void *),void *,const char *,va_list);

/* Open a file and associate it with a (possibly specified) stream */
FILE *
freopen(
char *filename,
char *mode,
FILE *fp
){
	int modef;
	int textmode = 0;
	int create = 0;
	int append = 0;
	int fd;
	struct stat statbuf;

	if(strchr(mode,'r') != NULL){
		modef = O_RDONLY;
	} else if(strchr(mode,'w') != NULL){
		create = 1;
		modef = O_WRONLY;
	} else if(strchr(mode,'a') != NULL){
		modef = O_WRONLY;
		append = 1;
		if(stat(filename,&statbuf) == -1 && errno == ENOENT)
			create = 1;	/* Doesn't exist, so create */
	} else
		return NULL;	/* No recognizable mode! */

	if(strchr(mode,'+') != NULL)
		modef = O_RDWR;	/* Update implies R/W */

	if(strchr(mode,'t') != NULL)
		textmode = 1;
	
	if(create)
		fd = _CREAT(filename,S_IREAD|S_IWRITE);
	else
		fd = _OPEN(filename,modef);
	if(fd == -1)
		return NULL;

	if(fp != NULL){
		_fclose(fp);
	} else {
		if((fp = _fcreat()) == NULL){
			_CLOSE(fd);
			if(create)
				unlink(filename);
			return NULL;
		}
	}
	fp->fd = fd;
	fp->offset = 0;
	fp->type = _FL_FILE;
	fp->bufmode = _IOFBF;
	fp->ptr = strdup(filename);
	fp->flags.ascii = textmode;
	fp->flags.append = append;
	fp->bufsize = BUFSIZ;
	seteol(fp,Eol);
	return fp;
}
/* Associate a file or socket descripter (small integer) with a stream */
FILE *
fdopen(
int handle,
char *mode
){
	FILE *fp;
	int textmode = 0;
	int append = 0;

	if(handle == -1)
		return NULL;

	if(strchr(mode,'a') != NULL)
		append = 1;

	if(strchr(mode,'t') != NULL)
		textmode = 1;
	
	if((fp = _fcreat()) == NULL)
		return NULL;

	fp->fd = handle;
	fp->bufmode = _IOFBF;
	fp->type = _fd_type(handle);
	fp->flags.ascii = textmode;
	fp->flags.append = append;

	fp->bufsize = BUFSIZ;
	/* set default eol sequence, can be overridden by user */
	switch(fp->type){
	case _FL_SOCK:
		seteol(fp,eolseq(handle));	/* Socket eol seq */
		break;
	case _FL_FILE:
		seteol(fp,Eol);	/* System end-of-line sequence */
		break;
	}
	fp->refcnt = 1;

	return fp;
}
/* Create a stream in pipe mode (whatever is written can be
 * read back). These always work in binary mode.
 */
FILE *
pipeopen(void)
{
	FILE *fp;

	if((fp = _fcreat()) == NULL)
		return NULL;

	fp->fd = -1;
	fp->type = _FL_PIPE;
	fp->bufmode = _IOFBF;
	fp->bufsize = BUFSIZ;

	strcpy(fp->eol,"\r\n");
	return fp;
}
/* Open an asynch port for direct I/O. This must have already been attached
 * as a NOS interface. All packet-mode I/O is suspended until this stream
 * is closed.
 */
FILE *
asyopen(
char *name,	/* Name of interface */
char *mode	/* Usual fopen-style mode (used only for text/binary) */
){
	FILE *fp;
	int dev;
	int textmode = 0;

	if((dev = asy_open(name)) == -1)
		return NULL;
	if((fp = _fcreat()) == NULL)
		return NULL;

	if(strchr(mode,'t') != NULL)
		textmode = 1;

	fp->fd = dev;
	fp->type = _FL_ASY;
	fp->bufmode = _IOFBF;
	fp->flags.ascii = textmode;

	fp->bufsize = BUFSIZ;
	strcpy(fp->eol,"\r\n");
	return fp;
}
/* Create a new display screen and associate it with a stream. */
FILE *
displayopen(
char *mode,
int noscrol,
int sfsize
){
	FILE *fp;
	int textmode = 0;

	if(strchr(mode,'t') != NULL)
		textmode = 1;

	if((fp = _fcreat()) == NULL)
		return NULL;

	fp->fd = -1;
	fp->type = _FL_DISPLAY;
	fp->bufmode = _IOFBF;
	fp->flags.ascii = textmode;

	fp->ptr = newdisplay(0,0,noscrol,sfsize);
	fp->bufsize = BUFSIZ;
	strcpy(fp->eol,"\r\n");
	return fp;
}
/* Open the sound card driver on a stream */
FILE *
soundopen()
{
	FILE *fp;

	if((fp = _fcreat()) == NULL)
		return NULL;

	fp->fd = -1;
	fp->type = _FL_SOUND;
	fp->bufmode = _IOFBF;
	fp->flags.ascii = 0;

	fp->bufsize = BUFSIZ;
	return fp;
}

/* Read string from stdin into buf until newline, which is not retained */
char *
gets(char *s)
{
	int c;
	char *cp;

	cp = s;
	for(;;){
		if((c = getc(stdin)) == EOF)
			return NULL;

		if(c == '\n')
			break;

		if(s != NULL)
			*cp++ = c;
	}
	if(s != NULL)
		*cp = '\0';
	return s;
}

/* Read a line from a stream into a buffer, retaining newline */
char *
fgets(
char *buf,	/* User buffer */
int len,	/* Length of buffer */
FILE *fp	/* Input stream */
){
	int c;
	char *cp;

	cp = buf;
	while(len-- > 1){	/* Allow room for the terminal null */
		if((c = getc(fp)) == EOF){
			return NULL;
		}
		if(buf != NULL)
			*cp++ = c;
		if(c == '\n')
			break;
	}
	if(buf != NULL)
		*cp = '\0';
	return buf;
}

/* Do printf on a stream */
int
fprintf(FILE *fp,const char *fmt,...)
{
	va_list args;
	int len;

	va_start(args,fmt);
	len = vfprintf(fp,fmt,args);
	va_end(args);
	return len;
}
/* Printf on standard output stream */
int
printf(const char *fmt,...)
{
	va_list args;
	int len;

	va_start(args,fmt);
	len = vfprintf(stdout,fmt,args);
	va_end(args);
	return len;
}
/* variable arg version of printf */
int
vprintf(const char *fmt, va_list args)
{
	return vfprintf(stdout,fmt,args);
}

static void
putter(char c,void *p)
{
	fputc(c,(FILE *)p);
}

int
vfprintf(FILE *fp,const char *fmt, va_list args)
{
	if(fp == NULL || fp->cookie != _COOKIE)
		return -1;
	return _format(putter,(void *)fp,fmt, args);
}

static void
sputter(char c,void *p)
{
	char **cpp;

	cpp = (char **)p;
	*(*cpp)++ = c;
}

int
vsprintf(char *s,const char *fmt,va_list args)
{
	int r;
	r = _format(sputter,(void *)&s,fmt,args);
	*s = '\0';
	return r;
}
int
sprintf(char *s,const char *fmt,...)
{
	va_list args;
	int len;

	va_start(args,fmt);
	len = vsprintf(s,fmt,args);
	va_end(args);
	return len;
}

/* put a char to a stream */ 
int
fputc(int c,FILE *fp)
{
	int nbytes;
	struct mbuf *bp;
	int eol;

	if(c == '\n' && fp->flags.ascii){
		nbytes = strlen(fp->eol);
		eol = 1;
	} else {
		nbytes = 1;
		eol = 0;
	}
	bp = fp->obuf;
	if(bp != NULL && bp->size - bp->cnt < nbytes && fflush(fp) == EOF)
		return EOF;
	if(fp->obuf == NULL)
		fp->obuf = ambufw(max(nbytes,fp->bufsize));

	bp = fp->obuf;
	if(eol)
		memcpy(&bp->data[bp->cnt],fp->eol,nbytes);
	else
		bp->data[bp->cnt] = c;
	bp->cnt += nbytes;

	if(bp->cnt == bp->size || (fp->bufmode == _IONBF)
	 || ((fp->bufmode == _IOLBF) && eol)){
		if(fflush(fp) == EOF)
			return EOF;
	}
	return c;
}
/* put a string to a stream */
int
fputs(char *buf,FILE *fp)
{
	int cnt,len;

	len = strlen(buf);
	cnt = fwrite(buf,1,len,fp);
	if(cnt != len)
		return EOF;
	return buf[len-1];
}
/* put a short to a stream in native order */
int
putshort(short c,FILE *fp)
{
	return fwrite(&c,2,1,fp);
}
/* Get a short from a stream in native order */
int
getshort(FILE *fp)
{
	unsigned short c;

	if(fread(&c,2,1,fp) == 0)
		return -1;
	return c;
}

/* Put a string to standard output */
int
puts(char *s)
{
	if(fputs(s,stdout) == EOF)
		return EOF;
	putchar('\n');
	return 1;
}

/* Return a conservative estimate of the bytes ready to be read */
int
frrdy(FILE *fp)
{
	/* Just return the bytes on the stdio input buffer */
	if(fp->ibuf != NULL)
		return len_p(fp->ibuf);
	return 0;
}

/* Read a character from the stream */
int
fgetc(FILE *fp)
{
	int c;

	if(fp == NULL || fp->cookie != _COOKIE)
		return EOF;
	c = _fgetc(fp);
	if(!fp->flags.ascii || c == EOF || c != fp->eol[0])
		return c;
	/* First char of newline sequence encountered */
	if(fp->eol[1] == '\0')
		return '\n';	/* Translate 1-char eol sequence */
	/* Try to read next input character */
	if((c = _fgetc(fp)) == EOF)
		return fp->eol[0];	/* Got a better idea? */
	if(c == fp->eol[1]){
		/* Translate two-character eol sequence into newline */
		return '\n';
	} else {
		/* CR-NUL sequence on Internet -> bare CR (kludge?) */
		if(c != '\0')
			ungetc(c,fp);
		/* Otherwise return first char unchanged */
		return fp->eol[0];
	}
}
/* Read a character from a stream without newline processing */
int
_fgetc(FILE *fp)
{
	struct mbuf *bp;

	if(fp == NULL || fp->cookie != _COOKIE)
		return EOF;
	fflush(fp);
	if((bp = fp->ibuf) == NULL || bp->cnt == 0)
		if(_fillbuf(fp,1) == NULL)
			return EOF;
	if(fp->type == _FL_PIPE)
		ksignal(&fp->obuf,1);
	return PULLCHAR(&fp->ibuf);
}

/* Flush output on a stream. All actual output is done here. */
int
fflush(FILE *fp)
{
	struct mbuf *bp;
	int cnt;

	if(fp == NULL || fp->cookie != _COOKIE || fp->obuf == NULL)
		return 0;

	bp = fp->obuf;
	fp->obuf = NULL;
	switch(fp->type){
	case _FL_SOUND:
		return sb_send(&bp);
	case _FL_ASY:
		return asy_send(fp->fd,&bp);
	case _FL_PIPE:
		append(&fp->ibuf,&bp);
		ksignal(&fp->ibuf,1);
		while(len_p(fp->ibuf) >= BUFSIZ)
			kwait(&fp->obuf);	/* Hold at hiwat mark */	
		return 0;
	case _FL_SOCK:
		return send_mbuf(fp->fd,&bp,0,NULL,0);
	case _FL_FILE:
		do {
			if(fp->flags.append)
				_LSEEK(fp->fd,0L,SEEK_END);
			else
				_LSEEK(fp->fd,fp->offset,SEEK_SET);
			cnt = _WRITE(fp->fd,bp->data,bp->cnt);
			if(cnt > 0)
				fp->offset += cnt;
			if(cnt != bp->cnt){
				fp->flags.err = 1;
				free_p(&bp);
				return EOF;
			}
			free_mbuf(&bp);
		} while(bp != NULL);
		return 0;
	case _FL_DISPLAY:
		do {
			displaywrite(fp->ptr,bp->data,bp->cnt);
			free_mbuf(&bp);
		} while(bp != NULL);
		return 0;
	}
	return 0;	/* Can't happen */
}

/* Set the end-of-line sequence on a stream */
int
seteol(FILE *fp,char *seq)
{
	if(fp == NULL || fp->cookie != _COOKIE)
		return -1;
	if(seq != NULL)
		strncpy(fp->eol,seq,sizeof(fp->eol));
	else
		*fp->eol = '\0';
	return 0;
}
/* Enable/disable eol translation, return previous state */
int
fmode(FILE *fp,int mode)
{
	int prev;

	if(fp == NULL || fp->cookie != _COOKIE)
		return -1;
	fflush(fp);
	prev = fp->flags.ascii;
	fp->flags.ascii = mode;
	return prev;
}
/* Control blocking behavior for fread on network, pipe and asy streams */
int
fblock(FILE *fp,int mode)
{
	int prev;

	if(fp == NULL || fp->cookie != _COOKIE)
		return -1;
	prev = fp->flags.partread;
	fp->flags.partread = mode;
	return prev;
}

int
fclose(FILE *fp)
{
	if(fp == NULL || fp->cookie != _COOKIE){
		return -1;
	}
	if(--fp->refcnt != 0)
		return 0;	/* Others are still using it */
	_fclose(fp);
	if(fp->prev != NULL)
		fp->prev->next = fp->next;
	else
		_Files = fp->next;

	if(fp->next != NULL)
		fp->next->prev = fp->prev;
	free(fp);
	return 0;
}
int
fseek(
FILE *fp,
long offset,
int whence
){
	struct stat statbuf;

	if(fp == NULL || fp->cookie != _COOKIE || fp->type != _FL_FILE){
		errno = EINVAL;
		return -1;
	}
	/* Optimize for do-nothing seek */ 
#ifdef	notdef
	if(whence == SEEK_SET && fp->offset == offset)
		return 0;
#endif
	fflush(fp);	/* Flush output buffer */
	/* On relative seeks, adjust for data in input buffer */
	switch(whence){
	case SEEK_SET:
		fp->offset = offset;	/* Absolute seek */
		break;
	case SEEK_CUR:
		/* Relative seek, adjusting for buffered data */
		fp->offset += offset - len_p(fp->ibuf);
		break;
	case SEEK_END:
		/* Find out how big the file currently is */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?