home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format 54 / af054sub.adf / DTree.lha / DTree / DTree.c < prev    next >
C/C++ Source or Header  |  1993-08-26  |  14KB  |  497 lines

  1. /*
  2. ** DTree.c 1.00
  3. ** Copyright (c) 1993 by Sam Yee.
  4. ** All Rights Reserved.
  5. **
  6. ** Permission is here granted for the distribution of DTree, provided
  7. ** that files are intacted and in unmodified state.
  8. */
  9.  
  10. /*******************************************************************/
  11. /* includes */
  12. #include <clib/alib_protos.h>
  13. #include <clib/dos_protos.h>
  14. #include <clib/exec_protos.h>
  15. #include <dos/dos.h>
  16. #include <dos/dosasl.h>
  17. #include <exec/memory.h>
  18. #include <pragmas/dos_pragmas.h>
  19. #include <pragmas/exec_pragmas.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. /*******************************************************************/
  24. /* constants, macros, etc. */
  25. /* passing arguments through registers sometimes yield smaller code */
  26. #define REG(x)          register __ ## x
  27. #define ASM             __asm
  28.  
  29. /* for ReadArgs() */
  30. #define OPT_DIRS        0
  31. #define OPT_SHOWFILES   1
  32. #define OPT_IBMFONT     2
  33. #define OPT_JOINCHARS   3
  34. #define OPT_COLOR       4
  35. #define OPT_COUNT       5
  36.  
  37. /* ansi control sequences */
  38. #define ANSIOFF "\033[0m"
  39. #define COLOR1  "\033[31m"
  40. #define COLOR2  "\033[32m"
  41. #define COLOR3  "\033[33m"
  42. #define COLOR6  "\033[36m"
  43.  
  44. /* template for ReadArgs() */
  45. #define TEMPLATE "DTree 1.00 -- Directory Tree Displayer\n\
  46. Copyright (c) 1993 by Sam Yee.\n\
  47. All Rights Reserved.  Freely Distributable.\n\
  48. Compiled on "__DATE__ " (" __TIME__").\n\n\
  49. DIR/M,FILES/S,IBMFONT/S,JOINCHARS/K,COLOR/S"
  50.  
  51. #define LEADING_SPACES  3
  52.  
  53. /* extract a byte from 32-bit branch display character mask */
  54. #define GET_VBAR(x) ((x) & 0xff)
  55. #define GET_L(x)    (((x) & 0xff00) >> 8)
  56. #define GET_T90(x)  (((x) & 0xff0000) >> 16)
  57. #define GET_DASH(x) (((x) & 0xff000000) >> 24)
  58.  
  59. /*******************************************************************/
  60. /* need these for #pragmas */
  61. extern struct DOSBase  *DOSBase;
  62. extern struct SysBase  *SysBase;
  63.  
  64. /*******************************************************************/
  65. /* when the FILES argument is given, store each file in a node, and
  66.    display the whole linked list when the directory is done scanning
  67. */
  68. typedef
  69. struct
  70. {
  71.     struct List list;
  72.     int         node_count;
  73. } FileList;
  74.  
  75. /*******************************************************************/
  76. /* prototypes */
  77.  
  78. /* disable SAS/C's ^C checking */
  79. void __regargs __chkabort(void);
  80. void __regargs __chkabort(){}
  81. void __regargs _CXBRK(void);
  82. void __regargs _CXBRK(){}
  83.  
  84. BOOL tree_scan(BPTR dir_lock, struct FileInfoBlock *fib, int depth,
  85.                BOOL *nextdir_array, BOOL show_files,
  86.                ULONG join_chars, BOOL color);
  87. struct Node * ASM AddName(REG(a0) FileList *list,
  88.                           REG(a1) char *name);
  89. BOOL ASM do_dir(REG(a0) char *dirname, REG(d0) BOOL show_files,
  90.                 REG(d1) ULONG join_chars, REG(d2) BOOL color);
  91. void ASM myqsort(REG(a0) char *v[], REG(d0) int left,
  92.                  REG(d1) int right);
  93. void ASM swap(REG(a0) char *v[], REG(d0) int i, REG(d1) int j);
  94. char ** ASM SortFileList(REG(a0) FileList *file_list);
  95. BOOL NextDirLock(BPTR this_lock, struct FileInfoBlock *fib,
  96.                  FileList *list, BOOL *die);
  97.  
  98. /*******************************************************************/
  99. /* some global (oh no!) data */
  100. char *__stdiowin = NULL,
  101.      *__stdiov37 = NULL,
  102.      *version = "$VER: DTree 1.00 (14.7.93)";
  103.  
  104. /*******************************************************************/
  105. /* main routine, what else? */
  106. int
  107. main(void)
  108. {
  109.     struct RDArgs   *myrda;
  110.     UBYTE           **dirs;
  111.                     /* IBM extended characters */
  112.     ULONG           join_chars = 0x2d2b5c7c;
  113.     LONG            result[OPT_COUNT];
  114.     long            rc = 10,
  115.                     i;
  116.  
  117.     if (myrda = (struct RDArgs *)AllocDosObject(DOS_RDARGS,NULL))
  118.     {
  119.             /* read from stdin instead */
  120.         myrda->RDA_Source.CS_Buffer = NULL;
  121.         myrda->RDA_Source.CS_Length = 0L;
  122.  
  123.         for (i = 0; i < OPT_COUNT; i++)
  124.             result[i] = 0L;
  125.  
  126.         if (ReadArgs(TEMPLATE,result,myrda))
  127.         {
  128.             if (result[OPT_IBMFONT])
  129.                 join_chars = 0xc4c3c0b3;
  130.             else if (i = result[OPT_JOINCHARS])
  131.             {
  132.                 if (StrToLong((char *)i,&join_chars) < 0)
  133.                     join_chars = *((ULONG *)i);
  134.             }
  135.  
  136.             if (dirs = (UBYTE **)result[OPT_DIRS])
  137.             {
  138.                 for (i = 0; dirs[i]; i++)
  139.                 {
  140.                     if (!do_dir(dirs[i],result[OPT_SHOWFILES],
  141.                                 join_chars,
  142.                                 result[OPT_COLOR]) && dirs[i+1])
  143.                         PutStr("\n");
  144.                     else
  145.                         break;
  146.                 }
  147.             }
  148.             else    /* current directory as default */
  149.                 do_dir("",result[OPT_SHOWFILES],join_chars,
  150.                        result[OPT_COLOR]);
  151.  
  152.             if (result[OPT_COLOR])
  153.                 PutStr(ANSIOFF);
  154.  
  155.             FreeArgs(myrda);
  156.             rc = 0;
  157.         }
  158.         else
  159.             PrintFault(IoErr(),NULL);
  160.  
  161.         FreeDosObject(DOS_RDARGS,myrda);
  162.     }
  163.  
  164.     return(rc);
  165. }
  166.  
  167. /*******************************************************************/
  168. /* display the tree of one directory */
  169. BOOL ASM /* ^c break? */
  170. do_dir(REG(a0) char *dirname,
  171.        REG(d0) BOOL show_files,
  172.        REG(d1) ULONG join_chars,
  173.        REG(d2) BOOL color)
  174. {
  175.     struct FileInfoBlock    *fib;
  176.     BPTR                    dir_lock;
  177.     BOOL                    broke = FALSE,
  178.                             nextdir_array[64];
  179.     char                    fname[108];
  180.  
  181.     if (dir_lock = Lock(dirname,ACCESS_READ))
  182.     {
  183.         if (fib = (struct FileInfoBlock *)
  184.                         AllocDosObject(DOS_FIB,NULL))
  185.         {
  186.             memset(nextdir_array,0,sizeof(nextdir_array));
  187.  
  188.                 /* get real name */
  189.             if (NameFromLock(dir_lock,fname,sizeof(fname)))
  190.             {
  191.                 if (color)
  192.                     PutStr(COLOR6);
  193.  
  194.                 PutStr(fname);
  195.                 PutStr("\n");
  196.             }
  197.  
  198.             if (broke = tree_scan(dir_lock,fib,0,nextdir_array,
  199.                                   show_files,join_chars,color))
  200.                 PrintFault(ERROR_BREAK,NULL);
  201.  
  202.             FreeDosObject(DOS_FIB,fib);
  203.         }
  204.  
  205.         UnLock(dir_lock);
  206.     }
  207.     else
  208.         PrintFault(IoErr(),NULL);
  209.  
  210.     return(broke);
  211. }
  212.  
  213. /*******************************************************************/
  214. /* find the next directory lock, given the current one */
  215. BOOL /* found next dir? */
  216. NextDirLock(BPTR                    this_lock,
  217.             struct FileInfoBlock    *fib,
  218.             FileList                *list,
  219.             BOOL                    *die)
  220. {
  221.         /* scan for next directory, or parent directory ends */
  222.     while (ExNext(this_lock,fib))
  223.     {
  224.         if(CheckSignal(SIGBREAKF_CTRL_C))
  225.         {
  226.             *die = TRUE;
  227.             break;
  228.         }
  229.         else if (fib->fib_DirEntryType > 0)  /* a dir */
  230.             return(TRUE);
  231.         else if (list)  /* put filename into link list? */
  232.             AddName(list,fib->fib_FileName);
  233.     }
  234.  
  235.     return(FALSE);
  236. }
  237.  
  238. /*******************************************************************/
  239. /* display a branch to parent */
  240. void
  241. DisplayBranch(char  *label,
  242.               int   depth,
  243.               BOOL  *nextdir_array,
  244.               BOOL  show_files,
  245.               ULONG join_chars,
  246.               BOOL  is_dir,
  247.               BOOL  color)
  248. {
  249.     BPTR    out_fh = Output();
  250.     char    *col_str = COLOR1;  /* color for a file */
  251.     int     i,
  252.             j,
  253.             c = 0;
  254.  
  255.     PutStr(color ? COLOR3 : "");
  256.  
  257.     for (i = 0; i < depth; i++)
  258.     {
  259.         FPutC(out_fh,nextdir_array[i] ? GET_VBAR(join_chars) : ' ');
  260.  
  261.         for(j = 0; j < LEADING_SPACES; j++)
  262.             FPutC(out_fh,' ');
  263.     }
  264.  
  265.     if (is_dir)
  266.     {
  267.         col_str = COLOR2;
  268.         FPutC(out_fh,nextdir_array[depth] ?
  269.                      GET_T90(join_chars) : GET_L(join_chars));
  270.         c = GET_DASH(join_chars);
  271.     }
  272.     else if (show_files)
  273.     {
  274.         FPutC(out_fh,nextdir_array[depth] ?
  275.                      GET_VBAR(join_chars) : ' ');
  276.         c = ' ';
  277.     }
  278.  
  279.     if (c)
  280.         for (i = 0; i < LEADING_SPACES; i++)
  281.             FPutC(out_fh,c);
  282.  
  283.     if (color)
  284.         PutStr(col_str);
  285.  
  286.     PutStr(label);
  287.     PutStr("\n");
  288. }
  289.  
  290. /*******************************************************************/
  291. /* return a sorted array of strings, given a linked list,
  292.    use FreeVec() to free string array.
  293.    note: link list scanning could have been optimized, but
  294.          we want keep the nodes as ADT */
  295. char ** ASM
  296. SortFileList(REG(a0) FileList   *file_list)
  297. {
  298.     struct Node *node;
  299.     struct List temp_list;
  300.     char        **fnames;
  301.     int         i = 0;
  302.  
  303.     if (fnames = (char **)AllocVec(file_list->node_count<<2,
  304.                                    MEMF_PUBLIC))
  305.     {
  306.         NewList(&temp_list);
  307.  
  308.         while (node = RemHead((struct List *)file_list))
  309.         {
  310.             AddTail(&temp_list,node);   /* re-queue */
  311.             fnames[i++] = node->ln_Name;
  312.         }
  313.  
  314.             /* put things back */
  315.         while (node = RemTail(&temp_list))
  316.             AddHead((struct List *)file_list,node);
  317.  
  318.         myqsort(fnames,0,file_list->node_count-1);
  319.     }
  320.  
  321.     return(fnames);
  322. }
  323.  
  324. /*******************************************************************/
  325. /* scan the directory given */
  326. BOOL    /* use press ^C? */
  327. tree_scan(BPTR                  dir_lock,
  328.           struct FileInfoBlock  *fib,
  329.           int                   depth,  /* how deep from parent? */
  330.           BOOL                  *nextdir_array,
  331.           BOOL                  show_files,
  332.           ULONG                 join_chars,
  333.           BOOL                  color)
  334. {
  335.     struct Node             *node;
  336.     FileList                file_list;
  337.     struct FileInfoBlock    *new_fib;
  338.     BPTR                    new_lock;
  339.     char                    fname[108];
  340.     BOOL                    die = FALSE,
  341.                             is_dir;
  342.  
  343.     NewList((struct List *)&file_list);
  344.     file_list.node_count = 0;
  345.  
  346.     if (Examine(dir_lock,fib))
  347.     {
  348.         while (ExNext(dir_lock,fib) && !die)
  349.         {
  350.             if (show_files && (fib->fib_DirEntryType < 0))
  351.                 AddName(&file_list,fib->fib_FileName);
  352.  
  353.             while (TRUE)
  354.             {
  355.                 if (CheckSignal(SIGBREAKF_CTRL_C))
  356.                 {
  357.                     die = TRUE;
  358.                     break;
  359.                 }
  360.  
  361.                 is_dir = (fib->fib_DirEntryType > 0) ? TRUE : FALSE;
  362.                 NameFromLock(dir_lock,fname,108);
  363.                 AddPart(fname,fib->fib_FileName,108);
  364.                 nextdir_array[depth] =
  365.                     NextDirLock(dir_lock,fib,show_files ? &file_list
  366.                                                         : NULL,&die);
  367.  
  368.                 if (is_dir && !die)
  369.                 {
  370.                     DisplayBranch(FilePart(fname),depth,
  371.                                   nextdir_array,show_files,join_chars,
  372.                                   is_dir,color);
  373.  
  374.                     if (new_lock = Lock(fname,ACCESS_READ))
  375.                     {
  376.                         if (new_fib = (struct FileInfoBlock *)
  377.                                         AllocDosObject(DOS_FIB,NULL))
  378.                         {
  379.                             /* recursively, go into the sub-dir */
  380.                             die = tree_scan(new_lock,new_fib,depth+1,
  381.                                             nextdir_array,show_files,
  382.                                             join_chars,color);
  383.                             FreeDosObject(DOS_FIB,new_fib);
  384.                         }
  385.  
  386.                         UnLock(new_lock);
  387.                     }
  388.                 }
  389.  
  390.                 if(!nextdir_array[depth] || die)
  391.                     break;
  392.             }
  393.         }
  394.  
  395.         if (file_list.node_count && !die)
  396.         {
  397.             int     i;
  398.             char    **fnames;
  399.  
  400.             if (fnames = SortFileList(&file_list))
  401.             {
  402.                 for (i = 0; i < file_list.node_count; i++)
  403.                 {
  404.                     if(CheckSignal(SIGBREAKF_CTRL_C))
  405.                     {
  406.                         die = TRUE;
  407.                         break;
  408.                     }
  409.  
  410.                     DisplayBranch(fnames[i],depth,nextdir_array,
  411.                                   show_files,join_chars,FALSE,color);
  412.                 }
  413.  
  414.                 FreeVec(fnames);
  415.             }
  416.  
  417.             if (depth && !die)
  418.             {
  419.                 nextdir_array[depth] = FALSE;
  420.                 DisplayBranch("",depth,nextdir_array,show_files,
  421.                               join_chars,FALSE,color);
  422.             }
  423.         }
  424.  
  425.         while (node = RemHead((struct List *)&file_list))
  426.             FreeVec(node);
  427.     }
  428.  
  429.     return(die);
  430. }
  431.  
  432. /*******************************************************************/
  433. /* copy a filename into filenames link list */
  434. struct Node * ASM
  435. AddName(REG(a0) FileList    *list,
  436.         REG(a1) char        *name)
  437. {
  438.     struct Node *node;
  439.     char        *copy;
  440.  
  441.     if (node = AllocVec(sizeof(struct Node) + strlen(name)+1,
  442.                         MEMF_PUBLIC))
  443.     {
  444.         copy = ((char *)node) + sizeof(struct Node);
  445.         strcpy(copy,name);
  446.         node->ln_Name = copy;
  447.         AddTail((struct List *)list,node);
  448.         list->node_count++;
  449.     }
  450.  
  451.     return(node);
  452. }
  453.  
  454. /*******************************************************************/
  455. /* a significantly smaller quicksort than qsort() */
  456. void ASM
  457. myqsort(REG(a0) char    *v[],
  458.         REG(d0) int     left,
  459.         REG(d1) int     right)
  460. {
  461.     int i,
  462.         last;
  463.  
  464.     if (left < right)
  465.     {
  466.         swap(v,left,(left + right)>>1);
  467.         last = left;
  468.  
  469.         for (i = left+1; i <= right; i++)
  470.         {
  471.             if (stricmp(v[i], v[left]) < 0)
  472.                 swap(v, ++last, i);
  473.         }
  474.  
  475.         swap(v, left, last);
  476.         myqsort(v, left, last-1);
  477.         myqsort(v, last+1, right);
  478.     }
  479. }
  480.  
  481. /*******************************************************************/
  482. /* swap two text pointers */
  483. void ASM
  484. swap(REG(a0) char   *v[],
  485.      REG(d0) int    i,
  486.      REG(d1) int    j)
  487. {
  488.     char *temp;
  489.  
  490.     temp = v[i];
  491.     v[i] = v[j];
  492.     v[j] = temp;
  493. }
  494.  
  495. /*******************************************************************/
  496. /* END */
  497.