Category : Miscellaneous Language Source Code
Archive   : BRF3DIR.ZIP
Filename : DIR.CB
Output of file : DIR.CB contained in archive : BRF3DIR.ZIP
/* dir.m: */
/* A full-fledged, integrated environment for manipulating files */
/* and directories from within BRIEF. Uses the dialog manager. */
/* If sorting is desired, also pulls in sort macros. */
/* */
/* Written by Dan Teven. Preliminary version, August 6, 1987. */
/* Requires the dialog manager from BRIEF version 2.01. */
/* */
#include "dialog.h"
/* These definitions are the names of temporary files that the directory */
/* macro will use. You can change them to specify a full path name. */
/* For best performance, specify a temp file on a RAMdisk. */
#define TEMP_FILE "dir.tmp"
#define ERROR_FILE "dir.err"
#define TAG_CHAR "û"
/* These numbers define the column positions for the various fields */
/* of the directory listing (with the format defined here and no tabs). */
/* The full definition is a sort command for the buffer. */
#define NAME_SORT "_dir_sort"
#define EXT_SORT "_dir_sort 11"
#define SIZE_SORT "_dir_sort 15"
#define TIME_SORT "_dir_sort 25"
/* The tag column is with tabs 6. */
#define TAG_COL 47
/* */
/* _init: */
/* Initialize global variables. The only two global strings are */
/* used to hold the current directory path and file spec. */
/* */
_init ()
{
int _dir_buffer,
_dir_tags;
string _dir_wd,
_filespec;
global _dir_wd,
_filespec,
_dir_buffer,
_dir_tags;
}
/* */
/* dir: */
/* The directory macro. The syntax is dir [pathspec] where */
/* pathspec is an optional alternate path or file specifier to */
/* use. */
/* */
dir (...)
{
extern add_to_path;
int last_loc,
current_buffer;
string initial_wd;
/* Get the current directory so we can change back to it upon */
/* exiting. Make that the default. */
getwd ("", initial_wd);
_dir_wd = initial_wd;
/* If no directory spec passed on the command line, we use */
/* the default. We use the passed spec if possible. */
if (!get_parm (0, _filespec))
_filespec = _dir_wd;
/* Try to change immediately to the filespec entered as if */
/* it were a directory. If we can change to it, it becomes */
/* the default for future invocations. */
if (cd (_filespec))
{
getwd ("", _dir_wd);
_filespec = "*.*";
}
else
/* OK, so it wasn't just a directory. */
/* If we have a backslash in the path specifier, split it */
/* into a new directory specifier and file specifier. */
/* If not, it must be all file specifier, which implies */
/* use of the current directory. */
{
if (last_loc = search_string ("\\\\[~\\\\/]+", _filespec + "", TRUE))
{
_dir_wd = substr (_filespec, 1, last_loc - 1);
_filespec = substr (_filespec, last_loc + 1);
}
/* Try to change to the directory specified. If the cd */
/* fails, we know the directory is bad, and we reset it to */
/* the current directory and exit. */
if (cd (_dir_wd))
getwd ("", _dir_wd);
else
{
error ("Invalid path specified.");
beep ();
return FALSE;
}
}
message ("Creating directory list...");
/* Create a temporary file containing the directory listing */
/* for _filespec, and read it in. We are already in the */
/* directory referred to. */
current_buffer = inq_buffer ();
set_buffer (_dir_buffer = create_buffer ("Directory", NULL, TRUE));
dos ("dir " + (_filespec + (" >&" + TEMP_FILE)));
read_file (TEMP_FILE);
/* Determine if any files matched the file spec. If none did, */
/* we clean up and exit. */
if (search_back ("
error ("No files found.");
beep ();
}
else
{
_reformat_directory ();
_process_menu (4, 20, 54, 2, "", "Press Alt-H for Help", NULL, _dir_buffer, "_dir_action", TRUE);
}
/* Delete the directory buffer, and the file(s) associated with */
/* it. Reset the packages for the current buffer. */
set_buffer (current_buffer);
call_registered_macro (1);
delete_buffer (_dir_buffer);
del (TEMP_FILE);
/* Change back to the original directory, and return. */
cd (initial_wd);
return TRUE;
}
/* */
/* _reformat_directory: */
/* Takes a buffer (named by the global variable _dir_buffer) and */
/* converts it to a more readable and useful menu-style format. */
/* */
_reformat_directory ()
{
string name;
/* Delete the first four lines of the file, which are two */
/* blank lines, the volume label, and the directory specifier. */
move_abs (4, 1);
drop_anchor (3);
top_of_buffer ();
delete_block ();
/* Insert a tab before every remaining line of the file. Then */
/* insert two delimiters into the file, and sort it so that */
/* all the directories are in one list and all the files are */
/* in the other. */
translate ("<{[~]*}>", "\\t\\0 ;_dir_tag_line", TRUE, TRUE);
insert ("Directories:\nFiles:\n");
while (search_fwd ("
{
drop_anchor (3);
cut ();
search_back ("
}
/* Remove the
/* know are all before the current position at this point. */
/* Also, change the action to _dir_chdir. */
translate ("
translate (";_dir_tag_line", ";_dir_chdir", TRUE, FALSE, TRUE, FALSE, FALSE);
/* Delete the last lines of the buffer, which are the */
/* number of files/free space and a blank line. */
end_of_buffer ();
up ();
delete_line ();
delete_line ();
tabs (6);
top_of_buffer ();
_dir_tags = 0;
}
/* */
/* _dir_action: */
/* Handles events passed to it by the dialog manager. */
/* */
_dir_action (...)
{
int event_type;
string button_text;
get_parm (0, event_type);
switch (event_type)
{
case DIALOG_INIT:
{
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
button_text = "Directory of " + _dir_wd;
/* If the directory name is the root, we don't */
/* add the \ before the file specifier. */
if (strlen (_dir_wd) > 3)
button_text += "\\";
message (button_text + (_filespec + "."));
}
case DIALOG_TERM:
{
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
assign_to_key ("
}
/* We check to make sure there's a semicolon on the line */
/* before we move to it. */
case DIALOG_ALTER_MENU:
{
get_parm (2, button_text);
if (!index (button_text, ";"))
return FALSE;
}
/* If a menu button is picked, we execute the action */
/* associated with the button. This action will be either */
/* changing to another directory or tagging a file. */
case DIALOG_PICK_MENU:
{
get_parm (2, button_text);
execute_macro (substr (button_text, index (button_text, ";") + 1));
}
}
returns TRUE;
}
/* _dir_tag_all: */
/* If there are tagged files, untags them all. Otherwise, tags */
/* all the files. */
_dir_tag_all ()
{
save_position ();
top_of_buffer ();
/* If any lines are tagged, untag them. If none are, tag */
/* them all. */
if (_dir_tags)
{
_dir_tags = 0;
translate (TAG_CHAR, " ", TRUE, FALSE);
}
else
{
search_fwd ("
while (!inq_position ())
{
_dir_tag_line ();
down ();
}
}
restore_position ();
}
/* */
/* _dir_tag_line: */
/* Toggles the tag state of a particular file. */
/* */
_dir_tag_line (...)
{
move_abs (0, TAG_COL);
if (read (1) == TAG_CHAR)
{
insert (" ");
--_dir_tags;
}
else
{
insert (TAG_CHAR);
++_dir_tags;
}
delete_char ();
beginning_of_line ();
}
/* */
/* _dir_filename: */
/* Reads and returns the filename the cursor is located at. */
/* If the name is not a file or directory, returns "". */
/* */
_dir_filename (...)
{
int space_loc,
ext_loc;
string file_name;
/* If we have no semicolon on this line, it's not the name of */
/* a file or directory, so we return a null string. */
if (!index (file_name = read (), ";"))
return "";
/* Trim leading and trailing white space (and the rest of the */
/* line) from the name. If we have any white space left, */
/* it's in the middle and must be replaced by a period. */
file_name = lower (trim (ltrim (substr (file_name, 1, 13))));
if (space_loc = index (file_name, " "))
{
ext_loc = rindex (file_name, " ") + 1;
file_name = (substr (file_name, 1, --space_loc) + ".") + substr (file_name, ext_loc);
}
return file_name;
}
/* */
/* _dir_tagged: */
/* Returns TRUE if the current file is tagged, FALSE otherwise. */
/* */
int _dir_tagged ()
{
int val;
move_abs (0, TAG_COL);
val = read (1) == TAG_CHAR;
refresh();
beginning_of_line ();
return val;
}
/* */
/* _dir_chdir: */
/* Changes the current directory and redisplays. */
/* */
_dir_chdir (...)
{
string new_dir;
/* Read the directory name from the buffer, and trim leading and */
/* trailing white space from it. If we have any white space left, */
/* it's in the middle and must be replaced by a period. If we */
/* have just a period, we return; we're already on the current */
/* directory. */
if ((new_dir = _dir_filename ()) == ".")
{
beep ();
return;
}
/* Change directory. Since we may not be coming back, make */
/* sure we remove the TEMP_FILE first. */
message ("Changing directory...");
del (TEMP_FILE);
/* Change to the new directory, which we know is a legal directory, */
/* and get the new working directory name. Write a new temp file. */
/* Delete the existing buffer and read in the new one; reformat */
/* it; bring it into the window. */
cd (new_dir);
getwd ("", _dir_wd);
new_dir = _dir_wd;
_filespec = "*.*";
_dir_refresh ();
/* If the directory is the root, we don't */
/* add the \ before the file specifier. */
if (strlen (new_dir) > 3)
new_dir += "\\";
message ("Directory of %s*.*.", new_dir);
}
/* */
/* _dir_refresh: */
/* Calls DOS to write the directory to the temp file, deletes */
/* the contents of the current buffer, and reads the temp file */
/* back in. Reformats the directory and restores the highlight */
/* (that delete_block removed). */
/* */
_dir_refresh (...)
{
extern _dialog_menu_home;
dos ("dir " + (_filespec + (">&" + TEMP_FILE)));
raise_anchor ();
top_of_buffer ();
drop_anchor (1);
end_of_buffer ();
prev_char ();
delete_block ();
read_file (TEMP_FILE);
top_of_buffer ();
_reformat_directory ();
_dialog_menu_home ();
}
/* */
/* _for_tagged: */
/* For all the lines that are tagged, performs another macro */
/* that is passed to it as a parameter. If no lines are tagged, */
/* performs the macro on the current line. */
/* */
_for_tagged (...)
{
string action;
get_parm (0, action);
if (_dir_tags)
{
raise_anchor ();
save_position ();
top_of_buffer ();
search_fwd ("
while (!inq_position ())
{
if (_dir_tagged ())
execute_macro (action);
down ();
}
restore_position ();
drop_anchor (3);
message ("Done.");
}
else
execute_macro (action);
}
/* */
/* _dir_edit: */
/* Parses a filename from the current line, and creates a buffer */
/* for it. Does not remove the directory menu. */
/* */
_dir_edit (...)
{
string file_name;
int not_legal_file,
old_buffer;
/* If the current line is not a file, we don't want to edit */
/* it. The best way to tell if it is a file is to search */
/* forward for the Files: marker; if we don't find it, it's */
/* a file. */
save_position ();
not_legal_file = search_fwd ("
if (not_legal_file)
beep ();
else
{
file_name = _dir_filename ();
old_buffer = inq_buffer ();
set_buffer (create_buffer (file_name, file_name, FALSE));
call_registered_macro (1);
set_buffer (old_buffer);
call_registered_macro (1);
message ("File %s edited.", file_name);
}
}
/* */
/* _dir_copy: */
/* Prompts for a destination to copy to. If files are tagged, */
/* copies all the tagged files to the same destination. If not, */
/* copies the current file to the destination. Redraws the menu */
/* when it's done. */
/* */
_dir_copy (...)
{
string prompt;
/* Prompt for the destination to copy the file to. If Esc */
/* is pressed, do not copy it. */
if (_dir_tags)
sprintf (prompt, "Copy %d tagged files to: ", _dir_tags);
else
{
if ((prompt = _dir_filename ()) == "")
{
beep ();
return;
}
prompt = "Copy " + (prompt + " to: ");
}
if (get_parm (0, prompt, prompt, 64))
{
_for_tagged ("__dir_copy " + prompt);
message ("Updating directory...");
raise_anchor ();
save_position ();
_dir_refresh ();
restore_position ();
drop_anchor (3);
message ("");
}
else
message ("Copy cancelled.");
}
/* */
/* __dir_copy: */
/* Lower level routine that copies the file where the */
/* cursor is located to the passed destination. */
/* */
__dir_copy (...)
{
string command,
destination;
int error_buf;
/* Build the copy command. We are already in the same */
/* directory as the source file, so we don't need a full */
/* path name for that file. We allow a path name for the */
/* destination file. */
if ((destination = _dir_filename ()) == "")
{
beep ();
return;
}
message ("Copying %s...", destination);
sprintf (command, "copy %s ", destination);
get_parm (0, destination);
command += destination + (" >&" + ERROR_FILE);
/* Copy the file, and get the error file (if any) into */
/* a system buffer. This is the only way to check for errors. */
dos (command);
set_buffer (error_buf = create_buffer (ERROR_FILE, ERROR_FILE, TRUE));
/* Check for errors in the file. */
if (search_fwd ("File(s) copied", FALSE, TRUE))
message ("Copied.");
else
{
error ("%s.", trim (ltrim (read ())));
beep ();
}
/* Delete the error buffer and file, and change back to */
/* the directory buffer. */
set_buffer (_dir_buffer);
delete_buffer (error_buf);
del (ERROR_FILE);
}
/* */
/* _dir_delete: */
/* If files are tagged, deletes them all after confirmation. */
/* If none are, deletes the marked file after confirmation. */
/* (If a directory is selected, beeps.) */
/* */
_dir_delete (...)
{
string response;
int not_legal_file;
/* Only ask for confirmation once. It will be handy to be */
/* able to delete groups of files without being nagged. */
/* If files are marked, we only use those; if none are, we */
/* have to make sure that a file is selected. */
if (_dir_tags)
sprintf (response, "Delete %d tagged files from disk [yn]? ", _dir_tags);
else
{
save_position ();
not_legal_file = search_fwd ("
if (not_legal_file)
{
beep ();
return;
}
sprintf (response, "Delete %s from disk [yn]? ", _dir_filename ());
}
/* If we can proceed, we delete all the files. Note that */
/* __dir_delete has to move up after deleting a line from */
/* the buffer so that all tagged files will be seen. This */
/* is why we move down afterward, then move back up while we */
/* are past EOF. We can never end up past EOF, and we end */
/* up where we were before if there are files below which */
/* can move up in the list. */
if (get_parm (0, response, response, 1) && lower (response) == "y")
{
_for_tagged ("__dir_delete");
raise_anchor ();
down ();
while (inq_position ())
up ();
drop_anchor (3);
}
else
message ("Deletion cancelled.");
}
/* */
/* __dir_delete: */
/* Lower level call to read a filename and actually delete it. */
/* Corrects the display by removing the line the file was on. */
/* */
__dir_delete (...)
{
string file_name,
temp;
int file_attrib;
file_name = _dir_filename ();
temp = add_to_path (_dir_wd, file_name);
if (del (file_name) <= 0)
/* We know the file exists, since it's in our list. */
/* (If the user did something stupid during an Alt-Z, */
/* that's his problem.) */
/* We know that system, hidden, and volume files do */
/* not make it into the directory list, and directories */
/* are already sorted out; so the only weird attribute */
/* the file could have is read-only. If the file is */
/* read-only, that's why the del failed. If not, it */
/* must have failed because the file's being edited. */
{
file_pattern (file_name);
find_file (NULL, NULL, NULL, NULL, file_attrib);
if (file_attrib & 0x0001)
{
error ("File %s is read-only.", file_name);
beep ();
}
else
{
error ("You can't delete an edited file.");
beep ();
}
return;
}
if (_dir_tagged ())
{
error ("decrementing _dir_tags %d", _dir_tags);
--_dir_tags;
}
delete_line ();
up ();
message ("File %s deleted.", file_name);
}
/* */
/* _dir_rename: */
/* For the current file, prompts for a new name, and attempts */
/* to rename it. Uses command-level rename, and so does not work */
/* across directories. */
/* */
_dir_rename (...)
{
string prompt,
destination,
file_name;
int error_buf,
ext_loc;
/* If we are not on a file name, beep. */
save_position ();
ext_loc = search_fwd ("
if (ext_loc)
{
beep ();
return;
}
/* First, get the destination. We allow only a 12-character */
/* response since path names are not legal. Then build the */
/* rename command. */
sprintf (prompt, "Rename %s to: ", file_name = _dir_filename ());
if (get_parm (0, destination, prompt, 12))
{
sprintf (prompt, "rename %s ", file_name);
prompt += destination + (" >&" + ERROR_FILE);
/* Rename the file, and get the error file (if any) into */
/* a system buffer. This is the only way to catch errors. */
dos (prompt);
set_buffer (error_buf = create_buffer (ERROR_FILE, ERROR_FILE, TRUE));
/* Check for errors in the file. If there were none, */
/* update the screen with the new name. */
if (read (1) == "\n")
{
message ("Renamed.");
set_buffer (_dir_buffer);
drop_anchor (1);
move_abs (0, 17);
delete_block ();
if (ext_loc = index (destination, "."))
{
sprintf (file_name, "\t%-8s ", substr (destination, 1, ext_loc - 1));
sprintf (prompt, "%-3s", substr (destination, ext_loc + 1));
file_name += prompt;
}
else
sprintf (file_name, "\t%-12s", destination);
insert (upper (file_name));
beginning_of_line ();
}
else
{
error ("%s.", trim (ltrim (read ())));
beep ();
}
/* Delete the error buffer and file, and change back to */
/* the directory buffer. */
set_buffer (_dir_buffer);
delete_buffer (error_buf);
del (ERROR_FILE);
}
else
message ("Rename cancelled.");
}
/* */
/* _dir_sort: */
/* Sorts the files and directories (separately) on one of several */
/* criteria, including name, extension, size, and time. */
/* */
_dir_sort (...)
{
int sort_col;
string sort_command;
extern sort_block;
/* Do a little error checking. */
if (!inq_macro ("sort_buffer") && load_macro ("sort") <= 0)
{
error ("Unable to load sort macro.");
beep ();
return;
}
if (get_parm (0, sort_col))
sprintf (sort_command, "sort_block %d", sort_col);
else
sort_command = "sort_block";
/* Turn off the status messages while we sort. Temporarily */
/* raise the line mark and save its location, while we use */
/* another line mark to delimit the areas to sort. */
raise_anchor ();
save_position ();
/* Mark the directories in the list to be sorted first, then sort. */
/* Note that sort_block and _sort_on_field remove the anchor. */
top_of_buffer ();
down ();
drop_anchor (3);
search_fwd ("
execute_macro (sort_command);
/* Mark the files, then sort. */
search_fwd ("
drop_anchor (3);
end_of_buffer ();
execute_macro (sort_command);
/* Clean up. Put the cursor where we found it, and restore */
/* the mark. Clear the message line. */
restore_position ();
drop_anchor (3);
}
/* */
/* _dir_help: */
/* Finds the help file in BHELP and displays it in a pop-up */
/* window. Clears the window when any key is pressed. */
/* */
_dir_help (...)
{
int help_buffer;
set_buffer (help_buffer = create_buffer ("Help", "c:/brief/help/dir.txt", TRUE));
create_window (16, 21, 49, 5, "Any key to resume");
attach_buffer (help_buffer);
refresh ();
while (!inq_kbd_char ())
;
read_char ();
set_buffer (_dir_buffer);
delete_window ();
delete_buffer (help_buffer);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/