3 * dumpscan - routines for scanning and manipulating AFS volume dumps
5 * Copyright (c) 1998 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
29 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
43 static char spbuf
[SPBUFLEN
+ 1] = "";
48 /* Generate an ASCII representation of an integer <val>, as follows:
49 * <base> indicates the base to be used (2-36)
50 * <uc> is nonzero if letter digits should be uppercase
51 * <prec> is the minimum number of digits
52 * The resulting number is stored in <buf>, which must be long enough
53 * to receive it. The minimum length is <prec> or ceil(log{base}(val)),
54 * whichever is larger, plus room for a trailing NUL.
57 mkint(char *buf
, unsigned long val
, int base
, int uc
, int prec
)
63 val
= (val
- dig
) / base
;
74 for (i
= 0; i
< (len
+ 1) / 2; i
++) {
76 buf
[i
] = buf
[len
- i
- 1];
77 buf
[len
- i
- 1] = dig
;
83 /* Write spaces faster than one at a time */
85 wsp(XFILE
* X
, int count
)
92 for (x
= spbuf
, i
= SPBUFLEN
; i
; x
++, i
--)
96 while (count
> SPBUFLEN
) {
97 err
= xfwrite(X
, spbuf
, SPBUFLEN
);
103 return xfwrite(X
, spbuf
, count
);
108 /* This function is a mostly-complete implementation of snprintf,
109 * with the following features:
111 * - Actually obeys the length limit, which (unfortunately) many
112 * implementations of snprintf do not.
114 * - Supports all the standard format specifiers for integers
115 * (d, i, o, u, x, X), floating-point values (f, e, E, g, G),
116 * and strings and characters (c, s, %), plus a few unusual
117 * but useful ones described below.
119 * - Supports all the standard flags (-, 0, +, space, #). These
120 * flags are ignored if used when they are not appropriate.
122 * - Supports the standard size modifiers for short (h), long (h),
123 * and double (L) arguments. These modifiers are ignored if used
124 * when they are not appropriate.
126 * - Supports minimum field width and precision, where appropriate,
127 * including the use of '*' to specify a value given as an argument
128 * instead of in the format string. There is a maximum precision
131 * - At present, the 'p' specifier for printing pointers is not
132 * implemented, because it is inherently non-portable and thus
133 * can be implemented correctly only by the compiler's run-time
136 * - Floating-point specifier (%e, %f, %g) are implemented by
137 * calling the standard sprintf, and thus may be unsafe.
139 * - The '%...$' notation is used primarily when the format string
140 * is specified by the user, who knows but cannot change the order
141 * of the arguments. Such usage is inherently dangerous and
142 * insecure; thus, it is not supported.
144 * The custom format specifier '%I' is supported. This specifier
145 * takes as its argument an unsigned long integer containing an
146 * IPv4 address in network byte order. The address is rendered
147 * either as a hostname or as a dotted quad, as follows:
149 * - If precision is nonzero or unspecified, a hostname lookup
150 * is attempted; if it is successful, the hostname is printed.
151 * If the hostname lookup fails, the address is printed in
152 * dotted-quad notation.
154 * - If precision is explicitly specified as 0, then the hostname
155 * lookup is skipped, and dotted-quad notation is always used.
157 * - If a hostname is to be printed:
158 * + The precision controls the maximum number of characters
159 * printed, as with %s.
160 * + If the '#' flag is specified, any letters in the hostname
161 * will be forced to lower case before printing.
162 * + If the '+' flag is specified, any letters in the hostname
163 * will be forced to upper case before printing. If both
164 * '#' and '+' are given, the '+' flag will be ignored.
165 * + The '0' and ' ' flags have no effect.
167 * - If a dotted quad is to be printed:
168 * + The precision has no effect; dotted quads are always
169 * 7 to 12 characters in length, depending on the value
170 * to be printed and the format flags used.
171 * + If the '0' flag is given, each field (byte) of the address
172 * will be padded with '0' on the left to three digits.
173 * + If the ' ' flag is given, each field (byte) of the address
174 * will be padded with spaces on the left to three digits. If
175 * both '0' and ' ' are given, the ' ' flag will be ignored.
176 * + The '#' and '+' flags have no effect.
180 vxfprintf(XFILE
* X
, char *fmt
, va_list ap
)
182 unsigned int width
, precision
, haveprec
, len
;
183 int ljust
, plsign
, spsign
, altform
, zfill
;
184 int hflag
, lflag
, count
, *countp
, j
;
185 char *x
, *y
, *lit
= 0, xbuf
[MAXPREC
+ 21], fbuf
[20];
204 if ((err
= xfwrite(X
, lit
, fmt
- lit
)))
209 /** Found a format specifier **/
210 ljust
= plsign
= spsign
= altform
= zfill
= 0;
211 width
= precision
= haveprec
= 0;
215 /* parse format flags */
221 continue; /* left justify */
225 continue; /* use + or - */
229 continue; /* use space or - */
233 continue; /* alternate form */
237 continue; /* pad with 0 */
244 /* parse minimum width */
246 width
= va_arg(ap
, int);
249 while (isdigit(*fmt
)) {
250 width
= (width
* 10) + (*fmt
- '0');
254 /* parse precision */
259 precision
= va_arg(ap
, int);
262 while (isdigit(*fmt
)) {
263 precision
= (precision
* 10) + (*fmt
- '0');
268 /* parse size flags */
274 continue; /* short argument */
278 continue; /* long argument */
285 /* parse format specifier */
294 FVAL
= va_arg(ap
, double);
295 sprintf(fbuf
, "%%%s%s.*L%c", plsign
? "+" : (spsign
? " " : ""),
296 altform
? "#" : "", fmt
[-1]);
299 if (precision
> MAXPREC
)
301 sprintf(xbuf
, fbuf
, precision
, FVAL
);
307 case 'd': /* signed decimal integer */
309 SVAL
= va_arg(ap
, long);
311 SVAL
= va_arg(ap
, int);
313 SVAL
= va_arg(ap
, int);
314 UVAL
= (SVAL
< 0) ? -SVAL
: SVAL
;
327 precision
= width
- !!xbuf
[0];
330 if (precision
< 1 + !!xbuf
[0])
331 precision
= 1 + !!xbuf
[0];
333 if (precision
> MAXPREC
)
336 mkint(xbuf
+ 1, UVAL
, 10, 0, precision
);
342 case 'o': /* unsigned octal integer */
344 UVAL
= va_arg(ap
, unsigned long);
346 UVAL
= va_arg(ap
, unsigned int);
348 UVAL
= va_arg(ap
, unsigned int);
358 if (precision
> MAXPREC
)
361 mkint(xbuf
+ 1, UVAL
, 8, 0, precision
);
362 x
= xbuf
+ (xbuf
[1] == '0' || !altform
);
366 case 'u': /* unsigned decimal integer */
368 UVAL
= va_arg(ap
, unsigned long);
370 UVAL
= va_arg(ap
, unsigned int);
372 UVAL
= va_arg(ap
, unsigned int);
380 if (precision
> MAXPREC
)
383 mkint(xbuf
, UVAL
, 10, 0, precision
);
389 case 'X': /* unsigned hexadecimal integer */
391 UVAL
= va_arg(ap
, unsigned long);
393 UVAL
= va_arg(ap
, unsigned int);
395 UVAL
= va_arg(ap
, unsigned int);
406 if (precision
> MAXPREC
)
409 mkint(xbuf
+ 2, UVAL
, 16, 0, precision
);
410 x
= xbuf
+ ((altform
&& UVAL
) ? 0 : 2);
414 case '%': /* literal % */
421 case 'c': /* character */
422 xbuf
[0] = va_arg(ap
, int);
428 case 's': /* string */
429 x
= va_arg(ap
, char *);
433 if (haveprec
&& precision
< len
)
437 case 'I': /* IP address:
438 * value is provided as a network-order unsigned long integer
439 * precision specifies max hostname length, as for %s
440 * if precision is explicitly 0, no hostname lookup is done
441 * if 0fill specified, IPaddr fields are 0-filled to 3 digits
442 * if spsign specified, IPaddr fields are space-filled to 3 digits
444 UVAL
= va_arg(ap
, unsigned long);
446 /* XXX: add support for an application-provided function
447 * for doing hostname lookups. We don't do it automatically
448 * because on some platforms that would prevent us from
449 * being fully statically linked.
451 if (haveprec
&& !precision
)
454 he
= gethostbyaddr((char *)&ia
, 4, AF_INET
);
458 if (haveprec
&& precision
< len
)
472 x
= "%03u.%03u.%03u.%03u";
474 x
= "%3u.%3u.%3u.%3u";
477 sprintf(xbuf
, x
, (UVAL
& 0xff000000) >> 24,
478 (UVAL
& 0x00ff0000) >> 16, (UVAL
& 0x0000ff00) >> 8,
479 (UVAL
& 0x000000ff));
485 case 'n': /* report count so far */
487 lcountp
= va_arg(ap
, long *);
490 hcountp
= va_arg(ap
, short *);
493 countp
= va_arg(ap
, int *);
498 default: /* unknown specifier */
502 /* render the results */
510 if (!ljust
&& (err
= wsp(X
, j
)))
512 if ((err
= xfwrite(X
, x
, len
)))
514 if (ljust
&& (err
= wsp(X
, j
)))
517 if (lit
&& (err
= xfwrite(X
, lit
, fmt
- lit
)))
524 xfprintf(XFILE
* X
, char *fmt
, ...)
530 err
= vxfprintf(X
, fmt
, ap
);