###############################################################################
#
# File:         fileutils-3.12.patch
# RCS:          $Header: $
# Description:  complete patch
# Author:       Christian Limpach <chris@nice.ch>
# Created:      Mon Apr  3 20:51:26 1995
# Modified:     Mon Apr  3 21:45:04 1995 (Christian Limpach) chris@nice.ch
# Language:     patch
# Package:      N/A
# Status:       Experimental (Do Not Distribute)
#
# (C) Copyright 1995, Christian Limpach, all rights reserved.
# This is free software, and you are welcome to redistribute it
# under certain conditions; see ftp://nice.ethz.ch/users/chris/TERMS
# for details. This software comes with ABSOLUTELY NO WARRANTY.
#
###############################################################################

# three-times/hidden patches for 3.9 by Marcel Waldvogel
# updated to 3.12
diff -rc /tmp/fileutils-3.12/man/ls.1 fileutils-3.12/man/ls.1
*** /tmp/fileutils-3.12/man/ls.1	Tue Apr 26 22:08:55 1994
--- fileutils-3.12/man/ls.1	Sun Apr  2 00:17:56 1995
***************
*** 187,192 ****
--- 187,208 ----
  .B COLUMNS
  is used if it is set; otherwise the default is 80.
  .TP
+ .I "\-3, \-\-three-times"
+ List all three times in a long format listing, making an entry three
+ lines long, one each for modification (labelled `mod'), inode change
+ (`ino') and access (`acc') time.
+ .TP
+ .I "\-v"
+ Give a very verbose output listing (almost) all information contained
+ in the inode. This is the same as the concatenation of the
+ .IR \-l ,
+ .IR \-s ,
+ .IR \-i ,
+ .IR \-F
+ and
+ .IR \-3
+ options.
+ .TP
  .I "\-T, \-\-tabsize cols"
  Assume that each tabstop is
  .I cols
diff -rc /tmp/fileutils-3.12/src/ls.c fileutils-3.12/src/ls.c
*** /tmp/fileutils-3.12/src/ls.c	Fri Nov  4 06:08:15 1994
--- fileutils-3.12/src/ls.c	Sun Apr  2 00:53:17 1995
***************
*** 117,122 ****
--- 117,125 ----
  static int is_not_dot_or_dotdot ();
  static int length_of_file_name_and_frills ();
  static void add_ignore_pattern ();
+ static void add_hidden_pattern ();
+ static void clear_hidden_patterns ();
+ static void hide_files ();
  static void attach ();
  static void clear_files ();
  static void extract_dirs_from_files ();
***************
*** 276,281 ****
--- 279,288 ----
  
  static int print_block_size;
  
+ /* Nonzero means show all three times (only if long is also selected).  -3  */
+ 
+ static int three_times;
+ 
  /* Nonzero means show file sizes in kilobytes instead of blocks
     (the size of which is system-dependent).  -k */
  
***************
*** 344,349 ****
--- 351,364 ----
  
  static struct ignore_pattern *ignore_patterns;
  
+ /* Same as before, but these are per directory. */
+ 
+ static struct ignore_pattern *hidden_patterns;
+ 
+ /* Nonzero means hide files listed in .hidden.  -h  */
+ 
+ static int ignore_from_dot_hidden;
+ 
  /* Nonzero means quote nongraphic chars in file names.  -b  */
  
  static int quote_funny_chars;
***************
*** 400,405 ****
--- 415,421 ----
    {"directory", no_argument, 0, 'd'},
    {"dired", no_argument, 0, 'D'},
    {"full-time", no_argument, &full_time, 1},
+   {"hidden", no_argument, 0, 'h'},
    {"inode", no_argument, 0, 'i'},
    {"kilobytes", no_argument, 0, 'k'},
    {"numeric-uid-gid", no_argument, 0, 'n'},
***************
*** 421,426 ****
--- 437,443 ----
    {"sort", required_argument, 0, 10},
    {"tabsize", required_argument, 0, 'T'},
    {"time", required_argument, 0, 11},
+   {"three-times", no_argument, 0, '3'},
    {"help", no_argument, &show_help, 1},
    {"version", no_argument, &show_version, 1},
    {0, 0, 0, 0}
***************
*** 698,704 ****
    p = getenv ("TABSIZE");
    tabsize = p ? atoi (p) : 8;
  
