Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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