Home | History | Annotate | Line # | Download | only in ksh
      1 /*	$NetBSD: shf.c,v 1.16 2024/02/05 21:20:09 andvar Exp $	*/
      2 
      3 /*
      4  *  Shell file I/O routines
      5  */
      6 #include <sys/cdefs.h>
      7 
      8 #ifndef lint
      9 __RCSID("$NetBSD: shf.c,v 1.16 2024/02/05 21:20:09 andvar Exp $");
     10 #endif
     11 
     12 #include <sys/stat.h>
     13 
     14 #include "sh.h"
     15 #include "ksh_limval.h"
     16 
     17 
     18 /* flags to shf_emptybuf() */
     19 #define EB_READSW	0x01	/* about to switch to reading */
     20 #define EB_GROW		0x02	/* grow buffer if necessary (STRING+DYNAMIC) */
     21 
     22 /*
     23  * Replacement stdio routines.  Stdio is too flakey on too many machines
     24  * to be useful when you have multiple processes using the same underlying
     25  * file descriptors.
     26  */
     27 
     28 static int	shf_fillbuf	ARGS((struct shf *shf));
     29 static int	shf_emptybuf	ARGS((struct shf *shf, int flags));
     30 
     31 /* Open a file.  First three args are for open(), last arg is flags for
     32  * this package.  Returns NULL if file could not be opened, or if a dup
     33  * fails.
     34  */
     35 struct shf *
     36 shf_open(name, oflags, mode, sflags)
     37 	const char *name;
     38 	int oflags;
     39 	int mode;
     40 	int sflags;
     41 {
     42 	struct shf *shf;
     43 	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
     44 	int fd;
     45 
     46 	/* Done before open so if alloca fails, fd won't be lost. */
     47 	shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
     48 	shf->areap = ATEMP;
     49 	shf->buf = (unsigned char *) &shf[1];
     50 	shf->bsize = bsize;
     51 	shf->flags = SHF_ALLOCS;
     52 	/* Rest filled in by reopen. */
     53 
     54 	fd = open(name, oflags, mode);
     55 	if (fd < 0) {
     56 		afree(shf, shf->areap);
     57 		return NULL;
     58 	}
     59 	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
     60 		int nfd;
     61 
     62 		nfd = ksh_dupbase(fd, FDBASE);
     63 		close(fd);
     64 		if (nfd < 0) {
     65 			afree(shf, shf->areap);
     66 			return NULL;
     67 		}
     68 		fd = nfd;
     69 	}
     70 	sflags &= ~SHF_ACCMODE;
     71 	sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD
     72 		  : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR
     73 		     : SHF_RDWR);
     74 
     75 	return shf_reopen(fd, sflags, shf);
     76 }
     77 
     78 /* Set up the shf structure for a file descriptor.  Doesn't fail. */
     79 struct shf *
     80 shf_fdopen(fd, sflags, shf)
     81 	int fd;
     82 	int sflags;
     83 	struct shf *shf;
     84 {
     85 	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
     86 
     87 	/* use fcntl() to figure out correct read/write flags */
     88 	if (sflags & SHF_GETFL) {
     89 		int flags = fcntl(fd, F_GETFL, 0);
     90 
     91 		if (flags < 0)
     92 			/* will get an error on first read/write */
     93 			sflags |= SHF_RDWR;
     94 		else
     95 			switch (flags & O_ACCMODE) {
     96 			case O_RDONLY: sflags |= SHF_RD; break;
     97 			case O_WRONLY: sflags |= SHF_WR; break;
     98 			case O_RDWR: sflags |= SHF_RDWR; break;
     99 			}
    100 	}
    101 
    102 	if (!(sflags & (SHF_RD | SHF_WR)))
    103 		internal_errorf(1, "shf_fdopen: missing read/write");
    104 
    105 	if (shf) {
    106 		if (bsize) {
    107 			shf->buf = (unsigned char *) alloc(bsize, ATEMP);
    108 			sflags |= SHF_ALLOCB;
    109 		} else
    110 			shf->buf = (unsigned char *) 0;
    111 	} else {
    112 		shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
    113 		shf->buf = (unsigned char *) &shf[1];
    114 		sflags |= SHF_ALLOCS;
    115 	}
    116 	shf->areap = ATEMP;
    117 	shf->fd = fd;
    118 	shf->rp = shf->wp = shf->buf;
    119 	shf->rnleft = 0;
    120 	shf->rbsize = bsize;
    121 	shf->wnleft = 0; /* force call to shf_emptybuf() */
    122 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
    123 	shf->flags = sflags;
    124 	shf->errno_ = 0;
    125 	shf->bsize = bsize;
    126 	if (sflags & SHF_CLEXEC)
    127 		fd_clexec(fd);
    128 	return shf;
    129 }
    130 
    131 /* Set up an existing shf (and buffer) to use the given fd */
    132 struct shf *
    133 shf_reopen(fd, sflags, shf)
    134 	int fd;
    135 	int sflags;
    136 	struct shf *shf;
    137 {
    138 	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
    139 
    140 	/* use fcntl() to figure out correct read/write flags */
    141 	if (sflags & SHF_GETFL) {
    142 		int flags = fcntl(fd, F_GETFL, 0);
    143 
    144 		if (flags < 0)
    145 			/* will get an error on first read/write */
    146 			sflags |= SHF_RDWR;
    147 		else
    148 			switch (flags & O_ACCMODE) {
    149 			case O_RDONLY: sflags |= SHF_RD; break;
    150 			case O_WRONLY: sflags |= SHF_WR; break;
    151 			case O_RDWR: sflags |= SHF_RDWR; break;
    152 			}
    153 	}
    154 
    155 	if (!(sflags & (SHF_RD | SHF_WR)))
    156 		internal_errorf(1, "shf_reopen: missing read/write");
    157 	if (!shf || !shf->buf || shf->bsize < bsize)
    158 		internal_errorf(1, "shf_reopen: bad shf/buf/bsize");
    159 
    160 	/* assumes shf->buf and shf->bsize already set up */
    161 	shf->fd = fd;
    162 	shf->rp = shf->wp = shf->buf;
    163 	shf->rnleft = 0;
    164 	shf->rbsize = bsize;
    165 	shf->wnleft = 0; /* force call to shf_emptybuf() */
    166 	shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
    167 	shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
    168 	shf->errno_ = 0;
    169 	if (sflags & SHF_CLEXEC)
    170 		fd_clexec(fd);
    171 	return shf;
    172 }
    173 
    174 /* Open a string for reading or writing.  If reading, bsize is the number
    175  * of bytes that can be read.  If writing, bsize is the maximum number of
    176  * bytes that can be written.  If shf is not null, it is filled in and
    177  * returned, if it is null, shf is allocated.  If writing and buf is null
    178  * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
    179  * used for the initial size).  Doesn't fail.
    180  * When writing, a byte is reserved for a trailing null - see shf_sclose().
    181  */
    182 struct shf *
    183 shf_sopen(buf, bsize, sflags, shf)
    184 	char *buf;
    185 	int bsize;
    186 	int sflags;
    187 	struct shf *shf;
    188 {
    189 	/* can't have a read+write string */
    190 	if (!(sflags & (SHF_RD | SHF_WR))
    191 	    || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR))
    192 		internal_errorf(1, "shf_sopen: flags 0x%x", sflags);
    193 
    194 	if (!shf) {
    195 		shf = (struct shf *) alloc(sizeof(struct shf), ATEMP);
    196 		sflags |= SHF_ALLOCS;
    197 	}
    198 	shf->areap = ATEMP;
    199 	if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
    200 		if (bsize <= 0)
    201 			bsize = 64;
    202 		sflags |= SHF_ALLOCB;
    203 		buf = alloc(bsize, shf->areap);
    204 	}
    205 	shf->fd = -1;
    206 	shf->buf = shf->rp = shf->wp = (unsigned char *) buf;
    207 	shf->rnleft = bsize;
    208 	shf->rbsize = bsize;
    209 	shf->wnleft = bsize - 1;	/* space for a '\0' */
    210 	shf->wbsize = bsize;
    211 	shf->flags = sflags | SHF_STRING;
    212 	shf->errno_ = 0;
    213 	shf->bsize = bsize;
    214 
    215 	return shf;
    216 }
    217 
    218 /* Flush and close file descriptor, free the shf structure */
    219 int
    220 shf_close(shf)
    221 	struct shf *shf;
    222 {
    223 	int ret = 0;
    224 
    225 	if (shf->fd >= 0) {
    226 		ret = shf_flush(shf);
    227 		if (close(shf->fd) < 0)
    228 			ret = EOF;
    229 	}
    230 	if (shf->flags & SHF_ALLOCS)
    231 		afree(shf, shf->areap);
    232 	else if (shf->flags & SHF_ALLOCB)
    233 		afree(shf->buf, shf->areap);
    234 
    235 	return ret;
    236 }
    237 
    238 /* Flush and close file descriptor, don't free file structure */
    239 int
    240 shf_fdclose(shf)
    241 	struct shf *shf;
    242 {
    243 	int ret = 0;
    244 
    245 	if (shf->fd >= 0) {
    246 		ret = shf_flush(shf);
    247 		if (close(shf->fd) < 0)
    248 			ret = EOF;
    249 		shf->rnleft = 0;
    250 		shf->rp = shf->buf;
    251 		shf->wnleft = 0;
    252 		shf->fd = -1;
    253 	}
    254 
    255 	return ret;
    256 }
    257 
    258 /* Close a string - if it was opened for writing, it is null terminated;
    259  * returns a pointer to the string and frees shf if it was allocated
    260  * (does not free string if it was allocated).
    261  */
    262 char *
    263 shf_sclose(shf)
    264 	struct shf *shf;
    265 {
    266 	unsigned char *s = shf->buf;
    267 
    268 	/* null terminate */
    269 	if (shf->flags & SHF_WR) {
    270 		shf->wnleft++;
    271 		shf_putc('\0', shf);
    272 	}
    273 	if (shf->flags & SHF_ALLOCS)
    274 		afree(shf, shf->areap);
    275 	return (char *) s;
    276 }
    277 
    278 /* Flush and free file structure, don't close file descriptor */
    279 int
    280 shf_finish(shf)
    281 	struct shf *shf;
    282 {
    283 	int ret = 0;
    284 
    285 	if (shf->fd >= 0)
    286 		ret = shf_flush(shf);
    287 	if (shf->flags & SHF_ALLOCS)
    288 		afree(shf, shf->areap);
    289 	else if (shf->flags & SHF_ALLOCB)
    290 		afree(shf->buf, shf->areap);
    291 
    292 	return ret;
    293 }
    294 
    295 /* Un-read what has been read but not examined, or write what has been
    296  * buffered.  Returns 0 for success, EOF for (write) error.
    297  */
    298 int
    299 shf_flush(shf)
    300 	struct shf *shf;
    301 {
    302 	if (shf->flags & SHF_STRING)
    303 		return (shf->flags & SHF_WR) ? EOF : 0;
    304 
    305 	if (shf->fd < 0)
    306 		internal_errorf(1, "shf_flush: no fd");
    307 
    308 	if (shf->flags & SHF_ERROR) {
    309 		errno = shf->errno_;
    310 		return EOF;
    311 	}
    312 
    313 	if (shf->flags & SHF_READING) {
    314 		shf->flags &= ~(SHF_EOF | SHF_READING);
    315 		if (shf->rnleft > 0) {
    316 			lseek(shf->fd, (off_t) -shf->rnleft, 1);
    317 			shf->rnleft = 0;
    318 			shf->rp = shf->buf;
    319 		}
    320 		return 0;
    321 	} else if (shf->flags & SHF_WRITING)
    322 		return shf_emptybuf(shf, 0);
    323 
    324 	return 0;
    325 }
    326 
    327 /* Write out any buffered data.  If currently reading, flushes the read
    328  * buffer.  Returns 0 for success, EOF for (write) error.
    329  */
    330 static int
    331 shf_emptybuf(shf, flags)
    332 	struct shf *shf;
    333 	int flags;
    334 {
    335 	int ret = 0;
    336 
    337 	if (!(shf->flags & SHF_STRING) && shf->fd < 0)
    338 		internal_errorf(1, "shf_emptybuf: no fd");
    339 
    340 	if (shf->flags & SHF_ERROR) {
    341 		errno = shf->errno_;
    342 		return EOF;
    343 	}
    344 
    345 	if (shf->flags & SHF_READING) {
    346 		if (flags & EB_READSW) /* doesn't happen */
    347 			return 0;
    348 		ret = shf_flush(shf);
    349 		shf->flags &= ~SHF_READING;
    350 	}
    351 	if (shf->flags & SHF_STRING) {
    352 		unsigned char	*nbuf;
    353 
    354 		/* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB
    355 		 * is set... (changing the shf pointer could cause problems)
    356 		 */
    357 		if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC)
    358 		    || !(shf->flags & SHF_ALLOCB))
    359 			return EOF;
    360 		/* allocate more space for buffer */
    361 		nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2,
    362 						shf->areap);
    363 		shf->rp = nbuf + (shf->rp - shf->buf);
    364 		shf->wp = nbuf + (shf->wp - shf->buf);
    365 		shf->rbsize += shf->wbsize;
    366 		shf->wnleft += shf->wbsize;
    367 		shf->wbsize *= 2;
    368 		shf->buf = nbuf;
    369 	} else {
    370 		if (shf->flags & SHF_WRITING) {
    371 			int ntowrite = shf->wp - shf->buf;
    372 			unsigned char *buf = shf->buf;
    373 			int n;
    374 
    375 			while (ntowrite > 0) {
    376 				n = write(shf->fd, buf, ntowrite);
    377 				if (n < 0) {
    378 					if (errno == EINTR
    379 					    && !(shf->flags & SHF_INTERRUPT))
    380 						continue;
    381 					shf->flags |= SHF_ERROR;
    382 					shf->errno_ = errno;
    383 					shf->wnleft = 0;
    384 					if (buf != shf->buf) {
    385 						/* allow a second flush
    386 						 * to work */
    387 						memmove(shf->buf, buf,
    388 							ntowrite);
    389 						shf->wp = shf->buf + ntowrite;
    390 					}
    391 					return EOF;
    392 				}
    393 				buf += n;
    394 				ntowrite -= n;
    395 			}
    396 			if (flags & EB_READSW) {
    397 				shf->wp = shf->buf;
    398 				shf->wnleft = 0;
    399 				shf->flags &= ~SHF_WRITING;
    400 				return 0;
    401 			}
    402 		}
    403 		shf->wp = shf->buf;
    404 		shf->wnleft = shf->wbsize;
    405 	}
    406 	shf->flags |= SHF_WRITING;
    407 
    408 	return ret;
    409 }
    410 
    411 /* Fill up a read buffer.  Returns EOF for a read error, 0 otherwise. */
    412 static int
    413 shf_fillbuf(shf)
    414 	struct shf *shf;
    415 {
    416 	if (shf->flags & SHF_STRING)
    417 		return 0;
    418 
    419 	if (shf->fd < 0)
    420 		internal_errorf(1, "shf_fillbuf: no fd");
    421 
    422 	if (shf->flags & (SHF_EOF | SHF_ERROR)) {
    423 		if (shf->flags & SHF_ERROR)
    424 			errno = shf->errno_;
    425 		return EOF;
    426 	}
    427 
    428 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
    429 		return EOF;
    430 
    431 	shf->flags |= SHF_READING;
    432 
    433 	shf->rp = shf->buf;
    434 	while (1) {
    435 		shf->rnleft = blocking_read(shf->fd, (char *) shf->buf,
    436 					    shf->rbsize);
    437 		if (shf->rnleft < 0 && errno == EINTR
    438 		    && !(shf->flags & SHF_INTERRUPT))
    439 			continue;
    440 		break;
    441 	}
    442 	if (shf->rnleft <= 0) {
    443 		if (shf->rnleft < 0) {
    444 			shf->flags |= SHF_ERROR;
    445 			shf->errno_ = errno;
    446 			shf->rnleft = 0;
    447 			shf->rp = shf->buf;
    448 			return EOF;
    449 		}
    450 		shf->flags |= SHF_EOF;
    451 	}
    452 	return 0;
    453 }
    454 
    455 /* Seek to a new position in the file.  If writing, flushes the buffer
    456  * first.  If reading, optimizes small relative seeks that stay inside the
    457  * buffer.  Returns 0 for success, EOF otherwise.
    458  */
    459 int
    460 shf_seek(shf, where, from)
    461 	struct shf *shf;
    462 	off_t where;
    463 	int from;
    464 {
    465 	if (shf->fd < 0) {
    466 		errno = EINVAL;
    467 		return EOF;
    468 	}
    469 
    470 	if (shf->flags & SHF_ERROR) {
    471 		errno = shf->errno_;
    472 		return EOF;
    473 	}
    474 
    475 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
    476 		return EOF;
    477 
    478 	if (shf->flags & SHF_READING) {
    479 		if (from == SEEK_CUR &&
    480 				(where < 0 ?
    481 					-where >= shf->rbsize - shf->rnleft :
    482 					where < shf->rnleft)) {
    483 			shf->rnleft -= where;
    484 			shf->rp += where;
    485 			return 0;
    486 		}
    487 		shf->rnleft = 0;
    488 		shf->rp = shf->buf;
    489 	}
    490 
    491 	shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING);
    492 
    493 	if (lseek(shf->fd, where, from) < 0) {
    494 		shf->errno_ = errno;
    495 		shf->flags |= SHF_ERROR;
    496 		return EOF;
    497 	}
    498 
    499 	return 0;
    500 }
    501 
    502 
    503 /* Read a buffer from shf.  Returns the number of bytes read into buf,
    504  * if no bytes were read, returns 0 if end of file was seen, EOF if
    505  * a read error occurred.
    506  */
    507 int
    508 shf_read(buf, bsize, shf)
    509 	char *buf;
    510 	int bsize;
    511 	struct shf *shf;
    512 {
    513 	int orig_bsize = bsize;
    514 	int ncopy;
    515 
    516 	if (!(shf->flags & SHF_RD))
    517 		internal_errorf(1, "shf_read: flags %x", shf->flags);
    518 
    519 	if (bsize <= 0)
    520 		internal_errorf(1, "shf_read: bsize %d", bsize);
    521 
    522 	while (bsize > 0) {
    523 		if (shf->rnleft == 0
    524 		    && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
    525 			break;
    526 		ncopy = shf->rnleft;
    527 		if (ncopy > bsize)
    528 			ncopy = bsize;
    529 		memcpy(buf, shf->rp, ncopy);
    530 		buf += ncopy;
    531 		bsize -= ncopy;
    532 		shf->rp += ncopy;
    533 		shf->rnleft -= ncopy;
    534 	}
    535 	/* Note: fread(3S) returns 0 for errors - this doesn't */
    536 	return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0)
    537 				   : orig_bsize - bsize;
    538 }
    539 
    540 /* Read up to a newline or EOF.  The newline is put in buf; buf is always
    541  * null terminated.  Returns NULL on read error or if nothing was read before
    542  * end of file, returns a pointer to the null byte in buf otherwise.
    543  */
    544 char *
    545 shf_getse(buf, bsize, shf)
    546 	char *buf;
    547 	int bsize;
    548 	struct shf *shf;
    549 {
    550 	unsigned char *end;
    551 	int ncopy;
    552 	char *orig_buf = buf;
    553 
    554 	if (!(shf->flags & SHF_RD))
    555 		internal_errorf(1, "shf_getse: flags %x", shf->flags);
    556 
    557 	if (bsize <= 0)
    558 		return (char *) 0;
    559 
    560 	--bsize;	/* save room for null */
    561 	do {
    562 		if (shf->rnleft == 0) {
    563 			if (shf_fillbuf(shf) == EOF)
    564 				return NULL;
    565 			if (shf->rnleft == 0) {
    566 				*buf = '\0';
    567 				return buf == orig_buf ? NULL : buf;
    568 			}
    569 		}
    570 		end = (unsigned char *) memchr((char *) shf->rp, '\n',
    571 					     shf->rnleft);
    572 		ncopy = end ? end - shf->rp + 1 : shf->rnleft;
    573 		if (ncopy > bsize)
    574 			ncopy = bsize;
    575 		memcpy(buf, (char *) shf->rp, ncopy);
    576 		shf->rp += ncopy;
    577 		shf->rnleft -= ncopy;
    578 		buf += ncopy;
    579 		bsize -= ncopy;
    580 
    581 	} while (!end && bsize);
    582 	*buf = '\0';
    583 	return buf;
    584 }
    585 
    586 /* Returns the char read.  Returns EOF for error and end of file. */
    587 int
    588 shf_getchar(shf)
    589 	struct shf *shf;
    590 {
    591 	if (!(shf->flags & SHF_RD))
    592 		internal_errorf(1, "shf_getchar: flags %x", shf->flags);
    593 
    594 	if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
    595 		return EOF;
    596 	--shf->rnleft;
    597 	return *shf->rp++;
    598 }
    599 
    600 /* Put a character back in the input stream.  Returns the character if
    601  * successful, EOF if there is no room.
    602  */
    603 int
    604 shf_ungetc(c, shf)
    605 	int c;
    606 	struct shf *shf;
    607 {
    608 	if (!(shf->flags & SHF_RD))
    609 		internal_errorf(1, "shf_ungetc: flags %x", shf->flags);
    610 
    611 	if ((shf->flags & SHF_ERROR) || c == EOF
    612 	    || (shf->rp == shf->buf && shf->rnleft))
    613 		return EOF;
    614 
    615 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
    616 		return EOF;
    617 
    618 	if (shf->rp == shf->buf)
    619 		shf->rp = shf->buf + shf->rbsize;
    620 	if (shf->flags & SHF_STRING) {
    621 		/* Can unget what was read, but not something different - we
    622 		 * don't want to modify a string.
    623 		 */
    624 		if (shf->rp[-1] != c)
    625 			return EOF;
    626 		shf->flags &= ~SHF_EOF;
    627 		shf->rp--;
    628 		shf->rnleft++;
    629 		return c;
    630 	}
    631 	shf->flags &= ~SHF_EOF;
    632 	*--(shf->rp) = c;
    633 	shf->rnleft++;
    634 	return c;
    635 }
    636 
    637 /* Write a character.  Returns the character if successful, EOF if
    638  * the char could not be written.
    639  */
    640 int
    641 shf_putchar(c, shf)
    642 	int c;
    643 	struct shf *shf;
    644 {
    645 	if (!(shf->flags & SHF_WR))
    646 		internal_errorf(1, "shf_putchar: flags %x", shf->flags);
    647 
    648 	if (c == EOF)
    649 		return EOF;
    650 
    651 	if (shf->flags & SHF_UNBUF) {
    652 		char cc = c;
    653 		int n;
    654 
    655 		if (shf->fd < 0)
    656 			internal_errorf(1, "shf_putchar: no fd");
    657 		if (shf->flags & SHF_ERROR) {
    658 			errno = shf->errno_;
    659 			return EOF;
    660 		}
    661 		while ((n = write(shf->fd, &cc, 1)) != 1)
    662 			if (n < 0) {
    663 				if (errno == EINTR
    664 				    && !(shf->flags & SHF_INTERRUPT))
    665 					continue;
    666 				shf->flags |= SHF_ERROR;
    667 				shf->errno_ = errno;
    668 				return EOF;
    669 			}
    670 	} else {
    671 		/* Flush deals with strings and sticky errors */
    672 		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF)
    673 			return EOF;
    674 		shf->wnleft--;
    675 		*shf->wp++ = c;
    676 	}
    677 
    678 	return c;
    679 }
    680 
    681 /* Write a string.  Returns the length of the string if successful, EOF if
    682  * the string could not be written.
    683  */
    684 int
    685 shf_puts(s, shf)
    686 	const char *s;
    687 	struct shf *shf;
    688 {
    689 	if (!s)
    690 		return EOF;
    691 
    692 	return shf_write(s, strlen(s), shf);
    693 }
    694 
    695 /* Write a buffer.  Returns nbytes if successful, EOF if there is an error. */
    696 int
    697 shf_write(buf, nbytes, shf)
    698 	const char *buf;
    699 	int nbytes;
    700 	struct shf *shf;
    701 {
    702 	int orig_nbytes = nbytes;
    703 	int n;
    704 	int ncopy;
    705 
    706 	if (!(shf->flags & SHF_WR))
    707 		internal_errorf(1, "shf_write: flags %x", shf->flags);
    708 
    709 	if (nbytes < 0)
    710 		internal_errorf(1, "shf_write: nbytes %d", nbytes);
    711 
    712 	/* Don't buffer if buffer is empty and we're writing a large amount. */
    713 	if ((ncopy = shf->wnleft)
    714 	    && (shf->wp != shf->buf || nbytes < shf->wnleft))
    715 	{
    716 		if (ncopy > nbytes)
    717 			ncopy = nbytes;
    718 		memcpy(shf->wp, buf, ncopy);
    719 		nbytes -= ncopy;
    720 		buf += ncopy;
    721 		shf->wp += ncopy;
    722 		shf->wnleft -= ncopy;
    723 	}
    724 	if (nbytes > 0) {
    725 		/* Flush deals with strings and sticky errors */
    726 		if (shf_emptybuf(shf, EB_GROW) == EOF)
    727 			return EOF;
    728 		if (nbytes > shf->wbsize) {
    729 			ncopy = nbytes;
    730 			if (shf->wbsize)
    731 				ncopy -= nbytes % shf->wbsize;
    732 			nbytes -= ncopy;
    733 			while (ncopy > 0) {
    734 				n = write(shf->fd, buf, ncopy);
    735 				if (n < 0) {
    736 					if (errno == EINTR
    737 					    && !(shf->flags & SHF_INTERRUPT))
    738 						continue;
    739 					shf->flags |= SHF_ERROR;
    740 					shf->errno_ = errno;
    741 					shf->wnleft = 0;
    742 					/* Note: fwrite(3S) returns 0 for
    743 					 * errors - this doesn't */
    744 					return EOF;
    745 				}
    746 				buf += n;
    747 				ncopy -= n;
    748 			}
    749 		}
    750 		if (nbytes > 0) {
    751 			memcpy(shf->wp, buf, nbytes);
    752 			shf->wp += nbytes;
    753 			shf->wnleft -= nbytes;
    754 		}
    755 	}
    756 
    757 	return orig_nbytes;
    758 }
    759 
    760 int
    761 shf_fprintf(struct shf *shf, const char *fmt, ...)
    762 {
    763 	va_list args;
    764 	int n;
    765 
    766 	va_start(args, fmt);
    767 	n = shf_vfprintf(shf, fmt, args);
    768 	va_end(args);
    769 
    770 	return n;
    771 }
    772 
    773 int
    774 shf_snprintf(char *buf, int bsize, const char *fmt, ...)
    775 {
    776 	struct shf shf;
    777 	va_list args;
    778 	int n;
    779 
    780 	if (!buf || bsize <= 0)
    781 		internal_errorf(1, "shf_snprintf: buf %lx, bsize %d",
    782 			(long) buf, bsize);
    783 
    784 	shf_sopen(buf, bsize, SHF_WR, &shf);
    785 	va_start(args, fmt);
    786 	n = shf_vfprintf(&shf, fmt, args);
    787 	va_end(args);
    788 	shf_sclose(&shf); /* null terminates */
    789 	return n;
    790 }
    791 
    792 char *
    793 shf_smprintf(const char *fmt, ...)
    794 {
    795 	struct shf shf;
    796 	va_list args;
    797 
    798 	shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf);
    799 	va_start(args, fmt);
    800 	shf_vfprintf(&shf, fmt, args);
    801 	va_end(args);
    802 	return shf_sclose(&shf); /* null terminates */
    803 }
    804 
    805 #undef FP  			/* if you want floating point stuff */
    806 
    807 #define BUF_SIZE	128
    808 #define FPBUF_SIZE	(DMAXEXP+16)/* this must be >
    809 				 *	MAX(DMAXEXP, log10(pow(2, DSIGNIF)))
    810 				 *    + ceil(log10(DMAXEXP)) + 8 (I think).
    811 				 * Since this is hard to express as a
    812 				 * constant, just use a large buffer.
    813 				 */
    814 
    815 /*
    816  *	What kinda of machine we on?  Hopefully the C compiler will optimize
    817  *  this out...
    818  *
    819  *	For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit
    820  *  machines it don't matter.  Assumes C compiler has converted shorts to
    821  *  ints before pushing them.
    822  */
    823 #define POP_INT(f, s, a) (((f) & FL_LONG) ?				\
    824 				va_arg((a), unsigned long)		\
    825 			    :						\
    826 				(sizeof(int) < sizeof(long) ?		\
    827 					((s) ?				\
    828 						(long) va_arg((a), int)	\
    829 					    :				\
    830 						va_arg((a), unsigned))	\
    831 				    :					\
    832 					va_arg((a), unsigned)))
    833 
    834 #define ABIGNUM		32000	/* big numer that will fit in a short */
    835 #define LOG2_10		3.321928094887362347870319429	/* log base 2 of 10 */
    836 
    837 #define	FL_HASH		0x001	/* `#' seen */
    838 #define FL_PLUS		0x002	/* `+' seen */
    839 #define FL_RIGHT	0x004	/* `-' seen */
    840 #define FL_BLANK	0x008	/* ` ' seen */
    841 #define FL_SHORT	0x010	/* `h' seen */
    842 #define FL_LONG		0x020	/* `l' seen */
    843 #define FL_ZERO		0x040	/* `0' seen */
    844 #define FL_DOT		0x080	/* '.' seen */
    845 #define FL_UPPER	0x100	/* format character was uppercase */
    846 #define FL_NUMBER	0x200	/* a number was formatted %[douxefg] */
    847 
    848 
    849 #ifdef FP
    850 #include <math.h>
    851 
    852 static double
    853 my_ceil(d)
    854 	double	d;
    855 {
    856 	double		i;
    857 
    858 	return d - modf(d, &i) + (d < 0 ? -1 : 1);
    859 }
    860 #endif /* FP */
    861 
    862 int
    863 shf_vfprintf(shf, fmt, args)
    864 	struct shf *shf;
    865 	const char *fmt;
    866 	va_list args;
    867 {
    868 	char		c, *s;
    869 	int		UNINITIALIZED(tmp);
    870 	int		field, precision;
    871 	int		len;
    872 	int		flags;
    873 	unsigned long	lnum;
    874 					/* %#o produces the longest output */
    875 	char		numbuf[(BITS(long) + 2) / 3 + 1];
    876 	/* this stuff for dealing with the buffer */
    877 	int		nwritten = 0;
    878 	static char nulls[] = "(null %s)";
    879 #ifdef FP
    880 	/* should be in <math.h>
    881 	 *  extern double frexp();
    882 	 */
    883 	extern char *ecvt();
    884 
    885 	double		fpnum;
    886 	int		expo, decpt;
    887 	char		style;
    888 	char		fpbuf[FPBUF_SIZE];
    889 #endif /* FP */
    890 
    891 	if (!fmt)
    892 		return 0;
    893 
    894 	while ((c = *fmt++)) {
    895 		if (c != '%') {
    896 			shf_putc(c, shf);
    897 			nwritten++;
    898 			continue;
    899 		}
    900 		/*
    901 		 *	This will accept flags/fields in any order - not
    902 		 *  just the order specified in printf(3), but this is
    903 		 *  the way _doprnt() seems to work (on bsd and sysV).
    904 		 *  The only restriction is that the format character must
    905 		 *  come last :-).
    906 		 */
    907 		flags = field = precision = 0;
    908 		for ( ; (c = *fmt++) ; ) {
    909 			switch (c) {
    910 			case '#':
    911 				flags |= FL_HASH;
    912 				continue;
    913 
    914 			case '+':
    915 				flags |= FL_PLUS;
    916 				continue;
    917 
    918 			case '-':
    919 				flags |= FL_RIGHT;
    920 				continue;
    921 
    922 			case ' ':
    923 				flags |= FL_BLANK;
    924 				continue;
    925 
    926 			case '0':
    927 				if (!(flags & FL_DOT))
    928 					flags |= FL_ZERO;
    929 				continue;
    930 
    931 			case '.':
    932 				flags |= FL_DOT;
    933 				precision = 0;
    934 				continue;
    935 
    936 			case '*':
    937 				tmp = va_arg(args, int);
    938 				if (flags & FL_DOT)
    939 					precision = tmp;
    940 				else if ((field = tmp) < 0) {
    941 					field = -field;
    942 					flags |= FL_RIGHT;
    943 				}
    944 				continue;
    945 
    946 			case 'l':
    947 				flags |= FL_LONG;
    948 				continue;
    949 
    950 			case 'h':
    951 				flags |= FL_SHORT;
    952 				continue;
    953 			}
    954 			if (digit(c)) {
    955 				tmp = c - '0';
    956 				while (c = *fmt++, digit(c))
    957 					tmp = tmp * 10 + c - '0';
    958 				--fmt;
    959 				if (tmp < 0)		/* overflow? */
    960 					tmp = 0;
    961 				if (flags & FL_DOT)
    962 					precision = tmp;
    963 				else
    964 					field = tmp;
    965 				continue;
    966 			}
    967 			break;
    968 		}
    969 
    970 		if (precision < 0)
    971 			precision = 0;
    972 
    973 		if (!c)		/* nasty format */
    974 			break;
    975 
    976 		if (c >= 'A' && c <= 'Z') {
    977 			flags |= FL_UPPER;
    978 			c = c - 'A' + 'a';
    979 		}
    980 
    981 		switch (c) {
    982 		case 'p': /* pointer */
    983 			flags &= ~(FL_LONG | FL_SHORT);
    984 			if (sizeof(char *) > sizeof(int))
    985 				flags |= FL_LONG; /* hope it fits.. */
    986 			/* aaahhh... */
    987 			/*FALLTHROUGH*/
    988 		case 'd':
    989 		case 'i':
    990 		case 'o':
    991 		case 'u':
    992 		case 'x':
    993 			flags |= FL_NUMBER;
    994 			s = &numbuf[sizeof(numbuf)];
    995 			lnum = POP_INT(flags, c == 'd', args);
    996 			switch (c) {
    997 			case 'd':
    998 			case 'i':
    999 				if (0 > (long) lnum)
   1000 					lnum = - (long) lnum, tmp = 1;
   1001 				else
   1002 					tmp = 0;
   1003 				/* aaahhhh..... */
   1004 				/*FALLTHROUGH*/
   1005 			case 'u':
   1006 				do {
   1007 					*--s = lnum % 10 + '0';
   1008 					lnum /= 10;
   1009 				} while (lnum);
   1010 
   1011 				if (c != 'u') {
   1012 					if (tmp)
   1013 						*--s = '-';
   1014 					else if (flags & FL_PLUS)
   1015 						*--s = '+';
   1016 					else if (flags & FL_BLANK)
   1017 						*--s = ' ';
   1018 				}
   1019 				break;
   1020 
   1021 			case 'o':
   1022 				do {
   1023 					*--s = (lnum & 0x7) + '0';
   1024 					lnum >>= 3;
   1025 				} while (lnum);
   1026 
   1027 				if ((flags & FL_HASH) && *s != '0')
   1028 					*--s = '0';
   1029 				break;
   1030 
   1031 			case 'p':
   1032 			case 'x':
   1033 			    {
   1034 				const char *digits = (flags & FL_UPPER) ?
   1035 						  "0123456789ABCDEF"
   1036 						: "0123456789abcdef";
   1037 				do {
   1038 					*--s = digits[lnum & 0xf];
   1039 					lnum >>= 4;
   1040 				} while (lnum);
   1041 
   1042 				if (flags & FL_HASH) {
   1043 					*--s = (flags & FL_UPPER) ? 'X' : 'x';
   1044 					*--s = '0';
   1045 				}
   1046 			    }
   1047 			}
   1048 			len = &numbuf[sizeof(numbuf)] - s;
   1049 			if (flags & FL_DOT) {
   1050 				if (precision > len) {
   1051 					field = precision;
   1052 					flags |= FL_ZERO;
   1053 				} else
   1054 					precision = len; /* no loss */
   1055 			}
   1056 			break;
   1057 
   1058 #ifdef FP
   1059 		case 'e':
   1060 		case 'g':
   1061 		case 'f':
   1062 		    {
   1063 			char *p;
   1064 
   1065 			/*
   1066 			 *	This could probably be done better,
   1067 			 *  but it seems to work.  Note that gcvt()
   1068 			 *  is not used, as you cannot tell it to
   1069 			 *  not strip the zeros.
   1070 			 */
   1071 			flags |= FL_NUMBER;
   1072 			if (!(flags & FL_DOT))
   1073 				precision = 6;	/* default */
   1074 			/*
   1075 			 *	Assumes doubles are pushed on
   1076 			 *  the stack.  If this is not so, then
   1077 			 *  FL_LONG/FL_SHORT should be checked.
   1078 			 */
   1079 			fpnum = va_arg(args, double);
   1080 			s = fpbuf;
   1081 			style = c;
   1082 			/*
   1083 			 *  This is the same as
   1084 			 *	expo = ceil(log10(fpnum))
   1085 			 *  but doesn't need -lm.  This is an
   1086 			 *  approximation as expo is rounded up.
   1087 			 */
   1088 			(void) frexp(fpnum, &expo);
   1089 			expo = my_ceil(expo / LOG2_10);
   1090 
   1091 			if (expo < 0)
   1092 				expo = 0;
   1093 
   1094 			p = ecvt(fpnum, precision + 1 + expo,
   1095 				 &decpt, &tmp);
   1096 			if (c == 'g') {
   1097 				if (decpt < -4 || decpt > precision)
   1098 					style = 'e';
   1099 				else
   1100 					style = 'f';
   1101 				if (decpt > 0 && (precision -= decpt) < 0)
   1102 					precision = 0;
   1103 			}
   1104 			if (tmp)
   1105 				*s++ = '-';
   1106 			else if (flags & FL_PLUS)
   1107 				*s++ = '+';
   1108 			else if (flags & FL_BLANK)
   1109 				*s++ = ' ';
   1110 
   1111 			if (style == 'e')
   1112 				*s++ = *p++;
   1113 			else {
   1114 				if (decpt > 0) {
   1115 					/* Overflow check - should
   1116 					 * never have this problem.
   1117 					 */
   1118 					if (decpt >
   1119 						&fpbuf[sizeof(fpbuf)]
   1120 							- s - 8)
   1121 						decpt =
   1122 						 &fpbuf[sizeof(fpbuf)]
   1123 							- s - 8;
   1124 					(void) memcpy(s, p, decpt);
   1125 					s += decpt;
   1126 					p += decpt;
   1127 				} else
   1128 					*s++ = '0';
   1129 			}
   1130 
   1131 			/* print the fraction? */
   1132 			if (precision > 0) {
   1133 				*s++ = '.';
   1134 				/* Overflow check - should
   1135 				 * never have this problem.
   1136 				 */
   1137 				if (precision > &fpbuf[sizeof(fpbuf)]
   1138 							- s - 7)
   1139 					precision =
   1140 						&fpbuf[sizeof(fpbuf)]
   1141 						- s - 7;
   1142 				for (tmp = decpt;  tmp++ < 0 &&
   1143 					    precision > 0 ; precision--)
   1144 					*s++ = '0';
   1145 				tmp = strlen(p);
   1146 				if (precision > tmp)
   1147 					precision = tmp;
   1148 				/* Overflow check - should
   1149 				 * never have this problem.
   1150 				 */
   1151 				if (precision > &fpbuf[sizeof(fpbuf)]
   1152 							- s - 7)
   1153 					precision =
   1154 						&fpbuf[sizeof(fpbuf)]
   1155 						- s - 7;
   1156 				(void) memcpy(s, p, precision);
   1157 				s += precision;
   1158 				/*
   1159 				 *	`g' format strips trailing
   1160 				 *  zeros after the decimal.
   1161 				 */
   1162 				if (c == 'g' && !(flags & FL_HASH)) {
   1163 					while (*--s == '0')
   1164 						;
   1165 					if (*s != '.')
   1166 						s++;
   1167 				}
   1168 			} else if (flags & FL_HASH)
   1169 				*s++ = '.';
   1170 
   1171 			if (style == 'e') {
   1172 				*s++ = (flags & FL_UPPER) ? 'E' : 'e';
   1173 				if (--decpt >= 0)
   1174 					*s++ = '+';
   1175 				else {
   1176 					*s++ = '-';
   1177 					decpt = -decpt;
   1178 				}
   1179 				p = &numbuf[sizeof(numbuf)];
   1180 				for (tmp = 0; tmp < 2 || decpt ; tmp++) {
   1181 					*--p = '0' + decpt % 10;
   1182 					decpt /= 10;
   1183 				}
   1184 				tmp = &numbuf[sizeof(numbuf)] - p;
   1185 				(void) memcpy(s, p, tmp);
   1186 				s += tmp;
   1187 			}
   1188 
   1189 			len = s - fpbuf;
   1190 			s = fpbuf;
   1191 			precision = len;
   1192 			break;
   1193 		    }
   1194 #endif /* FP */
   1195 
   1196 		case 's':
   1197 			if (!(s = va_arg(args, char *)))
   1198 				s = nulls;
   1199 			len = strlen(s);
   1200 			break;
   1201 
   1202 		case 'c':
   1203 			flags &= ~FL_DOT;
   1204 			numbuf[0] = va_arg(args, int);
   1205 			s = numbuf;
   1206 			len = 1;
   1207 			break;
   1208 
   1209 		case '%':
   1210 		default:
   1211 			numbuf[0] = c;
   1212 			s = numbuf;
   1213 			len = 1;
   1214 			break;
   1215 		}
   1216 
   1217 		/*
   1218 		 *	At this point s should point to a string that is
   1219 		 *  to be formatted, and len should be the length of the
   1220 		 *  string.
   1221 		 */
   1222 		if (!(flags & FL_DOT) || len < precision)
   1223 			precision = len;
   1224 		if (field > precision) {
   1225 			field -= precision;
   1226 			if (!(flags & FL_RIGHT)) {
   1227 				field = -field;
   1228 				/* skip past sign or 0x when padding with 0 */
   1229 				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
   1230 					if (*s == '+' || *s == '-' || *s ==' ')
   1231 					{
   1232 						shf_putc(*s, shf);
   1233 						s++;
   1234 						precision--;
   1235 						nwritten++;
   1236 					} else if (*s == '0') {
   1237 						shf_putc(*s, shf);
   1238 						s++;
   1239 						nwritten++;
   1240 						if (--precision > 0 &&
   1241 							(*s | 0x20) == 'x')
   1242 						{
   1243 							shf_putc(*s, shf);
   1244 							s++;
   1245 							precision--;
   1246 							nwritten++;
   1247 						}
   1248 					}
   1249 					c = '0';
   1250 				} else
   1251 					c = flags & FL_ZERO ? '0' : ' ';
   1252 				if (field < 0) {
   1253 					nwritten += -field;
   1254 					for ( ; field < 0 ; field++)
   1255 						shf_putc(c, shf);
   1256 				}
   1257 			} else
   1258 				c = ' ';
   1259 		} else
   1260 			field = 0;
   1261 
   1262 		if (precision > 0) {
   1263 			nwritten += precision;
   1264 			for ( ; precision-- > 0 ; s++)
   1265 				shf_putc(*s, shf);
   1266 		}
   1267 		if (field > 0) {
   1268 			nwritten += field;
   1269 			for ( ; field > 0 ; --field)
   1270 				shf_putc(c, shf);
   1271 		}
   1272 	}
   1273 
   1274 	return shf_error(shf) ? EOF : nwritten;
   1275 }
   1276