home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d178 / ls.lha / Ls / ls.c < prev    next >
C/C++ Source or Header  |  1989-02-04  |  24KB  |  903 lines

  1. /* --------------------------------------------------------------------- *
  2.   LS.C -- an "improved" directory listing utility to replace the
  3.   AmigaDOS DIR and LIST commands.
  4.  
  5.   V1.0   August 1986 Written from scratch by Justin V. McCormick.
  6.   V2.0 November 1988 Revised for Lattice 5.0 and made 1.3 compatible.
  7.  
  8. Notice:
  9.  
  10.   This program is placed in the public domain with the understanding
  11. that the author makes no claims or guarantees with regard to its
  12. suitability for any given application, and that the author assumes no
  13. responsibility for damages incurred by its usage.  Any resemblance
  14. of this program to any other program, either living or dead, is
  15. purely coincidental.
  16.  
  17.   Feel free to steal this code and make millions of dollars from its sale
  18. or commercial use, but please give credit where credit is due.
  19.  
  20. Synopsis:
  21.  
  22.   Features adaptive columnar listing, versatile sort options,
  23. UNIX-style pattern matching, recursive subdirectory listing, etc!
  24.  
  25. Usage:
  26.     ls [options] [path1] [path2] ...
  27.  
  28. Options:
  29.     -?    Help!
  30.     -c    Show file comment info, -c implies -l
  31.     -d    Show directory names only
  32.     -f    Show filenames only
  33.     -l      Long verbose listing showing filesizes and dates
  34.     -n    No sort, just spit them out in the order ExNext() returns
  35.     -r    Reverse sort direction
  36.     -s    Sorted by size smallest to largest
  37.     -t    Sorted by date oldest to newest
  38.     -R    Recursive descent of subdirectories
  39.  
  40.   All arguments are optional.  Default is to give short columnar listing,
  41. sorted alphabetically, using the current directory.  Alphabetizing is case
  42. insensitive.
  43.  
  44.   Patterns may be matched in the given names, using the UNIX-style '*'
  45. to wildcard any number of characters, and '?' to wildcard a single
  46. character.  If you need to specify a pathname with spaces in it like
  47. "Wombat Soup", you need to put quotes around it.  LS can process up to 30
  48. separate pathname patterns in one command line.
  49.  
  50. Bugs:
  51.  
  52.   Redirecting the shortlist output to PRT: gives undesirable results,
  53. since I am using relative cursor positioning commands to format the
  54. screen output.  I thought about using an array to store a virtual
  55. screen, but my primary goals were to keep the size down and display
  56. speed at a maxiumum.  Also, LS cannot pattern match devices (like "dh*:")
  57. or support multiple levels of pattern matching (like "dh0:?/L*.info").
  58. This would involve another level of recursion and groking the Device List.
  59.  
  60. Changes From 1.0 to 2.0:
  61.  
  62.  o Source code prototyped, linted, traced, optimized, tweaked, etc.
  63.  o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0.
  64.  o High-volume routines recoded in assembly (lssup.a).
  65.  o Now handles multiple paths/files on a command line, up to 30.
  66.  o New sort flags, including no sort.
  67.  o Enhanced wildcards, understands complex *.?*.* expressions now.
  68.  o More efficient ExNext() performance, less ram used for recursion.
  69.  o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now.
  70.  o Command line parser handles quoted pathnames now (LC 5.0 benefit).
  71.  o Short listing finally auto-adjusts to new console window sizes!
  72.  o Pen color escape codes bypassed when redirecting long output.
  73.  o Sorting by size or date is also subsorted alphabetically now.
  74.  o Long listing shows new 1.3 file attributes, plus comment indicator.
  75.  o File dates are now in international format, YY-MM-DD.
  76.  o Fixed listings with files datestamped after 99-12-31 (overflow).
  77.  o Fixed listings with files datestamped before 78-01-01 (time < 0).
  78.  
  79. * --------------------------------------------------------------------- */
  80.  
  81. #include "ls.h"
  82.  
  83. /* Structure used to hold file info in a linked list */
  84. struct FibEntry
  85. {
  86.   struct FibEntry *NextFib;
  87.   struct FibEntry *LastFib;
  88.   struct FileInfoBlock *Fibp;
  89. };
  90.  
  91. /* Externs from lssup.a */
  92. /*lint +fva2 */
  93. extern int __stdargs asprintf (char *, char *,...);
  94. /*lint -fva2 */
  95.  
  96. extern __asm void SortFibs (R_D0 long, R_D1 long, R_A0 struct FibEntry *);
  97. extern __stdargs long iswild (char *);
  98. extern __stdargs long wildmatch (char *, char *);
  99. extern __stdargs char *FibFileDate (struct DateStamp *);
  100. extern __stdargs void GetWinBounds(long *, long *);
  101.  
  102. /* Local CODE */
  103. struct FibEntry *GetDir (BPTR, struct FileInfoBlock *);
  104. struct FibEntry *AllocFib (void);
  105. void CleanUp (char *, long);
  106. void ColorPen2 (void);
  107. void CursorOff (void);
  108. void CursorOn (void);
  109. void DirIt (BPTR, char *);
  110. void FreeAllFibs (struct FibEntry *);
  111. void FreeFib (struct FibEntry *);
  112. void LListDir (struct FibEntry *);
  113. void LListEntry (struct FileInfoBlock *);
  114. void LongList (long *, long *, struct FibEntry *);
  115. void main (int, char **);
  116. void PagePrompt (long);
  117. void ResetPen (void);
  118. void SListDir (struct FibEntry *);
  119. void TestBreak (void);
  120. void Usage (void);
  121. void WCHR (char *);
  122. void WSTR (char *);
  123.  
  124. BPTR Out = 0L;
  125. BPTR In = 0L;
  126. BPTR lockp = 0L;
  127. struct FileInfoBlock *GFibp = 0L;
  128.  
  129. long BREAKFLAG = 0;
  130. long CONSOLE = 0;
  131. long dircount = 0;
  132. long DIRFILEFLAG = 0;
  133. long errstat = 0;
  134. long filecount = 0;
  135. long LISTALL = 0;
  136. long LONGLIST = 0;
  137. long maxnamlen = 0;
  138. long NOSORTFLAG = 0;
  139. long NOTEFLAG = 0;
  140. long PATHNAMED = 0;
  141. long REVFLAG = 0;
  142. long sortkey = 0;
  143. long WILDCARD = 0;
  144. long CurWinRows = 20L;
  145. long CurWinCols = 77L;
  146.  
  147. char filename[160];
  148. char pattern[160];
  149. char workstr[160];
  150.  
  151. static char Author[] = "\23333mLS 2.0\2330m by Justin V. McCormick 1988";
  152. static char usage[] = "\nUsage: ls [-cdflnrstR] [path1] [path2] ...\n";
  153.  
  154. /* -------------------------------------------------------------------- */
  155. void main (argc, argv)
  156.   int argc;
  157.   char **argv;
  158. {
  159.   struct Process *procp;
  160.   long cnt, i;
  161.  
  162.   if (argc == 0)            /* son of Workbench -- no go! */
  163.     exit (0);
  164.  
  165. /* Grab FileHandles for input and output to console (or redirection file) */
  166.   In = Input ();
  167.   Out = Output ();
  168.   CONSOLE = (IsInteractive (Out) == 0L) ? 0L : 1L; /* Is this console output? */
  169.  
  170. /* Allocate a global FileInfoBlock for ExNext() */
  171.   if ( (GFibp = (struct FileInfoBlock *)AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR)) == 0L)
  172.     CleanUp("No RAM?", 103L);
  173.  
  174. /* Parse command line arguments <ugh> */
  175.   cnt = 1;
  176.   if (argc >= 2)
  177.   {
  178.     if (argv[1][0] == '-')
  179.     {
  180.       cnt++;
  181.       for (i = strlen(argv[1]) - 1; i > 0; i--)
  182.       {
  183.         switch (argv[1][i])
  184.         {
  185.       case 'c': 
  186.         LONGLIST = 1;
  187.         NOTEFLAG = 1;
  188.         break;
  189.           case 'd':
  190.             DIRFILEFLAG |= 1;
  191.             break;
  192.           case 'f':
  193.             DIRFILEFLAG |= 2;
  194.             break;
  195.       case 'l': 
  196.         LONGLIST = 1;
  197.         break;
  198.       case 'n':
  199.         NOSORTFLAG = 1;
  200.         break;
  201.       case 'r':
  202.         REVFLAG = 1;
  203.         break;
  204.       case 's':
  205.         sortkey = 1;
  206.         break;
  207.       case 't': 
  208.         sortkey = 2;
  209.         break;
  210.       case 'R': 
  211.         LISTALL = 1;
  212.         break;
  213.       case '?': 
  214.         Usage ();
  215.         break;
  216.       default: 
  217.         (void) asprintf (workstr, "Unknown option \'%c\'\n", argv[1][i]);
  218.         WSTR (workstr);
  219.         Usage ();
  220.         break;
  221.     }
  222.       }
  223.     }
  224.   }
  225.  
  226. /* Clean up the state flags */
  227.   if ( (argc - cnt) > 1)
  228.     LISTALL |= 2;
  229.  
  230.   if (DIRFILEFLAG == 0)
  231.     DIRFILEFLAG = 3;
  232.  
  233. /* Loop through the remaining args now */
  234.   do
  235.   {
  236.     PATHNAMED = 0;
  237.     if (cnt < argc)
  238.     {
  239.       (void) stpcpy (pattern, argv[cnt]);
  240.       PATHNAMED = 1;
  241.     }
  242.  
  243.     if (PATHNAMED)            /* If user specified a pathname    */
  244.     {
  245.       WILDCARD = iswild (pattern);     /* check for wildcards         */
  246.  
  247.       if (WILDCARD)            /* If wildcards, separate    */
  248.       {                    /* pattern from pathname    */
  249.         for (i = (strlen (pattern) - 1); i >= 0; i--)
  250.         {
  251.           if (pattern[i] == '/' || pattern[i] == ':')
  252.           {
  253.         (void) strncpy (filename, pattern, (UWORD) (i + 1));
  254.         filename[i + 2] = (BYTE) 0;
  255.         (void) stpcpy (workstr, &pattern[i + 1]);
  256.         (void) stpcpy (pattern, workstr);
  257.         break;
  258.           }
  259.         }
  260. /* Disallow wildcards in pathname */
  261.         if (iswild (filename))
  262.           CleanUp ("Sorry, can't pattern match paths", 5L);
  263.       }
  264.       else                /* No wildcards, use filename as is */
  265.       {
  266.         (void) stpcpy (filename, pattern);
  267.       }
  268.  
  269. /* If the user specified a pathname, try to grab a FileLock on it */
  270. /* Discard trailing slash if silly Joe User put one there */
  271.       if (filename[1] != 0 && filename[strlen (filename) - 1] == '/')
  272.         filename[strlen (filename) - 1] = (BYTE) 0;
  273.  
  274.       lockp = Lock (filename, ACCESS_READ);
  275.  
  276.       if (!lockp)            /* Can't Lock it!         */
  277.       {
  278.         errstat = IoErr ();
  279.         (void) strcat (filename, " not found");
  280.         CleanUp (filename, (long)errstat);
  281.       }
  282.     }
  283.     else
  284.     {
  285. /*
  286.  * If no filename was specified, steal Lock on current directory from
  287.  * CLI process task info.  We durn well better get something useful back;
  288.  * we don't do any error checking on the stolen Lock.
  289.  */
  290.       procp = (struct Process *) FindTask (0L);
  291.       lockp = procp->pr_CurrentDir;
  292.       filename[0] = 0;            /* Tell DirIt() to use current dir */
  293.     }
  294.  
  295. /* Get the directory for this path, display it */
  296.     DirIt (lockp, filename);
  297.  
  298. /* Release the lock, bump our arg counter */
  299.     if (lockp != 0 && PATHNAMED != 0)
  300.       UnLock (lockp);
  301.     lockp = 0L;
  302.     cnt++;
  303.  
  304.     if (cnt < argc)
  305.       WCHR("\n");
  306.   } while (cnt < argc && BREAKFLAG == 0);
  307.  
  308.   CleanUp ("", 0L);
  309. }
  310.  
  311. /* -------------------------------------------------------------------- */
  312. /* Deallocate and close everything                     */
  313. /* -------------------------------------------------------------------- */
  314. void CleanUp (exit_msg, exit_status)
  315.   char *exit_msg;
  316.   long exit_status;
  317. {
  318.   if (lockp && PATHNAMED)
  319.     UnLock (lockp);
  320.  
  321.   if (GFibp != 0L)
  322.     FreeMem(GFibp, (long)sizeof(struct FileInfoBlock));
  323.  
  324.   if (exit_status)
  325.   {
  326.     (void) asprintf (workstr, "ls: %s, Error #%ld\n", exit_msg, exit_status);
  327.     WSTR (workstr);
  328.   }
  329.   exit ((int) exit_status);
  330. }
  331.  
  332. /* -------------------------------------------------------------------- */
  333. void DirIt (lockp, dirname)
  334.   BPTR lockp;
  335.   char *dirname;
  336. {
  337.   BPTR  tlockp;
  338.   struct FibEntry *fibheadp;
  339.   struct FibEntry *tfibp;
  340.   char *subdir;
  341.   long strsize;
  342.  
  343. /* Try to fill FileInfoBlock, bomb if not readable for some reason */
  344.   if (!Examine (lockp, GFibp))
  345.   {
  346.     (void) asprintf (workstr, "Can't examine file or directory\n");
  347.     WSTR (workstr);
  348.     return;
  349.   }
  350.  
  351. /* Put directory header if this is a recursive listing */
  352.   if (dirname[0] && LISTALL > 0)
  353.   {
  354.     if (CONSOLE != 0)
  355.      (void)asprintf(workstr, "\23330;41m %s \2330m\n", dirname);
  356.     else
  357.      (void)asprintf(workstr, "%s\n", dirname);
  358.     WSTR(workstr);
  359.   }
  360.  
  361. /* If this is a single file list it verbosely */
  362.   if (GFibp->fib_EntryType < 0 && (DIRFILEFLAG & 2) != 0)
  363.   {
  364.     LListEntry (GFibp);
  365.   }
  366.   else
  367.   {
  368. /* Otherwise do a directory     */
  369. /* Allocate and initialize a FibEntry head node */
  370.     if ( (fibheadp = GetDir (lockp, GFibp)) != 0L && BREAKFLAG == 0)
  371.     {
  372.       if (NOSORTFLAG == 0)
  373.         SortFibs ((long)sortkey, REVFLAG, fibheadp);
  374.  
  375.       if (LONGLIST == 0)
  376.     SListDir (fibheadp);
  377.       else
  378.     LListDir (fibheadp);
  379.  
  380.       if ( (LISTALL & 1) != 0)
  381.       {
  382.         tfibp = fibheadp;
  383.     do
  384.     {
  385.       if (tfibp->Fibp->fib_EntryType > 0)
  386.       {
  387.         strsize = (strlen (dirname) + strlen (tfibp->Fibp->fib_FileName) + 2);
  388.         subdir = (char *) AllocMem ((LONG)strsize, 0L);
  389.         if (strlen (dirname) != 0)
  390.         {
  391.           (void) stpcpy (subdir, dirname);
  392.           if (dirname[strlen (dirname) - 1] != ':')
  393.         (void) strcat (subdir, "/");
  394.         }
  395.         (void) strcat (subdir, tfibp->Fibp->fib_FileName);
  396.         tlockp = Lock (subdir, ACCESS_READ);
  397.         if (tlockp == 0L)
  398.         {
  399.           WSTR (subdir);
  400.           WSTR (" -- can't lock it!\n");
  401.           break;
  402.         }
  403.         else
  404.         {
  405.           WCHR ("\n");        /* Put a blank line between directories */
  406.           DirIt (tlockp, subdir);
  407.           UnLock (tlockp);
  408.           FreeMem (subdir, (LONG)strsize);
  409.         }
  410.       }
  411.       tfibp = tfibp->NextFib;
  412.     } while (tfibp != fibheadp && BREAKFLAG == 0);
  413.       }
  414.     }
  415. /* Clean up */
  416.     FreeAllFibs (fibheadp);
  417.   }
  418. }
  419.  
  420. /* -------------------------------------------------------------------- */
  421. /* Allocate and fill a linked list of FileInfoBlocks             */
  422. /* -------------------------------------------------------------------- */
  423. struct FibEntry *GetDir (lockp, fibp)
  424.   BPTR lockp;
  425.   struct FileInfoBlock *fibp;
  426. {
  427.   long nextstat;
  428.   long tempnamlen;
  429.   struct FibEntry *tfibp;
  430.   struct FibEntry *headfib;
  431.  
  432.   maxnamlen = dircount = filecount = 0L;
  433.   headfib = 0L;
  434.  
  435.   do
  436.   {
  437.     TestBreak();
  438.     if (BREAKFLAG != 0)
  439.       return(headfib);
  440.     nextstat = ExNext (lockp, fibp);
  441.  
  442.     if (nextstat != 0)    /* We got something */
  443.     {
  444. /* See if it matches our pattern */
  445.       if (!WILDCARD || wildmatch (fibp->fib_FileName, pattern))
  446.       {
  447.  
  448. /* Bump count of files or directories */
  449.     if (fibp->fib_EntryType > 0)
  450.         {
  451.           if ((DIRFILEFLAG & 1) != 0)
  452.             dircount++;
  453.           else
  454.             goto ALLOCFIB;
  455.         }
  456.         else
  457.         {
  458.           if ((DIRFILEFLAG & 2) != 0)
  459.             filecount++;
  460.           else
  461.             continue;
  462.         }
  463.  
  464. /* See if this is the longest filename for later use in listing */
  465.     tempnamlen = strlen (fibp->fib_FileName);
  466.     if (tempnamlen > maxnamlen)
  467.       maxnamlen = tempnamlen;
  468.  
  469.         ALLOCFIB:
  470. /* Allocate another FibEntry to put the info in */
  471.         if (headfib == 0L)
  472.         {
  473.           headfib = AllocFib();
  474.           if (headfib == 0L)
  475.             return(headfib);
  476.           headfib->NextFib = headfib;
  477.           headfib->LastFib = headfib;
  478.           *(headfib->Fibp) = *(fibp);
  479.           tfibp = headfib;
  480.         }
  481.         else
  482.         {
  483.       tfibp->NextFib = AllocFib ();
  484.       if (tfibp->NextFib == 0L)
  485.         return(0L);
  486.  
  487. /* Copy FIB contents to next entry for ExNext to work with */
  488.       *(tfibp->NextFib->Fibp) = *(fibp);
  489.  
  490. /* Link it into the list */
  491.       tfibp->NextFib->LastFib = tfibp;
  492.       tfibp = tfibp->NextFib;
  493.       tfibp->NextFib = headfib;
  494.     }
  495.       }
  496.     }
  497.   } while (nextstat);
  498.  
  499. /* Return TRUE if entries found, else print message and return FALSE */
  500.   if ( (dircount + filecount) != 0)
  501.   {
  502.     return (headfib);
  503.   }
  504.   else
  505.   {
  506.     if (WILDCARD == 0 && DIRFILEFLAG == 3)
  507.       WSTR ("Volume or directory is empty.\n");
  508.     else
  509.       WSTR ("No match.\n");
  510.     return (0L);
  511.   }
  512. }
  513.  
  514. /* -------------------------------------------------------------------- */
  515. /* List a FibEntry list in a compact fashion                 */
  516. /* -------------------------------------------------------------------- */
  517. void SListDir (fibheadp)
  518.   struct FibEntry *fibheadp;
  519. {
  520.   struct FibEntry *tfibp;
  521.   long tabsize;
  522.   long maxtab;
  523.   long totrows;
  524.   long maxwinrow;
  525.   long colcnt;
  526.   long rowcnt;
  527.   long tabcnt;
  528.   long pagecnt = 1;
  529.  
  530.   CursorOff ();        /* Turn the cursor off since it will blink anyway */
  531.   GetWinBounds(&CurWinCols, &CurWinRows);
  532.  
  533.   tfibp = fibheadp;
  534.   tabcnt = rowcnt = colcnt = 0;
  535.  
  536.   tabsize = maxnamlen + 2;
  537.   if (CurWinCols < tabsize)
  538.     maxtab = 1;
  539.   else
  540.     maxtab = CurWinCols / tabsize;
  541.   maxwinrow = CurWinRows - 3;
  542.   if (maxwinrow <= 0)
  543.     maxwinrow = 1;
  544.   totrows = (dircount + filecount) / maxtab;
  545.   if ((dircount + filecount) % maxtab != 0)
  546.     totrows++;
  547.  
  548.   do
  549.   {
  550.     if (tfibp->Fibp->fib_EntryType > 0)
  551.     {
  552.       if ( (DIRFILEFLAG & 1) == 0)
  553.         goto GETNEXTFIB;
  554.       else
  555.         ColorPen2 ();
  556.     }
  557.     if (tabcnt)
  558.       (void) asprintf (workstr, "\233%ldC", (long)tabcnt);
  559.     else
  560.       workstr[0] = (BYTE) 0;
  561.     (void) strcat (workstr, tfibp->Fibp->fib_FileName);
  562.     (void) strcat (workstr, "\n");
  563.     WSTR (workstr);
  564.     if (tfibp->Fibp->fib_EntryType > 0)
  565.       ResetPen ();
  566.     rowcnt++;
  567.  
  568.     if (rowcnt == maxwinrow || rowcnt == totrows)
  569.     {
  570.       colcnt++;                /* Start a new column         */
  571. /* Check to see if we have used the last column up and are about to run
  572.  * off the screen entirely.  If so, give the user a chance to read it first.
  573.  */
  574.       if (colcnt == maxtab && rowcnt == maxwinrow && CONSOLE != 0)
  575.       {
  576.         if (maxwinrow > 1)
  577.         {
  578.          ++pagecnt;            /* Advance page number count    */
  579.      PagePrompt (pagecnt);        /* Print it, wait for user    */
  580.     }
  581.     totrows -= maxwinrow;
  582.     colcnt = tabcnt = rowcnt = 0L;
  583.       }
  584.       else    /* Just move over one row and back up to the top */
  585.       {
  586.     (void) asprintf (workstr, "\233%ldA", (long)rowcnt);
  587.     WSTR (workstr);
  588.     tabcnt += tabsize;
  589.     rowcnt = 0L;
  590.       }
  591.     }
  592.     GETNEXTFIB:
  593.     tfibp = tfibp->NextFib;
  594.   } while (tfibp != fibheadp);
  595.  
  596.   if (totrows - rowcnt > 0)        /* Cursor down till level with     */
  597.   {                    /* lowest line on screen     */
  598.     (void) asprintf (workstr, "\233%ldE", (long)(totrows - rowcnt));
  599.     WSTR (workstr);
  600.   }
  601.   CursorOn ();
  602. }
  603.  
  604. /* -------------------------------------------------------------------- */
  605. /* Reset character color to default Pen1 colors             */
  606. /* -------------------------------------------------------------------- */
  607. void ResetPen ()
  608. {
  609.   if (CONSOLE != 0)
  610.     WSTR ("\2330m");
  611. }
  612.  
  613. /* -------------------------------------------------------------------- */
  614. /* Turn the cursor on                            */
  615. /* -------------------------------------------------------------------- */
  616. void CursorOn ()
  617. {
  618.   if (CONSOLE != 0)
  619.     WSTR ("\233 p");
  620. }
  621.  
  622. /* -------------------------------------------------------------------- */
  623. /* Turn the cursor off for faster text output                 */
  624. /* -------------------------------------------------------------------- */
  625. void CursorOff ()
  626. {
  627.   if (CONSOLE != 0)
  628.     WSTR ("\2330 p");
  629. }
  630.  
  631. /* -------------------------------------------------------------------- */
  632. /* Make Pen2 <usually yellow/orange> the current charcter color     */
  633. /* -------------------------------------------------------------------- */
  634. void ColorPen2 ()
  635. {
  636.   if (CONSOLE != 0)
  637.     WSTR ("\23333m");
  638. }
  639.  
  640. /* -------------------------------------------------------------------- */
  641. /* Prompt the user to hit return, wait till return is hit         */
  642. /* -------------------------------------------------------------------- */
  643. void PagePrompt (page)
  644.   long page;
  645. {
  646.   WSTR ("\2337m -- MORE -- Press Return: \2330m");
  647.   (void) Read (In, workstr, 1L);
  648.   (void) asprintf (workstr, "\233F\233K\2334;33mPage %ld:\2330m\n", (long)page);
  649.   WSTR (workstr);
  650. }
  651.  
  652. /* -------------------------------------------------------------------- */
  653. /* List a directory in a verbose informative manner             */
  654. /* -------------------------------------------------------------------- */
  655. void LListDir (fibheadp)
  656.   struct FibEntry *fibheadp;
  657. {
  658.   long totblocks = 0L;
  659.   long totbytes = 0L;
  660.  
  661.   CursorOff ();
  662.   LongList (&totblocks, &totbytes, fibheadp);
  663.  
  664.   (void) asprintf (workstr, "Dirs:%-3ld Files:%-4ld Blocks:%-5ld Bytes:%-8ld\n",
  665.       (long)dircount, (long)filecount, totblocks, totbytes);
  666.   WSTR (workstr);
  667.   CursorOn ();
  668. }
  669.  
  670. /* -------------------------------------------------------------------- */
  671. void LongList (totblocks, totbytes, fibheadp)
  672.   long *totblocks, *totbytes;
  673.   struct FibEntry *fibheadp;
  674. {
  675.   struct FibEntry *tfibp;
  676.  
  677.   tfibp = fibheadp;
  678.   do
  679.   {
  680.     LListEntry (tfibp->Fibp);
  681.     if (tfibp->Fibp->fib_EntryType < 0)
  682.     {
  683.       *totblocks += tfibp->Fibp->fib_NumBlocks;
  684.       *totbytes += tfibp->Fibp->fib_Size;
  685.     }
  686.     tfibp = tfibp->NextFib;
  687.   } while (tfibp != fibheadp);
  688. }
  689.  
  690. /* -------------------------------------------------------------------- */
  691. /* Verbosely list a particular FibEntry                 */
  692. /* -------------------------------------------------------------------- */
  693. void LListEntry (fib)
  694.   struct FileInfoBlock *fib;
  695. {
  696.   long i, pmodes;
  697.   char *cp1;
  698.   char entry[160];
  699.  
  700.   pmodes = fib->fib_Protection & 0xff;
  701.   cp1 = stpcpy (entry, "chsparwed ");
  702.   for (i = 0; i < 4; i++)
  703.   {
  704.     if ((pmodes & (1 << i)) != 0)
  705.       entry[8 - i] = '-';
  706.   }
  707.   for (; i < 8; i++)
  708.   {
  709.     if ((pmodes & (1 << i)) == 0)
  710.       entry[8 - i] = '-';
  711.   }
  712.   if (fib->fib_Comment[0] == 0)
  713.     entry[0] = '-';
  714.  
  715.   cp1 = stpcpy (cp1, FibFileDate (&fib->fib_Date));
  716.   if (fib->fib_EntryType > 0)
  717.   {
  718.     if ( (DIRFILEFLAG & 1) == 0)
  719.       return;
  720.  
  721.     if (CONSOLE)
  722.       cp1 = stpcpy (cp1, "\23333m");
  723.     cp1 = stpcpy (cp1, "   Directory   ");
  724.     if (CONSOLE)
  725.       cp1 = strcat (cp1, "\2330m");
  726.   }
  727.   else
  728.     (void) asprintf (&entry[27], " %4ld %8ld ", fib->fib_NumBlocks, fib->fib_Size);
  729.   (void)strcat(entry, fib->fib_FileName);
  730.   (void)strcat(cp1, "\n");
  731.   WSTR (entry);
  732.  
  733.   if (NOTEFLAG != 0 && fib->fib_Comment[0] != 0)
  734.   {
  735.     if (CONSOLE)
  736.       (void)asprintf(cp1, "\23333m/* %s */\2330m\n", fib->fib_Comment);
  737.     else
  738.       (void)asprintf(cp1, "/* %s */\n", fib->fib_Comment);
  739.     WSTR (workstr);
  740.   }
  741. }
  742.  
  743. #ifdef NOASM
  744. /* -------------------------------------------------------------------- */
  745. /* Calculate date based on DateStamp structure, return a string pointer */
  746. /* -------------------------------------------------------------------- */
  747. char *CalcDate (fib)
  748.   struct FileInfoBlock *fib;
  749. {
  750.   static long days[12] =
  751.   {
  752.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  753.   };
  754.  
  755.   static char *months[12] =
  756.   {
  757.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  758.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  759.   };
  760.   char datestr[25];
  761.   long i, mdays;
  762.   long day, hour;
  763.   long minute, sec;
  764.   long ldays;
  765.   long year;
  766.  
  767.   ldays = 1461L;
  768.   year = 78L;
  769.   day = fib->fib_Date.ds_Days;
  770.   minute = fib->fib_Date.ds_Minute;
  771.   sec = fib->fib_Date.ds_Tick / 50L;
  772.   year += (day / ldays) * 4L;
  773.   day %= ldays;
  774.  
  775.   while (day)
  776.   {
  777.     mdays = 365;
  778.     if ((year & 3) == 0)
  779.       mdays++;
  780.     if (day < mdays)
  781.       break;
  782.     day -= mdays;
  783.     year++;
  784.   }
  785.  
  786.   for (i = 0L, day++; i < 12; i++)
  787.   {
  788.     mdays = days[i];
  789.     if (i == 1 && (year & 3) == 0)
  790.       mdays++;
  791.     if (day <= mdays)
  792.       break;
  793.     day -= mdays;
  794.   }
  795.   hour = minute / 60;
  796.   minute -= hour * 60;
  797.   (void) asprintf (datestr, "%02ld-%s-%02ld %02ld:%02ld:%02ld ", day, (long)months[i], year, hour, minute, sec);
  798.   return (datestr);
  799. }
  800. #endif
  801.  
  802. /* -------------------------------------------------------------------- */
  803. /* Use AmigaDos to put a string on the stdout                 */
  804. /* -------------------------------------------------------------------- */
  805. void WSTR (tstring)
  806.   char *tstring;
  807. {
  808.   (void) Write (Out, tstring, (long) strlen (tstring));
  809. }
  810.  
  811. /* -------------------------------------------------------------------- */
  812. /* Use AmigaDos to put a character on the stdout             */
  813. /* -------------------------------------------------------------------- */
  814. void WCHR (ch)
  815.   char *ch;
  816. {
  817.   (void) Write (Out, ch, 1L);
  818. }
  819.  
  820. /* -------------------------------------------------------------------- */
  821. /* Check to see if the user hit ^C                     */
  822. /* -------------------------------------------------------------------- */
  823. void TestBreak ()
  824. {
  825.   unsigned long oldsig;
  826.  
  827.   oldsig = SetSignal (0L, SIGBREAKF_CTRL_C);
  828.   if ( (oldsig & SIGBREAKF_CTRL_C) != 0L)
  829.   {
  830.     WSTR ("\2330m\233 p**BREAK\n");
  831.     BREAKFLAG = 1;
  832.   }
  833. }
  834.  
  835. /* -------------------------------------------------------------------- */
  836. /* Explain how to use                             */
  837. /* -------------------------------------------------------------------- */
  838. void Usage ()
  839. {
  840.   WSTR (Author);
  841.   WSTR (usage);
  842.   WSTR (" c > Show comments\n");
  843.   WSTR (" d > Dirs only\n");
  844.   WSTR (" f > Files only\n");
  845.   WSTR (" l > Long listing\n");
  846.   WSTR (" n > No sort\n");
  847.   WSTR (" r > Reverse sort\n");
  848.   WSTR (" s > Sort by size\n");
  849.   WSTR (" t > Sort by date\n");
  850.   WSTR (" R > Recursive listing\n");
  851.   CleanUp ("", 0L);
  852. }
  853.  
  854. /* -------------------------------------------------------------------- */
  855. /* Allocate a FibEntry structure and associated FileInfoBlock         */
  856. /* -------------------------------------------------------------------- */
  857. struct FibEntry *AllocFib ()
  858. {
  859.   struct FibEntry *tfibp;
  860.  
  861.   tfibp = (struct FibEntry *) AllocMem \
  862. ((long)( sizeof (struct FibEntry) + sizeof(struct FileInfoBlock) ), 0L);
  863.   if (tfibp != 0L)
  864.   {
  865.     tfibp->Fibp = (struct FileInfoBlock *)((ULONG)tfibp + sizeof(struct FibEntry));
  866.   }
  867.   else
  868.     BREAKFLAG = 1;
  869.   return (tfibp);
  870. }
  871.  
  872. /* -------------------------------------------------------------------- */
  873. /* Free up memory allocated to a linked list of FibEntrys         */
  874. /* -------------------------------------------------------------------- */
  875. void FreeAllFibs (fibheadp)
  876.   struct FibEntry *fibheadp;
  877. {
  878.   struct FibEntry *fibp;
  879.   struct FibEntry *tfibp;
  880.  
  881.   if (fibheadp != 0)
  882.   {
  883.     fibp = fibheadp;
  884.     do
  885.     {
  886.       tfibp = fibp->NextFib;
  887.       FreeFib (fibp);
  888.       fibp = tfibp;
  889.     } while (tfibp != fibheadp);
  890.   }
  891. }
  892.  
  893. /* -------------------------------------------------------------------- */
  894. /* Deallocate a single FibEntry structure                 */
  895. /* -------------------------------------------------------------------- */
  896. void FreeFib (fibp)
  897.   struct FibEntry *fibp;
  898. {
  899.   if (fibp != 0L)
  900.     FreeMem (fibp, (long)(sizeof (struct FibEntry) + sizeof(struct FileInfoBlock)));
  901. }
  902.  
  903.