home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / A / FIND / FINDUTIL.1 / FINDUTIL / findutils-4.1 / lib / listfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-02  |  6.3 KB  |  274 lines

  1. /* listfile.c -- display a long listing of a file
  2.    Copyright (C) 1991, 1993 Free Software Foundation, Inc.
  3.  
  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.
  8.  
  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.
  13.  
  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.  */
  17.  
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21.  
  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"
  30.  
  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. char *getenv ();
  40. extern int errno;
  41. #endif
  42.  
  43. /* Since major is a function on SVR4, we can't use `ifndef major'.  */
  44. #ifdef MAJOR_IN_MKDEV
  45. #include <sys/mkdev.h>
  46. #define HAVE_MAJOR
  47. #endif
  48. #ifdef MAJOR_IN_SYSMACROS
  49. #include <sys/sysmacros.h>
  50. #define HAVE_MAJOR
  51. #endif
  52.  
  53. #ifdef STAT_MACROS_BROKEN
  54. #undef S_ISCHR
  55. #undef S_ISBLK
  56. #undef S_ISLNK
  57. #endif
  58.  
  59. #ifndef S_ISCHR
  60. #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
  61. #endif
  62. #ifndef S_ISBLK
  63. #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
  64. #endif
  65. #if defined(S_IFLNK) && !defined(S_ISLNK)
  66. #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  67. #endif
  68.  
  69. #if defined(S_ISLNK)
  70. int readlink ();
  71. #endif
  72.  
  73. /* Extract or fake data from a `struct stat'.
  74.    ST_NBLOCKS: Number of 512-byte blocks in the file
  75.    (including indirect blocks).
  76.    HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
  77.    This workaround loses when mixing HP-UX and 4BSD filesystems, though.  */
  78. #ifdef _POSIX_SOURCE
  79. # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
  80. #else
  81. # ifndef HAVE_ST_BLOCKS
  82. #  define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
  83. # else
  84. #  if defined(hpux) || defined(__hpux__)
  85. #   define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
  86. #  else
  87. #   define ST_NBLOCKS(statp) ((statp)->st_blocks)
  88. #  endif
  89. # endif
  90. #endif
  91.  
  92. /* Convert B 512-byte blocks to kilobytes if K is nonzero,
  93.    otherwise return it unchanged. */
  94. #define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b))
  95.  
  96. #ifndef _POSIX_VERSION
  97. struct passwd *getpwuid ();
  98. struct group *getgrgid ();
  99. #endif
  100.  
  101. #ifdef major            /* Might be defined in sys/types.h.  */
  102. #define HAVE_MAJOR
  103. #endif
  104. #ifndef HAVE_MAJOR
  105. #define major(dev)  (((dev) >> 8) & 0xff)
  106. #define minor(dev)  ((dev) & 0xff)
  107. #endif
  108. #undef HAVE_MAJOR
  109.  
  110. char *xmalloc ();
  111. void error ();
  112. void mode_string ();
  113.  
  114. char *get_link_name ();
  115. char *getgroup ();
  116. char *getuser ();
  117. void print_name_with_quoting ();
  118.  
  119. /* NAME is the name to print.
  120.    RELNAME is the path to access it from the current directory.
  121.    STATP is the results of stat or lstat on it.
  122.    STREAM is the stdio stream to print on.  */
  123.  
  124. void
  125. list_file (name, relname, statp, stream)
  126.      char *name;
  127.      char *relname;
  128.      struct stat *statp;
  129.      FILE *stream;
  130. {
  131.   static int kilobytes = -1;    /* -1 = uninitialized, 0 = 512, 1 = 1024. */
  132.   char modebuf[20];
  133.   char timebuf[40];
  134.   time_t current_time = time ((time_t *) 0);
  135.  
  136.   if (kilobytes == -1)
  137.     kilobytes = getenv ("POSIXLY_CORRECT") == 0;
  138.  
  139.   mode_string (statp->st_mode, modebuf);
  140.   modebuf[10] = '\0';
  141.  
  142.   strcpy (timebuf, ctime (&statp->st_mtime));
  143.   if (current_time > statp->st_mtime + 6L * 30L * 24L * 60L * 60L /* Old. */
  144.       || current_time < statp->st_mtime - 60L * 60L) /* In the future. */
  145.     {
  146.       /* The file is fairly old or in the future.
  147.      POSIX says the cutoff is 6 months old;
  148.      approximate this by 6*30 days.
  149.      Allow a 1 hour slop factor for what is considered "the future",
  150.      to allow for NFS server/client clock disagreement.
  151.      Show the year instead of the time of day.  */
  152.       strcpy (timebuf + 11, timebuf + 19);
  153.     }
  154.   timebuf[16] = 0;
  155.  
  156.   fprintf (stream, "%6lu ", statp->st_ino);
  157.  
  158.   fprintf (stream, "%4u ", convert_blocks (ST_NBLOCKS (statp), kilobytes));
  159.  
  160.   /* The space between the mode and the number of links is the POSIX
  161.      "optional alternate access method flag". */
  162.   fprintf (stream, "%s %3u ", modebuf, statp->st_nlink);
  163.  
  164.   fprintf (stream, "%-8.8s ", getuser (statp->st_uid));
  165.  
  166.   fprintf (stream, "%-8.8s ", getgroup (statp->st_gid));
  167.  
  168.   if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
  169. #ifdef HAVE_ST_RDEV
  170.     fprintf (stream, "%3u, %3u ", major (statp->st_rdev), minor (statp->st_rdev));
  171. #else
  172.     fprintf (stream, "         ");
  173. #endif
  174.   else
  175.     fprintf (stream, "%8lu ", statp->st_size);
  176.  
  177.   fprintf (stream, "%s ", timebuf + 4);
  178.  
  179.   print_name_with_quoting (name, stream);
  180.  
  181. #ifdef S_ISLNK
  182.   if (S_ISLNK (statp->st_mode))
  183.     {
  184.       char *linkname = get_link_name (name, relname);
  185.  
  186.       if (linkname)
  187.     {
  188.       fputs (" -> ", stream);
  189.       print_name_with_quoting (linkname, stream);
  190.       free (linkname);
  191.     }
  192.     }
  193. #endif
  194.   putc ('\n', stream);
  195. }
  196.  
  197. void
  198. print_name_with_quoting (p, stream)
  199.      register char *p;
  200.      FILE *stream;
  201. {
  202.   register unsigned char c;
  203.  
  204.   while ((c = *p++) != '\0')
  205.     {
  206.       switch (c)
  207.     {
  208.     case '\\':
  209.       fprintf (stream, "\\\\");
  210.       break;
  211.  
  212.     case '\n':
  213.       fprintf (stream, "\\n");
  214.       break;
  215.  
  216.     case '\b':
  217.       fprintf (stream, "\\b");
  218.       break;
  219.  
  220.     case '\r':
  221.       fprintf (stream, "\\r");
  222.       break;
  223.  
  224.     case '\t':
  225.       fprintf (stream, "\\t");
  226.       break;
  227.  
  228.     case '\f':
  229.       fprintf (stream, "\\f");
  230.       break;
  231.  
  232.     case ' ':
  233.       fprintf (stream, "\\ ");
  234.       break;
  235.  
  236.     case '"':
  237.       fprintf (stream, "\\\"");
  238.       break;
  239.  
  240.     default:
  241.       if (c > 040 && c < 0177)
  242.         putc (c, stream);
  243.       else
  244.         fprintf (stream, "\\%03o", (unsigned int) c);
  245.     }
  246.     }
  247. }
  248.  
  249. #ifdef S_ISLNK
  250. char *
  251. get_link_name (name, relname)
  252.      char *name;
  253.      char *relname;
  254. {
  255.   register char *linkname;
  256.   register int linklen;
  257.  
  258.   /* st_size is wrong for symlinks on AIX, and on
  259.      mount points with some automounters.
  260.      So allocate a pessimistic PATH_MAX + 1 bytes.  */
  261. #define LINK_BUF PATH_MAX
  262.   linkname = (char *) xmalloc (LINK_BUF + 1);
  263.   linklen = readlink (relname, linkname, LINK_BUF);
  264.   if (linklen < 0)
  265.     {
  266.       error (0, errno, "%s", name);
  267.       free (linkname);
  268.       return 0;
  269.     }
  270.   linkname[linklen] = '\0';
  271.   return linkname;
  272. }
  273. #endif
  274.