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