Home | History | Annotate | Line # | Download | only in stat
      1  1.55       nia /*	$NetBSD: stat.c,v 1.55 2025/05/15 19:11:44 nia Exp $ */
      2   1.1    atatat 
      3   1.1    atatat /*
      4  1.36       apb  * Copyright (c) 2002-2011 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  *
     19   1.1    atatat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1    atatat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1    atatat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1    atatat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1    atatat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1    atatat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1    atatat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1    atatat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1    atatat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1    atatat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1    atatat  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1    atatat  */
     31   1.1    atatat 
     32  1.15     lukem #if HAVE_NBTOOL_CONFIG_H
     33  1.15     lukem #include "nbtool_config.h"
     34  1.38       dsl /* config checked libc, we need the prototype as well */
     35  1.38       dsl #undef HAVE_DEVNAME
     36  1.15     lukem #endif
     37  1.15     lukem 
     38   1.1    atatat #include <sys/cdefs.h>
     39  1.15     lukem #if !defined(lint)
     40  1.55       nia __RCSID("$NetBSD: stat.c,v 1.55 2025/05/15 19:11:44 nia Exp $");
     41  1.11     lukem #endif
     42  1.11     lukem 
     43  1.15     lukem #if ! HAVE_NBTOOL_CONFIG_H
     44  1.11     lukem #define HAVE_STRUCT_STAT_ST_FLAGS 1
     45  1.13    atatat #define HAVE_STRUCT_STAT_ST_GEN 1
     46  1.13    atatat #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
     47  1.21       jmc #define HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 1
     48  1.13    atatat #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
     49  1.13    atatat #define HAVE_DEVNAME 1
     50  1.15     lukem #endif /* HAVE_NBTOOL_CONFIG_H */
     51   1.1    atatat 
     52  1.10    atatat #include <sys/types.h>
     53   1.1    atatat #include <sys/stat.h>
     54   1.6    atatat 
     55   1.6    atatat #include <ctype.h>
     56   1.7    atatat #include <err.h>
     57  1.18    atatat #include <errno.h>
     58   1.6    atatat #include <grp.h>
     59   1.8    atatat #include <limits.h>
     60   1.6    atatat #include <pwd.h>
     61   1.6    atatat #include <stdio.h>
     62   1.7    atatat #include <stdlib.h>
     63   1.1    atatat #include <string.h>
     64   1.6    atatat #include <time.h>
     65   1.6    atatat #include <unistd.h>
     66  1.50  christos #if HAVE_STRUCT_STAT_ST_FLAGS && !HAVE_NBTOOL_CONFIG_H
     67  1.49  christos #include <util.h>
     68  1.49  christos #endif
     69  1.36       apb #include <vis.h>
     70   1.1    atatat 
     71  1.13    atatat #if HAVE_STRUCT_STAT_ST_FLAGS
     72  1.13    atatat #define DEF_F "%#Xf "
     73  1.13    atatat #define RAW_F "%f "
     74  1.13    atatat #define SHELL_F " st_flags=%f"
     75  1.13    atatat #else /* HAVE_STRUCT_STAT_ST_FLAGS */
     76  1.13    atatat #define DEF_F
     77  1.13    atatat #define RAW_F
     78  1.13    atatat #define SHELL_F
     79  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
     80  1.13    atatat 
     81  1.13    atatat #if HAVE_STRUCT_STAT_ST_BIRTHTIME
     82  1.13    atatat #define DEF_B "\"%SB\" "
     83  1.13    atatat #define RAW_B "%B "
     84  1.37       erh #define SHELL_B "st_birthtime=%SB "
     85  1.40  christos #define LINUX_B	"%n Birth: %SB"
     86  1.13    atatat #else /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
     87  1.13    atatat #define DEF_B
     88  1.13    atatat #define RAW_B
     89  1.13    atatat #define SHELL_B
     90  1.40  christos #define LINUX_B
     91  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
     92  1.13    atatat 
     93  1.13    atatat #if HAVE_STRUCT_STAT_ST_ATIM
     94  1.13    atatat #define st_atimespec st_atim
     95  1.13    atatat #define st_ctimespec st_ctim
     96  1.13    atatat #define st_mtimespec st_mtim
     97  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_ATIM */
     98  1.13    atatat 
     99   1.1    atatat #define DEF_FORMAT \
    100  1.13    atatat 	"%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " DEF_B \
    101  1.13    atatat 	"%k %b " DEF_F "%N"
    102  1.13    atatat #define RAW_FORMAT	"%d %i %#p %l %u %g %r %z %a %m %c " RAW_B \
    103  1.13    atatat 	"%k %b " RAW_F "%N"
    104   1.1    atatat #define LS_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%SY"
    105   1.1    atatat #define LSF_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%T%SY"
    106   1.1    atatat #define SHELL_FORMAT \
    107   1.1    atatat 	"st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \
    108   1.1    atatat 	"st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \
    109  1.37       erh 	"st_atime=%Sa st_mtime=%Sm st_ctime=%Sc " SHELL_B \
    110  1.13    atatat 	"st_blksize=%k st_blocks=%b" SHELL_F
    111   1.1    atatat #define LINUX_FORMAT \
    112   1.1    atatat 	"  File: \"%N\"%n" \
    113  1.39  christos 	"  Size: %-11z  Blocks: %-11b  IO Block: %-11k  %HT%n" \
    114  1.39  christos 	"Device: %Hd,%Ld   Inode: %i    Links: %l%n" \
    115  1.40  christos 	"  Mode: (%Mp%03OLp/%.10Sp)         Uid: (%5u/%8Su)  Gid: (%5g/%8Sg)%n" \
    116   1.1    atatat 	"Access: %Sa%n" \
    117   1.1    atatat 	"Modify: %Sm%n" \
    118  1.40  christos 	"Change: %Sc" \
    119  1.40  christos 	LINUX_B
    120   1.1    atatat 
    121   1.1    atatat #define TIME_FORMAT	"%b %e %T %Y"
    122   1.1    atatat 
    123   1.2    atatat #define FLAG_POUND	0x01
    124   1.2    atatat #define FLAG_SPACE	0x02
    125   1.2    atatat #define FLAG_PLUS	0x04
    126   1.2    atatat #define FLAG_ZERO	0x08
    127   1.2    atatat #define FLAG_MINUS	0x10
    128   1.1    atatat 
    129   1.1    atatat /*
    130   1.2    atatat  * These format characters must all be unique, except the magic one.
    131   1.1    atatat  */
    132   1.2    atatat #define FMT_MAGIC	'%'
    133   1.2    atatat #define FMT_DOT		'.'
    134   1.2    atatat 
    135   1.1    atatat #define SIMPLE_NEWLINE	'n'
    136   1.1    atatat #define SIMPLE_TAB	't'
    137   1.1    atatat #define SIMPLE_PERCENT	'%'
    138   1.2    atatat #define SIMPLE_NUMBER	'@'
    139   1.2    atatat 
    140   1.2    atatat #define FMT_POUND	'#'
    141   1.2    atatat #define FMT_SPACE	' '
    142   1.2    atatat #define FMT_PLUS	'+'
    143   1.2    atatat #define FMT_ZERO	'0'
    144   1.2    atatat #define FMT_MINUS	'-'
    145   1.1    atatat 
    146   1.1    atatat #define FMT_DECIMAL 	'D'
    147   1.1    atatat #define FMT_OCTAL 	'O'
    148   1.1    atatat #define FMT_UNSIGNED 	'U'
    149   1.1    atatat #define FMT_HEX 	'X'
    150   1.1    atatat #define FMT_FLOAT 	'F'
    151   1.1    atatat #define FMT_STRING 	'S'
    152   1.1    atatat 
    153   1.5    atatat #define FMTF_DECIMAL	0x01
    154   1.5    atatat #define FMTF_OCTAL	0x02
    155   1.5    atatat #define FMTF_UNSIGNED	0x04
    156   1.5    atatat #define FMTF_HEX	0x08
    157   1.5    atatat #define FMTF_FLOAT	0x10
    158   1.5    atatat #define FMTF_STRING	0x20
    159   1.5    atatat 
    160   1.1    atatat #define HIGH_PIECE	'H'
    161   1.1    atatat #define MIDDLE_PIECE	'M'
    162   1.1    atatat #define LOW_PIECE	'L'
    163   1.1    atatat 
    164  1.24      elad #define	SHOW_realpath	'R'
    165   1.1    atatat #define SHOW_st_dev	'd'
    166   1.1    atatat #define SHOW_st_ino	'i'
    167   1.1    atatat #define SHOW_st_mode	'p'
    168   1.1    atatat #define SHOW_st_nlink	'l'
    169   1.1    atatat #define SHOW_st_uid	'u'
    170   1.1    atatat #define SHOW_st_gid	'g'
    171   1.1    atatat #define SHOW_st_rdev	'r'
    172   1.1    atatat #define SHOW_st_atime	'a'
    173   1.1    atatat #define SHOW_st_mtime	'm'
    174   1.1    atatat #define SHOW_st_ctime	'c'
    175  1.10    atatat #define SHOW_st_btime	'B'
    176   1.1    atatat #define SHOW_st_size	'z'
    177   1.1    atatat #define SHOW_st_blocks	'b'
    178   1.1    atatat #define SHOW_st_blksize	'k'
    179   1.1    atatat #define SHOW_st_flags	'f'
    180   1.1    atatat #define SHOW_st_gen	'v'
    181   1.1    atatat #define SHOW_symlink	'Y'
    182   1.1    atatat #define SHOW_filetype	'T'
    183   1.1    atatat #define SHOW_filename	'N'
    184   1.1    atatat #define SHOW_sizerdev	'Z'
    185   1.1    atatat 
    186  1.35     joerg static void	usage(const char *) __dead;
    187  1.35     joerg static void	output(const struct stat *, const char *,
    188  1.34  christos 	    const char *, int, int, int);
    189  1.35     joerg static int	format1(const struct stat *,	/* stat info */
    190   1.1    atatat 	    const char *,		/* the file name */
    191   1.1    atatat 	    const char *, int,		/* the format string itself */
    192   1.1    atatat 	    char *, size_t,		/* a place to put the output */
    193   1.1    atatat 	    int, int, int, int,		/* the parsed format */
    194  1.34  christos 	    int, int, int);
    195   1.1    atatat 
    196  1.35     joerg static const char *timefmt;
    197  1.35     joerg static int linkfail;
    198   1.1    atatat 
    199   1.4    atatat #define addchar(s, c, nl) \
    200   1.1    atatat 	do { \
    201   1.4    atatat 		(void)fputc((c), (s)); \
    202   1.4    atatat 		(*nl) = ((c) == '\n'); \
    203   1.1    atatat 	} while (0/*CONSTCOND*/)
    204   1.1    atatat 
    205   1.1    atatat int
    206   1.1    atatat main(int argc, char *argv[])
    207   1.1    atatat {
    208   1.1    atatat 	struct stat st;
    209   1.4    atatat 	int ch, rc, errs, am_readlink;
    210   1.4    atatat 	int lsF, fmtchar, usestat, fn, nonl, quiet;
    211  1.28     lukem 	const char *statfmt, *options, *synopsis;
    212   1.1    atatat 
    213   1.4    atatat 	am_readlink = 0;
    214   1.1    atatat 	lsF = 0;
    215   1.1    atatat 	fmtchar = '\0';
    216   1.1    atatat 	usestat = 0;
    217   1.1    atatat 	nonl = 0;
    218   1.4    atatat 	quiet = 0;
    219   1.4    atatat 	linkfail = 0;
    220   1.1    atatat 	statfmt = NULL;
    221   1.1    atatat 	timefmt = NULL;
    222   1.1    atatat 
    223  1.34  christos 	setprogname(argv[0]);
    224  1.34  christos 
    225   1.4    atatat 	if (strcmp(getprogname(), "readlink") == 0) {
    226   1.4    atatat 		am_readlink = 1;
    227  1.34  christos 		options = "fnqsv";
    228  1.54       kre 		synopsis = "[-fnqsv] file ...";
    229   1.4    atatat 		statfmt = "%Y";
    230   1.4    atatat 		fmtchar = 'f';
    231  1.54       kre 		if (getenv("POSIXLY_CORRECT") == NULL)
    232  1.54       kre 			quiet = 1;
    233   1.4    atatat 	} else {
    234   1.4    atatat 		options = "f:FlLnqrst:x";
    235   1.4    atatat 		synopsis = "[-FlLnqrsx] [-f format] [-t timefmt] [file ...]";
    236   1.4    atatat 	}
    237   1.4    atatat 
    238   1.4    atatat 	while ((ch = getopt(argc, argv, options)) != -1)
    239   1.1    atatat 		switch (ch) {
    240   1.1    atatat 		case 'F':
    241   1.1    atatat 			lsF = 1;
    242   1.1    atatat 			break;
    243   1.1    atatat 		case 'L':
    244   1.1    atatat 			usestat = 1;
    245   1.1    atatat 			break;
    246   1.1    atatat 		case 'n':
    247   1.1    atatat 			nonl = 1;
    248   1.1    atatat 			break;
    249   1.4    atatat 		case 'q':
    250   1.4    atatat 			quiet = 1;
    251   1.4    atatat 			break;
    252   1.1    atatat 		case 'f':
    253  1.24      elad 			if (am_readlink) {
    254  1.24      elad 				statfmt = "%R";
    255  1.24      elad 				break;
    256  1.24      elad 			}
    257   1.1    atatat 			statfmt = optarg;
    258   1.1    atatat 			/* FALLTHROUGH */
    259   1.1    atatat 		case 'l':
    260   1.1    atatat 		case 'r':
    261   1.1    atatat 		case 's':
    262  1.34  christos 			if (am_readlink) {
    263  1.34  christos 				quiet = 1;
    264  1.34  christos 				break;
    265  1.34  christos 			}
    266  1.34  christos 			/*FALLTHROUGH*/
    267   1.1    atatat 		case 'x':
    268   1.1    atatat 			if (fmtchar != 0)
    269   1.1    atatat 				errx(1, "can't use format '%c' with '%c'",
    270   1.1    atatat 				    fmtchar, ch);
    271   1.1    atatat 			fmtchar = ch;
    272   1.1    atatat 			break;
    273   1.1    atatat 		case 't':
    274   1.1    atatat 			timefmt = optarg;
    275   1.1    atatat 			break;
    276  1.34  christos 		case 'v':
    277  1.34  christos 			quiet = 0;
    278  1.34  christos 			break;
    279   1.1    atatat 		default:
    280   1.4    atatat 			usage(synopsis);
    281   1.1    atatat 		}
    282   1.1    atatat 
    283   1.1    atatat 	argc -= optind;
    284   1.1    atatat 	argv += optind;
    285   1.2    atatat 	fn = 1;
    286   1.1    atatat 
    287  1.54       kre 	if (am_readlink && argc == 0)
    288  1.54       kre 		usage(synopsis);
    289  1.54       kre 
    290   1.1    atatat 	if (fmtchar == '\0') {
    291   1.1    atatat 		if (lsF)
    292   1.1    atatat 			fmtchar = 'l';
    293   1.1    atatat 		else {
    294   1.1    atatat 			fmtchar = 'f';
    295   1.1    atatat 			statfmt = DEF_FORMAT;
    296   1.1    atatat 		}
    297   1.1    atatat 	}
    298   1.1    atatat 
    299   1.1    atatat 	if (lsF && fmtchar != 'l')
    300   1.1    atatat 		errx(1, "can't use format '%c' with -F", fmtchar);
    301   1.1    atatat 
    302   1.1    atatat 	switch (fmtchar) {
    303   1.1    atatat 	case 'f':
    304   1.1    atatat 		/* statfmt already set */
    305   1.1    atatat 		break;
    306   1.1    atatat 	case 'l':
    307   1.1    atatat 		statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
    308   1.1    atatat 		break;
    309   1.1    atatat 	case 'r':
    310   1.1    atatat 		statfmt = RAW_FORMAT;
    311   1.1    atatat 		break;
    312   1.1    atatat 	case 's':
    313   1.1    atatat 		statfmt = SHELL_FORMAT;
    314  1.37       erh 		if (timefmt == NULL)
    315  1.37       erh 			timefmt = "%s";
    316   1.1    atatat 		break;
    317   1.1    atatat 	case 'x':
    318   1.1    atatat 		statfmt = LINUX_FORMAT;
    319   1.1    atatat 		if (timefmt == NULL)
    320  1.41       kre 			timefmt = "%Y-%m-%d %H:%M:%S.%f %z";
    321   1.1    atatat 		break;
    322   1.1    atatat 	default:
    323   1.4    atatat 		usage(synopsis);
    324   1.1    atatat 		/*NOTREACHED*/
    325   1.1    atatat 	}
    326   1.1    atatat 
    327   1.1    atatat 	if (timefmt == NULL)
    328   1.1    atatat 		timefmt = TIME_FORMAT;
    329   1.1    atatat 
    330   1.1    atatat 	errs = 0;
    331   1.1    atatat 	do {
    332  1.48       kre 		if (argc == 0) {
    333  1.48       kre 			fn = 0;
    334   1.1    atatat 			rc = fstat(STDIN_FILENO, &st);
    335  1.48       kre 		} else if (usestat) {
    336  1.18    atatat 			/*
    337  1.18    atatat 			 * Try stat() and if it fails, fall back to
    338  1.18    atatat 			 * lstat() just in case we're examining a
    339  1.18    atatat 			 * broken symlink.
    340  1.18    atatat 			 */
    341  1.18    atatat 			if ((rc = stat(argv[0], &st)) == -1 &&
    342  1.18    atatat 			    errno == ENOENT &&
    343  1.18    atatat 			    (rc = lstat(argv[0], &st)) == -1)
    344  1.18    atatat 				errno = ENOENT;
    345  1.48       kre 		} else
    346   1.1    atatat 			rc = lstat(argv[0], &st);
    347   1.1    atatat 
    348   1.1    atatat 		if (rc == -1) {
    349   1.1    atatat 			errs = 1;
    350   1.4    atatat 			linkfail = 1;
    351  1.54       kre 			if (!quiet) {
    352  1.54       kre 				if (argc == 0)
    353  1.54       kre 					warn("%s: %s",
    354  1.54       kre 					    "(stdin)", "fstat");
    355  1.54       kre 				else
    356  1.55       nia 					warn("%s: %s", argv[0],
    357  1.55       nia 					    usestat ? "stat" : "lstat");
    358  1.54       kre 			}
    359  1.54       kre 		} else if (am_readlink && statfmt[1] == 'Y' &&
    360  1.54       kre 		    (st.st_mode & S_IFMT) != S_IFLNK) {
    361  1.54       kre 			linkfail = 1;
    362   1.4    atatat 			if (!quiet)
    363  1.54       kre 				warnx("%s: Not a symbolic link", argv[0]);
    364  1.48       kre 		} else
    365  1.34  christos 			output(&st, argv[0], statfmt, fn, nonl, quiet);
    366   1.1    atatat 
    367   1.1    atatat 		argv++;
    368   1.1    atatat 		argc--;
    369   1.2    atatat 		fn++;
    370   1.1    atatat 	} while (argc > 0);
    371   1.1    atatat 
    372   1.4    atatat 	return (am_readlink ? linkfail : errs);
    373   1.1    atatat }
    374   1.1    atatat 
    375  1.35     joerg static void
    376   1.4    atatat usage(const char *synopsis)
    377   1.1    atatat {
    378   1.1    atatat 
    379   1.4    atatat 	(void)fprintf(stderr, "usage: %s %s\n", getprogname(), synopsis);
    380   1.1    atatat 	exit(1);
    381   1.1    atatat }
    382   1.1    atatat 
    383   1.1    atatat /*
    384   1.1    atatat  * Parses a format string.
    385   1.1    atatat  */
    386  1.35     joerg static void
    387   1.1    atatat output(const struct stat *st, const char *file,
    388  1.34  christos     const char *statfmt, int fn, int nonl, int quiet)
    389   1.1    atatat {
    390   1.1    atatat 	int flags, size, prec, ofmt, hilo, what;
    391  1.36       apb 	/*
    392  1.36       apb 	 * buf size is enough for an item of length PATH_MAX,
    393  1.36       apb 	 * multiplied by 4 for vis encoding, plus 4 for symlink
    394  1.36       apb 	 * " -> " prefix, plus 1 for \0 terminator.
    395  1.36       apb 	 */
    396  1.36       apb 	char buf[PATH_MAX * 4 + 4 + 1];
    397   1.1    atatat 	const char *subfmt;
    398   1.1    atatat 	int nl, t, i;
    399   1.1    atatat 
    400   1.4    atatat 	nl = 1;
    401   1.1    atatat 	while (*statfmt != '\0') {
    402   1.1    atatat 
    403   1.1    atatat 		/*
    404   1.1    atatat 		 * Non-format characters go straight out.
    405   1.1    atatat 		 */
    406   1.2    atatat 		if (*statfmt != FMT_MAGIC) {
    407   1.4    atatat 			addchar(stdout, *statfmt, &nl);
    408   1.1    atatat 			statfmt++;
    409   1.1    atatat 			continue;
    410   1.1    atatat 		}
    411   1.1    atatat 
    412   1.1    atatat 		/*
    413   1.1    atatat 		 * The current format "substring" starts here,
    414   1.2    atatat 		 * and then we skip the magic.
    415   1.1    atatat 		 */
    416   1.1    atatat 		subfmt = statfmt;
    417   1.1    atatat 		statfmt++;
    418   1.1    atatat 
    419   1.1    atatat 		/*
    420   1.1    atatat 		 * Some simple one-character "formats".
    421   1.1    atatat 		 */
    422   1.1    atatat 		switch (*statfmt) {
    423   1.1    atatat 		case SIMPLE_NEWLINE:
    424   1.4    atatat 			addchar(stdout, '\n', &nl);
    425   1.1    atatat 			statfmt++;
    426   1.1    atatat 			continue;
    427   1.1    atatat 		case SIMPLE_TAB:
    428   1.4    atatat 			addchar(stdout, '\t', &nl);
    429   1.1    atatat 			statfmt++;
    430   1.1    atatat 			continue;
    431   1.1    atatat 		case SIMPLE_PERCENT:
    432   1.4    atatat 			addchar(stdout, '%', &nl);
    433   1.1    atatat 			statfmt++;
    434   1.1    atatat 			continue;
    435   1.2    atatat 		case SIMPLE_NUMBER: {
    436   1.2    atatat 			char num[12], *p;
    437   1.2    atatat 
    438   1.2    atatat 			snprintf(num, sizeof(num), "%d", fn);
    439   1.2    atatat 			for (p = &num[0]; *p; p++)
    440   1.4    atatat 				addchar(stdout, *p, &nl);
    441   1.2    atatat 			statfmt++;
    442   1.2    atatat 			continue;
    443   1.2    atatat 		}
    444   1.1    atatat 		}
    445   1.1    atatat 
    446   1.1    atatat 		/*
    447   1.1    atatat 		 * This must be an actual format string.  Format strings are
    448   1.1    atatat 		 * similar to printf(3) formats up to a point, and are of
    449   1.1    atatat 		 * the form:
    450   1.1    atatat 		 *
    451   1.1    atatat 		 *	%	required start of format
    452   1.1    atatat 		 *	[-# +0]	opt. format characters
    453   1.1    atatat 		 *	size	opt. field width
    454   1.1    atatat 		 *	.	opt. decimal separator, followed by
    455   1.1    atatat 		 *	prec	opt. precision
    456   1.1    atatat 		 *	fmt	opt. output specifier (string, numeric, etc.)
    457   1.1    atatat 		 *	sub	opt. sub field specifier (high, middle, low)
    458   1.1    atatat 		 *	datum	required field specifier (size, mode, etc)
    459   1.1    atatat 		 *
    460   1.1    atatat 		 * Only the % and the datum selector are required.  All data
    461   1.1    atatat 		 * have reasonable default output forms.  The "sub" specifier
    462   1.1    atatat 		 * only applies to certain data (mode, dev, rdev, filetype).
    463   1.1    atatat 		 * The symlink output defaults to STRING, yet will only emit
    464   1.1    atatat 		 * the leading " -> " if STRING is explicitly specified.  The
    465   1.1    atatat 		 * sizerdev datum will generate rdev output for character or
    466   1.1    atatat 		 * block devices, and size output for all others.
    467  1.36       apb 		 * For STRING output, the # format requests vis encoding.
    468   1.1    atatat 		 */
    469   1.1    atatat 		flags = 0;
    470   1.1    atatat 		do {
    471   1.2    atatat 			if      (*statfmt == FMT_POUND)
    472   1.2    atatat 				flags |= FLAG_POUND;
    473   1.2    atatat 			else if (*statfmt == FMT_SPACE)
    474   1.2    atatat 				flags |= FLAG_SPACE;
    475   1.2    atatat 			else if (*statfmt == FMT_PLUS)
    476   1.2    atatat 				flags |= FLAG_PLUS;
    477   1.2    atatat 			else if (*statfmt == FMT_ZERO)
    478   1.2    atatat 				flags |= FLAG_ZERO;
    479   1.2    atatat 			else if (*statfmt == FMT_MINUS)
    480   1.2    atatat 				flags |= FLAG_MINUS;
    481   1.1    atatat 			else
    482   1.1    atatat 				break;
    483   1.1    atatat 			statfmt++;
    484   1.1    atatat 		} while (1/*CONSTCOND*/);
    485   1.1    atatat 
    486   1.1    atatat 		size = -1;
    487  1.47    rillig 		if (isdigit((unsigned char)*statfmt)) {
    488   1.1    atatat 			size = 0;
    489  1.47    rillig 			while (isdigit((unsigned char)*statfmt)) {
    490   1.1    atatat 				size = (size * 10) + (*statfmt - '0');
    491   1.1    atatat 				statfmt++;
    492   1.1    atatat 				if (size < 0)
    493   1.1    atatat 					goto badfmt;
    494   1.1    atatat 			}
    495   1.1    atatat 		}
    496   1.1    atatat 
    497   1.1    atatat 		prec = -1;
    498   1.2    atatat 		if (*statfmt == FMT_DOT) {
    499   1.1    atatat 			statfmt++;
    500   1.1    atatat 
    501   1.1    atatat 			prec = 0;
    502  1.47    rillig 			while (isdigit((unsigned char)*statfmt)) {
    503   1.1    atatat 				prec = (prec * 10) + (*statfmt - '0');
    504   1.1    atatat 				statfmt++;
    505   1.1    atatat 				if (prec < 0)
    506   1.1    atatat 					goto badfmt;
    507   1.1    atatat 			}
    508   1.1    atatat 		}
    509   1.1    atatat 
    510   1.5    atatat #define fmtcase(x, y)		case (y): (x) = (y); statfmt++; break
    511   1.5    atatat #define fmtcasef(x, y, z)	case (y): (x) = (z); statfmt++; break
    512   1.1    atatat 		switch (*statfmt) {
    513   1.5    atatat 			fmtcasef(ofmt, FMT_DECIMAL,	FMTF_DECIMAL);
    514   1.5    atatat 			fmtcasef(ofmt, FMT_OCTAL,	FMTF_OCTAL);
    515   1.5    atatat 			fmtcasef(ofmt, FMT_UNSIGNED,	FMTF_UNSIGNED);
    516   1.5    atatat 			fmtcasef(ofmt, FMT_HEX,		FMTF_HEX);
    517   1.5    atatat 			fmtcasef(ofmt, FMT_FLOAT,	FMTF_FLOAT);
    518   1.5    atatat 			fmtcasef(ofmt, FMT_STRING,	FMTF_STRING);
    519   1.1    atatat 		default:
    520   1.1    atatat 			ofmt = 0;
    521   1.1    atatat 			break;
    522   1.1    atatat 		}
    523   1.1    atatat 
    524   1.1    atatat 		switch (*statfmt) {
    525   1.1    atatat 			fmtcase(hilo, HIGH_PIECE);
    526   1.1    atatat 			fmtcase(hilo, MIDDLE_PIECE);
    527   1.1    atatat 			fmtcase(hilo, LOW_PIECE);
    528   1.1    atatat 		default:
    529   1.1    atatat 			hilo = 0;
    530   1.1    atatat 			break;
    531   1.1    atatat 		}
    532   1.1    atatat 
    533   1.1    atatat 		switch (*statfmt) {
    534  1.24      elad 			fmtcase(what, SHOW_realpath);
    535   1.1    atatat 			fmtcase(what, SHOW_st_dev);
    536   1.1    atatat 			fmtcase(what, SHOW_st_ino);
    537   1.1    atatat 			fmtcase(what, SHOW_st_mode);
    538   1.1    atatat 			fmtcase(what, SHOW_st_nlink);
    539   1.1    atatat 			fmtcase(what, SHOW_st_uid);
    540   1.1    atatat 			fmtcase(what, SHOW_st_gid);
    541   1.1    atatat 			fmtcase(what, SHOW_st_rdev);
    542   1.1    atatat 			fmtcase(what, SHOW_st_atime);
    543   1.1    atatat 			fmtcase(what, SHOW_st_mtime);
    544   1.1    atatat 			fmtcase(what, SHOW_st_ctime);
    545  1.10    atatat 			fmtcase(what, SHOW_st_btime);
    546   1.1    atatat 			fmtcase(what, SHOW_st_size);
    547   1.1    atatat 			fmtcase(what, SHOW_st_blocks);
    548   1.1    atatat 			fmtcase(what, SHOW_st_blksize);
    549   1.1    atatat 			fmtcase(what, SHOW_st_flags);
    550   1.1    atatat 			fmtcase(what, SHOW_st_gen);
    551   1.1    atatat 			fmtcase(what, SHOW_symlink);
    552   1.1    atatat 			fmtcase(what, SHOW_filetype);
    553   1.1    atatat 			fmtcase(what, SHOW_filename);
    554   1.1    atatat 			fmtcase(what, SHOW_sizerdev);
    555   1.1    atatat 		default:
    556   1.1    atatat 			goto badfmt;
    557   1.1    atatat 		}
    558   1.5    atatat #undef fmtcasef
    559   1.1    atatat #undef fmtcase
    560   1.1    atatat 
    561   1.1    atatat 		t = format1(st,
    562   1.1    atatat 		     file,
    563   1.1    atatat 		     subfmt, statfmt - subfmt,
    564   1.4    atatat 		     buf, sizeof(buf),
    565  1.34  christos 		     flags, size, prec, ofmt, hilo, what, quiet);
    566   1.1    atatat 
    567  1.28     lukem 		for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++)
    568   1.4    atatat 			addchar(stdout, buf[i], &nl);
    569   1.1    atatat 
    570   1.1    atatat 		continue;
    571   1.1    atatat 
    572   1.1    atatat 	badfmt:
    573   1.1    atatat 		errx(1, "%.*s: bad format",
    574   1.1    atatat 		    (int)(statfmt - subfmt + 1), subfmt);
    575   1.1    atatat 	}
    576   1.1    atatat 
    577   1.1    atatat 	if (!nl && !nonl)
    578   1.4    atatat 		(void)fputc('\n', stdout);
    579   1.4    atatat 	(void)fflush(stdout);
    580   1.1    atatat }
    581   1.1    atatat 
    582  1.39  christos static const char *
    583  1.39  christos fmttime(char *buf, size_t len, const char *fmt, time_t secs, long nsecs)
    584  1.39  christos {
    585  1.39  christos 	struct tm tm;
    586  1.43       kre 	const char *fpb, *fp1, *fp2;	/* pointers into fmt */
    587  1.43       kre 	char *fmt2 = NULL;		/* replacement fmt (if not NULL) */
    588  1.43       kre 				/* XXX init of next twp for stupid gcc only */
    589  1.43       kre 	char *f2p = NULL;		/* ptr into fmt2 - last added */
    590  1.43       kre 	size_t flen = 0;
    591  1.43       kre 	size_t o;
    592  1.43       kre 	int sl;
    593  1.42       kre 
    594  1.39  christos 	if (localtime_r(&secs, &tm) == NULL) {
    595  1.39  christos 		secs = 0;
    596  1.39  christos 		(void)localtime_r(&secs, &tm);
    597  1.39  christos 	}
    598  1.43       kre 	for (fp1 = fpb = fmt; (fp2 = strchr(fp1, '%')) != NULL; ) {
    599  1.43       kre 		if (fp2[1] != 'f') {
    600  1.43       kre 			/* make sure we don't find the 2nd '%' in "%%" */
    601  1.43       kre 			fp1 = fp2 + 1 + (fp2[1] != '\0');
    602  1.43       kre 			continue;
    603  1.43       kre 		}
    604  1.43       kre 		if (fmt2 == NULL) {
    605  1.43       kre 			/* allow for ~100 %f's in the format ... */
    606  1.43       kre 			flen = strlen(fmt) + 1024;
    607  1.43       kre 
    608  1.43       kre 			if ((fmt2 = calloc(flen, 1)) == NULL) {
    609  1.43       kre 				fp1 = fp2 + 2;
    610  1.43       kre 				continue;
    611  1.43       kre 			}
    612  1.43       kre 			f2p = fmt2;
    613  1.43       kre 
    614  1.43       kre 			o = (size_t)(fp2 - fpb);
    615  1.43       kre 			memcpy(f2p, fpb, o);	/* must fit */
    616  1.39  christos 			fmt = fmt2;
    617  1.43       kre 		} else {
    618  1.43       kre 			o = (size_t)(fp2 - fpb);
    619  1.43       kre 			if (flen > o)
    620  1.43       kre 				memcpy(f2p, fpb, o);
    621  1.43       kre 		}
    622  1.43       kre 		if (flen < o + 10) {	/* 9 digits + \0 == 10 */
    623  1.43       kre 			*f2p = '\0';
    624  1.43       kre 			break;
    625  1.43       kre 		}
    626  1.43       kre 		f2p += o;
    627  1.43       kre 		flen -= o;
    628  1.43       kre 		sl = snprintf(f2p, flen, "%.9ld", nsecs);
    629  1.43       kre 		if (sl == -1)
    630  1.43       kre 			sl = 0;
    631  1.43       kre 		f2p += sl;
    632  1.43       kre 		*f2p = '\0';
    633  1.43       kre 		flen -= sl;
    634  1.43       kre 		fp1 = fp2 + 2;
    635  1.43       kre 		fpb = fp1;
    636  1.43       kre 	}
    637  1.43       kre 	if (fmt2 != NULL) {
    638  1.43       kre 		o = strlen(fpb);
    639  1.43       kre 		if (flen > o) {
    640  1.43       kre 			memcpy(f2p, fpb, o);
    641  1.43       kre 			f2p[o] = '\0';
    642  1.39  christos 		}
    643  1.39  christos 	}
    644  1.39  christos 
    645  1.39  christos 	(void)strftime(buf, len, fmt, &tm);
    646  1.39  christos 	free(fmt2);
    647  1.39  christos 	return buf;
    648  1.39  christos }
    649  1.39  christos 
    650   1.1    atatat /*
    651   1.1    atatat  * Arranges output according to a single parsed format substring.
    652   1.1    atatat  */
    653  1.35     joerg static int
    654   1.1    atatat format1(const struct stat *st,
    655   1.1    atatat     const char *file,
    656   1.1    atatat     const char *fmt, int flen,
    657   1.1    atatat     char *buf, size_t blen,
    658   1.1    atatat     int flags, int size, int prec, int ofmt,
    659  1.34  christos     int hilo, int what, int quiet)
    660   1.1    atatat {
    661  1.39  christos 	uint64_t data;
    662  1.28     lukem 	char *stmp, lfmt[24], tmp[20];
    663  1.28     lukem 	const char *sdata;
    664  1.44       mrg 	char smode[12], sid[13], path[PATH_MAX + 4], visbuf[PATH_MAX * 4 + 4];
    665   1.1    atatat 	struct passwd *pw;
    666   1.1    atatat 	struct group *gr;
    667  1.14       chs 	time_t secs;
    668  1.14       chs 	long nsecs;
    669  1.36       apb 	int l;
    670  1.36       apb 	int formats;	/* bitmap of allowed formats for this datum */
    671  1.36       apb 	int small;	/* true if datum is a small integer */
    672  1.36       apb 	int gottime;	/* true if secs and nsecs are valid */
    673  1.36       apb 	int shift;	/* powers of 2 to scale numbers before printing */
    674  1.36       apb 	size_t prefixlen; /* length of constant prefix for string data */
    675   1.1    atatat 
    676   1.1    atatat 	formats = 0;
    677   1.1    atatat 	small = 0;
    678  1.14       chs 	gottime = 0;
    679  1.14       chs 	secs = 0;
    680  1.14       chs 	nsecs = 0;
    681  1.23    atatat 	shift = 0;
    682  1.36       apb 	prefixlen = 0;
    683   1.1    atatat 
    684   1.1    atatat 	/*
    685   1.1    atatat 	 * First, pick out the data and tweak it based on hilo or
    686   1.1    atatat 	 * specified output format (symlink output only).
    687   1.1    atatat 	 */
    688   1.1    atatat 	switch (what) {
    689   1.1    atatat 	case SHOW_st_dev:
    690   1.1    atatat 	case SHOW_st_rdev:
    691   1.1    atatat 		small = (sizeof(st->st_dev) == 4);
    692   1.1    atatat 		data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
    693  1.13    atatat #if HAVE_DEVNAME
    694   1.1    atatat 		sdata = (what == SHOW_st_dev) ?
    695   1.1    atatat 		    devname(st->st_dev, S_IFBLK) :
    696   1.1    atatat 		    devname(st->st_rdev,
    697  1.38       dsl 			S_ISCHR(st->st_mode) ? S_IFCHR :
    698  1.38       dsl 			S_ISBLK(st->st_mode) ? S_IFBLK :
    699  1.38       dsl 			0U);
    700   1.3    atatat 		if (sdata == NULL)
    701   1.3    atatat 			sdata = "???";
    702  1.13    atatat #endif /* HAVE_DEVNAME */
    703   1.1    atatat 		if (hilo == HIGH_PIECE) {
    704   1.1    atatat 			data = major(data);
    705   1.1    atatat 			hilo = 0;
    706   1.1    atatat 		}
    707   1.1    atatat 		else if (hilo == LOW_PIECE) {
    708   1.1    atatat 			data = minor((unsigned)data);
    709   1.1    atatat 			hilo = 0;
    710   1.1    atatat 		}
    711   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
    712  1.13    atatat #if HAVE_DEVNAME
    713   1.5    atatat 		    FMTF_STRING;
    714  1.13    atatat #else /* HAVE_DEVNAME */
    715  1.13    atatat 		    0;
    716  1.13    atatat #endif /* HAVE_DEVNAME */
    717  1.39  christos 		if (ofmt == 0) {
    718  1.39  christos 			if (data == (uint64_t)-1)
    719  1.39  christos 				ofmt = FMTF_DECIMAL;
    720  1.39  christos 			else
    721  1.39  christos 				ofmt = FMTF_UNSIGNED;
    722  1.39  christos 		}
    723   1.1    atatat 		break;
    724   1.1    atatat 	case SHOW_st_ino:
    725   1.1    atatat 		small = (sizeof(st->st_ino) == 4);
    726   1.1    atatat 		data = st->st_ino;
    727   1.1    atatat 		sdata = NULL;
    728   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    729   1.1    atatat 		if (ofmt == 0)
    730   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    731   1.1    atatat 		break;
    732   1.1    atatat 	case SHOW_st_mode:
    733   1.1    atatat 		small = (sizeof(st->st_mode) == 4);
    734   1.1    atatat 		data = st->st_mode;
    735   1.1    atatat 		strmode(st->st_mode, smode);
    736  1.28     lukem 		stmp = smode;
    737  1.28     lukem 		l = strlen(stmp);
    738  1.28     lukem 		if (stmp[l - 1] == ' ')
    739  1.28     lukem 			stmp[--l] = '\0';
    740   1.1    atatat 		if (hilo == HIGH_PIECE) {
    741   1.1    atatat 			data >>= 12;
    742  1.28     lukem 			stmp += 1;
    743  1.28     lukem 			stmp[3] = '\0';
    744   1.1    atatat 			hilo = 0;
    745   1.1    atatat 		}
    746   1.1    atatat 		else if (hilo == MIDDLE_PIECE) {
    747   1.2    atatat 			data = (data >> 9) & 07;
    748  1.28     lukem 			stmp += 4;
    749  1.28     lukem 			stmp[3] = '\0';
    750   1.1    atatat 			hilo = 0;
    751   1.1    atatat 		}
    752   1.1    atatat 		else if (hilo == LOW_PIECE) {
    753   1.2    atatat 			data &= 0777;
    754  1.28     lukem 			stmp += 7;
    755  1.28     lukem 			stmp[3] = '\0';
    756   1.1    atatat 			hilo = 0;
    757   1.1    atatat 		}
    758  1.28     lukem 		sdata = stmp;
    759   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
    760   1.5    atatat 		    FMTF_STRING;
    761   1.1    atatat 		if (ofmt == 0)
    762   1.5    atatat 			ofmt = FMTF_OCTAL;
    763   1.1    atatat 		break;
    764   1.1    atatat 	case SHOW_st_nlink:
    765   1.1    atatat 		small = (sizeof(st->st_dev) == 4);
    766   1.1    atatat 		data = st->st_nlink;
    767   1.1    atatat 		sdata = NULL;
    768   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    769   1.1    atatat 		if (ofmt == 0)
    770   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    771   1.1    atatat 		break;
    772   1.1    atatat 	case SHOW_st_uid:
    773   1.1    atatat 		small = (sizeof(st->st_uid) == 4);
    774   1.1    atatat 		data = st->st_uid;
    775   1.1    atatat 		if ((pw = getpwuid(st->st_uid)) != NULL)
    776   1.1    atatat 			sdata = pw->pw_name;
    777   1.1    atatat 		else {
    778   1.1    atatat 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);
    779   1.1    atatat 			sdata = sid;
    780   1.1    atatat 		}
    781   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
    782   1.5    atatat 		    FMTF_STRING;
    783   1.1    atatat 		if (ofmt == 0)
    784   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    785   1.1    atatat 		break;
    786   1.1    atatat 	case SHOW_st_gid:
    787   1.1    atatat 		small = (sizeof(st->st_gid) == 4);
    788   1.1    atatat 		data = st->st_gid;
    789   1.1    atatat 		if ((gr = getgrgid(st->st_gid)) != NULL)
    790   1.1    atatat 			sdata = gr->gr_name;
    791   1.1    atatat 		else {
    792   1.1    atatat 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);
    793   1.1    atatat 			sdata = sid;
    794   1.1    atatat 		}
    795   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
    796   1.5    atatat 		    FMTF_STRING;
    797   1.1    atatat 		if (ofmt == 0)
    798   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    799   1.1    atatat 		break;
    800   1.1    atatat 	case SHOW_st_atime:
    801  1.14       chs 		gottime = 1;
    802  1.14       chs 		secs = st->st_atime;
    803  1.16     lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
    804  1.14       chs 		nsecs = st->st_atimensec;
    805  1.14       chs #endif
    806   1.1    atatat 		/* FALLTHROUGH */
    807   1.1    atatat 	case SHOW_st_mtime:
    808  1.14       chs 		if (!gottime) {
    809  1.17    atatat 			gottime = 1;
    810  1.14       chs 			secs = st->st_mtime;
    811  1.16     lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
    812  1.14       chs 			nsecs = st->st_mtimensec;
    813  1.14       chs #endif
    814  1.14       chs 		}
    815   1.1    atatat 		/* FALLTHROUGH */
    816   1.1    atatat 	case SHOW_st_ctime:
    817  1.14       chs 		if (!gottime) {
    818  1.17    atatat 			gottime = 1;
    819  1.14       chs 			secs = st->st_ctime;
    820  1.16     lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
    821  1.14       chs 			nsecs = st->st_ctimensec;
    822  1.14       chs #endif
    823  1.14       chs 		}
    824  1.45       mrg #if HAVE_STRUCT_STAT_ST_BIRTHTIME
    825  1.10    atatat 		/* FALLTHROUGH */
    826  1.10    atatat 	case SHOW_st_btime:
    827  1.14       chs 		if (!gottime) {
    828  1.17    atatat 			gottime = 1;
    829  1.19       jmc 			secs = st->st_birthtime;
    830  1.21       jmc #if HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
    831  1.19       jmc 			nsecs = st->st_birthtimensec;
    832  1.21       jmc #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC */
    833  1.14       chs 		}
    834  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
    835  1.14       chs 		small = (sizeof(secs) == 4);
    836  1.14       chs 		data = secs;
    837  1.39  christos 		sdata = fmttime(path, sizeof(path), timefmt, secs, nsecs);
    838  1.39  christos 
    839   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
    840   1.5    atatat 		    FMTF_FLOAT | FMTF_STRING;
    841   1.1    atatat 		if (ofmt == 0)
    842   1.5    atatat 			ofmt = FMTF_DECIMAL;
    843   1.1    atatat 		break;
    844   1.1    atatat 	case SHOW_st_size:
    845   1.1    atatat 		small = (sizeof(st->st_size) == 4);
    846   1.1    atatat 		data = st->st_size;
    847   1.1    atatat 		sdata = NULL;
    848   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    849   1.1    atatat 		if (ofmt == 0)
    850   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    851  1.23    atatat 		switch (hilo) {
    852  1.23    atatat 		case HIGH_PIECE:
    853  1.23    atatat 			shift = 30;	/* gigabytes */
    854  1.23    atatat 			hilo = 0;
    855  1.23    atatat 			break;
    856  1.23    atatat 		case MIDDLE_PIECE:
    857  1.23    atatat 			shift = 20;	/* megabytes */
    858  1.23    atatat 			hilo = 0;
    859  1.23    atatat 			break;
    860  1.23    atatat 		case LOW_PIECE:
    861  1.23    atatat 			shift = 10;	/* kilobytes */
    862  1.23    atatat 			hilo = 0;
    863  1.23    atatat 			break;
    864  1.23    atatat 		}
    865   1.1    atatat 		break;
    866   1.1    atatat 	case SHOW_st_blocks:
    867   1.1    atatat 		small = (sizeof(st->st_blocks) == 4);
    868   1.1    atatat 		data = st->st_blocks;
    869   1.1    atatat 		sdata = NULL;
    870   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    871   1.1    atatat 		if (ofmt == 0)
    872   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    873   1.1    atatat 		break;
    874   1.1    atatat 	case SHOW_st_blksize:
    875   1.1    atatat 		small = (sizeof(st->st_blksize) == 4);
    876   1.1    atatat 		data = st->st_blksize;
    877   1.1    atatat 		sdata = NULL;
    878   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    879   1.1    atatat 		if (ofmt == 0)
    880   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    881   1.1    atatat 		break;
    882  1.11     lukem #if HAVE_STRUCT_STAT_ST_FLAGS
    883   1.1    atatat 	case SHOW_st_flags:
    884   1.1    atatat 		small = (sizeof(st->st_flags) == 4);
    885   1.1    atatat 		data = st->st_flags;
    886  1.50  christos 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    887  1.50  christos #if !HAVE_NBTOOL_CONFIG_H
    888  1.49  christos 		sdata = flags_to_string((u_long)st->st_flags, "-");
    889  1.50  christos 		formats |= FMT_STRING;
    890  1.50  christos #endif
    891   1.1    atatat 		if (ofmt == 0)
    892   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    893   1.1    atatat 		break;
    894  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
    895  1.13    atatat #if HAVE_STRUCT_STAT_ST_GEN
    896   1.1    atatat 	case SHOW_st_gen:
    897   1.1    atatat 		small = (sizeof(st->st_gen) == 4);
    898   1.1    atatat 		data = st->st_gen;
    899   1.1    atatat 		sdata = NULL;
    900   1.5    atatat 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
    901   1.1    atatat 		if (ofmt == 0)
    902   1.5    atatat 			ofmt = FMTF_UNSIGNED;
    903   1.1    atatat 		break;
    904  1.13    atatat #endif /* HAVE_STRUCT_STAT_ST_GEN */
    905  1.24      elad 	case SHOW_realpath:
    906  1.24      elad 		small = 0;
    907  1.24      elad 		data = 0;
    908  1.25   mlelstv 		if (file == NULL) {
    909  1.31  dholland 			(void)strlcpy(path, "(stdin)", sizeof(path));
    910  1.25   mlelstv 			sdata = path;
    911  1.25   mlelstv 		} else {
    912  1.25   mlelstv 			snprintf(path, sizeof(path), " -> ");
    913  1.25   mlelstv 			if (realpath(file, path + 4) == NULL) {
    914  1.34  christos 				if (!quiet)
    915  1.34  christos 					warn("realpath `%s'", file);
    916  1.25   mlelstv 				linkfail = 1;
    917  1.25   mlelstv 				l = 0;
    918  1.25   mlelstv 				path[0] = '\0';
    919  1.25   mlelstv 			}
    920  1.27    atatat 			sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
    921  1.36       apb 			prefixlen = (ofmt == FMTF_STRING ? 4 : 0);
    922  1.24      elad 		}
    923  1.24      elad 
    924  1.24      elad 		formats = FMTF_STRING;
    925  1.24      elad 		if (ofmt == 0)
    926  1.24      elad 			ofmt = FMTF_STRING;
    927  1.24      elad 		break;
    928   1.1    atatat 	case SHOW_symlink:
    929   1.1    atatat 		small = 0;
    930   1.1    atatat 		data = 0;
    931   1.1    atatat 		if (S_ISLNK(st->st_mode)) {
    932   1.1    atatat 			snprintf(path, sizeof(path), " -> ");
    933   1.9    provos 			l = readlink(file, path + 4, sizeof(path) - 4 - 1);
    934   1.1    atatat 			if (l == -1) {
    935  1.34  christos 				if (!quiet)
    936  1.34  christos 					warn("readlink `%s'", file);
    937   1.4    atatat 				linkfail = 1;
    938   1.1    atatat 				l = 0;
    939   1.1    atatat 				path[0] = '\0';
    940   1.1    atatat 			}
    941   1.1    atatat 			path[l + 4] = '\0';
    942   1.5    atatat 			sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
    943  1.36       apb 			prefixlen = (ofmt == FMTF_STRING ? 4 : 0);
    944   1.1    atatat 		}
    945   1.4    atatat 		else {
    946   1.4    atatat 			linkfail = 1;
    947   1.1    atatat 			sdata = "";
    948   1.4    atatat 		}
    949   1.5    atatat 		formats = FMTF_STRING;
    950   1.1    atatat 		if (ofmt == 0)
    951   1.5    atatat 			ofmt = FMTF_STRING;
    952   1.1    atatat 		break;
    953   1.1    atatat 	case SHOW_filetype:
    954   1.1    atatat 		small = 0;
    955   1.1    atatat 		data = 0;
    956  1.28     lukem 		sdata = "";
    957   1.1    atatat 		if (hilo == 0 || hilo == LOW_PIECE) {
    958   1.1    atatat 			switch (st->st_mode & S_IFMT) {
    959  1.28     lukem 			case S_IFIFO:	sdata = "|";			break;
    960  1.28     lukem 			case S_IFDIR:	sdata = "/";			break;
    961   1.1    atatat 			case S_IFREG:
    962   1.1    atatat 				if (st->st_mode &
    963   1.1    atatat 				    (S_IXUSR | S_IXGRP | S_IXOTH))
    964  1.28     lukem 					sdata = "*";
    965   1.1    atatat 				break;
    966  1.28     lukem 			case S_IFLNK:	sdata = "@";			break;
    967  1.19       jmc #ifdef S_IFSOCK
    968  1.28     lukem 			case S_IFSOCK:	sdata = "=";			break;
    969  1.19       jmc #endif
    970  1.13    atatat #ifdef S_IFWHT
    971  1.28     lukem 			case S_IFWHT:	sdata = "%";			break;
    972  1.13    atatat #endif /* S_IFWHT */
    973  1.13    atatat #ifdef S_IFDOOR
    974  1.28     lukem 			case S_IFDOOR:	sdata = ">";			break;
    975  1.13    atatat #endif /* S_IFDOOR */
    976   1.1    atatat 			}
    977   1.1    atatat 			hilo = 0;
    978   1.1    atatat 		}
    979   1.1    atatat 		else if (hilo == HIGH_PIECE) {
    980   1.1    atatat 			switch (st->st_mode & S_IFMT) {
    981   1.1    atatat 			case S_IFIFO:	sdata = "Fifo File";		break;
    982   1.1    atatat 			case S_IFCHR:	sdata = "Character Device";	break;
    983   1.1    atatat 			case S_IFDIR:	sdata = "Directory";		break;
    984   1.1    atatat 			case S_IFBLK:	sdata = "Block Device";		break;
    985   1.1    atatat 			case S_IFREG:	sdata = "Regular File";		break;
    986   1.1    atatat 			case S_IFLNK:	sdata = "Symbolic Link";	break;
    987  1.19       jmc #ifdef S_IFSOCK
    988   1.1    atatat 			case S_IFSOCK:	sdata = "Socket";		break;
    989  1.19       jmc #endif
    990  1.13    atatat #ifdef S_IFWHT
    991   1.1    atatat 			case S_IFWHT:	sdata = "Whiteout File";	break;
    992  1.13    atatat #endif /* S_IFWHT */
    993  1.13    atatat #ifdef S_IFDOOR
    994  1.13    atatat 			case S_IFDOOR:	sdata = "Door";			break;
    995  1.13    atatat #endif /* S_IFDOOR */
    996   1.1    atatat 			default:	sdata = "???";			break;
    997   1.1    atatat 			}
    998   1.1    atatat 			hilo = 0;
    999   1.1    atatat 		}
   1000   1.5    atatat 		formats = FMTF_STRING;
   1001   1.1    atatat 		if (ofmt == 0)
   1002   1.5    atatat 			ofmt = FMTF_STRING;
   1003   1.1    atatat 		break;
   1004   1.1    atatat 	case SHOW_filename:
   1005   1.1    atatat 		small = 0;
   1006   1.1    atatat 		data = 0;
   1007  1.20    atatat 		if (file == NULL) {
   1008  1.31  dholland 			(void)strlcpy(path, "(stdin)", sizeof(path));
   1009  1.20    atatat 			if (hilo == HIGH_PIECE || hilo == LOW_PIECE)
   1010  1.20    atatat 				hilo = 0;
   1011  1.20    atatat 		}
   1012  1.20    atatat 		else if (hilo == 0)
   1013  1.31  dholland 			(void)strlcpy(path, file, sizeof(path));
   1014  1.20    atatat 		else {
   1015  1.20    atatat 			char *s;
   1016  1.31  dholland 			(void)strlcpy(path, file, sizeof(path));
   1017  1.20    atatat 			s = strrchr(path, '/');
   1018  1.20    atatat 			if (s != NULL) {
   1019  1.20    atatat 				/* trim off trailing /'s */
   1020  1.20    atatat 				while (s != path &&
   1021  1.20    atatat 				    s[0] == '/' && s[1] == '\0')
   1022  1.20    atatat 					*s-- = '\0';
   1023  1.20    atatat 				s = strrchr(path, '/');
   1024  1.20    atatat 			}
   1025  1.20    atatat 			if (hilo == HIGH_PIECE) {
   1026  1.20    atatat 				if (s == NULL)
   1027  1.31  dholland 					(void)strlcpy(path, ".", sizeof(path));
   1028  1.20    atatat 				else {
   1029  1.20    atatat 					while (s != path && s[0] == '/')
   1030  1.20    atatat 						*s-- = '\0';
   1031  1.20    atatat 				}
   1032  1.20    atatat 				hilo = 0;
   1033  1.20    atatat 			}
   1034  1.20    atatat 			else if (hilo == LOW_PIECE) {
   1035  1.20    atatat 				if (s != NULL && s[1] != '\0')
   1036  1.31  dholland 					(void)strlcpy(path, s + 1,
   1037  1.20    atatat 						      sizeof(path));
   1038  1.20    atatat 				hilo = 0;
   1039  1.20    atatat 			}
   1040  1.20    atatat 		}
   1041   1.1    atatat 		sdata = path;
   1042   1.5    atatat 		formats = FMTF_STRING;
   1043   1.1    atatat 		if (ofmt == 0)
   1044   1.5    atatat 			ofmt = FMTF_STRING;
   1045   1.1    atatat 		break;
   1046   1.1    atatat 	case SHOW_sizerdev:
   1047   1.1    atatat 		if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
   1048   1.1    atatat 			char majdev[20], mindev[20];
   1049   1.1    atatat 			int l1, l2;
   1050   1.1    atatat 
   1051  1.48       kre 			if (size == 0)		/* avoid -1/2 */
   1052  1.48       kre 				size++;		/* 1/2 == 0/2 so this is safe */
   1053   1.1    atatat 			l1 = format1(st,
   1054   1.1    atatat 			    file,
   1055   1.1    atatat 			    fmt, flen,
   1056   1.1    atatat 			    majdev, sizeof(majdev),
   1057  1.48       kre 			    flags, (size - 1) / 2, prec,
   1058  1.34  christos 			    ofmt, HIGH_PIECE, SHOW_st_rdev, quiet);
   1059   1.1    atatat 			l2 = format1(st,
   1060   1.1    atatat 			    file,
   1061   1.1    atatat 			    fmt, flen,
   1062   1.1    atatat 			    mindev, sizeof(mindev),
   1063  1.48       kre 			    flags | FLAG_MINUS , size / 2, prec,
   1064  1.34  christos 			    ofmt, LOW_PIECE, SHOW_st_rdev, quiet);
   1065   1.1    atatat 			return (snprintf(buf, blen, "%.*s,%.*s",
   1066   1.1    atatat 			    l1, majdev, l2, mindev));
   1067   1.1    atatat 		}
   1068   1.1    atatat 		else {
   1069   1.1    atatat 			return (format1(st,
   1070   1.1    atatat 			    file,
   1071   1.1    atatat 			    fmt, flen,
   1072   1.1    atatat 			    buf, blen,
   1073   1.1    atatat 			    flags, size, prec,
   1074  1.34  christos 			    ofmt, 0, SHOW_st_size, quiet));
   1075   1.1    atatat 		}
   1076   1.1    atatat 		/*NOTREACHED*/
   1077   1.1    atatat 	default:
   1078   1.1    atatat 		errx(1, "%.*s: bad format", (int)flen, fmt);
   1079   1.1    atatat 	}
   1080   1.1    atatat 
   1081  1.53    rillig 	if (hilo != 0			// subdatum not supported
   1082  1.53    rillig 	    || !(ofmt & formats)	// output format not supported
   1083  1.53    rillig 	    || (ofmt == FMTF_STRING && flags & FLAG_SPACE)
   1084  1.53    rillig 	    || (ofmt == FMTF_STRING && flags & FLAG_PLUS)
   1085  1.53    rillig 	    || (ofmt == FMTF_STRING && flags & FLAG_ZERO))
   1086   1.1    atatat 		errx(1, "%.*s: bad format", (int)flen, fmt);
   1087   1.1    atatat 
   1088   1.1    atatat 	/*
   1089  1.36       apb 	 * FLAG_POUND with FMTF_STRING means use vis(3) encoding.
   1090  1.36       apb 	 * First prefixlen chars are not encoded.
   1091  1.36       apb 	 */
   1092  1.36       apb 	if ((flags & FLAG_POUND) != 0 && ofmt == FMTF_STRING) {
   1093  1.52       kre 		flags &= ~FLAG_POUND;
   1094  1.36       apb 		strncpy(visbuf, sdata, prefixlen);
   1095  1.46       mrg 		/* Avoid GCC warnings. */
   1096  1.46       mrg 		visbuf[prefixlen] = 0;
   1097  1.36       apb 		strnvis(visbuf + prefixlen, sizeof(visbuf) - prefixlen,
   1098  1.36       apb 		    sdata + prefixlen, VIS_WHITE | VIS_OCTAL | VIS_CSTYLE);
   1099  1.36       apb 		sdata = visbuf;
   1100  1.36       apb 	}
   1101  1.36       apb 
   1102  1.36       apb 	/*
   1103   1.1    atatat 	 * Assemble the format string for passing to printf(3).
   1104   1.1    atatat 	 */
   1105   1.1    atatat 	lfmt[0] = '\0';
   1106   1.1    atatat 	(void)strcat(lfmt, "%");
   1107   1.2    atatat 	if (flags & FLAG_POUND)
   1108   1.1    atatat 		(void)strcat(lfmt, "#");
   1109   1.2    atatat 	if (flags & FLAG_SPACE)
   1110   1.1    atatat 		(void)strcat(lfmt, " ");
   1111   1.2    atatat 	if (flags & FLAG_PLUS)
   1112   1.1    atatat 		(void)strcat(lfmt, "+");
   1113   1.2    atatat 	if (flags & FLAG_MINUS)
   1114   1.1    atatat 		(void)strcat(lfmt, "-");
   1115   1.2    atatat 	if (flags & FLAG_ZERO)
   1116   1.1    atatat 		(void)strcat(lfmt, "0");
   1117   1.1    atatat 
   1118   1.1    atatat 	/*
   1119   1.1    atatat 	 * Only the timespecs support the FLOAT output format, and that
   1120   1.1    atatat 	 * requires work that differs from the other formats.
   1121   1.1    atatat 	 */
   1122   1.5    atatat 	if (ofmt == FMTF_FLOAT) {
   1123   1.1    atatat 		/*
   1124   1.1    atatat 		 * Nothing after the decimal point, so just print seconds.
   1125   1.1    atatat 		 */
   1126   1.1    atatat 		if (prec == 0) {
   1127   1.1    atatat 			if (size != -1) {
   1128   1.1    atatat 				(void)snprintf(tmp, sizeof(tmp), "%d", size);
   1129   1.1    atatat 				(void)strcat(lfmt, tmp);
   1130   1.1    atatat 			}
   1131  1.29  dholland 			(void)strcat(lfmt, "lld");
   1132  1.29  dholland 			return (snprintf(buf, blen, lfmt,
   1133  1.29  dholland 			    (long long)secs));
   1134   1.1    atatat 		}
   1135   1.1    atatat 
   1136   1.1    atatat 		/*
   1137   1.1    atatat 		 * Unspecified precision gets all the precision we have:
   1138   1.1    atatat 		 * 9 digits.
   1139   1.1    atatat 		 */
   1140   1.1    atatat 		if (prec == -1)
   1141   1.1    atatat 			prec = 9;
   1142   1.1    atatat 
   1143   1.1    atatat 		/*
   1144   1.1    atatat 		 * Adjust the size for the decimal point and the digits
   1145   1.1    atatat 		 * that will follow.
   1146   1.1    atatat 		 */
   1147   1.1    atatat 		size -= prec + 1;
   1148   1.1    atatat 
   1149   1.1    atatat 		/*
   1150   1.1    atatat 		 * Any leftover size that's legitimate will be used.
   1151   1.1    atatat 		 */
   1152   1.1    atatat 		if (size > 0) {
   1153   1.1    atatat 			(void)snprintf(tmp, sizeof(tmp), "%d", size);
   1154   1.1    atatat 			(void)strcat(lfmt, tmp);
   1155   1.1    atatat 		}
   1156  1.30  dholland 		/* Seconds: time_t cast to long long. */
   1157  1.29  dholland 		(void)strcat(lfmt, "lld");
   1158   1.1    atatat 
   1159   1.1    atatat 		/*
   1160   1.1    atatat 		 * The stuff after the decimal point always needs zero
   1161   1.1    atatat 		 * filling.
   1162   1.1    atatat 		 */
   1163   1.1    atatat 		(void)strcat(lfmt, ".%0");
   1164   1.1    atatat 
   1165   1.1    atatat 		/*
   1166   1.1    atatat 		 * We can "print" at most nine digits of precision.  The
   1167   1.1    atatat 		 * rest we will pad on at the end.
   1168  1.30  dholland 		 *
   1169  1.30  dholland 		 * Nanoseconds: long.
   1170   1.1    atatat 		 */
   1171  1.29  dholland 		(void)snprintf(tmp, sizeof(tmp), "%dld", prec > 9 ? 9 : prec);
   1172   1.1    atatat 		(void)strcat(lfmt, tmp);
   1173   1.1    atatat 
   1174   1.1    atatat 		/*
   1175   1.1    atatat 		 * For precision of less that nine digits, trim off the
   1176   1.1    atatat 		 * less significant figures.
   1177   1.1    atatat 		 */
   1178   1.1    atatat 		for (; prec < 9; prec++)
   1179  1.14       chs 			nsecs /= 10;
   1180   1.1    atatat 
   1181   1.1    atatat 		/*
   1182   1.1    atatat 		 * Use the format, and then tack on any zeroes that
   1183   1.1    atatat 		 * might be required to make up the requested precision.
   1184   1.1    atatat 		 */
   1185  1.29  dholland 		l = snprintf(buf, blen, lfmt, (long long)secs, nsecs);
   1186  1.28     lukem 		for (; prec > 9 && l < (int)blen; prec--, l++)
   1187   1.1    atatat 			(void)strcat(buf, "0");
   1188   1.1    atatat 		return (l);
   1189   1.1    atatat 	}
   1190   1.1    atatat 
   1191   1.1    atatat 	/*
   1192   1.1    atatat 	 * Add on size and precision, if specified, to the format.
   1193   1.1    atatat 	 */
   1194   1.1    atatat 	if (size != -1) {
   1195   1.1    atatat 		(void)snprintf(tmp, sizeof(tmp), "%d", size);
   1196   1.1    atatat 		(void)strcat(lfmt, tmp);
   1197   1.1    atatat 	}
   1198   1.1    atatat 	if (prec != -1) {
   1199   1.1    atatat 		(void)snprintf(tmp, sizeof(tmp), ".%d", prec);
   1200   1.1    atatat 		(void)strcat(lfmt, tmp);
   1201   1.1    atatat 	}
   1202   1.1    atatat 
   1203   1.1    atatat 	/*
   1204   1.1    atatat 	 * String output uses the temporary sdata.
   1205   1.1    atatat 	 */
   1206   1.5    atatat 	if (ofmt == FMTF_STRING) {
   1207   1.1    atatat 		if (sdata == NULL)
   1208   1.1    atatat 			errx(1, "%.*s: bad format", (int)flen, fmt);
   1209   1.1    atatat 		(void)strcat(lfmt, "s");
   1210   1.1    atatat 		return (snprintf(buf, blen, lfmt, sdata));
   1211   1.1    atatat 	}
   1212   1.1    atatat 
   1213   1.1    atatat 	/*
   1214   1.1    atatat 	 * Ensure that sign extension does not cause bad looking output
   1215   1.1    atatat 	 * for some forms.
   1216   1.1    atatat 	 */
   1217   1.5    atatat 	if (small && ofmt != FMTF_DECIMAL)
   1218  1.39  christos 		data = (uint32_t)data;
   1219   1.1    atatat 
   1220   1.1    atatat 	/*
   1221   1.1    atatat 	 * The four "numeric" output forms.
   1222   1.1    atatat 	 */
   1223   1.1    atatat 	(void)strcat(lfmt, "ll");
   1224   1.1    atatat 	switch (ofmt) {
   1225   1.5    atatat 	case FMTF_DECIMAL:	(void)strcat(lfmt, "d");	break;
   1226  1.23    atatat 	case FMTF_OCTAL:	(void)strcat(lfmt, "o");	break;
   1227   1.5    atatat 	case FMTF_UNSIGNED:	(void)strcat(lfmt, "u");	break;
   1228   1.5    atatat 	case FMTF_HEX:		(void)strcat(lfmt, "x");	break;
   1229   1.1    atatat 	}
   1230   1.1    atatat 
   1231  1.23    atatat 	/*
   1232  1.23    atatat 	 * shift and round to nearest for kilobytes, megabytes,
   1233  1.23    atatat 	 * gigabytes.
   1234  1.23    atatat 	 */
   1235  1.23    atatat 	if (shift > 0) {
   1236  1.23    atatat 		data >>= (shift - 1);
   1237  1.23    atatat 		data++;
   1238  1.23    atatat 		data >>= 1;
   1239  1.23    atatat 	}
   1240  1.23    atatat 
   1241   1.1    atatat 	return (snprintf(buf, blen, lfmt, data));
   1242   1.1    atatat }
   1243