xref: /netbsd-src/bin/ksh/shf.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: shf.c,v 1.5 2003/06/23 11:39:02 agc 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.5 2003/06/23 11:39:02 agc Exp $");
10 #endif
11 
12 
13 #include "sh.h"
14 #include "ksh_stat.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 #ifdef OS2
581 		if (end && buf > orig_buf + 1 && buf[-2] == '\r') {
582 			buf--;
583 			bsize++;
584 			buf[-1] = '\n';
585 		}
586 #endif
587 
588 	} while (!end && bsize);
589 	*buf = '\0';
590 	return buf;
591 }
592 
593 /* Returns the char read.  Returns EOF for error and end of file. */
594 int
595 shf_getchar(shf)
596 	struct shf *shf;
597 {
598 	if (!(shf->flags & SHF_RD))
599 		internal_errorf(1, "shf_getchar: flags %x", shf->flags);
600 
601 	if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
602 		return EOF;
603 	--shf->rnleft;
604 	return *shf->rp++;
605 }
606 
607 /* Put a character back in the input stream.  Returns the character if
608  * successful, EOF if there is no room.
609  */
610 int
611 shf_ungetc(c, shf)
612 	int c;
613 	struct shf *shf;
614 {
615 	if (!(shf->flags & SHF_RD))
616 		internal_errorf(1, "shf_ungetc: flags %x", shf->flags);
617 
618 	if ((shf->flags & SHF_ERROR) || c == EOF
619 	    || (shf->rp == shf->buf && shf->rnleft))
620 		return EOF;
621 
622 	if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
623 		return EOF;
624 
625 	if (shf->rp == shf->buf)
626 		shf->rp = shf->buf + shf->rbsize;
627 	if (shf->flags & SHF_STRING) {
628 		/* Can unget what was read, but not something different - we
629 		 * don't want to modify a string.
630 		 */
631 		if (shf->rp[-1] != c)
632 			return EOF;
633 		shf->flags &= ~SHF_EOF;
634 		shf->rp--;
635 		shf->rnleft++;
636 		return c;
637 	}
638 	shf->flags &= ~SHF_EOF;
639 	*--(shf->rp) = c;
640 	shf->rnleft++;
641 	return c;
642 }
643 
644 /* Write a character.  Returns the character if successful, EOF if
645  * the char could not be written.
646  */
647 int
648 shf_putchar(c, shf)
649 	int c;
650 	struct shf *shf;
651 {
652 	if (!(shf->flags & SHF_WR))
653 		internal_errorf(1, "shf_putchar: flags %x", shf->flags);
654 
655 	if (c == EOF)
656 		return EOF;
657 
658 	if (shf->flags & SHF_UNBUF) {
659 		char cc = c;
660 		int n;
661 
662 		if (shf->fd < 0)
663 			internal_errorf(1, "shf_putchar: no fd");
664 		if (shf->flags & SHF_ERROR) {
665 			errno = shf->errno_;
666 			return EOF;
667 		}
668 		while ((n = write(shf->fd, &cc, 1)) != 1)
669 			if (n < 0) {
670 				if (errno == EINTR
671 				    && !(shf->flags & SHF_INTERRUPT))
672 					continue;
673 				shf->flags |= SHF_ERROR;
674 				shf->errno_ = errno;
675 				return EOF;
676 			}
677 	} else {
678 		/* Flush deals with strings and sticky errors */
679 		if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF)
680 			return EOF;
681 		shf->wnleft--;
682 		*shf->wp++ = c;
683 	}
684 
685 	return c;
686 }
687 
688 /* Write a string.  Returns the length of the string if successful, EOF if
689  * the string could not be written.
690  */
691 int
692 shf_puts(s, shf)
693 	const char *s;
694 	struct shf *shf;
695 {
696 	if (!s)
697 		return EOF;
698 
699 	return shf_write(s, strlen(s), shf);
700 }
701 
702 /* Write a buffer.  Returns nbytes if successful, EOF if there is an error. */
703 int
704 shf_write(buf, nbytes, shf)
705 	const char *buf;
706 	int nbytes;
707 	struct shf *shf;
708 {
709 	int orig_nbytes = nbytes;
710 	int n;
711 	int ncopy;
712 
713 	if (!(shf->flags & SHF_WR))
714 		internal_errorf(1, "shf_write: flags %x", shf->flags);
715 
716 	if (nbytes < 0)
717 		internal_errorf(1, "shf_write: nbytes %d", nbytes);
718 
719 	/* Don't buffer if buffer is empty and we're writting a large amount. */
720 	if ((ncopy = shf->wnleft)
721 	    && (shf->wp != shf->buf || nbytes < shf->wnleft))
722 	{
723 		if (ncopy > nbytes)
724 			ncopy = nbytes;
725 		memcpy(shf->wp, buf, ncopy);
726 		nbytes -= ncopy;
727 		buf += ncopy;
728 		shf->wp += ncopy;
729 		shf->wnleft -= ncopy;
730 	}
731 	if (nbytes > 0) {
732 		/* Flush deals with strings and sticky errors */
733 		if (shf_emptybuf(shf, EB_GROW) == EOF)
734 			return EOF;
735 		if (nbytes > shf->wbsize) {
736 			ncopy = nbytes;
737 			if (shf->wbsize)
738 				ncopy -= nbytes % shf->wbsize;
739 			nbytes -= ncopy;
740 			while (ncopy > 0) {
741 				n = write(shf->fd, buf, ncopy);
742 				if (n < 0) {
743 					if (errno == EINTR
744 					    && !(shf->flags & SHF_INTERRUPT))
745 						continue;
746 					shf->flags |= SHF_ERROR;
747 					shf->errno_ = errno;
748 					shf->wnleft = 0;
749 					/* Note: fwrite(3S) returns 0 for
750 					 * errors - this doesn't */
751 					return EOF;
752 				}
753 				buf += n;
754 				ncopy -= n;
755 			}
756 		}
757 		if (nbytes > 0) {
758 			memcpy(shf->wp, buf, nbytes);
759 			shf->wp += nbytes;
760 			shf->wnleft -= nbytes;
761 		}
762 	}
763 
764 	return orig_nbytes;
765 }
766 
767 int
768 #ifdef HAVE_PROTOTYPES
769 shf_fprintf(struct shf *shf, const char *fmt, ...)
770 #else
771 shf_fprintf(shf, fmt, va_alist)
772 	struct shf *shf;
773 	const char *fmt;
774 	va_dcl
775 #endif
776 {
777 	va_list args;
778 	int n;
779 
780 	SH_VA_START(args, fmt);
781 	n = shf_vfprintf(shf, fmt, args);
782 	va_end(args);
783 
784 	return n;
785 }
786 
787 int
788 #ifdef HAVE_PROTOTYPES
789 shf_snprintf(char *buf, int bsize, const char *fmt, ...)
790 #else
791 shf_snprintf(buf, bsize, fmt, va_alist)
792 	char *buf;
793 	int bsize;
794 	const char *fmt;
795 	va_dcl
796 #endif
797 {
798 	struct shf shf;
799 	va_list args;
800 	int n;
801 
802 	if (!buf || bsize <= 0)
803 		internal_errorf(1, "shf_snprintf: buf %lx, bsize %d",
804 			(long) buf, bsize);
805 
806 	shf_sopen(buf, bsize, SHF_WR, &shf);
807 	SH_VA_START(args, fmt);
808 	n = shf_vfprintf(&shf, fmt, args);
809 	va_end(args);
810 	shf_sclose(&shf); /* null terminates */
811 	return n;
812 }
813 
814 char *
815 #ifdef HAVE_PROTOTYPES
816 shf_smprintf(const char *fmt, ...)
817 #else
818 shf_smprintf(fmt, va_alist)
819 	char *fmt;
820 	va_dcl
821 #endif
822 {
823 	struct shf shf;
824 	va_list args;
825 
826 	shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf);
827 	SH_VA_START(args, fmt);
828 	shf_vfprintf(&shf, fmt, args);
829 	va_end(args);
830 	return shf_sclose(&shf); /* null terminates */
831 }
832 
833 #undef FP  			/* if you want floating point stuff */
834 
835 #define BUF_SIZE	128
836 #define FPBUF_SIZE	(DMAXEXP+16)/* this must be >
837 				 *	MAX(DMAXEXP, log10(pow(2, DSIGNIF)))
838 				 *    + ceil(log10(DMAXEXP)) + 8 (I think).
839 				 * Since this is hard to express as a
840 				 * constant, just use a large buffer.
841 				 */
842 
843 /*
844  *	What kinda of machine we on?  Hopefully the C compiler will optimize
845  *  this out...
846  *
847  *	For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit
848  *  machines it don't matter.  Assmumes C compiler has converted shorts to
849  *  ints before pushing them.
850  */
851 #define POP_INT(f, s, a) (((f) & FL_LONG) ?				\
852 				va_arg((a), unsigned long)		\
853 			    :						\
854 				(sizeof(int) < sizeof(long) ?		\
855 					((s) ?				\
856 						(long) va_arg((a), int)	\
857 					    :				\
858 						va_arg((a), unsigned))	\
859 				    :					\
860 					va_arg((a), unsigned)))
861 
862 #define ABIGNUM		32000	/* big numer that will fit in a short */
863 #define LOG2_10		3.321928094887362347870319429	/* log base 2 of 10 */
864 
865 #define	FL_HASH		0x001	/* `#' seen */
866 #define FL_PLUS		0x002	/* `+' seen */
867 #define FL_RIGHT	0x004	/* `-' seen */
868 #define FL_BLANK	0x008	/* ` ' seen */
869 #define FL_SHORT	0x010	/* `h' seen */
870 #define FL_LONG		0x020	/* `l' seen */
871 #define FL_ZERO		0x040	/* `0' seen */
872 #define FL_DOT		0x080	/* '.' seen */
873 #define FL_UPPER	0x100	/* format character was uppercase */
874 #define FL_NUMBER	0x200	/* a number was formated %[douxefg] */
875 
876 
877 #ifdef FP
878 #include <math.h>
879 
880 static double
881 my_ceil(d)
882 	double	d;
883 {
884 	double		i;
885 
886 	return d - modf(d, &i) + (d < 0 ? -1 : 1);
887 }
888 #endif /* FP */
889 
890 int
891 shf_vfprintf(shf, fmt, args)
892 	struct shf *shf;
893 	const char *fmt;
894 	va_list args;
895 {
896 	char		c, *s;
897 	int		UNINITIALIZED(tmp);
898 	int		field, precision;
899 	int		len;
900 	int		flags;
901 	unsigned long	lnum;
902 					/* %#o produces the longest output */
903 	char		numbuf[(BITS(long) + 2) / 3 + 1];
904 	/* this stuff for dealing with the buffer */
905 	int		nwritten = 0;
906 #ifdef FP
907 	/* should be in <math.h>
908 	 *  extern double frexp();
909 	 */
910 	extern char *ecvt();
911 
912 	double		fpnum;
913 	int		expo, decpt;
914 	char		style;
915 	char		fpbuf[FPBUF_SIZE];
916 #endif /* FP */
917 
918 	if (!fmt)
919 		return 0;
920 
921 	while ((c = *fmt++)) {
922 		if (c != '%') {
923 			shf_putc(c, shf);
924 			nwritten++;
925 			continue;
926 		}
927 		/*
928 		 *	This will accept flags/fields in any order - not
929 		 *  just the order specified in printf(3), but this is
930 		 *  the way _doprnt() seems to work (on bsd and sysV).
931 		 *  The only resriction is that the format character must
932 		 *  come last :-).
933 		 */
934 		flags = field = precision = 0;
935 		for ( ; (c = *fmt++) ; ) {
936 			switch (c) {
937 			case '#':
938 				flags |= FL_HASH;
939 				continue;
940 
941 			case '+':
942 				flags |= FL_PLUS;
943 				continue;
944 
945 			case '-':
946 				flags |= FL_RIGHT;
947 				continue;
948 
949 			case ' ':
950 				flags |= FL_BLANK;
951 				continue;
952 
953 			case '0':
954 				if (!(flags & FL_DOT))
955 					flags |= FL_ZERO;
956 				continue;
957 
958 			case '.':
959 				flags |= FL_DOT;
960 				precision = 0;
961 				continue;
962 
963 			case '*':
964 				tmp = va_arg(args, int);
965 				if (flags & FL_DOT)
966 					precision = tmp;
967 				else if ((field = tmp) < 0) {
968 					field = -field;
969 					flags |= FL_RIGHT;
970 				}
971 				continue;
972 
973 			case 'l':
974 				flags |= FL_LONG;
975 				continue;
976 
977 			case 'h':
978 				flags |= FL_SHORT;
979 				continue;
980 			}
981 			if (digit(c)) {
982 				tmp = c - '0';
983 				while (c = *fmt++, digit(c))
984 					tmp = tmp * 10 + c - '0';
985 				--fmt;
986 				if (tmp < 0)		/* overflow? */
987 					tmp = 0;
988 				if (flags & FL_DOT)
989 					precision = tmp;
990 				else
991 					field = tmp;
992 				continue;
993 			}
994 			break;
995 		}
996 
997 		if (precision < 0)
998 			precision = 0;
999 
1000 		if (!c)		/* nasty format */
1001 			break;
1002 
1003 		if (c >= 'A' && c <= 'Z') {
1004 			flags |= FL_UPPER;
1005 			c = c - 'A' + 'a';
1006 		}
1007 
1008 		switch (c) {
1009 		case 'p': /* pointer */
1010 			flags &= ~(FL_LONG | FL_SHORT);
1011 			if (sizeof(char *) > sizeof(int))
1012 				flags |= FL_LONG; /* hope it fits.. */
1013 			/* aaahhh... */
1014 		case 'd':
1015 		case 'i':
1016 		case 'o':
1017 		case 'u':
1018 		case 'x':
1019 			flags |= FL_NUMBER;
1020 			s = &numbuf[sizeof(numbuf)];
1021 			lnum = POP_INT(flags, c == 'd', args);
1022 			switch (c) {
1023 			case 'd':
1024 			case 'i':
1025 				if (0 > (long) lnum)
1026 					lnum = - (long) lnum, tmp = 1;
1027 				else
1028 					tmp = 0;
1029 				/* aaahhhh..... */
1030 
1031 			case 'u':
1032 				do {
1033 					*--s = lnum % 10 + '0';
1034 					lnum /= 10;
1035 				} while (lnum);
1036 
1037 				if (c != 'u') {
1038 					if (tmp)
1039 						*--s = '-';
1040 					else if (flags & FL_PLUS)
1041 						*--s = '+';
1042 					else if (flags & FL_BLANK)
1043 						*--s = ' ';
1044 				}
1045 				break;
1046 
1047 			case 'o':
1048 				do {
1049 					*--s = (lnum & 0x7) + '0';
1050 					lnum >>= 3;
1051 				} while (lnum);
1052 
1053 				if ((flags & FL_HASH) && *s != '0')
1054 					*--s = '0';
1055 				break;
1056 
1057 			case 'p':
1058 			case 'x':
1059 			    {
1060 				const char *digits = (flags & FL_UPPER) ?
1061 						  "0123456789ABCDEF"
1062 						: "0123456789abcdef";
1063 				do {
1064 					*--s = digits[lnum & 0xf];
1065 					lnum >>= 4;
1066 				} while (lnum);
1067 
1068 				if (flags & FL_HASH) {
1069 					*--s = (flags & FL_UPPER) ? 'X' : 'x';
1070 					*--s = '0';
1071 				}
1072 			    }
1073 			}
1074 			len = &numbuf[sizeof(numbuf)] - s;
1075 			if (flags & FL_DOT) {
1076 				if (precision > len) {
1077 					field = precision;
1078 					flags |= FL_ZERO;
1079 				} else
1080 					precision = len; /* no loss */
1081 			}
1082 			break;
1083 
1084 #ifdef FP
1085 		case 'e':
1086 		case 'g':
1087 		case 'f':
1088 		    {
1089 			char *p;
1090 
1091 			/*
1092 			 *	This could proabably be done better,
1093 			 *  but it seems to work.  Note that gcvt()
1094 			 *  is not used, as you cannot tell it to
1095 			 *  not strip the zeros.
1096 			 */
1097 			flags |= FL_NUMBER;
1098 			if (!(flags & FL_DOT))
1099 				precision = 6;	/* default */
1100 			/*
1101 			 *	Assumes doubles are pushed on
1102 			 *  the stack.  If this is not so, then
1103 			 *  FL_LONG/FL_SHORT should be checked.
1104 			 */
1105 			fpnum = va_arg(args, double);
1106 			s = fpbuf;
1107 			style = c;
1108 			/*
1109 			 *  This is the same as
1110 			 *	expo = ceil(log10(fpnum))
1111 			 *  but doesn't need -lm.  This is an
1112 			 *  aproximation as expo is rounded up.
1113 			 */
1114 			(void) frexp(fpnum, &expo);
1115 			expo = my_ceil(expo / LOG2_10);
1116 
1117 			if (expo < 0)
1118 				expo = 0;
1119 
1120 			p = ecvt(fpnum, precision + 1 + expo,
1121 				 &decpt, &tmp);
1122 			if (c == 'g') {
1123 				if (decpt < -4 || decpt > precision)
1124 					style = 'e';
1125 				else
1126 					style = 'f';
1127 				if (decpt > 0 && (precision -= decpt) < 0)
1128 					precision = 0;
1129 			}
1130 			if (tmp)
1131 				*s++ = '-';
1132 			else if (flags & FL_PLUS)
1133 				*s++ = '+';
1134 			else if (flags & FL_BLANK)
1135 				*s++ = ' ';
1136 
1137 			if (style == 'e')
1138 				*s++ = *p++;
1139 			else {
1140 				if (decpt > 0) {
1141 					/* Overflow check - should
1142 					 * never have this problem.
1143 					 */
1144 					if (decpt >
1145 						&fpbuf[sizeof(fpbuf)]
1146 							- s - 8)
1147 						decpt =
1148 						 &fpbuf[sizeof(fpbuf)]
1149 							- s - 8;
1150 					(void) memcpy(s, p, decpt);
1151 					s += decpt;
1152 					p += decpt;
1153 				} else
1154 					*s++ = '0';
1155 			}
1156 
1157 			/* print the fraction? */
1158 			if (precision > 0) {
1159 				*s++ = '.';
1160 				/* Overflow check - should
1161 				 * never have this problem.
1162 				 */
1163 				if (precision > &fpbuf[sizeof(fpbuf)]
1164 							- s - 7)
1165 					precision =
1166 						&fpbuf[sizeof(fpbuf)]
1167 						- s - 7;
1168 				for (tmp = decpt;  tmp++ < 0 &&
1169 					    precision > 0 ; precision--)
1170 					*s++ = '0';
1171 				tmp = strlen(p);
1172 				if (precision > tmp)
1173 					precision = tmp;
1174 				/* Overflow check - should
1175 				 * never have this problem.
1176 				 */
1177 				if (precision > &fpbuf[sizeof(fpbuf)]
1178 							- s - 7)
1179 					precision =
1180 						&fpbuf[sizeof(fpbuf)]
1181 						- s - 7;
1182 				(void) memcpy(s, p, precision);
1183 				s += precision;
1184 				/*
1185 				 *	`g' format strips trailing
1186 				 *  zeros after the decimal.
1187 				 */
1188 				if (c == 'g' && !(flags & FL_HASH)) {
1189 					while (*--s == '0')
1190 						;
1191 					if (*s != '.')
1192 						s++;
1193 				}
1194 			} else if (flags & FL_HASH)
1195 				*s++ = '.';
1196 
1197 			if (style == 'e') {
1198 				*s++ = (flags & FL_UPPER) ? 'E' : 'e';
1199 				if (--decpt >= 0)
1200 					*s++ = '+';
1201 				else {
1202 					*s++ = '-';
1203 					decpt = -decpt;
1204 				}
1205 				p = &numbuf[sizeof(numbuf)];
1206 				for (tmp = 0; tmp < 2 || decpt ; tmp++) {
1207 					*--p = '0' + decpt % 10;
1208 					decpt /= 10;
1209 				}
1210 				tmp = &numbuf[sizeof(numbuf)] - p;
1211 				(void) memcpy(s, p, tmp);
1212 				s += tmp;
1213 			}
1214 
1215 			len = s - fpbuf;
1216 			s = fpbuf;
1217 			precision = len;
1218 			break;
1219 		    }
1220 #endif /* FP */
1221 
1222 		case 's':
1223 			if (!(s = va_arg(args, char *)))
1224 				s = "(null %s)";
1225 			len = strlen(s);
1226 			break;
1227 
1228 		case 'c':
1229 			flags &= ~FL_DOT;
1230 			numbuf[0] = va_arg(args, int);
1231 			s = numbuf;
1232 			len = 1;
1233 			break;
1234 
1235 		case '%':
1236 		default:
1237 			numbuf[0] = c;
1238 			s = numbuf;
1239 			len = 1;
1240 			break;
1241 		}
1242 
1243 		/*
1244 		 *	At this point s should point to a string that is
1245 		 *  to be formatted, and len should be the length of the
1246 		 *  string.
1247 		 */
1248 		if (!(flags & FL_DOT) || len < precision)
1249 			precision = len;
1250 		if (field > precision) {
1251 			field -= precision;
1252 			if (!(flags & FL_RIGHT)) {
1253 				field = -field;
1254 				/* skip past sign or 0x when padding with 0 */
1255 				if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
1256 					if (*s == '+' || *s == '-' || *s ==' ')
1257 					{
1258 						shf_putc(*s, shf);
1259 						s++;
1260 						precision--;
1261 						nwritten++;
1262 					} else if (*s == '0') {
1263 						shf_putc(*s, shf);
1264 						s++;
1265 						nwritten++;
1266 						if (--precision > 0 &&
1267 							(*s | 0x20) == 'x')
1268 						{
1269 							shf_putc(*s, shf);
1270 							s++;
1271 							precision--;
1272 							nwritten++;
1273 						}
1274 					}
1275 					c = '0';
1276 				} else
1277 					c = flags & FL_ZERO ? '0' : ' ';
1278 				if (field < 0) {
1279 					nwritten += -field;
1280 					for ( ; field < 0 ; field++)
1281 						shf_putc(c, shf);
1282 				}
1283 			} else
1284 				c = ' ';
1285 		} else
1286 			field = 0;
1287 
1288 		if (precision > 0) {
1289 			nwritten += precision;
1290 			for ( ; precision-- > 0 ; s++)
1291 				shf_putc(*s, shf);
1292 		}
1293 		if (field > 0) {
1294 			nwritten += field;
1295 			for ( ; field > 0 ; --field)
1296 				shf_putc(c, shf);
1297 		}
1298 	}
1299 
1300 	return shf_error(shf) ? EOF : nwritten;
1301 }
1302