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