home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3107 / dls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-22  |  11.3 KB  |  454 lines

  1. /* dls.c -    Descriptive ls
  2.  *
  3.  * Copyright (c) 1991 Tim Cook.
  4.  * Non-profit distribution allowed.  See README for details.
  5.  */
  6.  
  7. static char rcsid[] = "$Header: dls.c 1.0 91/03/22 $" ;
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <sys/types.h>
  12. #include <sys/param.h>
  13. #include <sys/dir.h>
  14. #include <sys/stat.h>
  15. #include <sys/file.h>
  16. #include <sys/time.h>
  17. #ifdef NDBM
  18. #include <ndbm.h>
  19. #else
  20. #if defined(sequent) && defined(NULL)
  21. #undef NULL
  22. #endif
  23. #include <dbm.h>
  24. #endif
  25.  
  26. #include <vclib.h>
  27. #include <list.h>
  28.  
  29. #define UID_TYPE    unsigned short
  30. #define GID_TYPE    unsigned short
  31.  
  32. extern time_t time () ;
  33. extern void *smalloc () ;
  34. extern int getuid () ;
  35. extern int getgroups () ;
  36.  
  37. extern char *optarg ;
  38. extern int optind, opterr ;
  39.  
  40. #define NULL_CP    ((char *) 0)
  41. #define EOS    '\0'
  42.  
  43. static struct file_info {
  44.    char *name ;
  45.    ino_t inode ;
  46.    u_short mode ;
  47.    short nlink ;
  48.    off_t size ;
  49.    time_t mtime ;
  50.    } ;
  51.  
  52. /* options */
  53. static int show_date = FALSE ;
  54. static int sort_by_date = FALSE ;
  55. static int even_inaccessible = FALSE ;
  56. static int filename_columns = 14 ;
  57.  
  58. /* other globals */
  59. #ifdef NDBM
  60. static DBM *desc_database ;
  61. #endif
  62. static time_t six_months_ago ;
  63. static struct file_info not_there ;    /* Symbolic value */
  64. static int name_and_size_columns ;
  65. static int space = FALSE ;        /* If TRUE, we need to print a blank
  66.                        line before anything else */
  67. static int printed_anything = FALSE ;
  68. static int uid ;
  69. static int no_groups ;
  70. static int groups[NGROUPS] ;
  71.  
  72. static void *get_element_from_argv () ;
  73. static void build_and_sort_list () ;
  74. static struct file_info *get_file_info () ;
  75. static void list_file () ;
  76. static void list_directory () ;
  77.  
  78.  
  79. int main (argc, argv)
  80.    int argc ;
  81.    char **argv ;
  82. {
  83.    int option ;
  84.    struct list file_list ;
  85.    struct file_info *file_info ;
  86.  
  87.    opterr = 0 ;
  88.    while ((option = getopt (argc, argv, "detf:")) != EOF) {
  89.       switch ((char) option) {
  90.          case 'd' :
  91.         show_date = TRUE ; break ;
  92.          case 'e' :
  93.         even_inaccessible = TRUE ; break ;
  94.          case 't' :
  95.         sort_by_date = TRUE ; break ;
  96.          case 'f' :
  97.         filename_columns = atoi (optarg) ; break ;
  98.      case '?' :
  99.             break ; } }
  100.  
  101.    name_and_size_columns = filename_columns + 8 ;
  102.  
  103.    if (show_date)
  104.       six_months_ago = time ((time_t *) 0) - (182 * 24 * 60 * 60) ;
  105.  
  106.    if (! even_inaccessible) {
  107.       uid = (UID_TYPE) getuid () ;
  108.       no_groups = getgroups (NGROUPS, groups) ; }
  109.  
  110.    if (optind - argc == 0) {
  111.       list_directory (".", FALSE) ;
  112. #ifdef NDBM
  113.       dbm_close (desc_database) ;
  114. #else
  115.       dbmclose () ;
  116. #endif
  117.       exit (0) ; }
  118.  
  119.    list_init (&file_list) ;
  120.    build_and_sort_list (&file_list, get_element_from_argv, (char *) argv,
  121.       (char *) &optind) ;
  122.  
  123.    while ((file_info = get_file_info (&file_list))
  124.       != (struct file_info *) NULL) {
  125.       if (file_info != ¬_there) {
  126.      if (file_info->mode & S_IFDIR)
  127.         list_directory (file_info->name, TRUE) ;
  128.      else {
  129.         list_file (file_info, FALSE) ; } } }
  130.    }
  131.  
  132.  
  133. static
  134. void *get_element_from_argv (param_1, param_2)
  135.    char *param_1, *param_2 ;
  136. {
  137.    int *argc ;
  138.    char **argv ;
  139.  
  140.    argv = (char **) param_1 ;
  141.    argc = (int *) param_2 ;
  142.    return (void *) argv[(*argc)++] ;
  143.    }
  144.  
  145.  
  146. static
  147. int file_info_date_cmp (info_1, info_2)
  148.    struct file_info **info_1, **info_2 ;
  149. {
  150.    return (int) ((*info_2)->mtime - (*info_1)->mtime) ;
  151.    }
  152.  
  153.  
  154. static
  155. int compare_str (str_1, str_2)
  156.    char **str_1, **str_2 ;
  157. {
  158.    return strcmp (*str_1, *str_2) ;
  159.    }
  160.  
  161.  
  162. static
  163. void build_and_sort_list (file_list, get_element, param_1, param_2)
  164.    struct list *file_list ;
  165.    void * (*get_element) () ;
  166.    char *param_1, *param_2 ;
  167. {
  168.    struct stat file_status ;
  169.    struct file_info *file_info ;
  170.    char *name ;
  171.  
  172.    if (sort_by_date) {
  173.       while ((name = (char *) get_element (param_1, param_2)) != NULL_CP) {
  174.      if (stat (name, &file_status) == -1)
  175.         perror (name) ;
  176.      else {
  177.         file_info =
  178.            (struct file_info *) smalloc (sizeof (struct file_info)) ;
  179.         file_info->name = name ;
  180.         file_info->inode = file_status.st_ino ;
  181.         file_info->mode = file_status.st_mode ;
  182.         file_info->nlink = file_status.st_nlink ;
  183.         file_info->size = file_status.st_size ;
  184.         file_info->mtime = file_status.st_mtime ;
  185.         list_push (file_list, (void *) file_info) ; } }
  186.       list_sort (file_list, file_info_date_cmp) ; }
  187.  
  188.    else {    /* Sort by name */
  189.       while ((name = (char *) get_element (param_1, param_2)) != NULL_CP) {
  190.      list_push (file_list, (void *) name) ; }
  191.       list_sort (file_list, compare_str) ; }
  192.    }
  193.  
  194.  
  195. static
  196. struct file_info *get_file_info (file_list)
  197.    struct list *file_list ;
  198. {
  199.    static struct file_info file_info ;
  200.    static struct stat status ;    /* Tongue twister */
  201.    char *name ;
  202.    int listable ;
  203.    int n ;
  204.  
  205.    if (sort_by_date)
  206.       return (struct file_info *) list_shift (file_list) ;
  207.    else {
  208.       name = (char *) list_shift (file_list) ;
  209.       if (name == (char *) NULL)
  210.      return (struct file_info *) NULL ;
  211.       else
  212.     if (stat (name, &status) == -1) {
  213.        perror (name) ;
  214.        return ¬_there ; }
  215.     else {
  216.        if (! even_inaccessible) {
  217.           if (status.st_uid == (UID_TYPE) uid)
  218.          listable = status.st_mode & 0500 ;
  219.           else {
  220.          for (n = 0 ; n < no_groups ; n++) {
  221.             if (status.st_gid == (GID_TYPE) groups[n]) {
  222.                listable = status.st_mode & 050 ;
  223.                n = no_groups + 1 ; } }
  224.          if (n == no_groups)
  225.             listable = status.st_mode & 05 ; } }
  226.        else
  227.           listable = TRUE ;
  228.        if (! listable)
  229.           return ¬_there ;
  230.        else {
  231.           file_info.name = name ;
  232.           file_info.inode = status.st_ino ;
  233.           file_info.mode = status.st_mode ;
  234.           file_info.nlink = status.st_nlink ;
  235.           file_info.size = status.st_size ;
  236.           file_info.mtime = status.st_mtime ;
  237.           return &file_info ; } } }
  238.    }
  239.  
  240.  
  241. static void *get_element_from_dir () ;
  242.  
  243.  
  244. static
  245. void list_directory (name, show_directory)
  246.    char *name ;
  247.    int show_directory ;
  248. {
  249.    DIR *directory ;
  250.    struct list file_list ;
  251.    struct file_info *file_info ;
  252.  
  253.    space = FALSE ;
  254.    if (show_directory) {
  255.       if (printed_anything) {
  256.      printc ('\n') ; }
  257.       printf ("%s:\n", name) ;
  258.       printed_anything = TRUE ; }
  259.  
  260.    if ((directory = opendir (name)) == (DIR *) NULL) {
  261.       perror (name) ; }
  262.    else {
  263.       list_init (&file_list) ;
  264.       build_and_sort_list (&file_list, get_element_from_dir,
  265.      (char *) directory, name) ;
  266.       while ((file_info = get_file_info (&file_list))
  267.          != (struct file_info *) NULL) {
  268.      if (file_info != ¬_there)
  269.         list_file (file_info, TRUE) ; }
  270.       list_free (&file_list) ;
  271.       closedir (directory) ; }
  272.    space = TRUE ;
  273.    }
  274.  
  275.  
  276. static
  277. void *get_element_from_dir (param_1, param_2)
  278.    char *param_1 ;
  279.    char *param_2 ;
  280. {
  281.    char *p ;
  282.    struct direct *dir_entry ;
  283.    int n ;
  284.  
  285.    for (dir_entry = readdir ((DIR *) param_1) ;
  286.         dir_entry != (struct direct *) NULL && dir_entry->d_name[0] == '.' ;
  287.     dir_entry = readdir ((DIR *) param_1)) ;
  288.    if (dir_entry == (struct direct *) NULL)
  289.       return (void *) NULL ;
  290.  
  291.    n = strlen ((char *) param_2) + dir_entry->d_namlen + 2 ;
  292.    p = (char *) smalloc ((size_t) n) ;
  293.    strcpy (p, (char *) param_2) ;
  294.    strcat (p, "/") ;
  295.    strncat (p, dir_entry->d_name, dir_entry->d_namlen) ;
  296.    p[n] = EOS ;
  297.    return (void *) p ;
  298.    }
  299.  
  300.  
  301. static
  302. char *get_description (pathname, inode_ptr)
  303.    char *pathname ;
  304.    ino_t *inode_ptr ;
  305. {
  306.    static char desc_file[MAXNAMLEN+1] = "" ;
  307.    static char new_desc_file[MAXNAMLEN+1] ;
  308.    static char file_name[MAXNAMLEN+1] ;
  309.    static datum key, value ;
  310.    static int no_desc_file = TRUE ;
  311.    static int desc_not_found ;
  312.    struct stat status ;
  313.    char *p ;
  314.  
  315.    split_pathname (pathname, new_desc_file, file_name) ;
  316.  
  317.    if (no_desc_file || strcmp (new_desc_file, desc_file) != 0) {
  318.       strcpy (desc_file, new_desc_file) ;
  319.       if (*new_desc_file != EOS)
  320.      strcat (new_desc_file, "/") ;
  321. #ifdef NDBM
  322.       strcat (new_desc_file, ".desc") ;
  323.       dbm_close (desc_database) ;
  324.       if ((desc_database = dbm_open (new_desc_file, O_RDONLY, 0))
  325.             == (DBM *) NULL)
  326.      desc_not_found = TRUE ;
  327.       else
  328.      no_desc_file = desc_not_found = FALSE ;
  329. #else
  330.       strcat (new_desc_file, ".desc.pag") ;
  331.       dbmclose () ;
  332.       no_desc_file = TRUE ;
  333.       /* Check this ourselves to prevent dbm from complaining */
  334.       if (stat (new_desc_file, &status) == 0) {
  335.      p = strrchr (new_desc_file, '.') ;
  336.      *p = EOS ;
  337.      dbminit (new_desc_file) ;
  338.          no_desc_file = desc_not_found = FALSE ; }
  339.       else {
  340.          desc_not_found = TRUE ; }
  341. #endif    /* NDBM */
  342.       }
  343.    if (desc_not_found) {
  344.       return NULL_CP ; }
  345.    else {
  346.       /* Check for it by name */
  347.       key.dptr = file_name ;
  348.       key.dsize = strlen (file_name) ;
  349.       if (key.dsize == sizeof (ino_t))
  350.      key.dsize++ ;
  351. #ifdef NDBM
  352.       value = dbm_fetch (desc_database, key) ;
  353. #else
  354.       value = fetch (key) ;
  355. #endif
  356.       if (value.dptr == NULL_CP) {
  357.      /* Check for it by inode */
  358.      key.dptr = (char *) inode_ptr ;
  359.      key.dsize = sizeof (ino_t) ;
  360. #ifdef NDBM
  361.      value = dbm_fetch (desc_database, key) ;
  362. #else
  363.      value = fetch (key) ;
  364. #endif
  365.      if (value.dptr != NULL_CP) {
  366.         /* Now use the name we got using the inode */
  367.         key.dptr = value.dptr ;
  368.         key.dsize = value.dsize ;
  369. #ifdef NDBM
  370.         value = dbm_fetch (desc_database, key) ;
  371. #else
  372.         value = fetch (key) ;
  373. #endif
  374.         } }
  375.       return (char *) value.dptr ; }
  376.    }
  377.       
  378.  
  379.  
  380. static
  381. void list_file (file_info, doing_directory)
  382.    struct file_info *file_info ;
  383.    int doing_directory ;
  384. {
  385.    static char month[][12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  386.       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
  387.    char *p ;
  388.    static char file_name[MAXNAMLEN+1] ;
  389.    char *desc ;
  390.    static char size[12] ;
  391.    static char date[16] ;
  392.    int name_len, size_len, gap ;
  393.    struct tm *tm_time ;
  394.  
  395.    strcpy (file_name, file_info->name) ;
  396.    p = file_name ;
  397.    if (! doing_directory && p[0] == '.' && p[1] == '/' && p[2] != EOS)
  398.       p += 2 ;
  399.    desc = get_description (p, &(file_info->inode)) ;
  400.    if (doing_directory)
  401.       p = strrchr (p, '/') + 1 ;
  402.  
  403.    name_len = strlen (p) ;
  404.    /* If it is a directory, make it obvious */
  405.    if (file_info->mode & S_IFDIR) {
  406.       strcat (p, "/") ;
  407.       name_len++ ;
  408.       size[1] = EOS ;
  409.       size_len = 1 ;
  410.       if (file_info->nlink > 2) {    /* Denotes a directory that contains */
  411.      size[0] = '=' ; }        /* one or more sub-directories */
  412.       else {
  413.      size[0] = '-' ; } }
  414.    else {
  415.       sprintf (size, "%d", file_info->size) ;
  416.       size_len = strlen (size) ; }
  417.    if (name_len + size_len < name_and_size_columns)
  418.       gap = name_and_size_columns - name_len ;
  419.    else {
  420.       print (p) ;
  421.       p[0] = '\n' ; p[1] = EOS ;
  422.       gap = name_and_size_columns ; }
  423.    if (show_date) {
  424.       tm_time = localtime (&file_info->mtime) ;
  425.       if (six_months_ago > file_info->mtime) {
  426.      /* The bloody thing is more than 6 months old! */
  427. #ifdef US_DATE_FORMAT
  428.      sprintf (date, " %s %2d  %d ", month[tm_time->tm_mon],
  429.         tm_time->tm_mday, tm_time->tm_year + 1900) ;
  430. #else
  431.      sprintf (date, " %2d %s  %d ", tm_time->tm_mday,
  432.         month[tm_time->tm_mon], tm_time->tm_year + 1900) ;
  433. #endif
  434.          }
  435.       else {
  436. #ifdef US_DATE_FORMAT
  437.      sprintf (date " %s %2d %02d:%02d ", month[tm_time->tm_mon],
  438.         tm_time->tm_mday, tm_time->tm_hour, tm_time->tm_min) ;
  439. #else
  440.      sprintf (date, " %2d %s %02d:%02d ", tm_time->tm_mday,
  441.          month[tm_time->tm_mon], tm_time->tm_hour, tm_time->tm_min) ;
  442. #endif
  443.       } }
  444.    else {
  445.       date[0] = ' ' ;
  446.       date[1] = EOS ; }
  447.  
  448.    if (space) {
  449.       printc ('\n') ;
  450.       space = FALSE ; }
  451.    printf ("%s %*s%s %s\n", p, gap, size, date, desc) ;
  452.    printed_anything = TRUE ;
  453.    }
  454.