Blame shf.c

Packit Service 95ac19
/*	$OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $	*/
Packit Service 95ac19
Packit Service 95ac19
/*-
Packit Service 95ac19
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
Packit Service 95ac19
 *		 2012, 2013, 2015, 2016, 2017, 2018
Packit Service 95ac19
 *	mirabilos <m@mirbsd.org>
Packit Service 95ac19
 * Copyright (c) 2015
Packit Service 95ac19
 *	Daniel Richard G. <skunk@iSKUNK.ORG>
Packit Service 95ac19
 *
Packit Service 95ac19
 * Provided that these terms and disclaimer and all copyright notices
Packit Service 95ac19
 * are retained or reproduced in an accompanying document, permission
Packit Service 95ac19
 * is granted to deal in this work without restriction, including un-
Packit Service 95ac19
 * limited rights to use, publicly perform, distribute, sell, modify,
Packit Service 95ac19
 * merge, give away, or sublicence.
Packit Service 95ac19
 *
Packit Service 95ac19
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
Packit Service 95ac19
 * the utmost extent permitted by applicable law, neither express nor
Packit Service 95ac19
 * implied; without malicious intent or gross negligence. In no event
Packit Service 95ac19
 * may a licensor, author or contributor be held liable for indirect,
Packit Service 95ac19
 * direct, other damage, loss, or other issues arising in any way out
Packit Service 95ac19
 * of dealing in the work, even if advised of the possibility of such
Packit Service 95ac19
 * damage or existence of a defect, except proven that it results out
Packit Service 95ac19
 * of said person's immediate fault when using the work as intended.
Packit Service 95ac19
 *-
Packit Service 95ac19
 * Use %zX instead of %p and floating point isn't supported at all.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#include "sh.h"
Packit Service 95ac19
Packit Service 95ac19
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.97 2018/01/14 01:28:16 tg Exp $");
Packit Service 95ac19
Packit Service 95ac19
/* flags to shf_emptybuf() */
Packit Service 95ac19
#define EB_READSW	0x01	/* about to switch to reading */
Packit Service 95ac19
#define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Replacement stdio routines. Stdio is too flakey on too many machines
Packit Service 95ac19
 * to be useful when you have multiple processes using the same underlying
Packit Service 95ac19
 * file descriptors.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
static int shf_fillbuf(struct shf *);
Packit Service 95ac19
static int shf_emptybuf(struct shf *, int);
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Open a file. First three args are for open(), last arg is flags for
Packit Service 95ac19
 * this package. Returns NULL if file could not be opened, or if a dup
Packit Service 95ac19
 * fails.
Packit Service 95ac19
 */
Packit Service 95ac19
struct shf *
Packit Service 95ac19
shf_open(const char *name, int oflags, int mode, int sflags)
Packit Service 95ac19
{
Packit Service 95ac19
	struct shf *shf;
Packit Service 95ac19
	ssize_t bsize =
Packit Service 95ac19
	    /* at most 512 */
Packit Service 95ac19
	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
Packit Service 95ac19
	int fd, eno;
Packit Service 95ac19
Packit Service 95ac19
	/* Done before open so if alloca fails, fd won't be lost. */
Packit Service 95ac19
	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
Packit Service 95ac19
	shf->areap = ATEMP;
Packit Service 95ac19
	shf->buf = (unsigned char *)&shf[1];
Packit Service 95ac19
	shf->bsize = bsize;
Packit Service 95ac19
	shf->flags = SHF_ALLOCS;
Packit Service 95ac19
	/* Rest filled in by reopen. */
Packit Service 95ac19
Packit Service 95ac19
	fd = binopen3(name, oflags, mode);
Packit Service 95ac19
	if (fd < 0) {
Packit Service 95ac19
		eno = errno;
Packit Service 95ac19
		afree(shf, shf->areap);
Packit Service 95ac19
		errno = eno;
Packit Service 95ac19
		return (NULL);
Packit Service 95ac19
	}
Packit Service 95ac19
	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
Packit Service 95ac19
		int nfd;
Packit Service 95ac19
Packit Service 95ac19
		nfd = fcntl(fd, F_DUPFD, FDBASE);
Packit Service 95ac19
		eno = errno;
Packit Service 95ac19
		close(fd);
Packit Service 95ac19
		if (nfd < 0) {
Packit Service 95ac19
			afree(shf, shf->areap);
Packit Service 95ac19
			errno = eno;
Packit Service 95ac19
			return (NULL);
Packit Service 95ac19
		}
Packit Service 95ac19
		fd = nfd;
Packit Service 95ac19
	}
Packit Service 95ac19
	sflags &= ~SHF_ACCMODE;
Packit Service 95ac19
	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD :
Packit Service 95ac19
	    ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR);
