1 /*
2 * Usage:
3 * $0 [ options... ] [ files ]
4
5 * Filters the named files; if there are no files, stdin is used.
6
7 * Options:
8 * -r: reverse short-, int-, and long-sized objects.
9 * N.B. General byte-swapping throughout the file should
10 * be handled by something like dd.
11 * -f fmt: format output according to fmt (default "a").
12 * -F file: file contains format.
13 * -h: print help message, then exit.
14 * -l x: limit output to no more than x characters per line (default 80).
15 * -p: print offsets (lines begin <offset>:<tab> ).
16 * -o: like -p, but print using octal.
17 * -P len: print offsets (lines begin <len>x<n>+<offset>:<tab> ).
18 * -O: like -P, but print offset part using octal.
19 * -t: use \# T (T=F,I,...) to indicate data type; also
20 * start newlines for each data type or copyout, and
21 * terminate copyouts with tabs. WARNING: inviz can't properly
22 * invert output unless -t is set.
23
24 * -L: print a human-readable version of the internal representation
25 * of the format.
26 * -D: turn on debug mode.
27
28 * Formats:
29 * see grammar.y for structure.
30
31 * Output formatting:
32 * Ascii:
33 * bell -> \a (__STDC__ only)
34 * backspace -> \b
35 * formfeed -> \f
36 * newline -> \n
37 * return -> \r
38 * tab -> \t
39 * vertical tab -> \v (__STDC__ only)
40 * backslash -> \\
41 * ^ -> \^
42 * all other printing characters (octal 040 - 177): unchanged
43 * all other non-printing characters in the range 0 - 039: ^@ ^A, etc
44 * all others -> \nnn
45 * In addition, after transforming newline to \n, a true newline is printed.
46
47 */
48
49 #include <stdio.h>
50 #include <ctype.h>
51 #include "string.h"
52 #include "memory.h"
53 #include <errno.h>
54
55 #define VIZ_MAIN
56 #include "viz.h"
57
58 #ifndef _SYS_ERRNO_H_
59 extern errno;
60 extern int sys_nerr;
61 extern char *sys_errlist[];
62 #endif
63
64 #ifndef _STDLIB_H_
65 extern char *malloc();
66 extern optind, opterr;
67 extern char *optarg;
68 #endif
69
70 MEMP rootlist;
71
72 char *prog;
73 struct Format Fmt = {
74 "a", /* Default format */
75 NULL, /* input text */
76 0, /* format is not from a file */
77 0, /* current line number in format */
78 NULL, /* ptr to start of curr line */
79 NULL}; /* ptr to 1 past last item */
80 int show_list = 0; /* show the format list */
81 int debug = 0; /* ==list + show the creation of the list */
82 int show_type = 0; /* use \# T to show data type */
83 int process_to_eof = 1; /* !0 means user gave a counted item list */
84 int print_offset_octal = 0; /* print offsets using octal output */
85 int reverse_int = 0; /* reverse ea integral type before evaluating */
86 int do_condense = 1; /* bool: condense list if !0 */
87
88 int print_offset = 0;
89
90 /* Describes what's happening on the current line. */
91 struct {
92 int maxlen; /* Maximum line length */
93 int avail; /* Amount remaining on current line
94 * before running into maxlen.
95 */
96 int avail_nl; /* amount remaining after doing newline
97 * plus any offset labelling, etc.
98 */
99 char mode; /* Current output mode: ( a/c/C/S/.../\0 ) */
100 } line = { 80, 80, 80, '\0' };
101
102 int item_len;
103
104 /* For printing values in binary */
105 char binary[256][9];
106
107 /* Registers for storing counts */
108 long count_reg[256];
109
110 /* Amount of data (in chars) that have been processed so far. */
111 long *data_offset = &count_reg[(int) '@'];
112
113 static struct {
114 char *main; /* main i/o buffer */
115 char *secondary; /* when needed, data is copied here for alignment */
116 char *end; /* marks 1 past last valid posn in main buf */
117 char *next; /* points to next char in main that is unprocessed */
118 } readbuf = { NULL, NULL, NULL, NULL };
119
120 int out_of_size = 0; /* Set to 1 when read_data has returned all it can in
121 * requested size
122 */
123 int out_of_data = 0; /* Set to 1 when read_data has returned all it can
124 * (note that EOF occurs before read_data finishes
125 * returning all the final data from its buffer)
126 */
127
128
129 typedef union {
130 char *c;
131 unsigned char *uc;
132 short *s;
133 unsigned short *us;
134 int *i;
135 unsigned int *ui;
136 long *l;
137 unsigned long *ul;
138 float *f;
139 double *d;
140 } ALLTYPE;
141
142 #ifdef MIN
143 #undef MIN
144 #endif
145
146 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
147
148 /* Need should be used before outputting an item; it makes sure there's
149 * enough space on the current line, and if not, it calls do_newline
150 * to get the space. It's a macro because it's called on a per-item basis.
151 */
152 #define need(n) { \
153 register mode; \
154 if (line.avail < (n) ) { \
155 mode = line.mode; \
156 do_newline(); \
157 set_mode(mode); \
158 } \
159 }
160
161 /* OUTPUTSTR uses need() to check that there's room for a string; then
162 * prints it, and adjusts the available-space counter. It's a macro
163 * because it's called on a per-item basis.
164 */
165 #define OUTPUTSTR(s) \
166 { \
167 register n=0; \
168 register char *q, *p; \
169 q = p = (s); \
170 while (*p) { \
171 n++; \
172 if (*p++ == '\t') n += 7; \
173 } \
174 need(n); \
175 fputs((q), stdout); \
176 line.avail -= n; \
177 }
178
179 /* adj_count(x) is used to keep a counter in the valid range when
180 * it's counting to EOF. (Note that a file could be larger than
181 * LONG_MAX, so counting bytes through EOF would not be good.)
182 * Therefore adj_count(x) checks if x < 0 (which is the sign that
183 * we are counting to EOF) and replaces it with UPTO_EOF, a number
184 * that is less than 0 but not << 0. If x > 0, we don't assign
185 * anything to x. adj_count() should not appear in any inner loop,
186 * of course.
187 */
188 #define adj_count(x) (x < 0 ? x = UPTO_EOF : UPTO_EOF)
189
main(argc,argv)190 main(argc, argv)
191 int argc;
192 char **argv;
193 {
194 int n;
195 void fillformat();
196 void viz();
197 void viz_text();
198 void line_init();
199 void binary_init();
200
201 int i, nfiles;
202
203 prog = argv[0];
204
205 rootlist = NIL;
206
207 binary_init();
208
209 if ( (i = get_options(argc, argv)) == 0)
210 return 1;
211
212 if (yyparse() != 0)
213 return 1;
214
215 if (process_to_eof) {
216 /* Apply an <inf> multiplier to the user's list. Potential
217 * problem: when the list includes sublists, the rootlist
218 * returned by the grammar points to the first sublist.
219 * Thus, we repackage the entire list as a sublist of a new root;
220 * this makes sure that the count applied to the rootlist is
221 * applied to the entire list.
222 */
223 MEMBER *temp = newlist(rootlist);
224 temp->count = UPTO_EOF;
225 rootlist = temp;
226 }
227
228 if (debug || show_list) {
229 (void) fprintf(stderr, "Before condensing:\n");
230 printlist(0, rootlist);
231 (void) fprintf(stderr, "--------\n");
232 }
233
234 if (do_condense) {
235 n = condenselist(rootlist);
236
237 if (debug || show_list) {
238 (void) fprintf(stderr, "After condensing:\n");
239 (void) fprintf(stderr, "%d change%s\n", n, (n!=1) ? "s" : "");
240 printlist(0, rootlist);
241 (void) fprintf(stderr, "--------\n");
242 }
243 } else {
244 if (debug || show_list) {
245 (void) fprintf(stderr, "List condensing is turned off\n");
246 }
247 }
248
249 fillformat(rootlist);
250
251
252 nfiles = argc - i;
253
254 if (i == argc) {
255 if (read_data_init() == -1)
256 return 1;
257 clearerr(stdin);
258 out_of_size = 0;
259 out_of_data = 0;
260
261 line_init();
262
263 if (print_offset)
264 (void) put_offset();
265
266 viz(rootlist, 1);
267 } else {
268 do {
269 if (freopen(argv[i], "r", stdin) == (FILE *) NULL) {
270 (void) fprintf(stderr, "%s: failed to open %s: ",prog, argv[i]);
271 perror("");
272 } else {
273
274 if (read_data_init() == -1)
275 return 1;
276 clearerr(stdin);
277 out_of_size = 0;
278 out_of_data = 0;
279
280 *data_offset = 0;
281
282 if (nfiles > 1)
283 (void) printf("\n==> %s <==\t\n", argv[i]);
284
285 line_init();
286
287 if (print_offset)
288 (void) put_offset();
289
290 viz(rootlist, 1);
291 }
292
293 } while (++i < argc);
294 }
295
296 if ( !out_of_data && process_to_eof && !ferror(stdin) ) {
297 /* There can be up to (sizeof(double) - 1) characters that remain
298 * unprocessed, if the final input elements are 'D', but only 1
299 * char remains on stdin. Process the remainder in ascii.
300 */
301 viz_text((long) sizeof(double), 1, 'C', NULL, 0);
302 }
303
304 if (line.avail < (line.maxlen-1) ) { /* Note that line_init sets
305 * line.avail=line.maxlen-1
306 * for an empty line */
307 (void) putchar('\n');
308 }
309 return 0;
310 }
311
312 void
binary_init()313 binary_init()
314 {
315 /* Initializes the array binary[256][9] with
316 * the binary ascii representation of 0..255.
317 */
318
319 int i, j, n;
320 static char *s16[16] = {
321 "0000", "0001", "0010", "0011",
322 "0100", "0101", "0110", "0111",
323
324 "1000", "1001", "1010", "1011",
325 "1100", "1101", "1110", "1111",
326 };
327
328
329 for (i=0; i<16; i++)
330 for (n=i*16, j=0; j<16; j++) {
331 (void) strcpy(binary[n+j], s16[i]);
332 (void) strcpy(binary[n+j]+4, s16[j]);
333 }
334 }
335
get_options(argc,argv)336 int get_options(argc, argv)
337 int argc;
338 char **argv;
339 {
340 /* Sets options; returns argv index of first file argument.
341 * If there are no file arguments, returns argc.
342 */
343 int c;
344 char *loadfile();
345 int fmt_done = 0;
346 int i;
347
348 while ( (c = getopt(argc, argv, "c:f:F:hl:oO:pP:tDL")) != -1) {
349 switch (c) {
350 case 'r':
351 reverse_int = 1;
352 break;
353 case 'f':
354 if (fmt_done) {
355 (void) fprintf(stderr,
356 "%s: Only one instance of -f and/or -F may be used.\n",
357 prog);
358 exit(1);
359 }
360 Fmt.text = optarg;
361 fmt_done = 1;
362 break;
363 case 'F':
364 if (fmt_done) {
365 (void) fprintf(stderr,
366 "%s: Only one instance of -f and/or -F may be used.\n",
367 prog);
368 exit(1);
369 }
370 Fmt.file = 1;
371 Fmt.text = loadfile(optarg);
372 fmt_done = 1;
373 if (Fmt.text == NULL) {
374 (void) fprintf(stderr,
375 "%s: Failed to load format from `%s' -- ",
376 prog, optarg);
377 if (errno > 0 && errno <= sys_nerr)
378 (void) fprintf(stderr, "%s\n", sys_errlist[errno]);
379 else
380 (void) fprintf(stderr, "errno = %d\n", errno);
381 exit(1);
382 }
383 break;
384 case 'h':
385 (void) fprintf(stderr, "\
386 Usage:\n%s [-f fmt | -F file] \n\
387 \t[-r] [-h] [-l x] [-p|o] [-P|O len] [-t] [-L] [-D] [file ...]\n",
388 prog);
389 (void) fprintf(stderr, "\
390 Options:\n");
391 (void) fprintf(stderr, "\
392 -f fmt: format output according to fmt (default \"a\").\n\
393 -F file: format is contained in file.\n\
394 \n\
395 -h: print this help message on stderr, then exit.\n\
396 -l x: limit output to no more than x characters per line (default 80).\n\
397 -p: print offsets (each line is begun <offset>:<tab> ).\n\
398 -P len: print offsets using format <len>*<n>+<offset>:<tab> ).\n\
399 -o, -O len: like -p and -P, but using octal for offset.\n\
400 -r: reverse bytes in each integer-type value before interpreting\n\
401 (this applies to short, int, and long-sized data).\n\
402 -t: use \\# <T> to show data type (so inviz can invert result).\n\
403 -L: print internal version of the format (not generally useful).\n\
404 -D: turn on debug mode (not generally useful).\n\n");
405
406 (void) fprintf(stderr, "\
407 Formats:\n\
408 If fmt doesn't begin with a count, it's repeated until EOF is reached.\n\
409 Basic format: [count] input_size output_fmt [ >reg_char ].\n\
410 + count: decimal or $reg_char or $$.\n\
411 + input_size: one of C/Z/S/I/L/F/D.\n\
412 + output_fmt: one of a/b/c/d/u/o/h/x/f/g/~/\"printf-fmt\".\n\
413 + Default pairings: [abc~] <-> C; [duohx] <-> I; [fg] <-> F\n\
414 [CZ] <-> a; [SIL] <-> d; [FD] <-> g\n\
415 + Illegal pairings: [CSIL] & [fg]; [SILFD] & [ac]; [FD] & [abcduohx]\n");
416 (void) fprintf(stderr, "\
417 Special formats:\n\
418 + n or \\n output a newline; e.g. 17n means 17 newlines\n\
419 + [xxx] output comment xxx; e.g. 2[hello] means print `hello' twice\n\
420 Compound formats:\n\
421 + The above simple formats can be concatenated:\n\
422 24a5f means 24 ascii chars, then 5 floats\n\
423 + Parentheses group and nest:\n\
424 I3(24a5f) means 1 int, then 3 groups of 24 chars & 5 floats\n");
425 exit(0);
426 break;
427 case 'l':
428 line.maxlen = atoi(optarg);
429 break;
430 case 'o':
431 print_offset_octal = 1;
432 /* FALLTHROUGH */
433 case 'p':
434 if (print_offset) {
435 fprintf(stderr,
436 "Options -p|o and -P|O are mutually exclusive\n");
437 exit(1);
438 }
439 print_offset = 1;
440 break;
441 case 'O':
442 print_offset_octal = 1;
443 /* FALLTHROUGH */
444 case 'P':
445 if (print_offset) {
446 fprintf(stderr, "Options -p and -P are mutually exclusive\n");
447 exit(1);
448 }
449 print_offset = atoi(optarg);
450 if (print_offset < 2) {
451 fprintf(stderr,
452 "%s: record length for offsets must be > 1; you used `%s'\n",
453 prog, optarg);
454 exit(1);
455 }
456 break;
457 case 't':
458 show_type = 1;
459 break;
460 case 'L':
461 show_list = 1;
462 break;
463 case 'D':
464 debug = 1;
465 break;
466 case '?':
467 return 0;
468 /* NOTREACHED */
469 break;
470 default:
471 (void) fprintf(stderr,
472 "%s: unexpected option `%c' returned to get_options\n",
473 prog, c);
474 return 0;
475 /* NOTREACHED */
476 break;
477 }
478 }
479 return optind;
480 }
481
fillformat(list)482 void fillformat(list)
483 MEMBER *list;
484 {
485 MEMBER *p;
486
487 #define IC (p->u.iospec.ichar)
488 #define OC (p->u.iospec.ochar)
489
490 for (p = list; p != NIL; p = p->next) {
491 if (p->type == T_LISTHEAD) {
492 fillformat(p->u.sublist);
493 } else if (p->type == T_IOSPEC) {
494 if (p->u.iospec.fmt != NULL)
495 ; /* Format already assigned by user */
496
497 else if (OC == 'a' || OC == 'c' || OC == '~')
498 ; /* Format isn't used for 'a', 'c', '~' output */
499
500 else if (IC == 'C' && OC == 'b')
501 p->u.iospec.fmt = Cb_fmt;
502 else if (IC == 'C' && OC == 'o')
503 p->u.iospec.fmt = Co_fmt;
504 else if (IC == 'C' && OC == 'd')
505 p->u.iospec.fmt = Cd_fmt;
506 else if (IC == 'C' && OC == 'u')
507 p->u.iospec.fmt = Cu_fmt;
508 else if (IC == 'C' && OC == 'x')
509 p->u.iospec.fmt = Cx_fmt;
510
511 else if (IC == 'Z' && OC == 'b')
512 p->u.iospec.fmt = Zb_fmt;
513 else if (IC == 'Z' && OC == 'o')
514 p->u.iospec.fmt = Zo_fmt;
515 else if (IC == 'Z' && OC == 'd')
516 p->u.iospec.fmt = Zd_fmt;
517 else if (IC == 'Z' && OC == 'u')
518 p->u.iospec.fmt = Zu_fmt;
519 else if (IC == 'Z' && OC == 'x')
520 p->u.iospec.fmt = Zx_fmt;
521
522 else if (IC == 'S' && OC == 'b')
523 p->u.iospec.fmt = Sb_fmt;
524 else if (IC == 'S' && OC == 'o')
525 p->u.iospec.fmt = So_fmt;
526 else if (IC == 'S' && OC == 'd')
527 p->u.iospec.fmt = Sd_fmt;
528 else if (IC == 'S' && OC == 'u')
529 p->u.iospec.fmt = Su_fmt;
530 else if (IC == 'S' && OC == 'x')
531 p->u.iospec.fmt = Sx_fmt;
532
533 else if (IC == 'I' && OC == 'b')
534 p->u.iospec.fmt = Ib_fmt;
535 else if (IC == 'I' && OC == 'o')
536 p->u.iospec.fmt = Io_fmt;
537 else if (IC == 'I' && OC == 'd')
538 p->u.iospec.fmt = Id_fmt;
539 else if (IC == 'I' && OC == 'u')
540 p->u.iospec.fmt = Iu_fmt;
541 else if (IC == 'I' && OC == 'x')
542 p->u.iospec.fmt = Ix_fmt;
543
544 else if (IC == 'L' && OC == 'b')
545 p->u.iospec.fmt = Lb_fmt;
546 else if (IC == 'L' && OC == 'o')
547 p->u.iospec.fmt = Lo_fmt;
548 else if (IC == 'L' && OC == 'd')
549 p->u.iospec.fmt = Ld_fmt;
550 else if (IC == 'L' && OC == 'u')
551 p->u.iospec.fmt = Lu_fmt;
552 else if (IC == 'L' && OC == 'x')
553 p->u.iospec.fmt = Lx_fmt;
554
555 else if (IC == 'F' && OC == 'f')
556 p->u.iospec.fmt = Ff_fmt;
557 else if (IC == 'F' && OC == 'g')
558 p->u.iospec.fmt = Fg_fmt;
559
560 else if (IC == 'D' && OC == 'f')
561 p->u.iospec.fmt = Df_fmt;
562 else if (IC == 'D' && OC == 'g')
563 p->u.iospec.fmt = Dg_fmt;
564
565 else {
566 (void) fprintf(stderr,
567 "%s: ichar = `%c', ochar = `%c' in fillformat()!\n",
568 prog, IC, OC);
569 break;
570 }
571 }
572 }
573 #undef IC
574 #undef OC
575 }
576
line_init()577 void line_init()
578 {
579 /* Allow 1 position at end of line for the newline that is bound to
580 * eventually be printed.
581 */
582 line.avail_nl = line.avail = line.maxlen - 1;
583 line.mode = '\0';
584 }
585
do_newline()586 do_newline()
587 {
588 /* Starts a new line of output; the output mode is set to '\0' */
589
590 putchar('\n');
591 line_init();
592 if (print_offset)
593 (void) put_offset();
594 line.avail_nl = line.avail; /* amount available after doing newline */
595 }
596
set_mode(newmode)597 void set_mode(newmode)
598 int newmode;
599 {
600 /* Set_mode changes modes. If the mode is currently the desired mode,
601 * no action is taken. Otherwise, if the mode is currently '\0',
602 * it means that nothing has yet been written to the current line
603 * (excepting a possible offset), and a newline need not be done
604 * before output setting mode. Otherwise, if the mode is switching into
605 * or out of 'a' and show_type is set, do_newline is called to set up
606 * a new line; the mode is then set.
607
608 * Special case: if the old mode is '~', and we are printing offsets,
609 * force a newline to begin so that skipped data don't cause a
610 * nonsensical offset on the line following the skipped data
611
612 * Set_mode is a function on the assumption that mode changes are
613 * relatively rare, compared to outputting many values at a single mode.
614 */
615
616 #if 0
617 fprintf(stderr,
618 "set_mode: line.mode = %c newmode = %c print_offset = %d\n",
619 line.mode, newmode, print_offset);
620 #endif
621
622 if (newmode == line.mode)
623 return;
624
625 if (show_type) {
626 if (line.avail != line.avail_nl) {
627 /* have printed something; may need a newline */
628 if (line.mode == 'a' || newmode == 'a'
629 || (print_offset && line.mode == '~'))
630 do_newline();
631 }
632
633 if (newmode != '\0' && newmode != 'a') {
634 printf("\\# %c ", newmode);
635 line.avail -= 6;
636 }
637 } else if (print_offset && line.mode == '~') {
638 do_newline();
639 }
640 line.mode = newmode;
641 }
642
read_data_init()643 read_data_init()
644 {
645 if ( readbuf.main == NULL) {
646 if ( (readbuf.main = malloc((unsigned) BUFFERSIZE)) == NULL ||
647 (readbuf.secondary = malloc((unsigned) BUFFERSIZE)) == NULL ) {
648 (void) fprintf(stderr,
649 "%s: malloc failed in read_data_init: ", prog);
650 perror("");
651 return -1;
652 }
653 }
654 readbuf.end = readbuf.main + BUFFERSIZE;
655 readbuf.next = readbuf.end;
656 return 0;
657 }
658
659 void
seek_data(dsize,offset,whence)660 seek_data(dsize, offset, whence)
661 int dsize; /* Size of one datum */
662 long offset; /* How much to seek, in units of dsize */
663 int whence; /* 0, 1, 2 mean seek w.r.t. start, cur, eof */
664 {
665 /* If seeking relative to current location, convert to an absolute
666 * seek from origin (because we've probably read past user's notion
667 * of current location.
668 */
669 long my_offset = dsize*offset;
670 int my_whence = whence;
671 if (whence == 1) {
672 my_offset += *data_offset;
673 my_whence = 0;
674 }
675 if (fseek(stdin, my_offset, my_whence) != 0) {
676 fprintf(stderr, "%s: fseek(stdin, %ld, %d) failed:\n",
677 prog, offset*dsize, whence);
678 perror("");
679 if (my_whence != whence) {
680 fprintf(stderr, "N.B. Actual call was fseek(stdin, %ld, %d), \
681 to correct for %s's readahead.\n", my_offset, my_whence, prog);
682 }
683 exit(1);
684 }
685 /* Invalidate the current contents of the input stream */
686 readbuf.next = readbuf.end;
687 }
688
read_data(dsize,type,n,p)689 read_data(dsize, type, n, p)
690 int dsize; /* Size of one datum; must be < length of an io buffer */
691 int type; /* one of 'C' 'S', 'I', 'L', 'F', 'D', 'Z' */
692 long n; /* number of dsize elt's requested; ignored for type==Z;
693 * if < 0, LONG_MAX is substituted.
694 */
695 char **p; /* On return, *p pts to beginning of first datum */
696
697 /* Return: 0 on EOF or fread error; else number available, 0 .. n
698 * (A 0 return, if not EOF or error, means that there are fewer than dsize
699 * chars available).
700 */
701 {
702 register int m, nc;
703
704 char *s;
705 int nread;
706
707 if (n < 0)
708 n = LONG_MAX;
709
710 /* Check if we need to get more data:
711 * we get more whenever there is less than dsize data
712 * remaining in our buffer (or when the type is 'Z' and there isn't
713 * a null somewhere in the input buffer); otherwise, we return whatever
714 * we have already available (dsize is size of one datum) */
715
716 nc = readbuf.end - readbuf.next; /* number of remaining chars */
717
718 /* fprintf(stderr, "readdata request is %d nc = %d... ", n, nc); */
719
720 if (nc < dsize ||
721 (type == 'Z' && (s = memchr(readbuf.next, '\0', nc)) == NULL) ) {
722 /* need more */
723
724 if (nc > 0)
725 (void) memcpy(readbuf.main, readbuf.next, nc);
726
727 readbuf.next = readbuf.main;
728
729 /* Read more data and recompute nc */
730 nread = fread(readbuf.main + nc, 1, BUFFERSIZE - nc, stdin);
731 readbuf.end = readbuf.main + nc + nread;
732 nc = readbuf.end - readbuf.next;
733
734 if (nc < dsize)
735 out_of_size = 1;
736 if (nc == 0)
737 out_of_data = 1;
738 }
739 /* fprintf(stderr, "%d\n", nc); */
740
741 /* Compute m = number of dsize elements available in buffer; m is the
742 * return value from read_data. We assume that all m elements
743 * be consumed by caller.
744
745 * Note that we've tested, above, that the number of available
746 * characters is at least dsize; m will be > 0.
747 */
748 if (type == 'Z') {
749 if ((s = memchr(readbuf.next, '\0', nc)) == NULL)
750 m = nc; /* Didn't reach a null; oh well. */
751 else
752 m = s + 1 - readbuf.next;
753 } else {
754 m = MIN( nc / dsize, n);
755 }
756
757
758 /* Now let nc be the number of characters in m elements: */
759 nc = m * dsize;
760 if (aligned(type, readbuf.next)) {
761 *p = readbuf.next;
762 } else {
763 (void) memcpy(readbuf.secondary, readbuf.next, nc);
764 *p = readbuf.secondary;
765 }
766 readbuf.next += nc;
767
768 if (reverse_int) {
769 switch (type) {
770 case 'S':
771 {
772 register i;
773 register short *sp;
774 for (sp = (short *) *p, i=m+1; --i; ++sp) {
775 REVERSE_SHORT(*sp, short);
776 }
777 }
778 break;
779
780 case 'I':
781 {
782 register int i;
783 register int *ip;
784 for (ip = (int *) *p, i=m+1; --i; ++ip) {
785 REVERSE_INT(*ip, int);
786 }
787 }
788 break;
789
790 case 'L':
791 {
792 register int i;
793 register long *lp;
794 for (lp = (long *) *p, i=m+1; --i; ++lp) {
795 REVERSE_LONG(*lp, long);
796 }
797 }
798 break;
799 default:
800 /* No action is default */
801 break;
802 }
803 }
804 /* fprintf(stderr, "readdata returning %d\n", m); */
805 return m;
806 }
807
808 void
unread_data(n)809 unread_data(n)
810 long n; /* number of chars to unread */
811
812 /* Can cause terrible problems if n > number_points gotten on last
813 * read_data. Silently tries to protect itself against
814 * invalid arguments. (There didn't seem to be much point
815 * in telling caller about invalid arguments, as caller should
816 * know exactly how much data it got on last call to read_data().)
817 */
818 {
819
820
821
822 if (readbuf.next - readbuf.main < n)
823 return; /* Can't push back n chars */
824
825 readbuf.next -= n;
826
827 return;
828 }
829
put_offset()830 put_offset()
831 {
832 char offset_buf[60];
833 int i;
834
835 if (print_offset == 1) {
836 if (print_offset_octal)
837 (void) sprintf(offset_buf, "%#6o:\t", *data_offset);
838 else
839 (void) sprintf(offset_buf, "%6d:\t", *data_offset);
840
841 } else {
842 register int l = *data_offset / print_offset;
843 register int m = *data_offset % print_offset;
844 if (print_offset_octal)
845 (void) sprintf(offset_buf, "%d*%d+%#3o:\t", print_offset, l, m);
846 else
847 (void) sprintf(offset_buf, "%d*%d+%3d:\t", print_offset, l, m);
848 }
849 /* Compute amount on line. Allow 8 for tab -- but strlen() returns
850 * 1 for tab, so add 7 more. The line.avail value is increased by
851 * 1 to allow for fact that it's decremented by line_init.
852 */
853 i = (line.maxlen - (line.avail + 1)) + strlen(offset_buf) + 7;
854 /* Take result modulo 8 by masking off lowest 3 bits. */
855 i &= ~7;
856 line.avail = line.maxlen - i;
857 (void) fputs(offset_buf, stdout);
858
859 return 0;
860 }
861
862 void
viz(list,iteration)863 viz(list, iteration)
864 MEMBER *list;
865 int iteration; /* which iteration of the list this is */
866 {
867
868 register i;
869 MEMBER *p;
870
871 long count;
872 int size;
873 char ichar;
874
875 int n;
876 long lastv;
877
878 void viz_text(), viz_numeric();
879
880 ALLTYPE u;
881
882 count_reg[(int) '('] = iteration;
883
884 for (p = list; p != NIL && !out_of_size ; p = p->next) {
885
886 count = (p->count >= 0) ? p->count :
887 (p->count == UPTO_EOF) ? LONG_MAX : count_reg[ - p->count];
888 if (count <= 0)
889 continue;
890
891 switch (p->type) {
892 case T_IOSPEC:
893 switch (p->u.iospec.ochar) {
894 case 'a':
895 viz_text(count, p->u.iospec.size,
896 p->u.iospec.ichar, p->u.iospec.fmt,
897 (int) p->u.iospec.reg_no);
898 break;
899 case '~':
900 /* Output nothing, but read at least the last value so that
901 * we can store it in a register if need be. ...ok, we should
902 * really do a seek here, but I don't think it matters that
903 * much and it would be a pain to incorporate seeking when
904 * not all input sources might support it.
905 */
906 set_mode('~');
907 size = p->u.iospec.size;
908 ichar = p->u.iospec.ichar;
909 lastv = 0;
910 /* save the last value. This is a kludgy way
911 * of doing it, but what the hey.
912 */
913 switch (ichar) {
914 case 'C':
915 for (; count && (n = read_data(size, ichar, count, &u.c));
916 count -= n) {
917 *data_offset += n * size;
918 lastv = (long) *(u.c + n - 1);
919 }
920 break;
921 case 'Z':
922 for (; count &&
923 (n = read_data(size, ichar, count, &u.c)); count--) {
924 *data_offset += n * size;
925 lastv = n;
926 }
927 break;
928 case 'S':
929 for (; count &&
930 (n = read_data(size, ichar, count, (char **) &u.s));
931 count -= n) {
932 *data_offset += n * size;
933 lastv = (long) *(u.s + n - 1);
934 }
935 break;
936 case 'I':
937 for (; count &&
938 (n = read_data(size, ichar, count, (char **) &u.i));
939 count -= n) {
940 *data_offset += n * size;
941 lastv = (long) *(u.i + n - 1);
942 }
943 break;
944 case 'L':
945 for (; count &&
946 (n = read_data(size, ichar, count, (char **) &u.l));
947 count -= n) {
948 *data_offset += n * size;
949 lastv = *(u.l + n - 1);
950 }
951 break;
952 default:
953 /* Don't need to save values of float or double data;
954 * just read it
955 */
956 for (; count && (n = read_data(size, ichar, count, &u.c));
957 count -= n) {
958 *data_offset += n * size;
959 }
960 break;
961 }
962 if (p->u.iospec.reg_no)
963 count_reg[p->u.iospec.reg_no] = lastv;
964 else
965 count_reg['#'] = lastv;
966 break;
967 default:
968 viz_numeric(count, p->u.iospec.size,
969 p->u.iospec.ichar, p->u.iospec.ochar,
970 p->u.iospec.fmt, (int) p->u.iospec.reg_no);
971 break;
972 }
973 break;
974 case T_LISTHEAD:
975 for (i=0; i < count && !out_of_size; i++)
976 viz(p->u.sublist, i+1);
977 /* Re-load $( with iteration count for this level; was overwritten
978 * by recursive call to viz().
979 */
980 count_reg[(int) '('] = iteration;
981 break;
982 case T_COPYOUT:
983 {
984
985 if (show_type)
986 do_newline();
987 for (i=0; i < count; i++) {
988 char s[1000];
989 viz_decode(p->u.copyout, 'a', s);
990 OUTPUTSTR(s);
991 if (show_type)
992 OUTPUTSTR("\t");
993 }
994 }
995 break;
996 case T_SEEK:
997 {
998 int whence;
999 if (p->u.seek.direction < 0 && p->u.seek.direction >= -255)
1000 whence = count_reg[-p->u.seek.direction];
1001 else
1002 whence = p->u.seek.direction;
1003 seek_data(1, p->u.seek.count, whence);
1004 }
1005 break;
1006 case T_NEWLINE:
1007 /* Put out n-1 newlines; then use do_newline to get the
1008 * final newline out.
1009 */
1010 for (i=1; i < count; i++)
1011 putchar('\n');
1012 do_newline();
1013 break;
1014 case T_MATH:
1015 /* Do math on register */
1016 n = p->u.math.operand;
1017 if (n == UPTO_EOF)
1018 n = iteration;
1019 else if (n < 0)
1020 n = count_reg[-n];
1021
1022 for (i=0; i < count; i++) {
1023 switch (p->u.math.operator) {
1024 case '+':
1025 count_reg[p->u.math.reg_no] += n;
1026 break;
1027 case '-':
1028 count_reg[p->u.math.reg_no] -= n;
1029 break;
1030 case '*':
1031 count_reg[p->u.math.reg_no] *= n;
1032 break;
1033 case '/':
1034 count_reg[p->u.math.reg_no] /= n;
1035 break;
1036 case '%':
1037 count_reg[p->u.math.reg_no] %= n;
1038 break;
1039 case '=':
1040 count_reg[p->u.math.reg_no] = n;
1041 break;
1042 case 'P':
1043 /* Special case: null operator, w/ side effect of
1044 * printing register.
1045 */
1046 {
1047 char buf[100];
1048 (void) sprintf(buf, "%ld ", count_reg[p->u.math.reg_no]);
1049 OUTPUTSTR(buf);
1050 }
1051 break;
1052 default:
1053 (void) fprintf(stderr,
1054 "%s: unknown math operator `%c' in viz().\n",
1055 prog, p->u.math.operator);
1056 exit(1);
1057 }
1058 }
1059 /***
1060 (void) fprintf(stderr, "data_offset = %d Register %c = %d\n",
1061 *data_offset, p->u.math.reg_no, count_reg[p->u.math.reg_no]);
1062 ***/
1063 break;
1064 default:
1065 (void) fprintf(stderr, "%s: unknown member type %d in viz().\n",
1066 prog, p->type);
1067 exit(1);
1068 break;
1069 }
1070 }
1071 }
1072
1073 void
viz_text(count,size,ichar,fmt,reg_no)1074 viz_text(count, size, ichar, fmt, reg_no)
1075 long count; /* negative counts process data forever */
1076 int size;
1077 int ichar;
1078 char *fmt;
1079 int reg_no;
1080 {
1081 int n;
1082 register int i;
1083 register unsigned char c;
1084 register ALLTYPE u;
1085 register l;
1086 register last_was_backslash_0=0;
1087 ALLTYPE t;
1088
1089 char item_buf[1000]; /* output buffer for each non-ascii item */
1090
1091 set_mode('a');
1092
1093 if (fmt != NULL) {
1094 /* User-assigned format */
1095 for (; count && adj_count(count) &&
1096 (n = read_data(size, ichar, count, (char **) &t.uc));
1097 ichar == 'Z' ? count-- : (count -= n)) {
1098 if (ichar == 'Z') {
1099 /* Treat it as a string */
1100 (void) sprintf(item_buf, fmt, t.c);
1101 l = strlen(item_buf);
1102 need(l);
1103 line.avail -= l;
1104 (void) puts(item_buf);
1105 *data_offset += n;
1106 } else {
1107 /* Treat it as a bunch of characters */
1108 u.uc = t.uc;
1109 for (i = n; i != 0; --i, (*data_offset)++ ) {
1110 (void) sprintf(item_buf, fmt, *u.uc++);
1111 l = strlen(item_buf);
1112 need(l);
1113 line.avail -= l;
1114 (void) puts(item_buf);
1115 }
1116 }
1117 }
1118
1119 } else {
1120 /* Use built-in rules for outputting data */
1121
1122 for (; count && adj_count(count) &&
1123 (n = read_data(size, ichar, count, (char **) &t.uc));
1124 ichar == 'Z' ? count-- : (count -= n)) {
1125 u.uc = t.uc;
1126 for (i = n; i != 0; --i, (*data_offset)++ ) {
1127 c = *u.uc++;
1128 if (isascii(c) && isprint(c)) {
1129 if (c == '\\' || c == '^') {
1130 need(2);
1131 (void) putchar('\\');
1132 (void) putchar(c);
1133 line.avail -= 2;
1134 last_was_backslash_0 = 0;
1135 } else {
1136 if (last_was_backslash_0 && isdigit(c)) {
1137 /* Start newline to distinguish "\03" from "\0" "3" */
1138 do_newline();
1139 }
1140 need(1);
1141 (void) putchar(c);
1142 line.avail--;
1143 last_was_backslash_0 = 0;
1144 }
1145 } else {
1146 /* Non-printing. N.B. Can't take the common putchar('\\')
1147 * lines out to the top, because if we print a '\\', and then
1148 * find we really need four characters, it's too late to
1149 * take back the already-printed backslash.
1150 */
1151 need(2);
1152 last_was_backslash_0 = 0;
1153 switch (c) {
1154 case '\0':
1155 (void) putchar('\\');
1156 (void) putchar('0');
1157 last_was_backslash_0 = 1;
1158 line.avail -= 2;
1159 break;
1160 #ifdef __STDC__
1161 case '\a':
1162 (void) putchar('\\');
1163 (void) putchar('a');
1164 line.avail -= 2;
1165 break;
1166 #endif
1167 case '\b':
1168 (void) putchar('\\');
1169 (void) putchar('b');
1170 line.avail -= 2;
1171 break;
1172 case '\f':
1173 (void) putchar('\\');
1174 (void) putchar('f');
1175 line.avail -= 2;
1176 break;
1177 case '\n':
1178 (void) putchar('\\');
1179 (void) putchar('n');
1180 line.avail -= 2;
1181 (*data_offset)++;
1182 do_newline();
1183 set_mode('a');
1184 (*data_offset)--;
1185 break;
1186 case '\r':
1187 (void) putchar('\\');
1188 (void) putchar('r');
1189 line.avail -= 2;
1190 break;
1191 case '\t':
1192 (void) putchar('\\');
1193 (void) putchar('t');
1194 line.avail -= 2;
1195 break;
1196 #ifdef __STDC__
1197 case '\v':
1198 (void) putchar('\\');
1199 (void) putchar('v');
1200 line.avail -= 2;
1201 break;
1202 #endif
1203 default:
1204 #ifndef EBCDIC
1205 if (c <= ' ') {
1206 (void) putchar('^');
1207 (void) putchar(c + 'A' - 1);
1208 line.avail -= 2;
1209 break;
1210 } else
1211 #endif
1212 {
1213 need(4);
1214 (void) sprintf(item_buf, "\\%3.3o", (int) c);
1215 (void) fputs(item_buf, stdout);
1216 line.avail -= 4;
1217 }
1218 break;
1219 }
1220 }
1221 }
1222 }
1223 } /* endif (fmt == NULL) */
1224
1225 /* Store the count away. */
1226 count_reg[reg_no ? reg_no : '#'] = (ichar != 'Z') ? (long) c : n;
1227 }
1228
1229 void
viz_numeric(count,size,ichar,ochar,fmt,reg_no)1230 viz_numeric(count, size, ichar, ochar, fmt, reg_no)
1231 long count; /* negative counts process data forever */
1232 int size;
1233 int ichar;
1234 int ochar;
1235 char *fmt;
1236 int reg_no;
1237 {
1238 register int i;
1239 int n;
1240 ALLTYPE u;
1241 long lastv;
1242
1243 char item_buf[100]; /* output buffer for each item */
1244
1245 if (ochar == 'c')
1246 set_mode('c');
1247 else
1248 set_mode(ichar);
1249
1250 switch (ichar) {
1251 case 'C':
1252 case 'Z':
1253 /* chars */
1254 if (ochar == 'c') {
1255 for (; count && adj_count(count) &&
1256 (n=read_data(size, ichar, count, (char **) &u.uc));
1257 ichar == 'Z' ? count-- : (count -= n)) {
1258
1259 for (i = n; i != 0; i--, (*data_offset)++) {
1260 if (isprint(*u.uc) && !isspace(*u.uc)) {
1261 (void) sprintf(item_buf, " %c ", (int) *u.uc++);
1262 } else if (*u.uc == '\0') {
1263 (void) sprintf(item_buf, " \\0 ", (int) *u.uc++);
1264 } else {
1265 (void) sprintf(item_buf, "\\%3.3o ", (int) *u.uc++);
1266 }
1267 OUTPUTSTR(item_buf);
1268 }
1269 }
1270 if (ichar != 'Z')
1271 lastv = (long) *(u.uc - 1);
1272 else
1273 lastv = n;
1274
1275 } else if (ochar == 'b') {
1276 /* print in binary */
1277 for (; count && adj_count(count) &&
1278 (n = read_data(size, ichar, count, &u.uc));
1279 ichar == 'Z' ? count-- : (count -= n)) {
1280 for (i = n; i != 0; i--, (*data_offset)++) {
1281 /* register unsigned uc = *u.uc++;
1282 fprintf(stderr, "uc = %d\n", uc);
1283 */
1284 (void) sprintf(item_buf, fmt, binary[*u.uc++]);
1285 OUTPUTSTR(item_buf);
1286 }
1287 }
1288 if (ichar != 'Z')
1289 lastv = (long) *(u.uc - 1);
1290 else
1291 lastv = n;
1292
1293 } else if (ochar == 'd') {
1294 /* plain char */
1295 for (; count && adj_count(count) &&
1296 (n = read_data(size, ichar, count, &u.c));
1297 ichar == 'Z' ? count-- : (count -= n)) {
1298 for (i = n; i != 0; i--, (*data_offset)++) {
1299 (void) sprintf(item_buf, fmt, (int) *u.c++);
1300 OUTPUTSTR(item_buf);
1301 }
1302 }
1303 if (ichar != 'Z')
1304 lastv = (long) *(u.c - 1);
1305 else
1306 lastv = n;
1307
1308 } else {
1309 /* unsigned char */
1310 for (;count && adj_count(count) &&
1311 (n = read_data(size, ichar, count, (char **) &u.uc));
1312 ichar == 'Z' ? count-- : (count -= n)) {
1313 for (i = n; i != 0; i--, (*data_offset)++) {
1314 (void) sprintf(item_buf, fmt, (unsigned int) *u.uc++);
1315 OUTPUTSTR(item_buf);
1316 }
1317 }
1318 if (ichar != 'Z')
1319 lastv = (long) *(u.uc - 1);
1320 else
1321 lastv = n;
1322 }
1323 break;
1324 case 'S':
1325 /* shorts */
1326 if (ochar == 'd') {
1327 /* signed short */
1328 for (; count && adj_count(count) &&
1329 (n = read_data(size, ichar, count, (char **) &u.s));
1330 count -= n) {
1331 for (i = n; i != 0; i--, *data_offset += sizeof(short)) {
1332 (void) sprintf(item_buf, fmt, (int) *u.s++);
1333 OUTPUTSTR(item_buf);
1334 }
1335 }
1336 lastv = (long) *(u.s - 1);
1337
1338 } else if (ochar == 'b') {
1339 /* output in binary representation */
1340 for (; count && adj_count(count) &&
1341 (n = read_data(size, ichar, count, &u.c));
1342 count -= n) {
1343 for (i = n; i != 0; i--, *data_offset += sizeof(short)) {
1344 register unsigned short us = *u.us++;
1345 (void) sprintf(item_buf, fmt
1346 #if (L_SHORT > 7)
1347 , binary[(us >> 56) & 0377]
1348 #endif
1349 #if (L_SHORT > 6)
1350 , binary[(us >> 48) & 0377]
1351 #endif
1352 #if (L_SHORT > 5)
1353 , binary[(us >> 40) & 0377]
1354 #endif
1355 #if (L_SHORT > 4)
1356 , binary[(us >> 32) & 0377]
1357 #endif
1358 #if (L_SHORT > 3)
1359 , binary[(us >> 24) & 0377]
1360 #endif
1361 #if (L_SHORT > 2)
1362 , binary[(us >> 16) & 0377]
1363 #endif
1364 , binary[(us >> 8) & 0377]
1365 , binary[us & 0377]
1366 );
1367 OUTPUTSTR(item_buf);
1368 }
1369 }
1370 lastv = (long) *(u.us - 1);
1371
1372 } else {
1373 /* unsigned short */
1374 for (;count && adj_count(count) &&
1375 (n = read_data(size, ichar, count, (char **) &u.us));
1376 count -= n) {
1377 for (i=n; i != 0; i--, *data_offset += sizeof(unsigned short)) {
1378 (void) sprintf(item_buf, fmt, (unsigned int) *u.us++);
1379 OUTPUTSTR(item_buf);
1380 }
1381 }
1382 lastv = (long) *(u.us - 1);
1383 }
1384 break;
1385 case 'I':
1386 /* ints */
1387 if (ochar == 'd') {
1388 /* signed int */
1389 for (;count && adj_count(count) &&
1390 (n = read_data(size, ichar, count, (char **) &u.i));
1391 count -= n) {
1392 for (i = n; i != 0; i--, *data_offset += sizeof(int)) {
1393 (void) sprintf(item_buf, fmt, *u.i++);
1394 OUTPUTSTR(item_buf);
1395 }
1396 }
1397 lastv = (long) *(u.i - 1);
1398
1399 } else if (ochar == 'b') {
1400 /* output in binary representation */
1401 for (; count && adj_count(count) &&
1402 (n = read_data(size, ichar, count, &u.c));
1403 count -= n) {
1404 for (i = n; i != 0; i--, *data_offset += sizeof(int)) {
1405 register unsigned int ui = *u.ui++;
1406 (void) sprintf(item_buf, fmt
1407 #if (L_INT > 7)
1408 , binary[(ui >> 56) & 0377]
1409 #endif
1410 #if (L_INT > 6)
1411 , binary[(ui >> 48) & 0377]
1412 #endif
1413 #if (L_INT > 5)
1414 , binary[(ui >> 40) & 0377]
1415 #endif
1416 #if (L_INT > 4)
1417 , binary[(ui >> 32) & 0377]
1418 #endif
1419 #if (L_INT > 3)
1420 , binary[(ui >> 24) & 0377]
1421 #endif
1422 #if (L_INT > 2)
1423 , binary[(ui >> 16) & 0377]
1424 #endif
1425 , binary[(ui >> 8) & 0377]
1426 , binary[ui & 0377]
1427 );
1428 OUTPUTSTR(item_buf);
1429 }
1430 }
1431 lastv = (long) *(u.i - 1);
1432
1433 } else {
1434 /* unsigned int */
1435 for (;count && adj_count(count) &&
1436 (n = read_data(size, ichar, count, (char **) &u.ui));
1437 count -= n) {
1438 for (i = n; i != 0; i--, *data_offset += sizeof(unsigned int)) {
1439 (void) sprintf(item_buf, fmt, *u.ui++);
1440 OUTPUTSTR(item_buf);
1441 }
1442 }
1443 lastv = (long) *(u.ui - 1);
1444 }
1445 break;
1446 case 'L':
1447 /* longs */
1448 if (ochar == 'd') {
1449 /* signed long */
1450 for (;count && adj_count(count) &&
1451 (n = read_data(size, ichar, count, (char **) &u.l));
1452 count -= n) {
1453 for (i = n; i != 0; i--, *data_offset += sizeof(long)) {
1454 (void) sprintf(item_buf, fmt, *u.l++);
1455 OUTPUTSTR(item_buf);
1456 }
1457 }
1458 lastv = *(u.l - 1);
1459
1460 } else if (ochar == 'b') {
1461 /* output in binary representation */
1462 for (; count && adj_count(count) &&
1463 (n = read_data(size, ichar, count, &u.c));
1464 count -= n) {
1465 for (i = n; i != 0; i--, *data_offset += sizeof(long)) {
1466 register unsigned int ul = *u.ul++;
1467 (void) sprintf(item_buf, fmt
1468 #if (L_LONG > 7)
1469 , binary[(ul >> 56) & 0377]
1470 #endif
1471 #if (L_LONG > 6)
1472 , binary[(ul >> 48) & 0377]
1473 #endif
1474 #if (L_LONG > 5)
1475 , binary[(ul >> 40) & 0377]
1476 #endif
1477 #if (L_LONG > 4)
1478 , binary[(ul >> 32) & 0377]
1479 #endif
1480 #if (L_LONG > 3)
1481 , binary[(ul >> 24) & 0377]
1482 #endif
1483 #if (L_LONG > 2)
1484 , binary[(ul >> 16) & 0377]
1485 #endif
1486 , binary[(ul >> 8) & 0377]
1487 , binary[ul & 0377]
1488 );
1489 OUTPUTSTR(item_buf);
1490 }
1491 }
1492 lastv = (long) *(u.ul - 1);
1493
1494 } else {
1495 /* unsigned long */
1496 for (;count && adj_count(count) &&
1497 (n = read_data(size, ichar, count, (char **) &u.ul));
1498 count -= n) {
1499 for (i = n; i != 0; i--, *data_offset += sizeof(unsigned long)) {
1500 (void) sprintf(item_buf, fmt, *u.ul++);
1501 OUTPUTSTR(item_buf);
1502 }
1503 }
1504 lastv = (long) *(u.ul - 1);
1505 }
1506 break;
1507 /* NOTREACHED */
1508 break;
1509 case 'F':
1510 /* floats */
1511 for (; count && adj_count(count) &&
1512 (n = read_data(size, ichar, count, (char **) &u.f));
1513 count -= n) {
1514 for (i = n; i != 0; i--, *data_offset += sizeof(float)) {
1515 (void) sprintf(item_buf, fmt, *u.f++);
1516 OUTPUTSTR(item_buf);
1517 }
1518 }
1519 lastv = 0;
1520 break;
1521 case 'D':
1522 /* doubles */
1523 for (; count && adj_count(count) &&
1524 (n = read_data(size, ichar, count, (char **) &u.d));
1525 count -= n) {
1526 for (i = n; i != 0; i--, *data_offset += sizeof(double)) {
1527 (void) sprintf(item_buf, fmt, *u.d++);
1528 OUTPUTSTR(item_buf);
1529 }
1530 }
1531 lastv = 0;
1532 break;
1533 default:
1534 (void) fprintf(stderr,
1535 "%s: ichar = `%c', ochar = `%c' in viz_numeric()!\n",
1536 prog, ichar, ochar);
1537 exit(1);
1538 break;
1539 }
1540 count_reg[reg_no ? reg_no : '#'] = lastv;
1541 }
1542