• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 static int shf_fillbuf(struct shf *);
41 static 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  */
48 struct shf *
shf_open(const char * name,int oflags,int mode,int sflags)49 shf_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 */
93 static void
shf_open_hlp(int fd,int * sflagsp,const char * where)94 shf_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. */
126 struct shf *
shf_fdopen(int fd,int sflags,struct shf * shf)127 shf_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 */
161 struct shf *
shf_reopen(int fd,int sflags,struct shf * shf)162 shf_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  */
195 struct shf *
shf_sopen(char * buf,ssize_t bsize,int sflags,struct shf * shf)196 shf_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 */
228 int
shf_close(struct shf * shf)229 shf_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 */
247 int
shf_fdclose(struct shf * shf)248 shf_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  */
270 char *
shf_sclose(struct shf * shf)271 shf_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  */
289 int
shf_flush(struct shf * shf)290 shf_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  */
321 static int
shf_emptybuf(struct shf * shf,int flags)322 shf_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. */
404 static int
shf_fillbuf(struct shf * shf)405 shf_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  */
450 ssize_t
shf_read(char * buf,ssize_t bsize,struct shf * shf)451 shf_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  */
486 char *
shf_getse(char * buf,ssize_t bsize,struct shf * shf)487 shf_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. */
527 int
shf_getchar(struct shf * shf)528 shf_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  */
544 int
shf_ungetc(int c,struct shf * shf)545 shf_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  */
582 int
shf_putchar(int c,struct shf * shf)583 shf_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  */
626 ssize_t
shf_puts(const char * s,struct shf * shf)627 shf_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. */
636 ssize_t
shf_write(const char * buf,ssize_t nbytes,struct shf * shf)637 shf_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 
708 ssize_t
shf_fprintf(struct shf * shf,const char * fmt,...)709 shf_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 
721 ssize_t
shf_snprintf(char * buf,ssize_t bsize,const char * fmt,...)722 shf_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 
741 char *
shf_smprintf(const char * fmt,...)742 shf_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 
768 ssize_t
shf_vfprintf(struct shf * shf,const char * fmt,va_list args)769 shf_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)
1058 int
shf_getc(struct shf * shf)1059 shf_getc(struct shf *shf)
1060 {
1061 	return (shf_getc_i(shf));
1062 }
1063 
1064 int
shf_putc(int c,struct shf * shf)1065 shf_putc(int c, struct shf *shf)
1066 {
1067 	return (shf_putc_i(c, shf));
1068 }
1069 #endif
1070 
1071 #ifdef DEBUG
1072 const char *
cstrerror(int errnum)1073 cstrerror(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
1083 extern const int sys_nerr;
1084 extern const char * const sys_errlist[];
1085 #endif
1086 #endif
1087 
1088 const char *
cstrerror(int errnum)1089 cstrerror(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