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