* configure.in: add Galition and Estonian languages.
[findutils.git] / lib / listfile.c
blob9e63e11c3e6f1c17dda783468d1d3e623b073426
1 /* listfile.c -- display a long listing of a file
2 Copyright (C) 1991, 1993 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <time.h>
28 #include <errno.h>
29 #include "pathmax.h"
31 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36 #ifdef STDC_HEADERS
37 #include <stdlib.h>
38 #else
39 extern int errno;
40 #endif
42 /* Since major is a function on SVR4, we can't use `ifndef major'. */
43 #ifdef MAJOR_IN_MKDEV
44 #include <sys/mkdev.h>
45 #define HAVE_MAJOR
46 #endif
47 #ifdef MAJOR_IN_SYSMACROS
48 #include <sys/sysmacros.h>
49 #define HAVE_MAJOR
50 #endif
52 #ifdef STAT_MACROS_BROKEN
53 #undef S_ISCHR
54 #undef S_ISBLK
55 #undef S_ISLNK
56 #endif
58 #ifndef S_ISCHR
59 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
60 #endif
61 #ifndef S_ISBLK
62 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
63 #endif
64 #if defined(S_IFLNK) && !defined(S_ISLNK)
65 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
66 #endif
69 /* Extract or fake data from a `struct stat'.
70 ST_NBLOCKS: Number of 512-byte blocks in the file
71 (including indirect blocks).
72 HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
73 This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
74 #ifdef _POSIX_SOURCE
75 # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
76 #else
77 # ifndef HAVE_ST_BLOCKS
78 # define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
79 # else
80 # if defined(hpux) || defined(__hpux__)
81 # define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
82 # else
83 # define ST_NBLOCKS(statp) ((statp)->st_blocks)
84 # endif
85 # endif
86 #endif
88 /* Convert B 512-byte blocks to kilobytes if K is nonzero,
89 otherwise return it unchanged. */
90 #define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
92 #ifndef _POSIX_VERSION
93 struct passwd *getpwuid ();
94 struct group *getgrgid ();
95 #endif
97 #ifdef major /* Might be defined in sys/types.h. */
98 #define HAVE_MAJOR
99 #endif
100 #ifndef HAVE_MAJOR
101 #define major(dev) (((dev) >> 8) & 0xff)
102 #define minor(dev) ((dev) & 0xff)
103 #endif
104 #undef HAVE_MAJOR
106 char *xmalloc ();
107 void error ();
108 void mode_string ();
110 char *get_link_name ();
111 char *getgroup ();
112 char *getuser ();
113 void print_name_with_quoting ();
115 /* NAME is the name to print.
116 RELNAME is the path to access it from the current directory.
117 STATP is the results of stat or lstat on it.
118 STREAM is the stdio stream to print on. */
120 void
121 list_file (name, relname, statp, stream)
122 char *name;
123 char *relname;
124 struct stat *statp;
125 FILE *stream;
127 static int kilobytes = -1; /* -1 = uninitialized, 0 = 512, 1 = 1024. */
128 char modebuf[20];
129 char timebuf[40];
130 time_t current_time = time ((time_t *) 0);
132 if (kilobytes == -1)
133 kilobytes = getenv ("POSIXLY_CORRECT") == 0;
135 mode_string (statp->st_mode, modebuf);
136 modebuf[10] = '\0';
138 strcpy (timebuf, ctime (&statp->st_mtime));
139 if (current_time > statp->st_mtime + 6L * 30L * 24L * 60L * 60L /* Old. */
140 || current_time < statp->st_mtime - 60L * 60L) /* In the future. */
142 /* The file is fairly old or in the future.
143 POSIX says the cutoff is 6 months old;
144 approximate this by 6*30 days.
145 Allow a 1 hour slop factor for what is considered "the future",
146 to allow for NFS server/client clock disagreement.
147 Show the year instead of the time of day. */
148 strcpy (timebuf + 11, timebuf + 19);
150 timebuf[16] = 0;
152 fprintf (stream, "%6lu ", statp->st_ino);
154 fprintf (stream, "%4lu ", convert_blocks (ST_NBLOCKS (statp), kilobytes));
156 /* The space between the mode and the number of links is the POSIX
157 "optional alternate access method flag". */
158 fprintf (stream, "%s %3u ", modebuf, statp->st_nlink);
160 fprintf (stream, "%-8.8s ", getuser (statp->st_uid));
162 fprintf (stream, "%-8.8s ", getgroup (statp->st_gid));
164 if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
165 #ifdef HAVE_ST_RDEV
166 fprintf (stream, "%3u, %3u ", major (statp->st_rdev), minor (statp->st_rdev));
167 #else
168 fprintf (stream, " ");
169 #endif
170 else
171 fprintf (stream, "%8lu ", statp->st_size);
173 fprintf (stream, "%s ", timebuf + 4);
175 print_name_with_quoting (name, stream);
177 #ifdef S_ISLNK
178 if (S_ISLNK (statp->st_mode))
180 char *linkname = get_link_name (name, relname);
182 if (linkname)
184 fputs (" -> ", stream);
185 print_name_with_quoting (linkname, stream);
186 free (linkname);
189 #endif
190 putc ('\n', stream);
193 void
194 print_name_with_quoting (p, stream)
195 register char *p;
196 FILE *stream;
198 register unsigned char c;
200 while ((c = *p++) != '\0')
202 switch (c)
204 case '\\':
205 fprintf (stream, "\\\\");
206 break;
208 case '\n':
209 fprintf (stream, "\\n");
210 break;
212 case '\b':
213 fprintf (stream, "\\b");
214 break;
216 case '\r':
217 fprintf (stream, "\\r");
218 break;
220 case '\t':
221 fprintf (stream, "\\t");
222 break;
224 case '\f':
225 fprintf (stream, "\\f");
226 break;
228 case ' ':
229 fprintf (stream, "\\ ");
230 break;
232 case '"':
233 fprintf (stream, "\\\"");
234 break;
236 default:
237 if (c > 040 && c < 0177)
238 putc (c, stream);
239 else
240 fprintf (stream, "\\%03o", (unsigned int) c);
245 #ifdef S_ISLNK
246 char *
247 get_link_name (name, relname)
248 char *name;
249 char *relname;
251 register char *linkname;
252 register int linklen;
254 /* st_size is wrong for symlinks on AIX, and on
255 mount points with some automounters.
256 So allocate a pessimistic PATH_MAX + 1 bytes. */
257 #define LINK_BUF PATH_MAX
258 linkname = (char *) xmalloc (LINK_BUF + 1);
259 linklen = readlink (relname, linkname, LINK_BUF);
260 if (linklen < 0)
262 error (0, errno, "%s", name);
263 free (linkname);
264 return 0;
266 linkname[linklen] = '\0';
267 return linkname;
269 #endif