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
6 *	Thorsten Glaser <tg@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.62 2013/10/09 11:59:30 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 = open(name, oflags | O_BINARY, 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("%s: %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("%s: %s", "shf_reopen", "bad shf/buf/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("%s: flags 0x%X", "shf_sopen", sflags);
201
202	if (!shf) {
203		shf = alloc(sizeof(struct shf), ATEMP);
204		sflags |= SHF_ALLOCS;
205	}
206	shf->areap = ATEMP;
207	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
208		if (bsize <= 0)
209			bsize = 64;
210		sflags |= SHF_ALLOCB;
211		buf = alloc(bsize, shf->areap);
212	}
213	shf->fd = -1;
214	shf->buf = shf->rp = shf->wp = (unsigned char *)buf;
215	shf->rnleft = bsize;
216	shf->rbsize = bsize;
217	shf->wnleft = bsize - 1;	/* space for a '\0' */
218	shf->wbsize = bsize;
219	shf->flags = sflags | SHF_STRING;
220	shf->errnosv = 0;
221	shf->bsize = bsize;
222
223	return (shf);
224}
225
226/* Flush and close file descriptor, free the shf structure */
227int
228shf_close(struct shf *shf)
229{
230	int ret = 0;
231
232	if (shf->fd >= 0) {
233		ret = shf_flush(shf);
234		if (close(shf->fd) < 0)
235			ret = EOF;
236	}
237	if (shf->flags & SHF_ALLOCS)
238		afree(shf, shf->areap);
239	else if (shf->flags & SHF_ALLOCB)
240		afree(shf->buf, shf->areap);
241
242	return (ret);
243}
244
245/* Flush and close file descriptor, don't free file structure */
246int
247shf_fdclose(struct shf *shf)
248{
249	int ret = 0;
250
251	if (shf->fd >= 0) {
252		ret = shf_flush(shf);
253		if (close(shf->fd) < 0)
254			ret = EOF;
255		shf->rnleft = 0;
256		shf->rp = shf->buf;
257		shf->wnleft = 0;
258		shf->fd = -1;
259	}
260
261	return (ret);
262}
263
264/*
265 * Close a string - if it was opened for writing, it is NUL terminated;
266 * returns a pointer to the string and frees shf if it was allocated
267 * (does not free string if it was allocated).
268 */
269char *
270shf_sclose(struct shf *shf)
271{
272	unsigned char *s = shf->buf;
273
274	/* NUL terminate */
275	if (shf->flags & SHF_WR) {
276		shf->wnleft++;
277		shf_putc('\0', shf);
278	}
279	if (shf->flags & SHF_ALLOCS)
280		afree(shf, shf->areap);
281	return ((char *)s);
282}
283
284/*
285 * Un-read what has been read but not examined, or write what has been
286 * buffered. Returns 0 for success, EOF for (write) error.
287 */
288int
289shf_flush(struct shf *shf)
290{
291	if (shf->flags & SHF_STRING)
292		return ((shf->flags & SHF_WR) ? EOF : 0);
293
294	if (shf->fd < 0)
295		internal_errorf("%s: %s", "shf_flush", "no fd");
296
297	if (shf->flags & SHF_ERROR) {
298		errno = shf->errnosv;
299		return (EOF);
300	}
301
302	if (shf->flags & SHF_READING) {
303		shf->flags &= ~(SHF_EOF | SHF_READING);
304		if (shf->rnleft > 0) {
305			lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR);
306			shf->rnleft = 0;
307			shf->rp = shf->buf;
308		}
309		return (0);
310	} else if (shf->flags & SHF_WRITING)
311		return (shf_emptybuf(shf, 0));
312
313	return (0);
314}
315
316/*
317 * Write out any buffered data. If currently reading, flushes the read
318 * buffer. Returns 0 for success, EOF for (write) error.
319 */
320static int
321shf_emptybuf(struct shf *shf, int flags)
322{
323	int ret = 0;
324
325	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
326		internal_errorf("%s: %s", "shf_emptybuf", "no fd");
327
328	if (shf->flags & SHF_ERROR) {
329		errno = shf->errnosv;
330		return (EOF);
331	}
332
333	if (shf->flags & SHF_READING) {
334		if (flags & EB_READSW)
335			/* doesn't happen */
336			return (0);
337		ret = shf_flush(shf);
338		shf->flags &= ~SHF_READING;
339	}
340	if (shf->flags & SHF_STRING) {
341		unsigned char *nbuf;
342
343		/*
344		 * Note that we assume SHF_ALLOCS is not set if
345		 * SHF_ALLOCB is set... (changing the shf pointer could
346		 * cause problems)
347		 */
348		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) ||
349		    !(shf->flags & SHF_ALLOCB))
350			return (EOF);
351		/* allocate more space for buffer */
352		nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
353		shf->rp = nbuf + (shf->rp - shf->buf);
354		shf->wp = nbuf + (shf->wp - shf->buf);
355		shf->rbsize += shf->wbsize;
356		shf->wnleft += shf->wbsize;
357		shf->wbsize <<= 1;
358		shf->buf = nbuf;
359	} else {
360		if (shf->flags & SHF_WRITING) {
361			ssize_t n, ntowrite = shf->wp - shf->buf;
362			unsigned char *buf = shf->buf;
363
364			while (ntowrite > 0) {
365				n = write(shf->fd, buf, ntowrite);
366				if (n < 0) {
367					if (errno == EINTR &&
368					    !(shf->flags & SHF_INTERRUPT))
369						continue;
370					shf->flags |= SHF_ERROR;
371					shf->errnosv = errno;
372					shf->wnleft = 0;
373					if (buf != shf->buf) {
374						/*
375						 * allow a second flush
376						 * to work
377						 */
378						memmove(shf->buf, buf,
379						    ntowrite);
380						shf->wp = shf->buf + ntowrite;
381					}
382					return (EOF);
383				}
384				buf += n;
385				ntowrite -= n;
386			}
387			if (flags & EB_READSW) {
388				shf->wp = shf->buf;
389				shf->wnleft = 0;
390				shf->flags &= ~SHF_WRITING;
391				return (0);
392			}
393		}
394		shf->wp = shf->buf;
395		shf->wnleft = shf->wbsize;
396	}
397	shf->flags |= SHF_WRITING;
398
399	return (ret);
400}
401
402/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */
403static int
404shf_fillbuf(struct shf *shf)
405{
406	ssize_t n;
407
408	if (shf->flags & SHF_STRING)
409		return (0);
410
411	if (shf->fd < 0)
412		internal_errorf("%s: %s", "shf_fillbuf", "no fd");
413
414	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
415		if (shf->flags & SHF_ERROR)
416			errno = shf->errnosv;
417		return (EOF);
418	}
419
420	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
421		return (EOF);
422
423	shf->flags |= SHF_READING;
424
425	shf->rp = shf->buf;
426	while (/* CONSTCOND */ 1) {
427		n = blocking_read(shf->fd, (char *)shf->buf, shf->rbsize);
428		if (n < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT))
429			continue;
430		break;
431	}
432	if (n < 0) {
433		shf->flags |= SHF_ERROR;
434		shf->errnosv = errno;
435		shf->rnleft = 0;
436		shf->rp = shf->buf;
437		return (EOF);
438	}
439	if ((shf->rnleft = n) == 0)
440		shf->flags |= SHF_EOF;
441	return (0);
442}
443
444/*
445 * Read a buffer from shf. Returns the number of bytes read into buf, if
446 * no bytes were read, returns 0 if end of file was seen, EOF if a read
447 * error occurred.
448 */
449ssize_t
450shf_read(char *buf, ssize_t bsize, struct shf *shf)
451{
452	ssize_t ncopy, orig_bsize = bsize;
453
454	if (!(shf->flags & SHF_RD))
455		internal_errorf("%s: flags 0x%X", "shf_read", shf->flags);
456
457	if (bsize <= 0)
458		internal_errorf("%s: %s %zd", "shf_write", "bsize", bsize);
459
460	while (bsize > 0) {
461		if (shf->rnleft == 0 &&
462		    (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
463			break;
464		ncopy = shf->rnleft;
465		if (ncopy > bsize)
466			ncopy = bsize;
467		memcpy(buf, shf->rp, ncopy);
468		buf += ncopy;
469		bsize -= ncopy;
470		shf->rp += ncopy;
471		shf->rnleft -= ncopy;
472	}
473	/* Note: fread(3S) returns 0 for errors - this doesn't */
474	return (orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) :
475	    orig_bsize - bsize);
476}
477
478/*
479 * Read up to a newline or EOF. The newline is put in buf; buf is always
480 * NUL terminated. Returns NULL on read error or if nothing was read
481 * before end of file, returns a pointer to the NUL byte in buf
482 * otherwise.
483 */
484char *
485shf_getse(char *buf, ssize_t bsize, struct shf *shf)
486{
487	unsigned char *end;
488	ssize_t ncopy;
489	char *orig_buf = buf;
490
491	if (!(shf->flags & SHF_RD))
492		internal_errorf("%s: flags 0x%X", "shf_getse", shf->flags);
493
494	if (bsize <= 0)
495		return (NULL);
496
497	/* save room for NUL */
498	--bsize;
499	do {
500		if (shf->rnleft == 0) {
501			if (shf_fillbuf(shf) == EOF)
502				return (NULL);
503			if (shf->rnleft == 0) {
504				*buf = '\0';
505				return (buf == orig_buf ? NULL : buf);
506			}
507		}
508		end = (unsigned char *)memchr((char *)shf->rp, '\n',
509		    shf->rnleft);
510		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
511		if (ncopy > bsize)
512			ncopy = bsize;
513		memcpy(buf, (char *) shf->rp, ncopy);
514		shf->rp += ncopy;
515		shf->rnleft -= ncopy;
516		buf += ncopy;
517		bsize -= ncopy;
518	} while (!end && bsize);
519	*buf = '\0';
520	return (buf);
521}
522
523/* Returns the char read. Returns EOF for error and end of file. */
524int
525shf_getchar(struct shf *shf)
526{
527	if (!(shf->flags & SHF_RD))
528		internal_errorf("%s: flags 0x%X", "shf_getchar", shf->flags);
529
530	if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
531		return (EOF);
532	--shf->rnleft;
533	return (*shf->rp++);
534}
535
536/*
537 * Put a character back in the input stream. Returns the character if
538 * successful, EOF if there is no room.
539 */
540int
541shf_ungetc(int c, struct shf *shf)
542{
543	if (!(shf->flags & SHF_RD))
544		internal_errorf("%s: flags 0x%X", "shf_ungetc", shf->flags);
545
546	if ((shf->flags & SHF_ERROR) || c == EOF ||
547	    (shf->rp == shf->buf && shf->rnleft))
548		return (EOF);
549
550	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
551		return (EOF);
552
553	if (shf->rp == shf->buf)
554		shf->rp = shf->buf + shf->rbsize;
555	if (shf->flags & SHF_STRING) {
556		/*
557		 * Can unget what was read, but not something different;
558		 * we don't want to modify a string.
559		 */
560		if ((int)(shf->rp[-1]) != c)
561			return (EOF);
562		shf->flags &= ~SHF_EOF;
563		shf->rp--;
564		shf->rnleft++;
565		return (c);
566	}
567	shf->flags &= ~SHF_EOF;
568	*--(shf->rp) = c;
569	shf->rnleft++;
570	return (c);
571}
572
573/*
574 * Write a character. Returns the character if successful, EOF if the
575 * char could not be written.
576 */
577int
578shf_putchar(int c, struct shf *shf)
579{
580	if (!(shf->flags & SHF_WR))
581		internal_errorf("%s: flags 0x%X", "shf_putchar", shf->flags);
582
583	if (c == EOF)
584		return (EOF);
585
586	if (shf->flags & SHF_UNBUF) {
587		unsigned char cc = (unsigned char)c;
588		ssize_t n;
589
590		if (shf->fd < 0)
591			internal_errorf("%s: %s", "shf_putchar", "no fd");
592		if (shf->flags & SHF_ERROR) {
593			errno = shf->errnosv;
594			return (EOF);
595		}
596		while ((n = write(shf->fd, &cc, 1)) != 1)
597			if (n < 0) {
598				if (errno == EINTR &&
599				    !(shf->flags & SHF_INTERRUPT))
600					continue;
601				shf->flags |= SHF_ERROR;
602				shf->errnosv = errno;
603				return (EOF);
604			}
605	} else {
606		/* Flush deals with strings and sticky errors */
607		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF)
608			return (EOF);
609		shf->wnleft--;
610		*shf->wp++ = c;
611	}
612
613	return (c);
614}
615
616/*
617 * Write a string. Returns the length of the string if successful, EOF
618 * if the string could not be written.
619 */
620ssize_t
621shf_puts(const char *s, struct shf *shf)
622{
623	if (!s)
624		return (EOF);
625
626	return (shf_write(s, strlen(s), shf));
627}
628
629/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */
630ssize_t
631shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
632{
633	ssize_t n, ncopy, orig_nbytes = nbytes;
634
635	if (!(shf->flags & SHF_WR))
636		internal_errorf("%s: flags 0x%X", "shf_write", shf->flags);
637
638	if (nbytes < 0)
639		internal_errorf("%s: %s %zd", "shf_write", "nbytes", nbytes);
640
641	/* Don't buffer if buffer is empty and we're writting a large amount. */
642	if ((ncopy = shf->wnleft) &&
643	    (shf->wp != shf->buf || nbytes < shf->wnleft)) {
644		if (ncopy > nbytes)
645			ncopy = nbytes;
646		memcpy(shf->wp, buf, ncopy);
647		nbytes -= ncopy;
648		buf += ncopy;
649		shf->wp += ncopy;
650		shf->wnleft -= ncopy;
651	}
652	if (nbytes > 0) {
653		if (shf->flags & SHF_STRING) {
654			/* resize buffer until there's enough space left */
655			while (nbytes > shf->wnleft)
656				if (shf_emptybuf(shf, EB_GROW) == EOF)
657					return (EOF);
658			/* then write everything into the buffer */
659		} else {
660			/* flush deals with sticky errors */
661			if (shf_emptybuf(shf, EB_GROW) == EOF)
662				return (EOF);
663			/* write chunks larger than window size directly */
664			if (nbytes > shf->wbsize) {
665				ncopy = nbytes;
666				if (shf->wbsize)
667					ncopy -= nbytes % shf->wbsize;
668				nbytes -= ncopy;
669				while (ncopy > 0) {
670					n = write(shf->fd, buf, ncopy);
671					if (n < 0) {
672						if (errno == EINTR &&
673						    !(shf->flags & SHF_INTERRUPT))
674							continue;
675						shf->flags |= SHF_ERROR;
676						shf->errnosv = errno;
677						shf->wnleft = 0;
678						/*
679						 * Note: fwrite(3) returns 0
680						 * for errors - this doesn't
681						 */
682						return (EOF);
683					}
684					buf += n;
685					ncopy -= n;
686				}
687			}
688			/* ... and buffer the rest */
689		}
690		if (nbytes > 0) {
691			/* write remaining bytes to buffer */
692			memcpy(shf->wp, buf, nbytes);
693			shf->wp += nbytes;
694			shf->wnleft -= nbytes;
695		}
696	}
697
698	return (orig_nbytes);
699}
700
701ssize_t
702shf_fprintf(struct shf *shf, const char *fmt, ...)
703{
704	va_list args;
705	ssize_t n;
706
707	va_start(args, fmt);
708	n = shf_vfprintf(shf, fmt, args);
709	va_end(args);
710
711	return (n);
712}
713
714ssize_t
715shf_snprintf(char *buf, ssize_t bsize, const char *fmt, ...)
716{
717	struct shf shf;
718	va_list args;
719	ssize_t n;
720
721	if (!buf || bsize <= 0)
722		internal_errorf("shf_snprintf: buf %zX, bsize %zd",
723		    (size_t)buf, bsize);
724
725	shf_sopen(buf, bsize, SHF_WR, &shf);
726	va_start(args, fmt);
727	n = shf_vfprintf(&shf, fmt, args);
728	va_end(args);
729	/* NUL terminates */
730	shf_sclose(&shf);
731	return (n);
732}
733
734char *
735shf_smprintf(const char *fmt, ...)
736{
737	struct shf shf;
738	va_list args;
739
740	shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
741	va_start(args, fmt);
742	shf_vfprintf(&shf, fmt, args);
743	va_end(args);
744	/* NUL terminates */
745	return (shf_sclose(&shf));
746}
747
748#define	FL_HASH		0x001	/* '#' seen */
749#define FL_PLUS		0x002	/* '+' seen */
750#define FL_RIGHT	0x004	/* '-' seen */
751#define FL_BLANK	0x008	/* ' ' seen */
752#define FL_SHORT	0x010	/* 'h' seen */
753#define FL_LONG		0x020	/* 'l' seen */
754#define FL_ZERO		0x040	/* '0' seen */
755#define FL_DOT		0x080	/* '.' seen */
756#define FL_UPPER	0x100	/* format character was uppercase */
757#define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
758#define FL_SIZET	0x400	/* 'z' seen */
759#define FM_SIZES	0x430	/* h/l/z mask */
760
761ssize_t
762shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
763{
764	const char *s;
765	char c, *cp;
766	int tmp = 0, flags;
767	ssize_t field, precision, len;
768	unsigned long lnum;
769	/* %#o produces the longest output */
770	char numbuf[(8 * sizeof(long) + 2) / 3 + 1
771#ifdef DEBUG
772		/* a NUL for LLVM/Clang scan-build */
773		+ 1
774#endif
775	    ];
776	/* this stuff for dealing with the buffer */
777	ssize_t nwritten = 0;
778
779#define VA(type) va_arg(args, type)
780
781	if (!fmt)
782		return (0);
783
784	while ((c = *fmt++)) {
785		if (c != '%') {
786			shf_putc(c, shf);
787			nwritten++;
788			continue;
789		}
790		/*
791		 * This will accept flags/fields in any order - not just
792		 * the order specified in printf(3), but this is the way
793		 * _doprnt() seems to work (on BSD and SYSV). The only
794		 * restriction is that the format character must come
795		 * last :-).
796		 */
797		flags = 0;
798		field = precision = 0;
799		for ( ; (c = *fmt++) ; ) {
800			switch (c) {
801			case '#':
802				flags |= FL_HASH;
803				continue;
804
805			case '+':
806				flags |= FL_PLUS;
807				continue;
808
809			case '-':
810				flags |= FL_RIGHT;
811				continue;
812
813			case ' ':
814				flags |= FL_BLANK;
815				continue;
816
817			case '0':
818				if (!(flags & FL_DOT))
819					flags |= FL_ZERO;
820				continue;
821
822			case '.':
823				flags |= FL_DOT;
824				precision = 0;
825				continue;
826
827			case '*':
828				tmp = VA(int);
829				if (flags & FL_DOT)
830					precision = tmp;
831				else if ((field = tmp) < 0) {
832					field = -field;
833					flags |= FL_RIGHT;
834				}
835				continue;
836
837			case 'l':
838				flags &= ~FM_SIZES;
839				flags |= FL_LONG;
840				continue;
841
842			case 'h':
843				flags &= ~FM_SIZES;
844				flags |= FL_SHORT;
845				continue;
846
847			case 'z':
848				flags &= ~FM_SIZES;
849				flags |= FL_SIZET;
850				continue;
851			}
852			if (ksh_isdigit(c)) {
853				bool overflowed = false;
854
855				tmp = c - '0';
856				while (c = *fmt++, ksh_isdigit(c)) {
857					if (notok2mul(2147483647, tmp, 10))
858						overflowed = true;
859					tmp = tmp * 10 + c - '0';
860				}
861				--fmt;
862				if (overflowed)
863					tmp = 0;
864				if (flags & FL_DOT)
865					precision = tmp;
866				else
867					field = tmp;
868				continue;
869			}
870			break;
871		}
872
873		if (precision < 0)
874			precision = 0;
875
876		if (!c)
877			/* nasty format */
878			break;
879
880		if (c >= 'A' && c <= 'Z') {
881			flags |= FL_UPPER;
882			c = ksh_tolower(c);
883		}
884
885		switch (c) {
886		case 'd':
887		case 'i':
888			if (flags & FL_SIZET)
889				lnum = (long)VA(ssize_t);
890			else if (flags & FL_LONG)
891				lnum = VA(long);
892			else if (flags & FL_SHORT)
893				lnum = (long)(short)VA(int);
894			else
895				lnum = (long)VA(int);
896			goto integral;
897
898		case 'o':
899		case 'u':
900		case 'x':
901			if (flags & FL_SIZET)
902				lnum = VA(size_t);
903			else if (flags & FL_LONG)
904				lnum = VA(unsigned long);
905			else if (flags & FL_SHORT)
906				lnum = (unsigned long)(unsigned short)VA(int);
907			else
908				lnum = (unsigned long)VA(unsigned int);
909
910 integral:
911			flags |= FL_NUMBER;
912			cp = numbuf + sizeof(numbuf);
913#ifdef DEBUG
914			/*
915			 * this is necessary so Clang 3.2 realises
916			 * utf_skipcols/shf_putc in the output loop
917			 * terminate; these values are always ASCII
918			 * so an out-of-bounds access cannot happen
919			 * but Clang doesn't know that
920			 */
921			*--cp = '\0';
922#endif
923
924			switch (c) {
925			case 'd':
926			case 'i':
927				if (0 > (long)lnum) {
928					lnum = -(long)lnum;
929					tmp = 1;
930				} else
931					tmp = 0;
932				/* FALLTHROUGH */
933			case 'u':
934				do {
935					*--cp = lnum % 10 + '0';
936					lnum /= 10;
937				} while (lnum);
938
939				if (c != 'u') {
940					if (tmp)
941						*--cp = '-';
942					else if (flags & FL_PLUS)
943						*--cp = '+';
944					else if (flags & FL_BLANK)
945						*--cp = ' ';
946				}
947				break;
948
949			case 'o':
950				do {
951					*--cp = (lnum & 0x7) + '0';
952					lnum >>= 3;
953				} while (lnum);
954
955				if ((flags & FL_HASH) && *cp != '0')
956					*--cp = '0';
957				break;
958
959			case 'x': {
960				const char *digits = (flags & FL_UPPER) ?
961				    digits_uc : digits_lc;
962				do {
963					*--cp = digits[lnum & 0xf];
964					lnum >>= 4;
965				} while (lnum);
966
967				if (flags & FL_HASH) {
968					*--cp = (flags & FL_UPPER) ? 'X' : 'x';
969					*--cp = '0';
970				}
971			}
972			}
973			len = numbuf + sizeof(numbuf) - (s = cp);
974#ifdef DEBUG
975			/* see above comment for Clang 3.2 */
976			--len;
977#endif
978			if (flags & FL_DOT) {
979				if (precision > len) {
980					field = precision;
981					flags |= FL_ZERO;
982				} else
983					/* no loss */
984					precision = len;
985			}
986			break;
987
988		case 's':
989			if ((s = VA(const char *)) == NULL)
990				s = "(null)";
991			else if (flags & FL_HASH) {
992				print_value_quoted(shf, s);
993				continue;
994			}
995			len = utf_mbswidth(s);
996			break;
997
998		case 'c':
999			flags &= ~FL_DOT;
1000			c = (char)(VA(int));
1001			/* FALLTHROUGH */
1002
1003		case '%':
1004		default:
1005			numbuf[0] = c;
1006			numbuf[1] = 0;
1007			s = numbuf;
1008			len = 1;
1009			break;
1010		}
1011
1012		/*
1013		 * At this point s should point to a string that is to be
1014		 * formatted, and len should be the length of the string.
1015		 */
1016		if (!(flags & FL_DOT) || len < precision)
1017			precision = len;
1018		if (field > precision) {
1019			field -= precision;
1020			if (!(flags & FL_RIGHT)) {
1021				field = -field;
1022				/* skip past sign or 0x when padding with 0 */
1023				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
1024					if (*s == '+' || *s == '-' ||
1025					    *s == ' ') {
1026						shf_putc(*s, shf);
1027						s++;
1028						precision--;
1029						nwritten++;
1030					} else if (*s == '0') {
1031						shf_putc(*s, shf);
1032						s++;
1033						nwritten++;
1034						if (--precision > 0 &&
1035						    (*s | 0x20) == 'x') {
1036							shf_putc(*s, shf);
1037							s++;
1038							precision--;
1039							nwritten++;
1040						}
1041					}
1042					c = '0';
1043				} else
1044					c = flags & FL_ZERO ? '0' : ' ';
1045				if (field < 0) {
1046					nwritten += -field;
1047					for ( ; field < 0 ; field++)
1048						shf_putc(c, shf);
1049				}
1050			} else
1051				c = ' ';
1052		} else
1053			field = 0;
1054
1055		if (precision > 0) {
1056			const char *q;
1057
1058			nwritten += precision;
1059			q = utf_skipcols(s, precision);
1060			do {
1061				shf_putc(*s, shf);
1062			} while (++s < q);
1063		}
1064		if (field > 0) {
1065			nwritten += field;
1066			for ( ; field > 0 ; --field)
1067				shf_putc(c, shf);
1068		}
1069	}
1070
1071	return (shf_error(shf) ? EOF : nwritten);
1072}
1073
1074#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
1075int
1076shf_getc(struct shf *shf)
1077{
1078	return (shf_getc_i(shf));
1079}
1080
1081int
1082shf_putc(int c, struct shf *shf)
1083{
1084	return (shf_putc_i(c, shf));
1085}
1086#endif
1087
1088#ifdef DEBUG
1089const char *
1090cstrerror(int errnum)
1091{
1092#undef strerror
1093	return (strerror(errnum));
1094#define strerror dontuse_strerror /* poisoned */
1095}
1096#elif !HAVE_STRERROR
1097
1098#if HAVE_SYS_ERRLIST
1099#if !HAVE_SYS_ERRLIST_DECL
1100extern const int sys_nerr;
1101extern const char * const sys_errlist[];
1102#endif
1103#endif
1104
1105const char *
1106cstrerror(int errnum)
1107{
1108	/* "Unknown error: " + sign + rough estimate + NUL */
1109	static char errbuf[15 + 1 + (8 * sizeof(int) + 2) / 3 + 1];
1110
1111#if HAVE_SYS_ERRLIST
1112	if (errnum > 0 && errnum < sys_nerr && sys_errlist[errnum])
1113		return (sys_errlist[errnum]);
1114#endif
1115
1116	switch (errnum) {
1117	case 0:
1118		return ("Undefined error: 0");
1119#ifdef EPERM
1120	case EPERM:
1121		return ("Operation not permitted");
1122#endif
1123#ifdef ENOENT
1124	case ENOENT:
1125		return ("No such file or directory");
1126#endif
1127#ifdef ESRCH
1128	case ESRCH:
1129		return ("No such process");
1130#endif
1131#ifdef E2BIG
1132	case E2BIG:
1133		return ("Argument list too long");
1134#endif
1135#ifdef ENOEXEC
1136	case ENOEXEC:
1137		return ("Exec format error");
1138#endif
1139#ifdef ENOMEM
1140	case ENOMEM:
1141		return ("Cannot allocate memory");
1142#endif
1143#ifdef EACCES
1144	case EACCES:
1145		return ("Permission denied");
1146#endif
1147#ifdef ENOTDIR
1148	case ENOTDIR:
1149		return ("Not a directory");
1150#endif
1151#ifdef EINVAL
1152	case EINVAL:
1153		return ("Invalid argument");
1154#endif
1155#ifdef ELOOP
1156	case ELOOP:
1157		return ("Too many levels of symbolic links");
1158#endif
1159	default:
1160		shf_snprintf(errbuf, sizeof(errbuf),
1161		    "Unknown error: %d", errnum);
1162		return (errbuf);
1163	}
1164}
1165#endif
1166