home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / pd / part01 / pd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-31  |  48.8 KB  |  1,348 lines

  1. /**************************************************************************
  2.  
  3.  N O T I C E :   Copyright 1991,1992,1993 (c) Scott Fehrman
  4.                  
  5.                  This program and it's related documents may be distributed
  6.                  and/or copied without charge. The related source code and 
  7.                  executable files may be used freely providing that all 
  8.                  copyright notices and information about the author and 
  9.                  company are not removed or altered in any manner. The users
  10.                  of this program and it's related documents understand that 
  11.                  this material is provided "as is" with no warranty. The 
  12.                  author and/or company are not responsible for any 
  13.                  "side effects" and/or problems that this material may have
  14.                  on system and/or application files and data. The use of this
  15.                  program and it's related material implies that the user 
  16.                  understands the terms and conditions for which it is provided.
  17.  
  18.       Program:   pd.c
  19.  
  20.        Author:   Scott L. Fehrman, Systems Engineer
  21.                  Sun Microsystems Computer Corporation
  22.                  Two Pierce Place
  23.                  Suite 1500
  24.                  Itasca, IL 60173
  25.                  (708) 285-7632
  26.                  scott.fehrman@Central.Sun.COM
  27.  
  28. ***************************************************************************/
  29.  
  30. /*** include system header files ***/
  31.  
  32. #include <stdio.h>                /* standard unix input/output facilities */
  33. #include <time.h>                 /* file date/time data */
  34. #include <sys/types.h>            /* system types used by <sys/stat.h> */
  35. #include <sys/param.h>            /* machine dependant paramters */
  36. #include <dirent.h>               /* directory entry information */
  37. #include <sys/stat.h>             /* status information about files */
  38. #include <malloc.h>               /* dyn memory allocation */
  39. #include <errno.h>                /* error handling */
  40. #include <pwd.h>                  /* passwd file data */
  41. #include <grp.h>                  /* group file data */
  42.  
  43. /*** define constant variables ***/
  44.  
  45. #define       VERSION  "3.3.1"    /* program revision stamp */
  46. #define  MAX_NAME_LEN  60         /* max character length of a file name */
  47. #define MAX_ERROR_LEN  60         /* max character length of error mess */
  48. #define  SCREEN_WIDTH  80         /* number of characters on screen, max */
  49. #define          TRUE  1          /* define the TRUE value */ 
  50. #define         FALSE  0          /* define the FALSE value */
  51. #define     NUM_BLANK  2          /* blank characters between columns */
  52. #define      ENV_NAME  "PD"       /* environment variable options */
  53. #define    ENTRY_FILE  0         
  54. #define     ENTRY_DIR  1
  55. #define       CMD_DIR  2 
  56.  
  57. /*** define macros if needed ***/
  58.  
  59. #ifndef S_ISDIR
  60. #define    S_ISDIR(m)  (((m)&S_IFMT) == S_IFDIR) /* is a directory */
  61. #endif
  62.  
  63. #ifndef SVR3
  64. #ifndef S_ISLNK
  65. #define    S_ISLNK(m)  (((m)&S_IFMT) == S_IFLNK) /* is symbolic link */
  66. #endif
  67. #endif
  68.  
  69. #ifndef S_ISBLK
  70. #define    S_ISBLK(m)  (((m)&S_IFMT) == S_IFBLK) /* is block device */
  71. #endif
  72.  
  73. #ifndef S_ISCHR
  74. #define    S_ISCHR(m)  (((m)&S_IFMT) == S_IFCHR) /* is char device */
  75. #endif
  76.  
  77. #ifndef major
  78. #define major(dev) (((dev) >> 8) & 0xff)         /* device major # */
  79. #endif
  80.  
  81. #ifndef minor
  82. #define minor(dev) ((dev) & 0xff)                /* device minor # */
  83. #endif
  84.  
  85. /*** function prototypes ***/
  86.  
  87. int  open_directory();            /* open the directory */
  88. int  sort_name();                 /* func for qsort() by file name, default */
  89. int  sort_date_modified();        /* func for qsort() by date modified */
  90. int  sort_size();                 /* func for qsort() by file size */
  91. int  sort_rev_name();             /* func for qsort() by file name, reverse */
  92. int  sort_rev_date_modified();    /* func for qsort() by date modified, rev */
  93. int  sort_rev_size();             /* func for qsort() by file size, rev */
  94. void entry_store();               /* store entry in ptr array */
  95. void entry_release();             /* release allocated memory for arrays */
  96. void process_cmd_dir();           /* process the dirs on command line */
  97. void process_cmd_file();          /* process the files on command line */
  98. void command_option();            /* command line option */
  99. void process_directory();         /* process the opened directory */
  100. void display_header();            /* print header data (pathname) */
  101. void read_directory();            /* read the files in the open directory */
  102. void close_directory();           /* close the directory */
  103. void display_directory();         /* display directory as "n" columns */
  104. void display_expanded();          /* display entry in expanded format */
  105. void getenv_option();             /* get any environment options */
  106. void stat_file();                 /* get file status from argument */
  107. void align_column();              /* align output to a specific column */
  108. void repeat_char();               /* repeat a character # of times */
  109. void program_usage();             /* if error, how to use program */
  110. void program_help();              /* help with this program */
  111. void program_version();           /* display version stamp */
  112.  
  113. /*** declare variables ***/
  114.  
  115. typedef struct EntryTag {                     /* struct for entries */
  116.               char szName[MAX_NAME_LEN];      /* entry name */
  117.               int  iSize;                     /* entry size */
  118.               int  iMod;                      /* entry date modified */
  119.               } EntryData;
  120.  
  121. extern char   *getenv();                      /* ptr to external string */
  122.  
  123. EntryData     *File,                          /* ptr to array, files */
  124.               *Dir,                           /* ptr to array, directories */
  125.               *Cmd;                           /* ptr to array, cmd line dirs */
  126.  
  127. char          *szProgName,                    /* program name argv[0] */
  128.               szDirName[MAX_NAME_LEN],        /* dir name argv[0+x] */
  129.               cQtyChar = '.';                 /* qty terminating char */
  130.  
  131. int           iAllocFile = 100,               /* # files to alloc memory */
  132.               iAllocDir = 100,                /* # dirs to alloc memory */
  133.               iAllocCmd = 100,                /* # cmd dirs to alloc memory */
  134.               iReturn,                        /* Return value */
  135.               iCmdFiles = 0,                  /* qty cmd line files */
  136.               iCmdDirs = 0,                   /* qty cmd line dirs */
  137.               iRemoteDir = FALSE,             /* is remote directory */
  138.               iNumFiles,                      /* counter # files */
  139.               iNumDirs,                       /* counter # dirs */
  140.               iNumEntries = 0,                /* counter total entries */
  141.               iLongest,                       /* length of longest name */
  142.               iNumColumns,                    /* # of columns to display */
  143.               iScrWidth = SCREEN_WIDTH,       /* Screen width # columns */
  144.               iSortOptions = 0,               /* qty of sort options */
  145.               iFlagAbort = FALSE,             /* flag, do not run -h, -v */
  146.               iFlagAccessed = FALSE,          /* flag, date/time accessed */
  147.               iFlagAltOutput = FALSE,         /* flag, alternate output */
  148.               iFlagBrief = FALSE,             /* flag, brief output */
  149.               iFlagCount = FALSE,             /* flag, count entries only */
  150.               iFlagDirs = TRUE,               /* flag, show files */
  151.               iFlagDot = TRUE,                /* flag, show files start with .*/
  152.               iFlagFiles = TRUE,              /* flag, show directories */
  153.               iFlagHidden = FALSE,            /* flag, show "." & ".." */
  154.               iFlagHeader = TRUE,             /* flag, show header extn dis */
  155.               iFlagInode = FALSE,             /* flag, show file inode # */
  156.               iFlagLink = FALSE,              /* flag, show link status */
  157.               iFlagLinkCnt = FALSE,           /* flag, show file link count */
  158.               iFlagModified = FALSE,          /* flag, date/time modified */
  159.               iFlagPath = TRUE,               /* flag, show pathname */
  160.               iFlagPro = FALSE,               /* flag, protection data */
  161.               iFlagQty = TRUE,                /* flag, show qty of entries */
  162.               iFlagReverse = FALSE,           /* flag, reverse sort */
  163.               iFlagSingle = FALSE,            /* flag, single column */
  164.               iFlagSize = FALSE,              /* flag, size & owner data */
  165.               iFlagSort = TRUE,               /* flag, sort files -ns */
  166.               iFlagSortModified = FALSE,      /* flag, sort date modified */
  167.               iFlagSortSize = FALSE,          /* flag, sort file size */
  168.               iFlagStatus = FALSE,            /* flag, date/time stat mod */
  169.               iFlagWide = FALSE,              /* flag, wide format 132 col */
  170.               iFilesOnly = FALSE;             /* flag, cmd line, files only */
  171.  
  172. DIR           *dirp;                          /* ptr to dir struct DIR */
  173. struct dirent *filep;                         /* ptr to file struct dirent */
  174. struct stat   stb;                            /* ptr to file status struct */
  175. struct tm     *tmp;                           /* ptr to time/date struct */
  176. struct passwd *passwdp;                       /* ptr to passwd struct */
  177. struct group  *groupp;                        /* ptr to group struct */
  178.  
  179. /**********************************************************************/
  180. int main(argc, argv)
  181. /**********************************************************************
  182.  
  183. main function: "returns an integer"
  184.  
  185.    * check the environment varaible for any program options.
  186.    * allocate an inital amount of memory for storing entries
  187.    * parse the command line: ( we don't care about the order ) 
  188.    * seperate the file/dir names from the options, 
  189.    * for each file, store name in file array
  190.    * for each directory, store name in directory array
  191.    * if no "command-line" files or dirs, add the current dir "." to array
  192.    * if files found, call function to process them
  193.    * if directories found, call function to process them
  194.  
  195. **********************************************************************/
  196. int   argc; 
  197. char *argv[];
  198. {
  199.    register int  t;
  200.    int           iTemp;
  201.    char          szError[MAX_ERROR_LEN], 
  202.                  szOption[MAX_NAME_LEN];
  203.  
  204.    iReturn = 0;
  205.    szProgName = argv[0];
  206.    getenv_option();
  207.  
  208.    File = (EntryData *)malloc((unsigned int)(sizeof(EntryData)*iAllocFile));
  209.    Dir  = (EntryData *)malloc((unsigned int)(sizeof(EntryData)*iAllocDir));
  210.    Cmd  = (EntryData *)malloc((unsigned int)(sizeof(EntryData)*iAllocCmd));
  211.  
  212.    if ( !File || !Dir || !Cmd ) {
  213.       (void)sprintf(szError,"%s: malloc()",szProgName);
  214.       perror(szError);
  215.       exit(TRUE);
  216.    }
  217.  
  218.    for ( t=1 ; t<argc ; t++ ) {
  219.       if ( argv[t][0] == '-' ) {
  220.          (void)strcpy(szOption,++argv[t]);
  221.          command_option(szOption);
  222.       }
  223.       else {
  224.          iRemoteDir = TRUE;
  225.          if ( !iFlagAbort ) {
  226.             if ( stat(argv[t], &stb) < 0 ) {                 /* valid file */
  227. #ifdef SVR3
  228.                iFlagAbort = TRUE;
  229.                iReturn = TRUE;
  230.                (void)sprintf(szError,"%s: %s",szProgName,argv[t]);
  231.                perror(szError);
  232. #else
  233.                if ( lstat(argv[t], &stb) < 0 ) {           /* maybe a link */
  234.                   iFlagAbort = TRUE;
  235.                   iReturn = TRUE;
  236.                   (void)sprintf(szError,"%s: %s",szProgName,argv[t]);
  237.                   perror(szError);
  238.                }
  239.                else {
  240.                   entry_store(ENTRY_FILE,argv[t],
  241.                      (int)stb.st_mtime,(int)stb.st_size,iCmdFiles++);
  242.                }
  243. #endif
  244.             }
  245.             else {                                           /* valid entry */
  246.                if ( S_ISDIR(stb.st_mode) ) {                   /* directory */
  247.                   entry_store(CMD_DIR,argv[t],0,0,iCmdDirs++);
  248.                }
  249.                else {                                               /* file */
  250.                   iTemp = strlen(argv[t]);
  251.                   if ( iTemp > iLongest ) iLongest = iTemp;
  252.                   entry_store(ENTRY_FILE,argv[t],
  253.                      (int)stb.st_mtime,(int)stb.st_size,iCmdFiles++);
  254.                }
  255.             }
  256.          }
  257.       }
  258.    }
  259.    if ( !iCmdFiles && !iCmdDirs ) {
  260.       entry_store(CMD_DIR,".",0,0,iCmdDirs++);
  261.    }
  262.    if ( !iFlagAbort ) {
  263.       if ( iCmdFiles && iFlagFiles ) 
  264.          process_cmd_file(iCmdFiles);
  265.       if ( iCmdDirs ) {
  266.          process_cmd_dir(iCmdDirs);
  267.          entry_release(CMD_DIR);
  268.       }
  269.       entry_release(ENTRY_FILE);
  270.       entry_release(ENTRY_DIR);
  271.    }
  272.    return(iReturn);
  273. }
  274.  
  275. /**********************************************************************/
  276. void entry_store(iType,pszName,iMod,iSize,iCount)
  277. /**********************************************************************
  278.  
  279. entry store function: "returns nothing"
  280.  
  281.    * receives a pointer to entry name, type, modify date, size, and count
  282.    * places data into proper pointer array depending on the type
  283.    * each array is checked for memory overflow
  284.    * if overflow, then realloc() is called to double memory size
  285.  
  286. **********************************************************************/
  287. char *pszName;
  288. int   iType,
  289.       iMod,
  290.       iSize,
  291.       iCount;
  292. {
  293.    char szError[MAX_ERROR_LEN];
  294.    switch ( iType ) {
  295.       case CMD_DIR:
  296.          if ( iCount == iAllocCmd ) {
  297.             iAllocCmd *= 2;
  298.             Cmd = (EntryData *)realloc(
  299.                   (char *)Cmd,
  300.                   (unsigned int)(sizeof(EntryData)*iAllocCmd));
  301.             if ( !Cmd ) {
  302.                (void)sprintf(szError,"%s: realloc()",szProgName);
  303.                perror(szError);
  304.                exit(1);
  305.             }
  306.          }
  307.          (void)strcpy(Cmd[iCount].szName,pszName);
  308.          break;
  309.       case ENTRY_FILE:
  310.          if ( iCount == iAllocFile ) {
  311.             iAllocFile *= 2;
  312.             File = (EntryData *)realloc(
  313.                    (char *)File,
  314.                    (unsigned int)(sizeof(EntryData)*iAllocFile));
  315.             if ( !File ) {
  316.                (void)sprintf(szError,"%s: realloc()",szProgName);
  317.                perror(szError);
  318.                exit(1);
  319.             }
  320.          }
  321.          (void)strcpy(File[iCount].szName,pszName);
  322.          File[iCount].iMod = iMod;
  323.          File[iCount].iSize = iSize;
  324.          break;
  325.       case ENTRY_DIR:
  326.          if ( iCount == iAllocDir ) {
  327.             iAllocDir *= 2;
  328.             Dir = (EntryData *)realloc(
  329.                   (char *)Dir,
  330.                   (unsigned int)(sizeof(EntryData)*iAllocDir));
  331.             if ( !Dir ) {
  332.                (void)sprintf(szError,"%s: realloc()",szProgName);
  333.                perror(szError);
  334.                exit(1);
  335.             }
  336.          }
  337.          (void)strcpy(Dir[iCount].szName,pszName);
  338.          Dir[iCount].iMod = iMod;
  339.          Dir[iCount].iSize = iSize;
  340.          break;
  341.    }
  342.    return;
  343. }
  344.  
  345. /**********************************************************************/
  346. void entry_release(iType)
  347. /**********************************************************************
  348.  
  349. entry release function: "returns nothing"
  350.  
  351.    * receives an entry type
  352.    * releases the allocated memory for the given type
  353.  
  354. **********************************************************************/
  355. int iType;
  356. {
  357.    switch ( iType ) {
  358.       case CMD_DIR:
  359.          (void)free((char *)Cmd);
  360.          break;
  361.       case ENTRY_FILE:
  362.          (void)free((char *)File);
  363.          break;
  364.       case ENTRY_DIR:
  365.          (void)free((char *)Dir);
  366.          break;
  367.    }
  368.    return;
  369. }
  370.  
  371. /**********************************************************************/
  372. void process_cmd_dir(iDir)
  373. /**********************************************************************
  374.  
  375. process command-line directory: "returns nothing"
  376.  
  377. * reads each directory name in the pointer array
  378. * for each name, the directory is opened then processed
  379.  
  380. **********************************************************************/
  381. int iDir;
  382. {
  383.    register int i;
  384.    for ( i=0 ; i<iDir ; i++ ) {
  385.       szDirName[0] = '\0';
  386.       (void)strcpy(szDirName,Cmd[i].szName);
  387.       if ( open_directory() ) process_directory();
  388.    }
  389.    return;
  390. }
  391.  
  392. /**********************************************************************/
  393. void process_cmd_file(iFile)
  394. /**********************************************************************
  395.  
  396. process command-line file: "returns nothing"
  397.  
  398. * the files in the pointer array are sorted depending on the options
  399. * the display_directory function is called
  400.  
  401. **********************************************************************/
  402. int iFile;
  403. {
  404.    int iTemp;
  405.    iNumFiles = iFile;
  406.    iNumEntries = iFile;
  407.    iNumDirs = 0;
  408.    iNumColumns = iScrWidth / ( iLongest+NUM_BLANK );
  409.    if ( iFlagSingle ) iNumColumns = 1;
  410.    szDirName[0] = '\0';
  411.    if ( iNumFiles ) {
  412.       if ( iFlagSort && iNumFiles > 1 ) {
  413.          if ( iFlagReverse ) 
  414.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_rev_name);
  415.          else 
  416.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  417.       }
  418.       else if ( iFlagSortModified && iNumFiles > 1 ) {
  419.          qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  420.          if ( iFlagReverse )
  421.             qsort((char *)File,iNumFiles,sizeof(EntryData),
  422.                sort_rev_date_modified);
  423.          else 
  424.             qsort((char *)File,iNumFiles,sizeof(EntryData),
  425.                sort_date_modified);
  426.       }
  427.       else if ( iFlagSortSize && iNumFiles > 1 ) {
  428.          qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  429.          if ( iFlagReverse )
  430.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_rev_size);
  431.          else
  432.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_size);
  433.       }
  434.       iTemp = iFlagPath;
  435.       iFlagPath = FALSE;
  436.       iFilesOnly = TRUE;
  437.       display_directory();
  438.       iFlagPath = iTemp;
  439.       iFilesOnly = FALSE;
  440.    }
  441.    return;
  442. }
  443.  
  444. /**********************************************************************/
  445. void getenv_option()
  446. /**********************************************************************
  447.  
  448. get environment options: "returns nothing"
  449.  
  450. * calls the getenv() system function
  451. * the character array is parsed for multiple options
  452. * for each option, the command_option() pd function is called
  453. * set the qty terminating character if ENV options are used
  454.  
  455. **********************************************************************/
  456. {
  457.    register int i, j;
  458.    int          iChar;
  459.    char        *szEnv = getenv(ENV_NAME),
  460.                 szOption[MAX_NAME_LEN];
  461.    if ( szEnv != NULL ) {
  462.       cQtyChar = ':';
  463.       if ( (iChar = strlen(szEnv)) ) {
  464.          szOption[0] = '\0';
  465.          j=0;
  466.          for ( i=0 ; i<iChar ; i++ ) {
  467.             if ( szEnv[i] == ' ' ) {
  468.                if ( strlen(szOption) ) {
  469.                   szOption[j] = '\0';
  470.                   command_option(szOption);
  471.                   szOption[0] = '\0';
  472.                   j=0;
  473.                }
  474.             }
  475.             else if ( szEnv[i] != '-' ) szOption[j++] = szEnv[i];
  476.          }
  477.          if ( strlen(szOption) ) {
  478.             szOption[j] = '\0';
  479.             command_option(szOption);
  480.          }
  481.       }
  482.    }
  483.    return;
  484. }
  485.  
  486. /**********************************************************************/
  487. void command_option(szOption)
  488. /**********************************************************************
  489.  
  490. command-line options: "returns nothing"
  491.  
  492. * receives an option string (character array)
  493. * checks for a valid option name
  494. * if valid option then various flags are set
  495.  
  496. **********************************************************************/
  497. char *szOption;
  498. {
  499.    if ( !strcmp(szOption,"h") || !strcmp(szOption,"help") ){
  500.       program_help();
  501.       iFlagAbort = TRUE;
  502.    }
  503.    else if ( !strcmp(szOption,"a") || !strcmp(szOption,"all") ){
  504.       iFlagHidden = TRUE;
  505.       iFlagDot = TRUE;
  506.    }
  507.    else if ( !strcmp(szOption,"b") || !strcmp(szOption,"brief") ){
  508.       iFlagBrief = TRUE;
  509.       iFlagHeader = FALSE;
  510.       iFlagPath = FALSE;
  511.       iFlagQty = FALSE;
  512.    }
  513.    else if ( !strcmp(szOption,"c") || !strcmp(szOption,"count")){
  514.       iFlagCount = TRUE;
  515.       iFlagSort = FALSE;
  516.    }
  517.    else if ( !strcmp(szOption,"d") || !strcmp(szOption,"dir") ){
  518.       iFlagFiles = FALSE;
  519.    }
  520.    else if ( !strcmp(szOption,"f") || !strcmp(szOption,"file") ){
  521.       iFlagDirs = FALSE;
  522.    }
  523.    else if ( !strcmp(szOption,"r") || !strcmp(szOption,"reverse")){
  524.       iFlagReverse = TRUE;
  525.    }
  526.    else if ( !strcmp(szOption,"v") || !strcmp(szOption,"version") ){
  527.       program_version();
  528.       iFlagAbort = TRUE;
  529.    }
  530.    else if ( !strcmp(szOption,"lc") || !strcmp(szOption,"link_cnt") ){
  531.       iFlagAltOutput = TRUE;
  532.       iFlagLinkCnt = TRUE;
  533.    }
  534.    else if ( !strcmp(szOption,"nd") || !strcmp(szOption,"no_dot") ){
  535.       if ( !iFlagHidden ) iFlagDot = FALSE;
  536.    }
  537.    else if ( !strcmp(szOption,"nh") || !strcmp(szOption,"no_hdr") ){
  538.       iFlagHeader = FALSE;
  539.    }
  540.    else if ( !strcmp(szOption,"np") || !strcmp(szOption,"no_pwd") ){
  541.       iFlagPath = FALSE;
  542.    }
  543.    else if ( !strcmp(szOption,"nq") || !strcmp(szOption,"no_qty") ){
  544.       iFlagQty = FALSE;
  545.    }
  546.    else if ( !strcmp(szOption,"ns") || !strcmp(szOption,"no_sort") ){
  547.       iFlagSort = FALSE;
  548.    }
  549.    else if ( !strcmp(szOption,"sc") || !strcmp(szOption,"sglcol")) {
  550.       iFlagSingle = TRUE;
  551.    }
  552.    else if ( !strcmp(szOption,"sm") || !strcmp(szOption,"sort_dtm")) {
  553.       iFlagSortModified = TRUE;
  554.       iFlagAltOutput = TRUE;
  555.       iFlagModified = TRUE;
  556.       iFlagSort = FALSE;
  557.       iSortOptions++;
  558.    }
  559.    else if ( !strcmp(szOption,"ss") || !strcmp(szOption,"sort_size")) {
  560.       iFlagSortSize = TRUE;
  561.       iFlagAltOutput = TRUE;
  562.       iFlagSize = TRUE;
  563.       iFlagSort = FALSE;
  564.       iSortOptions++;
  565.    }
  566.    else if ( !strcmp(szOption,"dta") || !strcmp(szOption,"accessed")){
  567.       iFlagAltOutput = TRUE;
  568.       iFlagAccessed = TRUE;
  569.    }
  570.    else if ( !strcmp(szOption,"dtm") || !strcmp(szOption,"modified")){
  571.       iFlagAltOutput = TRUE;
  572.       iFlagModified = TRUE;
  573.    }
  574.    else if ( !strcmp(szOption,"dts") || !strcmp(szOption,"status")){
  575.       iFlagAltOutput = TRUE;
  576.       iFlagStatus = TRUE;
  577.    }
  578.    else if ( !strcmp(szOption,"det") || !strcmp(szOption,"detail")){
  579.       iFlagAltOutput = TRUE; 
  580.       iFlagAccessed = TRUE;
  581.       iFlagModified = TRUE;
  582.       iFlagStatus = TRUE; 
  583.    }
  584.    else if ( !strcmp(szOption,"s") || !strcmp(szOption,"size")){
  585.       iFlagAltOutput = TRUE;
  586.       iFlagSize = TRUE;
  587.    }
  588.    else if ( !strcmp(szOption,"p") || !strcmp(szOption,"pro")){
  589.       iFlagAltOutput = TRUE;
  590.       iFlagPro = TRUE;
  591.    }
  592.    else if ( !strcmp(szOption,"w") || !strcmp(szOption,"wide")){
  593.       iFlagWide = TRUE;
  594.       iScrWidth = 132;
  595.    }
  596. #ifndef SVR3
  597.    else if ( !strcmp(szOption,"l") || !strcmp(szOption,"link")) {
  598.       iFlagLink = TRUE;
  599.    }
  600. #endif
  601.    else if ( !strcmp(szOption,"i") || !strcmp(szOption,"inode")) {
  602.       iFlagAltOutput = TRUE;
  603.       iFlagInode = TRUE;
  604.    }
  605.    else {
  606.       iReturn = 1;
  607.       (void)printf("Error: Invalid option: '-%s', use '-h' for help.",szOption);
  608.       program_usage();
  609.       iFlagAbort = TRUE;
  610.    }
  611.    if ( iSortOptions > 1 ) {
  612.       iReturn = 1;
  613.       (void)printf("Error: incompatible sort options specified, other than '-r'.");
  614.       program_usage();
  615.       iFlagAbort = TRUE;
  616.    }
  617.    return;
  618. }
  619.  
  620. /**********************************************************************/
  621. int open_directory()
  622. /**********************************************************************
  623.  
  624. open directory: "returns an integer"
  625.  
  626. * uses the dir name string (character array)
  627. * calls the opendir() system function
  628. * obtains a pointer to the directory entry
  629.  
  630. **********************************************************************/
  631. {
  632.    char szError[MAX_ERROR_LEN];
  633.    int  iReturnValue = FALSE;
  634.    if ( (dirp = opendir(szDirName)) != NULL ) 
  635.       iReturnValue = TRUE;
  636.    else {
  637.       iReturn = TRUE;
  638.       (void)printf("\n");
  639.       (void)sprintf(szError,"%s: %s",szProgName, szDirName);
  640.       perror(szError);
  641.       (void)printf("\n");
  642.    }
  643.    return(iReturnValue);
  644. }
  645.  
  646. /**********************************************************************/
  647. void process_directory()
  648. /**********************************************************************
  649.  
  650. process directory: "returns nothing"
  651.  
  652. * reads the given directory
  653. * closes the directory
  654. * sorts the entries depending on the options
  655. * calls the display_directory() function 
  656.  
  657. **********************************************************************/
  658. {
  659.    read_directory(); 
  660.    close_directory();
  661.    iNumColumns = iScrWidth / ( iLongest+NUM_BLANK );
  662.    if ( iFlagSingle ) iNumColumns = 1;
  663.    if ( iNumFiles+iNumDirs > 0 ) {
  664.       if ( iFlagSort ) {
  665.          if ( iNumFiles > 1 )
  666.             if ( iFlagReverse ) 
  667.                qsort((char *)File,iNumFiles,sizeof(EntryData),sort_rev_name);
  668.             else
  669.                qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  670.          if ( iNumDirs > 1 )
  671.             if ( iFlagReverse )
  672.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_rev_name);
  673.             else
  674.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_name);
  675.       }
  676.       else if ( iFlagSortModified ) {
  677.          if ( iNumFiles > 1 ) {
  678.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  679.             if ( iFlagReverse )
  680.                qsort((char *)File,iNumFiles,sizeof(EntryData),
  681.                   sort_rev_date_modified);
  682.             else
  683.                qsort((char *)File,iNumFiles,sizeof(EntryData),
  684.                   sort_date_modified);
  685.          }
  686.      if ( iNumDirs > 1 ) {
  687.             qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_name);
  688.             if ( iFlagReverse )
  689.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),
  690.                   sort_rev_date_modified);
  691.             else
  692.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),
  693.                   sort_date_modified);
  694.          }
  695.       }
  696.       else if ( iFlagSortSize ) {
  697.          if ( iNumFiles > 1 ) {
  698.             qsort((char *)File,iNumFiles,sizeof(EntryData),sort_name);
  699.             if ( iFlagReverse )
  700.                qsort((char *)File,iNumFiles,sizeof(EntryData),sort_rev_size);
  701.             else
  702.                qsort((char *)File,iNumFiles,sizeof(EntryData),sort_size);
  703.          }
  704.          if ( iNumDirs > 1 ) {
  705.             qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_name);
  706.             if ( iFlagReverse )
  707.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_rev_size);
  708.             else
  709.                qsort((char *)Dir,iNumDirs,sizeof(EntryData),sort_size);
  710.          }
  711.       }
  712.       display_directory();
  713.    }
  714.    if ( !iNumEntries ) {
  715.       iReturn = TRUE;
  716.       (void)printf("No entries selected. \n\n");
  717.    }
  718.    return;
  719. }
  720.  
  721. /**********************************************************************/
  722. void display_header()
  723. /**********************************************************************
  724.  
  725. display header: "returns nothing"
  726.  
  727. * show the directory pathname if local dir then use "." 
  728. * show the quantity of entries in the directory
  729.  
  730. **********************************************************************/
  731. {
  732.    char *cwd, *getcwd();
  733.    if ( iRemoteDir ) 
  734.       (void)printf("%s",szDirName);
  735.    else {
  736.       cwd = getcwd((char *)NULL, 128);
  737.       (void)printf("%s",cwd);
  738.    }
  739.    if (iNumEntries == 1) 
  740.       (void)printf("           %d Entry%c\n\n",iNumEntries,cQtyChar);
  741.    else                  
  742.       (void)printf("           %d Entries%c\n\n",iNumEntries,cQtyChar);
  743.    return;
  744. }
  745.  
  746. /**********************************************************************/
  747. void read_directory()
  748. /**********************************************************************
  749.  
  750. read directory: "returns nothing"
  751.  
  752. * reads the given directory
  753. * file entries are stored in the file pointer array
  754. * dir entries are stored in the dir pointer array
  755.  
  756. **********************************************************************/
  757. {
  758.    int  iTemp,
  759.         iDone = FALSE;
  760.    char szEntry[MAX_NAME_LEN],
  761.         szFullName[MAX_NAME_LEN],
  762.         szError[MAX_ERROR_LEN];
  763.  
  764.    iTemp = 0;
  765.    iNumFiles = 0;
  766.    iNumDirs = 0;
  767.    iLongest = 0;
  768.  
  769.    do {
  770.       filep = readdir(dirp);
  771.       if ( filep ) {
  772.          (void)strcpy(szEntry,filep->d_name);
  773.          if ( strcmp(szEntry,".") && strcmp(szEntry,"..") || iFlagHidden ) {
  774.             (void)strcpy(szFullName,szDirName);
  775.             if ( strcmp(szDirName,"/") ) (void)strcat(szFullName,"/");
  776.             (void)strcat(szFullName,szEntry);
  777.             if ( stat(szFullName, &stb) < 0 ) {
  778.                if ( errno == ENOENT ) {                   /* No such entry */
  779.                   if ( szEntry[0] == '.' && iFlagDot == FALSE ) {
  780.                      continue;
  781.                   }
  782.                   else {
  783.                      entry_store(ENTRY_FILE,szEntry,0,0,iNumFiles++);
  784.                   }
  785.                }
  786.                else {
  787.                   iReturn = TRUE;
  788.                   (void)sprintf(szError,"%s: %s",szProgName,szFullName);
  789.                   perror(szError);
  790.                }
  791.             }
  792.             else {
  793.                if ( S_ISDIR(stb.st_mode) ) {              /* directory */
  794.                   if ( szEntry[0] == '.' && iFlagDot == FALSE ) {
  795.                      continue;
  796.                   }
  797.                   else {
  798.                      entry_store(ENTRY_DIR,szEntry,
  799.                         (int)stb.st_mtime,(int)stb.st_size,iNumDirs++);
  800.                   }
  801.                }
  802.                else {                                     /* file */
  803.                   if ( szEntry[0] == '.' && iFlagDot == FALSE ) {
  804.                      continue;
  805.                   }
  806.                   else {
  807.                      entry_store(ENTRY_FILE,szEntry,
  808.                         (int)stb.st_mtime,(int)stb.st_size,iNumFiles++);
  809.                   }
  810.                }
  811.                iTemp = strlen(szEntry);
  812.                if ( iTemp > iLongest ) iLongest = iTemp;
  813.             }
  814.          }
  815.       }
  816.       else iDone = TRUE;
  817.    } while ( !iDone );
  818.    return;
  819. }
  820.  
  821. /**********************************************************************/
  822. void close_directory()                   /* close an opened directory */
  823. /**********************************************************************/
  824. {
  825.    (void)closedir(dirp);
  826.    return;
  827. }
  828.  
  829. /**********************************************************************/
  830. int sort_name(entry1,entry2)          /* qsort func, by entry name */
  831. /**********************************************************************/
  832. EntryData *entry1,
  833.           *entry2;
  834. {
  835.    return strcmp(entry1->szName,entry2->szName);
  836. }
  837.  
  838. /**********************************************************************/
  839. int sort_rev_name(entry1,entry2)     /* qsort func, by rev entry name */
  840. /**********************************************************************/
  841. EntryData *entry1,
  842.           *entry2;
  843. {
  844.    return strcmp(entry2->szName,entry1->szName);
  845. }
  846.  
  847. /**********************************************************************/
  848. int sort_date_modified(entry1,entry2)      /* qsort func, by date mod */
  849. /**********************************************************************/
  850. EntryData *entry1,
  851.           *entry2;
  852. {
  853.    return(entry2->iMod - entry1->iMod);
  854. }
  855.  
  856. /**********************************************************************/
  857. int sort_rev_date_modified(entry1,entry2) /* qsort func, rev date mod */
  858. /**********************************************************************/
  859. EntryData *entry1,
  860.           *entry2;
  861. {
  862.    return(entry1->iMod - entry2->iMod);
  863. }
  864.  
  865. /**********************************************************************/
  866. int sort_size(entry1,entry2)                   /* qsort func, by size */
  867. /**********************************************************************/
  868. EntryData *entry1,
  869.           *entry2;
  870. {
  871.    return(entry2->iSize - entry1->iSize);
  872. }
  873.  
  874. /**********************************************************************/
  875. int sort_rev_size(entry1,entry2)           /* qsort func, rev by size */
  876. /**********************************************************************/
  877. EntryData *entry1,
  878.           *entry2;
  879. {
  880.    return(entry1->iSize - entry2->iSize);
  881. }
  882.  
  883. /**********************************************************************/
  884. void display_directory()
  885. /**********************************************************************
  886.  
  887. display directory: "returns nothing"
  888.  
  889. * shows pathname and entry qty if needed
  890. * shows file and dir count if needed
  891. * if using alternate output show column header
  892. * for each entry in the directory display its name
  893. * if using alternate output show the needed details
  894.  
  895. **********************************************************************/
  896. {
  897.    register int t,
  898.                 i;
  899.    int          iColCnt,
  900.                 iColWidth,
  901.                 iNblanks, 
  902.                 iSpace = 3;
  903.    char         szPathName[MAX_NAME_LEN];
  904.  
  905.    iColWidth = iScrWidth / iNumColumns;
  906.    iNumEntries = 0;
  907.  
  908.    if ( iFlagBrief && iFlagCount ) iFlagQty = TRUE;
  909.    if ( !iFlagFiles && !iFlagDirs ) {
  910.       iFlagFiles = TRUE;
  911.       iFlagDirs = TRUE;
  912.    }
  913.    if ( iFlagFiles )  iNumEntries += iNumFiles;
  914.    if ( iFlagDirs )   iNumEntries += iNumDirs;
  915.    if ( !iFlagBrief ) (void)printf("\n");
  916.    if ( iFlagPath )   display_header();
  917.    if ( iNumFiles && iFlagFiles ) {
  918.       iColCnt = 0;
  919.       iNblanks = 0;
  920.       if ( iFlagQty ) {
  921.          if (iNumFiles == 1) 
  922.             (void)printf("%d File%c\n",iNumFiles,cQtyChar);
  923.          else
  924.             (void)printf("%d Files%c\n",iNumFiles,cQtyChar);
  925.          if ( !iFlagBrief ) (void)printf("\n");
  926.       }
  927.       if ( !iFlagCount ) {   
  928.          if ( iFlagAltOutput ) {            /* ALTERNATE OUTPUT FORMAT */
  929.             if ( iFlagHeader ) {
  930.                (void)printf("Name");
  931.                align_column(iLongest,strlen("name"),iSpace);
  932.                if ( iFlagInode )    (void)printf(" Inode #  ");
  933.                if ( iFlagLinkCnt )  (void)printf("Link Cnt  ");
  934.                if ( iFlagSize )     (void)printf("Size (bytes)  ");
  935.                if ( iFlagPro )     {(void)printf("User  Group Other  ");
  936.                                     (void)printf("    User.Group     ");}
  937.                if ( iFlagAccessed ) (void)printf("Accessed           ");
  938.                if ( iFlagModified ) (void)printf("Modified           ");
  939.                if ( iFlagStatus )   (void)printf("Status Changed     ");
  940.                (void)printf("\n");
  941.                repeat_char('-',iScrWidth-1); (void)printf("\n");
  942.             }
  943.             for ( t=0 ; t<iNumFiles ; ++t ) {
  944.                if ( iFilesOnly ) (void)strcpy(szPathName,File[t].szName);
  945.                else {
  946.                   (void)strcpy(szPathName,szDirName);
  947.                   if ( strcmp(szDirName,"/") ) (void)strcat(szPathName,"/");
  948.                   (void)strcat(szPathName,File[t].szName);
  949.                }
  950.                stat_file(File[t].szName,szPathName);
  951.             }
  952.             if ( !iFlagBrief ) (void)printf("\n");
  953.          }
  954.          else {                                            /* DEFAULT FORMAT */
  955.             for ( t=0 ; t<iNumFiles ; ++t ) {
  956.                for ( i=0; i<iNblanks ; ++i ) (void)putchar(' ');
  957.                (void)printf("%s",File[t].szName);
  958.                if (++iColCnt >= iNumColumns) {
  959.                   (void)putchar('\n');
  960.                   iColCnt = 0;
  961.                   iNblanks = 0;
  962.                }
  963.                else iNblanks = iColWidth - strlen(File[t].szName);
  964.             }
  965.             if (iColCnt != 0) (void)putchar('\n');
  966.             if ( !iFlagBrief ) (void)printf("\n");
  967.          }
  968.       }
  969.    }
  970.    if ( iNumDirs && iFlagDirs ) {                    /* DISPLAY DIRECTORIES */
  971.       iColCnt = 0;
  972.       iNblanks = 0;
  973.       if ( iFlagQty ) {                     /* DISPLAY THE QTY OF DIRS FLAG */
  974.          if (iNumDirs == 1) 
  975.             (void)printf("%d Directory%c\n",iNumDirs,cQtyChar);
  976.          else
  977.             (void)printf("%d Directories%c\n",iNumDirs,cQtyChar);
  978.          if ( !iFlagBrief ) (void)printf("\n");
  979.       }
  980.       if ( !iFlagCount ) {   
  981.          if ( iFlagAltOutput ) {                 /* ALTERNATE OUTPUT FORMAT */
  982.             if ( iFlagHeader ) {
  983.                (void)printf("Name");
  984.                align_column(iLongest,strlen("name"),iSpace);
  985.                if ( iFlagInode )    (void)printf(" Inode #  ");
  986.                if ( iFlagLinkCnt )  (void)printf("Link Cnt  ");
  987.                if ( iFlagSize )     (void)printf("Size (bytes)  ");
  988.                if ( iFlagPro )     {(void)printf("User  Group Other  ");
  989.                                     (void)printf("    User.Group     ");}
  990.                if ( iFlagAccessed ) (void)printf("Accessed           ");
  991.                if ( iFlagModified ) (void)printf("Modified           ");
  992.                if ( iFlagStatus )   (void)printf("Status Changed     ");
  993.                (void)printf("\n");
  994.                repeat_char('-',iScrWidth-1); (void)printf("\n");
  995.             }
  996.             for ( t=0 ; t<iNumDirs ; ++t ) {
  997.                (void)strcpy(szPathName,szDirName);
  998.                if ( strcmp(szDirName,"/") ) 
  999.                   (void)strcat(szPathName,(char *)"/");
  1000.                (void)strcat(szPathName,Dir[t].szName);
  1001.                stat_file(Dir[t].szName,szPathName);
  1002.             }
  1003.             if ( !iFlagBrief ) (void)printf("\n");
  1004.          }
  1005.          else {                                           /* DEFAULT FORMAT */
  1006.             for ( t=0 ; t<iNumDirs ; ++t ) {
  1007.                for ( i=0 ; i<iNblanks ; ++i ) (void)putchar(' ');
  1008.                (void)printf("%s",Dir[t].szName);
  1009.                if (++iColCnt >= iNumColumns) {
  1010.                   (void)putchar('\n');
  1011.                   iColCnt = 0;
  1012.                   iNblanks = 0;
  1013.                }
  1014.                else iNblanks = iColWidth - strlen(Dir[t].szName);
  1015.                }
  1016.             if (iColCnt != 0) (void)putchar('\n');
  1017.             if ( !iFlagBrief ) (void)printf("\n");
  1018.          }
  1019.       }
  1020.    }
  1021.    return;
  1022. }
  1023.  
  1024. /**********************************************************************/
  1025. void stat_file(szFileName,szPathName)
  1026. /**********************************************************************
  1027.  
  1028. stat file: "returns nothing"
  1029.  
  1030. * receives the file name and the path name
  1031. * calls the system stat() function
  1032. * depending on the flags, various information is displayed
  1033.  
  1034. **********************************************************************/
  1035. char *szFileName,
  1036.      *szPathName;
  1037. {
  1038.    int  iLink, 
  1039.         iSpace = 3, 
  1040.         iValidFile = TRUE;
  1041.    char szError[MAX_ERROR_LEN], 
  1042.         szLinkName[MAX_NAME_LEN];
  1043.  
  1044.    szLinkName[0] = '\0';
  1045.    if ( lstat(szPathName, &stb) < 0 ) {
  1046.       iReturn = TRUE;
  1047.       (void)sprintf(szError,"%s: %s",szProgName,szPathName);
  1048.       perror(szError);
  1049.    }
  1050.    else {
  1051.  
  1052. #ifndef SVR3
  1053.       if ( S_ISLNK(stb.st_mode) )
  1054.          if ( (iLink = readlink(szPathName,szLinkName,MAX_NAME_LEN)) ) 
  1055.             szLinkName[iLink] = '\0';
  1056. #endif
  1057.  
  1058.       if ( iFlagLink ) {
  1059.          (void)printf("%s",szFileName);
  1060.          if ( iLongest >= strlen("Name") )
  1061.             align_column(iLongest,strlen(szFileName),iSpace);
  1062.          else
  1063.             align_column(strlen("Name"),strlen(szFileName),iSpace);        
  1064.          display_expanded(szLinkName, iValidFile);
  1065.          (void)printf("\n");
  1066.       }
  1067.       else {
  1068.          if ( stat(szPathName, &stb) < 0 ) {
  1069.             if ( errno == ENOENT ) {
  1070.                iValidFile = FALSE;
  1071.                (void)printf("%s",szFileName);
  1072.                if ( iLongest >= strlen("Name") )
  1073.                   align_column(iLongest,strlen(szFileName),iSpace);
  1074.                else
  1075.                   align_column(strlen("Name"),strlen(szFileName),iSpace);
  1076.                display_expanded(szLinkName, iValidFile);
  1077.                (void)printf("\n");
  1078.             }
  1079.             else {
  1080.                iReturn = TRUE;
  1081.                (void)sprintf(szError,"%s: %s",szProgName,szPathName);
  1082.                perror(szError);
  1083.             }
  1084.          }
  1085.          else {
  1086.             (void)printf("%s",szFileName);
  1087.             if ( iLongest >= strlen("Name") )
  1088.                align_column(iLongest,strlen(szFileName),iSpace);
  1089.             else
  1090.                align_column(strlen("Name"),strlen(szFileName),iSpace);
  1091.             display_expanded(szLinkName, iValidFile);
  1092.             (void)printf("\n");
  1093.          }
  1094.       }
  1095.    }
  1096.    return;
  1097. }
  1098.  
  1099. /**********************************************************************/
  1100. void display_expanded(szLinkName, iValid) 
  1101. /**********************************************************************
  1102.  
  1103. display expanded: "returns nothing"
  1104.  
  1105. * this is used only for alternate outputs
  1106. * depending on various flags, different sections are used
  1107.  
  1108. **********************************************************************/
  1109. char *szLinkName; 
  1110. int   iValid;
  1111. {
  1112.    int iHour, iMin, iSec, iMonth, iDay, iYear;
  1113.    if ( iValid ) {
  1114.       if ( iFlagInode )   (void)printf("%7ld   ",stb.st_ino);
  1115.       if ( iFlagLinkCnt ) (void)printf("%6d    ",stb.st_nlink);
  1116.       if ( iFlagSize ) {
  1117.          if ( S_ISCHR(stb.st_mode) || S_ISBLK(stb.st_mode) ) {
  1118.             (void)printf("   %3u,  %3u  ",
  1119.                major(stb.st_rdev),minor(stb.st_rdev));
  1120.          }
  1121.          else {
  1122.             (void)printf("%12ld  ",stb.st_size);
  1123.          }
  1124.       }
  1125.       if ( iFlagPro ) {
  1126.          if ( stb.st_mode & S_IRUSR ) (void)printf("r");
  1127.          else                         (void)printf("-");
  1128.          if ( stb.st_mode & S_IWUSR ) (void)printf("w");
  1129.          else                         (void)printf("-");
  1130.          if ( stb.st_mode & S_ISUID ) {
  1131.             (void)printf("S");
  1132.          }
  1133.          else {
  1134.             if ( stb.st_mode & S_IXUSR ) (void)printf("x");
  1135.             else                         (void)printf("-");
  1136.          }
  1137.          (void)printf("   ");
  1138.          if ( stb.st_mode & S_IRGRP ) (void)printf("r");
  1139.          else                         (void)printf("-");
  1140.          if ( stb.st_mode & S_IWGRP ) (void)printf("w");
  1141.          else                         (void)printf("-");
  1142.          if ( stb.st_mode & S_ISGID ) {
  1143.             (void)printf("S");
  1144.          }
  1145.          else {
  1146.             if ( stb.st_mode & S_IXGRP ) (void)printf("x");
  1147.             else                         (void)printf("-");      
  1148.          }
  1149.          (void)printf("   ");
  1150.          if ( stb.st_mode & S_IROTH ) (void)printf("r");
  1151.          else                         (void)printf("-");
  1152.          if ( stb.st_mode & S_IWOTH ) (void)printf("w");
  1153.          else                         (void)printf("-");
  1154.          if ( stb.st_mode & S_IXOTH ) (void)printf("x");
  1155.          else                         (void)printf("-");      
  1156.          (void)printf("    ");
  1157.          passwdp = (struct passwd *)getpwuid((int)stb.st_uid);
  1158.          if ( passwdp != NULL ) (void)printf("%8s.",passwdp->pw_name);
  1159.          else                   (void)printf("%8d.",stb.st_uid);
  1160.          groupp = (struct group *)getgrgid((int)stb.st_gid);
  1161.          if ( groupp != NULL )  (void)printf("%-8s",groupp->gr_name);
  1162.          else                   (void)printf("%-8d",stb.st_gid);
  1163.          (void)printf("  ");
  1164.       }
  1165.       if ( iFlagAccessed ) {
  1166.          tmp = localtime(&stb.st_atime);
  1167.          iHour = tmp->tm_hour; iMin = tmp->tm_min; iSec = tmp->tm_sec;
  1168.          iMonth = tmp->tm_mon+1; iDay = tmp->tm_mday; iYear = tmp->tm_year;
  1169.          if ( iMonth < 10 ) (void)printf("0%1d/",iMonth);
  1170.          else               (void)printf("%2d/",iMonth);
  1171.          if ( iDay < 10 )   (void)printf("0%1d/",iDay);
  1172.          else               (void)printf("%2d/",iDay);
  1173.          if ( iYear < 10 )  (void)printf("0%1d",iYear);
  1174.          else               (void)printf("%2d",iYear);
  1175.          (void)printf("-");
  1176.          if ( iHour < 10 ) (void)printf("0%1d:",iHour);
  1177.          else              (void)printf("%2d:",iHour);
  1178.          if ( iMin < 10 )  (void)printf("0%1d:",iMin);
  1179.          else              (void)printf("%2d:",iMin);
  1180.          if ( iSec < 10 )  (void)printf("0%1d",iSec);
  1181.          else              (void)printf("%2d",iSec);
  1182.          (void)printf("  ");
  1183.       }
  1184.       if ( iFlagModified ) {
  1185.          tmp = localtime(&stb.st_mtime);
  1186.          iHour = tmp->tm_hour; iMin = tmp->tm_min; iSec = tmp->tm_sec;
  1187.          iMonth = tmp->tm_mon+1; iDay = tmp->tm_mday; iYear = tmp->tm_year;
  1188.          if ( iMonth < 10 ) (void)printf("0%1d/",iMonth);
  1189.          else               (void)printf("%2d/",iMonth);
  1190.          if ( iDay < 10 )   (void)printf("0%1d/",iDay);
  1191.          else               (void)printf("%2d/",iDay);
  1192.          if ( iYear < 10 )  (void)printf("0%1d",iYear);
  1193.          else               (void)printf("%2d",iYear);
  1194.          (void)printf("-");
  1195.          if ( iHour < 10 ) (void)printf("0%1d:",iHour);
  1196.          else              (void)printf("%2d:",iHour);
  1197.          if ( iMin < 10 )  (void)printf("0%1d:",iMin);
  1198.          else              (void)printf("%2d:",iMin);
  1199.          if ( iSec < 10 )  (void)printf("0%1d",iSec);
  1200.          else              (void)printf("%2d",iSec);
  1201.          (void)printf("  ");
  1202.       }
  1203.       if ( iFlagStatus ) {
  1204.          tmp = localtime(&stb.st_ctime);
  1205.          iHour = tmp->tm_hour; iMin = tmp->tm_min; iSec = tmp->tm_sec;
  1206.          iMonth = tmp->tm_mon+1; iDay = tmp->tm_mday; iYear = tmp->tm_year;
  1207.          if ( iMonth < 10 ) (void)printf("0%1d/",iMonth);
  1208.          else               (void)printf("%2d/",iMonth);
  1209.          if ( iDay < 10 )   (void)printf("0%1d/",iDay);
  1210.          else               (void)printf("%2d/",iDay);
  1211.          if ( iYear < 10 )  (void)printf("0%1d",iYear);
  1212.          else               (void)printf("%2d",iYear);
  1213.          (void)printf("-");
  1214.          if ( iHour < 10 ) (void)printf("0%1d:",iHour);
  1215.          else              (void)printf("%2d:",iHour);
  1216.          if ( iMin < 10 )  (void)printf("0%1d:",iMin);
  1217.          else              (void)printf("%2d:",iMin);
  1218.          if ( iSec < 10 )  (void)printf("0%1d",iSec);
  1219.          else              (void)printf("%2d",iSec);
  1220.          (void)printf("  ");
  1221.       }
  1222.    }
  1223.    else {
  1224.       (void)printf("(Broken Link) destination doesn't exist:   ");
  1225.    }
  1226.    if ( strlen(szLinkName) ) {
  1227.       if ( iFlagLink ) (void)printf("(Link Status)");
  1228.       else             (void)printf("-> %s",szLinkName);
  1229.    }
  1230.    return;
  1231. }
  1232.  
  1233. /**********************************************************************/
  1234. void align_column(iLong,iCurrent,iGap)  /* pad stdout to align column */
  1235. /**********************************************************************/
  1236. int iLong, 
  1237.     iCurrent,
  1238.     iGap;
  1239. {
  1240.    register int i,
  1241.                 t;
  1242.    t = iLong - iCurrent;
  1243.    for ( i=0 ; i<t ; i++ ) (void)putchar(' ');
  1244.    for ( i=0 ; i<iGap ; i++ ) (void)putchar(' ');
  1245.    return;
  1246. }
  1247.  
  1248. /**********************************************************************/
  1249. void repeat_char(cChar,iQty)             /* repeat a char in a string */
  1250. /**********************************************************************/
  1251. char         cChar;
  1252. register int iQty;
  1253. {
  1254.    register int i;
  1255.    for ( i=0 ; i<iQty ; i++ ) (void)putchar(cChar);
  1256.    return;
  1257. }
  1258.  
  1259. /**********************************************************************/
  1260. void program_usage()
  1261. /**********************************************************************/
  1262. {
  1263.    (void)printf("\n");
  1264.    (void)printf("Usage: %s  <options>  <list of files/dirs>\n",szProgName);
  1265.    return;
  1266. }
  1267.  
  1268. /**********************************************************************/
  1269. void program_help()
  1270. /**********************************************************************/
  1271. {
  1272.    (void)printf(
  1273.    "       -a   | -all       ...   show all entries ( include '.' & '..' ).\n");
  1274.    (void)printf(
  1275.    "       -b   | -brief     ...   same as '-nh -np -nq' & no blank lines.\n");
  1276.    (void)printf(
  1277.    "       -c   | -count     ...   show counts only.\n");
  1278.    (void)printf(
  1279.    "       -d   | -dir       ...   directories only.\n");
  1280.    (void)printf(
  1281.    "       -f   | -file      ...   files only.\n");
  1282.    (void)printf(
  1283.    "       -h   | -help      ...   help information.\n");
  1284.    (void)printf(
  1285.    "       -i   | -inode     ...   show file inode number.\n");
  1286. #ifndef SVR3
  1287.    (void)printf(
  1288.    "       -l   | -link      ...   if symbolic link, show links status\n");
  1289. #endif
  1290.    (void)printf(
  1291.    "       -p   | -pro       ...   file protection (user,group,other).\n");
  1292.    (void)printf(
  1293.    "       -r   | -reverse   ...   sort entries in reverse order.\n");
  1294.    (void)printf(
  1295.    "       -s   | -size      ...   file size.\n");
  1296.    (void)printf(
  1297.    "       -v   | -version   ...   version stamp.\n");
  1298.    (void)printf(
  1299.    "       -w   | -wide      ...   wide format output ( 132 columns ).\n");
  1300.    (void)printf(
  1301.    "       -lc  | -link_cnt  ...   hard link count.\n");
  1302.    (void)printf(
  1303.    "       -nd  | -no_dot    ...   don't show files that start with '.'.\n");
  1304.    (void)printf(
  1305.    "       -nh  | -no_hdr    ...   don't show header on extended output.\n");
  1306.    (void)printf(
  1307.    "       -np  | -no_pwd    ...   don't show pathname.\n");
  1308.    (void)printf(
  1309.    "       -nq  | -no_qty    ...   don't show quantities.\n");
  1310.    (void)printf(
  1311.    "       -ns  | -no_sort   ...   don't sort the files/directories.\n");
  1312.    (void)printf(
  1313.    "       -sc  | -sglcol    ...   force single column output.\n");
  1314.    (void)printf(
  1315.    "       -sm  | -sort_dtm  ...   sort by date modified.\n");
  1316.    (void)printf(
  1317.    "       -ss  | -sort_size ...   sort by file size.\n");
  1318.    (void)printf(
  1319.    "       -det | -detail    ...   all date/time options.\n");
  1320.    (void)printf(
  1321.    "       -dta | -accessed  ...   date/time accessed.\n");
  1322.    (void)printf(
  1323.    "       -dtm | -modified  ...   date/time modified.\n");
  1324.    (void)printf(
  1325.    "       -dts | -status    ...   date/time status changed.\n");
  1326.    program_usage();
  1327.    return;
  1328. }
  1329.  
  1330. /**********************************************************************/
  1331. void program_version()
  1332. /**********************************************************************/
  1333. {
  1334.    (void)printf(
  1335.    "[ print directory (pd)           Scott L. Fehrman           version (%s)]\n"
  1336.    ,VERSION);
  1337.    return;
  1338. }
  1339.  
  1340. #ifdef SVR3
  1341. /**********************************************************************/
  1342. int lstat()  /*** this is a dumb function if using SVR3 UNIX system ***/
  1343. /**********************************************************************/
  1344. {
  1345.    return(0);
  1346. }
  1347. #endif
  1348.