!   while ((c = getopt_long (argc, argv, "abcdfgiklmnpqrstuw:xABCDFGI:LNQRST:UX1",
  			   long_options, (int *) 0)) != EOF)
      {
        switch (c)
--- 715,722 ----
    p = getenv ("TABSIZE");
    tabsize = p ? atoi (p) : 8;
  
!   while ((c = getopt_long (argc, argv,
!                            "abcdfghiklmnpqrstuvw:xABCDFGI:LNQRST:UX13",
  			   long_options, (int *) 0)) != EOF)
      {
        switch (c)
***************
*** 739,744 ****
--- 757,767 ----
  	  /* No effect.  For BSD compatibility. */
  	  break;
  
+ 	case 'h':
+ 	  /* Interprete the .hidden files. */
+ 	  ignore_from_dot_hidden = 1;
+ 	  break;
+ 
  	case 'i':
  	  print_inode = 1;
  	  break;
***************
*** 784,789 ****
--- 807,821 ----
  	  time_type = time_atime;
  	  break;
  
+ 	case 'v':
+ 	  /* Same as enabling -l, -i, -s, -F, and -3 */
+ 	  format = long_format;
+ 	  print_inode = 1;
+ 	  print_block_size = 1;
+ 	  three_times = 1;
+ 	  indicator_style = all;
+ 	  break;
+ 
  	case 'w':
  	  line_length = atoi (optarg);
  	  if (line_length < 1)
***************
*** 864,869 ****
--- 896,905 ----
  	  format = one_per_line;
  	  break;
  
+ 	case '3':
+ 	  three_times = 1;
+ 	  break;
+ 
  	case 10:		/* +sort */
  	  i = argmatch (optarg, sort_args);
  	  if (i < 0)
***************
*** 952,957 ****
--- 988,996 ----
  
    clear_files ();
  
+   if (ignore_from_dot_hidden)
+     hide_files (name);
+ 
    while ((next = readdir (reading)) != NULL)
      if (file_interesting (next))
        total_blocks += gobble_file (next->d_name, 0, name);
***************
*** 1016,1021 ****
--- 1055,1148 ----
    ignore_patterns = ignore;
  }
  
+ /* The same as before, but add it to the hidden_patterns list after having
+    copied the string.   */
+ 
+ static void
+ add_hidden_pattern (pattern)
+      char *pattern;
+ {
+   register struct ignore_pattern *hidden;
+   
+   hidden = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
+   hidden->pattern = xstrdup (pattern);
+   /* Add it to the head of the linked list. */
+   hidden->next = hidden_patterns;
+   hidden_patterns = hidden;
+ }
+ 
+ /* Removes all entries from the list of hidden patterns, freeing the
+    patterns also.   */
+ 
+ static void
+ clear_hidden_patterns ()
+ {
+   register struct ignore_pattern *hidden, *next;
+  
+   hidden = hidden_patterns;
+   hidden_patterns = NULL;
+  
+   while (hidden != NULL)
+   {
+     next = hidden->next;
+     free(hidden->pattern);
+     free(hidden);
+     hidden = next;
+   }
+ }
+ 
+ /* Add all files from .hidden in the current directory (if it exists)
+    to the hidden_patterns list, after clearing it first.   */
+ 
+ static void
+ hide_files (dirname)
+      char *dirname;
+ {
+   register char *path, *line;
+   int linesize, length, offset;
+   FILE *hidden;
+   clear_hidden_patterns ();
+  
+   path = (char *) xmalloc (strlen (dirname) + sizeof (".hidden") + 2);
+   attach (path, dirname, ".hidden");
+   hidden = fopen (path, "r");
+   if (hidden != NULL)
+   {
+     /* If there was an error while opening, we just ignore it */
+     /* Start at 32 chars per line and double each time it isn't enough */
+     linesize = 32;
+     offset = 0;
+     line = (char *) xmalloc (linesize);
+    
+     while (!feof (hidden))
+     {
+       if (fgets (line + offset, linesize - offset, hidden) == NULL)
+         break;        /* We got to the file end */
+       length = strlen(line);
+       if (length == 0) /* Should not happen */
+         break;
+       if (line[length - 1] != '\n')
+       {
+         /* There wasn't enough space in the buffer, we make it twice as big
+          and append the rest by trying again.  */
+       offset = length;
+       linesize *= 2;
+       line = (char *) xrealloc (line, linesize);
+       }
+       else
+       {
+         /* Add the line to the pattern space */
+         line[length - 1] = '\0';
+       add_hidden_pattern (line);
+       offset = 0;
+       }
+     }
+     free (line);
+     fclose (hidden);
+   }
+   free (path);
+ }
+ 
  /* Return nonzero if the file in `next' should be listed. */
  
  static int
***************
*** 1028,1033 ****
--- 1155,1163 ----
      if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
        return 0;
  
+   for (ignore = hidden_patterns; ignore; ignore = ignore->next)
+     if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
+       return 0;
    if (really_all_files
        || next->d_name[0] != '.'
        || (all_files
***************
*** 1516,1521 ****
--- 1646,1682 ----
      }
  }
  
+ static char *
+ fill_time(timebuf, when)
+     char *timebuf;
+     time_t when;
+ {
+   strcpy (timebuf, ctime (&when));
+ 
+   if (full_time)
+     timebuf[24] = '\0';
+   else
+     {
+       if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
+ 	  || current_time < when - 60L * 60L) /* In the future. */
+ 	{
+ 	  /* The file is fairly old or in the future.
+ 	     POSIX says the cutoff is 6 months old;
+ 	     approximate this by 6*30 days.
+ 	     Allow a 1 hour slop factor for what is considered "the future",
+ 	     to allow for NFS server/client clock disagreement.
+ 	     Show the year instead of the time of day.  */
+ 	  strcpy (timebuf + 11, timebuf + 19);
+ 	}
+       timebuf[16] = 0;
+     }
+   
+   if (full_time)
+     return timebuf;
+   else
+     return timebuf+4;
+ }
+ 
  static void
  print_long_format (f)
       struct fileinfo *f;
