-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.c
545 lines (455 loc) · 8.02 KB
/
io.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
#include <sys/compat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "shellio.h"
#include "sh.h"
/*
* This module deals with character output to the Unix standard error and
* standard output streams. In a shell, we really do not have the freedom
* to use the ISO library facilities, since the shell redirection operator
* causes too many problems with it.
*/
typedef int stream_t;
#define COMMAND_NAME "sh"
#define NUM_BUF_SIZE 64
/*
* Convert a long integer to a string.
*
* Note that we don't use ldiv () to construct the string in order to avoid
* problems with the most negative number.
*/
#if USE_PROTO
unsigned char * ltoa (unsigned char * dest, size_t len, long num, int radix,
int precision)
#else
unsigned char *
ltoa (dest, len, num, radix, precision)
unsigned char * dest;
size_t len;
long num;
int radix;
int precision;
#endif
{
static unsigned char radixstr [] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
unsigned char * ptr = dest + len;
unsigned long temp = num < 0 ? - num : num;
* -- ptr = 0;
do {
if (ptr == dest)
break;
* -- ptr = radixstr [temp % radix];
temp = temp / radix;
} while (temp != 0 || -- precision > 0);
if (num < 0 && ptr != dest)
* -- ptr = '-';
return ptr;
}
/*
* Convert an integer to a string.
*/
#if USE_PROTO
unsigned char * itoa (unsigned char * dest, size_t len, int num, int radix,
int precision)
#else
unsigned char *
itoa (dest, len, num, radix, precision)
unsigned char * dest;
size_t len;
int num;
int radix;
int precision;
#endif
{
return ltoa (dest, len, (long) num, radix, precision);
}
/*
* Forward declarations.
*/
LOCAL void io_panic PROTO ((stream_t _fd));
/*
* Write a single character to the indicated stream. Ignore EBADF errors, make
* other errors fatal.
*/
#if USE_PROTO
LOCAL void write_char (stream_t fd, unsigned char ch)
#else
LOCAL void
write_char (fd, ch)
stream_t fd;
unsigned char ch;
#endif
{
if (write (fd, & ch, 1) == -1) {
#if defined (EBADF)
if (errno == EBADF)
return;
#endif
io_panic (fd);
}
}
/*
* Write a counted buffer to the indicated stream. Ignore EBADF errors and
* make other errors fatal.
*/
#if USE_PROTO
LOCAL void write_buffer (stream_t fd, CONST VOID * buf, size_t len)
#else
LOCAL void
write_buffer (fd, buf, len)
stream_t fd;
CONST VOID * buf;
size_t len;
#endif
{
if (write (fd, buf, len) == -1) {
#if defined (EBADF)
if (errno == EBADF)
return;
#endif
io_panic (fd);
}
}
/*
* Write a string to the indicated stream. Ignore EBADF errors, make other
* errors fatal.
*/
#if USE_PROTO
LOCAL void write_string (stream_t fd, CONST unsigned char * str)
#else
LOCAL void
write_string (fd, str)
stream_t fd;
CONST unsigned char * str;
#endif
{
write_buffer (fd, str, strlen (str));
}
/*
* Write an long to the indicated stream. Ignore EBADF errors, make other
* errors fatal.
*/
#if USE_PROTO
LOCAL void write_long (stream_t fd, long num)
#else
LOCAL void
write_long (fd, num)
stream_t fd;
long num;
#endif
{
unsigned char buf [NUM_BUF_SIZE];
write_string (fd, ltoa (buf, sizeof (buf), num, 10, 0));
}
/*
* Deal with some kind of fatal I/O error.
*/
#if USE_PROTO
LOCAL void io_panic (stream_t fd)
#else
LOCAL void
io_panic (fd)
stream_t fd;
#endif
{
static int in_panic;
int saved_error = errno;
if (in_panic ++ != 0)
exit (3);
if (fd == STDOUT_FILENO)
fd = STDERR_FILENO;
else if (isatty (fd)) {
} else if ((fd = open ("/dev/tty", O_WRONLY)) != -1) {
} else
exit (3);
write_string (fd, COMMAND_NAME);
write_string (fd, ": fatal output error \"");
write_string (fd, strerror (saved_error));
write_string (fd, "\"\n");
}
/*
* error message prologue - print line number and file if
* not interactive.
*/
#if USE_PROTO
LOCAL void error_vicinity (void)
#else
LOCAL void
error_vicinity ()
#endif
{
if (sesp->s_type == SFILE) {
shellerr_outstr (sesp->s_strp);
shellerr_outstr (": shell script ");
if ((sesp->s_flag & SESSION_EOF) != 0)
shellerr_outstr ("EOF");
else {
shellerr_outstr ("line ");
shellerr_outint (sesp->s_line);
}
shellerr_outstr (": ");
} else
shellerr_outstr ("sh: ");
}
#define SHELL_FILENO STDERR_FILENO
#define SHELLERR_FILENO STDERR_FILENO
#define CMD_FILENO STDOUT_FILENO
#define CMDERR_FILENO STDERR_FILENO
/*
* Write data from the shell.
*/
#if USE_PROTO
void shell_outstr (CONST unsigned char * str)
#else
void
shell_outstr (str)
CONST unsigned char * str;
#endif
{
write_string (SHELL_FILENO, str);
}
#if USE_PROTO
void shell_outchar (unsigned char ch)
#else
void
shell_outchar (ch)
unsigned char ch;
#endif
{
write_char (SHELL_FILENO, ch);
}
#if USE_PROTO
void shell_outint (int num)
#else
void
shell_outint (num)
int num;
#endif
{
write_long (SHELL_FILENO, (long) num);
}
#if USE_PROTO
void shell_outlong (long num)
#else
void
shell_outlong (num)
long num;
#endif
{
write_long (SHELL_FILENO, num);
}
#if USE_PROTO
void shell_endl (void)
#else
void
shell_endl ()
#endif
{
write_char (SHELL_FILENO, '\n');
}
/*
* Write an error report from the shell.
*/
#if USE_PROTO
int shellerr_begin (CONST unsigned char * locus)
#else
int
shellerr_begin (locus)
CONST unsigned char * locus;
#endif
{
errflag ++;
if (noeflag)
return 0;
error_vicinity ();
write_string (SHELLERR_FILENO, locus);
write_string (SHELLERR_FILENO, ": ");
return 1;
}
#if USE_PROTO
void shellerr_outstr (CONST unsigned char * str)
#else
void
shellerr_outstr (str)
CONST unsigned char * str;
#endif
{
write_string (SHELLERR_FILENO, str);
}
#if USE_PROTO
void shellerr_outchar (unsigned char ch)
#else
void
shellerr_outchar (ch)
unsigned char ch;
#endif
{
write_char (SHELLERR_FILENO, ch);
}
#if USE_PROTO
void shellerr_outint (int num)
#else
void
shellerr_outint (num)
int num;
#endif
{
write_long (SHELLERR_FILENO, (long) num);
}
#if USE_PROTO
void shellerr_outlong (long num)
#else
void
shellerr_outlong (num)
long num;
#endif
{
write_long (SHELLERR_FILENO, num);
}
#if USE_PROTO
void shellerr_endl (void)
#else
void
shellerr_endl ()
#endif
{
write_char (SHELLERR_FILENO, '\n');
}
#if USE_PROTO
void shellerr_simple (CONST unsigned char * locus, CONST unsigned char * str)
#else
void
shellerr_simple (locus, str)
CONST unsigned char * locus;
CONST unsigned char * str;
#endif
{
if (shellerr_begin (locus)) {
shellerr_outstr (str);
shellerr_endl ();
}
}
/*
* Write data from a command.
*/
#if USE_PROTO
void cmd_outstr (CONST unsigned char * str)
#else
void
cmd_outstr (str)
CONST unsigned char * str;
#endif
{
write_string (CMD_FILENO, str);
}
#if USE_PROTO
void cmd_outchar (unsigned char ch)
#else
void
cmd_outchar (ch)
unsigned char ch;
#endif
{
write_char (CMD_FILENO, ch);
}
#if USE_PROTO
void cmd_outint (int num)
#else
void
cmd_outint (num)
int num;
#endif
{
write_long (CMD_FILENO, (long) num);
}
#if USE_PROTO
void cmd_outlong (long num)
#else
void
cmd_outlong (num)
long num;
#endif
{
write_long (CMD_FILENO, num);
}
#if USE_PROTO
void cmd_endl (void)
#else
void
cmd_endl ()
#endif
{
write_char (CMD_FILENO, '\n');
}
/*
* Write an error report from a builtin.
*/
#if USE_PROTO
int cmderr_begin (CONST unsigned char * name)
#else
int
cmderr_begin (name)
CONST unsigned char * name;
#endif
{
if (noeflag)
return 0;
error_vicinity ();
write_string (CMDERR_FILENO, "builtin \"");
write_string (CMDERR_FILENO, name);
write_string (CMDERR_FILENO, "\": ");
return 1;
}
#if USE_PROTO
void cmderr_outstr (CONST unsigned char * str)
#else
void
cmderr_outstr (str)
CONST unsigned char * str;
#endif
{
write_string (CMDERR_FILENO, str);
}
#if USE_PROTO
void cmderr_outchar (unsigned char ch)
#else
void
cmderr_outchar (ch)
unsigned char ch;
#endif
{
write_char (CMDERR_FILENO, ch);
}
#if USE_PROTO
void cmderr_outint (int num)
#else
void
cmderr_outint (num)
int num;
#endif
{
write_long (CMDERR_FILENO, (long) num);
}
#if USE_PROTO
void cmderr_outlong (long num)
#else
void
cmderr_outlong (num)
long num;
#endif
{
write_long (CMDERR_FILENO, num);
}
#if USE_PROTO
void cmderr_endl (void)
#else
void
cmderr_endl ()
#endif
{
write_char (CMDERR_FILENO, '\n');
}