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