***************
*** 1531,1573 ****
    char bigbuf[7 * 20 + 10 + 24 + 9 + 1];
    char *p;
    time_t when;
  
    mode_string (f->stat.st_mode, modebuf);
    modebuf[10] = '\0';
  
!   switch (time_type)
!     {
!     case time_ctime:
!       when = f->stat.st_ctime;
!       break;
!     case time_mtime:
!       when = f->stat.st_mtime;
!       break;
!     case time_atime:
!       when = f->stat.st_atime;
!       break;
!     }
! 
!   strcpy (timebuf, ctime (&when));
! 
!   if (full_time)
!     timebuf[24] = '\0';
    else
      {
!       if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
! 	  || current_time < when - 60L * 60L) /* In the future. */
! 	{
! 	  /* The file is fairly old or in the future.
! 	     POSIX says the cutoff is 6 months old;
! 	     approximate this by 6*30 days.
! 	     Allow a 1 hour slop factor for what is considered "the future",
! 	     to allow for NFS server/client clock disagreement.
! 	     Show the year instead of the time of day.  */
! 	  strcpy (timebuf + 11, timebuf + 19);
! 	}
!       timebuf[16] = 0;
      }
! 
    p = bigbuf;
  
    if (print_inode)
--- 1692,1720 ----
    char bigbuf[7 * 20 + 10 + 24 + 9 + 1];
    char *p;
    time_t when;
+   int len = 0;	/* indention to the mod field when printing three-times */
  
    mode_string (f->stat.st_mode, modebuf);
    modebuf[10] = '\0';
  
!   if (three_times)
!     when = f->stat.st_mtime;
    else
      {
!       switch (time_type)
!         {
!         case time_ctime:
!           when = f->stat.st_ctime;
!           break;
!         case time_mtime:
!           when = f->stat.st_mtime;
!           break;
!         case time_atime:
!           when = f->stat.st_atime;
!           break;
!         }
      }
!   
    p = bigbuf;
  
    if (print_inode)
***************
*** 1611,1617 ****
      sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
    p += strlen (p);
  
!   sprintf (p, "%s ", full_time ? timebuf : timebuf + 4);
    p += strlen (p);
  
    DIRED_INDENT ();
--- 1758,1771 ----
      sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
    p += strlen (p);
  
!   if (three_times)
!     {
!       len = p - bigbuf;
!       sprintf (p, "mod ");
!       p += strlen (p);
!     }
!   
!   sprintf (p, "%s ", fill_time(timebuf, when));
    p += strlen (p);
  
    DIRED_INDENT ();
***************
*** 1632,1637 ****
--- 1786,1804 ----
      }
    else if (indicator_style != none)
      print_type_indicator (f->stat.st_mode);
+ 
+   if (three_times)
+     {
+       /* terminate current line and print additional two lines */
+       putchar('\n');
+       indent(0, len);
+       DIRED_INDENT ();
+       printf("ino %s", fill_time(timebuf, f->stat.st_ctime));
+       putchar('\n');
+       indent(0, len);
+       DIRED_INDENT ();
+       printf("acc %s", fill_time(timebuf, f->stat.st_atime));
+     }
  }
  
  
***************
*** 2126,2131 ****
--- 2293,2299 ----
        printf ("\
    -G, --no-group             inhibit display of group information\n\
    -g                         (ignored)\n\
+   -h, --hidden               don't show files listed in the .hidden file\n\
    -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN\n\
    -i, --inode                print index number of each file\n\
    -k, --kilobytes            use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
***************
*** 2154,2159 ****
--- 2322,2328 ----
    -x                         list entries by lines instead of by columns\n\
    -X                         sort alphabetically by entry extension\n\
    -1                         list one file per line\n\
+   -3, --three-times          list all three times in a long format listing\n\
        --help                 display this help and exit\n\
        --version              output version information and exit\n\
  \n\
diff -rc /tmp/fileutils-3.12/src/system.h fileutils-3.12/src/system.h
*** /tmp/fileutils-3.12/src/system.h	Thu Oct 20 15:54:43 1994
--- fileutils-3.12/src/system.h	Sun Apr  2 00:52:04 1995
***************
*** 127,133 ****
  #endif
  #undef HAVE_MAJOR
  
! #ifdef HAVE_UTIME_H
  #include <utime.h>
  #else
  struct utimbuf
--- 127,133 ----
  #endif
  #undef HAVE_MAJOR
  
! #if defined(HAVE_UTIME_H) && !defined(NeXT)
  #include <utime.h>
  #else
  struct utimbuf
