home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / utilities / dirutils / visualshell / src / tree.c < prev    next >
C/C++ Source or Header  |  1992-10-29  |  15KB  |  516 lines

  1.         /*********************************
  2.          *                               *
  3.          *   Visual Shell v1.17  10/92   *
  4.          *                               *
  5.          *     by Torsten Jürgeleit      *
  6.          *                               *
  7.          *           tree part           *
  8.          *                               *
  9.          *********************************/
  10.  
  11.     /* Includes */
  12.  
  13. #include "includes.h"
  14. #include "imports.h"
  15. #include "protos.h"
  16.  
  17.     /* Show directory tree */
  18.  
  19.    VOID
  20. action_tree(VOID)
  21. {
  22.    struct FileRequest  *freq = &file_req[active_freq];
  23.    struct TreeRequest  *treq = &tree_req;
  24.    struct TreeNode     *old_cursor_tnode = NULL;
  25.    BYTE  *name = &file2_buffer[0];
  26.    SHORT error;
  27.  
  28.    if ((error = build_device_name(name, freq->fr_DirLock)) ==
  29.                             VSH_STATUS_NORMAL) {
  30.       hcomp_freq_cursor(freq);
  31.       print_info_line(INFO_LINE_MODE_EMPTY);
  32.       print_fkey_text(FKEY_MODE_NONE);
  33.       if ((error = build_dir_tree(treq, name)) == VSH_STATUS_NORMAL) {
  34.  
  35.      /* Get our position in dir tree */
  36.      name = BaseName(&freq->fr_DirName[0]);
  37.      do {
  38.         old_cursor_tnode = get_tree_node_by_name(treq, old_cursor_tnode,
  39.                                       name);
  40.      } while (Strcmp(&freq->fr_DirName[0], build_tnode_path_name(treq,
  41.                             old_cursor_tnode)));
  42.      treq->tr_DirNode    = old_cursor_tnode;
  43.      treq->tr_CursorNode = &treq->tr_RootNode;
  44.      treq->tr_XPos       = 0;
  45.      treq->tr_YPos       = 0;
  46.      print_tree_page(treq);
  47.      do {
  48.         ULONG signals = Wait(SIGF_INTUITION | SIGF_ACTION);
  49.  
  50.         if (signals & SIGF_INTUITION) {   /* timing events from Intuition */
  51.            struct IntuiMessage  *msg;
  52.  
  53.            if (msg = (struct IntuiMessage *)
  54.                          GetMsg(con_window->UserPort)) {
  55.           ULONG class = msg->Class;
  56.  
  57.           ReplyMsg((struct Message *)msg);
  58.           switch (class) {
  59.              case REFRESHWINDOW :
  60.             print_tree_page(treq);
  61.             break;
  62.              case INTUITICKS :
  63.             if (auto_repeat) {
  64.                scroll_tree_req();
  65.             }
  66.             break;
  67.           }
  68.            }
  69.         }
  70.         if (signals & SIGF_ACTION) {
  71.            switch (action) {
  72.           case VSH_ACTION_NUM_ENTER :
  73.              error = read_new_dir(freq, build_tnode_path_name(treq,
  74.                  treq->tr_CursorNode), READ_DIR_MODE_NO_OUTPUT);
  75.              break;
  76.           case VSH_ACTION_SPEED_SEARCH :
  77.              old_cursor_tnode = treq->tr_CursorNode;
  78.              if (get_input(INPUT_MODE_TREQ_ENTRY, &gadget_buffer[0])
  79.                                  == FALSE) {
  80.             move_treq_cursor(treq, old_cursor_tnode,
  81.                               MOVE_MODE_NORMAL);
  82.              }
  83.              print_fkey_text(FKEY_MODE_QUIT_ONLY);
  84.              print_treq_status(treq);
  85.              break;
  86.           case VSH_ACTION_SCROLL_LEFT :
  87.           case VSH_ACTION_SCROLL_RIGHT :
  88.           case VSH_ACTION_SCROLL_UP :
  89.           case VSH_ACTION_SCROLL_DOWN :
  90.              scroll_tree_req();
  91.              break;
  92.            }
  93.         }
  94.      } while (action != VSH_ACTION_QUIT && action != VSH_ACTION_ESC &&
  95.                         action != VSH_ACTION_NUM_ENTER);
  96.       }
  97.       print_status(VSH_STATUS_FREE_TREE);
  98.       free_dir_tree(treq);
  99.       status = error;
  100.       draw_requesters(DRAW_MODE_CLEAR);
  101.    }
  102. }
  103.     /* Displaye tree page */
  104.  
  105.    VOID
  106. print_tree_page(struct TreeRequest  *treq)
  107. {
  108.    SetAPen(con_rport, (LONG)COLOR0);
  109.    RectFill(con_rport, (LONG)(BORDER_LEFT - 2), (LONG)
  110.             (BORDER_TOP_HIDDEN - 1), (LONG)(vsh_width - BORDER_RIGHT
  111.                         + 1), (LONG)(cli_vpos - 3));
  112.    draw_line(COLOR1, (USHORT)2, (USHORT)(BORDER_TOP_HIDDEN - 2),
  113.           (USHORT)(vsh_width - 3), (USHORT)(BORDER_TOP_HIDDEN - 2));
  114.    move_treq_cursor(treq, treq->tr_DirNode, MOVE_MODE_NO_CURSOR);
  115.    print_fkey_text(FKEY_MODE_QUIT_ONLY);
  116.    print_treq_status(treq);
  117. }
  118.     /* Build directory tree */
  119.  
  120.    SHORT
  121. build_dir_tree(struct TreeRequest  *treq, BYTE *dev_name)
  122. {
  123.    struct TreeNode  *tnode = &tree_req.tr_RootNode;
  124.    SHORT error;
  125.  
  126.    strcpy(&treq->tr_DeviceName[0], dev_name);
  127.    strcpy(&treq->tr_DirName[0], dev_name);
  128.    NewList((struct List *)&tnode->tn_List);   /* init root node */
  129.    tnode->tn_Node.mln_Succ = NULL;
  130.    tnode->tn_Node.mln_Pred = NULL;
  131.    tnode->tn_ParentNode    = NULL;   /* indicates root node */
  132.    tnode->tn_XPos          = 0;
  133.    tnode->tn_YPos          = 0;
  134.    tnode->tn_MaxDirs       = 1;
  135.    strcpy(&tnode->tn_Name[0], dev_name);
  136.    enable_abort = 1;
  137.    do {
  138.       if ((error = read_tree_dirs(treq, tnode)) == VSH_STATUS_NORMAL) {
  139.      tnode = get_next_unscanned_tree_node(treq, tnode);
  140.       }
  141.    } while (tnode && error == VSH_STATUS_NORMAL);
  142.    enable_abort = 0;
  143.    return(error);
  144. }
  145.     /* Get all subdirectories in given directory */
  146.  
  147.    SHORT
  148. read_tree_dirs(struct TreeRequest  *treq, struct TreeNode  *parent_tnode)
  149. {
  150.    struct MinList   *list = &parent_tnode->tn_List;
  151.    struct TreeNode  *tnode;
  152.    BPTR  lock;
  153.    BYTE  *path = &path1_buffer[0];
  154.    BOOL  keepon = TRUE;
  155.    SHORT error = VSH_STATUS_NORMAL;
  156.  
  157.    if (!(lock = quiet_lock(&treq->tr_DirName[0], (LONG)SHARED_LOCK))) {
  158.       error = VSH_ERROR_LOCK_FAILED;
  159.    } else {
  160.       if (Examine(lock, fib) == DOSFALSE) {   /* enter dir */
  161.      error = VSH_ERROR_EXAMINE_FAILED;
  162.       } else {
  163.  
  164.      /* Scan loop */
  165.      do {
  166.  
  167.         /* ESC pressed ? */
  168.         if (CheckAbort(NULL)) {
  169.            error = VSH_ERROR_ABORTED;
  170.         } else {
  171.  
  172.            /* Get next dir entry */
  173.            if (ExNext(lock, fib) == DOSFALSE) {
  174.           if (IoErr() != ERROR_NO_MORE_ENTRIES) {
  175.              error = VSH_ERROR_EXNEXT_FAILED;
  176.           }
  177.           keepon = FALSE;
  178.            } else {
  179.  
  180.           /* New dir found */
  181.           if (fib->fib_DirEntryType > 0) {
  182.              if (!(tnode = (struct TreeNode *)AllocMem((LONG)
  183.                       sizeof(struct TreeNode), MEMF_PUBLIC |
  184.                                  MEMF_CLEAR))) {
  185.             error = VSH_ERROR_OUT_OF_MEM;
  186.              } else {
  187.  
  188.             /* Build new directory tree node */
  189.             NewList((struct List *)&tnode->tn_List);
  190.             tnode->tn_XPos       = parent_tnode->tn_XPos + 1;
  191.             tnode->tn_YPos       = 0;
  192.             tnode->tn_MaxDirs    = 1;
  193.             tnode->tn_MaxDepth   = tnode->tn_XPos + 1;
  194.             tnode->tn_ParentNode = parent_tnode;
  195.             strcpy(&tnode->tn_Name[0], &fib->fib_FileName[0]);
  196.             AddTail((struct List *)list, (struct Node *)tnode);
  197.  
  198.             /* Print full dir name in status line */
  199.             if ((error = build_path_name_from_lock(path, lock))
  200.                              == VSH_STATUS_NORMAL) {
  201.                print_dos_status(DOS_MODE_TREE, path, NULL);
  202.             }
  203.              }
  204.           }
  205.            }
  206.         }
  207.      } while (error == VSH_STATUS_NORMAL && keepon == TRUE);
  208.       }
  209.       UnLock(lock);
  210.    }
  211.    return(error);
  212. }
  213.     /* Get node of next unscanned directory in tree */
  214.  
  215.    struct TreeNode *
  216. get_next_unscanned_tree_node(struct TreeRequest  *treq,
  217.                          struct TreeNode  *parent_tnode)
  218. {
  219.    struct TreeNode  *tnode;
  220.    ULONG max_dirs, max_depth;
  221.    BYTE  *ptr, *path = &treq->tr_DirName[0];
  222.    BOOL  keepon = TRUE;
  223.  
  224.    tnode = (struct TreeNode *)parent_tnode->tn_List.mlh_Head;   /* try to go deeper */
  225.    if (tnode->tn_Node.mln_Succ) {   /* list not empty ? */
  226.       tnode->tn_YPos = parent_tnode->tn_YPos;
  227.       TackOn(path, &tnode->tn_Name[0]);
  228.    } else {
  229.       do {   /* else go back */
  230.      ptr = BaseName(path);   /* go one dir back */
  231.      if (*(ptr - 1) == '/') {
  232.         ptr--;
  233.      }
  234.      *ptr  = '\0';
  235.      tnode = (struct TreeNode *)parent_tnode->tn_Node.mln_Succ;   /* next dir in list */
  236.      if (tnode->tn_Node.mln_Succ) {   /* not end of list ? */
  237.         tnode->tn_YPos = parent_tnode->tn_YPos + parent_tnode->tn_MaxDirs;
  238.         TackOn(path, &tnode->tn_Name[0]);
  239.         keepon = FALSE;
  240.      } else {
  241.         if (!(parent_tnode = parent_tnode->tn_ParentNode)) {   /* root reached ? */
  242.            tnode  = NULL;
  243.            keepon = FALSE;
  244.         } else {
  245.            max_dirs  = 0;   /* count dirs and get max depth in branch of tree */
  246.            max_depth = 0;
  247.            for (tnode = (struct TreeNode *)parent_tnode->tn_List.mlh_Head;
  248.             tnode->tn_Node.mln_Succ; tnode = (struct TreeNode *)
  249.                           tnode->tn_Node.mln_Succ) {
  250.           max_dirs += tnode->tn_MaxDirs;
  251.           if (tnode->tn_MaxDepth > max_depth) {
  252.              max_depth = tnode->tn_MaxDepth;
  253.           }
  254.            }
  255.            parent_tnode->tn_MaxDirs += max_dirs - 1;
  256.            parent_tnode->tn_MaxDepth = max_depth;
  257.         }
  258.      }
  259.       } while (keepon == TRUE);
  260.    }
  261.    return(tnode);
  262. }
  263.     /* Free directory tree */
  264.  
  265.    VOID
  266. free_dir_tree(struct TreeRequest  *treq)
  267. {
  268.    struct TreeNode  *tnode = &treq->tr_RootNode;
  269.    struct MinList   *list;
  270.  
  271.    do {
  272.       list = &tnode->tn_List;
  273.       if ((struct MinList *)list->mlh_TailPred != list) {   /* list not empty ? */
  274.      tnode = (struct TreeNode *)list->mlh_Head;
  275.       } else {
  276.      if (tnode = tnode->tn_ParentNode) {
  277.         FreeMem((APTR)RemHead((struct List *)&tnode->tn_List), (LONG)
  278.                            sizeof(struct TreeNode));
  279.      }
  280.       }
  281.    } while (tnode);
  282. }
  283.     /* Scroll directory tree */
  284.  
  285.    VOID
  286. scroll_tree_req(VOID)
  287. {
  288.    struct TreeRequest  *treq = &tree_req;
  289.    struct TreeNode     *tnode2, *tnode = treq->tr_CursorNode;
  290.    USHORT columns = treq->tr_Columns, rows = treq->tr_Rows;
  291.    ULONG  cxpos, cypos, xpos = treq->tr_XPos, ypos = treq->tr_YPos,
  292.            max_dirs  = treq->tr_RootNode.tn_MaxDepth,
  293.            max_depth = treq->tr_RootNode.tn_MaxDirs;
  294.  
  295.    do {
  296.       switch (scroll_flag) {
  297.      case 1 :   /* scroll up */
  298.         tnode = get_prev_column_tree_node(tnode);
  299.         break;
  300.      case 2 :   /* scroll down */
  301.         tnode = get_next_column_tree_node(tnode);
  302.         break;
  303.      case 4 :   /* scroll left */
  304.         if (tnode2 = tnode->tn_ParentNode) {
  305.            tnode = tnode2;
  306.         }
  307.         break;
  308.      case 8 :   /* scroll right */
  309.         tnode2 = (struct TreeNode *)tnode->tn_List.mlh_Head;
  310.         if (tnode2->tn_Node.mln_Succ) {
  311.            tnode = tnode2;
  312.         } else {
  313.            tnode = get_next_column_tree_node(tnode);
  314.         }
  315.         break;
  316.       }
  317.       if (tnode != treq->tr_CursorNode) {
  318.      cxpos = tnode->tn_XPos;
  319.      cypos = tnode->tn_YPos;
  320.      if (cxpos <= xpos) {
  321.         xpos = cxpos;
  322.         if (xpos) {
  323.            xpos--;
  324.         }
  325.      } else {
  326.         if (cxpos >= (xpos + columns - 1)) {
  327.            xpos = cxpos - columns + 1;
  328.            if ((xpos + columns) < max_dirs) {
  329.           xpos++;
  330.            }
  331.         }
  332.      }
  333.      if (cypos <= ypos) {
  334.         ypos = cypos;
  335.         if (ypos) {
  336.            ypos--;
  337.         }
  338.      } else {
  339.         if (cypos >= (ypos + rows - 1)) {
  340.            ypos = cypos - rows + 1;
  341.            if ((ypos + rows) < max_depth) {
  342.           ypos++;
  343.            }
  344.         }
  345.      }
  346.      hcomp_treq_cursor(treq);
  347.      treq->tr_CursorNode = tnode;
  348.      if (xpos != treq->tr_XPos || ypos != treq->tr_YPos) {
  349.         treq->tr_XPos = xpos;
  350.         treq->tr_YPos = ypos;
  351.         print_dir_tree(treq);
  352.      }
  353.      hcomp_treq_cursor(treq);
  354.      print_treq_status(treq);
  355.       }
  356.    } while (vsh_scroll_speed == SCROLL_SPEED_FAST && auto_repeat);
  357. }
  358.     /* Build full path name for given node in dir tree */
  359.  
  360.    BYTE *
  361. build_tnode_path_name(struct TreeRequest  *treq,
  362.                          struct TreeNode  *search_tnode)
  363. {
  364.    struct TreeNode  *tnode2, *tnode = &treq->tr_RootNode;
  365.    ULONG xpos = search_tnode->tn_XPos, ypos = search_tnode->tn_YPos;
  366.    BYTE  *path = &path1_buffer[0];
  367.  
  368.    strcpy(path, &tnode->tn_Name[0]);
  369.    while (tnode != search_tnode) {
  370.       tnode2 = (struct TreeNode *)tnode->tn_Node.mln_Succ;
  371.       if (tnode2 && tnode2->tn_Node.mln_Succ && tnode2->tn_YPos <= ypos) {
  372.      tnode  = tnode2;   /* next entry in list */
  373.      tnode2 = (struct TreeNode *)tnode->tn_Node.mln_Succ;
  374.      if (!tnode2->tn_Node.mln_Succ || tnode2->tn_YPos > ypos) {
  375.         TackOn(path, &tnode->tn_Name[0]);
  376.      }
  377.       } else {
  378.      tnode2 = (struct TreeNode *)tnode->tn_List.mlh_Head;
  379.      if (tnode2->tn_Node.mln_Succ && tnode2->tn_XPos <= xpos) {
  380.         tnode  = tnode2;   /* go deeper */
  381.         tnode2 = (struct TreeNode *)tnode->tn_Node.mln_Succ;
  382.         if (!tnode2->tn_Node.mln_Succ || tnode2->tn_YPos > ypos) {
  383.            TackOn(path, &tnode->tn_Name[0]);
  384.         }
  385.      }
  386.       }
  387.    }
  388.    return(path);
  389. }
  390.     /* Jump to an specified entry in dir tree */
  391.  
  392.    VOID
  393. jump_to_treq_entry(BYTE *name, USHORT mode)
  394. {
  395.    struct TreeRequest  *treq = &tree_req;
  396.    struct TreeNode     *tnode;
  397.  
  398.    if (mode == JUMP_MODE_FIRST) {
  399.       tnode = NULL;
  400.    } else {
  401.       tnode = treq->tr_CursorNode;
  402.    }
  403.    if ((tnode = get_tree_node_by_name(treq, tnode, name)) || (tnode =
  404.           get_tree_node_by_name(treq, (struct TreeNode *)NULL, name))) {
  405.       move_treq_cursor(treq, tnode, MOVE_MODE_NORMAL);
  406.    }      
  407. }
  408.     /* Move cursor to specified entry in dir tree */
  409.  
  410.    VOID
  411. move_treq_cursor(struct TreeRequest *treq, struct TreeNode *tnode,
  412.                                 USHORT mode)
  413. {
  414.    ULONG  xpos  = treq->tr_XPos, ypos = treq->tr_YPos,
  415.            cxpos = tnode->tn_XPos, cypos = tnode->tn_YPos;
  416.    USHORT columns   = treq->tr_Columns, rows = treq->tr_Rows,
  417.            max_depth = treq->tr_RootNode.tn_MaxDepth,
  418.            max_dirs  = treq->tr_RootNode.tn_MaxDirs;
  419.  
  420.    if (tnode != treq->tr_CursorNode || mode == MOVE_MODE_NO_CURSOR) {
  421.       if (mode != MOVE_MODE_NO_CURSOR) {
  422.      hcomp_treq_cursor(treq);
  423.       }
  424.       if (cxpos <= xpos || cxpos >= (xpos + columns - 1) || cypos <= ypos ||
  425.                            cypos >= (ypos + rows - 1)) {
  426.      if (max_depth > columns) {
  427.         if (cxpos <= (columns / 2)) {
  428.            xpos = 0;
  429.         } else {
  430.            xpos = cxpos - columns / 2;
  431.            if ((xpos + columns) > max_depth) {
  432.           xpos -= (xpos + columns) - max_depth;
  433.            }
  434.         }
  435.      }
  436.      if (max_dirs > rows) {
  437.         if (cypos <= (rows / 2)) {
  438.            ypos = 0;
  439.         } else {
  440.            ypos = cypos - rows / 2;
  441.            if ((ypos + rows) > max_dirs) {
  442.           ypos -= (ypos + rows) - max_dirs;
  443.            }
  444.         }
  445.      }
  446.      treq->tr_XPos = xpos;
  447.      treq->tr_YPos = ypos;
  448.      print_dir_tree(treq);
  449.       } else {
  450.      if (mode == MOVE_MODE_NO_CURSOR) {
  451.         print_dir_tree(treq);
  452.      }
  453.       }
  454.       treq->tr_CursorNode = tnode;
  455.       hcomp_treq_cursor(treq);
  456.    }
  457. }
  458.     /* Get tree node by given name */
  459.  
  460.    struct TreeNode *
  461. get_tree_node_by_name(struct TreeRequest *treq, struct TreeNode *tnode,
  462.                                  BYTE *name)
  463. {
  464.    struct TreeNode  *tnode2;
  465.    ULONG len = strlen(name);
  466.    BYTE  *ptr, *path = &treq->tr_DirName[0];
  467.    BOOL  keepon, searching = TRUE;
  468.  
  469.    if (! len) {
  470.       tnode = &treq->tr_RootNode;
  471.       strcpy(path, &tnode->tn_Name[0]);
  472.    } else {
  473.       if (! tnode) {
  474.       tnode = &treq->tr_RootNode;
  475.      strcpy(path, &tnode->tn_Name[0]);
  476.      if (! Strncmp(&tnode->tn_Name[0], name, len)) {
  477.         searching = FALSE;   /* found */
  478.      }
  479.       }
  480.       while (searching == TRUE) {
  481.      tnode2 = (struct TreeNode *)tnode->tn_List.mlh_Head;   /* try to go deeper */
  482.      if (tnode2->tn_Node.mln_Succ) {   /* list not empty ? */
  483.         tnode = tnode2;
  484.         TackOn(path, &tnode->tn_Name[0]);
  485.      } else {
  486.         keepon = TRUE;
  487.         do {   /* else go back */
  488.            ptr = BaseName(path);   /* go one dir back */
  489.            if (*(ptr - 1) == (BYTE)'/') {
  490.           ptr--;
  491.            }
  492.            *ptr  = '\0';
  493.            tnode2 = (struct TreeNode *)tnode->tn_Node.mln_Succ;   /* next dir in list */
  494.            if (tnode2->tn_Node.mln_Succ) {   /* not end of list ? */
  495.           tnode = tnode2;
  496.           TackOn(path, &tnode->tn_Name[0]);
  497.           keepon = FALSE;
  498.            } else {
  499.           if (!(tnode = tnode->tn_ParentNode)) {   /* root reached ? */
  500.              tnode     = NULL;
  501.              keepon    = FALSE;
  502.              searching = FALSE;   /* not found */
  503.           }
  504.            }
  505.         } while (keepon == TRUE);
  506.      }
  507.      if (searching == TRUE) {
  508.         if (! Strncmp(&tnode->tn_Name[0], name, len)) {
  509.            searching = FALSE;
  510.         }
  511.      }
  512.       }
  513.    }
  514.    return(tnode);
  515. }
  516.