home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / wp / brf3dir.zip / DIR.CB next >
Text File  |  1989-09-29  |  25KB  |  908 lines

  1. /*                                                                                                  */
  2. /*     dir.m:                                                                                     */
  3. /*         A full-fledged, integrated environment for manipulating files         */
  4. /*     and directories from within BRIEF.    Uses the dialog manager.             */
  5. /*     If sorting is desired, also pulls in sort macros.                             */
  6. /*                                                                                                  */
  7. /*         Written by Dan Teven.  Preliminary version, August 6, 1987.          */
  8. /*     Requires the dialog manager from BRIEF version 2.01.                         */
  9. /*                                                                                                  */
  10.  
  11. #include "dialog.h"
  12.  
  13. /*     These definitions are the names of temporary files that the directory */
  14. /*     macro will use.  You can change them to specify a full path name.      */
  15. /*     For best performance, specify a temp file on a RAMdisk.                     */
  16.  
  17. #define TEMP_FILE       "dir.tmp"
  18. #define ERROR_FILE      "dir.err"
  19.  
  20. #define TAG_CHAR          "√"
  21.  
  22. /*     These numbers define the column positions for the various fields         */
  23. /*     of the directory listing (with the format defined here and no tabs).  */
  24. /*     The full definition is a sort command for the buffer.                      */
  25.  
  26. #define NAME_SORT   "_dir_sort"
  27. #define EXT_SORT      "_dir_sort 11"
  28. #define SIZE_SORT   "_dir_sort 15"
  29. #define TIME_SORT   "_dir_sort 25"
  30.  
  31. /*     The tag column is with tabs 6.                                                     */
  32.  
  33. #define TAG_COL      47
  34.  
  35. /*                                                                                                  */
  36. /*     _init:                                                                                     */
  37. /*         Initialize global variables.    The only two global strings are         */
  38. /*     used to hold the current directory path and file spec.                     */
  39. /*                                                                                                  */
  40.  
  41. _init ()
  42. {
  43.     int _dir_buffer,
  44.          _dir_tags;
  45.        string _dir_wd,
  46.              _filespec;
  47.  
  48.     global _dir_wd,
  49.              _filespec,
  50.              _dir_buffer,
  51.              _dir_tags;
  52.  
  53. }
  54.  
  55. /*                                                                                                  */
  56. /*     dir:                                                                                         */
  57. /*         The directory macro.  The syntax is dir [pathspec] where              */
  58. /*     pathspec is an optional alternate path or file specifier to              */
  59. /*     use.                                                                                         */
  60. /*                                                                                                  */
  61.  
  62. dir (...)
  63. {
  64.     extern add_to_path;
  65.  
  66.     int last_loc,
  67.          current_buffer;
  68.  
  69.     string initial_wd;
  70.  
  71.     /*     Get the current directory so we can change back to it upon             */
  72.     /*     exiting.  Make that the default.                                              */
  73.  
  74.     getwd ("", initial_wd);
  75.     _dir_wd = initial_wd;
  76.  
  77.     /*     If no directory spec passed on the command line, we use                 */
  78.     /*     the default.  We use the passed spec if possible.                         */
  79.  
  80.     if (!get_parm (0, _filespec))
  81.         _filespec = _dir_wd;
  82.  
  83.     /*     Try to change immediately to the filespec entered as if                 */
  84.     /*     it were a directory.  If we can change to it, it becomes              */
  85.     /*     the default for future invocations.                                          */
  86.  
  87.     if (cd (_filespec))
  88.         {
  89.         getwd ("", _dir_wd);
  90.         _filespec = "*.*";
  91.         }
  92.     else
  93.         /*     OK, so it wasn't just a directory.                                         */
  94.         /*     If we have a backslash in the path specifier, split it             */
  95.         /*     into a new directory specifier and file specifier.                  */
  96.         /*     If not, it must be all file specifier, which implies                 */
  97.         /*     use of the current directory.                                              */
  98.  
  99.         {
  100.         if (last_loc = search_string ("\\\\[~\\\\/]+", _filespec + "", TRUE))
  101.             {
  102.             _dir_wd = substr (_filespec, 1, last_loc - 1);
  103.             _filespec = substr (_filespec, last_loc + 1);
  104.             }
  105.  
  106.         /*     Try to change to the directory specified.  If the cd                 */
  107.         /*     fails, we know the directory is bad, and we reset it to             */
  108.         /*     the current directory and exit.                                             */
  109.  
  110.         if (cd (_dir_wd))
  111.             getwd ("", _dir_wd);
  112.         else
  113.             {
  114.             error ("Invalid path specified.");
  115.             beep ();
  116.             return FALSE;
  117.             }
  118.         }
  119.  
  120.     message ("Creating directory list...");
  121.  
  122.     /*     Create a temporary file containing the directory listing              */
  123.     /*     for _filespec, and read it in.  We are already in the                  */
  124.     /*     directory referred to.                                                             */
  125.  
  126.     current_buffer = inq_buffer ();
  127.     set_buffer (_dir_buffer = create_buffer ("Directory", NULL, TRUE));
  128.  
  129.     dos ("dir " + (_filespec + (" >&" + TEMP_FILE)));
  130.     read_file (TEMP_FILE);
  131.  
  132.     /*     Determine if any files matched the file spec.  If none did,          */
  133.     /*     we clean up and exit.                                                             */
  134.  
  135.     if (search_back ("<File not found", TRUE, TRUE))
  136.         {
  137.         error ("No files found.");
  138.         beep ();
  139.         }
  140.     else
  141.         {
  142.         _reformat_directory ();
  143.         _process_menu (4, 20, 54, 2, "", "Press Alt-H for Help", NULL, _dir_buffer, "_dir_action", TRUE);
  144.         }
  145.  
  146.     /*     Delete the directory buffer, and the file(s) associated with         */
  147.     /*     it.  Reset the packages for the current buffer.                          */
  148.  
  149.     set_buffer (current_buffer);
  150.     call_registered_macro (1);
  151.     delete_buffer (_dir_buffer);
  152.     del (TEMP_FILE);
  153.  
  154.     /*     Change back to the original directory, and return.                      */
  155.  
  156.     cd (initial_wd);
  157.     return TRUE;
  158. }
  159.  
  160. /*                                                                                                  */
  161. /*     _reformat_directory:                                                                  */
  162. /*         Takes a buffer (named by the global variable _dir_buffer) and         */
  163. /*     converts it to a more readable and useful menu-style format.             */
  164. /*                                                                                                  */
  165.  
  166. _reformat_directory ()
  167. {
  168.     string name;
  169.  
  170.     /*     Delete the first four lines of the file, which are two                 */
  171.     /*     blank lines, the volume label, and the directory specifier.          */
  172.  
  173.     move_abs (4, 1);
  174.     drop_anchor (3);
  175.     top_of_buffer ();
  176.     delete_block ();
  177.  
  178.     /*     Insert a tab before every remaining line of the file.  Then          */
  179.     /*     insert two delimiters into the file, and sort it so that              */
  180.     /*     all the directories are in one list and all the files are             */
  181.     /*     in the other.                                                                         */
  182.  
  183.     translate ("<{[~]*}>", "\\t\\0      ;_dir_tag_line", TRUE, TRUE);
  184.     insert ("Directories:\nFiles:\n");
  185.  
  186.     while (search_fwd ("<DIR>", FALSE, TRUE))
  187.         {
  188.         drop_anchor (3);
  189.         cut ();
  190.         search_back ("<F", TRUE, TRUE);
  191.         paste ();
  192.         }
  193.  
  194.     /*     Remove the <DIR> marker for the directories, which we                  */
  195.     /*     know are all before the current position at this point.                 */
  196.     /*     Also, change the action to _dir_chdir.                                      */
  197.  
  198.     translate ("<DIR>   ", "        ", TRUE, FALSE, TRUE, FALSE, FALSE);
  199.     translate (";_dir_tag_line", ";_dir_chdir", TRUE, FALSE, TRUE, FALSE, FALSE);
  200.  
  201.     /*     Delete the last lines of the buffer, which are the                      */
  202.     /*     number of files/free space and a blank line.                              */
  203.  
  204.     end_of_buffer ();
  205.     up ();
  206.     delete_line ();
  207.     delete_line ();
  208.  
  209.     tabs (6);
  210.     top_of_buffer ();
  211.     _dir_tags = 0;
  212. }
  213.  
  214. /*                                                                                                  */
  215. /*     _dir_action:                                                                             */
  216. /*         Handles events passed to it by the dialog manager.                      */
  217. /*                                                                                                  */
  218.  
  219. _dir_action (...)
  220. {
  221.     int event_type;
  222.  
  223.     string button_text;
  224.  
  225.     get_parm (0, event_type);
  226.  
  227.  
  228.     switch (event_type)
  229.         {
  230.         case DIALOG_INIT:
  231.             {
  232.             assign_to_key ("<Alt-A>", "_dir_tag_all");
  233.             assign_to_key ("<Alt-C>", "_dir_copy");
  234.             assign_to_key ("<Alt-D>", "_dir_delete");
  235.             assign_to_key ("<Alt-E>", "_for_tagged _dir_edit");
  236.             assign_to_key ("<Alt-H>", "_dir_help");
  237.             assign_to_key ("<Alt-N>", NAME_SORT);
  238.             assign_to_key ("<Alt-R>", "_for_tagged _dir_rename");
  239.             assign_to_key ("<Alt-S>", SIZE_SORT);
  240.             assign_to_key ("<Alt-T>", TIME_SORT);
  241.             assign_to_key ("<Alt-X>", EXT_SORT);
  242.             assign_to_key ("<Alt-Z>", "dos");
  243.  
  244.             button_text = "Directory of " + _dir_wd;
  245.  
  246.             /*     If the directory name is the root, we don't                         */
  247.             /*     add the \ before the file specifier.                                 */
  248.  
  249.             if (strlen (_dir_wd) > 3)
  250.                 button_text += "\\";
  251.             message (button_text + (_filespec + "."));
  252.             }
  253.         case DIALOG_TERM:
  254.             {
  255.             assign_to_key ("<Alt-A>", "nothing");
  256.             assign_to_key ("<Alt-C>", "nothing");
  257.             assign_to_key ("<Alt-D>", "nothing");
  258.             assign_to_key ("<Alt-E>", "nothing");
  259.             assign_to_key ("<Alt-H>", "nothing");
  260.             assign_to_key ("<Alt-N>", "nothing");
  261.             assign_to_key ("<Alt-R>", "nothing");
  262.             assign_to_key ("<Alt-S>", "nothing");
  263.             assign_to_key ("<Alt-T>", "nothing");
  264.             assign_to_key ("<Alt-X>", "nothing");
  265.             assign_to_key ("<Alt-Z>", "nothing");
  266.             }
  267.  
  268.             /*     We check to make sure there's a semicolon on the line          */
  269.             /*     before we move to it.                                                     */
  270.  
  271.         case DIALOG_ALTER_MENU:
  272.             {
  273.             get_parm (2, button_text);
  274.  
  275.             if (!index (button_text, ";"))
  276.                 return FALSE;
  277.             }
  278.  
  279.             /*     If a menu button is picked, we execute the action                 */
  280.             /*     associated with the button.  This action will be either         */
  281.             /*     changing to another directory or tagging a file.                 */
  282.  
  283.         case DIALOG_PICK_MENU:
  284.             {
  285.             get_parm (2, button_text);
  286.  
  287.             execute_macro (substr (button_text, index (button_text, ";") + 1));
  288.             }
  289.         }
  290.     returns TRUE;
  291. }
  292.  
  293. /*     _dir_tag_all:                                                                             */
  294. /*         If there are tagged files, untags them all.    Otherwise, tags         */
  295. /*     all the files.                                                                          */
  296.  
  297. _dir_tag_all ()
  298. {
  299.     save_position ();
  300.     top_of_buffer ();
  301.  
  302.     /*     If any lines are tagged, untag them.  If none are, tag                 */
  303.     /*     them all.                                                                             */
  304.  
  305.     if (_dir_tags)
  306.         {
  307.         _dir_tags = 0;
  308.         translate (TAG_CHAR, " ", TRUE, FALSE);
  309.         }
  310.     else
  311.         {
  312.         search_fwd ("<F", TRUE, TRUE);
  313.         down ();
  314.  
  315.         while (!inq_position ())
  316.             {
  317.             _dir_tag_line ();
  318.             down ();
  319.             }
  320.         }
  321.     restore_position ();
  322. }
  323.  
  324. /*                                                                                                  */
  325. /*     _dir_tag_line:                                                                          */
  326. /*         Toggles the tag state of a particular file.                                 */
  327. /*                                                                                                  */
  328.  
  329. _dir_tag_line (...)
  330. {
  331.     move_abs (0, TAG_COL);
  332.  
  333.     if (read (1) == TAG_CHAR)
  334.         {
  335.         insert (" ");
  336.         --_dir_tags;
  337.         }
  338.     else
  339.         {
  340.         insert (TAG_CHAR);
  341.         ++_dir_tags;
  342.         }
  343.     delete_char ();
  344.     beginning_of_line ();
  345. }
  346.  
  347. /*                                                                                                  */
  348. /*     _dir_filename:                                                                          */
  349. /*         Reads and returns the filename the cursor is located at.              */
  350. /*     If the name is not a file or directory, returns "".                         */
  351. /*                                                                                                  */
  352.  
  353. _dir_filename (...)
  354. {
  355.     int space_loc,
  356.          ext_loc;
  357.  
  358.     string file_name;
  359.  
  360.     /*     If we have no semicolon on this line, it's not the name of             */
  361.     /*     a file or directory, so we return a null string.                         */
  362.  
  363.     if (!index (file_name = read (), ";"))
  364.         return "";
  365.  
  366.     /*     Trim leading and trailing white space (and the rest of the             */
  367.     /*     line) from the name.  If we have any white space left,                 */
  368.     /*     it's in the middle and must be replaced by a period.                     */
  369.  
  370.     file_name = lower (trim (ltrim (substr (file_name, 1, 13))));
  371.  
  372.     if (space_loc = index (file_name, " "))
  373.         {
  374.         ext_loc = rindex (file_name, " ") + 1;
  375.         file_name = (substr (file_name, 1, --space_loc) + ".") + substr (file_name, ext_loc);
  376.         }
  377.     return file_name;
  378. }
  379.  
  380. /*                                                                                                  */
  381. /*     _dir_tagged:                                                                             */
  382. /*         Returns TRUE if the current file is tagged, FALSE otherwise.         */
  383. /*                                                                                                  */
  384.  
  385. int _dir_tagged ()
  386. {
  387.    int val;      
  388.    move_abs (0, TAG_COL);
  389.    val = read (1) == TAG_CHAR;   
  390.    refresh();
  391.     beginning_of_line ();
  392.       return val;
  393. }
  394.  
  395. /*                                                                                                  */
  396. /*     _dir_chdir:                                                                              */
  397. /*         Changes the current directory and redisplays.                             */
  398. /*                                                                                                  */
  399.  
  400. _dir_chdir (...)
  401. {
  402.     string new_dir;
  403.  
  404.     /*     Read the directory name from the buffer, and trim leading and         */
  405.     /*     trailing white space from it.  If we have any white space left,     */
  406.     /*     it's in the middle and must be replaced by a period.    If we          */
  407.     /*     have just a period, we return; we're already on the current          */
  408.     /*     directory.                                                                             */
  409.  
  410.     if ((new_dir = _dir_filename ()) == ".")
  411.         {
  412.         beep ();
  413.         return;
  414.         }
  415.  
  416.     /*     Change directory.  Since we may not be coming back, make              */
  417.     /*     sure we remove the TEMP_FILE first.                                          */
  418.  
  419.     message ("Changing directory...");
  420.     del (TEMP_FILE);
  421.  
  422.     /*     Change to the new directory, which we know is a legal directory,     */
  423.     /*     and get the new working directory name.  Write a new temp file.     */
  424.     /*     Delete the existing buffer and read in the new one; reformat         */
  425.     /*     it; bring it into the window.                                                  */
  426.  
  427.     cd (new_dir);
  428.     getwd ("", _dir_wd);
  429.     new_dir = _dir_wd;
  430.     _filespec = "*.*";
  431.     _dir_refresh ();
  432.  
  433.     /*     If the directory is the root, we don't                                      */
  434.     /*     add the \ before the file specifier.                                         */
  435.  
  436.     if (strlen (new_dir) > 3)
  437.         new_dir += "\\";
  438.     message ("Directory of %s*.*.", new_dir);
  439. }
  440.  
  441. /*                                                                                                  */
  442. /*     _dir_refresh:                                                                             */
  443. /*         Calls DOS to write the directory to the temp file, deletes             */
  444. /*     the contents of the current buffer, and reads the temp file              */
  445. /*     back in.  Reformats the directory and restores the highlight             */
  446. /*     (that delete_block removed).                                                         */
  447. /*                                                                                                  */
  448.  
  449. _dir_refresh (...)
  450. {
  451.     extern _dialog_menu_home;
  452.  
  453.     dos ("dir " + (_filespec + (">&" + TEMP_FILE)));
  454.     raise_anchor ();
  455.     top_of_buffer ();
  456.     drop_anchor (1);
  457.     end_of_buffer ();
  458.     prev_char ();
  459.     delete_block ();
  460.     read_file (TEMP_FILE);
  461.     top_of_buffer ();
  462.     _reformat_directory ();
  463.     _dialog_menu_home ();
  464. }
  465.  
  466. /*                                                                                                  */
  467. /*     _for_tagged:                                                                             */
  468. /*         For all the lines that are tagged, performs another macro             */
  469. /*     that is passed to it as a parameter.  If no lines are tagged,             */
  470. /*     performs the macro on the current line.                                         */
  471. /*                                                                                                  */
  472.  
  473. _for_tagged (...)
  474. {
  475.     string action;
  476.  
  477.     get_parm (0, action);
  478.  
  479.     if (_dir_tags)
  480.         {
  481.            raise_anchor ();
  482.         save_position ();
  483.         top_of_buffer ();
  484.         search_fwd ("<F", TRUE, TRUE);
  485.         down ();
  486.  
  487.         while (!inq_position ())
  488.             {
  489.             if (_dir_tagged ())
  490.                 execute_macro (action);
  491.                down ();
  492.             }
  493.         restore_position ();
  494.         drop_anchor (3);
  495.         message ("Done.");
  496.         }
  497.     else
  498.         execute_macro (action);
  499. }
  500.  
  501. /*                                                                                                  */
  502. /*     _dir_edit:                                                                                 */
  503. /*         Parses a filename from the current line, and creates a buffer         */
  504. /*     for it.    Does not remove the directory menu.                                  */
  505. /*                                                                                                  */
  506.  
  507. _dir_edit (...)
  508. {
  509.     string file_name;
  510.  
  511.     int not_legal_file,
  512.          old_buffer;
  513.  
  514.     /*     If the current line is not a file, we don't want to edit              */
  515.     /*     it.  The best way to tell if it is a file is to search                 */
  516.     /*     forward for the Files: marker; if we don't find it, it's              */
  517.     /*     a file.                                                                                 */
  518.  
  519.     save_position ();
  520.     not_legal_file = search_fwd ("<F", TRUE, TRUE);
  521.     restore_position ();
  522.  
  523.     if (not_legal_file)
  524.         beep ();
  525.     else
  526.         {
  527.         file_name = _dir_filename ();
  528.         old_buffer = inq_buffer ();
  529.         set_buffer (create_buffer (file_name, file_name, FALSE));
  530.         call_registered_macro (1);
  531.         set_buffer (old_buffer);
  532.         call_registered_macro (1);
  533.         message ("File %s edited.", file_name);
  534.         }
  535. }
  536.  
  537. /*                                                                                                  */
  538. /*     _dir_copy:                                                                                 */
  539. /*         Prompts for a destination to copy to.    If files are tagged,          */
  540. /*     copies all the tagged files to the same destination.    If not,             */
  541. /*     copies the current file to the destination.    Redraws the menu             */
  542. /*     when it's done.                                                                         */
  543. /*                                                                                                  */
  544.  
  545. _dir_copy (...)
  546. {
  547.     string prompt;
  548.  
  549.     /*     Prompt for the destination to copy the file to.  If Esc                 */
  550.     /*     is pressed, do not copy it.                                                     */
  551.  
  552.     if (_dir_tags)
  553.         sprintf (prompt, "Copy %d tagged files to: ", _dir_tags);
  554.     else
  555.         {
  556.         if ((prompt = _dir_filename ()) == "")
  557.             {
  558.             beep ();
  559.             return;
  560.             }
  561.         prompt = "Copy " + (prompt + " to: ");
  562.         }
  563.  
  564.     if (get_parm (0, prompt, prompt, 64))
  565.         {
  566.         _for_tagged ("__dir_copy " + prompt);
  567.         message ("Updating directory...");
  568.         raise_anchor ();
  569.         save_position ();
  570.         _dir_refresh ();
  571.         restore_position ();
  572.         drop_anchor (3);
  573.         message ("");
  574.         }
  575.     else
  576.         message ("Copy cancelled.");
  577. }
  578.  
  579. /*                                                                                                  */
  580. /*     __dir_copy:                                                                              */
  581. /*         Lower level routine that copies the file where the                      */
  582. /*     cursor is located to the passed destination.                                  */
  583. /*                                                                                                  */
  584.  
  585. __dir_copy (...)
  586. {
  587.     string command,
  588.              destination;
  589.  
  590.     int error_buf;
  591.  
  592.     /*     Build the copy command.  We are already in the same                     */
  593.     /*     directory as the source file, so we don't need a full                  */
  594.     /*     path name for that file.  We allow a path name for the                 */
  595.     /*     destination file.                                                                  */
  596.  
  597.     if ((destination = _dir_filename ()) == "")
  598.         {
  599.         beep ();
  600.         return;
  601.         }
  602.  
  603.     message ("Copying %s...", destination);
  604.     sprintf (command, "copy %s ", destination);
  605.     get_parm (0, destination);
  606.     command += destination + (" >&" + ERROR_FILE);
  607.  
  608.     /*     Copy the file, and get the error file (if any) into                     */
  609.     /*     a system buffer.    This is the only way to check for errors.          */
  610.  
  611.     dos (command);
  612.     set_buffer (error_buf = create_buffer (ERROR_FILE, ERROR_FILE, TRUE));
  613.  
  614.     /*     Check for errors in the file.                                                  */
  615.  
  616.     if (search_fwd ("File(s) copied", FALSE, TRUE))
  617.         message ("Copied.");
  618.     else
  619.         {
  620.         error ("%s.", trim (ltrim (read ())));
  621.         beep ();
  622.         }
  623.  
  624.     /*     Delete the error buffer and file, and change back to                     */
  625.     /*     the directory buffer.                                                             */
  626.  
  627.     set_buffer (_dir_buffer);
  628.     delete_buffer (error_buf);
  629.     del (ERROR_FILE);
  630. }
  631.  
  632. /*                                                                                                  */
  633. /*     _dir_delete:                                                                             */
  634. /*         If files are tagged, deletes them all after confirmation.             */
  635. /*     If none are, deletes the marked file after confirmation.                  */
  636. /*     (If a directory is selected, beeps.)                                             */
  637. /*                                                                                                  */
  638.  
  639. _dir_delete (...)
  640. {
  641.     string response;
  642.  
  643.     int not_legal_file;
  644.  
  645.     /*     Only ask for confirmation once.    It will be handy to be                 */
  646.     /*     able to delete groups of files without being nagged.                     */
  647.     /*     If files are marked, we only use those; if none are, we                 */
  648.     /*     have to make sure that a file is selected.                                 */
  649.  
  650.     if (_dir_tags)
  651.         sprintf (response, "Delete %d tagged files from disk [yn]? ", _dir_tags);
  652.     else
  653.         {
  654.         save_position ();
  655.         not_legal_file = search_fwd ("<F", TRUE, TRUE);
  656.         restore_position ();
  657.  
  658.         if (not_legal_file)
  659.             {
  660.             beep ();
  661.             return;
  662.             }
  663.         sprintf (response, "Delete %s from disk [yn]? ", _dir_filename ());
  664.         }
  665.  
  666.     /*     If we can proceed, we delete all the files.    Note that                 */
  667.     /*     __dir_delete has to move up after deleting a line from                 */
  668.     /*     the buffer so that all tagged files will be seen.    This                 */
  669.     /*     is why we move down afterward, then move back up while we             */
  670.     /*     are past EOF.    We can never end up past EOF, and we end                 */
  671.     /*     up where we were before if there are files below which                 */
  672.     /*     can move up in the list.                                                         */
  673.  
  674.     if (get_parm (0, response, response, 1) && lower (response) == "y")
  675.         {
  676.         _for_tagged ("__dir_delete");
  677.         raise_anchor ();
  678.         down ();
  679.  
  680.         while (inq_position ())
  681.             up ();
  682.         drop_anchor (3);
  683.         }
  684.     else
  685.         message ("Deletion cancelled.");
  686. }
  687.  
  688. /*                                                                                                  */
  689. /*     __dir_delete:                                                                             */
  690. /*         Lower level call to read a filename and actually delete it.          */
  691. /*     Corrects the display by removing the line the file was on.                 */
  692. /*                                                                                                  */
  693.  
  694. __dir_delete (...)
  695. {
  696.     string file_name,
  697.              temp;
  698.  
  699.     int file_attrib;
  700.  
  701.     file_name = _dir_filename ();
  702.     temp = add_to_path (_dir_wd, file_name);
  703.  
  704.     if (del (file_name) <= 0)
  705.         /*     We know the file exists, since it's in our list.                     */
  706.         /*     (If the user did something stupid during an Alt-Z,                  */
  707.         /*     that's his problem.)                                                          */
  708.         /*     We know that system, hidden, and volume files do                     */
  709.         /*     not make it into the directory list, and directories                 */
  710.         /*     are already sorted out; so the only weird attribute                 */
  711.         /*     the file could have is read-only.  If the file is                     */
  712.         /*     read-only, that's why the del failed.    If not, it                     */
  713.         /*     must have failed because the file's being edited.                     */
  714.  
  715.         {
  716.         file_pattern (file_name);
  717.         find_file (NULL, NULL, NULL, NULL, file_attrib);
  718.  
  719.         if (file_attrib & 0x0001)
  720.             {
  721.             error ("File %s is read-only.", file_name);
  722.             beep ();
  723.             }
  724.         else
  725.             {
  726.             error ("You can't delete an edited file.");
  727.             beep ();
  728.             }
  729.         return;
  730.         }
  731.  
  732.     if (_dir_tagged ())
  733.    {
  734.        error ("decrementing _dir_tags %d", _dir_tags);
  735.        --_dir_tags;
  736.    }
  737.       
  738.     delete_line ();
  739.     up ();
  740.     message ("File %s deleted.", file_name);
  741. }
  742.  
  743. /*                                                                                                  */
  744. /*     _dir_rename:                                                                             */
  745. /*         For the current file, prompts for a new name, and attempts             */
  746. /*     to rename it.    Uses command-level rename, and so does not work          */
  747. /*     across directories.                                                                     */
  748. /*                                                                                                  */
  749.  
  750. _dir_rename (...)
  751. {
  752.     string prompt,
  753.              destination,
  754.              file_name;
  755.  
  756.     int error_buf,
  757.          ext_loc;
  758.  
  759.     /*     If we are not on a file name, beep.                                          */
  760.  
  761.     save_position ();
  762.     ext_loc = search_fwd ("<F", TRUE, TRUE);
  763.     restore_position ();
  764.  
  765.     if (ext_loc)
  766.         {
  767.         beep ();
  768.         return;
  769.         }
  770.  
  771.     /*     First, get the destination.  We allow only a 12-character             */
  772.     /*     response since path names are not legal.    Then build the              */
  773.     /*     rename command.                                                                     */
  774.  
  775.     sprintf (prompt, "Rename %s to: ", file_name = _dir_filename ());
  776.  
  777.     if (get_parm (0, destination, prompt, 12))
  778.         {
  779.         sprintf (prompt, "rename %s ", file_name);
  780.         prompt += destination + (" >&" + ERROR_FILE);
  781.  
  782.         /*     Rename the file, and get the error file (if any) into              */
  783.         /*     a system buffer.    This is the only way to catch errors.             */
  784.  
  785.         dos (prompt);
  786.         set_buffer (error_buf = create_buffer (ERROR_FILE, ERROR_FILE, TRUE));
  787.  
  788.         /*     Check for errors in the file.  If there were none,                  */
  789.         /*     update the screen with the new name.                                     */
  790.  
  791.         if (read (1) == "\n")
  792.             {
  793.             message ("Renamed.");
  794.             set_buffer (_dir_buffer);
  795.             drop_anchor (1);
  796.             move_abs (0, 17);
  797.             delete_block ();
  798.  
  799.             if (ext_loc = index (destination, "."))
  800.                 {
  801.                 sprintf (file_name, "\t%-8s ", substr (destination, 1, ext_loc - 1));
  802.                 sprintf (prompt, "%-3s", substr (destination, ext_loc + 1));
  803.                 file_name += prompt;
  804.                 }
  805.             else
  806.                 sprintf (file_name, "\t%-12s", destination);
  807.             insert (upper (file_name));
  808.             beginning_of_line ();
  809.             }
  810.         else
  811.             {
  812.             error ("%s.", trim (ltrim (read ())));
  813.             beep ();
  814.             }
  815.  
  816.         /*     Delete the error buffer and file, and change back to                 */
  817.         /*     the directory buffer.                                                         */
  818.  
  819.         set_buffer (_dir_buffer);
  820.         delete_buffer (error_buf);
  821.         del (ERROR_FILE);
  822.         }
  823.     else
  824.         message ("Rename cancelled.");
  825. }
  826.  
  827. /*                                                                                                  */
  828. /*     _dir_sort:                                                                                 */
  829. /*         Sorts the files and directories (separately) on one of several      */
  830. /*     criteria, including name, extension, size, and time.                         */
  831. /*                                                                                                  */
  832.  
  833. _dir_sort (...)
  834. {
  835.     int sort_col;
  836.  
  837.     string sort_command;
  838.  
  839.     extern sort_block;
  840.  
  841.     /*     Do a little error checking.                                                     */
  842.  
  843.     if (!inq_macro ("sort_buffer") && load_macro ("sort") <= 0)
  844.         {
  845.         error ("Unable to load sort macro.");
  846.         beep ();
  847.         return;
  848.         }
  849.  
  850.     if (get_parm (0, sort_col))
  851.         sprintf (sort_command, "sort_block %d", sort_col);
  852.     else
  853.         sort_command = "sort_block";
  854.  
  855.     /*     Turn off the status messages while we sort.    Temporarily              */
  856.     /*     raise the line mark and save its location, while we use                 */
  857.     /*     another line mark to delimit the areas to sort.                          */
  858.  
  859.     raise_anchor ();
  860.     save_position ();
  861.  
  862.     /*     Mark the directories in the list to be sorted first, then sort.     */
  863.     /*     Note that sort_block and _sort_on_field remove the anchor.             */
  864.  
  865.     top_of_buffer ();
  866.     down ();
  867.     drop_anchor (3);
  868.     search_fwd ("<F", TRUE, TRUE);
  869.     up ();
  870.     execute_macro (sort_command);
  871.  
  872.     /*     Mark the files, then sort.                                                      */
  873.  
  874.     search_fwd ("<F", TRUE, TRUE);
  875.     down ();
  876.     drop_anchor (3);
  877.     end_of_buffer ();
  878.     execute_macro (sort_command);
  879.  
  880.     /*     Clean up.  Put the cursor where we found it, and restore              */
  881.     /*     the mark.  Clear the message line.                                             */
  882.  
  883.     restore_position ();
  884.     drop_anchor (3);
  885. }
  886.  
  887. /*                                                                                                  */
  888. /*     _dir_help:                                                                                 */
  889. /*         Finds the help file in BHELP and displays it in a pop-up              */
  890. /*     window.    Clears the window when any key is pressed.                         */
  891. /*                                                                                                  */
  892.  
  893. _dir_help (...)
  894. {
  895.     int help_buffer;
  896.  
  897.     set_buffer (help_buffer = create_buffer ("Help", "c:/brief/help/dir.txt", TRUE));
  898.     create_window (16, 21, 49, 5, "Any key to resume");
  899.     attach_buffer (help_buffer);
  900.     refresh ();
  901.     while (!inq_kbd_char ())
  902.         ;
  903.     read_char ();
  904.     set_buffer (_dir_buffer);
  905.     delete_window ();
  906.     delete_buffer (help_buffer);
  907. }
  908.