?? stdio.c
字號:
/* Standard I/O routines with socket support
* Replaces those in Borland C++ library
*/
#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 "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))
long _lseek(int fd,long offset,int whence);
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;
/* 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;
}
/* 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,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(char *fmt,...)
{
va_list args;
int len;
va_start(args,fmt);
len = vfprintf(stdout,fmt,args);
va_end(args);
return len;
}
/* The guts of printf, uses variable arg version of sprintf */
int
vprintf(char *fmt, va_list args)
{
return vfprintf(stdout,fmt,args);
}
/* There's a more efficient version of vfprintf() in vfprintf.c
* that avoids the malloc(BUFSIZ) call by calling the internal
* Borland __vprinter() function directly.
*/
#ifndef __TURBOC__
/* The guts of printf, uses variable arg version of sprintf */
int
vfprintf(FILE *fp,char *fmt, va_list args)
{
int len,cnt,withargs;
char *buf;
if(fp == NULL || fp->cookie != _COOKIE)
return -1;
if(strchr(fmt,'%') == NULL){
/* Common case optimization: no args, so we don't
* need vsprintf()
*/
withargs = 0;
buf = fmt;
} else {
/* Use a default value that is hopefully longer than the
* biggest output string we'll ever print (!)
*/
withargs = 1;
buf = mallocw(BUFSIZ);
vsprintf(buf,fmt,args);
}
len = strlen(buf);
cnt = fwrite(buf,1,len,fp);
if(cnt != len)
cnt = -1;
if(withargs)
free(buf);
return cnt;
}
#endif /* __TURBOC__ */
/* 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 string to standard output */
int
puts(char *s)
{
if(fputs(s,stdout) == EOF)
return EOF;
putchar('\n');
return 1;
}
/* 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){
flushall();
return 0;
}
if(fp->obuf == NULL)
return 0; /* Nothing to do */
bp = fp->obuf;
fp->obuf = NULL;
switch(fp->type){
case _FL_ASY:
while(bp != NULL){
asy_write(fp->fd,bp->data,bp->cnt);
bp = free_mbuf(&bp);
}
return 0;
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;
}
bp = free_mbuf(&bp);
} while(bp != NULL);
return 0;
case _FL_DISPLAY:
do {
displaywrite(fp->ptr,bp->data,bp->cnt);
bp = 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 */
if(fstat(fp->fd,&statbuf) == -1)
return -1; /* "Can't happen" */
fp->offset = statbuf.st_size + offset;
break;
}
/* Toss input buffer */
free_p(&fp->ibuf);
fp->ibuf = NULL;
fp->flags.eof = 0;
return 0;
}
long
ftell(FILE *fp)
{
if(fp == NULL || fp->cookie != _COOKIE || fp->type != _FL_FILE)
return -1;
fflush(fp);
return fp->offset - len_p(fp->ibuf);
}
int
ungetc(int c,FILE *fp)
{
if(fp == NULL || fp->cookie != _COOKIE)
return -1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -