home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / wp / dirmacro.zip / DIR.CB next >
Text File  |  1990-04-16  |  25KB  |  910 lines

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