15155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
55155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@mirbsd.org>
65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
2103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *-
2203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Use %zX instead of %p and floating point isn't supported at all.
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
27c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.56 2013/01/01 03:32:44 tg Exp $");
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* flags to shf_emptybuf() */
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define EB_READSW	0x01	/* about to switch to reading */
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Replacement stdio routines. Stdio is too flakey on too many machines
355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * to be useful when you have multiple processes using the same underlying
365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * file descriptors.
375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int shf_fillbuf(struct shf *);
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int shf_emptybuf(struct shf *, int);
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
4303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Open a file. First three args are for open(), last arg is flags for
445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * this package. Returns NULL if file could not be opened, or if a dup
455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * fails.
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf *
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_open(const char *name, int oflags, int mode, int sflags)
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct shf *shf;
5103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t bsize =
5203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    /* at most 512 */
5303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fd;
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Done before open so if alloca fails, fd won't be lost. */
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->areap = ATEMP;
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->buf = (unsigned char *)&shf[1];
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->bsize = bsize;
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags = SHF_ALLOCS;
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Rest filled in by reopen. */
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	fd = open(name, oflags, mode);
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (fd < 0) {
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(shf, shf->areap);
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int nfd;
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nfd = fcntl(fd, F_DUPFD, FDBASE);
735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (nfd < 0) {
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(shf, shf->areap);
765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fd = nfd;
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sflags &= ~SHF_ACCMODE;
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD :
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR);
835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf_reopen(fd, sflags, shf));
855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* helper function for shf_fdopen and shf_reopen */
8803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic void
8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_open_hlp(int fd, int *sflagsp, const char *where)
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int sflags = *sflagsp;
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* use fcntl() to figure out correct read/write flags */
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sflags & SHF_GETFL) {
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int flags = fcntl(fd, F_GETFL, 0);
965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (flags < 0)
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* will get an error on first read/write */
995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sflags |= SHF_RDWR;
1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (flags & O_ACCMODE) {
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case O_RDONLY:
1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sflags |= SHF_RD;
1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case O_WRONLY:
1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sflags |= SHF_WR;
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case O_RDWR:
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sflags |= SHF_RDWR;
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*sflagsp = sflags;
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(sflags & (SHF_RD | SHF_WR)))
11703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s", where, "missing read/write");
11803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
11903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
12003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* Set up the shf structure for a file descriptor. Doesn't fail. */
12103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastruct shf *
12203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_fdopen(int fd, int sflags, struct shf *shf)
12303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
12403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t bsize =
12503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    /* at most 512 */
12603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shf_open_hlp(fd, &sflags, "shf_fdopen");
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf) {
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (bsize) {
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->buf = alloc(bsize, ATEMP);
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sflags |= SHF_ALLOCB;
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->buf = NULL;
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->buf = (unsigned char *)&shf[1];
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sflags |= SHF_ALLOCS;
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->areap = ATEMP;
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->fd = fd;
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rp = shf->wp = shf->buf;
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rnleft = 0;
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rbsize = bsize;
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wnleft = 0; /* force call to shf_emptybuf() */
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags = sflags;
14803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shf->errnosv = 0;
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->bsize = bsize;
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sflags & SHF_CLEXEC)
1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fcntl(fd, F_SETFD, FD_CLOEXEC);
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf);
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Set up an existing shf (and buffer) to use the given fd */
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf *
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_reopen(int fd, int sflags, struct shf *shf)
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t bsize =
16003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    /* at most 512 */
16103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shf_open_hlp(fd, &sflags, "shf_reopen");
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!shf || !shf->buf || shf->bsize < bsize)
16503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s", "shf_reopen", "bad shf/buf/bsize");
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* assumes shf->buf and shf->bsize already set up */
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->fd = fd;
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rp = shf->wp = shf->buf;
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rnleft = 0;
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rbsize = bsize;
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wnleft = 0; /* force call to shf_emptybuf() */
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
17503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shf->errnosv = 0;
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sflags & SHF_CLEXEC)
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fcntl(fd, F_SETFD, FD_CLOEXEC);
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf);
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
18203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Open a string for reading or writing. If reading, bsize is the number
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of bytes that can be read. If writing, bsize is the maximum number of
18403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * bytes that can be written. If shf is not NULL, it is filled in and
18503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * returned, if it is NULL, shf is allocated. If writing and buf is NULL
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * used for the initial size). Doesn't fail.
18803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct shf *
19103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* can't have a read+write string */
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
19503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_sopen", sflags);
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!shf) {
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf = alloc(sizeof(struct shf), ATEMP);
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sflags |= SHF_ALLOCS;
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->areap = ATEMP;
2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (bsize <= 0)
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			bsize = 64;
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sflags |= SHF_ALLOCB;
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		buf = alloc(bsize, shf->areap);
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->fd = -1;
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rnleft = bsize;
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rbsize = bsize;
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wnleft = bsize - 1;	/* space for a '\0' */
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->wbsize = bsize;
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags = sflags | SHF_STRING;
21503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shf->errnosv = 0;
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->bsize = bsize;
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf);
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Flush and close file descriptor, free the shf structure */
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_close(struct shf *shf)
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int ret = 0;
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->fd >= 0) {
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = shf_flush(shf);
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (close(shf->fd) < 0)
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = EOF;
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_ALLOCS)
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(shf, shf->areap);
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (shf->flags & SHF_ALLOCB)
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(shf->buf, shf->areap);
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Flush and close file descriptor, don't free file structure */
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fdclose(struct shf *shf)
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int ret = 0;
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->fd >= 0) {
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = shf_flush(shf);
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (close(shf->fd) < 0)
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = EOF;
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rnleft = 0;
2515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp = shf->buf;
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft = 0;
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->fd = -1;
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
25903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
26003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Close a string - if it was opened for writing, it is NUL terminated;
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * returns a pointer to the string and frees shf if it was allocated
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * (does not free string if it was allocated).
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_sclose(struct shf *shf)
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned char *s = shf->buf;
2685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* NUL terminate */
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_WR) {
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft++;
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_putc('\0', shf);
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_ALLOCS)
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(shf, shf->areap);
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((char *)s);
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
27903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
28003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Un-read what has been read but not examined, or write what has been
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * buffered. Returns 0 for success, EOF for (write) error.
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_flush(struct shf *shf)
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_STRING)
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return ((shf->flags & SHF_WR) ? EOF : 0);
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->fd < 0)
29003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s", "shf_flush", "no fd");
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_ERROR) {
29303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = shf->errnosv;
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_READING) {
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->flags &= ~(SHF_EOF | SHF_READING);
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->rnleft > 0) {
3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR);
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->rnleft = 0;
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->rp = shf->buf;
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (shf->flags & SHF_WRITING)
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (shf_emptybuf(shf, 0));
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
31103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
31203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write out any buffered data. If currently reading, flushes the read
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * buffer. Returns 0 for success, EOF for (write) error.
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_emptybuf(struct shf *shf, int flags)
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int ret = 0;
3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
32103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s", "shf_emptybuf", "no fd");
3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_ERROR) {
32403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = shf->errnosv;
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_READING) {
32903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (flags & EB_READSW)
33003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* doesn't happen */
3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
3325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = shf_flush(shf);
3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->flags &= ~SHF_READING;
3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_STRING) {
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unsigned char *nbuf;
3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
33803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
33903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Note that we assume SHF_ALLOCS is not set if
34003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * SHF_ALLOCB is set... (changing the shf pointer could
34103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * cause problems)
3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    !(shf->flags & SHF_ALLOCB))
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (EOF);
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* allocate more space for buffer */
34703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
3485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp = nbuf + (shf->rp - shf->buf);
3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wp = nbuf + (shf->wp - shf->buf);
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rbsize += shf->wbsize;
3515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft += shf->wbsize;
35203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->wbsize <<= 1;
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->buf = nbuf;
3545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->flags & SHF_WRITING) {
35603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ssize_t n, ntowrite = shf->wp - shf->buf;
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unsigned char *buf = shf->buf;
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (ntowrite > 0) {
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				n = write(shf->fd, buf, ntowrite);
3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (n < 0) {
3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (errno == EINTR &&
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    !(shf->flags & SHF_INTERRUPT))
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						continue;
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					shf->flags |= SHF_ERROR;
36603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					shf->errnosv = errno;
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					shf->wnleft = 0;
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (buf != shf->buf) {
36903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/*
37003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 * allow a second flush
37103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 * to work
37203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						 */
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						memmove(shf->buf, buf,
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						    ntowrite);
3755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf->wp = shf->buf + ntowrite;
3765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (EOF);
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				buf += n;
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ntowrite -= n;
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (flags & EB_READSW) {
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf->wp = shf->buf;
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf->wnleft = 0;
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf->flags &= ~SHF_WRITING;
3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
3875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wp = shf->buf;
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft = shf->wbsize;
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags |= SHF_WRITING;
3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fillbuf(struct shf *shf)
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
40103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t n;
40203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_STRING)
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->fd < 0)
40703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s", "shf_fillbuf", "no fd");
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->flags & SHF_ERROR)
41103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errno = shf->errnosv;
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags |= SHF_READING;
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rp = shf->buf;
42103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
42203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
42303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (n < 0) {
42803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->flags |= SHF_ERROR;
42903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->errnosv = errno;
43003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->rnleft = 0;
43103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->rp = shf->buf;
43203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (EOF);
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
43403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if ((shf->rnleft = n) == 0)
43503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf->flags |= SHF_EOF;
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
43903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
44003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Read a buffer from shf. Returns the number of bytes read into buf, if
44103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * no bytes were read, returns 0 if end of file was seen, EOF if a read
44203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * error occurred.
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
44403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
44503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_read(char *buf, ssize_t bsize, struct shf *shf)
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
44703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t ncopy, orig_bsize = bsize;
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_RD))
45003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_read", shf->flags);
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (bsize <= 0)
45303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s %zd", "shf_write", "bsize", bsize);
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (bsize > 0) {
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->rnleft == 0 &&
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ncopy = shf->rnleft;
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ncopy > bsize)
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ncopy = bsize;
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(buf, shf->rp, ncopy);
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		buf += ncopy;
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bsize -= ncopy;
4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp += ncopy;
4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rnleft -= ncopy;
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Note: fread(3S) returns 0 for errors - this doesn't */
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) :
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    orig_bsize - bsize);
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
47303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
47403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Read up to a newline or EOF. The newline is put in buf; buf is always
47503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * NUL terminated. Returns NULL on read error or if nothing was read
47603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * before end of file, returns a pointer to the NUL byte in buf
47703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * otherwise.
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
48003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_getse(char *buf, ssize_t bsize, struct shf *shf)
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned char *end;
48303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t ncopy;
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *orig_buf = buf;
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_RD))
48703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_getse", shf->flags);
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (bsize <= 0)
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
49203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* save room for NUL */
493c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	--bsize;
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->rnleft == 0) {
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (shf_fillbuf(shf) == EOF)
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (NULL);
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (shf->rnleft == 0) {
4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*buf = '\0';
5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (buf == orig_buf ? NULL : buf);
5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
50303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		end = (unsigned char *)memchr((char *)shf->rp, '\n',
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    shf->rnleft);
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ncopy > bsize)
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ncopy = bsize;
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(buf, (char *) shf->rp, ncopy);
5095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp += ncopy;
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rnleft -= ncopy;
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		buf += ncopy;
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bsize -= ncopy;
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while (!end && bsize);
5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*buf = '\0';
5155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (buf);
5165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Returns the char read. Returns EOF for error and end of file. */
5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_getchar(struct shf *shf)
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_RD))
52303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_getchar", shf->flags);
5245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	--shf->rnleft;
5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (*shf->rp++);
5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
53103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
53203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Put a character back in the input stream. Returns the character if
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * successful, EOF if there is no room.
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_ungetc(int c, struct shf *shf)
5375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_RD))
53903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_ungetc", shf->flags);
5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((shf->flags & SHF_ERROR) || c == EOF ||
5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (shf->rp == shf->buf && shf->rnleft))
5435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
5465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->rp == shf->buf)
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp = shf->buf + shf->rbsize;
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_STRING) {
55103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
55203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Can unget what was read, but not something different;
55303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * we don't want to modify a string.
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
555c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if ((int)(shf->rp[-1]) != c)
5565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (EOF);
5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->flags &= ~SHF_EOF;
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rp--;
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->rnleft++;
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (c);
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->flags &= ~SHF_EOF;
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*--(shf->rp) = c;
5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf->rnleft++;
5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (c);
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
56803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
56903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write a character. Returns the character if successful, EOF if the
57003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * char could not be written.
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_putchar(int c, struct shf *shf)
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_WR))
57603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_putchar", shf->flags);
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == EOF)
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf->flags & SHF_UNBUF) {
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unsigned char cc = (unsigned char)c;
58303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ssize_t n;
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->fd < 0)
58603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			internal_errorf("%s: %s", "shf_putchar", "no fd");
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->flags & SHF_ERROR) {
58803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errno = shf->errnosv;
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (EOF);
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((n = write(shf->fd, &cc, 1)) != 1)
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (n < 0) {
5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (errno == EINTR &&
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    !(shf->flags & SHF_INTERRUPT))
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					continue;
5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf->flags |= SHF_ERROR;
59703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				shf->errnosv = errno;
5985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (EOF);
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Flush deals with strings and sticky errors */
6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF)
6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (EOF);
6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft--;
6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*shf->wp++ = c;
6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (c);
6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
61103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
61203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Write a string. Returns the length of the string if successful, EOF
61303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * if the string could not be written.
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
61503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_puts(const char *s, struct shf *shf)
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!s)
6195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (EOF);
6205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf_write(s, strlen(s), shf));
6225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */
62503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
62603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_write(const char *buf, ssize_t nbytes, struct shf *shf)
6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
62803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t n, ncopy, orig_nbytes = nbytes;
6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf->flags & SHF_WR))
63103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: flags 0x%X", "shf_write", shf->flags);
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nbytes < 0)
63403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("%s: %s %zd", "shf_write", "nbytes", nbytes);
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Don't buffer if buffer is empty and we're writting a large amount. */
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((ncopy = shf->wnleft) &&
6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ncopy > nbytes)
6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ncopy = nbytes;
6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(shf->wp, buf, ncopy);
6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nbytes -= ncopy;
6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		buf += ncopy;
6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wp += ncopy;
6455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf->wnleft -= ncopy;
6465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nbytes > 0) {
6485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf->flags & SHF_STRING) {
6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* resize buffer until there's enough space left */
6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (nbytes > shf->wnleft)
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (shf_emptybuf(shf, EB_GROW) == EOF)
6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (EOF);
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* then write everything into the buffer */
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
6555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* flush deals with sticky errors */
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (shf_emptybuf(shf, EB_GROW) == EOF)
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (EOF);
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* write chunks larger than window size directly */
6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (nbytes > shf->wbsize) {
6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ncopy = nbytes;
6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (shf->wbsize)
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					ncopy -= nbytes % shf->wbsize;
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				nbytes -= ncopy;
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while (ncopy > 0) {
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					n = write(shf->fd, buf, ncopy);
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (n < 0) {
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (errno == EINTR &&
6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						    !(shf->flags & SHF_INTERRUPT))
6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							continue;
6705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf->flags |= SHF_ERROR;
67103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						shf->errnosv = errno;
6725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf->wnleft = 0;
6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						/*
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * Note: fwrite(3) returns 0
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 * for errors - this doesn't
6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						 */
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						return (EOF);
6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					buf += n;
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					ncopy -= n;
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* ... and buffer the rest */
6845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (nbytes > 0) {
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* write remaining bytes to buffer */
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(shf->wp, buf, nbytes);
6885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->wp += nbytes;
6895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf->wnleft -= nbytes;
6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (orig_nbytes);
6945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
69603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_fprintf(struct shf *shf, const char *fmt, ...)
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_list args;
70003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t n;
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_start(args, fmt);
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	n = shf_vfprintf(shf, fmt, args);
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_end(args);
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (n);
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
70903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
71003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrashf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct shf shf;
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_list args;
71403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t n;
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!buf || bsize <= 0)
71703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
71803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (size_t)buf, bsize);
7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_sopen(buf, bsize, SHF_WR, &shf);
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_start(args, fmt);
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	n = shf_vfprintf(&shf, fmt, args);
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_end(args);
72403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* NUL terminates */
725c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	shf_sclose(&shf);
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (n);
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_smprintf(const char *fmt, ...)
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct shf shf;
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_list args;
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
7365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_start(args, fmt);
7375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_vfprintf(&shf, fmt, args);
7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	va_end(args);
73903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* NUL terminates */
74003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (shf_sclose(&shf));
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define BUF_SIZE	128
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define	FL_HASH		0x001	/* '#' seen */
7465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_PLUS		0x002	/* '+' seen */
7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_RIGHT	0x004	/* '-' seen */
7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_BLANK	0x008	/* ' ' seen */
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_SHORT	0x010	/* 'h' seen */
7505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_LONG		0x020	/* 'l' seen */
7515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_ZERO		0x040	/* '0' seen */
7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_DOT		0x080	/* '.' seen */
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_UPPER	0x100	/* format character was uppercase */
7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
75503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define FL_SIZET	0x400	/* 'z' seen */
75603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define FM_SIZES	0x430	/* h/l/z mask */
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
75803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_vfprintf(struct shf *shf, const char *fmt, va_list args)
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s;
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char c, *cp;
76303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int tmp = 0, flags;
76403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t field, precision, len;
7655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned long lnum;
7665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* %#o produces the longest output */
767c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char numbuf[(8 * sizeof(long) + 2) / 3 + 1
768c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG
769c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* a NUL for LLVM/Clang scan-build */
770c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		+ 1
771c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
772c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    ];
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* this stuff for dealing with the buffer */
77403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t nwritten = 0;
77503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
77603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define VA(type) va_arg(args, type)
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!fmt)
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = *fmt++)) {
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c != '%') {
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_putc(c, shf);
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			nwritten++;
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
78803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * This will accept flags/fields in any order - not just
78903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * the order specified in printf(3), but this is the way
79003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * _doprnt() seems to work (on BSD and SYSV). The only
79103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * restriction is that the format character must come
79203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * last :-).
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
79403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		flags = 0;
79503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		field = precision = 0;
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for ( ; (c = *fmt++) ; ) {
7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (c) {
7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '#':
7995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_HASH;
8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '+':
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_PLUS;
8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '-':
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_RIGHT;
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case ' ':
8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_BLANK;
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '0':
8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (!(flags & FL_DOT))
8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					flags |= FL_ZERO;
8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '.':
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_DOT;
8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				precision = 0;
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case '*':
82503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tmp = VA(int);
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (flags & FL_DOT)
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					precision = tmp;
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if ((field = tmp) < 0) {
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					field = -field;
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					flags |= FL_RIGHT;
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'l':
83503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				flags &= ~FM_SIZES;
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_LONG;
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'h':
84003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				flags &= ~FM_SIZES;
8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				flags |= FL_SHORT;
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
84303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
84403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			case 'z':
84503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				flags &= ~FM_SIZES;
84603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				flags |= FL_SIZET;
84703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				continue;
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ksh_isdigit(c)) {
850c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				bool overflowed = false;
851c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tmp = c - '0';
853c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				while (c = *fmt++, ksh_isdigit(c)) {
854c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (notok2mul(2147483647, tmp, 10))
855c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						overflowed = true;
8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					tmp = tmp * 10 + c - '0';
857c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				}
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--fmt;
859c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (overflowed)
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					tmp = 0;
8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (flags & FL_DOT)
8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					precision = tmp;
8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else
8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					field = tmp;
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (precision < 0)
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			precision = 0;
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
87303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!c)
87403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* nasty format */
8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c >= 'A' && c <= 'Z') {
8785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= FL_UPPER;
8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = ksh_tolower(c);
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (c) {
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'd':
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'i':
88503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (flags & FL_SIZET)
88603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = (long)VA(ssize_t);
88703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (flags & FL_LONG)
88803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = VA(long);
88903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (flags & FL_SHORT)
89003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = (long)(short)VA(int);
89103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else
89203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = (long)VA(int);
89303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto integral;
89403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'o':
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'u':
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'x':
89803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (flags & FL_SIZET)
89903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = VA(size_t);
90003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (flags & FL_LONG)
90103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = VA(unsigned long);
90203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (flags & FL_SHORT)
90303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = (unsigned long)(unsigned short)VA(int);
90403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else
90503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				lnum = (unsigned long)VA(unsigned int);
90603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
90703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra integral:
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= FL_NUMBER;
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cp = numbuf + sizeof(numbuf);
910c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG
911c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/*
912c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * this is necessary so Clang 3.2 realises
913c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * utf_skipcols/shf_putc in the output loop
914c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * terminate; these values are always ASCII
915c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * so an out-of-bounds access cannot happen
916c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * but Clang doesn't know that
917c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 */
918c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			*--cp = '\0';
919c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
92003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (c) {
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'd':
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'i':
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (0 > (long)lnum) {
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					lnum = -(long)lnum;
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					tmp = 1;
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					tmp = 0;
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* FALLTHROUGH */
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'u':
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				do {
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = lnum % 10 + '0';
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					lnum /= 10;
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} while (lnum);
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (c != 'u') {
9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (tmp)
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*--cp = '-';
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					else if (flags & FL_PLUS)
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*--cp = '+';
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					else if (flags & FL_BLANK)
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						*--cp = ' ';
9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'o':
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				do {
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = (lnum & 0x7) + '0';
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					lnum >>= 3;
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} while (lnum);
9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((flags & FL_HASH) && *cp != '0')
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = '0';
9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case 'x': {
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				const char *digits = (flags & FL_UPPER) ?
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    digits_uc : digits_lc;
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				do {
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = digits[lnum & 0xf];
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					lnum >>= 4;
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} while (lnum);
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (flags & FL_HASH) {
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--cp = '0';
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			len = numbuf + sizeof(numbuf) - (s = cp);
971c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG
972c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* see above comment for Clang 3.2 */
973c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			--len;
974c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (flags & FL_DOT) {
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (precision > len) {
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					field = precision;
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					flags |= FL_ZERO;
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else
98003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* no loss */
98103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					precision = len;
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 's':
98603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if ((s = VA(const char *)) == NULL)
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s = "(null)";
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			len = utf_mbswidth(s);
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'c':
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags &= ~FL_DOT;
993c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			c = (char)(VA(int));
994c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '%':
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			numbuf[0] = c;
999c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			numbuf[1] = 0;
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = numbuf;
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			len = 1;
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
10065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * At this point s should point to a string that is to be
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * formatted, and len should be the length of the string.
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(flags & FL_DOT) || len < precision)
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			precision = len;
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (field > precision) {
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			field -= precision;
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(flags & FL_RIGHT)) {
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				field = -field;
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* skip past sign or 0x when padding with 0 */
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (*s == '+' || *s == '-' ||
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    *s == ' ') {
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf_putc(*s, shf);
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						s++;
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						precision--;
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						nwritten++;
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					} else if (*s == '0') {
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf_putc(*s, shf);
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						s++;
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						nwritten++;
10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (--precision > 0 &&
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						    (*s | 0x20) == 'x') {
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							shf_putc(*s, shf);
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							s++;
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							precision--;
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							nwritten++;
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						}
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					c = '0';
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					c = flags & FL_ZERO ? '0' : ' ';
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (field < 0) {
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					nwritten += -field;
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					for ( ; field < 0 ; field++)
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						shf_putc(c, shf);
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = ' ';
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			field = 0;
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (precision > 0) {
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			const char *q;
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			nwritten += precision;
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			q = utf_skipcols(s, precision);
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			do {
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_putc(*s, shf);
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} while (++s < q);
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (field > 0) {
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			nwritten += field;
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for ( ; field > 0 ; --field)
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_putc(c, shf);
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (shf_error(shf) ? EOF : nwritten);
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1067c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
10685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_getc(struct shf *shf)
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1071c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (shf_getc_i(shf));
10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushf_putc(int c, struct shf *shf)
10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1077c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (shf_putc_i(c, shf));
1078c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1079c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1080c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1081c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef DEBUG
1082c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char *
1083c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasercstrerror(int errnum)
1084c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1085c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#undef strerror
1086c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (strerror(errnum));
1087c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define strerror dontuse_strerror /* poisoned */
1088c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1089c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#elif !HAVE_STRERROR
1090c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1091c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_SYS_ERRLIST
1092c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if !HAVE_SYS_ERRLIST_DECL
1093c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserextern const int sys_nerr;
1094c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserextern const char * const sys_errlist[];
1095c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1096c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1097c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1098c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char *
1099c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasercstrerror(int errnum)
1100c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1101c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* "Unknown error: " + sign + rough estimate + NUL */
1102c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
1103c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1104c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_SYS_ERRLIST
1105c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
1106c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (sys_errlist[errnum]);
1107c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1108c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1109c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (errnum) {
1110c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case 0:
1111c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Undefined error: 0");
1112c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EPERM
1113c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case EPERM:
1114c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Operation not permitted");
1115c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1116c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOENT
1117c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ENOENT:
1118c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("No such file or directory");
1119c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1120c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ESRCH
1121c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ESRCH:
1122c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("No such process");
1123c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1124c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef E2BIG
1125c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case E2BIG:
1126c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Argument list too long");
1127c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1128c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOEXEC
1129c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ENOEXEC:
1130c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Exec format error");
1131c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1132c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOMEM
1133c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ENOMEM:
1134c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Cannot allocate memory");
1135c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1136c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EACCES
1137c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case EACCES:
1138c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Permission denied");
1139c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1140c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ENOTDIR
1141c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ENOTDIR:
1142c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Not a directory");
1143c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1144c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef EINVAL
1145c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case EINVAL:
1146c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Invalid argument");
1147c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1148c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef ELOOP
1149c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case ELOOP:
1150c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ("Too many levels of symbolic links");
1151c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1152c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	default:
1153c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		shf_snprintf(errbuf, sizeof(errbuf),
1154c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    "Unknown error: %d", errnum);
1155c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (errbuf);
1156c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
1159