1/*	$OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $	*/
2
3/*-
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5 *		 2012, 2013, 2015, 2016
6 *	mirabilos <m@mirbsd.org>
7 *
8 * Provided that these terms and disclaimer and all copyright notices
9 * are retained or reproduced in an accompanying document, permission
10 * is granted to deal in this work without restriction, including un-
11 * limited rights to use, publicly perform, distribute, sell, modify,
12 * merge, give away, or sublicence.
13 *
14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15 * the utmost extent permitted by applicable law, neither express nor
16 * implied; without malicious intent or gross negligence. In no event
17 * may a licensor, author or contributor be held liable for indirect,
18 * direct, other damage, loss, or other issues arising in any way out
19 * of dealing in the work, even if advised of the possibility of such
20 * damage or existence of a defect, except proven that it results out
21 * of said person's immediate fault when using the work as intended.
22 *-
23 * Use %zX instead of %p and floating point isn't supported at all.
24 */
25
26#include "sh.h"
27
28__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.76 2016/07/25 00:04:47 tg Exp $");
29
30/* flags to shf_emptybuf() */
31#define EB_READSW	0x01	/* about to switch to reading */
32#define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
33
34/*
35 * Replacement stdio routines. Stdio is too flakey on too many machines
36 * to be useful when you have multiple processes using the same underlying
37 * file descriptors.
38 */
39
40static int shf_fillbuf(struct shf *);
41static int shf_emptybuf(struct shf *, int);
42
43/*
44 * Open a file. First three args are for open(), last arg is flags for
45 * this package. Returns NULL if file could not be opened, or if a dup
46 * fails.
47 */
48struct shf *
49shf_open(const char *name, int oflags, int mode, int sflags)
50{
51	struct shf *shf;
52	ssize_t bsize =
53	    /* at most 512 */
54	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
55	int fd, eno;
56
57	/* Done before open so if alloca fails, fd won't be lost. */
58	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
59	shf->areap = ATEMP;
60	shf->buf = (unsigned char *)&shf[1];
61	shf->bsize = bsize;
62	shf->flags = SHF_ALLOCS;
63	/* Rest filled in by reopen. */
64
65	fd = binopen3(name, oflags, mode);
66	if (fd < 0) {
67		eno = errno;
68		afree(shf, shf->areap);
69		errno = eno;
70		return (NULL);
71	}
72	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
73		int nfd;
74
75		nfd = fcntl(fd, F_DUPFD, FDBASE);
76		eno = errno;
77		close(fd);
78		if (nfd < 0) {
79			afree(shf, shf->areap);
80			errno = eno;
81			return (NULL);
82		}
83		fd = nfd;
84	}
85	sflags &= ~SHF_ACCMODE;
86	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD :
87	    ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR);
88
89	return (shf_reopen(fd, sflags, shf));
90}
91
92/* helper function for shf_fdopen and shf_reopen */
93static void
94shf_open_hlp(int fd, int *sflagsp, const char *where)
95{
96	int sflags = *sflagsp;
97
98	/* use fcntl() to figure out correct read/write flags */
99	if (sflags & SHF_GETFL) {
100		int flags = fcntl(fd, F_GETFL, 0);
101
102		if (flags < 0)
103			/* will get an error on first read/write */
104			sflags |= SHF_RDWR;
105		else {
106			switch (flags & O_ACCMODE) {
107			case O_RDONLY:
108				sflags |= SHF_RD;
109				break;
110			case O_WRONLY:
111				sflags |= SHF_WR;
112				break;
113			case O_RDWR:
114				sflags |= SHF_RDWR;
115				break;
116			}
117		}
118		*sflagsp = sflags;
119	}
120
121	if (!(sflags & (SHF_RD | SHF_WR)))
122		internal_errorf(Tf_sD_s, where, "missing read/write");
123}
124
125/* Set up the shf structure for a file descriptor. Doesn't fail. */
126struct shf *
127shf_fdopen(int fd, int sflags, struct shf *shf)
128{
129	ssize_t bsize =
130	    /* at most 512 */
131	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
132
133	shf_open_hlp(fd, &sflags, "shf_fdopen");
134	if (shf) {
135		if (bsize) {
136			shf->buf = alloc(bsize, ATEMP);
137			sflags |= SHF_ALLOCB;
138		} else
139			shf->buf = NULL;
140	} else {
141		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
142		shf->buf = (unsigned char *)&shf[1];
143		sflags |= SHF_ALLOCS;
144	}
145	shf->areap = ATEMP;
146	shf->fd = fd;
147	shf->rp = shf->wp = shf->buf;
148	shf->rnleft = 0;
149	shf->rbsize = bsize;
150	shf->wnleft = 0; /* force call to shf_emptybuf() */
151	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
152	shf->flags = sflags;
153	shf->errnosv = 0;
154	shf->bsize = bsize;
155	if (sflags & SHF_CLEXEC)
156		fcntl(fd, F_SETFD, FD_CLOEXEC);
157	return (shf);
158}
159
160/* Set up an existing shf (and buffer) to use the given fd */
161struct shf *
162shf_reopen(int fd, int sflags, struct shf *shf)
163{
164	ssize_t bsize =
165	    /* at most 512 */
166	    sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
167
168	shf_open_hlp(fd, &sflags, "shf_reopen");
169	if (!shf || !shf->buf || shf->bsize < bsize)
170		internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
171
172	/* assumes shf->buf and shf->bsize already set up */
173	shf->fd = fd;
174	shf->rp = shf->wp = shf->buf;
175	shf->rnleft = 0;
176	shf->rbsize = bsize;
177	shf->wnleft = 0; /* force call to shf_emptybuf() */
178	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
179	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
180	shf->errnosv = 0;
181	if (sflags & SHF_CLEXEC)
182		fcntl(fd, F_SETFD, FD_CLOEXEC);
183	return (shf);
184}
185
186/*
187 * Open a string for reading or writing. If reading, bsize is the number
188 * of bytes that can be read. If writing, bsize is the maximum number of
189 * bytes that can be written. If shf is not NULL, it is filled in and
190 * returned, if it is NULL, shf is allocated. If writing and buf is NULL
191 * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
192 * used for the initial size). Doesn't fail.
193 * When writing, a byte is reserved for a trailing NUL - see shf_sclose().
194 */
195struct shf *
196shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
197{
198	/* can't have a read+write string */
199	if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
200		internal_errorf(Tf_flags, "shf_sopen",
201		    (unsigned int)sflags);
202
203	if (!shf) {
204		shf = alloc(sizeof(struct shf), ATEMP);
205		sflags |= SHF_ALLOCS;
206	}
207	shf->areap = ATEMP;
208	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
209		if (bsize <= 0)
210			bsize = 64;
211		sflags |= SHF_ALLOCB;
212		buf = alloc(bsize, shf->areap);
213	}
214	shf->fd = -1;
215	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
216	shf->rnleft = bsize;
217	shf->rbsize = bsize;
218	shf->wnleft = bsize - 1;	/* space for a '\0' */
219	shf->wbsize = bsize;
220	shf->flags = sflags | SHF_STRING;
221	shf->errnosv = 0;
222	shf->bsize = bsize;
223
224	return (shf);
225}
226
227/* Flush and close file descriptor, free the shf structure */
228int
229shf_close(struct shf *shf)
230{
231	int ret = 0;
232
233	if (shf->fd >= 0) {
234		ret = shf_flush(shf);
235		if (close(shf->fd) < 0)
236			ret = -1;
237	}
238	if (shf->flags & SHF_ALLOCS)
239		afree(shf, shf->areap);
240	else if (shf->flags & SHF_ALLOCB)
241		afree(shf->buf, shf->areap);
242
243	return (ret);
244}
245
246/* Flush and close file descriptor, don't free file structure */
247int
248shf_fdclose(struct shf *shf)
249{
250	int ret = 0;
251
252	if (shf->fd >= 0) {
253		ret = shf_flush(shf);
254		if (close(shf->fd) < 0)
255			ret = -1;
256		shf->rnleft = 0;
257		shf->rp = shf->buf;
258		shf->wnleft = 0;
259		shf->fd = -1;
260	}
261
262	return (ret);
263}
264
265/*
266 * Close a string - if it was opened for writing, it is NUL terminated;
267 * returns a pointer to the string and frees shf if it was allocated
268 * (does not free string if it was allocated).
269 */
270char *
271shf_sclose(struct shf *shf)
272{
273	unsigned char *s = shf->buf;
274
275	/* NUL terminate */
276	if (shf->flags & SHF_WR) {
277		shf->wnleft++;
278		shf_putc('\0', shf);
279	}
280	if (shf->flags & SHF_ALLOCS)
281		afree(shf, shf->areap);
282	return ((char *)s);
283}
284
285/*
286 * Un-read what has been read but not examined, or write what has been
287 * buffered. Returns 0 for success, -1 for (write) error.
288 */
289int
290shf_flush(struct shf *shf)
291{
292	if (shf->flags & SHF_STRING)
293		return ((shf->flags & SHF_WR) ? -1 : 0);
294
295	if (shf->fd < 0)
296		internal_errorf(Tf_sD_s, "shf_flush", "no fd");
297
298	if (shf->flags & SHF_ERROR) {
299		errno = shf->errnosv;
300		return (-1);
301	}
302
303	if (shf->flags & SHF_READING) {
304		shf->flags &= ~(SHF_EOF | SHF_READING);
305		if (shf->rnleft > 0) {
306			lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR);
307			shf->rnleft = 0;
308			shf->rp = shf->buf;
309		}
310		return (0);
311	} else if (shf->flags & SHF_WRITING)
312		return (shf_emptybuf(shf, 0));
313
314	return (0);
315}
316
317/*
318 * Write out any buffered data. If currently reading, flushes the read
319 * buffer. Returns 0 for success, -1 for (write) error.
320 */
321static int
322shf_emptybuf(struct shf *shf, int flags)
323{
324	int ret = 0;
325
326	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
327		internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
328
329	if (shf->flags & SHF_ERROR) {
330		errno = shf->errnosv;
331		return (-1);
332	}
333
334	if (shf->flags & SHF_READING) {
335		if (flags & EB_READSW)
336			/* doesn't happen */
337			return (0);
338		ret = shf_flush(shf);
339		shf->flags &= ~SHF_READING;
340	}
341	if (shf->flags & SHF_STRING) {
342		unsigned char *nbuf;
343
344		/*
345		 * Note that we assume SHF_ALLOCS is not set if
346		 * SHF_ALLOCB is set... (changing the shf pointer could
347		 * cause problems)
348		 */
349		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
350		    !(shf->flags & SHF_ALLOCB))
351			return (-1);
352		/* allocate more space for buffer */
353		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
354		shf->rp = nbuf + (shf->rp - shf->buf);
355		shf->wp = nbuf + (shf->wp - shf->buf);
356		shf->rbsize += shf->wbsize;
357		shf->wnleft += shf->wbsize;
358		shf->wbsize <<= 1;
359		shf->buf = nbuf;
360	} else {
361		if (shf->flags & SHF_WRITING) {
362			ssize_t n, ntowrite = shf->wp - shf->buf;
363			unsigned char *buf = shf->buf;
364
365			while (ntowrite > 0) {
366				n = write(shf->fd, buf, ntowrite);
367				if (n < 0) {
368					if (errno == EINTR &&
369					    !(shf->flags & SHF_INTERRUPT))
370						continue;
371					shf->flags |= SHF_ERROR;
372					shf->errnosv = errno;
373					shf->wnleft = 0;
374					if (buf != shf->buf) {
375						/*
376						 * allow a second flush
377						 * to work
378						 */
379						memmove(shf->buf, buf,
380						    ntowrite);
381						shf->wp = shf->buf + ntowrite;
382					}
383					return (-1);
384				}
385				buf += n;
386				ntowrite -= n;
387			}
388			if (flags & EB_READSW) {
389				shf->wp = shf->buf;
390				shf->wnleft = 0;
391				shf->flags &= ~SHF_WRITING;
392				return (0);
393			}
394		}
395		shf->wp = shf->buf;
396		shf->wnleft = shf->wbsize;
397	}
398	shf->flags |= SHF_WRITING;
399
400	return (ret);
401}
402
403/* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */
404static int
405shf_fillbuf(struct shf *shf)
406{
407	ssize_t n;
408
409	if (shf->flags & SHF_STRING)
410		return (0);
411
412	if (shf->fd < 0)
413		internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
414
415	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
416		if (shf->flags & SHF_ERROR)
417			errno = shf->errnosv;
418		return (-1);
419	}
420
421	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
422		return (-1);
423
424	shf->flags |= SHF_READING;
425
426	shf->rp = shf->buf;
427	while (/* CONSTCOND */ 1) {
428		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
429		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
430			continue;
431		break;
432	}
433	if (n < 0) {
434		shf->flags |= SHF_ERROR;
435		shf->errnosv = errno;
436		shf->rnleft = 0;
437		shf->rp = shf->buf;
438		return (-1);
439	}
440	if ((shf->rnleft = n) == 0)
441		shf->flags |= SHF_EOF;
442	return (0);
443}
444
445/*
446 * Read a buffer from shf. Returns the number of bytes read into buf, if
447 * no bytes were read, returns 0 if end of file was seen, -1 if a read
448 * error occurred.
449 */
450ssize_t
451shf_read(char *buf, ssize_t bsize, struct shf *shf)
452{
453	ssize_t ncopy, orig_bsize = bsize;
454
455	if (!(shf->flags & SHF_RD))
456		internal_errorf(Tf_flags, Tshf_read,
457		    (unsigned int)shf->flags);
458
459	if (bsize <= 0)
460		internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
461
462	while (bsize > 0) {
463		if (shf->rnleft == 0 &&
464		    (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
465			break;
466		ncopy = shf->rnleft;
467		if (ncopy > bsize)
468			ncopy = bsize;
469		memcpy(buf, shf->rp, ncopy);
470		buf += ncopy;
471		bsize -= ncopy;
472		shf->rp += ncopy;
473		shf->rnleft -= ncopy;
474	}
475	/* Note: fread(3S) returns 0 for errors - this doesn't */
476	return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) :
477	    orig_bsize - bsize);
478}
479
480/*
481 * Read up to a newline or -1. The newline is put in buf; buf is always
482 * NUL terminated. Returns NULL on read error or if nothing was read
483 * before end of file, returns a pointer to the NUL byte in buf
484 * otherwise.
485 */
486char *
487shf_getse(char *buf, ssize_t bsize, struct shf *shf)
488{
489	unsigned char *end;
490	ssize_t ncopy;
491	char *orig_buf = buf;
492
493	if (!(shf->flags & SHF_RD))
494		internal_errorf(Tf_flags, "shf_getse",
495		    (unsigned int)shf->flags);
496
497	if (bsize <= 0)
498		return (NULL);
499
500	/* save room for NUL */
501	--bsize;
502	do {
503		if (shf->rnleft == 0) {
504			if (shf_fillbuf(shf) == -1)
505				return (NULL);
506			if (shf->rnleft == 0) {
507				*buf = '\0';
508				return (buf == orig_buf ? NULL : buf);
509			}
510		}
511		end = (unsigned char *)memchr((char *)shf->rp, '\n',
512		    shf->rnleft);
513		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
514		if (ncopy > bsize)
515			ncopy = bsize;
516		memcpy(buf, (char *) shf->rp, ncopy);
517		shf->rp += ncopy;
518		shf->rnleft -= ncopy;
519		buf += ncopy;
520		bsize -= ncopy;
521	} while (!end && bsize);
522	*buf = '\0';
523	return (buf);
524}
525
526/* Returns the char read. Returns -1 for error and end of file. */
527int
528shf_getchar(struct shf *shf)
529{
530	if (!(shf->flags & SHF_RD))
531		internal_errorf(Tf_flags, "shf_getchar",
532		    (unsigned int)shf->flags);
533
534	if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
535		return (-1);
536	--shf->rnleft;
537	return (*shf->rp++);
538}
539
540/*
541 * Put a character back in the input stream. Returns the character if
542 * successful, -1 if there is no room.
543 */
544int
545shf_ungetc(int c, struct shf *shf)
546{
547	if (!(shf->flags & SHF_RD))
548		internal_errorf(Tf_flags, "shf_ungetc",
549		    (unsigned int)shf->flags);
550
551	if ((shf->flags & SHF_ERROR) || c == -1 ||
552	    (shf->rp == shf->buf && shf->rnleft))
553		return (-1);
554
555	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1)
556		return (-1);
557
558	if (shf->rp == shf->buf)
559		shf->rp = shf->buf + shf->rbsize;
560	if (shf->flags & SHF_STRING) {
561		/*
562		 * Can unget what was read, but not something different;
563		 * we don't want to modify a string.
564		 */
565		if ((int)(shf->rp[-1]) != c)
566			return (-1);
567		shf->flags &= ~SHF_EOF;
568		shf->rp--;
569		shf->rnleft++;
570		return (c);
571	}
572	shf->flags &= ~SHF_EOF;
573	*--(shf->rp) = c;
574	shf->rnleft++;
575	return (c);
576}
577
578/*
579 * Write a character. Returns the character if successful, -1 if the
580 * char could not be written.
581 */
582int
583shf_putchar(int c, struct shf *shf)
584{
585	if (!(shf->flags & SHF_WR))
586		internal_errorf(Tf_flags, "shf_putchar",
587		    (unsigned int)shf->flags);
588
589	if (c == -1)
590		return (-1);
591
592	if (shf->flags & SHF_UNBUF) {
593		unsigned char cc = (unsigned char)c;
594		ssize_t n;
595
596		if (shf->fd < 0)
597			internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
598		if (shf->flags & SHF_ERROR) {
599			errno = shf->errnosv;
600			return (-1);
601		}
602		while ((n = write(shf->fd, &cc, 1)) != 1)
603			if (n < 0) {
604				if (errno == EINTR &&
605				    !(shf->flags & SHF_INTERRUPT))
606					continue;
607				shf->flags |= SHF_ERROR;
608				shf->errnosv = errno;
609				return (-1);
610			}
611	} else {
612		/* Flush deals with strings and sticky errors */
613		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1)
614			return (-1);
615		shf->wnleft--;
616		*shf->wp++ = c;
617	}
618
619	return (c);
620}
621
622/*
623 * Write a string. Returns the length of the string if successful, -1
624 * if the string could not be written.
625 */
626ssize_t
627shf_puts(const char *s, struct shf *shf)
628{
629	if (!s)
630		return (-1);
631
632	return (shf_write(s, strlen(s), shf));
633}
634
635/* Write a buffer. Returns nbytes if successful, -1 if there is an error. */
636ssize_t
637shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
638{
639	ssize_t n, ncopy, orig_nbytes = nbytes;
640
641	if (!(shf->flags & SHF_WR))
642		internal_errorf(Tf_flags, Tshf_write,
643		    (unsigned int)shf->flags);
644
645	if (nbytes < 0)
646		internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
647
648	/* Don't buffer if buffer is empty and we're writting a large amount. */
649	if ((ncopy = shf->wnleft) &&
650	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
651		if (ncopy > nbytes)
652			ncopy = nbytes;
653		memcpy(shf->wp, buf, ncopy);
654		nbytes -= ncopy;
655		buf += ncopy;
656		shf->wp += ncopy;
657		shf->wnleft -= ncopy;
658	}
659	if (nbytes > 0) {
660		if (shf->flags & SHF_STRING) {
661			/* resize buffer until there's enough space left */
662			while (nbytes > shf->wnleft)
663				if (shf_emptybuf(shf, EB_GROW) == -1)
664					return (-1);
665			/* then write everything into the buffer */
666		} else {
667			/* flush deals with sticky errors */
668			if (shf_emptybuf(shf, EB_GROW) == -1)
669				return (-1);
670			/* write chunks larger than window size directly */
671			if (nbytes > shf->wbsize) {
672				ncopy = nbytes;
673				if (shf->wbsize)
674					ncopy -= nbytes % shf->wbsize;
675				nbytes -= ncopy;
676				while (ncopy > 0) {
677					n = write(shf->fd, buf, ncopy);
678					if (n < 0) {
679						if (errno == EINTR &&
680						    !(shf->flags & SHF_INTERRUPT))
681							continue;
682						shf->flags |= SHF_ERROR;
683						shf->errnosv = errno;
684						shf->wnleft = 0;
685						/*
686						 * Note: fwrite(3) returns 0
687						 * for errors - this doesn't
688						 */
689						return (-1);
690					}
691					buf += n;
692					ncopy -= n;
693				}
694			}
695			/* ... and buffer the rest */
696		}
697		if (nbytes > 0) {
698			/* write remaining bytes to buffer */
699			memcpy(shf->wp, buf, nbytes);
700			shf->wp += nbytes;
701			shf->wnleft -= nbytes;
702		}
703	}
704
705	return (orig_nbytes);
706}
707
708ssize_t
709shf_fprintf(struct shf *shf, const char *fmt, ...)
710{
711	va_list args;
712	ssize_t n;
713
714	va_start(args, fmt);
715	n = shf_vfprintf(shf, fmt, args);
716	va_end(args);
717
718	return (n);
719}
720
721ssize_t
722shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
723{
724	struct shf shf;
725	va_list args;
726	ssize_t n;
727
728	if (!buf || bsize <= 0)
729		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
730		    (size_t)buf, bsize);
731
732	shf_sopen(buf, bsize, SHF_WR, &shf);
733	va_start(args, fmt);
734	n = shf_vfprintf(&shf, fmt, args);
735	va_end(args);
736	/* NUL terminates */
737	shf_sclose(&shf);
738	return (n);
739}
740
741char *
742shf_smprintf(const char *fmt, ...)
743{
744	struct shf shf;
745	va_list args;
746
747	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
748	va_start(args, fmt);
749	shf_vfprintf(&shf, fmt, args);
750	va_end(args);
751	/* NUL terminates */
752	return (shf_sclose(&shf));
753}
754
755#define	FL_HASH		0x001	/* '#' seen */
756#define FL_PLUS		0x002	/* '+' seen */
757#define FL_RIGHT	0x004	/* '-' seen */
758#define FL_BLANK	0x008	/* ' ' seen */
759#define FL_SHORT	0x010	/* 'h' seen */
760#define FL_LONG		0x020	/* 'l' seen */
761#define FL_ZERO		0x040	/* '0' seen */
762#define FL_DOT		0x080	/* '.' seen */
763#define FL_UPPER	0x100	/* format character was uppercase */
764#define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
765#define FL_SIZET	0x400	/* 'z' seen */
766#define FM_SIZES	0x430	/* h/l/z mask */
767
768ssize_t
769shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
770{
771	const char *s;
772	char c, *cp;
773	int tmp = 0, flags;
774	size_t field, precision, len;
775	unsigned long lnum;
776	/* %#o produces the longest output */
777	char numbuf[(8 * sizeof(long) + 2) / 3 + 1 + /* NUL */ 1];
778	/* this stuff for dealing with the buffer */
779	ssize_t nwritten = 0;
780
781#define VA(type) va_arg(args, type)
782
783	if (!fmt)
784		return (0);
785
786	while ((c = *fmt++)) {
787		if (c != '%') {
788			shf_putc(c, shf);
789			nwritten++;
790			continue;
791		}
792		/*
793		 * This will accept flags/fields in any order - not just
794		 * the order specified in printf(3), but this is the way
795		 * _doprnt() seems to work (on BSD and SYSV). The only
796		 * restriction is that the format character must come
797		 * last :-).
798		 */
799		flags = 0;
800		field = precision = 0;
801		while ((c = *fmt++)) {
802			switch (c) {
803			case '#':
804				flags |= FL_HASH;
805				continue;
806
807			case '+':
808				flags |= FL_PLUS;
809				continue;
810
811			case '-':
812				flags |= FL_RIGHT;
813				continue;
814
815			case ' ':
816				flags |= FL_BLANK;
817				continue;
818
819			case '0':
820				if (!(flags & FL_DOT))
821					flags |= FL_ZERO;
822				continue;
823
824			case '.':
825				flags |= FL_DOT;
826				precision = 0;
827				continue;
828
829			case '*':
830				tmp = VA(int);
831				if (tmp < 0) {
832					if (flags & FL_DOT)
833						precision = 0;
834					else {
835						field = (unsigned int)-tmp;
836						flags |= FL_RIGHT;
837					}
838				} else if (flags & FL_DOT)
839					precision = (unsigned int)tmp;
840				else
841					field = (unsigned int)tmp;
842				continue;
843
844			case 'l':
845				flags &= ~FM_SIZES;
846				flags |= FL_LONG;
847				continue;
848
849			case 'h':
850				flags &= ~FM_SIZES;
851				flags |= FL_SHORT;
852				continue;
853
854			case 'z':
855				flags &= ~FM_SIZES;
856				flags |= FL_SIZET;
857				continue;
858			}
859			if (ksh_isdigit(c)) {
860				bool overflowed = false;
861
862				tmp = ksh_numdig(c);
863				while (c = *fmt++, ksh_isdigit(c))
864					if (notok2mul(2147483647, tmp, 10))
865						overflowed = true;
866					else
867						tmp = tmp * 10 + ksh_numdig(c);
868				--fmt;
869				if (overflowed)
870					tmp = 0;
871				if (flags & FL_DOT)
872					precision = (unsigned int)tmp;
873				else
874					field = (unsigned int)tmp;
875				continue;
876			}
877			break;
878		}
879
880		if (!c)
881			/* nasty format */
882			break;
883
884		if (ksh_isupper(c)) {
885			flags |= FL_UPPER;
886			c = ksh_tolower(c);
887		}
888
889		switch (c) {
890		case 'd':
891		case 'i':
892			if (flags & FL_SIZET)
893				lnum = (long)VA(ssize_t);
894			else if (flags & FL_LONG)
895				lnum = VA(long);
896			else if (flags & FL_SHORT)
897				lnum = (long)(short)VA(int);
898			else
899				lnum = (long)VA(int);
900			goto integral;
901
902		case 'o':
903		case 'u':
904		case 'x':
905			if (flags & FL_SIZET)
906				lnum = VA(size_t);
907			else if (flags & FL_LONG)
908				lnum = VA(unsigned long);
909			else if (flags & FL_SHORT)
910				lnum = (unsigned long)(unsigned short)VA(int);
911			else
912				lnum = (unsigned long)VA(unsigned int);
913
914 integral:
915			flags |= FL_NUMBER;
916			cp = numbuf + sizeof(numbuf);
917			*--cp = '\0';
918
919			switch (c) {
920			case 'd':
921			case 'i':
922				if (0 > (long)lnum) {
923					lnum = -(long)lnum;
924					tmp = 1;
925				} else
926					tmp = 0;
927				/* FALLTHROUGH */
928			case 'u':
929				do {
930					*--cp = digits_lc[lnum % 10];
931					lnum /= 10;
932				} while (lnum);
933
934				if (c != 'u') {
935					if (tmp)
936						*--cp = '-';
937					else if (flags & FL_PLUS)
938						*--cp = '+';
939					else if (flags & FL_BLANK)
940						*--cp = ' ';
941				}
942				break;
943
944			case 'o':
945				do {
946					*--cp = digits_lc[lnum & 0x7];
947					lnum >>= 3;
948				} while (lnum);
949
950				if ((flags & FL_HASH) && *cp != '0')
951					*--cp = '0';
952				break;
953
954			case 'x': {
955				const char *digits = (flags & FL_UPPER) ?
956				    digits_uc : digits_lc;
957				do {
958					*--cp = digits[lnum & 0xF];
959					lnum >>= 4;
960				} while (lnum);
961
962				if (flags & FL_HASH) {
963					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
964					*--cp = '0';
965				}
966			    }
967			}
968			len = numbuf + sizeof(numbuf) - 1 - (s = cp);
969			if (flags & FL_DOT) {
970				if (precision > len) {
971					field = precision;
972					flags |= FL_ZERO;
973				} else
974					/* no loss */
975					precision = len;
976			}
977			break;
978
979		case 's':
980			if ((s = VA(const char *)) == NULL)
981				s = "(null)";
982			else if (flags & FL_HASH) {
983				print_value_quoted(shf, s);
984				continue;
985			}
986			len = utf_mbswidth(s);
987			break;
988
989		case 'c':
990			flags &= ~FL_DOT;
991			c = (char)(VA(int));
992			/* FALLTHROUGH */
993
994		case '%':
995		default:
996			numbuf[0] = c;
997			numbuf[1] = 0;
998			s = numbuf;
999			len = 1;
1000			break;
1001		}
1002
1003		/*
1004		 * At this point s should point to a string that is to be
1005		 * formatted, and len should be the length of the string.
1006		 */
1007		if (!(flags & FL_DOT) || len < precision)
1008			precision = len;
1009		if (field > precision) {
1010			field -= precision;
1011			if (!(flags & FL_RIGHT)) {
1012				/* skip past sign or 0x when padding with 0 */
1013				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
1014					if (*s == '+' || *s == '-' ||
1015					    *s == ' ') {
1016						shf_putc(*s, shf);
1017						s++;
1018						precision--;
1019						nwritten++;
1020					} else if (*s == '0') {
1021						shf_putc(*s, shf);
1022						s++;
1023						nwritten++;
1024						if (--precision &&
1025						    ksh_eq(*s, 'X', 'x')) {
1026							shf_putc(*s, shf);
1027							s++;
1028							precision--;
1029							nwritten++;
1030						}
1031					}
1032					c = '0';
1033				} else
1034					c = flags & FL_ZERO ? '0' : ' ';
1035				nwritten += field;
1036				while (field--)
1037					shf_putc(c, shf);
1038				field = 0;
1039			} else
1040				c = ' ';
1041		} else
1042			field = 0;
1043
1044		nwritten += precision;
1045		precision = utf_skipcols(s, precision, &tmp) - s;
1046		while (precision--)
1047			shf_putc(*s++, shf);
1048
1049		nwritten += field;
1050		while (field--)
1051			shf_putc(c, shf);
1052	}
1053
1054	return (shf_error(shf) ? -1 : nwritten);
1055}
1056
1057#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
1058int
1059shf_getc(struct shf *shf)
1060{
1061	return (shf_getc_i(shf));
1062}
1063
1064int
1065shf_putc(int c, struct shf *shf)
1066{
1067	return (shf_putc_i(c, shf));
1068}
1069#endif
1070
1071#ifdef DEBUG
1072const char *
1073cstrerror(int errnum)
1074{
1075#undef strerror
1076	return (strerror(errnum));
1077#define strerror dontuse_strerror /* poisoned */
1078}
1079#elif !HAVE_STRERROR
1080
1081#if HAVE_SYS_ERRLIST
1082#if !HAVE_SYS_ERRLIST_DECL
1083extern const int sys_nerr;
1084extern const char * const sys_errlist[];
1085#endif
1086#endif
1087
1088const char *
1089cstrerror(int errnum)
1090{
1091	/* "Unknown error: " + sign + rough estimate + NUL */
1092	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
1093
1094#if HAVE_SYS_ERRLIST
1095	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
1096		return (sys_errlist[errnum]);
1097#endif
1098
1099	switch (errnum) {
1100	case 0:
1101		return ("Undefined error: 0");
1102	case EPERM:
1103		return ("Operation not permitted");
1104	case ENOENT:
1105		return ("No such file or directory");
1106#ifdef ESRCH
1107	case ESRCH:
1108		return ("No such process");
1109#endif
1110#ifdef E2BIG
1111	case E2BIG:
1112		return ("Argument list too long");
1113#endif
1114	case ENOEXEC:
1115		return ("Exec format error");
1116	case EBADF:
1117		return ("Bad file descriptor");
1118#ifdef ENOMEM
1119	case ENOMEM:
1120		return ("Cannot allocate memory");
1121#endif
1122	case EACCES:
1123		return ("Permission denied");
1124	case EEXIST:
1125		return ("File exists");
1126	case ENOTDIR:
1127		return ("Not a directory");
1128#ifdef EINVAL
1129	case EINVAL:
1130		return ("Invalid argument");
1131#endif
1132#ifdef ELOOP
1133	case ELOOP:
1134		return ("Too many levels of symbolic links");
1135#endif
1136	default:
1137		shf_snprintf(errbuf, sizeof(errbuf),
1138		    "Unknown error: %d", errnum);
1139		return (errbuf);
1140	}
1141}
1142#endif
1143