Packit Service 95ac19
Packit Service 95ac19
	return (shf_reopen(fd, sflags, shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* helper function for shf_fdopen and shf_reopen */
Packit Service 95ac19
static void
Packit Service 95ac19
shf_open_hlp(int fd, int *sflagsp, const char *where)
Packit Service 95ac19
{
Packit Service 95ac19
	int sflags = *sflagsp;
Packit Service 95ac19
Packit Service 95ac19
	/* use fcntl() to figure out correct read/write flags */
Packit Service 95ac19
	if (sflags & SHF_GETFL) {
Packit Service 95ac19
		int flags = fcntl(fd, F_GETFL, 0);
Packit Service 95ac19
Packit Service 95ac19
		if (flags < 0)
Packit Service 95ac19
			/* will get an error on first read/write */
Packit Service 95ac19
			sflags |= SHF_RDWR;
Packit Service 95ac19
		else {
Packit Service 95ac19
			switch (flags & O_ACCMODE) {
Packit Service 95ac19
			case O_RDONLY:
Packit Service 95ac19
				sflags |= SHF_RD;
Packit Service 95ac19
				break;
Packit Service 95ac19
			case O_WRONLY:
Packit Service 95ac19
				sflags |= SHF_WR;
Packit Service 95ac19
				break;
Packit Service 95ac19
			case O_RDWR:
Packit Service 95ac19
				sflags |= SHF_RDWR;
Packit Service 95ac19
				break;
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		*sflagsp = sflags;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (!(sflags & (SHF_RD | SHF_WR)))
Packit Service 95ac19
		internal_errorf(Tf_sD_s, where, "missing read/write");
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Set up the shf structure for a file descriptor. Doesn't fail. */
Packit Service 95ac19
struct shf *
Packit Service 95ac19
shf_fdopen(int fd, int sflags, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	ssize_t bsize =
Packit Service 95ac19
	    /* at most 512 */
Packit Service 95ac19
	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
Packit Service 95ac19
Packit Service 95ac19
	shf_open_hlp(fd, &sflags, "shf_fdopen");
Packit Service 95ac19
	if (shf) {
Packit Service 95ac19
		if (bsize) {
Packit Service 95ac19
			shf->buf = alloc(bsize, ATEMP);
Packit Service 95ac19
			sflags |= SHF_ALLOCB;
Packit Service 95ac19
		} else
Packit Service 95ac19
			shf->buf = NULL;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
Packit Service 95ac19
		shf->buf = (unsigned char *)&shf[1];
Packit Service 95ac19
		sflags |= SHF_ALLOCS;
Packit Service 95ac19
	}
Packit Service 95ac19
	shf->areap = ATEMP;
Packit Service 95ac19
	shf->fd = fd;
Packit Service 95ac19
	shf->rp = shf->wp = shf->buf;
Packit Service 95ac19
	shf->rnleft = 0;
Packit Service 95ac19
	shf->rbsize = bsize;
Packit Service 95ac19
	shf->wnleft = 0; /* force call to shf_emptybuf() */
Packit Service 95ac19
	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
Packit Service 95ac19
	shf->flags = sflags;
Packit Service 95ac19
	shf->errnosv = 0;
Packit Service 95ac19
	shf->bsize = bsize;
Packit Service 95ac19
	if (sflags & SHF_CLEXEC)
Packit Service 95ac19
		fcntl(fd, F_SETFD, FD_CLOEXEC);
Packit Service 95ac19
	return (shf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Set up an existing shf (and buffer) to use the given fd */
Packit Service 95ac19
struct shf *
Packit Service 95ac19
shf_reopen(int fd, int sflags, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	ssize_t bsize =
Packit Service 95ac19
	    /* at most 512 */
Packit Service 95ac19
	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
Packit Service 95ac19
Packit Service 95ac19
	shf_open_hlp(fd, &sflags, "shf_reopen");
Packit Service 95ac19
	if (!shf || !shf->buf || shf->bsize < bsize)
Packit Service 95ac19
		internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
Packit Service 95ac19
Packit Service 95ac19
	/* assumes shf->buf and shf->bsize already set up */
Packit Service 95ac19
	shf->fd = fd;
Packit Service 95ac19
	shf->rp = shf->wp = shf->buf;
Packit Service 95ac19
	shf->rnleft = 0;
Packit Service 95ac19
	shf->rbsize = bsize;
Packit Service 95ac19
	shf->wnleft = 0; /* force call to shf_emptybuf() */
Packit Service 95ac19
	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
Packit Service 95ac19
	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
Packit Service 95ac19
	shf->errnosv = 0;
Packit Service 95ac19
	if (sflags & SHF_CLEXEC)
Packit Service 95ac19
		fcntl(fd, F_SETFD, FD_CLOEXEC);
Packit Service 95ac19
	return (shf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Open a string for reading or writing. If reading, bsize is the number
Packit Service 95ac19
 * of bytes that can be read. If writing, bsize is the maximum number of
Packit Service 95ac19
 * bytes that can be written. If shf is not NULL, it is filled in and
Packit Service 95ac19
 * returned, if it is NULL, shf is allocated. If writing and buf is NULL
Packit Service 95ac19
 * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
Packit Service 95ac19
 * used for the initial size). Doesn't fail.
Packit Service 95ac19
 * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
Packit Service 95ac19
 */
Packit Service 95ac19
struct shf *
Packit Service 95ac19
shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	/* can't have a read+write string */
Packit Service 95ac19
	if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
Packit Service 95ac19
		internal_errorf(Tf_flags, "shf_sopen",
Packit Service 95ac19
		    (unsigned int)sflags);
Packit Service 95ac19
Packit Service 95ac19
	if (!shf) {
Packit Service 95ac19
		shf = alloc(sizeof(struct shf), ATEMP);
Packit Service 95ac19
		sflags |= SHF_ALLOCS;
Packit Service 95ac19
	}
Packit Service 95ac19
	shf->areap = ATEMP;
Packit Service 95ac19
	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
Packit Service 95ac19
		if (bsize <= 0)
Packit Service 95ac19
			bsize = 64;
Packit Service 95ac19
		sflags |= SHF_ALLOCB;
Packit Service 95ac19
		buf = alloc(bsize, shf->areap);
Packit Service 95ac19
	}
Packit Service 95ac19
	shf->fd = -1;
Packit Service 95ac19
	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
Packit Service 95ac19
	shf->rnleft = bsize;
Packit Service 95ac19
	shf->rbsize = bsize;
Packit Service 95ac19
	shf->wnleft = bsize - 1;	/* space for a '\0' */
Packit Service 95ac19
	shf->wbsize = bsize;
Packit Service 95ac19
	shf->flags = sflags | SHF_STRING;
Packit Service 95ac19
	shf->errnosv = 0;
Packit Service 95ac19
	shf->bsize = bsize;
Packit Service 95ac19
Packit Service 95ac19
	return (shf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Flush and close file descriptor, free the shf structure */
Packit Service 95ac19
int
Packit Service 95ac19
shf_close(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	int ret = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (shf->fd >= 0) {
Packit Service 95ac19
		ret = shf_flush(shf);
Packit Service 95ac19
		if (close(shf->fd) < 0)
Packit Service 95ac19
			ret = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (shf->flags & SHF_ALLOCS)
Packit Service 95ac19
		afree(shf, shf->areap);
Packit Service 95ac19
	else if (shf->flags & SHF_ALLOCB)
Packit Service 95ac19
		afree(shf->buf, shf->areap);
Packit Service 95ac19
Packit Service 95ac19
	return (ret);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Flush and close file descriptor, don't free file structure */
Packit Service 95ac19
int
Packit Service 95ac19
shf_fdclose(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	int ret = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (shf->fd >= 0) {
Packit Service 95ac19
		ret = shf_flush(shf);
Packit Service 95ac19
		if (close(shf->fd) < 0)
Packit Service 95ac19
			ret = -1;
Packit Service 95ac19
		shf->rnleft = 0;
Packit Service 95ac19
		shf->rp = shf->buf;
Packit Service 95ac19
		shf->wnleft = 0;
Packit Service 95ac19
		shf->fd = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	return (ret);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Close a string - if it was opened for writing, it is NUL terminated;
Packit Service 95ac19
 * returns a pointer to the string and frees shf if it was allocated
Packit Service 95ac19
 * (does not free string if it was allocated).
Packit Service 95ac19
 */
Packit Service 95ac19
char *
Packit Service 95ac19
shf_sclose(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	unsigned char *s = shf->buf;
Packit Service 95ac19
Packit Service 95ac19
	/* NUL terminate */
Packit Service 95ac19
	if (shf->flags & SHF_WR) {
Packit Service 95ac19
		shf->wnleft++;
Packit Service 95ac19
		shf_putc('\0', shf);
Packit Service 95ac19
	}
Packit Service 95ac19
	if (shf->flags & SHF_ALLOCS)
Packit Service 95ac19
		afree(shf, shf->areap);
Packit Service 95ac19
	return ((char *)s);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Un-read what has been read but not examined, or write what has been
Packit Service 95ac19
 * buffered. Returns 0 for success, -1 for (write) error.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
shf_flush(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	int rv = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & SHF_STRING)
Packit Service 95ac19
		rv = (shf->flags & SHF_WR) ? -1 : 0;
Packit Service 95ac19
	else if (shf->fd < 0)
Packit Service 95ac19
		internal_errorf(Tf_sD_s, "shf_flush", "no fd");
Packit Service 95ac19
	else if (shf->flags & SHF_ERROR) {
Packit Service 95ac19
		errno = shf->errnosv;
Packit Service 95ac19
		rv = -1;
Packit Service 95ac19
	} else if (shf->flags & SHF_READING) {
Packit Service 95ac19
		shf->flags &= ~(SHF_EOF | SHF_READING);
Packit Service 95ac19
		if (shf->rnleft > 0) {
Packit Service 95ac19
			if (lseek(shf->fd, (off_t)-shf->rnleft,
Packit Service 95ac19
			    SEEK_CUR) == -1) {
Packit Service 95ac19
				shf->flags |= SHF_ERROR;
Packit Service 95ac19
				shf->errnosv = errno;
Packit Service 95ac19
				rv = -1;
Packit Service 95ac19
			}
Packit Service 95ac19
			shf->rnleft = 0;
Packit Service 95ac19
			shf->rp = shf->buf;
Packit Service 95ac19
		}
Packit Service 95ac19
	} else if (shf->flags & SHF_WRITING)
Packit Service 95ac19
		rv = shf_emptybuf(shf, 0);
Packit Service 95ac19
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Write out any buffered data. If currently reading, flushes the read
Packit Service 95ac19
 * buffer. Returns 0 for success, -1 for (write) error.
Packit Service 95ac19
 */
Packit Service 95ac19
static int
Packit Service 95ac19
shf_emptybuf(struct shf *shf, int flags)
Packit Service 95ac19
{
Packit Service 95ac19
	int ret = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
Packit Service 95ac19
		internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & SHF_ERROR) {
Packit Service 95ac19
		errno = shf->errnosv;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & SHF_READING) {
Packit Service 95ac19
		if (flags & EB_READSW)
Packit Service 95ac19
			/* doesn't happen */
Packit Service 95ac19
			return (0);
Packit Service 95ac19
		ret = shf_flush(shf);
Packit Service 95ac19
		shf->flags &= ~SHF_READING;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (shf->flags & SHF_STRING) {
Packit Service 95ac19
		unsigned char *nbuf;
Packit Service 95ac19
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * Note that we assume SHF_ALLOCS is not set if
Packit Service 95ac19
		 * SHF_ALLOCB is set... (changing the shf pointer could
Packit Service 95ac19
		 * cause problems)
Packit Service 95ac19
		 */
Packit Service 95ac19
		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
Packit Service 95ac19
		    !(shf->flags & SHF_ALLOCB))
Packit Service 95ac19
			return (-1);
Packit Service 95ac19
		/* allocate more space for buffer */
Packit Service 95ac19
		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
Packit Service 95ac19
		shf->rp = nbuf + (shf->rp - shf->buf);
Packit Service 95ac19
		shf->wp = nbuf + (shf->wp - shf->buf);
Packit Service 95ac19
		shf->rbsize += shf->wbsize;
Packit Service 95ac19
		shf->wnleft += shf->wbsize;
Packit Service 95ac19
		shf->wbsize <<= 1;
Packit Service 95ac19
		shf->buf = nbuf;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		if (shf->flags & SHF_WRITING) {
Packit Service 95ac19
			ssize_t n, ntowrite = shf->wp - shf->buf;
Packit Service 95ac19
			unsigned char *buf = shf->buf;
Packit Service 95ac19
Packit Service 95ac19
			while (ntowrite > 0) {
Packit Service 95ac19
				n = write(shf->fd, buf, ntowrite);
Packit Service 95ac19
				if (n < 0) {
Packit Service 95ac19
					if (errno == EINTR &&
Packit Service 95ac19
					    !(shf->flags & SHF_INTERRUPT))
Packit Service 95ac19
						continue;
Packit Service 95ac19
					shf->flags |= SHF_ERROR;
Packit Service 95ac19
					shf->errnosv = errno;
Packit Service 95ac19
					shf->wnleft = 0;
Packit Service 95ac19
					if (buf != shf->buf) {
Packit Service 95ac19
						/*
Packit Service 95ac19
						 * allow a second flush
Packit Service 95ac19
						 * to work
Packit Service 95ac19
						 */
Packit Service 95ac19
						memmove(shf->buf, buf,
Packit Service 95ac19
						    ntowrite);
Packit Service 95ac19
						shf->wp = shf->buf + ntowrite;
Packit Service 95ac19
					}
Packit Service 95ac19
					return (-1);
Packit Service 95ac19
				}
Packit Service 95ac19
				buf += n;
Packit Service 95ac19
				ntowrite -= n;
Packit Service 95ac19
			}
Packit Service 95ac19
			if (flags & EB_READSW) {
Packit Service 95ac19
				shf->wp = shf->buf;
Packit Service 95ac19
				shf->wnleft = 0;
Packit Service 95ac19
				shf->flags &= ~SHF_WRITING;
Packit Service 95ac19
				return (0);
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		shf->wp = shf->buf;
Packit Service 95ac19
		shf->wnleft = shf->wbsize;
Packit Service 95ac19
	}
Packit Service 95ac19
	shf->flags |= SHF_WRITING;
Packit Service 95ac19
Packit Service 95ac19
	return (ret);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */
Packit Service 95ac19
static int
Packit Service 95ac19
shf_fillbuf(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	ssize_t n;
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & SHF_STRING)
Packit Service 95ac19
		return (0);
Packit Service 95ac19
Packit Service 95ac19
	if (shf->fd < 0)
Packit Service 95ac19
		internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
Packit Service 95ac19
		if (shf->flags & SHF_ERROR)
Packit Service 95ac19
			errno = shf->errnosv;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	shf->flags |= SHF_READING;
Packit Service 95ac19
Packit Service 95ac19
	shf->rp = shf->buf;
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
Packit Service 95ac19
		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
Packit Service 95ac19
			continue;
Packit Service 95ac19
		break;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (n < 0) {
Packit Service 95ac19
		shf->flags |= SHF_ERROR;
Packit Service 95ac19
		shf->errnosv = errno;
Packit Service 95ac19
		shf->rnleft = 0;
Packit Service 95ac19
		shf->rp = shf->buf;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
	if ((shf->rnleft = n) == 0)
Packit Service 95ac19
		shf->flags |= SHF_EOF;
Packit Service 95ac19
	return (0);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Read a buffer from shf. Returns the number of bytes read into buf, if
Packit Service 95ac19
 * no bytes were read, returns 0 if end of file was seen, -1 if a read
Packit Service 95ac19
 * error occurred.
Packit Service 95ac19
 */
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_read(char *buf, ssize_t bsize, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	ssize_t ncopy, orig_bsize = bsize;
Packit Service 95ac19
Packit Service 95ac19
	if (!(shf->flags & SHF_RD))
Packit Service 95ac19
		internal_errorf(Tf_flags, Tshf_read,
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if (bsize <= 0)
Packit Service 95ac19
		internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
Packit Service 95ac19
Packit Service 95ac19
	while (bsize > 0) {
Packit Service 95ac19
		if (shf->rnleft == 0 &&
Packit Service 95ac19
		    (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
Packit Service 95ac19
			break;
Packit Service 95ac19
		ncopy = shf->rnleft;
Packit Service 95ac19
		if (ncopy > bsize)
Packit Service 95ac19
			ncopy = bsize;
Packit Service 95ac19
		memcpy(buf, shf->rp, ncopy);
Packit Service 95ac19
		buf += ncopy;
Packit Service 95ac19
		bsize -= ncopy;
Packit Service 95ac19
		shf->rp += ncopy;
Packit Service 95ac19
		shf->rnleft -= ncopy;
Packit Service 95ac19
	}
Packit Service 95ac19
	/* Note: fread(3S) returns 0 for errors - this doesn't */
Packit Service 95ac19
	return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) :
Packit Service 95ac19
	    orig_bsize - bsize);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Read up to a newline or -1. The newline is put in buf; buf is always
Packit Service 95ac19
 * NUL terminated. Returns NULL on read error or if nothing was read
Packit Service 95ac19
 * before end of file, returns a pointer to the NUL byte in buf
Packit Service 95ac19
 * otherwise.
Packit Service 95ac19
 */
Packit Service 95ac19
char *
Packit Service 95ac19
shf_getse(char *buf, ssize_t bsize, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	unsigned char *end;
Packit Service 95ac19
	ssize_t ncopy;
Packit Service 95ac19
	char *orig_buf = buf;
Packit Service 95ac19
Packit Service 95ac19
	if (!(shf->flags & SHF_RD))
Packit Service 95ac19
		internal_errorf(Tf_flags, "shf_getse",
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if (bsize <= 0)
Packit Service 95ac19
		return (NULL);
Packit Service 95ac19
Packit Service 95ac19
	/* save room for NUL */
Packit Service 95ac19
	--bsize;
Packit Service 95ac19
	do {
Packit Service 95ac19
		if (shf->rnleft == 0) {
Packit Service 95ac19
			if (shf_fillbuf(shf) == -1)
Packit Service 95ac19
				return (NULL);
Packit Service 95ac19
			if (shf->rnleft == 0) {
Packit Service 95ac19
				*buf = '\0';
Packit Service 95ac19
				return (buf == orig_buf ? NULL : buf);
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		end = (unsigned char *)memchr((char *)shf->rp, '\n',
Packit Service 95ac19
		    shf->rnleft);
Packit Service 95ac19
		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
Packit Service 95ac19
		if (ncopy > bsize)
Packit Service 95ac19
			ncopy = bsize;
Packit Service 95ac19
		memcpy(buf, (char *) shf->rp, ncopy);
Packit Service 95ac19
		shf->rp += ncopy;
Packit Service 95ac19
		shf->rnleft -= ncopy;
Packit Service 95ac19
		buf += ncopy;
Packit Service 95ac19
		bsize -= ncopy;
Packit Service 95ac19
#ifdef MKSH_WITH_TEXTMODE
Packit Service 95ac19
		if (end && buf > orig_buf + 1 && buf[-2] == '\r') {
Packit Service 95ac19
			buf--;
Packit Service 95ac19
			bsize++;
Packit Service 95ac19
			buf[-1] = '\n';
Packit Service 95ac19
		}
Packit Service 95ac19
#endif
Packit Service 95ac19
	} while (!end && bsize);
Packit Service 95ac19
#ifdef MKSH_WITH_TEXTMODE
Packit Service 95ac19
	if (!bsize && buf[-1] == '\r') {
Packit Service 95ac19
		int c = shf_getc(shf);
Packit Service 95ac19
		if (c == '\n')
Packit Service 95ac19
			buf[-1] = '\n';
Packit Service 95ac19
		else if (c != -1)
Packit Service 95ac19
			shf_ungetc(c, shf);
Packit Service 95ac19
	}
Packit Service 95ac19
#endif
Packit Service 95ac19
	*buf = '\0';
Packit Service 95ac19
	return (buf);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Returns the char read. Returns -1 for error and end of file. */
Packit Service 95ac19
int
Packit Service 95ac19
shf_getchar(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	if (!(shf->flags & SHF_RD))
Packit Service 95ac19
		internal_errorf(Tf_flags, "shf_getchar",
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	--shf->rnleft;
Packit Service 95ac19
	return (ord(*shf->rp++));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Put a character back in the input stream. Returns the character if
Packit Service 95ac19
 * successful, -1 if there is no room.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
shf_ungetc(int c, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	if (!(shf->flags & SHF_RD))
Packit Service 95ac19
		internal_errorf(Tf_flags, "shf_ungetc",
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if ((shf->flags & SHF_ERROR) || c == -1 ||
Packit Service 95ac19
	    (shf->rp == shf->buf && shf->rnleft))
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	if (shf->rp == shf->buf)
Packit Service 95ac19
		shf->rp = shf->buf + shf->rbsize;
Packit Service 95ac19
	if (shf->flags & SHF_STRING) {
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * Can unget what was read, but not something different;
Packit Service 95ac19
		 * we don't want to modify a string.
Packit Service 95ac19
		 */
Packit Service 95ac19
		if ((int)(shf->rp[-1]) != c)
Packit Service 95ac19
			return (-1);
Packit Service 95ac19
		shf->flags &= ~SHF_EOF;
Packit Service 95ac19
		shf->rp--;
Packit Service 95ac19
		shf->rnleft++;
Packit Service 95ac19
		return (c);
Packit Service 95ac19
	}
Packit Service 95ac19
	shf->flags &= ~SHF_EOF;
Packit Service 95ac19
	*--(shf->rp) = c;
Packit Service 95ac19
	shf->rnleft++;
Packit Service 95ac19
	return (c);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Write a character. Returns the character if successful, -1 if the
Packit Service 95ac19
 * char could not be written.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
shf_putchar(int c, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	if (!(shf->flags & SHF_WR))
Packit Service 95ac19
		internal_errorf(Tf_flags, "shf_putchar",
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if (c == -1)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	if (shf->flags & SHF_UNBUF) {
Packit Service 95ac19
		unsigned char cc = (unsigned char)c;
Packit Service 95ac19
		ssize_t n;
Packit Service 95ac19
Packit Service 95ac19
		if (shf->fd < 0)
Packit Service 95ac19
			internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
Packit Service 95ac19
		if (shf->flags & SHF_ERROR) {
Packit Service 95ac19
			errno = shf->errnosv;
Packit Service 95ac19
			return (-1);
Packit Service 95ac19
		}
Packit Service 95ac19
		while ((n = write(shf->fd, &cc, 1)) != 1)
Packit Service 95ac19
			if (n < 0) {
Packit Service 95ac19
				if (errno == EINTR &&
Packit Service 95ac19
				    !(shf->flags & SHF_INTERRUPT))
Packit Service 95ac19
					continue;
Packit Service 95ac19
				shf->flags |= SHF_ERROR;
Packit Service 95ac19
				shf->errnosv = errno;
Packit Service 95ac19
				return (-1);
Packit Service 95ac19
			}
Packit Service 95ac19
	} else {
Packit Service 95ac19
		/* Flush deals with strings and sticky errors */
Packit Service 95ac19
		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1)
Packit Service 95ac19
			return (-1);
Packit Service 95ac19
		shf->wnleft--;
Packit Service 95ac19
		*shf->wp++ = c;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	return (c);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Write a string. Returns the length of the string if successful, -1
Packit Service 95ac19
 * if the string could not be written.
Packit Service 95ac19
 */
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_puts(const char *s, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	if (!s)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	return (shf_write(s, strlen(s), shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Write a buffer. Returns nbytes if successful, -1 if there is an error. */
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	ssize_t n, ncopy, orig_nbytes = nbytes;
Packit Service 95ac19
Packit Service 95ac19
	if (!(shf->flags & SHF_WR))
Packit Service 95ac19
		internal_errorf(Tf_flags, Tshf_write,
Packit Service 95ac19
		    (unsigned int)shf->flags);
Packit Service 95ac19
Packit Service 95ac19
	if (nbytes < 0)
Packit Service 95ac19
		internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
Packit Service 95ac19
Packit Service 95ac19
	/* Don't buffer if buffer is empty and we're writting a large amount. */
Packit Service 95ac19
	if ((ncopy = shf->wnleft) &&
Packit Service 95ac19
	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
Packit Service 95ac19
		if (ncopy > nbytes)
Packit Service 95ac19
			ncopy = nbytes;
Packit Service 95ac19
		memcpy(shf->wp, buf, ncopy);
Packit Service 95ac19
		nbytes -= ncopy;
Packit Service 95ac19
		buf += ncopy;
Packit Service 95ac19
		shf->wp += ncopy;
Packit Service 95ac19
		shf->wnleft -= ncopy;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (nbytes > 0) {
Packit Service 95ac19
		if (shf->flags & SHF_STRING) {
Packit Service 95ac19
			/* resize buffer until there's enough space left */
Packit Service 95ac19
			while (nbytes > shf->wnleft)
Packit Service 95ac19
				if (shf_emptybuf(shf, EB_GROW) == -1)
Packit Service 95ac19
					return (-1);
Packit Service 95ac19
			/* then write everything into the buffer */
Packit Service 95ac19
		} else {
Packit Service 95ac19
			/* flush deals with sticky errors */
Packit Service 95ac19
			if (shf_emptybuf(shf, EB_GROW) == -1)
Packit Service 95ac19
				return (-1);
Packit Service 95ac19
			/* write chunks larger than window size directly */
Packit Service 95ac19
			if (nbytes > shf->wbsize) {
Packit Service 95ac19
				ncopy = nbytes;
Packit Service 95ac19
				if (shf->wbsize)
Packit Service 95ac19
					ncopy -= nbytes % shf->wbsize;
Packit Service 95ac19
				nbytes -= ncopy;
Packit Service 95ac19
				while (ncopy > 0) {
Packit Service 95ac19
					n = write(shf->fd, buf, ncopy);
Packit Service 95ac19
					if (n < 0) {
Packit Service 95ac19
						if (errno == EINTR &&
Packit Service 95ac19
						    !(shf->flags & SHF_INTERRUPT))
Packit Service 95ac19
							continue;
Packit Service 95ac19
						shf->flags |= SHF_ERROR;
Packit Service 95ac19
						shf->errnosv = errno;
Packit Service 95ac19
						shf->wnleft = 0;
Packit Service 95ac19
						/*
Packit Service 95ac19
						 * Note: fwrite(3) returns 0
Packit Service 95ac19
						 * for errors - this doesn't
Packit Service 95ac19
						 */
Packit Service 95ac19
						return (-1);
Packit Service 95ac19
					}
Packit Service 95ac19
					buf += n;
Packit Service 95ac19
					ncopy -= n;
Packit Service 95ac19
				}
Packit Service 95ac19
			}
Packit Service 95ac19
			/* ... and buffer the rest */
Packit Service 95ac19
		}
Packit Service 95ac19
		if (nbytes > 0) {
Packit Service 95ac19
			/* write remaining bytes to buffer */
Packit Service 95ac19
			memcpy(shf->wp, buf, nbytes);
Packit Service 95ac19
			shf->wp += nbytes;
Packit Service 95ac19
			shf->wnleft -= nbytes;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	return (orig_nbytes);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_fprintf(struct shf *shf, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list args;
Packit Service 95ac19
	ssize_t n;
Packit Service 95ac19
Packit Service 95ac19
	va_start(args, fmt);
Packit Service 95ac19
	n = shf_vfprintf(shf, fmt, args);
Packit Service 95ac19
	va_end(args);
Packit Service 95ac19
Packit Service 95ac19
	return (n);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	struct shf shf;
Packit Service 95ac19
	va_list args;
Packit Service 95ac19
	ssize_t n;
Packit Service 95ac19
Packit Service 95ac19
	if (!buf || bsize <= 0)
Packit Service 95ac19
		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
Packit Service 95ac19
		    (size_t)buf, bsize);
Packit Service 95ac19
Packit Service 95ac19
	shf_sopen(buf, bsize, SHF_WR, &shf;;
Packit Service 95ac19
	va_start(args, fmt);
Packit Service 95ac19
	n = shf_vfprintf(&shf, fmt, args);
Packit Service 95ac19
	va_end(args);
Packit Service 95ac19
	/* NUL terminates */
Packit Service 95ac19
	shf_sclose(&shf;;
Packit Service 95ac19
	return (n);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
char *
Packit Service 95ac19
shf_smprintf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	struct shf shf;
Packit Service 95ac19
	va_list args;
Packit Service 95ac19
Packit Service 95ac19
	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf;;
Packit Service 95ac19
	va_start(args, fmt);
Packit Service 95ac19
	shf_vfprintf(&shf, fmt, args);
Packit Service 95ac19
	va_end(args);
Packit Service 95ac19
	/* NUL terminates */
Packit Service 95ac19
	return (shf_sclose(&shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#define	FL_HASH		0x001	/* '#' seen */
Packit Service 95ac19
#define FL_PLUS		0x002	/* '+' seen */
Packit Service 95ac19
#define FL_RIGHT	0x004	/* '-' seen */
Packit Service 95ac19
#define FL_BLANK	0x008	/* ' ' seen */
Packit Service 95ac19
#define FL_SHORT	0x010	/* 'h' seen */
Packit Service 95ac19
#define FL_LONG		0x020	/* 'l' seen */
Packit Service 95ac19
#define FL_ZERO		0x040	/* '0' seen */
Packit Service 95ac19
#define FL_DOT		0x080	/* '.' seen */
Packit Service 95ac19
#define FL_UPPER	0x100	/* format character was uppercase */
Packit Service 95ac19
#define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
Packit Service 95ac19
#define FL_SIZET	0x400	/* 'z' seen */
Packit Service 95ac19
#define FM_SIZES	0x430	/* h/l/z mask */
Packit Service 95ac19
Packit Service 95ac19
ssize_t
Packit Service 95ac19
shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
Packit Service 95ac19
{
Packit Service 95ac19
	const char *s;
Packit Service 95ac19
	char c, *cp;
Packit Service 95ac19
	int tmp = 0, flags;
Packit Service 95ac19
	size_t field, precision, len;
Packit Service 95ac19
	unsigned long lnum;
Packit Service 95ac19
	/* %#o produces the longest output */
Packit Service 95ac19
	char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1];
Packit Service 95ac19
	/* this stuff for dealing with the buffer */
Packit Service 95ac19
	ssize_t nwritten = 0;
Packit Service 95ac19
Packit Service 95ac19
#define VA(type) va_arg(args, type)
Packit Service 95ac19
Packit Service 95ac19
	if (!fmt)
Packit Service 95ac19
		return (0);
Packit Service 95ac19
Packit Service 95ac19
	while ((c = *fmt++)) {
Packit Service 95ac19
		if (c != '%') {
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
			nwritten++;
Packit Service 95ac19
			continue;
Packit Service 95ac19
		}
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * This will accept flags/fields in any order - not just
Packit Service 95ac19
		 * the order specified in printf(3), but this is the way
Packit Service 95ac19
		 * _doprnt() seems to work (on BSD and SYSV). The only
Packit Service 95ac19
		 * restriction is that the format character must come
Packit Service 95ac19
		 * last :-).
Packit Service 95ac19
		 */
Packit Service 95ac19
		flags = 0;
Packit Service 95ac19
		field = precision = 0;
Packit Service 95ac19
		while ((c = *fmt++)) {
Packit Service 95ac19
			switch (c) {
Packit Service 95ac19
			case '#':
Packit Service 95ac19
				flags |= FL_HASH;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case '+':
Packit Service 95ac19
				flags |= FL_PLUS;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case '-':
Packit Service 95ac19
				flags |= FL_RIGHT;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case ' ':
Packit Service 95ac19
				flags |= FL_BLANK;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case '0':
Packit Service 95ac19
				if (!(flags & FL_DOT))
Packit Service 95ac19
					flags |= FL_ZERO;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case '.':
Packit Service 95ac19
				flags |= FL_DOT;
Packit Service 95ac19
				precision = 0;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case '*':
Packit Service 95ac19
				tmp = VA(int);
Packit Service 95ac19
				if (tmp < 0) {
Packit Service 95ac19
					if (flags & FL_DOT)
Packit Service 95ac19
						precision = 0;
Packit Service 95ac19
					else {
Packit Service 95ac19
						field = (unsigned int)-tmp;
Packit Service 95ac19
						flags |= FL_RIGHT;
Packit Service 95ac19
					}
Packit Service 95ac19
				} else if (flags & FL_DOT)
Packit Service 95ac19
					precision = (unsigned int)tmp;
Packit Service 95ac19
				else
Packit Service 95ac19
					field = (unsigned int)tmp;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case 'l':
Packit Service 95ac19
				flags &= ~FM_SIZES;
Packit Service 95ac19
				flags |= FL_LONG;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case 'h':
Packit Service 95ac19
				flags &= ~FM_SIZES;
Packit Service 95ac19
				flags |= FL_SHORT;
Packit Service 95ac19
				continue;
Packit Service 95ac19
Packit Service 95ac19
			case 'z':
Packit Service 95ac19
				flags &= ~FM_SIZES;
Packit Service 95ac19
				flags |= FL_SIZET;
Packit Service 95ac19
				continue;
Packit Service 95ac19
			}
Packit Service 95ac19
			if (ctype(c, C_DIGIT)) {
Packit Service 95ac19
				bool overflowed = false;
Packit Service 95ac19
Packit Service 95ac19
				tmp = ksh_numdig(c);
Packit Service 95ac19
				while (ctype((c = *fmt++), C_DIGIT))
Packit Service 95ac19
					if (notok2mul(2147483647, tmp, 10))
Packit Service 95ac19
						overflowed = true;
Packit Service 95ac19
					else
Packit Service 95ac19
						tmp = tmp * 10 + ksh_numdig(c);
Packit Service 95ac19
				--fmt;
Packit Service 95ac19
				if (overflowed)
Packit Service 95ac19
					tmp = 0;
Packit Service 95ac19
				if (flags & FL_DOT)
Packit Service 95ac19
					precision = (unsigned int)tmp;
Packit Service 95ac19
				else
Packit Service 95ac19
					field = (unsigned int)tmp;
Packit Service 95ac19
				continue;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		if (!c)
Packit Service 95ac19
			/* nasty format */
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		if (ctype(c, C_UPPER)) {
Packit Service 95ac19
			flags |= FL_UPPER;
Packit Service 95ac19
			c = ksh_tolower(c);
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		switch (c) {
Packit Service 95ac19
		case 'd':
Packit Service 95ac19
		case 'i':
Packit Service 95ac19
			if (flags & FL_SIZET)
Packit Service 95ac19
				lnum = (long)VA(ssize_t);
Packit Service 95ac19
			else if (flags & FL_LONG)
Packit Service 95ac19
				lnum = VA(long);
Packit Service 95ac19
			else if (flags & FL_SHORT)
Packit Service 95ac19
				lnum = (long)(short)VA(int);
Packit Service 95ac19
			else
Packit Service 95ac19
				lnum = (long)VA(int);
Packit Service 95ac19
			goto integral;
Packit Service 95ac19
Packit Service 95ac19
		case 'o':
Packit Service 95ac19
		case 'u':
Packit Service 95ac19
		case 'x':
Packit Service 95ac19
			if (flags & FL_SIZET)
Packit Service 95ac19
				lnum = VA(size_t);
Packit Service 95ac19
			else if (flags & FL_LONG)
Packit Service 95ac19
				lnum = VA(unsigned long);
Packit Service 95ac19
			else if (flags & FL_SHORT)
Packit Service 95ac19
				lnum = (unsigned long)(unsigned short)VA(int);
Packit Service 95ac19
			else
Packit Service 95ac19
				lnum = (unsigned long)VA(unsigned int);
Packit Service 95ac19
Packit Service 95ac19
 integral:
Packit Service 95ac19
			flags |= FL_NUMBER;
Packit Service 95ac19
			cp = numbuf + sizeof(numbuf);
Packit Service 95ac19
			*--cp = '\0';
Packit Service 95ac19
Packit Service 95ac19
			switch (c) {
Packit Service 95ac19
			case 'd':
Packit Service 95ac19
			case 'i':
Packit Service 95ac19
				if (0 > (long)lnum) {
Packit Service 95ac19
					lnum = -(long)lnum;
Packit Service 95ac19
					tmp = 1;
Packit Service 95ac19
				} else
Packit Service 95ac19
					tmp = 0;
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
			case 'u':
Packit Service 95ac19
				do {
Packit Service 95ac19
					*--cp = digits_lc[lnum % 10];
Packit Service 95ac19
					lnum /= 10;
Packit Service 95ac19
				} while (lnum);
Packit Service 95ac19
Packit Service 95ac19
				if (c != 'u') {
Packit Service 95ac19
					if (tmp)
Packit Service 95ac19
						*--cp = '-';
Packit Service 95ac19
					else if (flags & FL_PLUS)
Packit Service 95ac19
						*--cp = '+';
Packit Service 95ac19
					else if (flags & FL_BLANK)
Packit Service 95ac19
						*--cp = ' ';
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
Packit Service 95ac19
			case 'o':
Packit Service 95ac19
				do {
Packit Service 95ac19
					*--cp = digits_lc[lnum & 0x7];
Packit Service 95ac19
					lnum >>= 3;
Packit Service 95ac19
				} while (lnum);
Packit Service 95ac19
Packit Service 95ac19
				if ((flags & FL_HASH) && *cp != '0')
Packit Service 95ac19
					*--cp = '0';
Packit Service 95ac19
				break;
Packit Service 95ac19
Packit Service 95ac19
			case 'x': {
Packit Service 95ac19
				const char *digits = (flags & FL_UPPER) ?
Packit Service 95ac19
				    digits_uc : digits_lc;
Packit Service 95ac19
				do {
Packit Service 95ac19
					*--cp = digits[lnum & 0xF];
Packit Service 95ac19
					lnum >>= 4;
Packit Service 95ac19
				} while (lnum);
Packit Service 95ac19
Packit Service 95ac19
				if (flags & FL_HASH) {
Packit Service 95ac19
					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
Packit Service 95ac19
					*--cp = '0';
Packit Service 95ac19
				}
Packit Service 95ac19
			    }
Packit Service 95ac19
			}
Packit Service 95ac19
			len = numbuf + sizeof(numbuf) - 1 - (s = cp);
Packit Service 95ac19
			if (flags & FL_DOT) {
Packit Service 95ac19
				if (precision > len) {
Packit Service 95ac19
					field = precision;
Packit Service 95ac19
					flags |= FL_ZERO;
Packit Service 95ac19
				} else
Packit Service 95ac19
					/* no loss */
Packit Service 95ac19
					precision = len;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case 's':
Packit Service 95ac19
			if ((s = VA(const char *)) == NULL)
Packit Service 95ac19
				s = "(null)";
Packit Service 95ac19
			else if (flags & FL_HASH) {
Packit Service 95ac19
				print_value_quoted(shf, s);
Packit Service 95ac19
				continue;
Packit Service 95ac19
			}
Packit Service 95ac19
			len = utf_mbswidth(s);
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case 'c':
Packit Service 95ac19
			flags &= ~FL_DOT;
Packit Service 95ac19
			c = (char)(VA(int));
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
Packit Service 95ac19
		case '%':
Packit Service 95ac19
		default:
Packit Service 95ac19
			numbuf[0] = c;
Packit Service 95ac19
			numbuf[1] = 0;
Packit Service 95ac19
			s = numbuf;
Packit Service 95ac19
			len = 1;
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * At this point s should point to a string that is to be
Packit Service 95ac19
		 * formatted, and len should be the length of the string.
Packit Service 95ac19
		 */
Packit Service 95ac19
		if (!(flags & FL_DOT) || len < precision)
Packit Service 95ac19
			precision = len;
Packit Service 95ac19
		if (field > precision) {
Packit Service 95ac19
			field -= precision;
Packit Service 95ac19
			if (!(flags & FL_RIGHT)) {
Packit Service 95ac19
				/* skip past sign or 0x when padding with 0 */
Packit Service 95ac19
				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
Packit Service 95ac19
					if (ctype(*s, C_SPC | C_PLUS | C_MINUS)) {
Packit Service 95ac19
						shf_putc(*s, shf);
Packit Service 95ac19
						s++;
Packit Service 95ac19
						precision--;
Packit Service 95ac19
						nwritten++;
Packit Service 95ac19
					} else if (*s == '0') {
Packit Service 95ac19
						shf_putc(*s, shf);
Packit Service 95ac19
						s++;
Packit Service 95ac19
						nwritten++;
Packit Service 95ac19
						if (--precision &&
Packit Service 95ac19
						    ksh_eq(*s, 'X', 'x')) {
Packit Service 95ac19
							shf_putc(*s, shf);
Packit Service 95ac19
							s++;
Packit Service 95ac19
							precision--;
Packit Service 95ac19
							nwritten++;
Packit Service 95ac19
						}
Packit Service 95ac19
					}
Packit Service 95ac19
					c = '0';
Packit Service 95ac19
				} else
Packit Service 95ac19
					c = flags & FL_ZERO ? '0' : ' ';
Packit Service 95ac19
				nwritten += field;
Packit Service 95ac19
				while (field--)
Packit Service 95ac19
					shf_putc(c, shf);
Packit Service 95ac19
				field = 0;
Packit Service 95ac19
			} else
Packit Service 95ac19
				c = ' ';
Packit Service 95ac19
		} else
Packit Service 95ac19
			field = 0;
Packit Service 95ac19
Packit Service 95ac19
		nwritten += precision;
Packit Service 95ac19
		precision = utf_skipcols(s, precision, &tmp) - s;
Packit Service 95ac19
		while (precision--)
Packit Service 95ac19
			shf_putc(*s++, shf);
Packit Service 95ac19
Packit Service 95ac19
		nwritten += field;
Packit Service 95ac19
		while (field--)
Packit Service 95ac19
			shf_putc(c, shf);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	return (shf_error(shf) ? -1 : nwritten);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
Packit Service 95ac19
int
Packit Service 95ac19
shf_getc(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	return (shf_getc_i(shf));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
shf_putc(int c, struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	return (shf_putc_i(c, shf));
Packit Service 95ac19
}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#ifdef DEBUG
Packit Service 95ac19
const char *
Packit Service 95ac19
cstrerror(int errnum)
Packit Service 95ac19
{
Packit Service 95ac19
#undef strerror
Packit Service 95ac19
	return (strerror(errnum));
Packit Service 95ac19
#define strerror dontuse_strerror /* poisoned */
Packit Service 95ac19
}
Packit Service 95ac19
#elif !HAVE_STRERROR
Packit Service 95ac19
Packit Service 95ac19
#if HAVE_SYS_ERRLIST
Packit Service 95ac19
#if !HAVE_SYS_ERRLIST_DECL
Packit Service 95ac19
extern const int sys_nerr;
Packit Service 95ac19
extern const char * const sys_errlist[];
Packit Service 95ac19
#endif
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
const char *
Packit Service 95ac19
cstrerror(int errnum)
Packit Service 95ac19
{
Packit Service 95ac19
	/* "Unknown error: " + sign + rough estimate + NUL */
Packit Service 95ac19
	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
Packit Service 95ac19
Packit Service 95ac19
#if HAVE_SYS_ERRLIST
Packit Service 95ac19
	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
Packit Service 95ac19
		return (sys_errlist[errnum]);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	switch (errnum) {
Packit Service 95ac19
	case 0:
Packit Service 95ac19
		return ("Undefined error: 0");
Packit Service 95ac19
	case EPERM:
Packit Service 95ac19
		return ("Operation not permitted");
Packit Service 95ac19
	case ENOENT:
Packit Service 95ac19
		return ("No such file or directory");
Packit Service 95ac19
#ifdef ESRCH
Packit Service 95ac19
	case ESRCH:
Packit Service 95ac19
		return ("No such process");
Packit Service 95ac19
#endif
Packit Service 95ac19
#ifdef E2BIG
Packit Service 95ac19
	case E2BIG:
Packit Service 95ac19
		return ("Argument list too long");
Packit Service 95ac19
#endif
Packit Service 95ac19
	case ENOEXEC:
Packit Service 95ac19
		return ("Exec format error");
Packit Service 95ac19
	case EBADF:
Packit Service 95ac19
		return ("Bad file descriptor");
Packit Service 95ac19
#ifdef ENOMEM
Packit Service 95ac19
	case ENOMEM:
Packit Service 95ac19
		return ("Cannot allocate memory");
Packit Service 95ac19
#endif
Packit Service 95ac19
	case EACCES:
Packit Service 95ac19
		return ("Permission denied");
Packit Service 95ac19
	case EEXIST:
Packit Service 95ac19
		return ("File exists");
Packit Service 95ac19
	case ENOTDIR:
Packit Service 95ac19
		return ("Not a directory");
Packit Service 95ac19
#ifdef EINVAL
Packit Service 95ac19
	case EINVAL:
Packit Service 95ac19
		return ("Invalid argument");
Packit Service 95ac19
#endif
Packit Service 95ac19
#ifdef ELOOP
Packit Service 95ac19
	case ELOOP:
Packit Service 95ac19
		return ("Too many levels of symbolic links");
Packit Service 95ac19
#endif
Packit Service 95ac19
	default:
Packit Service 95ac19
		shf_snprintf(errbuf, sizeof(errbuf),
Packit Service 95ac19
		    "Unknown error: %d", errnum);
Packit Service 95ac19
		return (errbuf);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
/* fast character classes */
Packit Service 95ac19
const uint32_t tpl_ctypes[128] = {
Packit Service 95ac19
	/* 0x00 */
Packit Service 95ac19
	CiNUL,		CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	CiCNTRL,	CiTAB,		CiNL,		CiSPX,
Packit Service 95ac19
	CiSPX,		CiCR,		CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	/* 0x10 */
Packit Service 95ac19
	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
Packit Service 95ac19
	/* 0x20 */
Packit Service 95ac19
	CiSP,		CiALIAS | CiVAR1,	CiQC,	CiHASH,
Packit Service 95ac19
	CiSS,		CiPERCT,	CiQCL,		CiQC,
Packit Service 95ac19
	CiQCL,		CiQCL,		CiQCX | CiVAR1,	CiPLUS,
Packit Service 95ac19
	CiALIAS,	CiMINUS,	CiALIAS,	CiQCM,
Packit Service 95ac19
	/* 0x30 */
Packit Service 95ac19
	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
Packit Service 95ac19
	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
Packit Service 95ac19
	CiDIGIT,	CiDIGIT,	CiCOLON,	CiQCL,
Packit Service 95ac19
	CiANGLE,	CiEQUAL,	CiANGLE,	CiQUEST,
Packit Service 95ac19
	/* 0x40 */
Packit Service 95ac19
	CiALIAS | CiVAR1,	CiUPPER | CiHEXLT,
Packit Service 95ac19
	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
Packit Service 95ac19
	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
Packit Service 95ac19
	CiUPPER | CiHEXLT,	CiUPPER,
Packit Service 95ac19
	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
Packit Service 95ac19
	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
Packit Service 95ac19
	/* 0x50 */
Packit Service 95ac19
	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
Packit Service 95ac19
	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
Packit Service 95ac19
	CiUPPER,	CiUPPER,	CiUPPER,	CiQCX | CiBRACK,
Packit Service 95ac19
	CiQCX,		CiBRACK,	CiQCM,		CiUNDER,
Packit Service 95ac19
	/* 0x60 */
Packit Service 95ac19
	CiGRAVE,		CiLOWER | CiHEXLT,
Packit Service 95ac19
	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
Packit Service 95ac19
	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
Packit Service 95ac19
	CiLOWER | CiHEXLT,	CiLOWER,
Packit Service 95ac19
	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
Packit Service 95ac19
	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
Packit Service 95ac19
	/* 0x70 */
Packit Service 95ac19
	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
Packit Service 95ac19
	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
Packit Service 95ac19
	CiLOWER,	CiLOWER,	CiLOWER,	CiCURLY,
Packit Service 95ac19
	CiQCL,		CiCURLY,	CiQCM,		CiCNTRL
Packit Service 95ac19
};
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
set_ifs(const char *s)
Packit Service 95ac19
{
Packit Service 95ac19
#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
Packit Service 95ac19
	int i = 256;
Packit Service 95ac19
Packit Service 95ac19
	memset(ksh_ctypes, 0, sizeof(ksh_ctypes));
Packit Service 95ac19
	while (i--)
Packit Service 95ac19
		if (ebcdic_map[i] < 0x80U)
Packit Service 95ac19
			ksh_ctypes[i] = tpl_ctypes[ebcdic_map[i]];
Packit Service 95ac19
#else
Packit Service 95ac19
	memcpy(ksh_ctypes, tpl_ctypes, sizeof(tpl_ctypes));
Packit Service 95ac19
	memset((char *)ksh_ctypes + sizeof(tpl_ctypes), '\0',
Packit Service 95ac19
	    sizeof(ksh_ctypes) - sizeof(tpl_ctypes));
Packit Service 95ac19
#endif
Packit Service 95ac19
	ifs0 = *s;
Packit Service 95ac19
	while (*s)
Packit Service 95ac19
		ksh_ctypes[ord(*s++)] |= CiIFS;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
Packit Service 95ac19
#include <locale.h>
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Many headaches with EBCDIC:
Packit Service 95ac19
 * 1. There are numerous EBCDIC variants, and it is not feasible for us
Packit Service 95ac19
 *    to support them all. But we can support the EBCDIC code pages that
Packit Service 95ac19
 *    contain all (most?) of the characters in ASCII, and these
Packit Service 95ac19
 *    usually tend to agree on the code points assigned to the ASCII
Packit Service 95ac19
 *    subset. If you need a representative example, look at EBCDIC 1047,
Packit Service 95ac19
 *    which is first among equals in the IBM MVS development
Packit Service 95ac19
 *    environment: https://en.wikipedia.org/wiki/EBCDIC_1047
Packit Service 95ac19
 *    Unfortunately, the square brackets are not consistently mapped,
Packit Service 95ac19
 *    and for certain reasons, we need an unambiguous bijective
Packit Service 95ac19
 *    mapping between EBCDIC and "extended ASCII".
Packit Service 95ac19
 * 2. Character ranges that are contiguous in ASCII, like the letters
Packit Service 95ac19
 *    in [A-Z], are broken up into segments (i.e. [A-IJ-RS-Z]), so we
Packit Service 95ac19
 *    can't implement e.g. islower() as { return c >= 'a' && c <= 'z'; }
Packit Service 95ac19
 *    because it will also return true for a handful of extraneous
Packit Service 95ac19
 *    characters (like the plus-minus sign at 0x8F in EBCDIC 1047, a
Packit Service 95ac19
 *    little after 'i'). But at least '_' is not one of these.
Packit Service 95ac19
 * 3. The normal [0-9A-Za-z] characters are at codepoints beyond 0x80.
Packit Service 95ac19
 *    Not only do they require all 8 bits instead of 7, if chars are
Packit Service 95ac19
 *    signed, they will have negative integer values! Something like
Packit Service 95ac19
 *    (c - 'A') could actually become (c + 63)! Use the ord() macro to
Packit Service 95ac19
 *    ensure you're getting a value in [0, 255] (ORD for constants).
Packit Service 95ac19
 * 4. '\n' is actually NL (0x15, U+0085) instead of LF (0x25, U+000A).
Packit Service 95ac19
 *    EBCDIC has a proper newline character instead of "emulating" one
Packit Service 95ac19
 *    with line feeds, although this is mapped to LF for our purposes.
Packit Service 95ac19
 * 5. Note that it is possible to compile programs in ASCII mode on IBM
Packit Service 95ac19
 *    mainframe systems, using the -qascii option to the XL C compiler.
Packit Service 95ac19
 *    We can determine the build mode by looking at __CHARSET_LIB:
Packit Service 95ac19
 *    0 == EBCDIC, 1 == ASCII
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
ebcdic_init(void)
Packit Service 95ac19
{
Packit Service 95ac19
	int i = 256;
Packit Service 95ac19
	unsigned char t;
Packit Service 95ac19
	bool mapcache[256];
Packit Service 95ac19
Packit Service 95ac19
	while (i--)
Packit Service 95ac19
		ebcdic_rtt_toascii[i] = i;
Packit Service 95ac19
	memset(ebcdic_rtt_fromascii, 0xFF, sizeof(ebcdic_rtt_fromascii));
Packit Service 95ac19
	setlocale(LC_ALL, "");
Packit Service 95ac19
#ifdef MKSH_EBCDIC
Packit Service 95ac19
	if (__etoa_l(ebcdic_rtt_toascii, 256) != 256) {
Packit Service 95ac19
		write(2, "mksh: could not map EBCDIC to ASCII\n", 36);
Packit Service 95ac19
		exit(255);
Packit Service 95ac19
	}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	memset(mapcache, 0, sizeof(mapcache));
Packit Service 95ac19
	i = 256;
Packit Service 95ac19
	while (i--) {
Packit Service 95ac19
		t = ebcdic_rtt_toascii[i];
Packit Service 95ac19
		/* ensure unique round-trip capable mapping */
Packit Service 95ac19
		if (mapcache[t]) {
Packit Service 95ac19
			write(2, "mksh: duplicate EBCDIC to ASCII mapping\n", 40);
Packit Service 95ac19
			exit(255);
Packit Service 95ac19
		}
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * since there are 256 input octets, this also ensures
Packit Service 95ac19
		 * the other mapping direction is completely filled
Packit Service 95ac19
		 */
Packit Service 95ac19
		mapcache[t] = true;
Packit Service 95ac19
		/* fill the complete round-trip map */
Packit Service 95ac19
		ebcdic_rtt_fromascii[t] = i;
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * Only use the converted value if it's in the range
Packit Service 95ac19
		 * [0x00; 0x7F], which I checked; the "extended ASCII"
Packit Service 95ac19
		 * characters can be any encoding, not just Latin1,
Packit Service 95ac19
		 * and the C1 control characters other than NEL are
Packit Service 95ac19
		 * hopeless, but we map EBCDIC NEL to ASCII LF so we
Packit Service 95ac19
		 * cannot even use C1 NEL.
Packit Service 95ac19
		 * If ever we map to Unicode, bump the table width to
Packit Service 95ac19
		 * an unsigned int, and or the raw unconverted EBCDIC
Packit Service 95ac19
		 * values with 0x01000000 instead.
Packit Service 95ac19
		 */
Packit Service 95ac19
		if (t < 0x80U)
Packit Service 95ac19
			ebcdic_map[i] = (unsigned short)ord(t);
Packit Service 95ac19
		else
Packit Service 95ac19
			ebcdic_map[i] = (unsigned short)(0x100U | ord(i));
Packit Service 95ac19
	}
Packit Service 95ac19
	if (ebcdic_rtt_toascii[0] || ebcdic_rtt_fromascii[0] || ebcdic_map[0]) {
Packit Service 95ac19
		write(2, "mksh: NUL not at position 0\n", 28);
Packit Service 95ac19
		exit(255);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
#endif