home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 042.lha / c / eless.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-06-25  |  11.1 KB  |  393 lines

  1. /*From mnetor!seismo!gatech!hao!ames!ucbcad!ucbvax!unisoft!lll-lcc!well!ewhac Wed May 13 17:19:23 EDT 1987
  2. Article 4343 of comp.sys.amiga:
  3. Path: lsuc!mnetor!seismo!gatech!hao!ames!ucbcad!ucbvax!unisoft!lll-lcc!well!ewhac
  4. >From: ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab)
  5. Newsgroups: comp.sys.amiga
  6. Subject: Re: Faster directories under AmigaDOS -> binary incl.
  7. Summary: My own version.
  8. Message-ID: <3040@well.UUCP>
  9. Date: 12 May 87 05:05:58 GMT
  10. References: <8705110932.AA29181@cogsci.berkeley.edu>
  11. Reply-To: ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab)
  12. Organization: Whole Earth 'Lectronic Link, Sausalito, CA
  13. Lines: 376
  14.  
  15. [ Removal of this line by any means is punishable by Federal law. ]
  16.  
  17.     Shit.
  18.  
  19.     It seems like every time I come up with something resembling a useful
  20. utility, someone else beats me to it, and comes out with something almost
  21. the same.
  22.  
  23.     This was the case a looong time ago with a program I called LITE
  24. (Leo's Incredible Terminal Emulator).  Then David Wecker came out with his
  25. VT100 emulator, and suddenly there didn't seem to be any point in it any
  26. more (no slight upon you, Dave; it's an excellent program).
  27.  
  28.     Now it's happened again.  I *WAS* going to write a program for
  29. publication in Amazing Computing that did faster directories.  Then I found
  30. out that Dave Haynie has been working on almost the exact same program for
  31. the exact same magazine.  No problem, thinks I, I'll just clean it up a bit
  32. and throw it at the Net, or RoboCity News, or something.
  33.  
  34.     Now I log in to find this gentleman has already posted a program to
  35. help speed up directories.  It's enough to make a guy beat his head against
  36. the keyboard.  In fact, I think I will.
  37.  
  38.     nhbg mjmn ,kjh ,kmjnh nhbgvf bgvf]trnhbgvf mnjhbg .l,kmj .,m!!!!
  39.  
  40.     Sigh.
  41.  
  42.     Oh well, you may as well have the program to see what I did.  It
  43. uses the AmigaDOG ACTION_GET_BLOCK packet to get raw disk blocks off the
  44. disk and do things to them.  Preliminary studies indicate that directories
  45. are only 25% faster on average.  Speed increases ranged from 50% to -5%
  46. (yup, sorting things actually makes it run slower).  The test beds I used
  47. were Fish Disk 13 (all that BASIC crud), and the three-disk Portal program
  48. from Activision.  'dir' on Portal disk #2 takes about 2:35.  My program
  49. takes about 1:29 (as I recall).
  50.  
  51.     Known limitations:  Running the program on the boot disk crashes the
  52. machine (if you type 'cd' and get "DF0:" as a response, you are on the boot
  53. device).  If you 'cd' into a directory, remove the disk in question, then
  54. run the program, it fails gracefully, but gives an unhelpful error code.  It
  55. doesn't work on the RAM: driver.
  56.  
  57.     Dave Haynie and I have been conducting an E-mail discussion on our
  58. respective programs, and based on his description, his deserves publication
  59. more than mine does, and he has been working longer on it.  So Dave,
  60. consider this official notification:  Clean up your program and send it off
  61. to Amazing.
  62.  
  63.     I'm not trying to be negative about this.....  All right, maybe I
  64. am.  But I mean, gee whiz.  This is frustrating.....
  65.  
  66.     Oh well, hope you find the program useful.  External hacking to
  67. improve it is encouraged.
  68.  
  69.     By the way, the program is called 'eless.'
  70.  
  71. _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  72.  ________         ___            Leo L. Schwab
  73.        \        /___--__        The Guy in The Cape
  74.   ___  ___ /\            ---##\        ihnp4!ptsfa!well!ewhac
  75.       /   X  \_____    |  __ _---))            ..or..
  76.      /   /_\--    -----+==____\ // \  _        well ---\
  77. ___ (   o---+------------------O/   \/ \    dual ----> !unicom!ewhac
  78.      \     /            ___ \_  (`o )    hplabs -/       ("AE-wack")
  79.  ____ \___/                 \_/
  80.           Recumbent Bikes:            "Work FOR?  I don't work FOR
  81.         The _O_n_l_y Way To Fly!        anybody!  I'm just having fun."
  82.  
  83. _-_-_-_-_-_ All right, fine.  Don't cut here.  See if I care... _-_-_-_-_-_-_
  84.  :ts=8 bk=0
  85.  * 
  86.  * eless.c:    An attempt at a reasonable-speed 'ls' program by fiddling
  87.  *        with the DOS.
  88.  *
  89.  *        Compiles under Manx 3.20 and patched 3.40.
  90.  *        cc eless.c
  91.  *        ln eless.c -lc -o eless
  92.  *
  93.  * Leo L. Schwab        8704.26        (415)-456-6565
  94.  */
  95.  
  96. #include <exec/types.h>
  97. #include <exec/memory.h>
  98. #include <libraries/dosextens.h>
  99.  
  100. #define    BLOCKSIZE    128
  101. #define    STARTTAB    6
  102. #define ENDTAB        (BLOCKSIZE-51)
  103. #define    TABSIZ        (BLOCKSIZE-56)
  104. #define    FILENAME    (BLOCKSIZE-20)
  105. #define    HASHCHAIN    (BLOCKSIZE-4)
  106. #define    SECONDARY    (BLOCKSIZE-1)
  107. #define    ST_DIR        2
  108. #define    ST_FILE        -3
  109.  
  110. /*
  111.  * Note:  I usually declare Amiga functions this way to disable the compiler's
  112.  * type checking.  This allows me to assign values to variables without
  113.  * explicitly casting them to the appropriate type.  In reality, these
  114.  * functions return things entirely different from the way I've declared
  115.  * them.  For example, CreatePort() should really be declared as:
  116.  *
  117.  * struct MsgPort *CreatePort();
  118.  *
  119.  * Caveat Programmer.
  120.  */
  121. extern void    *AllocMem(), *CreatePort(), *RemTail(), *FindTask();
  122. extern long    Lock(), Examine();
  123.  
  124. long        dopacket();
  125. int        longcmp(), namecmp();
  126.  
  127.  
  128. struct StandardPacket    *packet;
  129. struct FileInfoBlock    *fib;
  130. struct FileLock        *lock;
  131. struct InfoData        *id;
  132. struct MsgPort        *dosreply;
  133. BPTR            lok;
  134. long            *buf, hashtab[TABSIZ];
  135.  
  136.  
  137. main (ac, av)
  138. char **av;
  139. {
  140.     int flag;
  141.  
  142.     openstuff ();
  143.  
  144.     if (ac < 2)        /*  No arguments; do current directory  */
  145.         printdir (((struct Process *) FindTask (0L)) -> pr_CurrentDir);
  146.  
  147.     else {            /*  Arguments; treat as directories  */
  148.         flag = (ac > 2);
  149.         while (++av, --ac) {
  150.             if (!(lok = Lock (*av, ACCESS_READ))) {
  151.                 printf ("%s: Not found.\n", *av);
  152.                 if (ac > 1)
  153.                     putchar ('\n');
  154.                 continue;
  155.             }
  156.  
  157.             if (!Examine (lok, fib))
  158.                 die ("Examine failed.");
  159.             if (fib -> fib_DirEntryType < 0) {
  160.                 printf ("%s: Not a directory.\n", *av);
  161.                 if (ac > 1)
  162.                     putchar ('\n');
  163.                 continue;
  164.             }
  165.  
  166.             if (flag)
  167.                 printf ("%s:\n", *av);
  168.             printdir (lok);
  169.             if (ac > 1)
  170.                 putchar ('\n');
  171.             UnLock (lok);  lok = NULL;
  172.         }
  173.     }
  174.  
  175.     closestuff ();
  176. }
  177.  
  178.  
  179. /*
  180.  * This function prints the directory in a nice, pretty columnar format.
  181.  */
  182. printdir (dirlock)
  183. BPTR dirlock;
  184. {
  185.     struct List        namelist;
  186.     register struct Node    *name, **namearray;
  187.     long            args[2];
  188.     register int        i, n;
  189.     int            len = 0, ncols, nlines, nfiles = 0;
  190.     char            fmt1[16], fmt2[16];
  191.     char            *fn = (char *) (&buf[FILENAME]) + 1;
  192.  
  193.     lock = (struct FileLock *) (dirlock << 2);
  194.     args[0] = lock -> fl_Key;    /*  Block number  */
  195.     args[1] = (long) buf >> 2;    /*  BPTR to buffer  */
  196.  
  197.     /*  Attempt to get raw directory block.  */
  198.     if (!dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2)) {
  199.         if (packet -> sp_Pkt.dp_Res2 == ERROR_ACTION_NOT_KNOWN)
  200.             printf ("Not a block device.\n");
  201.         else
  202.             printf ("Error %ld while getting dirblock.\n",
  203.                 packet -> sp_Pkt.dp_Res2);
  204.         return;
  205.     }
  206.  
  207.     /*  Copy DOS's hash table into our array.  */
  208.     for (i=0; i<TABSIZ; i++)
  209.         hashtab[i] = buf[i+STARTTAB];
  210.  
  211.     NewList (&namelist);
  212.     while (1) {
  213.         /*  Sort hash table.  */
  214.         qsort (hashtab, TABSIZ, sizeof (long), longcmp);
  215.         if (!hashtab[0])    /*  Empty hash table  */
  216.             break;
  217.  
  218.         /*
  219.          * Retrieve disk blocks according to sorted hash table and
  220.          * collect filenames.
  221.          */
  222.         for (i=0; hashtab[i] && i<TABSIZ; i++) {
  223.             args[0] = hashtab[i];
  224.             dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2);
  225.  
  226.             if (!(name = AllocMem (sizeof (*name) + *(fn-1) + 1L,
  227.                            MEMF_CLEAR))) {
  228.                 puts ("Node memory allocation failure.");
  229.                 goto bombout;
  230.             }
  231.  
  232.             name -> ln_Name = (char *) name + sizeof (*name);
  233.             name -> ln_Type = (buf[SECONDARY] == ST_DIR);
  234.             fn[*(fn-1)] = '\0';    /*  Force null-termination  */
  235.             strcpy (name -> ln_Name, fn);
  236.             AddTail (&namelist, name);
  237.             nfiles++;    /*  Number of files found  */
  238.  
  239.             hashtab[i] = buf[HASHCHAIN];
  240.         }
  241.     }
  242.     if (!nfiles)    /*  No files  */
  243.         return;
  244.  
  245.     /*  Create array that qsort can deal with.  */
  246.     if (!(namearray = AllocMem
  247.                ((long) nfiles * sizeof (char *), MEMF_CLEAR))) {
  248.         puts ("Name array allocation failure.");
  249.         goto bombout;
  250.     }
  251.  
  252.     /*  Load up the array.  */
  253.     for (name = namelist.lh_Head, i=0;
  254.          name -> ln_Succ;
  255.          name = name -> ln_Succ, i++)
  256.              namearray[i] = name;
  257.  
  258.     /*  Alphabetize filenames.  */
  259.     qsort (namearray, nfiles, sizeof (struct Node *), namecmp);
  260.  
  261.     /*  Find longest string so we can format intelligently.  */
  262.     for (i=0; i<nfiles; i++)
  263.         if ((n = strlen (namearray[i] -> ln_Name)) > len)
  264.             len = n;
  265.     len += 2;    /*  Inter-name spacing  */
  266.  
  267.     /*  Print them suckers out  */
  268.     ncols = 77 / len;        /*  Assume CON: is 77 columns  */
  269.     nlines = nfiles/ncols + (nfiles%ncols != 0);
  270.     sprintf (fmt1, "%%-%ds", len);        /*  Normal format string  */
  271.     sprintf (fmt2, "\033[33m%%-%ds\033[m", len);    /* For directories */
  272.     for (i=0; i<nlines; i++) {
  273.         for (n=i; n<nfiles; n+=nlines)
  274.             printf (namearray[n] -> ln_Type ? fmt2 : fmt1,
  275.                 namearray[n] -> ln_Name);
  276.         putchar ('\n');
  277.     }
  278.  
  279.     /*  Phew!  Now free all the stuff we allocated.  */
  280. bombout:
  281.     freenamelist (&namelist);
  282.     if (namearray)
  283.         FreeMem (namearray, (long) nfiles * sizeof (struct Node *));
  284. }
  285.  
  286. freenamelist (list)
  287. struct List *list;
  288. {
  289.     register struct Node *now;
  290.  
  291.     while (now = RemTail (list))
  292.         FreeMem (now, sizeof (*now) + strlen (now -> ln_Name) + 1L);
  293. }
  294.  
  295.  
  296. /*
  297.  * This function assumes the existence of a properly initialized
  298.  * standardpacket structure called "packet" and a reply port called
  299.  * "dosreply".  A more general function would not do this.
  300.  *
  301.  * This function is synchronous i.e. it doesn't return until the specified
  302.  * action has been performed.
  303.  */
  304. long
  305. dopacket (proc, action, args, nargs)
  306. struct MsgPort *proc;
  307. long action;
  308. register long *args;
  309. register int nargs;
  310. {
  311.     register long *argp = &packet -> sp_Pkt.dp_Arg1;
  312.  
  313.     for (; nargs>0; nargs--)
  314.         *argp++ = *args++;
  315.  
  316.     /*
  317.      * AmigaDOS scribbles over the reply port, so we have to initialize
  318.      * it every time we send a packet.
  319.      */
  320.     packet -> sp_Pkt.dp_Port = dosreply;
  321.     packet -> sp_Pkt.dp_Type = action;
  322.  
  323.     PutMsg (proc, packet);
  324.     WaitPort (dosreply);
  325.     GetMsg (dosreply);
  326.  
  327.     return (packet -> sp_Pkt.dp_Res1);
  328. }
  329.  
  330.  
  331. /*
  332.  * These functions are called by qsort().  The sense of camparisons is
  333.  * reversed in longcmp to get a reverse sort (largest elements first).
  334.  */
  335. longcmp (foo, bar)
  336. long *foo, *bar;
  337. {
  338.     /*
  339.      * We have to do it this way because qsort() expects an int to be
  340.      * returned.  Subtracting longs directly might overflow a 16-bit int.
  341.      */
  342.     return ((*foo < *bar) - (*foo > *bar));
  343. }
  344.  
  345. namecmp (foo, bar)
  346. struct Node **foo, **bar;
  347. {
  348.     return (strcmp ((*foo) -> ln_Name, (*bar) -> ln_Name));
  349. }
  350.  
  351.  
  352. /*
  353.  * Resource allocation/deallocation routines.
  354.  */
  355. openstuff ()
  356. {
  357.     if (!(packet = AllocMem ((long) sizeof (*packet), MEMF_CLEAR)))
  358.         die ("Can't allocate packet space.");
  359.  
  360.     if (!(dosreply = CreatePort (NULL, NULL)))
  361.         die ("Dos reply port create failed.");
  362.     packet -> sp_Msg.mn_Node.ln_Name    = (char *) &packet -> sp_Pkt;
  363.     packet -> sp_Pkt.dp_Link        = &packet -> sp_Msg;
  364.  
  365.     if (!(fib = AllocMem ((long) sizeof (*fib), MEMF_CLEAR)))
  366.         die ("Can't allocate FileInfoBlock.");
  367.  
  368.     /*
  369.      * Note:  This allocation may not work with DMA hard disks.
  370.      */
  371.     if (!(buf = AllocMem (BLOCKSIZE * 4L, MEMF_CHIP | MEMF_PUBLIC)))
  372.         die ("Couldn't allocate sector buffer.");
  373. }
  374.  
  375. closestuff ()
  376. {
  377.     if (lok)        UnLock (lok);
  378.     if (buf)        FreeMem (buf, BLOCKSIZE * 4L);
  379.     if (fib)        FreeMem (fib, (long) sizeof (*fib));
  380.     if (dosreply)        DeletePort (dosreply);
  381.     if (packet)        FreeMem (packet, (long) sizeof (*packet));
  382. }
  383.  
  384. die (str)
  385. char *str;
  386. {
  387.     puts (str);
  388.     closestuff ();
  389.     exit (1);
  390. }
  391.  
  392.