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