Home | History | Annotate | Line # | Download | only in stat
stat.c revision 1.2
      1  1.2  atatat /*	$NetBSD: stat.c,v 1.2 2002/05/09 17:52:03 atatat Exp $ */
      2  1.1  atatat 
      3  1.1  atatat /*
      4  1.1  atatat  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  1.1  atatat  * All rights reserved.
      6  1.1  atatat  *
      7  1.1  atatat  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  atatat  * by Andrew Brown.
      9  1.1  atatat  *
     10  1.1  atatat  * Redistribution and use in source and binary forms, with or without
     11  1.1  atatat  * modification, are permitted provided that the following conditions
     12  1.1  atatat  * are met:
     13  1.1  atatat  * 1. Redistributions of source code must retain the above copyright
     14  1.1  atatat  *    notice, this list of conditions and the following disclaimer.
     15  1.1  atatat  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  atatat  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  atatat  *    documentation and/or other materials provided with the distribution.
     18  1.1  atatat  * 3. All advertising materials mentioning features or use of this software
     19  1.1  atatat  *    must display the following acknowledgement:
     20  1.1  atatat  *      This product includes software developed by the NetBSD
     21  1.1  atatat  *      Foundation, Inc. and its contributors.
     22  1.1  atatat  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.1  atatat  *    contributors may be used to endorse or promote products derived
     24  1.1  atatat  *    from this software without specific prior written permission.
     25  1.1  atatat  *
     26  1.1  atatat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.1  atatat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.1  atatat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.1  atatat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.1  atatat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.1  atatat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.1  atatat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.1  atatat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.1  atatat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.1  atatat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.1  atatat  * POSSIBILITY OF SUCH DAMAGE.
     37  1.1  atatat  */
     38  1.1  atatat 
     39  1.1  atatat #include <sys/cdefs.h>
     40  1.1  atatat #ifndef lint
     41  1.2  atatat __RCSID("$NetBSD: stat.c,v 1.2 2002/05/09 17:52:03 atatat Exp $");
     42  1.1  atatat #endif
     43  1.1  atatat 
     44  1.1  atatat #include <sys/types.h>
     45  1.1  atatat #include <sys/param.h>
     46  1.1  atatat #include <sys/stat.h>
     47  1.1  atatat #include <unistd.h>
     48  1.1  atatat #include <err.h>
     49  1.1  atatat #include <string.h>
     50  1.1  atatat #include <stdio.h>
     51  1.1  atatat #include <ctype.h>
     52  1.1  atatat #include <stddef.h>
     53  1.1  atatat #include <stdlib.h>
     54  1.1  atatat #include <pwd.h>
     55  1.1  atatat #include <grp.h>
     56  1.1  atatat 
     57  1.1  atatat #define DEF_FORMAT \
     58  1.1  atatat 	"%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" %k %b %N"
     59  1.1  atatat #define RAW_FORMAT	"%d %i %#p %l %u %g %r %z %a %m %c %k %b %N"
     60  1.1  atatat #define LS_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%SY"
     61  1.1  atatat #define LSF_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%T%SY"
     62  1.1  atatat #define SHELL_FORMAT \
     63  1.1  atatat 	"st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \
     64  1.1  atatat 	"st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \
     65  1.1  atatat 	"st_atimespec=%a st_mtimespec=%m st_ctimespec=%c " \
     66  1.1  atatat 	"st_blksize=%k st_blocks=%b"
     67  1.1  atatat #define LINUX_FORMAT \
     68  1.1  atatat 	"  File: \"%N\"%n" \
     69  1.1  atatat 	"  Size: %-11z  FileType: %HT%n" \
     70  1.1  atatat 	"  Mode: (%04OLp/%.10Sp)         Uid: (%5u/%8Su)  Gid: (%5g/%8Sg)%n" \
     71  1.1  atatat 	"Device: %Hd,%Ld   Inode: %i    Links: %l%n" \
     72  1.1  atatat 	"Access: %Sa%n" \
     73  1.1  atatat 	"Modify: %Sm%n" \
     74  1.1  atatat 	"Change: %Sc"
     75  1.1  atatat 
     76  1.1  atatat #define TIME_FORMAT	"%b %e %T %Y"
     77  1.1  atatat 
     78  1.2  atatat #define FLAG_POUND	0x01
     79  1.2  atatat #define FLAG_SPACE	0x02
     80  1.2  atatat #define FLAG_PLUS	0x04
     81  1.2  atatat #define FLAG_ZERO	0x08
     82  1.2  atatat #define FLAG_MINUS	0x10
     83  1.1  atatat 
     84  1.1  atatat /*
     85  1.2  atatat  * These format characters must all be unique, except the magic one.
     86  1.1  atatat  */
     87  1.2  atatat #define FMT_MAGIC	'%'
     88  1.2  atatat #define FMT_DOT		'.'
     89  1.2  atatat 
     90  1.1  atatat #define SIMPLE_NEWLINE	'n'
     91  1.1  atatat #define SIMPLE_TAB	't'
     92  1.1  atatat #define SIMPLE_PERCENT	'%'
     93  1.2  atatat #define SIMPLE_NUMBER	'@'
     94  1.2  atatat 
     95  1.2  atatat #define FMT_POUND	'#'
     96  1.2  atatat #define FMT_SPACE	' '
     97  1.2  atatat #define FMT_PLUS	'+'
     98  1.2  atatat #define FMT_ZERO	'0'
     99  1.2  atatat #define FMT_MINUS	'-'
    100  1.1  atatat 
    101  1.1  atatat #define FMT_DECIMAL 	'D'
    102  1.1  atatat #define FMT_OCTAL 	'O'
    103  1.1  atatat #define FMT_UNSIGNED 	'U'
    104  1.1  atatat #define FMT_HEX 	'X'
    105  1.1  atatat #define FMT_FLOAT 	'F'
    106  1.1  atatat #define FMT_STRING 	'S'
    107  1.1  atatat 
    108  1.1  atatat #define HIGH_PIECE	'H'
    109  1.1  atatat #define MIDDLE_PIECE	'M'
    110  1.1  atatat #define LOW_PIECE	'L'
    111  1.1  atatat 
    112  1.1  atatat #define SHOW_st_dev	'd'
    113  1.1  atatat #define SHOW_st_ino	'i'
    114  1.1  atatat #define SHOW_st_mode	'p'
    115  1.1  atatat #define SHOW_st_nlink	'l'
    116  1.1  atatat #define SHOW_st_uid	'u'
    117  1.1  atatat #define SHOW_st_gid	'g'
    118  1.1  atatat #define SHOW_st_rdev	'r'
    119  1.1  atatat #define SHOW_st_atime	'a'
    120  1.1  atatat #define SHOW_st_mtime	'm'
    121  1.1  atatat #define SHOW_st_ctime	'c'
    122  1.1  atatat #define SHOW_st_size	'z'
    123  1.1  atatat #define SHOW_st_blocks	'b'
    124  1.1  atatat #define SHOW_st_blksize	'k'
    125  1.1  atatat #define SHOW_st_flags	'f'
    126  1.1  atatat #define SHOW_st_gen	'v'
    127  1.1  atatat #define SHOW_symlink	'Y'
    128  1.1  atatat #define SHOW_filetype	'T'
    129  1.1  atatat #define SHOW_filename	'N'
    130  1.1  atatat #define SHOW_sizerdev	'Z'
    131  1.1  atatat 
    132  1.1  atatat void	usage(void);
    133  1.1  atatat void	output(const struct stat *, const char *,
    134  1.2  atatat 	    const char *, int, int);
    135  1.1  atatat int	format1(const struct stat *,	/* stat info */
    136  1.1  atatat 	    const char *,		/* the file name */
    137  1.1  atatat 	    const char *, int,		/* the format string itself */
    138  1.1  atatat 	    char *, size_t,		/* a place to put the output */
    139  1.1  atatat 	    int, int, int, int,		/* the parsed format */
    140  1.1  atatat 	    int, int);
    141  1.1  atatat 
    142  1.1  atatat char *timefmt;
    143  1.1  atatat 
    144  1.1  atatat #define addchar(b, n, l, c, nl) \
    145  1.1  atatat 	do { \
    146  1.1  atatat 		if ((*(n)) < (l)) { \
    147  1.1  atatat 			(b)[(*(n))++] = (c); \
    148  1.1  atatat 			(*nl) = ((c) == '\n'); \
    149  1.1  atatat 		} \
    150  1.1  atatat 	} while (0/*CONSTCOND*/)
    151  1.1  atatat 
    152  1.1  atatat int
    153  1.1  atatat main(int argc, char *argv[])
    154  1.1  atatat {
    155  1.1  atatat 	struct stat st;
    156  1.1  atatat 	int ch, rc, errs;
    157  1.2  atatat 	int lsF, fmtchar, usestat, fn, nonl;
    158  1.1  atatat 	char *statfmt;
    159  1.1  atatat 
    160  1.1  atatat 	lsF = 0;
    161  1.1  atatat 	fmtchar = '\0';
    162  1.1  atatat 	usestat = 0;
    163  1.1  atatat 	nonl = 0;
    164  1.1  atatat 	statfmt = NULL;
    165  1.1  atatat 	timefmt = NULL;
    166  1.1  atatat 
    167  1.1  atatat 	while ((ch = getopt(argc, argv, "f:FlLnrst:x")) != -1)
    168  1.1  atatat 		switch (ch) {
    169  1.1  atatat 		case 'F':
    170  1.1  atatat 			lsF = 1;
    171  1.1  atatat 			break;
    172  1.1  atatat 		case 'L':
    173  1.1  atatat 			usestat = 1;
    174  1.1  atatat 			break;
    175  1.1  atatat 		case 'n':
    176  1.1  atatat 			nonl = 1;
    177  1.1  atatat 			break;
    178  1.1  atatat 		case 'f':
    179  1.1  atatat 			statfmt = optarg;
    180  1.1  atatat 			/* FALLTHROUGH */
    181  1.1  atatat 		case 'l':
    182  1.1  atatat 		case 'r':
    183  1.1  atatat 		case 's':
    184  1.1  atatat 		case 'x':
    185  1.1  atatat 			if (fmtchar != 0)
    186  1.1  atatat 				errx(1, "can't use format '%c' with '%c'",
    187  1.1  atatat 				    fmtchar, ch);
    188  1.1  atatat 			fmtchar = ch;
    189  1.1  atatat 			break;
    190  1.1  atatat 		case 't':
    191  1.1  atatat 			timefmt = optarg;
    192  1.1  atatat 			break;
    193  1.1  atatat 		default:
    194  1.1  atatat 			usage();
    195  1.1  atatat 		}
    196  1.1  atatat 
    197  1.1  atatat 	argc -= optind;
    198  1.1  atatat 	argv += optind;
    199  1.2  atatat 	fn = 1;
    200  1.1  atatat 
    201  1.1  atatat 	if (fmtchar == '\0') {
    202  1.1  atatat 		if (lsF)
    203  1.1  atatat 			fmtchar = 'l';
    204  1.1  atatat 		else {
    205  1.1  atatat 			fmtchar = 'f';
    206  1.1  atatat 			statfmt = DEF_FORMAT;
    207  1.1  atatat 		}
    208  1.1  atatat 	}
    209  1.1  atatat 
    210  1.1  atatat 	if (lsF && fmtchar != 'l')
    211  1.1  atatat 		errx(1, "can't use format '%c' with -F", fmtchar);
    212  1.1  atatat 
    213  1.1  atatat 	switch (fmtchar) {
    214  1.1  atatat 	case 'f':
    215  1.1  atatat 		/* statfmt already set */
    216  1.1  atatat 		break;
    217  1.1  atatat 	case 'l':
    218  1.1  atatat 		statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
    219  1.1  atatat 		break;
    220  1.1  atatat 	case 'r':
    221  1.1  atatat 		statfmt = RAW_FORMAT;
    222  1.1  atatat 		break;
    223  1.1  atatat 	case 's':
    224  1.1  atatat 		statfmt = SHELL_FORMAT;
    225  1.1  atatat 		break;
    226  1.1  atatat 	case 'x':
    227  1.1  atatat 		statfmt = LINUX_FORMAT;
    228  1.1  atatat 		if (timefmt == NULL)
    229  1.1  atatat 			timefmt = "%c";
    230  1.1  atatat 		break;
    231  1.1  atatat 	default:
    232  1.1  atatat 		usage();
    233  1.1  atatat 		/*NOTREACHED*/
    234  1.1  atatat 	}
    235  1.1  atatat 
    236  1.1  atatat 	if (timefmt == NULL)
    237  1.1  atatat 		timefmt = TIME_FORMAT;
    238  1.1  atatat 
    239  1.1  atatat 	errs = 0;
    240  1.1  atatat 	do {
    241  1.1  atatat 		if (argc == 0)
    242  1.1  atatat 			rc = fstat(STDIN_FILENO, &st);
    243  1.1  atatat 		else if (usestat)
    244  1.1  atatat 			rc = stat(argv[0], &st);
    245  1.1  atatat 		else
    246  1.1  atatat 			rc = lstat(argv[0], &st);
    247  1.1  atatat 
    248  1.1  atatat 		if (rc == -1) {
    249  1.1  atatat 			errs = 1;
    250  1.1  atatat 			warn("%s: stat", argc == 0 ? "(stdin)" : argv[0]);
    251  1.1  atatat 		}
    252  1.1  atatat 		else
    253  1.2  atatat 			output(&st, argv[0], statfmt, fn, nonl);
    254  1.1  atatat 
    255  1.1  atatat 		argv++;
    256  1.1  atatat 		argc--;
    257  1.2  atatat 		fn++;
    258  1.1  atatat 	} while (argc > 0);
    259  1.1  atatat 
    260  1.1  atatat 	return (errs);
    261  1.1  atatat }
    262  1.1  atatat 
    263  1.1  atatat void
    264  1.1  atatat usage(void)
    265  1.1  atatat {
    266  1.1  atatat 
    267  1.1  atatat 	(void)fprintf(stderr,
    268  1.1  atatat 	    "usage: %s [-FlLnrsx] [-f format] [-t timefmt] [file ...]\n",
    269  1.1  atatat 	    getprogname());
    270  1.1  atatat 	exit(1);
    271  1.1  atatat }
    272  1.1  atatat 
    273  1.1  atatat /*
    274  1.1  atatat  * Parses a format string.
    275  1.1  atatat  */
    276  1.1  atatat void
    277  1.1  atatat output(const struct stat *st, const char *file,
    278  1.2  atatat     const char *statfmt, int fn, int nonl)
    279  1.1  atatat {
    280  1.1  atatat 	int flags, size, prec, ofmt, hilo, what;
    281  1.1  atatat 	char buf[4096], subbuf[MAXPATHLEN];
    282  1.1  atatat 	const char *subfmt;
    283  1.1  atatat 	int nl, t, i;
    284  1.1  atatat 	size_t len;
    285  1.1  atatat 
    286  1.1  atatat 	len = 0;
    287  1.1  atatat 	while (*statfmt != '\0') {
    288  1.1  atatat 
    289  1.1  atatat 		/*
    290  1.1  atatat 		 * Non-format characters go straight out.
    291  1.1  atatat 		 */
    292  1.2  atatat 		if (*statfmt != FMT_MAGIC) {
    293  1.1  atatat 			addchar(buf, &len, sizeof(buf), *statfmt, &nl);
    294  1.1  atatat 			statfmt++;
    295  1.1  atatat 			continue;
    296  1.1  atatat 		}
    297  1.1  atatat 
    298  1.1  atatat 		/*
    299  1.1  atatat 		 * The current format "substring" starts here,
    300  1.2  atatat 		 * and then we skip the magic.
    301  1.1  atatat 		 */
    302  1.1  atatat 		subfmt = statfmt;
    303  1.1  atatat 		statfmt++;
    304  1.1  atatat 
    305  1.1  atatat 		/*
    306  1.1  atatat 		 * Some simple one-character "formats".
    307  1.1  atatat 		 */
    308  1.1  atatat 		switch (*statfmt) {
    309  1.1  atatat 		case SIMPLE_NEWLINE:
    310  1.1  atatat 			addchar(buf, &len, sizeof(buf), '\n', &nl);
    311  1.1  atatat 			statfmt++;
    312  1.1  atatat 			continue;
    313  1.1  atatat 		case SIMPLE_TAB:
    314  1.1  atatat 			addchar(buf, &len, sizeof(buf), '\t', &nl);
    315  1.1  atatat 			statfmt++;
    316  1.1  atatat 			continue;
    317  1.1  atatat 		case SIMPLE_PERCENT:
    318  1.1  atatat 			addchar(buf, &len, sizeof(buf), '%', &nl);
    319  1.1  atatat 			statfmt++;
    320  1.1  atatat 			continue;
    321  1.2  atatat 		case SIMPLE_NUMBER: {
    322  1.2  atatat 			char num[12], *p;
    323  1.2  atatat 
    324  1.2  atatat 			snprintf(num, sizeof(num), "%d", fn);
    325  1.2  atatat 			for (p = &num[0]; *p; p++)
    326  1.2  atatat 				addchar(buf, &len, sizeof(buf), *p, &nl);
    327  1.2  atatat 			statfmt++;
    328  1.2  atatat 			continue;
    329  1.2  atatat 		}
    330  1.1  atatat 		}
    331  1.1  atatat 
    332  1.1  atatat 		/*
    333  1.1  atatat 		 * This must be an actual format string.  Format strings are
    334  1.1  atatat 		 * similar to printf(3) formats up to a point, and are of
    335  1.1  atatat 		 * the form:
    336  1.1  atatat 		 *
    337  1.1  atatat 		 *	%	required start of format
    338  1.1  atatat 		 *	[-# +0]	opt. format characters
    339  1.1  atatat 		 *	size	opt. field width
    340  1.1  atatat 		 *	.	opt. decimal separator, followed by
    341  1.1  atatat 		 *	prec	opt. precision
    342  1.1  atatat 		 *	fmt	opt. output specifier (string, numeric, etc.)
    343  1.1  atatat 		 *	sub	opt. sub field specifier (high, middle, low)
    344  1.1  atatat 		 *	datum	required field specifier (size, mode, etc)
    345  1.1  atatat 		 *
    346  1.1  atatat 		 * Only the % and the datum selector are required.  All data
    347  1.1  atatat 		 * have reasonable default output forms.  The "sub" specifier
    348  1.1  atatat 		 * only applies to certain data (mode, dev, rdev, filetype).
    349  1.1  atatat 		 * The symlink output defaults to STRING, yet will only emit
    350  1.1  atatat 		 * the leading " -> " if STRING is explicitly specified.  The
    351  1.1  atatat 		 * sizerdev datum will generate rdev output for character or
    352  1.1  atatat 		 * block devices, and size output for all others.
    353  1.1  atatat 		 */
    354  1.1  atatat 		flags = 0;
    355  1.1  atatat 		do {
    356  1.2  atatat 			if      (*statfmt == FMT_POUND)
    357  1.2  atatat 				flags |= FLAG_POUND;
    358  1.2  atatat 			else if (*statfmt == FMT_SPACE)
    359  1.2  atatat 				flags |= FLAG_SPACE;
    360  1.2  atatat 			else if (*statfmt == FMT_PLUS)
    361  1.2  atatat 				flags |= FLAG_PLUS;
    362  1.2  atatat 			else if (*statfmt == FMT_ZERO)
    363  1.2  atatat 				flags |= FLAG_ZERO;
    364  1.2  atatat 			else if (*statfmt == FMT_MINUS)
    365  1.2  atatat 				flags |= FLAG_MINUS;
    366  1.1  atatat 			else
    367  1.1  atatat 				break;
    368  1.1  atatat 			statfmt++;
    369  1.1  atatat 		} while (1/*CONSTCOND*/);
    370  1.1  atatat 
    371  1.1  atatat 		size = -1;
    372  1.1  atatat 		if (isdigit((unsigned)*statfmt)) {
    373  1.1  atatat 			size = 0;
    374  1.1  atatat 			while (isdigit((unsigned)*statfmt)) {
    375  1.1  atatat 				size = (size * 10) + (*statfmt - '0');
    376  1.1  atatat 				statfmt++;
    377  1.1  atatat 				if (size < 0)
    378  1.1  atatat 					goto badfmt;
    379  1.1  atatat 			}
    380  1.1  atatat 		}
    381  1.1  atatat 
    382  1.1  atatat 		prec = -1;
    383  1.2  atatat 		if (*statfmt == FMT_DOT) {
    384  1.1  atatat 			statfmt++;
    385  1.1  atatat 
    386  1.1  atatat 			prec = 0;
    387  1.1  atatat 			while (isdigit((unsigned)*statfmt)) {
    388  1.1  atatat 				prec = (prec * 10) + (*statfmt - '0');
    389  1.1  atatat 				statfmt++;
    390  1.1  atatat 				if (prec < 0)
    391  1.1  atatat 					goto badfmt;
    392  1.1  atatat 			}
    393  1.1  atatat 		}
    394  1.1  atatat 
    395  1.1  atatat #define fmtcase(x, y) case (y): (x) = (y); statfmt++; break
    396  1.1  atatat 		switch (*statfmt) {
    397  1.1  atatat 			fmtcase(ofmt, FMT_DECIMAL);
    398  1.1  atatat 			fmtcase(ofmt, FMT_OCTAL);
    399  1.1  atatat 			fmtcase(ofmt, FMT_UNSIGNED);
    400  1.1  atatat 			fmtcase(ofmt, FMT_HEX);
    401  1.1  atatat 			fmtcase(ofmt, FMT_FLOAT);
    402  1.1  atatat 			fmtcase(ofmt, FMT_STRING);
    403  1.1  atatat 		default:
    404  1.1  atatat 			ofmt = 0;
    405  1.1  atatat 			break;
    406  1.1  atatat 		}
    407  1.1  atatat 
    408  1.1  atatat 		switch (*statfmt) {
    409  1.1  atatat 			fmtcase(hilo, HIGH_PIECE);
    410  1.1  atatat 			fmtcase(hilo, MIDDLE_PIECE);
    411  1.1  atatat 			fmtcase(hilo, LOW_PIECE);
    412  1.1  atatat 		default:
    413  1.1  atatat 			hilo = 0;
    414  1.1  atatat 			break;
    415  1.1  atatat 		}
    416  1.1  atatat 
    417  1.1  atatat 		switch (*statfmt) {
    418  1.1  atatat 			fmtcase(what, SHOW_st_dev);
    419  1.1  atatat 			fmtcase(what, SHOW_st_ino);
    420  1.1  atatat 			fmtcase(what, SHOW_st_mode);
    421  1.1  atatat 			fmtcase(what, SHOW_st_nlink);
    422  1.1  atatat 			fmtcase(what, SHOW_st_uid);
    423  1.1  atatat 			fmtcase(what, SHOW_st_gid);
    424  1.1  atatat 			fmtcase(what, SHOW_st_rdev);
    425  1.1  atatat 			fmtcase(what, SHOW_st_atime);
    426  1.1  atatat 			fmtcase(what, SHOW_st_mtime);
    427  1.1  atatat 			fmtcase(what, SHOW_st_ctime);
    428  1.1  atatat 			fmtcase(what, SHOW_st_size);
    429  1.1  atatat 			fmtcase(what, SHOW_st_blocks);
    430  1.1  atatat 			fmtcase(what, SHOW_st_blksize);
    431  1.1  atatat 			fmtcase(what, SHOW_st_flags);
    432  1.1  atatat 			fmtcase(what, SHOW_st_gen);
    433  1.1  atatat 			fmtcase(what, SHOW_symlink);
    434  1.1  atatat 			fmtcase(what, SHOW_filetype);
    435  1.1  atatat 			fmtcase(what, SHOW_filename);
    436  1.1  atatat 			fmtcase(what, SHOW_sizerdev);
    437  1.1  atatat 		default:
    438  1.1  atatat 			goto badfmt;
    439  1.1  atatat 		}
    440  1.1  atatat #undef fmtcase
    441  1.1  atatat 
    442  1.1  atatat 		t = format1(st,
    443  1.1  atatat 		     file,
    444  1.1  atatat 		     subfmt, statfmt - subfmt,
    445  1.1  atatat 		     subbuf, sizeof(subbuf),
    446  1.1  atatat 		     flags, size, prec, ofmt, hilo, what);
    447  1.1  atatat 
    448  1.1  atatat 		for (i = 0; i < t && i < sizeof(subbuf); i++)
    449  1.1  atatat 			addchar(buf, &len, sizeof(buf), subbuf[i], &nl);
    450  1.1  atatat 
    451  1.1  atatat 		continue;
    452  1.1  atatat 
    453  1.1  atatat 	badfmt:
    454  1.1  atatat 		errx(1, "%.*s: bad format",
    455  1.1  atatat 		    (int)(statfmt - subfmt + 1), subfmt);
    456  1.1  atatat 	}
    457  1.1  atatat 
    458  1.1  atatat 	(void)write(STDOUT_FILENO, buf, len);
    459  1.1  atatat 	if (!nl && !nonl)
    460  1.2  atatat 		(void)write(STDOUT_FILENO, "\n", sizeof("\n") - 1);
    461  1.1  atatat }
    462  1.1  atatat 
    463  1.1  atatat /*
    464  1.1  atatat  * Arranges output according to a single parsed format substring.
    465  1.1  atatat  */
    466  1.1  atatat int
    467  1.1  atatat format1(const struct stat *st,
    468  1.1  atatat     const char *file,
    469  1.1  atatat     const char *fmt, int flen,
    470  1.1  atatat     char *buf, size_t blen,
    471  1.1  atatat     int flags, int size, int prec, int ofmt,
    472  1.1  atatat     int hilo, int what)
    473  1.1  atatat {
    474  1.1  atatat 	u_int64_t data;
    475  1.1  atatat 	char *sdata, lfmt[24], tmp[20];
    476  1.1  atatat 	char smode[12], sid[12], path[MAXPATHLEN + 4];
    477  1.1  atatat 	struct passwd *pw;
    478  1.1  atatat 	struct group *gr;
    479  1.1  atatat 	const struct timespec *tsp;
    480  1.1  atatat 	struct timespec ts;
    481  1.1  atatat 	struct tm *tm;
    482  1.1  atatat 	int l, small, formats;
    483  1.1  atatat 
    484  1.1  atatat 	tsp = NULL;
    485  1.1  atatat 	formats = 0;
    486  1.1  atatat 	small = 0;
    487  1.1  atatat 
    488  1.1  atatat 	/*
    489  1.1  atatat 	 * First, pick out the data and tweak it based on hilo or
    490  1.1  atatat 	 * specified output format (symlink output only).
    491  1.1  atatat 	 */
    492  1.1  atatat 	switch (what) {
    493  1.1  atatat 	case SHOW_st_dev:
    494  1.1  atatat 	case SHOW_st_rdev:
    495  1.1  atatat 		small = (sizeof(st->st_dev) == 4);
    496  1.1  atatat 		data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
    497  1.1  atatat 		sdata = (what == SHOW_st_dev) ?
    498  1.1  atatat 		    devname(st->st_dev, S_IFBLK) :
    499  1.1  atatat 		    devname(st->st_rdev,
    500  1.1  atatat 		    S_ISCHR(st->st_mode) ? S_IFCHR :
    501  1.1  atatat 		    S_ISBLK(st->st_mode) ? S_IFBLK :
    502  1.1  atatat 		    0U);
    503  1.1  atatat 		if (hilo == HIGH_PIECE) {
    504  1.1  atatat 			data = major(data);
    505  1.1  atatat 			hilo = 0;
    506  1.1  atatat 		}
    507  1.1  atatat 		else if (hilo == LOW_PIECE) {
    508  1.1  atatat 			data = minor((unsigned)data);
    509  1.1  atatat 			hilo = 0;
    510  1.1  atatat 		}
    511  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX |
    512  1.1  atatat 		    FMT_STRING;
    513  1.1  atatat 		if (ofmt == 0)
    514  1.1  atatat 			ofmt = FMT_UNSIGNED;
    515  1.1  atatat 		break;
    516  1.1  atatat 	case SHOW_st_ino:
    517  1.1  atatat 		small = (sizeof(st->st_ino) == 4);
    518  1.1  atatat 		data = st->st_ino;
    519  1.1  atatat 		sdata = NULL;
    520  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    521  1.1  atatat 		if (ofmt == 0)
    522  1.1  atatat 			ofmt = FMT_UNSIGNED;
    523  1.1  atatat 		break;
    524  1.1  atatat 	case SHOW_st_mode:
    525  1.1  atatat 		small = (sizeof(st->st_mode) == 4);
    526  1.1  atatat 		data = st->st_mode;
    527  1.1  atatat 		strmode(st->st_mode, smode);
    528  1.1  atatat 		sdata = smode;
    529  1.1  atatat 		l = strlen(sdata);
    530  1.1  atatat 		if (sdata[l - 1] == ' ')
    531  1.1  atatat 			sdata[--l] = '\0';
    532  1.1  atatat 		if (hilo == HIGH_PIECE) {
    533  1.1  atatat 			data >>= 12;
    534  1.1  atatat 			sdata += 1;
    535  1.1  atatat 			sdata[3] = '\0';
    536  1.1  atatat 			hilo = 0;
    537  1.1  atatat 		}
    538  1.1  atatat 		else if (hilo == MIDDLE_PIECE) {
    539  1.2  atatat 			data = (data >> 9) & 07;
    540  1.1  atatat 			sdata += 4;
    541  1.1  atatat 			sdata[3] = '\0';
    542  1.1  atatat 			hilo = 0;
    543  1.1  atatat 		}
    544  1.1  atatat 		else if (hilo == LOW_PIECE) {
    545  1.2  atatat 			data &= 0777;
    546  1.1  atatat 			sdata += 7;
    547  1.1  atatat 			sdata[3] = '\0';
    548  1.1  atatat 			hilo = 0;
    549  1.1  atatat 		}
    550  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX |
    551  1.1  atatat 		    FMT_STRING;
    552  1.1  atatat 		if (ofmt == 0)
    553  1.1  atatat 			ofmt = FMT_OCTAL;
    554  1.1  atatat 		break;
    555  1.1  atatat 	case SHOW_st_nlink:
    556  1.1  atatat 		small = (sizeof(st->st_dev) == 4);
    557  1.1  atatat 		data = st->st_nlink;
    558  1.1  atatat 		sdata = NULL;
    559  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    560  1.1  atatat 		if (ofmt == 0)
    561  1.1  atatat 			ofmt = FMT_UNSIGNED;
    562  1.1  atatat 		break;
    563  1.1  atatat 	case SHOW_st_uid:
    564  1.1  atatat 		small = (sizeof(st->st_uid) == 4);
    565  1.1  atatat 		data = st->st_uid;
    566  1.1  atatat 		if ((pw = getpwuid(st->st_uid)) != NULL)
    567  1.1  atatat 			sdata = pw->pw_name;
    568  1.1  atatat 		else {
    569  1.1  atatat 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);
    570  1.1  atatat 			sdata = sid;
    571  1.1  atatat 		}
    572  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX |
    573  1.1  atatat 		    FMT_STRING;
    574  1.1  atatat 		if (ofmt == 0)
    575  1.1  atatat 			ofmt = FMT_UNSIGNED;
    576  1.1  atatat 		break;
    577  1.1  atatat 	case SHOW_st_gid:
    578  1.1  atatat 		small = (sizeof(st->st_gid) == 4);
    579  1.1  atatat 		data = st->st_gid;
    580  1.1  atatat 		if ((gr = getgrgid(st->st_gid)) != NULL)
    581  1.1  atatat 			sdata = gr->gr_name;
    582  1.1  atatat 		else {
    583  1.1  atatat 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);
    584  1.1  atatat 			sdata = sid;
    585  1.1  atatat 		}
    586  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX |
    587  1.1  atatat 		    FMT_STRING;
    588  1.1  atatat 		if (ofmt == 0)
    589  1.1  atatat 			ofmt = FMT_UNSIGNED;
    590  1.1  atatat 		break;
    591  1.1  atatat 	case SHOW_st_atime:
    592  1.1  atatat 		tsp = &st->st_atimespec;
    593  1.1  atatat 		/* FALLTHROUGH */
    594  1.1  atatat 	case SHOW_st_mtime:
    595  1.1  atatat 		if (tsp == NULL)
    596  1.1  atatat 			tsp = &st->st_mtimespec;
    597  1.1  atatat 		/* FALLTHROUGH */
    598  1.1  atatat 	case SHOW_st_ctime:
    599  1.1  atatat 		if (tsp == NULL)
    600  1.1  atatat 			tsp = &st->st_ctimespec;
    601  1.1  atatat 		ts = *tsp;		/* copy so we can muck with it */
    602  1.1  atatat 		small = (sizeof(ts.tv_sec) == 4);
    603  1.1  atatat 		data = ts.tv_sec;
    604  1.1  atatat 		small = 1;
    605  1.1  atatat 		tm = localtime(&ts.tv_sec);
    606  1.1  atatat 		(void)strftime(path, sizeof(path), timefmt, tm);
    607  1.1  atatat 		sdata = path;
    608  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX |
    609  1.1  atatat 		    FMT_FLOAT | FMT_STRING;
    610  1.1  atatat 		if (ofmt == 0)
    611  1.1  atatat 			ofmt = FMT_DECIMAL;
    612  1.1  atatat 		break;
    613  1.1  atatat 	case SHOW_st_size:
    614  1.1  atatat 		small = (sizeof(st->st_size) == 4);
    615  1.1  atatat 		data = st->st_size;
    616  1.1  atatat 		sdata = NULL;
    617  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    618  1.1  atatat 		if (ofmt == 0)
    619  1.1  atatat 			ofmt = FMT_UNSIGNED;
    620  1.1  atatat 		break;
    621  1.1  atatat 	case SHOW_st_blocks:
    622  1.1  atatat 		small = (sizeof(st->st_blocks) == 4);
    623  1.1  atatat 		data = st->st_blocks;
    624  1.1  atatat 		sdata = NULL;
    625  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    626  1.1  atatat 		if (ofmt == 0)
    627  1.1  atatat 			ofmt = FMT_UNSIGNED;
    628  1.1  atatat 		break;
    629  1.1  atatat 	case SHOW_st_blksize:
    630  1.1  atatat 		small = (sizeof(st->st_blksize) == 4);
    631  1.1  atatat 		data = st->st_blksize;
    632  1.1  atatat 		sdata = NULL;
    633  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    634  1.1  atatat 		if (ofmt == 0)
    635  1.1  atatat 			ofmt = FMT_UNSIGNED;
    636  1.1  atatat 		break;
    637  1.1  atatat 	case SHOW_st_flags:
    638  1.1  atatat 		small = (sizeof(st->st_flags) == 4);
    639  1.1  atatat 		data = st->st_flags;
    640  1.1  atatat 		sdata = NULL;
    641  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    642  1.1  atatat 		if (ofmt == 0)
    643  1.1  atatat 			ofmt = FMT_UNSIGNED;
    644  1.1  atatat 		break;
    645  1.1  atatat 	case SHOW_st_gen:
    646  1.1  atatat 		small = (sizeof(st->st_gen) == 4);
    647  1.1  atatat 		data = st->st_gen;
    648  1.1  atatat 		sdata = NULL;
    649  1.1  atatat 		formats = FMT_DECIMAL | FMT_OCTAL | FMT_UNSIGNED | FMT_HEX;
    650  1.1  atatat 		if (ofmt == 0)
    651  1.1  atatat 			ofmt = FMT_UNSIGNED;
    652  1.1  atatat 		break;
    653  1.1  atatat 	case SHOW_symlink:
    654  1.1  atatat 		small = 0;
    655  1.1  atatat 		data = 0;
    656  1.1  atatat 		if (S_ISLNK(st->st_mode)) {
    657  1.1  atatat 			snprintf(path, sizeof(path), " -> ");
    658  1.1  atatat 			l = readlink(file, path + 4, sizeof(path) - 4);
    659  1.1  atatat 			if (l == -1) {
    660  1.1  atatat 				l = 0;
    661  1.1  atatat 				path[0] = '\0';
    662  1.1  atatat 			}
    663  1.1  atatat 			path[l + 4] = '\0';
    664  1.1  atatat 			sdata = path + (ofmt == FMT_STRING ? 0 : 4);
    665  1.1  atatat 		}
    666  1.1  atatat 		else
    667  1.1  atatat 			sdata = "";
    668  1.1  atatat 		formats = FMT_STRING;
    669  1.1  atatat 		if (ofmt == 0)
    670  1.1  atatat 			ofmt = FMT_STRING;
    671  1.1  atatat 		break;
    672  1.1  atatat 	case SHOW_filetype:
    673  1.1  atatat 		small = 0;
    674  1.1  atatat 		data = 0;
    675  1.1  atatat 		sdata = smode;
    676  1.1  atatat 		sdata[0] = '\0';
    677  1.1  atatat 		if (hilo == 0 || hilo == LOW_PIECE) {
    678  1.1  atatat 			switch (st->st_mode & S_IFMT) {
    679  1.1  atatat 			case S_IFIFO:	(void)strcat(sdata, "|");	break;
    680  1.1  atatat 			case S_IFDIR:	(void)strcat(sdata, "/");	break;
    681  1.1  atatat 			case S_IFREG:
    682  1.1  atatat 				if (st->st_mode &
    683  1.1  atatat 				    (S_IXUSR | S_IXGRP | S_IXOTH))
    684  1.1  atatat 					(void)strcat(sdata, "*");
    685  1.1  atatat 				break;
    686  1.1  atatat 			case S_IFLNK:	(void)strcat(sdata, "@");	break;
    687  1.1  atatat 			case S_IFSOCK:	(void)strcat(sdata, "=");	break;
    688  1.1  atatat 			case S_IFWHT:	(void)strcat(sdata, "%");	break;
    689  1.1  atatat 			}
    690  1.1  atatat 			hilo = 0;
    691  1.1  atatat 		}
    692  1.1  atatat 		else if (hilo == HIGH_PIECE) {
    693  1.1  atatat 			switch (st->st_mode & S_IFMT) {
    694  1.1  atatat 			case S_IFIFO:	sdata = "Fifo File";		break;
    695  1.1  atatat 			case S_IFCHR:	sdata = "Character Device";	break;
    696  1.1  atatat 			case S_IFDIR:	sdata = "Directory";		break;
    697  1.1  atatat 			case S_IFBLK:	sdata = "Block Device";		break;
    698  1.1  atatat 			case S_IFREG:	sdata = "Regular File";		break;
    699  1.1  atatat 			case S_IFLNK:	sdata = "Symbolic Link";	break;
    700  1.1  atatat 			case S_IFSOCK:	sdata = "Socket";		break;
    701  1.1  atatat 			case S_IFWHT:	sdata = "Whiteout File";	break;
    702  1.1  atatat 			default:	sdata = "???";			break;
    703  1.1  atatat 			}
    704  1.1  atatat 			hilo = 0;
    705  1.1  atatat 		}
    706  1.1  atatat 		formats = FMT_STRING;
    707  1.1  atatat 		if (ofmt == 0)
    708  1.1  atatat 			ofmt = FMT_STRING;
    709  1.1  atatat 		break;
    710  1.1  atatat 	case SHOW_filename:
    711  1.1  atatat 		small = 0;
    712  1.1  atatat 		data = 0;
    713  1.1  atatat 		if (file == NULL)
    714  1.1  atatat 			(void)strncpy(path, "(stdin)", sizeof(path));
    715  1.1  atatat 		else
    716  1.1  atatat 			(void)strncpy(path, file, sizeof(path));
    717  1.1  atatat 		sdata = path;
    718  1.1  atatat 		formats = FMT_STRING;
    719  1.1  atatat 		if (ofmt == 0)
    720  1.1  atatat 			ofmt = FMT_STRING;
    721  1.1  atatat 		break;
    722  1.1  atatat 	case SHOW_sizerdev:
    723  1.1  atatat 		if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
    724  1.1  atatat 			char majdev[20], mindev[20];
    725  1.1  atatat 			int l1, l2;
    726  1.1  atatat 
    727  1.1  atatat 			l1 = format1(st,
    728  1.1  atatat 			    file,
    729  1.1  atatat 			    fmt, flen,
    730  1.1  atatat 			    majdev, sizeof(majdev),
    731  1.1  atatat 			    flags, size, prec,
    732  1.1  atatat 			    ofmt, HIGH_PIECE, SHOW_st_rdev);
    733  1.1  atatat 			l2 = format1(st,
    734  1.1  atatat 			    file,
    735  1.1  atatat 			    fmt, flen,
    736  1.1  atatat 			    mindev, sizeof(mindev),
    737  1.1  atatat 			    flags, size, prec,
    738  1.1  atatat 			    ofmt, LOW_PIECE, SHOW_st_rdev);
    739  1.1  atatat 			return (snprintf(buf, blen, "%.*s,%.*s",
    740  1.1  atatat 			    l1, majdev, l2, mindev));
    741  1.1  atatat 		}
    742  1.1  atatat 		else {
    743  1.1  atatat 			return (format1(st,
    744  1.1  atatat 			    file,
    745  1.1  atatat 			    fmt, flen,
    746  1.1  atatat 			    buf, blen,
    747  1.1  atatat 			    flags, size, prec,
    748  1.1  atatat 			    ofmt, 0, SHOW_st_size));
    749  1.1  atatat 		}
    750  1.1  atatat 		/*NOTREACHED*/
    751  1.1  atatat 	default:
    752  1.1  atatat 		errx(1, "%.*s: bad format", (int)flen, fmt);
    753  1.1  atatat 	}
    754  1.1  atatat 
    755  1.1  atatat 	/*
    756  1.1  atatat 	 * If a subdatum was specified but not supported, or an output
    757  1.1  atatat 	 * format was selected that is not supported, that's an error.
    758  1.1  atatat 	 */
    759  1.1  atatat 	if (hilo != 0 || (ofmt & formats) == 0)
    760  1.1  atatat 		errx(1, "%.*s: bad format", (int)flen, fmt);
    761  1.1  atatat 
    762  1.1  atatat 	/*
    763  1.1  atatat 	 * Assemble the format string for passing to printf(3).
    764  1.1  atatat 	 */
    765  1.1  atatat 	lfmt[0] = '\0';
    766  1.1  atatat 	(void)strcat(lfmt, "%");
    767  1.2  atatat 	if (flags & FLAG_POUND)
    768  1.1  atatat 		(void)strcat(lfmt, "#");
    769  1.2  atatat 	if (flags & FLAG_SPACE)
    770  1.1  atatat 		(void)strcat(lfmt, " ");
    771  1.2  atatat 	if (flags & FLAG_PLUS)
    772  1.1  atatat 		(void)strcat(lfmt, "+");
    773  1.2  atatat 	if (flags & FLAG_MINUS)
    774  1.1  atatat 		(void)strcat(lfmt, "-");
    775  1.2  atatat 	if (flags & FLAG_ZERO)
    776  1.1  atatat 		(void)strcat(lfmt, "0");
    777  1.1  atatat 
    778  1.1  atatat 	/*
    779  1.1  atatat 	 * Only the timespecs support the FLOAT output format, and that
    780  1.1  atatat 	 * requires work that differs from the other formats.
    781  1.1  atatat 	 */
    782  1.1  atatat 	if (ofmt == FMT_FLOAT) {
    783  1.1  atatat 		/*
    784  1.1  atatat 		 * Nothing after the decimal point, so just print seconds.
    785  1.1  atatat 		 */
    786  1.1  atatat 		if (prec == 0) {
    787  1.1  atatat 			if (size != -1) {
    788  1.1  atatat 				(void)snprintf(tmp, sizeof(tmp), "%d", size);
    789  1.1  atatat 				(void)strcat(lfmt, tmp);
    790  1.1  atatat 			}
    791  1.1  atatat 			(void)strcat(lfmt, "d");
    792  1.1  atatat 			return (snprintf(buf, blen, lfmt, ts.tv_sec));
    793  1.1  atatat 		}
    794  1.1  atatat 
    795  1.1  atatat 		/*
    796  1.1  atatat 		 * Unspecified precision gets all the precision we have:
    797  1.1  atatat 		 * 9 digits.
    798  1.1  atatat 		 */
    799  1.1  atatat 		if (prec == -1)
    800  1.1  atatat 			prec = 9;
    801  1.1  atatat 
    802  1.1  atatat 		/*
    803  1.1  atatat 		 * Adjust the size for the decimal point and the digits
    804  1.1  atatat 		 * that will follow.
    805  1.1  atatat 		 */
    806  1.1  atatat 		size -= prec + 1;
    807  1.1  atatat 
    808  1.1  atatat 		/*
    809  1.1  atatat 		 * Any leftover size that's legitimate will be used.
    810  1.1  atatat 		 */
    811  1.1  atatat 		if (size > 0) {
    812  1.1  atatat 			(void)snprintf(tmp, sizeof(tmp), "%d", size);
    813  1.1  atatat 			(void)strcat(lfmt, tmp);
    814  1.1  atatat 		}
    815  1.1  atatat 		(void)strcat(lfmt, "d");
    816  1.1  atatat 
    817  1.1  atatat 		/*
    818  1.1  atatat 		 * The stuff after the decimal point always needs zero
    819  1.1  atatat 		 * filling.
    820  1.1  atatat 		 */
    821  1.1  atatat 		(void)strcat(lfmt, ".%0");
    822  1.1  atatat 
    823  1.1  atatat 		/*
    824  1.1  atatat 		 * We can "print" at most nine digits of precision.  The
    825  1.1  atatat 		 * rest we will pad on at the end.
    826  1.1  atatat 		 */
    827  1.1  atatat 		(void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec);
    828  1.1  atatat 		(void)strcat(lfmt, tmp);
    829  1.1  atatat 
    830  1.1  atatat 		/*
    831  1.1  atatat 		 * For precision of less that nine digits, trim off the
    832  1.1  atatat 		 * less significant figures.
    833  1.1  atatat 		 */
    834  1.1  atatat 		for (; prec < 9; prec++)
    835  1.1  atatat 			ts.tv_nsec /= 10;
    836  1.1  atatat 
    837  1.1  atatat 		/*
    838  1.1  atatat 		 * Use the format, and then tack on any zeroes that
    839  1.1  atatat 		 * might be required to make up the requested precision.
    840  1.1  atatat 		 */
    841  1.1  atatat 		l = snprintf(buf, blen, lfmt, ts.tv_sec, ts.tv_nsec);
    842  1.1  atatat 		for (; prec > 9 && l < blen; prec--, l++)
    843  1.1  atatat 			(void)strcat(buf, "0");
    844  1.1  atatat 		return (l);
    845  1.1  atatat 	}
    846  1.1  atatat 
    847  1.1  atatat 	/*
    848  1.1  atatat 	 * Add on size and precision, if specified, to the format.
    849  1.1  atatat 	 */
    850  1.1  atatat 	if (size != -1) {
    851  1.1  atatat 		(void)snprintf(tmp, sizeof(tmp), "%d", size);
    852  1.1  atatat 		(void)strcat(lfmt, tmp);
    853  1.1  atatat 	}
    854  1.1  atatat 	if (prec != -1) {
    855  1.1  atatat 		(void)snprintf(tmp, sizeof(tmp), ".%d", prec);
    856  1.1  atatat 		(void)strcat(lfmt, tmp);
    857  1.1  atatat 	}
    858  1.1  atatat 
    859  1.1  atatat 	/*
    860  1.1  atatat 	 * String output uses the temporary sdata.
    861  1.1  atatat 	 */
    862  1.1  atatat 	if (ofmt == FMT_STRING) {
    863  1.1  atatat 		if (sdata == NULL)
    864  1.1  atatat 			errx(1, "%.*s: bad format", (int)flen, fmt);
    865  1.1  atatat 		(void)strcat(lfmt, "s");
    866  1.1  atatat 		return (snprintf(buf, blen, lfmt, sdata));
    867  1.1  atatat 	}
    868  1.1  atatat 
    869  1.1  atatat 	/*
    870  1.1  atatat 	 * Ensure that sign extension does not cause bad looking output
    871  1.1  atatat 	 * for some forms.
    872  1.1  atatat 	 */
    873  1.1  atatat 	if (small && ofmt != FMT_DECIMAL)
    874  1.1  atatat 		data = (u_int32_t)data;
    875  1.1  atatat 
    876  1.1  atatat 	/*
    877  1.1  atatat 	 * The four "numeric" output forms.
    878  1.1  atatat 	 */
    879  1.1  atatat 	(void)strcat(lfmt, "ll");
    880  1.1  atatat 	switch (ofmt) {
    881  1.1  atatat 	case FMT_DECIMAL:	(void)strcat(lfmt, "d");	break;
    882  1.1  atatat 	case FMT_OCTAL:		(void)strcat(lfmt, "o");	break;
    883  1.1  atatat 	case FMT_UNSIGNED:	(void)strcat(lfmt, "u");	break;
    884  1.1  atatat 	case FMT_HEX:		(void)strcat(lfmt, "x");	break;
    885  1.1  atatat 	}
    886  1.1  atatat 
    887  1.1  atatat 	return (snprintf(buf, blen, lfmt, data));
    888  1.1  atatat }
    889