⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shf.c

📁 一个开放源代码的 AT&T 的 Korn Shell 的复制品, 支持大多数 ksh89 的特性。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Shell file I/O routines */#include "sh.h"#include "ksh_stat.h"#include "ksh_limval.h"/* flags to shf_emptybuf() */#define EB_READSW	0x01	/* about to switch to reading */#define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) *//* * Replacement stdio routines.  Stdio is too flakey on too many machines * to be useful when you have multiple processes using the same underlying * file descriptors. */static int	shf_fillbuf	ARGS((struct shf *shf));static int	shf_emptybuf	ARGS((struct shf *shf, int flags));/* Open a file.  First three args are for open(), last arg is flags for * this package.  Returns NULL if file could not be opened, or if a dup * fails. */struct shf *shf_open(name, oflags, mode, sflags)	const char *name;	int oflags;	int mode;	int sflags;{	struct shf *shf;	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;	int fd;	/* Done before open so if alloca fails, fd won't be lost. */	shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);	shf->areap = ATEMP;	shf->buf = (unsigned char *) &shf[1];	shf->bsize = bsize;	shf->flags = SHF_ALLOCS;	/* Rest filled in by reopen. */	fd = open(name, oflags, mode);	if (fd < 0) {		afree(shf, shf->areap);		return NULL;	}	if ((sflags & SHF_MAPHI) && fd < FDBASE) {		int nfd;		nfd = ksh_dupbase(fd, FDBASE);		close(fd);		if (nfd < 0) {			afree(shf, shf->areap);			return NULL;		}		fd = nfd;	}	sflags &= ~SHF_ACCMODE;	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD		  : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR		     : SHF_RDWR);	return shf_reopen(fd, sflags, shf);}/* Set up the shf structure for a file descriptor.  Doesn't fail. */struct shf *shf_fdopen(fd, sflags, shf)	int fd;	int sflags;	struct shf *shf;{	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;	/* use fcntl() to figure out correct read/write flags */	if (sflags & SHF_GETFL) {		int flags = fcntl(fd, F_GETFL, 0);		if (flags < 0)			/* will get an error on first read/write */			sflags |= SHF_RDWR;		else			switch (flags & O_ACCMODE) {			case O_RDONLY: sflags |= SHF_RD; break;			case O_WRONLY: sflags |= SHF_WR; break;			case O_RDWR: sflags |= SHF_RDWR; break;			}	}	if (!(sflags & (SHF_RD | SHF_WR)))		internal_errorf(1, "shf_fdopen: missing read/write");	if (shf) {		if (bsize) {			shf->buf = (unsigned char *) alloc(bsize, ATEMP);			sflags |= SHF_ALLOCB;		} else			shf->buf = (unsigned char *) 0;	} else {		shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);		shf->buf = (unsigned char *) &shf[1];		sflags |= SHF_ALLOCS;	}	shf->areap = ATEMP;	shf->fd = fd;	shf->rp = shf->wp = shf->buf;	shf->rnleft = 0;	shf->rbsize = bsize;	shf->wnleft = 0; /* force call to shf_emptybuf() */	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;	shf->flags = sflags;	shf->errno_ = 0;	shf->bsize = bsize;	if (sflags & SHF_CLEXEC)		fd_clexec(fd);	return shf;}/* Set up an existing shf (and buffer) to use the given fd */struct shf *shf_reopen(fd, sflags, shf)	int fd;	int sflags;	struct shf *shf;{	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;	/* use fcntl() to figure out correct read/write flags */	if (sflags & SHF_GETFL) {		int flags = fcntl(fd, F_GETFL, 0);		if (flags < 0)			/* will get an error on first read/write */			sflags |= SHF_RDWR;		else			switch (flags & O_ACCMODE) {			case O_RDONLY: sflags |= SHF_RD; break;			case O_WRONLY: sflags |= SHF_WR; break;			case O_RDWR: sflags |= SHF_RDWR; break;			}	}	if (!(sflags & (SHF_RD | SHF_WR)))		internal_errorf(1, "shf_reopen: missing read/write");	if (!shf || !shf->buf || shf->bsize < bsize)		internal_errorf(1, "shf_reopen: bad shf/buf/bsize");	/* assumes shf->buf and shf->bsize already set up */	shf->fd = fd;	shf->rp = shf->wp = shf->buf;	shf->rnleft = 0;	shf->rbsize = bsize;	shf->wnleft = 0; /* force call to shf_emptybuf() */	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;	shf->errno_ = 0;	if (sflags & SHF_CLEXEC)		fd_clexec(fd);	return shf;}/* Open a string for reading or writing.  If reading, bsize is the number * of bytes that can be read.  If writing, bsize is the maximum number of * bytes that can be written.  If shf is not null, it is filled in and * returned, if it is null, shf is allocated.  If writing and buf is null * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is * used for the initial size).  Doesn't fail. * When writing, a byte is reserved for a trailing null - see shf_sclose(). */struct shf *shf_sopen(buf, bsize, sflags, shf)	char *buf;	int bsize;	int sflags;	struct shf *shf;{	/* can't have a read+write string */	if (!(sflags & (SHF_RD | SHF_WR))	    || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR))		internal_errorf(1, "shf_sopen: flags 0x%x", sflags);	if (!shf) {		shf = (struct shf *) alloc(sizeof(struct shf), ATEMP);		sflags |= SHF_ALLOCS;	}	shf->areap = ATEMP;	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {		if (bsize <= 0)			bsize = 64;		sflags |= SHF_ALLOCB;		buf = alloc(bsize, shf->areap);	}	shf->fd = -1;	shf->buf = shf->rp = shf->wp = (unsigned char *) buf;	shf->rnleft = bsize;	shf->rbsize = bsize;	shf->wnleft = bsize - 1;	/* space for a '\0' */	shf->wbsize = bsize;	shf->flags = sflags | SHF_STRING;	shf->errno_ = 0;	shf->bsize = bsize;	return shf;}/* Flush and close file descriptor, free the shf structure */intshf_close(shf)	struct shf *shf;{	int ret = 0;	if (shf->fd >= 0) {		ret = shf_flush(shf);		if (close(shf->fd) < 0)			ret = EOF;	}	if (shf->flags & SHF_ALLOCS)		afree(shf, shf->areap);	else if (shf->flags & SHF_ALLOCB)		afree(shf->buf, shf->areap);	return ret;}/* Flush and close file descriptor, don't free file structure */intshf_fdclose(shf)	struct shf *shf;{	int ret = 0;	if (shf->fd >= 0) {		ret = shf_flush(shf);		if (close(shf->fd) < 0)			ret = EOF;		shf->rnleft = 0;		shf->rp = shf->buf;		shf->wnleft = 0;		shf->fd = -1;	}	return ret;}/* Close a string - if it was opened for writing, it is null terminated; * returns a pointer to the string and frees shf if it was allocated * (does not free string if it was allocated). */char *shf_sclose(shf)	struct shf *shf;{	unsigned char *s = shf->buf;	/* null terminate */	if (shf->flags & SHF_WR) {		shf->wnleft++;		shf_putc('\0', shf);	}	if (shf->flags & SHF_ALLOCS)		afree(shf, shf->areap);	return (char *) s;}/* Flush and free file structure, don't close file descriptor */intshf_finish(shf)	struct shf *shf;{	int ret = 0;	if (shf->fd >= 0)		ret = shf_flush(shf);	if (shf->flags & SHF_ALLOCS)		afree(shf, shf->areap);	else if (shf->flags & SHF_ALLOCB)		afree(shf->buf, shf->areap);	return ret;}/* Un-read what has been read but not examined, or write what has been * buffered.  Returns 0 for success, EOF for (write) error. */intshf_flush(shf)	struct shf *shf;{	if (shf->flags & SHF_STRING)		return (shf->flags & SHF_WR) ? EOF : 0;	if (shf->fd < 0)		internal_errorf(1, "shf_flush: no fd");	if (shf->flags & SHF_ERROR) {		errno = shf->errno_;		return EOF;	}	if (shf->flags & SHF_READING) {		shf->flags &= ~(SHF_EOF | SHF_READING);		if (shf->rnleft > 0) {			lseek(shf->fd, (off_t) -shf->rnleft, 1);			shf->rnleft = 0;			shf->rp = shf->buf;		}		return 0;	} else if (shf->flags & SHF_WRITING)		return shf_emptybuf(shf, 0);	return 0;}/* Write out any buffered data.  If currently reading, flushes the read * buffer.  Returns 0 for success, EOF for (write) error. */static intshf_emptybuf(shf, flags)	struct shf *shf;	int flags;{	int ret = 0;	if (!(shf->flags & SHF_STRING) && shf->fd < 0)		internal_errorf(1, "shf_emptybuf: no fd");	if (shf->flags & SHF_ERROR) {		errno = shf->errno_;		return EOF;	}	if (shf->flags & SHF_READING) {		if (flags & EB_READSW) /* doesn't happen */			return 0;		ret = shf_flush(shf);		shf->flags &= ~SHF_READING;	}	if (shf->flags & SHF_STRING) {		unsigned char	*nbuf;		/* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB		 * is set... (changing the shf pointer could cause problems)		 */		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC)		    || !(shf->flags & SHF_ALLOCB))			return EOF;		/* allocate more space for buffer */		nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2,						shf->areap);		shf->rp = nbuf + (shf->rp - shf->buf);		shf->wp = nbuf + (shf->wp - shf->buf);		shf->rbsize += shf->wbsize;		shf->wbsize += shf->wbsize;		shf->wnleft += shf->wbsize;		shf->wbsize *= 2;		shf->buf = nbuf;	} else {		if (shf->flags & SHF_WRITING) {			int ntowrite = shf->wp - shf->buf;			unsigned char *buf = shf->buf;			int n;			while (ntowrite > 0) {				n = write(shf->fd, buf, ntowrite);				if (n < 0) {					if (errno == EINTR					    && !(shf->flags & SHF_INTERRUPT))						continue;					shf->flags |= SHF_ERROR;					shf->errno_ = errno;					shf->wnleft = 0;					if (buf != shf->buf) {						/* allow a second flush						 * to work */						memmove(shf->buf, buf,							ntowrite);						shf->wp = shf->buf + ntowrite;					}					return EOF;				}				buf += n;				ntowrite -= n;			}			if (flags & EB_READSW) {				shf->wp = shf->buf;				shf->wnleft = 0;				shf->flags &= ~SHF_WRITING;				return 0;			}		}		shf->wp = shf->buf;		shf->wnleft = shf->wbsize;	}	shf->flags |= SHF_WRITING;	return ret;}/* Fill up a read buffer.  Returns EOF for a read error, 0 otherwise. */static intshf_fillbuf(shf)	struct shf *shf;{	if (shf->flags & SHF_STRING)		return 0;	if (shf->fd < 0)		internal_errorf(1, "shf_fillbuf: no fd");	if (shf->flags & (SHF_EOF | SHF_ERROR)) {		if (shf->flags & SHF_ERROR)			errno = shf->errno_;		return EOF;	}	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)		return EOF;	shf->flags |= SHF_READING;	shf->rp = shf->buf;	while (1) {		shf->rnleft = blocking_read(shf->fd, (char *) shf->buf,					    shf->rbsize);		if (shf->rnleft < 0 && errno == EINTR		    && !(shf->flags & SHF_INTERRUPT))			continue;		break;	}	if (shf->rnleft <= 0) {		if (shf->rnleft < 0) {			shf->flags |= SHF_ERROR;			shf->errno_ = errno;			shf->rnleft = 0;			shf->rp = shf->buf;			return EOF;		}		shf->flags |= SHF_EOF;	}	return 0;}/* Seek to a new position in the file.  If writing, flushes the buffer * first.  If reading, optimizes small relative seeks that stay inside the * buffer.  Returns 0 for success, EOF otherwise. */intshf_seek(shf, where, from)	struct shf *shf;	off_t where;	int from;{	if (shf->fd < 0) {		errno = EINVAL;		return EOF;	}	if (shf->flags & SHF_ERROR) {		errno = shf->errno_;		return EOF;	}	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)		return EOF;	if (shf->flags & SHF_READING) {		if (from == SEEK_CUR &&				(where < 0 ?					-where >= shf->rbsize - shf->rnleft :					where < shf->rnleft)) {			shf->rnleft -= where;			shf->rp += where;			return 0;		}		shf->rnleft = 0;		shf->rp = shf->buf;	}	shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING);	if (lseek(shf->fd, where, from) < 0) {		shf->errno_ = errno;		shf->flags |= SHF_ERROR;		return EOF;	}	return 0;}/* Read a buffer from shf.  Returns the number of bytes read into buf, * if no bytes were read, returns 0 if end of file was seen, EOF if * a read error occurred. */intshf_read(buf, bsize, shf)	char *buf;	int bsize;	struct shf *shf;{	int orig_bsize = bsize;	int ncopy;	if (!(shf->flags & SHF_RD))		internal_errorf(1, "shf_read: flags %x", shf->flags);	if (bsize <= 0)		internal_errorf(1, "shf_read: bsize %d", bsize);	while (bsize > 0) {		if (shf->rnleft == 0		    && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))			break;		ncopy = shf->rnleft;		if (ncopy > bsize)			ncopy = bsize;		memcpy(buf, shf->rp, ncopy);		buf += ncopy;		bsize -= ncopy;		shf->rp += ncopy;		shf->rnleft -= ncopy;	}	/* Note: fread(3S) returns 0 for errors - this doesn't */	return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0)				   : orig_bsize - bsize;}/* Read up to a newline or EOF.  The newline is put in buf; buf is always * null terminated.  Returns NULL on read error or if nothing was read before * end of file, returns a pointer to the null byte in buf otherwise. */char *shf_getse(buf, bsize, shf)	char *buf;	int bsize;	struct shf *shf;{	unsigned char *end;	int ncopy;	char *orig_buf = buf;	if (!(shf->flags & SHF_RD))		internal_errorf(1, "shf_getse: flags %x", shf->flags);	if (bsize <= 0)		return (char *) 0;	--bsize;	/* save room for null */	do {		if (shf->rnleft == 0) {			if (shf_fillbuf(shf) == EOF)				return NULL;			if (shf->rnleft == 0) {				*buf = '\0';				return buf == orig_buf ? NULL : buf;			}		}		end = (unsigned char *) memchr((char *) shf->rp, '\n',					     shf->rnleft);		ncopy = end ? end - shf->rp + 1 : shf->rnleft;		if (ncopy > bsize)			ncopy = bsize;		memcpy(buf, (char *) shf->rp, ncopy);		shf->rp += ncopy;		shf->rnleft -= ncopy;		buf += ncopy;		bsize -= ncopy;#ifdef OS2		if (end && buf > orig_buf + 1 && buf[-2] == '\r') {			buf--;			bsize++;			buf[-1] = '\n';		}#endif	} while (!end && bsize);	*buf = '\0';	return buf;}/* Returns the char read.  Returns EOF for error and end of file. */intshf_getchar(shf)	struct shf *shf;{	if (!(shf->flags & SHF_RD))		internal_errorf(1, "shf_getchar: flags %x", shf->flags);	if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))		return EOF;	--shf->rnleft;	return *shf->rp++;}/* Put a character back in the input stream.  Returns the character if * successful, EOF if there is no room. */intshf_ungetc(c, shf)	int c;	struct shf *shf;{	if (!(shf->flags & SHF_RD))		internal_errorf(1, "shf_ungetc: flags %x", shf->flags);	if ((shf->flags & SHF_ERROR) || c == EOF	    || (shf->rp == shf->buf && shf->rnleft))		return EOF;	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)		return EOF;	if (shf->rp == shf->buf)		shf->rp = shf->buf + shf->rbsize;	if (shf->flags & SHF_STRING) {		/* Can unget what was read, but not something different - we		 * don't want to modify a string.		 */		if (shf->rp[-1] != c)			return EOF;		shf->flags &= ~SHF_EOF;		shf->rp--;		shf->rnleft++;		return c;	}	shf->flags &= ~SHF_EOF;	*--(shf->rp) = c;	shf->rnleft++;	return c;}/* Write a character.  Returns the character if successful, EOF if * the char could not be written. */intshf_putchar(c, shf)	int c;	struct shf *shf;{	if (!(shf->flags & SHF_WR))		internal_errorf(1, "shf_putchar: flags %x", shf->flags);	if (c == EOF)

⌨️ 快捷键说明

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