xref: /aosp_15_r20/external/mksh/src/shf.c (revision 7c356e860f31eadd15fd599fcfdb9fd21f16a9d4)
1*7c356e86SAndroid Build Coastguard Worker /*	$OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $	*/
2*7c356e86SAndroid Build Coastguard Worker 
3*7c356e86SAndroid Build Coastguard Worker /*-
4*7c356e86SAndroid Build Coastguard Worker  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5*7c356e86SAndroid Build Coastguard Worker  *		 2012, 2013, 2015, 2016, 2017, 2018, 2019
6*7c356e86SAndroid Build Coastguard Worker  *	mirabilos <[email protected]>
7*7c356e86SAndroid Build Coastguard Worker  * Copyright (c) 2015
8*7c356e86SAndroid Build Coastguard Worker  *	Daniel Richard G. <[email protected]>
9*7c356e86SAndroid Build Coastguard Worker  *
10*7c356e86SAndroid Build Coastguard Worker  * Provided that these terms and disclaimer and all copyright notices
11*7c356e86SAndroid Build Coastguard Worker  * are retained or reproduced in an accompanying document, permission
12*7c356e86SAndroid Build Coastguard Worker  * is granted to deal in this work without restriction, including un-
13*7c356e86SAndroid Build Coastguard Worker  * limited rights to use, publicly perform, distribute, sell, modify,
14*7c356e86SAndroid Build Coastguard Worker  * merge, give away, or sublicence.
15*7c356e86SAndroid Build Coastguard Worker  *
16*7c356e86SAndroid Build Coastguard Worker  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
17*7c356e86SAndroid Build Coastguard Worker  * the utmost extent permitted by applicable law, neither express nor
18*7c356e86SAndroid Build Coastguard Worker  * implied; without malicious intent or gross negligence. In no event
19*7c356e86SAndroid Build Coastguard Worker  * may a licensor, author or contributor be held liable for indirect,
20*7c356e86SAndroid Build Coastguard Worker  * direct, other damage, loss, or other issues arising in any way out
21*7c356e86SAndroid Build Coastguard Worker  * of dealing in the work, even if advised of the possibility of such
22*7c356e86SAndroid Build Coastguard Worker  * damage or existence of a defect, except proven that it results out
23*7c356e86SAndroid Build Coastguard Worker  * of said person's immediate fault when using the work as intended.
24*7c356e86SAndroid Build Coastguard Worker  *-
25*7c356e86SAndroid Build Coastguard Worker  * Use %zX instead of %p and floating point isn't supported at all.
26*7c356e86SAndroid Build Coastguard Worker  */
27*7c356e86SAndroid Build Coastguard Worker 
28*7c356e86SAndroid Build Coastguard Worker #include "sh.h"
29*7c356e86SAndroid Build Coastguard Worker 
30*7c356e86SAndroid Build Coastguard Worker __RCSID("$MirOS: src/bin/mksh/shf.c,v 1.102 2020/06/22 17:11:03 tg Exp $");
31*7c356e86SAndroid Build Coastguard Worker 
32*7c356e86SAndroid Build Coastguard Worker /* flags to shf_emptybuf() */
33*7c356e86SAndroid Build Coastguard Worker #define EB_READSW	0x01	/* about to switch to reading */
34*7c356e86SAndroid Build Coastguard Worker #define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
35*7c356e86SAndroid Build Coastguard Worker 
36*7c356e86SAndroid Build Coastguard Worker /*
37*7c356e86SAndroid Build Coastguard Worker  * Replacement stdio routines. Stdio is too flakey on too many machines
38*7c356e86SAndroid Build Coastguard Worker  * to be useful when you have multiple processes using the same underlying
39*7c356e86SAndroid Build Coastguard Worker  * file descriptors.
40*7c356e86SAndroid Build Coastguard Worker  */
41*7c356e86SAndroid Build Coastguard Worker 
42*7c356e86SAndroid Build Coastguard Worker static int shf_fillbuf(struct shf *);
43*7c356e86SAndroid Build Coastguard Worker static int shf_emptybuf(struct shf *, int);
44*7c356e86SAndroid Build Coastguard Worker 
45*7c356e86SAndroid Build Coastguard Worker /*
46*7c356e86SAndroid Build Coastguard Worker  * Open a file. First three args are for open(), last arg is flags for
47*7c356e86SAndroid Build Coastguard Worker  * this package. Returns NULL if file could not be opened, or if a dup
48*7c356e86SAndroid Build Coastguard Worker  * fails.
49*7c356e86SAndroid Build Coastguard Worker  */
50*7c356e86SAndroid Build Coastguard Worker struct shf *
shf_open(const char * name,int oflags,int mode,int sflags)51*7c356e86SAndroid Build Coastguard Worker shf_open(const char *name, int oflags, int mode, int sflags)
52*7c356e86SAndroid Build Coastguard Worker {
53*7c356e86SAndroid Build Coastguard Worker 	struct shf *shf;
54*7c356e86SAndroid Build Coastguard Worker 	ssize_t bsize =
55*7c356e86SAndroid Build Coastguard Worker 	    /* at most 512 */
56*7c356e86SAndroid Build Coastguard Worker 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
57*7c356e86SAndroid Build Coastguard Worker 	int fd, eno;
58*7c356e86SAndroid Build Coastguard Worker 
59*7c356e86SAndroid Build Coastguard Worker 	/* Done before open so if alloca fails, fd won't be lost. */
60*7c356e86SAndroid Build Coastguard Worker 	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
61*7c356e86SAndroid Build Coastguard Worker 	shf->areap = ATEMP;
62*7c356e86SAndroid Build Coastguard Worker 	shf->buf = (unsigned char *)&shf[1];
63*7c356e86SAndroid Build Coastguard Worker 	shf->bsize = bsize;
64*7c356e86SAndroid Build Coastguard Worker 	shf->flags = SHF_ALLOCS;
65*7c356e86SAndroid Build Coastguard Worker 	/* Rest filled in by reopen. */
66*7c356e86SAndroid Build Coastguard Worker 
67*7c356e86SAndroid Build Coastguard Worker 	fd = binopen3(name, oflags, mode);
68*7c356e86SAndroid Build Coastguard Worker 	if (fd < 0) {
69*7c356e86SAndroid Build Coastguard Worker 		eno = errno;
70*7c356e86SAndroid Build Coastguard Worker 		afree(shf, shf->areap);
71*7c356e86SAndroid Build Coastguard Worker 		errno = eno;
72*7c356e86SAndroid Build Coastguard Worker 		return (NULL);
73*7c356e86SAndroid Build Coastguard Worker 	}
74*7c356e86SAndroid Build Coastguard Worker 	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
75*7c356e86SAndroid Build Coastguard Worker 		int nfd;
76*7c356e86SAndroid Build Coastguard Worker 
77*7c356e86SAndroid Build Coastguard Worker 		nfd = fcntl(fd, F_DUPFD, FDBASE);
78*7c356e86SAndroid Build Coastguard Worker 		eno = errno;
79*7c356e86SAndroid Build Coastguard Worker 		close(fd);
80*7c356e86SAndroid Build Coastguard Worker 		if (nfd < 0) {
81*7c356e86SAndroid Build Coastguard Worker 			afree(shf, shf->areap);
82*7c356e86SAndroid Build Coastguard Worker 			errno = eno;
83*7c356e86SAndroid Build Coastguard Worker 			return (NULL);
84*7c356e86SAndroid Build Coastguard Worker 		}
85*7c356e86SAndroid Build Coastguard Worker 		fd = nfd;
86*7c356e86SAndroid Build Coastguard Worker 	}
87*7c356e86SAndroid Build Coastguard Worker 	sflags &= ~SHF_ACCMODE;
88*7c356e86SAndroid Build Coastguard Worker 	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD :
89*7c356e86SAndroid Build Coastguard Worker 	    ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR);
90*7c356e86SAndroid Build Coastguard Worker 
91*7c356e86SAndroid Build Coastguard Worker 	return (shf_reopen(fd, sflags, shf));
92*7c356e86SAndroid Build Coastguard Worker }
93*7c356e86SAndroid Build Coastguard Worker 
94*7c356e86SAndroid Build Coastguard Worker /* helper function for shf_fdopen and shf_reopen */
95*7c356e86SAndroid Build Coastguard Worker static void
shf_open_hlp(int fd,int * sflagsp,const char * where)96*7c356e86SAndroid Build Coastguard Worker shf_open_hlp(int fd, int *sflagsp, const char *where)
97*7c356e86SAndroid Build Coastguard Worker {
98*7c356e86SAndroid Build Coastguard Worker 	int sflags = *sflagsp;
99*7c356e86SAndroid Build Coastguard Worker 
100*7c356e86SAndroid Build Coastguard Worker 	/* use fcntl() to figure out correct read/write flags */
101*7c356e86SAndroid Build Coastguard Worker 	if (sflags & SHF_GETFL) {
102*7c356e86SAndroid Build Coastguard Worker 		int flags = fcntl(fd, F_GETFL, 0);
103*7c356e86SAndroid Build Coastguard Worker 
104*7c356e86SAndroid Build Coastguard Worker 		if (flags < 0)
105*7c356e86SAndroid Build Coastguard Worker 			/* will get an error on first read/write */
106*7c356e86SAndroid Build Coastguard Worker 			sflags |= SHF_RDWR;
107*7c356e86SAndroid Build Coastguard Worker 		else {
108*7c356e86SAndroid Build Coastguard Worker 			switch (flags & O_ACCMODE) {
109*7c356e86SAndroid Build Coastguard Worker 			case O_RDONLY:
110*7c356e86SAndroid Build Coastguard Worker 				sflags |= SHF_RD;
111*7c356e86SAndroid Build Coastguard Worker 				break;
112*7c356e86SAndroid Build Coastguard Worker 			case O_WRONLY:
113*7c356e86SAndroid Build Coastguard Worker 				sflags |= SHF_WR;
114*7c356e86SAndroid Build Coastguard Worker 				break;
115*7c356e86SAndroid Build Coastguard Worker 			case O_RDWR:
116*7c356e86SAndroid Build Coastguard Worker 				sflags |= SHF_RDWR;
117*7c356e86SAndroid Build Coastguard Worker 				break;
118*7c356e86SAndroid Build Coastguard Worker 			}
119*7c356e86SAndroid Build Coastguard Worker 		}
120*7c356e86SAndroid Build Coastguard Worker 		*sflagsp = sflags;
121*7c356e86SAndroid Build Coastguard Worker 	}
122*7c356e86SAndroid Build Coastguard Worker 
123*7c356e86SAndroid Build Coastguard Worker 	if (!(sflags & (SHF_RD | SHF_WR)))
124*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_sD_s, where, "missing read/write");
125*7c356e86SAndroid Build Coastguard Worker }
126*7c356e86SAndroid Build Coastguard Worker 
127*7c356e86SAndroid Build Coastguard Worker /* Set up the shf structure for a file descriptor. Doesn't fail. */
128*7c356e86SAndroid Build Coastguard Worker struct shf *
shf_fdopen(int fd,int sflags,struct shf * shf)129*7c356e86SAndroid Build Coastguard Worker shf_fdopen(int fd, int sflags, struct shf *shf)
130*7c356e86SAndroid Build Coastguard Worker {
131*7c356e86SAndroid Build Coastguard Worker 	ssize_t bsize =
132*7c356e86SAndroid Build Coastguard Worker 	    /* at most 512 */
133*7c356e86SAndroid Build Coastguard Worker 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
134*7c356e86SAndroid Build Coastguard Worker 
135*7c356e86SAndroid Build Coastguard Worker 	shf_open_hlp(fd, &sflags, "shf_fdopen");
136*7c356e86SAndroid Build Coastguard Worker 	if (shf) {
137*7c356e86SAndroid Build Coastguard Worker 		if (bsize) {
138*7c356e86SAndroid Build Coastguard Worker 			shf->buf = alloc(bsize, ATEMP);
139*7c356e86SAndroid Build Coastguard Worker 			sflags |= SHF_ALLOCB;
140*7c356e86SAndroid Build Coastguard Worker 		} else
141*7c356e86SAndroid Build Coastguard Worker 			shf->buf = NULL;
142*7c356e86SAndroid Build Coastguard Worker 	} else {
143*7c356e86SAndroid Build Coastguard Worker 		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
144*7c356e86SAndroid Build Coastguard Worker 		shf->buf = (unsigned char *)&shf[1];
145*7c356e86SAndroid Build Coastguard Worker 		sflags |= SHF_ALLOCS;
146*7c356e86SAndroid Build Coastguard Worker 	}
147*7c356e86SAndroid Build Coastguard Worker 	shf->areap = ATEMP;
148*7c356e86SAndroid Build Coastguard Worker 	shf->fd = fd;
149*7c356e86SAndroid Build Coastguard Worker 	shf->rp = shf->wp = shf->buf;
150*7c356e86SAndroid Build Coastguard Worker 	shf->rnleft = 0;
151*7c356e86SAndroid Build Coastguard Worker 	shf->rbsize = bsize;
152*7c356e86SAndroid Build Coastguard Worker 	shf->wnleft = 0; /* force call to shf_emptybuf() */
153*7c356e86SAndroid Build Coastguard Worker 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
154*7c356e86SAndroid Build Coastguard Worker 	shf->flags = sflags;
155*7c356e86SAndroid Build Coastguard Worker 	shf->errnosv = 0;
156*7c356e86SAndroid Build Coastguard Worker 	shf->bsize = bsize;
157*7c356e86SAndroid Build Coastguard Worker 	if (sflags & SHF_CLEXEC)
158*7c356e86SAndroid Build Coastguard Worker 		fcntl(fd, F_SETFD, FD_CLOEXEC);
159*7c356e86SAndroid Build Coastguard Worker 	return (shf);
160*7c356e86SAndroid Build Coastguard Worker }
161*7c356e86SAndroid Build Coastguard Worker 
162*7c356e86SAndroid Build Coastguard Worker /* Set up an existing shf (and buffer) to use the given fd */
163*7c356e86SAndroid Build Coastguard Worker struct shf *
shf_reopen(int fd,int sflags,struct shf * shf)164*7c356e86SAndroid Build Coastguard Worker shf_reopen(int fd, int sflags, struct shf *shf)
165*7c356e86SAndroid Build Coastguard Worker {
166*7c356e86SAndroid Build Coastguard Worker 	ssize_t bsize =
167*7c356e86SAndroid Build Coastguard Worker 	    /* at most 512 */
168*7c356e86SAndroid Build Coastguard Worker 	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
169*7c356e86SAndroid Build Coastguard Worker 
170*7c356e86SAndroid Build Coastguard Worker 	shf_open_hlp(fd, &sflags, "shf_reopen");
171*7c356e86SAndroid Build Coastguard Worker 	if (!shf || !shf->buf || shf->bsize < bsize)
172*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
173*7c356e86SAndroid Build Coastguard Worker 
174*7c356e86SAndroid Build Coastguard Worker 	/* assumes shf->buf and shf->bsize already set up */
175*7c356e86SAndroid Build Coastguard Worker 	shf->fd = fd;
176*7c356e86SAndroid Build Coastguard Worker 	shf->rp = shf->wp = shf->buf;
177*7c356e86SAndroid Build Coastguard Worker 	shf->rnleft = 0;
178*7c356e86SAndroid Build Coastguard Worker 	shf->rbsize = bsize;
179*7c356e86SAndroid Build Coastguard Worker 	shf->wnleft = 0; /* force call to shf_emptybuf() */
180*7c356e86SAndroid Build Coastguard Worker 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
181*7c356e86SAndroid Build Coastguard Worker 	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
182*7c356e86SAndroid Build Coastguard Worker 	shf->errnosv = 0;
183*7c356e86SAndroid Build Coastguard Worker 	if (sflags & SHF_CLEXEC)
184*7c356e86SAndroid Build Coastguard Worker 		fcntl(fd, F_SETFD, FD_CLOEXEC);
185*7c356e86SAndroid Build Coastguard Worker 	return (shf);
186*7c356e86SAndroid Build Coastguard Worker }
187*7c356e86SAndroid Build Coastguard Worker 
188*7c356e86SAndroid Build Coastguard Worker /*
189*7c356e86SAndroid Build Coastguard Worker  * Open a string for reading or writing. If reading, bsize is the number
190*7c356e86SAndroid Build Coastguard Worker  * of bytes that can be read. If writing, bsize is the maximum number of
191*7c356e86SAndroid Build Coastguard Worker  * bytes that can be written. If shf is not NULL, it is filled in and
192*7c356e86SAndroid Build Coastguard Worker  * returned, if it is NULL, shf is allocated. If writing and buf is NULL
193*7c356e86SAndroid Build Coastguard Worker  * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
194*7c356e86SAndroid Build Coastguard Worker  * used for the initial size). Doesn't fail.
195*7c356e86SAndroid Build Coastguard Worker  * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
196*7c356e86SAndroid Build Coastguard Worker  */
197*7c356e86SAndroid Build Coastguard Worker struct shf *
shf_sopen(char * buf,ssize_t bsize,int sflags,struct shf * shf)198*7c356e86SAndroid Build Coastguard Worker shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
199*7c356e86SAndroid Build Coastguard Worker {
200*7c356e86SAndroid Build Coastguard Worker 	/* can't have a read+write string */
201*7c356e86SAndroid Build Coastguard Worker 	if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
202*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, "shf_sopen",
203*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)sflags);
204*7c356e86SAndroid Build Coastguard Worker 
205*7c356e86SAndroid Build Coastguard Worker 	if (!shf) {
206*7c356e86SAndroid Build Coastguard Worker 		shf = alloc(sizeof(struct shf), ATEMP);
207*7c356e86SAndroid Build Coastguard Worker 		sflags |= SHF_ALLOCS;
208*7c356e86SAndroid Build Coastguard Worker 	}
209*7c356e86SAndroid Build Coastguard Worker 	shf->areap = ATEMP;
210*7c356e86SAndroid Build Coastguard Worker 	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
211*7c356e86SAndroid Build Coastguard Worker 		if (bsize <= 0)
212*7c356e86SAndroid Build Coastguard Worker 			bsize = 64;
213*7c356e86SAndroid Build Coastguard Worker 		sflags |= SHF_ALLOCB;
214*7c356e86SAndroid Build Coastguard Worker 		buf = alloc(bsize, shf->areap);
215*7c356e86SAndroid Build Coastguard Worker 	}
216*7c356e86SAndroid Build Coastguard Worker 	shf->fd = -1;
217*7c356e86SAndroid Build Coastguard Worker 	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
218*7c356e86SAndroid Build Coastguard Worker 	shf->rnleft = bsize;
219*7c356e86SAndroid Build Coastguard Worker 	shf->rbsize = bsize;
220*7c356e86SAndroid Build Coastguard Worker 	shf->wnleft = bsize - 1;	/* space for a '\0' */
221*7c356e86SAndroid Build Coastguard Worker 	shf->wbsize = bsize;
222*7c356e86SAndroid Build Coastguard Worker 	shf->flags = sflags | SHF_STRING;
223*7c356e86SAndroid Build Coastguard Worker 	shf->errnosv = 0;
224*7c356e86SAndroid Build Coastguard Worker 	shf->bsize = bsize;
225*7c356e86SAndroid Build Coastguard Worker 
226*7c356e86SAndroid Build Coastguard Worker 	return (shf);
227*7c356e86SAndroid Build Coastguard Worker }
228*7c356e86SAndroid Build Coastguard Worker 
229*7c356e86SAndroid Build Coastguard Worker /* Flush and close file descriptor, free the shf structure */
230*7c356e86SAndroid Build Coastguard Worker int
shf_close(struct shf * shf)231*7c356e86SAndroid Build Coastguard Worker shf_close(struct shf *shf)
232*7c356e86SAndroid Build Coastguard Worker {
233*7c356e86SAndroid Build Coastguard Worker 	int ret = 0;
234*7c356e86SAndroid Build Coastguard Worker 
235*7c356e86SAndroid Build Coastguard Worker 	if (shf->fd >= 0) {
236*7c356e86SAndroid Build Coastguard Worker 		ret = shf_flush(shf);
237*7c356e86SAndroid Build Coastguard Worker 		if (close(shf->fd) < 0)
238*7c356e86SAndroid Build Coastguard Worker 			ret = -1;
239*7c356e86SAndroid Build Coastguard Worker 	}
240*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_ALLOCS)
241*7c356e86SAndroid Build Coastguard Worker 		afree(shf, shf->areap);
242*7c356e86SAndroid Build Coastguard Worker 	else if (shf->flags & SHF_ALLOCB)
243*7c356e86SAndroid Build Coastguard Worker 		afree(shf->buf, shf->areap);
244*7c356e86SAndroid Build Coastguard Worker 
245*7c356e86SAndroid Build Coastguard Worker 	return (ret);
246*7c356e86SAndroid Build Coastguard Worker }
247*7c356e86SAndroid Build Coastguard Worker 
248*7c356e86SAndroid Build Coastguard Worker /* Flush and close file descriptor, don't free file structure */
249*7c356e86SAndroid Build Coastguard Worker int
shf_fdclose(struct shf * shf)250*7c356e86SAndroid Build Coastguard Worker shf_fdclose(struct shf *shf)
251*7c356e86SAndroid Build Coastguard Worker {
252*7c356e86SAndroid Build Coastguard Worker 	int ret = 0;
253*7c356e86SAndroid Build Coastguard Worker 
254*7c356e86SAndroid Build Coastguard Worker 	if (shf->fd >= 0) {
255*7c356e86SAndroid Build Coastguard Worker 		ret = shf_flush(shf);
256*7c356e86SAndroid Build Coastguard Worker 		if (close(shf->fd) < 0)
257*7c356e86SAndroid Build Coastguard Worker 			ret = -1;
258*7c356e86SAndroid Build Coastguard Worker 		shf->rnleft = 0;
259*7c356e86SAndroid Build Coastguard Worker 		shf->rp = shf->buf;
260*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft = 0;
261*7c356e86SAndroid Build Coastguard Worker 		shf->fd = -1;
262*7c356e86SAndroid Build Coastguard Worker 	}
263*7c356e86SAndroid Build Coastguard Worker 
264*7c356e86SAndroid Build Coastguard Worker 	return (ret);
265*7c356e86SAndroid Build Coastguard Worker }
266*7c356e86SAndroid Build Coastguard Worker 
267*7c356e86SAndroid Build Coastguard Worker /*
268*7c356e86SAndroid Build Coastguard Worker  * Close a string - if it was opened for writing, it is NUL terminated;
269*7c356e86SAndroid Build Coastguard Worker  * returns a pointer to the string and frees shf if it was allocated
270*7c356e86SAndroid Build Coastguard Worker  * (does not free string if it was allocated).
271*7c356e86SAndroid Build Coastguard Worker  */
272*7c356e86SAndroid Build Coastguard Worker char *
shf_sclose(struct shf * shf)273*7c356e86SAndroid Build Coastguard Worker shf_sclose(struct shf *shf)
274*7c356e86SAndroid Build Coastguard Worker {
275*7c356e86SAndroid Build Coastguard Worker 	unsigned char *s = shf->buf;
276*7c356e86SAndroid Build Coastguard Worker 
277*7c356e86SAndroid Build Coastguard Worker 	/* NUL terminate */
278*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_WR) {
279*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft++;
280*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\0', shf);
281*7c356e86SAndroid Build Coastguard Worker 	}
282*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_ALLOCS)
283*7c356e86SAndroid Build Coastguard Worker 		afree(shf, shf->areap);
284*7c356e86SAndroid Build Coastguard Worker 	return ((char *)s);
285*7c356e86SAndroid Build Coastguard Worker }
286*7c356e86SAndroid Build Coastguard Worker 
287*7c356e86SAndroid Build Coastguard Worker /*
288*7c356e86SAndroid Build Coastguard Worker  * Un-read what has been read but not examined, or write what has been
289*7c356e86SAndroid Build Coastguard Worker  * buffered. Returns 0 for success, -1 for (write) error.
290*7c356e86SAndroid Build Coastguard Worker  */
291*7c356e86SAndroid Build Coastguard Worker int
shf_flush(struct shf * shf)292*7c356e86SAndroid Build Coastguard Worker shf_flush(struct shf *shf)
293*7c356e86SAndroid Build Coastguard Worker {
294*7c356e86SAndroid Build Coastguard Worker 	int rv = 0;
295*7c356e86SAndroid Build Coastguard Worker 
296*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_STRING)
297*7c356e86SAndroid Build Coastguard Worker 		rv = (shf->flags & SHF_WR) ? -1 : 0;
298*7c356e86SAndroid Build Coastguard Worker 	else if (shf->fd < 0)
299*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_sD_s, "shf_flush", "no fd");
300*7c356e86SAndroid Build Coastguard Worker 	else if (shf->flags & SHF_ERROR) {
301*7c356e86SAndroid Build Coastguard Worker 		errno = shf->errnosv;
302*7c356e86SAndroid Build Coastguard Worker 		rv = -1;
303*7c356e86SAndroid Build Coastguard Worker 	} else if (shf->flags & SHF_READING) {
304*7c356e86SAndroid Build Coastguard Worker 		shf->flags &= ~(SHF_EOF | SHF_READING);
305*7c356e86SAndroid Build Coastguard Worker 		if (shf->rnleft > 0) {
306*7c356e86SAndroid Build Coastguard Worker 			if (lseek(shf->fd, (off_t)-shf->rnleft,
307*7c356e86SAndroid Build Coastguard Worker 			    SEEK_CUR) == -1) {
308*7c356e86SAndroid Build Coastguard Worker 				shf->flags |= SHF_ERROR;
309*7c356e86SAndroid Build Coastguard Worker 				shf->errnosv = errno;
310*7c356e86SAndroid Build Coastguard Worker 				rv = -1;
311*7c356e86SAndroid Build Coastguard Worker 			}
312*7c356e86SAndroid Build Coastguard Worker 			shf->rnleft = 0;
313*7c356e86SAndroid Build Coastguard Worker 			shf->rp = shf->buf;
314*7c356e86SAndroid Build Coastguard Worker 		}
315*7c356e86SAndroid Build Coastguard Worker 	} else if (shf->flags & SHF_WRITING)
316*7c356e86SAndroid Build Coastguard Worker 		rv = shf_emptybuf(shf, 0);
317*7c356e86SAndroid Build Coastguard Worker 
318*7c356e86SAndroid Build Coastguard Worker 	return (rv);
319*7c356e86SAndroid Build Coastguard Worker }
320*7c356e86SAndroid Build Coastguard Worker 
321*7c356e86SAndroid Build Coastguard Worker /*
322*7c356e86SAndroid Build Coastguard Worker  * Write out any buffered data. If currently reading, flushes the read
323*7c356e86SAndroid Build Coastguard Worker  * buffer. Returns 0 for success, -1 for (write) error.
324*7c356e86SAndroid Build Coastguard Worker  */
325*7c356e86SAndroid Build Coastguard Worker static int
shf_emptybuf(struct shf * shf,int flags)326*7c356e86SAndroid Build Coastguard Worker shf_emptybuf(struct shf *shf, int flags)
327*7c356e86SAndroid Build Coastguard Worker {
328*7c356e86SAndroid Build Coastguard Worker 	int ret = 0;
329*7c356e86SAndroid Build Coastguard Worker 
330*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
331*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
332*7c356e86SAndroid Build Coastguard Worker 
333*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_ERROR) {
334*7c356e86SAndroid Build Coastguard Worker 		errno = shf->errnosv;
335*7c356e86SAndroid Build Coastguard Worker 		return (-1);
336*7c356e86SAndroid Build Coastguard Worker 	}
337*7c356e86SAndroid Build Coastguard Worker 
338*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_READING) {
339*7c356e86SAndroid Build Coastguard Worker 		if (flags & EB_READSW)
340*7c356e86SAndroid Build Coastguard Worker 			/* doesn't happen */
341*7c356e86SAndroid Build Coastguard Worker 			return (0);
342*7c356e86SAndroid Build Coastguard Worker 		ret = shf_flush(shf);
343*7c356e86SAndroid Build Coastguard Worker 		shf->flags &= ~SHF_READING;
344*7c356e86SAndroid Build Coastguard Worker 	}
345*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_STRING) {
346*7c356e86SAndroid Build Coastguard Worker 		unsigned char *nbuf;
347*7c356e86SAndroid Build Coastguard Worker 
348*7c356e86SAndroid Build Coastguard Worker 		/*
349*7c356e86SAndroid Build Coastguard Worker 		 * Note that we assume SHF_ALLOCS is not set if
350*7c356e86SAndroid Build Coastguard Worker 		 * SHF_ALLOCB is set... (changing the shf pointer could
351*7c356e86SAndroid Build Coastguard Worker 		 * cause problems)
352*7c356e86SAndroid Build Coastguard Worker 		 */
353*7c356e86SAndroid Build Coastguard Worker 		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
354*7c356e86SAndroid Build Coastguard Worker 		    !(shf->flags & SHF_ALLOCB))
355*7c356e86SAndroid Build Coastguard Worker 			return (-1);
356*7c356e86SAndroid Build Coastguard Worker 		/* allocate more space for buffer */
357*7c356e86SAndroid Build Coastguard Worker 		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
358*7c356e86SAndroid Build Coastguard Worker 		shf->rp = nbuf + (shf->rp - shf->buf);
359*7c356e86SAndroid Build Coastguard Worker 		shf->wp = nbuf + (shf->wp - shf->buf);
360*7c356e86SAndroid Build Coastguard Worker 		shf->rbsize += shf->wbsize;
361*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft += shf->wbsize;
362*7c356e86SAndroid Build Coastguard Worker 		shf->wbsize <<= 1;
363*7c356e86SAndroid Build Coastguard Worker 		shf->buf = nbuf;
364*7c356e86SAndroid Build Coastguard Worker 	} else {
365*7c356e86SAndroid Build Coastguard Worker 		if (shf->flags & SHF_WRITING) {
366*7c356e86SAndroid Build Coastguard Worker 			ssize_t n, ntowrite = shf->wp - shf->buf;
367*7c356e86SAndroid Build Coastguard Worker 			unsigned char *buf = shf->buf;
368*7c356e86SAndroid Build Coastguard Worker 
369*7c356e86SAndroid Build Coastguard Worker 			while (ntowrite > 0) {
370*7c356e86SAndroid Build Coastguard Worker 				n = write(shf->fd, buf, ntowrite);
371*7c356e86SAndroid Build Coastguard Worker 				if (n < 0) {
372*7c356e86SAndroid Build Coastguard Worker 					if (errno == EINTR &&
373*7c356e86SAndroid Build Coastguard Worker 					    !(shf->flags & SHF_INTERRUPT))
374*7c356e86SAndroid Build Coastguard Worker 						continue;
375*7c356e86SAndroid Build Coastguard Worker 					shf->flags |= SHF_ERROR;
376*7c356e86SAndroid Build Coastguard Worker 					shf->errnosv = errno;
377*7c356e86SAndroid Build Coastguard Worker 					shf->wnleft = 0;
378*7c356e86SAndroid Build Coastguard Worker 					if (buf != shf->buf) {
379*7c356e86SAndroid Build Coastguard Worker 						/*
380*7c356e86SAndroid Build Coastguard Worker 						 * allow a second flush
381*7c356e86SAndroid Build Coastguard Worker 						 * to work
382*7c356e86SAndroid Build Coastguard Worker 						 */
383*7c356e86SAndroid Build Coastguard Worker 						memmove(shf->buf, buf,
384*7c356e86SAndroid Build Coastguard Worker 						    ntowrite);
385*7c356e86SAndroid Build Coastguard Worker 						shf->wp = shf->buf + ntowrite;
386*7c356e86SAndroid Build Coastguard Worker 					}
387*7c356e86SAndroid Build Coastguard Worker 					return (-1);
388*7c356e86SAndroid Build Coastguard Worker 				}
389*7c356e86SAndroid Build Coastguard Worker 				buf += n;
390*7c356e86SAndroid Build Coastguard Worker 				ntowrite -= n;
391*7c356e86SAndroid Build Coastguard Worker 			}
392*7c356e86SAndroid Build Coastguard Worker 			if (flags & EB_READSW) {
393*7c356e86SAndroid Build Coastguard Worker 				shf->wp = shf->buf;
394*7c356e86SAndroid Build Coastguard Worker 				shf->wnleft = 0;
395*7c356e86SAndroid Build Coastguard Worker 				shf->flags &= ~SHF_WRITING;
396*7c356e86SAndroid Build Coastguard Worker 				return (0);
397*7c356e86SAndroid Build Coastguard Worker 			}
398*7c356e86SAndroid Build Coastguard Worker 		}
399*7c356e86SAndroid Build Coastguard Worker 		shf->wp = shf->buf;
400*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft = shf->wbsize;
401*7c356e86SAndroid Build Coastguard Worker 	}
402*7c356e86SAndroid Build Coastguard Worker 	shf->flags |= SHF_WRITING;
403*7c356e86SAndroid Build Coastguard Worker 
404*7c356e86SAndroid Build Coastguard Worker 	return (ret);
405*7c356e86SAndroid Build Coastguard Worker }
406*7c356e86SAndroid Build Coastguard Worker 
407*7c356e86SAndroid Build Coastguard Worker /* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */
408*7c356e86SAndroid Build Coastguard Worker static int
shf_fillbuf(struct shf * shf)409*7c356e86SAndroid Build Coastguard Worker shf_fillbuf(struct shf *shf)
410*7c356e86SAndroid Build Coastguard Worker {
411*7c356e86SAndroid Build Coastguard Worker 	ssize_t n;
412*7c356e86SAndroid Build Coastguard Worker 
413*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_STRING)
414*7c356e86SAndroid Build Coastguard Worker 		return (0);
415*7c356e86SAndroid Build Coastguard Worker 
416*7c356e86SAndroid Build Coastguard Worker 	if (shf->fd < 0)
417*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
418*7c356e86SAndroid Build Coastguard Worker 
419*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
420*7c356e86SAndroid Build Coastguard Worker 		if (shf->flags & SHF_ERROR)
421*7c356e86SAndroid Build Coastguard Worker 			errno = shf->errnosv;
422*7c356e86SAndroid Build Coastguard Worker 		return (-1);
423*7c356e86SAndroid Build Coastguard Worker 	}
424*7c356e86SAndroid Build Coastguard Worker 
425*7c356e86SAndroid Build Coastguard Worker 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
426*7c356e86SAndroid Build Coastguard Worker 		return (-1);
427*7c356e86SAndroid Build Coastguard Worker 
428*7c356e86SAndroid Build Coastguard Worker 	shf->flags |= SHF_READING;
429*7c356e86SAndroid Build Coastguard Worker 
430*7c356e86SAndroid Build Coastguard Worker 	shf->rp = shf->buf;
431*7c356e86SAndroid Build Coastguard Worker 	while (/* CONSTCOND */ 1) {
432*7c356e86SAndroid Build Coastguard Worker 		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
433*7c356e86SAndroid Build Coastguard Worker 		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
434*7c356e86SAndroid Build Coastguard Worker 			continue;
435*7c356e86SAndroid Build Coastguard Worker 		break;
436*7c356e86SAndroid Build Coastguard Worker 	}
437*7c356e86SAndroid Build Coastguard Worker 	if (n < 0) {
438*7c356e86SAndroid Build Coastguard Worker 		shf->flags |= SHF_ERROR;
439*7c356e86SAndroid Build Coastguard Worker 		shf->errnosv = errno;
440*7c356e86SAndroid Build Coastguard Worker 		shf->rnleft = 0;
441*7c356e86SAndroid Build Coastguard Worker 		shf->rp = shf->buf;
442*7c356e86SAndroid Build Coastguard Worker 		return (-1);
443*7c356e86SAndroid Build Coastguard Worker 	}
444*7c356e86SAndroid Build Coastguard Worker 	if ((shf->rnleft = n) == 0)
445*7c356e86SAndroid Build Coastguard Worker 		shf->flags |= SHF_EOF;
446*7c356e86SAndroid Build Coastguard Worker 	return (0);
447*7c356e86SAndroid Build Coastguard Worker }
448*7c356e86SAndroid Build Coastguard Worker 
449*7c356e86SAndroid Build Coastguard Worker /*
450*7c356e86SAndroid Build Coastguard Worker  * Read a buffer from shf. Returns the number of bytes read into buf, if
451*7c356e86SAndroid Build Coastguard Worker  * no bytes were read, returns 0 if end of file was seen, -1 if a read
452*7c356e86SAndroid Build Coastguard Worker  * error occurred.
453*7c356e86SAndroid Build Coastguard Worker  */
454*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_read(char * buf,ssize_t bsize,struct shf * shf)455*7c356e86SAndroid Build Coastguard Worker shf_read(char *buf, ssize_t bsize, struct shf *shf)
456*7c356e86SAndroid Build Coastguard Worker {
457*7c356e86SAndroid Build Coastguard Worker 	ssize_t ncopy, orig_bsize = bsize;
458*7c356e86SAndroid Build Coastguard Worker 
459*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_RD))
460*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, Tshf_read,
461*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
462*7c356e86SAndroid Build Coastguard Worker 
463*7c356e86SAndroid Build Coastguard Worker 	if (bsize <= 0)
464*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
465*7c356e86SAndroid Build Coastguard Worker 
466*7c356e86SAndroid Build Coastguard Worker 	while (bsize > 0) {
467*7c356e86SAndroid Build Coastguard Worker 		if (shf->rnleft == 0 &&
468*7c356e86SAndroid Build Coastguard Worker 		    (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
469*7c356e86SAndroid Build Coastguard Worker 			break;
470*7c356e86SAndroid Build Coastguard Worker 		ncopy = shf->rnleft;
471*7c356e86SAndroid Build Coastguard Worker 		if (ncopy > bsize)
472*7c356e86SAndroid Build Coastguard Worker 			ncopy = bsize;
473*7c356e86SAndroid Build Coastguard Worker 		memcpy(buf, shf->rp, ncopy);
474*7c356e86SAndroid Build Coastguard Worker 		buf += ncopy;
475*7c356e86SAndroid Build Coastguard Worker 		bsize -= ncopy;
476*7c356e86SAndroid Build Coastguard Worker 		shf->rp += ncopy;
477*7c356e86SAndroid Build Coastguard Worker 		shf->rnleft -= ncopy;
478*7c356e86SAndroid Build Coastguard Worker 	}
479*7c356e86SAndroid Build Coastguard Worker 	/* Note: fread(3S) returns 0 for errors - this doesn't */
480*7c356e86SAndroid Build Coastguard Worker 	return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) :
481*7c356e86SAndroid Build Coastguard Worker 	    orig_bsize - bsize);
482*7c356e86SAndroid Build Coastguard Worker }
483*7c356e86SAndroid Build Coastguard Worker 
484*7c356e86SAndroid Build Coastguard Worker /*
485*7c356e86SAndroid Build Coastguard Worker  * Read up to a newline or -1. The newline is put in buf; buf is always
486*7c356e86SAndroid Build Coastguard Worker  * NUL terminated. Returns NULL on read error or if nothing was read
487*7c356e86SAndroid Build Coastguard Worker  * before end of file, returns a pointer to the NUL byte in buf
488*7c356e86SAndroid Build Coastguard Worker  * otherwise.
489*7c356e86SAndroid Build Coastguard Worker  */
490*7c356e86SAndroid Build Coastguard Worker char *
shf_getse(char * buf,ssize_t bsize,struct shf * shf)491*7c356e86SAndroid Build Coastguard Worker shf_getse(char *buf, ssize_t bsize, struct shf *shf)
492*7c356e86SAndroid Build Coastguard Worker {
493*7c356e86SAndroid Build Coastguard Worker 	unsigned char *end;
494*7c356e86SAndroid Build Coastguard Worker 	ssize_t ncopy;
495*7c356e86SAndroid Build Coastguard Worker 	char *orig_buf = buf;
496*7c356e86SAndroid Build Coastguard Worker 
497*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_RD))
498*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, "shf_getse",
499*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
500*7c356e86SAndroid Build Coastguard Worker 
501*7c356e86SAndroid Build Coastguard Worker 	if (bsize <= 0)
502*7c356e86SAndroid Build Coastguard Worker 		return (NULL);
503*7c356e86SAndroid Build Coastguard Worker 
504*7c356e86SAndroid Build Coastguard Worker 	/* save room for NUL */
505*7c356e86SAndroid Build Coastguard Worker 	--bsize;
506*7c356e86SAndroid Build Coastguard Worker 	do {
507*7c356e86SAndroid Build Coastguard Worker 		if (shf->rnleft == 0) {
508*7c356e86SAndroid Build Coastguard Worker 			if (shf_fillbuf(shf) == -1)
509*7c356e86SAndroid Build Coastguard Worker 				return (NULL);
510*7c356e86SAndroid Build Coastguard Worker 			if (shf->rnleft == 0) {
511*7c356e86SAndroid Build Coastguard Worker 				*buf = '\0';
512*7c356e86SAndroid Build Coastguard Worker 				return (buf == orig_buf ? NULL : buf);
513*7c356e86SAndroid Build Coastguard Worker 			}
514*7c356e86SAndroid Build Coastguard Worker 		}
515*7c356e86SAndroid Build Coastguard Worker 		end = (unsigned char *)memchr((char *)shf->rp, '\n',
516*7c356e86SAndroid Build Coastguard Worker 		    shf->rnleft);
517*7c356e86SAndroid Build Coastguard Worker 		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
518*7c356e86SAndroid Build Coastguard Worker 		if (ncopy > bsize)
519*7c356e86SAndroid Build Coastguard Worker 			ncopy = bsize;
520*7c356e86SAndroid Build Coastguard Worker 		memcpy(buf, (char *) shf->rp, ncopy);
521*7c356e86SAndroid Build Coastguard Worker 		shf->rp += ncopy;
522*7c356e86SAndroid Build Coastguard Worker 		shf->rnleft -= ncopy;
523*7c356e86SAndroid Build Coastguard Worker 		buf += ncopy;
524*7c356e86SAndroid Build Coastguard Worker 		bsize -= ncopy;
525*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_WITH_TEXTMODE
526*7c356e86SAndroid Build Coastguard Worker 		if (buf > orig_buf + 1 && ord(buf[-2]) == ORD('\r') &&
527*7c356e86SAndroid Build Coastguard Worker 		    ord(buf[-1]) == ORD('\n')) {
528*7c356e86SAndroid Build Coastguard Worker 			buf--;
529*7c356e86SAndroid Build Coastguard Worker 			bsize++;
530*7c356e86SAndroid Build Coastguard Worker 			buf[-1] = '\n';
531*7c356e86SAndroid Build Coastguard Worker 		}
532*7c356e86SAndroid Build Coastguard Worker #endif
533*7c356e86SAndroid Build Coastguard Worker 	} while (!end && bsize);
534*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_WITH_TEXTMODE
535*7c356e86SAndroid Build Coastguard Worker 	if (!bsize && ord(buf[-1]) == ORD('\r')) {
536*7c356e86SAndroid Build Coastguard Worker 		int c = shf_getc(shf);
537*7c356e86SAndroid Build Coastguard Worker 		if (ord(c) == ORD('\n'))
538*7c356e86SAndroid Build Coastguard Worker 			buf[-1] = '\n';
539*7c356e86SAndroid Build Coastguard Worker 		else if (c != -1)
540*7c356e86SAndroid Build Coastguard Worker 			shf_ungetc(c, shf);
541*7c356e86SAndroid Build Coastguard Worker 	}
542*7c356e86SAndroid Build Coastguard Worker #endif
543*7c356e86SAndroid Build Coastguard Worker 	*buf = '\0';
544*7c356e86SAndroid Build Coastguard Worker 	return (buf);
545*7c356e86SAndroid Build Coastguard Worker }
546*7c356e86SAndroid Build Coastguard Worker 
547*7c356e86SAndroid Build Coastguard Worker /* Returns the char read. Returns -1 for error and end of file. */
548*7c356e86SAndroid Build Coastguard Worker int
shf_getchar(struct shf * shf)549*7c356e86SAndroid Build Coastguard Worker shf_getchar(struct shf *shf)
550*7c356e86SAndroid Build Coastguard Worker {
551*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_RD))
552*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, "shf_getchar",
553*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
554*7c356e86SAndroid Build Coastguard Worker 
555*7c356e86SAndroid Build Coastguard Worker 	if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
556*7c356e86SAndroid Build Coastguard Worker 		return (-1);
557*7c356e86SAndroid Build Coastguard Worker 	--shf->rnleft;
558*7c356e86SAndroid Build Coastguard Worker 	return (ord(*shf->rp++));
559*7c356e86SAndroid Build Coastguard Worker }
560*7c356e86SAndroid Build Coastguard Worker 
561*7c356e86SAndroid Build Coastguard Worker /*
562*7c356e86SAndroid Build Coastguard Worker  * Put a character back in the input stream. Returns the character if
563*7c356e86SAndroid Build Coastguard Worker  * successful, -1 if there is no room.
564*7c356e86SAndroid Build Coastguard Worker  */
565*7c356e86SAndroid Build Coastguard Worker int
shf_ungetc(int c,struct shf * shf)566*7c356e86SAndroid Build Coastguard Worker shf_ungetc(int c, struct shf *shf)
567*7c356e86SAndroid Build Coastguard Worker {
568*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_RD))
569*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, "shf_ungetc",
570*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
571*7c356e86SAndroid Build Coastguard Worker 
572*7c356e86SAndroid Build Coastguard Worker 	if ((shf->flags & SHF_ERROR) || c == -1 ||
573*7c356e86SAndroid Build Coastguard Worker 	    (shf->rp == shf->buf && shf->rnleft))
574*7c356e86SAndroid Build Coastguard Worker 		return (-1);
575*7c356e86SAndroid Build Coastguard Worker 
576*7c356e86SAndroid Build Coastguard Worker 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
577*7c356e86SAndroid Build Coastguard Worker 		return (-1);
578*7c356e86SAndroid Build Coastguard Worker 
579*7c356e86SAndroid Build Coastguard Worker 	if (shf->rp == shf->buf)
580*7c356e86SAndroid Build Coastguard Worker 		shf->rp = shf->buf + shf->rbsize;
581*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_STRING) {
582*7c356e86SAndroid Build Coastguard Worker 		/*
583*7c356e86SAndroid Build Coastguard Worker 		 * Can unget what was read, but not something different;
584*7c356e86SAndroid Build Coastguard Worker 		 * we don't want to modify a string.
585*7c356e86SAndroid Build Coastguard Worker 		 */
586*7c356e86SAndroid Build Coastguard Worker 		if ((int)(shf->rp[-1]) != c)
587*7c356e86SAndroid Build Coastguard Worker 			return (-1);
588*7c356e86SAndroid Build Coastguard Worker 		shf->flags &= ~SHF_EOF;
589*7c356e86SAndroid Build Coastguard Worker 		shf->rp--;
590*7c356e86SAndroid Build Coastguard Worker 		shf->rnleft++;
591*7c356e86SAndroid Build Coastguard Worker 		return (c);
592*7c356e86SAndroid Build Coastguard Worker 	}
593*7c356e86SAndroid Build Coastguard Worker 	shf->flags &= ~SHF_EOF;
594*7c356e86SAndroid Build Coastguard Worker 	*--(shf->rp) = c;
595*7c356e86SAndroid Build Coastguard Worker 	shf->rnleft++;
596*7c356e86SAndroid Build Coastguard Worker 	return (c);
597*7c356e86SAndroid Build Coastguard Worker }
598*7c356e86SAndroid Build Coastguard Worker 
599*7c356e86SAndroid Build Coastguard Worker /*
600*7c356e86SAndroid Build Coastguard Worker  * Write a character. Returns the character if successful, -1 if the
601*7c356e86SAndroid Build Coastguard Worker  * char could not be written.
602*7c356e86SAndroid Build Coastguard Worker  */
603*7c356e86SAndroid Build Coastguard Worker int
shf_putchar(int c,struct shf * shf)604*7c356e86SAndroid Build Coastguard Worker shf_putchar(int c, struct shf *shf)
605*7c356e86SAndroid Build Coastguard Worker {
606*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_WR))
607*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, "shf_putchar",
608*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
609*7c356e86SAndroid Build Coastguard Worker 
610*7c356e86SAndroid Build Coastguard Worker 	if (c == -1)
611*7c356e86SAndroid Build Coastguard Worker 		return (-1);
612*7c356e86SAndroid Build Coastguard Worker 
613*7c356e86SAndroid Build Coastguard Worker 	if (shf->flags & SHF_UNBUF) {
614*7c356e86SAndroid Build Coastguard Worker 		unsigned char cc = (unsigned char)c;
615*7c356e86SAndroid Build Coastguard Worker 		ssize_t n;
616*7c356e86SAndroid Build Coastguard Worker 
617*7c356e86SAndroid Build Coastguard Worker 		if (shf->fd < 0)
618*7c356e86SAndroid Build Coastguard Worker 			internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
619*7c356e86SAndroid Build Coastguard Worker 		if (shf->flags & SHF_ERROR) {
620*7c356e86SAndroid Build Coastguard Worker 			errno = shf->errnosv;
621*7c356e86SAndroid Build Coastguard Worker 			return (-1);
622*7c356e86SAndroid Build Coastguard Worker 		}
623*7c356e86SAndroid Build Coastguard Worker 		while ((n = write(shf->fd, &cc, 1)) != 1)
624*7c356e86SAndroid Build Coastguard Worker 			if (n < 0) {
625*7c356e86SAndroid Build Coastguard Worker 				if (errno == EINTR &&
626*7c356e86SAndroid Build Coastguard Worker 				    !(shf->flags & SHF_INTERRUPT))
627*7c356e86SAndroid Build Coastguard Worker 					continue;
628*7c356e86SAndroid Build Coastguard Worker 				shf->flags |= SHF_ERROR;
629*7c356e86SAndroid Build Coastguard Worker 				shf->errnosv = errno;
630*7c356e86SAndroid Build Coastguard Worker 				return (-1);
631*7c356e86SAndroid Build Coastguard Worker 			}
632*7c356e86SAndroid Build Coastguard Worker 	} else {
633*7c356e86SAndroid Build Coastguard Worker 		/* Flush deals with strings and sticky errors */
634*7c356e86SAndroid Build Coastguard Worker 		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1)
635*7c356e86SAndroid Build Coastguard Worker 			return (-1);
636*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft--;
637*7c356e86SAndroid Build Coastguard Worker 		*shf->wp++ = c;
638*7c356e86SAndroid Build Coastguard Worker 	}
639*7c356e86SAndroid Build Coastguard Worker 
640*7c356e86SAndroid Build Coastguard Worker 	return (c);
641*7c356e86SAndroid Build Coastguard Worker }
642*7c356e86SAndroid Build Coastguard Worker 
643*7c356e86SAndroid Build Coastguard Worker /*
644*7c356e86SAndroid Build Coastguard Worker  * Write a string. Returns the length of the string if successful, -1
645*7c356e86SAndroid Build Coastguard Worker  * if the string could not be written.
646*7c356e86SAndroid Build Coastguard Worker  */
647*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_puts(const char * s,struct shf * shf)648*7c356e86SAndroid Build Coastguard Worker shf_puts(const char *s, struct shf *shf)
649*7c356e86SAndroid Build Coastguard Worker {
650*7c356e86SAndroid Build Coastguard Worker 	if (!s)
651*7c356e86SAndroid Build Coastguard Worker 		return (-1);
652*7c356e86SAndroid Build Coastguard Worker 
653*7c356e86SAndroid Build Coastguard Worker 	return (shf_write(s, strlen(s), shf));
654*7c356e86SAndroid Build Coastguard Worker }
655*7c356e86SAndroid Build Coastguard Worker 
656*7c356e86SAndroid Build Coastguard Worker /* Write a buffer. Returns nbytes if successful, -1 if there is an error. */
657*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_write(const char * buf,ssize_t nbytes,struct shf * shf)658*7c356e86SAndroid Build Coastguard Worker shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
659*7c356e86SAndroid Build Coastguard Worker {
660*7c356e86SAndroid Build Coastguard Worker 	ssize_t n, ncopy, orig_nbytes = nbytes;
661*7c356e86SAndroid Build Coastguard Worker 
662*7c356e86SAndroid Build Coastguard Worker 	if (!(shf->flags & SHF_WR))
663*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_flags, Tshf_write,
664*7c356e86SAndroid Build Coastguard Worker 		    (unsigned int)shf->flags);
665*7c356e86SAndroid Build Coastguard Worker 
666*7c356e86SAndroid Build Coastguard Worker 	if (nbytes < 0)
667*7c356e86SAndroid Build Coastguard Worker 		internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
668*7c356e86SAndroid Build Coastguard Worker 
669*7c356e86SAndroid Build Coastguard Worker 	/* don't buffer if buffer is empty and we're writing a large amount */
670*7c356e86SAndroid Build Coastguard Worker 	if ((ncopy = shf->wnleft) &&
671*7c356e86SAndroid Build Coastguard Worker 	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
672*7c356e86SAndroid Build Coastguard Worker 		if (ncopy > nbytes)
673*7c356e86SAndroid Build Coastguard Worker 			ncopy = nbytes;
674*7c356e86SAndroid Build Coastguard Worker 		memcpy(shf->wp, buf, ncopy);
675*7c356e86SAndroid Build Coastguard Worker 		nbytes -= ncopy;
676*7c356e86SAndroid Build Coastguard Worker 		buf += ncopy;
677*7c356e86SAndroid Build Coastguard Worker 		shf->wp += ncopy;
678*7c356e86SAndroid Build Coastguard Worker 		shf->wnleft -= ncopy;
679*7c356e86SAndroid Build Coastguard Worker 	}
680*7c356e86SAndroid Build Coastguard Worker 	if (nbytes > 0) {
681*7c356e86SAndroid Build Coastguard Worker 		if (shf->flags & SHF_STRING) {
682*7c356e86SAndroid Build Coastguard Worker 			/* resize buffer until there's enough space left */
683*7c356e86SAndroid Build Coastguard Worker 			while (nbytes > shf->wnleft)
684*7c356e86SAndroid Build Coastguard Worker 				if (shf_emptybuf(shf, EB_GROW) == -1)
685*7c356e86SAndroid Build Coastguard Worker 					return (-1);
686*7c356e86SAndroid Build Coastguard Worker 			/* then write everything into the buffer */
687*7c356e86SAndroid Build Coastguard Worker 		} else {
688*7c356e86SAndroid Build Coastguard Worker 			/* flush deals with sticky errors */
689*7c356e86SAndroid Build Coastguard Worker 			if (shf_emptybuf(shf, EB_GROW) == -1)
690*7c356e86SAndroid Build Coastguard Worker 				return (-1);
691*7c356e86SAndroid Build Coastguard Worker 			/* write chunks larger than window size directly */
692*7c356e86SAndroid Build Coastguard Worker 			if (nbytes > shf->wbsize) {
693*7c356e86SAndroid Build Coastguard Worker 				ncopy = nbytes;
694*7c356e86SAndroid Build Coastguard Worker 				if (shf->wbsize)
695*7c356e86SAndroid Build Coastguard Worker 					ncopy -= nbytes % shf->wbsize;
696*7c356e86SAndroid Build Coastguard Worker 				nbytes -= ncopy;
697*7c356e86SAndroid Build Coastguard Worker 				while (ncopy > 0) {
698*7c356e86SAndroid Build Coastguard Worker 					n = write(shf->fd, buf, ncopy);
699*7c356e86SAndroid Build Coastguard Worker 					if (n < 0) {
700*7c356e86SAndroid Build Coastguard Worker 						if (errno == EINTR &&
701*7c356e86SAndroid Build Coastguard Worker 						    !(shf->flags & SHF_INTERRUPT))
702*7c356e86SAndroid Build Coastguard Worker 							continue;
703*7c356e86SAndroid Build Coastguard Worker 						shf->flags |= SHF_ERROR;
704*7c356e86SAndroid Build Coastguard Worker 						shf->errnosv = errno;
705*7c356e86SAndroid Build Coastguard Worker 						shf->wnleft = 0;
706*7c356e86SAndroid Build Coastguard Worker 						/*
707*7c356e86SAndroid Build Coastguard Worker 						 * Note: fwrite(3) returns 0
708*7c356e86SAndroid Build Coastguard Worker 						 * for errors - this doesn't
709*7c356e86SAndroid Build Coastguard Worker 						 */
710*7c356e86SAndroid Build Coastguard Worker 						return (-1);
711*7c356e86SAndroid Build Coastguard Worker 					}
712*7c356e86SAndroid Build Coastguard Worker 					buf += n;
713*7c356e86SAndroid Build Coastguard Worker 					ncopy -= n;
714*7c356e86SAndroid Build Coastguard Worker 				}
715*7c356e86SAndroid Build Coastguard Worker 			}
716*7c356e86SAndroid Build Coastguard Worker 			/* ... and buffer the rest */
717*7c356e86SAndroid Build Coastguard Worker 		}
718*7c356e86SAndroid Build Coastguard Worker 		if (nbytes > 0) {
719*7c356e86SAndroid Build Coastguard Worker 			/* write remaining bytes to buffer */
720*7c356e86SAndroid Build Coastguard Worker 			memcpy(shf->wp, buf, nbytes);
721*7c356e86SAndroid Build Coastguard Worker 			shf->wp += nbytes;
722*7c356e86SAndroid Build Coastguard Worker 			shf->wnleft -= nbytes;
723*7c356e86SAndroid Build Coastguard Worker 		}
724*7c356e86SAndroid Build Coastguard Worker 	}
725*7c356e86SAndroid Build Coastguard Worker 
726*7c356e86SAndroid Build Coastguard Worker 	return (orig_nbytes);
727*7c356e86SAndroid Build Coastguard Worker }
728*7c356e86SAndroid Build Coastguard Worker 
729*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_fprintf(struct shf * shf,const char * fmt,...)730*7c356e86SAndroid Build Coastguard Worker shf_fprintf(struct shf *shf, const char *fmt, ...)
731*7c356e86SAndroid Build Coastguard Worker {
732*7c356e86SAndroid Build Coastguard Worker 	va_list args;
733*7c356e86SAndroid Build Coastguard Worker 	ssize_t n;
734*7c356e86SAndroid Build Coastguard Worker 
735*7c356e86SAndroid Build Coastguard Worker 	va_start(args, fmt);
736*7c356e86SAndroid Build Coastguard Worker 	n = shf_vfprintf(shf, fmt, args);
737*7c356e86SAndroid Build Coastguard Worker 	va_end(args);
738*7c356e86SAndroid Build Coastguard Worker 
739*7c356e86SAndroid Build Coastguard Worker 	return (n);
740*7c356e86SAndroid Build Coastguard Worker }
741*7c356e86SAndroid Build Coastguard Worker 
742*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_snprintf(char * buf,ssize_t bsize,const char * fmt,...)743*7c356e86SAndroid Build Coastguard Worker shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
744*7c356e86SAndroid Build Coastguard Worker {
745*7c356e86SAndroid Build Coastguard Worker 	struct shf shf;
746*7c356e86SAndroid Build Coastguard Worker 	va_list args;
747*7c356e86SAndroid Build Coastguard Worker 	ssize_t n;
748*7c356e86SAndroid Build Coastguard Worker 
749*7c356e86SAndroid Build Coastguard Worker 	if (!buf || bsize <= 0)
750*7c356e86SAndroid Build Coastguard Worker 		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
751*7c356e86SAndroid Build Coastguard Worker 		    (size_t)buf, bsize);
752*7c356e86SAndroid Build Coastguard Worker 
753*7c356e86SAndroid Build Coastguard Worker 	shf_sopen(buf, bsize, SHF_WR, &shf);
754*7c356e86SAndroid Build Coastguard Worker 	va_start(args, fmt);
755*7c356e86SAndroid Build Coastguard Worker 	n = shf_vfprintf(&shf, fmt, args);
756*7c356e86SAndroid Build Coastguard Worker 	va_end(args);
757*7c356e86SAndroid Build Coastguard Worker 	/* NUL terminates */
758*7c356e86SAndroid Build Coastguard Worker 	shf_sclose(&shf);
759*7c356e86SAndroid Build Coastguard Worker 	return (n);
760*7c356e86SAndroid Build Coastguard Worker }
761*7c356e86SAndroid Build Coastguard Worker 
762*7c356e86SAndroid Build Coastguard Worker char *
shf_smprintf(const char * fmt,...)763*7c356e86SAndroid Build Coastguard Worker shf_smprintf(const char *fmt, ...)
764*7c356e86SAndroid Build Coastguard Worker {
765*7c356e86SAndroid Build Coastguard Worker 	struct shf shf;
766*7c356e86SAndroid Build Coastguard Worker 	va_list args;
767*7c356e86SAndroid Build Coastguard Worker 
768*7c356e86SAndroid Build Coastguard Worker 	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
769*7c356e86SAndroid Build Coastguard Worker 	va_start(args, fmt);
770*7c356e86SAndroid Build Coastguard Worker 	shf_vfprintf(&shf, fmt, args);
771*7c356e86SAndroid Build Coastguard Worker 	va_end(args);
772*7c356e86SAndroid Build Coastguard Worker 	/* NUL terminates */
773*7c356e86SAndroid Build Coastguard Worker 	return (shf_sclose(&shf));
774*7c356e86SAndroid Build Coastguard Worker }
775*7c356e86SAndroid Build Coastguard Worker 
776*7c356e86SAndroid Build Coastguard Worker #define	FL_HASH		0x001	/* '#' seen */
777*7c356e86SAndroid Build Coastguard Worker #define FL_PLUS		0x002	/* '+' seen */
778*7c356e86SAndroid Build Coastguard Worker #define FL_RIGHT	0x004	/* '-' seen */
779*7c356e86SAndroid Build Coastguard Worker #define FL_BLANK	0x008	/* ' ' seen */
780*7c356e86SAndroid Build Coastguard Worker #define FL_SHORT	0x010	/* 'h' seen */
781*7c356e86SAndroid Build Coastguard Worker #define FL_LONG		0x020	/* 'l' seen */
782*7c356e86SAndroid Build Coastguard Worker #define FL_ZERO		0x040	/* '0' seen */
783*7c356e86SAndroid Build Coastguard Worker #define FL_DOT		0x080	/* '.' seen */
784*7c356e86SAndroid Build Coastguard Worker #define FL_UPPER	0x100	/* format character was uppercase */
785*7c356e86SAndroid Build Coastguard Worker #define FL_NUMBER	0x200	/* a number was formatted %[douxefg] */
786*7c356e86SAndroid Build Coastguard Worker #define FL_SIZET	0x400	/* 'z' seen */
787*7c356e86SAndroid Build Coastguard Worker #define FM_SIZES	0x430	/* h/l/z mask */
788*7c356e86SAndroid Build Coastguard Worker 
789*7c356e86SAndroid Build Coastguard Worker ssize_t
shf_vfprintf(struct shf * shf,const char * fmt,va_list args)790*7c356e86SAndroid Build Coastguard Worker shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
791*7c356e86SAndroid Build Coastguard Worker {
792*7c356e86SAndroid Build Coastguard Worker 	const char *s;
793*7c356e86SAndroid Build Coastguard Worker 	char c, *cp;
794*7c356e86SAndroid Build Coastguard Worker 	int tmp = 0, flags;
795*7c356e86SAndroid Build Coastguard Worker 	size_t field, precision, len;
796*7c356e86SAndroid Build Coastguard Worker 	unsigned long lnum;
797*7c356e86SAndroid Build Coastguard Worker 	/* %#o produces the longest output */
798*7c356e86SAndroid Build Coastguard Worker 	char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1];
799*7c356e86SAndroid Build Coastguard Worker 	/* this stuff for dealing with the buffer */
800*7c356e86SAndroid Build Coastguard Worker 	ssize_t nwritten = 0;
801*7c356e86SAndroid Build Coastguard Worker 
802*7c356e86SAndroid Build Coastguard Worker #define VA(type) va_arg(args, type)
803*7c356e86SAndroid Build Coastguard Worker 
804*7c356e86SAndroid Build Coastguard Worker 	if (!fmt)
805*7c356e86SAndroid Build Coastguard Worker 		return (0);
806*7c356e86SAndroid Build Coastguard Worker 
807*7c356e86SAndroid Build Coastguard Worker 	while ((c = *fmt++)) {
808*7c356e86SAndroid Build Coastguard Worker 		if (c != '%') {
809*7c356e86SAndroid Build Coastguard Worker 			shf_putc(c, shf);
810*7c356e86SAndroid Build Coastguard Worker 			nwritten++;
811*7c356e86SAndroid Build Coastguard Worker 			continue;
812*7c356e86SAndroid Build Coastguard Worker 		}
813*7c356e86SAndroid Build Coastguard Worker 		/*
814*7c356e86SAndroid Build Coastguard Worker 		 * This will accept flags/fields in any order - not just
815*7c356e86SAndroid Build Coastguard Worker 		 * the order specified in printf(3), but this is the way
816*7c356e86SAndroid Build Coastguard Worker 		 * _doprnt() seems to work (on BSD and SYSV). The only
817*7c356e86SAndroid Build Coastguard Worker 		 * restriction is that the format character must come
818*7c356e86SAndroid Build Coastguard Worker 		 * last :-).
819*7c356e86SAndroid Build Coastguard Worker 		 */
820*7c356e86SAndroid Build Coastguard Worker 		flags = 0;
821*7c356e86SAndroid Build Coastguard Worker 		field = precision = 0;
822*7c356e86SAndroid Build Coastguard Worker 		while ((c = *fmt++)) {
823*7c356e86SAndroid Build Coastguard Worker 			switch (c) {
824*7c356e86SAndroid Build Coastguard Worker 			case '#':
825*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_HASH;
826*7c356e86SAndroid Build Coastguard Worker 				continue;
827*7c356e86SAndroid Build Coastguard Worker 
828*7c356e86SAndroid Build Coastguard Worker 			case '+':
829*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_PLUS;
830*7c356e86SAndroid Build Coastguard Worker 				continue;
831*7c356e86SAndroid Build Coastguard Worker 
832*7c356e86SAndroid Build Coastguard Worker 			case '-':
833*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_RIGHT;
834*7c356e86SAndroid Build Coastguard Worker 				continue;
835*7c356e86SAndroid Build Coastguard Worker 
836*7c356e86SAndroid Build Coastguard Worker 			case ' ':
837*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_BLANK;
838*7c356e86SAndroid Build Coastguard Worker 				continue;
839*7c356e86SAndroid Build Coastguard Worker 
840*7c356e86SAndroid Build Coastguard Worker 			case '0':
841*7c356e86SAndroid Build Coastguard Worker 				if (!(flags & FL_DOT))
842*7c356e86SAndroid Build Coastguard Worker 					flags |= FL_ZERO;
843*7c356e86SAndroid Build Coastguard Worker 				continue;
844*7c356e86SAndroid Build Coastguard Worker 
845*7c356e86SAndroid Build Coastguard Worker 			case '.':
846*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_DOT;
847*7c356e86SAndroid Build Coastguard Worker 				precision = 0;
848*7c356e86SAndroid Build Coastguard Worker 				continue;
849*7c356e86SAndroid Build Coastguard Worker 
850*7c356e86SAndroid Build Coastguard Worker 			case '*':
851*7c356e86SAndroid Build Coastguard Worker 				tmp = VA(int);
852*7c356e86SAndroid Build Coastguard Worker 				if (tmp < 0) {
853*7c356e86SAndroid Build Coastguard Worker 					if (flags & FL_DOT)
854*7c356e86SAndroid Build Coastguard Worker 						precision = 0;
855*7c356e86SAndroid Build Coastguard Worker 					else {
856*7c356e86SAndroid Build Coastguard Worker 						field = (unsigned int)-tmp;
857*7c356e86SAndroid Build Coastguard Worker 						flags |= FL_RIGHT;
858*7c356e86SAndroid Build Coastguard Worker 					}
859*7c356e86SAndroid Build Coastguard Worker 				} else if (flags & FL_DOT)
860*7c356e86SAndroid Build Coastguard Worker 					precision = (unsigned int)tmp;
861*7c356e86SAndroid Build Coastguard Worker 				else
862*7c356e86SAndroid Build Coastguard Worker 					field = (unsigned int)tmp;
863*7c356e86SAndroid Build Coastguard Worker 				continue;
864*7c356e86SAndroid Build Coastguard Worker 
865*7c356e86SAndroid Build Coastguard Worker 			case 'l':
866*7c356e86SAndroid Build Coastguard Worker 				flags &= ~FM_SIZES;
867*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_LONG;
868*7c356e86SAndroid Build Coastguard Worker 				continue;
869*7c356e86SAndroid Build Coastguard Worker 
870*7c356e86SAndroid Build Coastguard Worker 			case 'h':
871*7c356e86SAndroid Build Coastguard Worker 				flags &= ~FM_SIZES;
872*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_SHORT;
873*7c356e86SAndroid Build Coastguard Worker 				continue;
874*7c356e86SAndroid Build Coastguard Worker 
875*7c356e86SAndroid Build Coastguard Worker 			case 'z':
876*7c356e86SAndroid Build Coastguard Worker 				flags &= ~FM_SIZES;
877*7c356e86SAndroid Build Coastguard Worker 				flags |= FL_SIZET;
878*7c356e86SAndroid Build Coastguard Worker 				continue;
879*7c356e86SAndroid Build Coastguard Worker 			}
880*7c356e86SAndroid Build Coastguard Worker 			if (ctype(c, C_DIGIT)) {
881*7c356e86SAndroid Build Coastguard Worker 				bool overflowed = false;
882*7c356e86SAndroid Build Coastguard Worker 
883*7c356e86SAndroid Build Coastguard Worker 				tmp = ksh_numdig(c);
884*7c356e86SAndroid Build Coastguard Worker 				while (ctype((c = *fmt++), C_DIGIT))
885*7c356e86SAndroid Build Coastguard Worker 					if (notok2mul(2147483647, tmp, 10))
886*7c356e86SAndroid Build Coastguard Worker 						overflowed = true;
887*7c356e86SAndroid Build Coastguard Worker 					else
888*7c356e86SAndroid Build Coastguard Worker 						tmp = tmp * 10 + ksh_numdig(c);
889*7c356e86SAndroid Build Coastguard Worker 				--fmt;
890*7c356e86SAndroid Build Coastguard Worker 				if (overflowed)
891*7c356e86SAndroid Build Coastguard Worker 					tmp = 0;
892*7c356e86SAndroid Build Coastguard Worker 				if (flags & FL_DOT)
893*7c356e86SAndroid Build Coastguard Worker 					precision = (unsigned int)tmp;
894*7c356e86SAndroid Build Coastguard Worker 				else
895*7c356e86SAndroid Build Coastguard Worker 					field = (unsigned int)tmp;
896*7c356e86SAndroid Build Coastguard Worker 				continue;
897*7c356e86SAndroid Build Coastguard Worker 			}
898*7c356e86SAndroid Build Coastguard Worker 			break;
899*7c356e86SAndroid Build Coastguard Worker 		}
900*7c356e86SAndroid Build Coastguard Worker 
901*7c356e86SAndroid Build Coastguard Worker 		if (!c)
902*7c356e86SAndroid Build Coastguard Worker 			/* nasty format */
903*7c356e86SAndroid Build Coastguard Worker 			break;
904*7c356e86SAndroid Build Coastguard Worker 
905*7c356e86SAndroid Build Coastguard Worker 		if (ctype(c, C_UPPER)) {
906*7c356e86SAndroid Build Coastguard Worker 			flags |= FL_UPPER;
907*7c356e86SAndroid Build Coastguard Worker 			c = ksh_tolower(c);
908*7c356e86SAndroid Build Coastguard Worker 		}
909*7c356e86SAndroid Build Coastguard Worker 
910*7c356e86SAndroid Build Coastguard Worker 		switch (c) {
911*7c356e86SAndroid Build Coastguard Worker 		case 'd':
912*7c356e86SAndroid Build Coastguard Worker 		case 'i':
913*7c356e86SAndroid Build Coastguard Worker 			if (flags & FL_SIZET)
914*7c356e86SAndroid Build Coastguard Worker 				lnum = (long)VA(ssize_t);
915*7c356e86SAndroid Build Coastguard Worker 			else if (flags & FL_LONG)
916*7c356e86SAndroid Build Coastguard Worker 				lnum = VA(long);
917*7c356e86SAndroid Build Coastguard Worker 			else if (flags & FL_SHORT)
918*7c356e86SAndroid Build Coastguard Worker 				lnum = (long)(short)VA(int);
919*7c356e86SAndroid Build Coastguard Worker 			else
920*7c356e86SAndroid Build Coastguard Worker 				lnum = (long)VA(int);
921*7c356e86SAndroid Build Coastguard Worker 			goto integral;
922*7c356e86SAndroid Build Coastguard Worker 
923*7c356e86SAndroid Build Coastguard Worker 		case 'o':
924*7c356e86SAndroid Build Coastguard Worker 		case 'u':
925*7c356e86SAndroid Build Coastguard Worker 		case 'x':
926*7c356e86SAndroid Build Coastguard Worker 			if (flags & FL_SIZET)
927*7c356e86SAndroid Build Coastguard Worker 				lnum = VA(size_t);
928*7c356e86SAndroid Build Coastguard Worker 			else if (flags & FL_LONG)
929*7c356e86SAndroid Build Coastguard Worker 				lnum = VA(unsigned long);
930*7c356e86SAndroid Build Coastguard Worker 			else if (flags & FL_SHORT)
931*7c356e86SAndroid Build Coastguard Worker 				lnum = (unsigned long)(unsigned short)VA(int);
932*7c356e86SAndroid Build Coastguard Worker 			else
933*7c356e86SAndroid Build Coastguard Worker 				lnum = (unsigned long)VA(unsigned int);
934*7c356e86SAndroid Build Coastguard Worker 
935*7c356e86SAndroid Build Coastguard Worker  integral:
936*7c356e86SAndroid Build Coastguard Worker 			flags |= FL_NUMBER;
937*7c356e86SAndroid Build Coastguard Worker 			cp = numbuf + sizeof(numbuf);
938*7c356e86SAndroid Build Coastguard Worker 			*--cp = '\0';
939*7c356e86SAndroid Build Coastguard Worker 
940*7c356e86SAndroid Build Coastguard Worker 			switch (c) {
941*7c356e86SAndroid Build Coastguard Worker 			case 'd':
942*7c356e86SAndroid Build Coastguard Worker 			case 'i':
943*7c356e86SAndroid Build Coastguard Worker 				if (0 > (long)lnum) {
944*7c356e86SAndroid Build Coastguard Worker 					lnum = -(long)lnum;
945*7c356e86SAndroid Build Coastguard Worker 					tmp = 1;
946*7c356e86SAndroid Build Coastguard Worker 				} else
947*7c356e86SAndroid Build Coastguard Worker 					tmp = 0;
948*7c356e86SAndroid Build Coastguard Worker 				/* FALLTHROUGH */
949*7c356e86SAndroid Build Coastguard Worker 			case 'u':
950*7c356e86SAndroid Build Coastguard Worker 				do {
951*7c356e86SAndroid Build Coastguard Worker 					*--cp = digits_lc[lnum % 10];
952*7c356e86SAndroid Build Coastguard Worker 					lnum /= 10;
953*7c356e86SAndroid Build Coastguard Worker 				} while (lnum);
954*7c356e86SAndroid Build Coastguard Worker 
955*7c356e86SAndroid Build Coastguard Worker 				if (c != 'u') {
956*7c356e86SAndroid Build Coastguard Worker 					if (tmp)
957*7c356e86SAndroid Build Coastguard Worker 						*--cp = '-';
958*7c356e86SAndroid Build Coastguard Worker 					else if (flags & FL_PLUS)
959*7c356e86SAndroid Build Coastguard Worker 						*--cp = '+';
960*7c356e86SAndroid Build Coastguard Worker 					else if (flags & FL_BLANK)
961*7c356e86SAndroid Build Coastguard Worker 						*--cp = ' ';
962*7c356e86SAndroid Build Coastguard Worker 				}
963*7c356e86SAndroid Build Coastguard Worker 				break;
964*7c356e86SAndroid Build Coastguard Worker 
965*7c356e86SAndroid Build Coastguard Worker 			case 'o':
966*7c356e86SAndroid Build Coastguard Worker 				do {
967*7c356e86SAndroid Build Coastguard Worker 					*--cp = digits_lc[lnum & 0x7];
968*7c356e86SAndroid Build Coastguard Worker 					lnum >>= 3;
969*7c356e86SAndroid Build Coastguard Worker 				} while (lnum);
970*7c356e86SAndroid Build Coastguard Worker 
971*7c356e86SAndroid Build Coastguard Worker 				if ((flags & FL_HASH) && *cp != '0')
972*7c356e86SAndroid Build Coastguard Worker 					*--cp = '0';
973*7c356e86SAndroid Build Coastguard Worker 				break;
974*7c356e86SAndroid Build Coastguard Worker 
975*7c356e86SAndroid Build Coastguard Worker 			case 'x': {
976*7c356e86SAndroid Build Coastguard Worker 				const char *digits = (flags & FL_UPPER) ?
977*7c356e86SAndroid Build Coastguard Worker 				    digits_uc : digits_lc;
978*7c356e86SAndroid Build Coastguard Worker 				do {
979*7c356e86SAndroid Build Coastguard Worker 					*--cp = digits[lnum & 0xF];
980*7c356e86SAndroid Build Coastguard Worker 					lnum >>= 4;
981*7c356e86SAndroid Build Coastguard Worker 				} while (lnum);
982*7c356e86SAndroid Build Coastguard Worker 
983*7c356e86SAndroid Build Coastguard Worker 				if (flags & FL_HASH) {
984*7c356e86SAndroid Build Coastguard Worker 					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
985*7c356e86SAndroid Build Coastguard Worker 					*--cp = '0';
986*7c356e86SAndroid Build Coastguard Worker 				}
987*7c356e86SAndroid Build Coastguard Worker 			    }
988*7c356e86SAndroid Build Coastguard Worker 			}
989*7c356e86SAndroid Build Coastguard Worker 			len = numbuf + sizeof(numbuf) - 1 - (s = cp);
990*7c356e86SAndroid Build Coastguard Worker 			if (flags & FL_DOT) {
991*7c356e86SAndroid Build Coastguard Worker 				if (precision > len) {
992*7c356e86SAndroid Build Coastguard Worker 					field = precision;
993*7c356e86SAndroid Build Coastguard Worker 					flags |= FL_ZERO;
994*7c356e86SAndroid Build Coastguard Worker 				} else
995*7c356e86SAndroid Build Coastguard Worker 					/* no loss */
996*7c356e86SAndroid Build Coastguard Worker 					precision = len;
997*7c356e86SAndroid Build Coastguard Worker 			}
998*7c356e86SAndroid Build Coastguard Worker 			break;
999*7c356e86SAndroid Build Coastguard Worker 
1000*7c356e86SAndroid Build Coastguard Worker 		case 's':
1001*7c356e86SAndroid Build Coastguard Worker 			if ((s = VA(const char *)) == NULL)
1002*7c356e86SAndroid Build Coastguard Worker 				s = "(null)";
1003*7c356e86SAndroid Build Coastguard Worker 			else if (flags & FL_HASH) {
1004*7c356e86SAndroid Build Coastguard Worker 				print_value_quoted(shf, s);
1005*7c356e86SAndroid Build Coastguard Worker 				continue;
1006*7c356e86SAndroid Build Coastguard Worker 			}
1007*7c356e86SAndroid Build Coastguard Worker 			len = utf_mbswidth(s);
1008*7c356e86SAndroid Build Coastguard Worker 			break;
1009*7c356e86SAndroid Build Coastguard Worker 
1010*7c356e86SAndroid Build Coastguard Worker 		case 'c':
1011*7c356e86SAndroid Build Coastguard Worker 			flags &= ~FL_DOT;
1012*7c356e86SAndroid Build Coastguard Worker 			c = (char)(VA(int));
1013*7c356e86SAndroid Build Coastguard Worker 			/* FALLTHROUGH */
1014*7c356e86SAndroid Build Coastguard Worker 
1015*7c356e86SAndroid Build Coastguard Worker 		case '%':
1016*7c356e86SAndroid Build Coastguard Worker 		default:
1017*7c356e86SAndroid Build Coastguard Worker 			numbuf[0] = c;
1018*7c356e86SAndroid Build Coastguard Worker 			numbuf[1] = 0;
1019*7c356e86SAndroid Build Coastguard Worker 			s = numbuf;
1020*7c356e86SAndroid Build Coastguard Worker 			len = 1;
1021*7c356e86SAndroid Build Coastguard Worker 			break;
1022*7c356e86SAndroid Build Coastguard Worker 		}
1023*7c356e86SAndroid Build Coastguard Worker 
1024*7c356e86SAndroid Build Coastguard Worker 		/*
1025*7c356e86SAndroid Build Coastguard Worker 		 * At this point s should point to a string that is to be
1026*7c356e86SAndroid Build Coastguard Worker 		 * formatted, and len should be the length of the string.
1027*7c356e86SAndroid Build Coastguard Worker 		 */
1028*7c356e86SAndroid Build Coastguard Worker 		if (!(flags & FL_DOT) || len < precision)
1029*7c356e86SAndroid Build Coastguard Worker 			precision = len;
1030*7c356e86SAndroid Build Coastguard Worker 		if (field > precision) {
1031*7c356e86SAndroid Build Coastguard Worker 			field -= precision;
1032*7c356e86SAndroid Build Coastguard Worker 			if (!(flags & FL_RIGHT)) {
1033*7c356e86SAndroid Build Coastguard Worker 				/* skip past sign or 0x when padding with 0 */
1034*7c356e86SAndroid Build Coastguard Worker 				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
1035*7c356e86SAndroid Build Coastguard Worker 					if (ctype(*s, C_SPC | C_PLUS | C_MINUS)) {
1036*7c356e86SAndroid Build Coastguard Worker 						shf_putc(*s, shf);
1037*7c356e86SAndroid Build Coastguard Worker 						s++;
1038*7c356e86SAndroid Build Coastguard Worker 						precision--;
1039*7c356e86SAndroid Build Coastguard Worker 						nwritten++;
1040*7c356e86SAndroid Build Coastguard Worker 					} else if (*s == '0') {
1041*7c356e86SAndroid Build Coastguard Worker 						shf_putc(*s, shf);
1042*7c356e86SAndroid Build Coastguard Worker 						s++;
1043*7c356e86SAndroid Build Coastguard Worker 						nwritten++;
1044*7c356e86SAndroid Build Coastguard Worker 						if (--precision &&
1045*7c356e86SAndroid Build Coastguard Worker 						    ksh_eq(*s, 'X', 'x')) {
1046*7c356e86SAndroid Build Coastguard Worker 							shf_putc(*s, shf);
1047*7c356e86SAndroid Build Coastguard Worker 							s++;
1048*7c356e86SAndroid Build Coastguard Worker 							precision--;
1049*7c356e86SAndroid Build Coastguard Worker 							nwritten++;
1050*7c356e86SAndroid Build Coastguard Worker 						}
1051*7c356e86SAndroid Build Coastguard Worker 					}
1052*7c356e86SAndroid Build Coastguard Worker 					c = '0';
1053*7c356e86SAndroid Build Coastguard Worker 				} else
1054*7c356e86SAndroid Build Coastguard Worker 					c = flags & FL_ZERO ? '0' : ' ';
1055*7c356e86SAndroid Build Coastguard Worker 				nwritten += field;
1056*7c356e86SAndroid Build Coastguard Worker 				while (field--)
1057*7c356e86SAndroid Build Coastguard Worker 					shf_putc(c, shf);
1058*7c356e86SAndroid Build Coastguard Worker 				field = 0;
1059*7c356e86SAndroid Build Coastguard Worker 			} else
1060*7c356e86SAndroid Build Coastguard Worker 				c = ' ';
1061*7c356e86SAndroid Build Coastguard Worker 		} else
1062*7c356e86SAndroid Build Coastguard Worker 			field = 0;
1063*7c356e86SAndroid Build Coastguard Worker 
1064*7c356e86SAndroid Build Coastguard Worker 		nwritten += precision;
1065*7c356e86SAndroid Build Coastguard Worker 		precision = utf_skipcols(s, precision, &tmp) - s;
1066*7c356e86SAndroid Build Coastguard Worker 		while (precision--)
1067*7c356e86SAndroid Build Coastguard Worker 			shf_putc(*s++, shf);
1068*7c356e86SAndroid Build Coastguard Worker 
1069*7c356e86SAndroid Build Coastguard Worker 		nwritten += field;
1070*7c356e86SAndroid Build Coastguard Worker 		while (field--)
1071*7c356e86SAndroid Build Coastguard Worker 			shf_putc(c, shf);
1072*7c356e86SAndroid Build Coastguard Worker 	}
1073*7c356e86SAndroid Build Coastguard Worker 
1074*7c356e86SAndroid Build Coastguard Worker 	return (shf_error(shf) ? -1 : nwritten);
1075*7c356e86SAndroid Build Coastguard Worker }
1076*7c356e86SAndroid Build Coastguard Worker 
1077*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_SHF_NO_INLINE
1078*7c356e86SAndroid Build Coastguard Worker int
shf_getc(struct shf * shf)1079*7c356e86SAndroid Build Coastguard Worker shf_getc(struct shf *shf)
1080*7c356e86SAndroid Build Coastguard Worker {
1081*7c356e86SAndroid Build Coastguard Worker 	return (shf_getc_i(shf));
1082*7c356e86SAndroid Build Coastguard Worker }
1083*7c356e86SAndroid Build Coastguard Worker 
1084*7c356e86SAndroid Build Coastguard Worker int
shf_putc(int c,struct shf * shf)1085*7c356e86SAndroid Build Coastguard Worker shf_putc(int c, struct shf *shf)
1086*7c356e86SAndroid Build Coastguard Worker {
1087*7c356e86SAndroid Build Coastguard Worker 	return (shf_putc_i(c, shf));
1088*7c356e86SAndroid Build Coastguard Worker }
1089*7c356e86SAndroid Build Coastguard Worker #endif
1090*7c356e86SAndroid Build Coastguard Worker 
1091*7c356e86SAndroid Build Coastguard Worker #ifdef DEBUG
1092*7c356e86SAndroid Build Coastguard Worker const char *
cstrerror(int errnum)1093*7c356e86SAndroid Build Coastguard Worker cstrerror(int errnum)
1094*7c356e86SAndroid Build Coastguard Worker {
1095*7c356e86SAndroid Build Coastguard Worker #undef strerror
1096*7c356e86SAndroid Build Coastguard Worker 	return (strerror(errnum));
1097*7c356e86SAndroid Build Coastguard Worker #define strerror dontuse_strerror /* poisoned */
1098*7c356e86SAndroid Build Coastguard Worker }
1099*7c356e86SAndroid Build Coastguard Worker #elif !HAVE_STRERROR
1100*7c356e86SAndroid Build Coastguard Worker 
1101*7c356e86SAndroid Build Coastguard Worker #if HAVE_SYS_ERRLIST
1102*7c356e86SAndroid Build Coastguard Worker #if !HAVE_SYS_ERRLIST_DECL
1103*7c356e86SAndroid Build Coastguard Worker extern const int sys_nerr;
1104*7c356e86SAndroid Build Coastguard Worker extern const char * const sys_errlist[];
1105*7c356e86SAndroid Build Coastguard Worker #endif
1106*7c356e86SAndroid Build Coastguard Worker #endif
1107*7c356e86SAndroid Build Coastguard Worker 
1108*7c356e86SAndroid Build Coastguard Worker const char *
cstrerror(int errnum)1109*7c356e86SAndroid Build Coastguard Worker cstrerror(int errnum)
1110*7c356e86SAndroid Build Coastguard Worker {
1111*7c356e86SAndroid Build Coastguard Worker 	/* "Unknown error: " + sign + rough estimate + NUL */
1112*7c356e86SAndroid Build Coastguard Worker 	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
1113*7c356e86SAndroid Build Coastguard Worker 
1114*7c356e86SAndroid Build Coastguard Worker #if HAVE_SYS_ERRLIST
1115*7c356e86SAndroid Build Coastguard Worker 	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
1116*7c356e86SAndroid Build Coastguard Worker 		return (sys_errlist[errnum]);
1117*7c356e86SAndroid Build Coastguard Worker #endif
1118*7c356e86SAndroid Build Coastguard Worker 
1119*7c356e86SAndroid Build Coastguard Worker 	switch (errnum) {
1120*7c356e86SAndroid Build Coastguard Worker 	case 0:
1121*7c356e86SAndroid Build Coastguard Worker 		return ("Undefined error: 0");
1122*7c356e86SAndroid Build Coastguard Worker 	case EPERM:
1123*7c356e86SAndroid Build Coastguard Worker 		return ("Operation not permitted");
1124*7c356e86SAndroid Build Coastguard Worker 	case ENOENT:
1125*7c356e86SAndroid Build Coastguard Worker 		return ("No such file or directory");
1126*7c356e86SAndroid Build Coastguard Worker #ifdef ESRCH
1127*7c356e86SAndroid Build Coastguard Worker 	case ESRCH:
1128*7c356e86SAndroid Build Coastguard Worker 		return ("No such process");
1129*7c356e86SAndroid Build Coastguard Worker #endif
1130*7c356e86SAndroid Build Coastguard Worker #ifdef E2BIG
1131*7c356e86SAndroid Build Coastguard Worker 	case E2BIG:
1132*7c356e86SAndroid Build Coastguard Worker 		return ("Argument list too long");
1133*7c356e86SAndroid Build Coastguard Worker #endif
1134*7c356e86SAndroid Build Coastguard Worker 	case ENOEXEC:
1135*7c356e86SAndroid Build Coastguard Worker 		return ("Exec format error");
1136*7c356e86SAndroid Build Coastguard Worker 	case EBADF:
1137*7c356e86SAndroid Build Coastguard Worker 		return ("Bad file descriptor");
1138*7c356e86SAndroid Build Coastguard Worker #ifdef ENOMEM
1139*7c356e86SAndroid Build Coastguard Worker 	case ENOMEM:
1140*7c356e86SAndroid Build Coastguard Worker 		return ("Cannot allocate memory");
1141*7c356e86SAndroid Build Coastguard Worker #endif
1142*7c356e86SAndroid Build Coastguard Worker 	case EACCES:
1143*7c356e86SAndroid Build Coastguard Worker 		return ("Permission denied");
1144*7c356e86SAndroid Build Coastguard Worker 	case EEXIST:
1145*7c356e86SAndroid Build Coastguard Worker 		return ("File exists");
1146*7c356e86SAndroid Build Coastguard Worker 	case ENOTDIR:
1147*7c356e86SAndroid Build Coastguard Worker 		return ("Not a directory");
1148*7c356e86SAndroid Build Coastguard Worker #ifdef EINVAL
1149*7c356e86SAndroid Build Coastguard Worker 	case EINVAL:
1150*7c356e86SAndroid Build Coastguard Worker 		return ("Invalid argument");
1151*7c356e86SAndroid Build Coastguard Worker #endif
1152*7c356e86SAndroid Build Coastguard Worker #ifdef ELOOP
1153*7c356e86SAndroid Build Coastguard Worker 	case ELOOP:
1154*7c356e86SAndroid Build Coastguard Worker 		return ("Too many levels of symbolic links");
1155*7c356e86SAndroid Build Coastguard Worker #endif
1156*7c356e86SAndroid Build Coastguard Worker 	default:
1157*7c356e86SAndroid Build Coastguard Worker 		shf_snprintf(errbuf, sizeof(errbuf),
1158*7c356e86SAndroid Build Coastguard Worker 		    "Unknown error: %d", errnum);
1159*7c356e86SAndroid Build Coastguard Worker 		return (errbuf);
1160*7c356e86SAndroid Build Coastguard Worker 	}
1161*7c356e86SAndroid Build Coastguard Worker }
1162*7c356e86SAndroid Build Coastguard Worker #endif
1163*7c356e86SAndroid Build Coastguard Worker 
1164*7c356e86SAndroid Build Coastguard Worker /* fast character classes */
1165*7c356e86SAndroid Build Coastguard Worker const uint32_t tpl_ctypes[128] = {
1166*7c356e86SAndroid Build Coastguard Worker 	/* 0x00 */
1167*7c356e86SAndroid Build Coastguard Worker 	CiNUL,		CiCNTRL,	CiCNTRL,	CiCNTRL,
1168*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
1169*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiTAB,		CiNL,		CiSPX,
1170*7c356e86SAndroid Build Coastguard Worker 	CiSPX,		CiCR,		CiCNTRL,	CiCNTRL,
1171*7c356e86SAndroid Build Coastguard Worker 	/* 0x10 */
1172*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
1173*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
1174*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
1175*7c356e86SAndroid Build Coastguard Worker 	CiCNTRL,	CiCNTRL,	CiCNTRL,	CiCNTRL,
1176*7c356e86SAndroid Build Coastguard Worker 	/* 0x20 */
1177*7c356e86SAndroid Build Coastguard Worker 	CiSP,		CiALIAS | CiVAR1,	CiQC,	CiHASH,
1178*7c356e86SAndroid Build Coastguard Worker 	CiSS,		CiPERCT,	CiQCL,		CiQC,
1179*7c356e86SAndroid Build Coastguard Worker 	CiQCL,		CiQCL,		CiQCX | CiVAR1,	CiPLUS,
1180*7c356e86SAndroid Build Coastguard Worker 	CiALIAS,	CiMINUS,	CiALIAS,	CiQCM,
1181*7c356e86SAndroid Build Coastguard Worker 	/* 0x30 */
1182*7c356e86SAndroid Build Coastguard Worker 	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
1183*7c356e86SAndroid Build Coastguard Worker 	CiOCTAL,	CiOCTAL,	CiOCTAL,	CiOCTAL,
1184*7c356e86SAndroid Build Coastguard Worker 	CiDIGIT,	CiDIGIT,	CiCOLON,	CiQCL,
1185*7c356e86SAndroid Build Coastguard Worker 	CiANGLE,	CiEQUAL,	CiANGLE,	CiQUEST,
1186*7c356e86SAndroid Build Coastguard Worker 	/* 0x40 */
1187*7c356e86SAndroid Build Coastguard Worker 	CiALIAS | CiVAR1,	CiUPPER | CiHEXLT,
1188*7c356e86SAndroid Build Coastguard Worker 	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
1189*7c356e86SAndroid Build Coastguard Worker 	CiUPPER | CiHEXLT,	CiUPPER | CiHEXLT,
1190*7c356e86SAndroid Build Coastguard Worker 	CiUPPER | CiHEXLT,	CiUPPER,
1191*7c356e86SAndroid Build Coastguard Worker 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
1192*7c356e86SAndroid Build Coastguard Worker 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
1193*7c356e86SAndroid Build Coastguard Worker 	/* 0x50 */
1194*7c356e86SAndroid Build Coastguard Worker 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
1195*7c356e86SAndroid Build Coastguard Worker 	CiUPPER,	CiUPPER,	CiUPPER,	CiUPPER,
1196*7c356e86SAndroid Build Coastguard Worker 	CiUPPER,	CiUPPER,	CiUPPER,	CiQCX | CiBRACK,
1197*7c356e86SAndroid Build Coastguard Worker 	CiQCX,		CiBRACK,	CiQCM,		CiUNDER,
1198*7c356e86SAndroid Build Coastguard Worker 	/* 0x60 */
1199*7c356e86SAndroid Build Coastguard Worker 	CiGRAVE,		CiLOWER | CiHEXLT,
1200*7c356e86SAndroid Build Coastguard Worker 	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
1201*7c356e86SAndroid Build Coastguard Worker 	CiLOWER | CiHEXLT,	CiLOWER | CiHEXLT,
1202*7c356e86SAndroid Build Coastguard Worker 	CiLOWER | CiHEXLT,	CiLOWER,
1203*7c356e86SAndroid Build Coastguard Worker 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
1204*7c356e86SAndroid Build Coastguard Worker 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
1205*7c356e86SAndroid Build Coastguard Worker 	/* 0x70 */
1206*7c356e86SAndroid Build Coastguard Worker 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
1207*7c356e86SAndroid Build Coastguard Worker 	CiLOWER,	CiLOWER,	CiLOWER,	CiLOWER,
1208*7c356e86SAndroid Build Coastguard Worker 	CiLOWER,	CiLOWER,	CiLOWER,	CiCURLY,
1209*7c356e86SAndroid Build Coastguard Worker 	CiQCL,		CiCURLY,	CiQCM,		CiCNTRL
1210*7c356e86SAndroid Build Coastguard Worker };
1211*7c356e86SAndroid Build Coastguard Worker 
1212*7c356e86SAndroid Build Coastguard Worker void
set_ifs(const char * s)1213*7c356e86SAndroid Build Coastguard Worker set_ifs(const char *s)
1214*7c356e86SAndroid Build Coastguard Worker {
1215*7c356e86SAndroid Build Coastguard Worker #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
1216*7c356e86SAndroid Build Coastguard Worker 	int i = 256;
1217*7c356e86SAndroid Build Coastguard Worker 
1218*7c356e86SAndroid Build Coastguard Worker 	memset(ksh_ctypes, 0, sizeof(ksh_ctypes));
1219*7c356e86SAndroid Build Coastguard Worker 	while (i--)
1220*7c356e86SAndroid Build Coastguard Worker 		if (ebcdic_map[i] < 0x80U)
1221*7c356e86SAndroid Build Coastguard Worker 			ksh_ctypes[i] = tpl_ctypes[ebcdic_map[i]];
1222*7c356e86SAndroid Build Coastguard Worker #else
1223*7c356e86SAndroid Build Coastguard Worker 	memcpy(ksh_ctypes, tpl_ctypes, sizeof(tpl_ctypes));
1224*7c356e86SAndroid Build Coastguard Worker 	memset((char *)ksh_ctypes + sizeof(tpl_ctypes), '\0',
1225*7c356e86SAndroid Build Coastguard Worker 	    sizeof(ksh_ctypes) - sizeof(tpl_ctypes));
1226*7c356e86SAndroid Build Coastguard Worker #endif
1227*7c356e86SAndroid Build Coastguard Worker 	ifs0 = *s;
1228*7c356e86SAndroid Build Coastguard Worker 	while (*s)
1229*7c356e86SAndroid Build Coastguard Worker 		ksh_ctypes[ord(*s++)] |= CiIFS;
1230*7c356e86SAndroid Build Coastguard Worker }
1231*7c356e86SAndroid Build Coastguard Worker 
1232*7c356e86SAndroid Build Coastguard Worker #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
1233*7c356e86SAndroid Build Coastguard Worker #include <locale.h>
1234*7c356e86SAndroid Build Coastguard Worker 
1235*7c356e86SAndroid Build Coastguard Worker /*
1236*7c356e86SAndroid Build Coastguard Worker  * Many headaches with EBCDIC:
1237*7c356e86SAndroid Build Coastguard Worker  * 1. There are numerous EBCDIC variants, and it is not feasible for us
1238*7c356e86SAndroid Build Coastguard Worker  *    to support them all. But we can support the EBCDIC code pages that
1239*7c356e86SAndroid Build Coastguard Worker  *    contain all (most?) of the characters in ASCII, and these
1240*7c356e86SAndroid Build Coastguard Worker  *    usually tend to agree on the code points assigned to the ASCII
1241*7c356e86SAndroid Build Coastguard Worker  *    subset. If you need a representative example, look at EBCDIC 1047,
1242*7c356e86SAndroid Build Coastguard Worker  *    which is first among equals in the IBM MVS development
1243*7c356e86SAndroid Build Coastguard Worker  *    environment: https://en.wikipedia.org/wiki/EBCDIC_1047
1244*7c356e86SAndroid Build Coastguard Worker  *    Unfortunately, the square brackets are not consistently mapped,
1245*7c356e86SAndroid Build Coastguard Worker  *    and for certain reasons, we need an unambiguous bijective
1246*7c356e86SAndroid Build Coastguard Worker  *    mapping between EBCDIC and "extended ASCII".
1247*7c356e86SAndroid Build Coastguard Worker  * 2. Character ranges that are contiguous in ASCII, like the letters
1248*7c356e86SAndroid Build Coastguard Worker  *    in [A-Z], are broken up into segments (i.e. [A-IJ-RS-Z]), so we
1249*7c356e86SAndroid Build Coastguard Worker  *    can't implement e.g. islower() as { return c >= 'a' && c <= 'z'; }
1250*7c356e86SAndroid Build Coastguard Worker  *    because it will also return true for a handful of extraneous
1251*7c356e86SAndroid Build Coastguard Worker  *    characters (like the plus-minus sign at 0x8F in EBCDIC 1047, a
1252*7c356e86SAndroid Build Coastguard Worker  *    little after 'i'). But at least '_' is not one of these.
1253*7c356e86SAndroid Build Coastguard Worker  * 3. The normal [0-9A-Za-z] characters are at codepoints beyond 0x80.
1254*7c356e86SAndroid Build Coastguard Worker  *    Not only do they require all 8 bits instead of 7, if chars are
1255*7c356e86SAndroid Build Coastguard Worker  *    signed, they will have negative integer values! Something like
1256*7c356e86SAndroid Build Coastguard Worker  *    (c - 'A') could actually become (c + 63)! Use the ord() macro to
1257*7c356e86SAndroid Build Coastguard Worker  *    ensure you're getting a value in [0, 255] (ORD for constants).
1258*7c356e86SAndroid Build Coastguard Worker  * 4. '\n' is actually NL (0x15, U+0085) instead of LF (0x25, U+000A).
1259*7c356e86SAndroid Build Coastguard Worker  *    EBCDIC has a proper newline character instead of "emulating" one
1260*7c356e86SAndroid Build Coastguard Worker  *    with line feeds, although this is mapped to LF for our purposes.
1261*7c356e86SAndroid Build Coastguard Worker  * 5. Note that it is possible to compile programs in ASCII mode on IBM
1262*7c356e86SAndroid Build Coastguard Worker  *    mainframe systems, using the -qascii option to the XL C compiler.
1263*7c356e86SAndroid Build Coastguard Worker  *    We can determine the build mode by looking at __CHARSET_LIB:
1264*7c356e86SAndroid Build Coastguard Worker  *    0 == EBCDIC, 1 == ASCII
1265*7c356e86SAndroid Build Coastguard Worker  */
1266*7c356e86SAndroid Build Coastguard Worker 
1267*7c356e86SAndroid Build Coastguard Worker void
ebcdic_init(void)1268*7c356e86SAndroid Build Coastguard Worker ebcdic_init(void)
1269*7c356e86SAndroid Build Coastguard Worker {
1270*7c356e86SAndroid Build Coastguard Worker 	int i = 256;
1271*7c356e86SAndroid Build Coastguard Worker 	unsigned char t;
1272*7c356e86SAndroid Build Coastguard Worker 	bool mapcache[256];
1273*7c356e86SAndroid Build Coastguard Worker 
1274*7c356e86SAndroid Build Coastguard Worker 	while (i--)
1275*7c356e86SAndroid Build Coastguard Worker 		ebcdic_rtt_toascii[i] = i;
1276*7c356e86SAndroid Build Coastguard Worker 	memset(ebcdic_rtt_fromascii, 0xFF, sizeof(ebcdic_rtt_fromascii));
1277*7c356e86SAndroid Build Coastguard Worker 	setlocale(LC_ALL, "");
1278*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_EBCDIC
1279*7c356e86SAndroid Build Coastguard Worker 	if (__etoa_l(ebcdic_rtt_toascii, 256) != 256) {
1280*7c356e86SAndroid Build Coastguard Worker 		write(2, "mksh: could not map EBCDIC to ASCII\n", 36);
1281*7c356e86SAndroid Build Coastguard Worker 		exit(255);
1282*7c356e86SAndroid Build Coastguard Worker 	}
1283*7c356e86SAndroid Build Coastguard Worker #endif
1284*7c356e86SAndroid Build Coastguard Worker 
1285*7c356e86SAndroid Build Coastguard Worker 	memset(mapcache, 0, sizeof(mapcache));
1286*7c356e86SAndroid Build Coastguard Worker 	i = 256;
1287*7c356e86SAndroid Build Coastguard Worker 	while (i--) {
1288*7c356e86SAndroid Build Coastguard Worker 		t = ebcdic_rtt_toascii[i];
1289*7c356e86SAndroid Build Coastguard Worker 		/* ensure unique round-trip capable mapping */
1290*7c356e86SAndroid Build Coastguard Worker 		if (mapcache[t]) {
1291*7c356e86SAndroid Build Coastguard Worker 			write(2, "mksh: duplicate EBCDIC to ASCII mapping\n", 40);
1292*7c356e86SAndroid Build Coastguard Worker 			exit(255);
1293*7c356e86SAndroid Build Coastguard Worker 		}
1294*7c356e86SAndroid Build Coastguard Worker 		/*
1295*7c356e86SAndroid Build Coastguard Worker 		 * since there are 256 input octets, this also ensures
1296*7c356e86SAndroid Build Coastguard Worker 		 * the other mapping direction is completely filled
1297*7c356e86SAndroid Build Coastguard Worker 		 */
1298*7c356e86SAndroid Build Coastguard Worker 		mapcache[t] = true;
1299*7c356e86SAndroid Build Coastguard Worker 		/* fill the complete round-trip map */
1300*7c356e86SAndroid Build Coastguard Worker 		ebcdic_rtt_fromascii[t] = i;
1301*7c356e86SAndroid Build Coastguard Worker 		/*
1302*7c356e86SAndroid Build Coastguard Worker 		 * Only use the converted value if it's in the range
1303*7c356e86SAndroid Build Coastguard Worker 		 * [0x00; 0x7F], which I checked; the "extended ASCII"
1304*7c356e86SAndroid Build Coastguard Worker 		 * characters can be any encoding, not just Latin1,
1305*7c356e86SAndroid Build Coastguard Worker 		 * and the C1 control characters other than NEL are
1306*7c356e86SAndroid Build Coastguard Worker 		 * hopeless, but we map EBCDIC NEL to ASCII LF so we
1307*7c356e86SAndroid Build Coastguard Worker 		 * cannot even use C1 NEL.
1308*7c356e86SAndroid Build Coastguard Worker 		 * If ever we map to UCS, bump the table width to
1309*7c356e86SAndroid Build Coastguard Worker 		 * an unsigned int, and or the raw unconverted EBCDIC
1310*7c356e86SAndroid Build Coastguard Worker 		 * values with 0x01000000 instead.
1311*7c356e86SAndroid Build Coastguard Worker 		 */
1312*7c356e86SAndroid Build Coastguard Worker 		if (t < 0x80U)
1313*7c356e86SAndroid Build Coastguard Worker 			ebcdic_map[i] = (unsigned short)ord(t);
1314*7c356e86SAndroid Build Coastguard Worker 		else
1315*7c356e86SAndroid Build Coastguard Worker 			ebcdic_map[i] = (unsigned short)(0x100U | ord(i));
1316*7c356e86SAndroid Build Coastguard Worker 	}
1317*7c356e86SAndroid Build Coastguard Worker 	if (ebcdic_rtt_toascii[0] || ebcdic_rtt_fromascii[0] || ebcdic_map[0]) {
1318*7c356e86SAndroid Build Coastguard Worker 		write(2, "mksh: NUL not at position 0\n", 28);
1319*7c356e86SAndroid Build Coastguard Worker 		exit(255);
1320*7c356e86SAndroid Build Coastguard Worker 	}
1321*7c356e86SAndroid Build Coastguard Worker }
1322*7c356e86SAndroid Build Coastguard Worker #endif
1323