Files
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
Un-ignored: the dev drive is the ground truth the restoration and
emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer
source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio
content). Kept in-repo for the pod-owner community.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:41:15 -05:00

555 lines
15 KiB
Plaintext

/*
** BRIEF -- Basic Reconfigurable Interactive Editing Facility
**
** Written by Dave Nanian and Michael Strickman.
*/
/*
** language.cb:
**
** This file contains the support modules for BRIEF's language package
** system.
*/
void _call_packages (string event_name);
void _parse_packages (string event_name);
string process_package (string event_name, string mac_name, string existing_packages, string file_ext);
void _reset_packages ();
string _package_abbrev ();
string escape_re (string original, ~string);
extern int _package_buf; // Parsed language package information.
string _curr_active; // The list of currently active packages.
void _init ()
{
int old_buf;
register_macro (1, "_call_on_packages");
register_macro (6, "_call_first_packages");
old_buf = set_buffer (_package_buf = create_buffer ("Packages", NULL, 1));
delete_line ();
set_buffer (old_buf);
}
void _call_on_packages ()
{
_call_packages ("_on");
}
void _call_first_packages ()
{
string filename;
inq_names (NULL, NULL, filename);
if (inq_message () == "New file (unable to open " + filename + ").")
_call_packages ("_new");
else
_call_packages ("_existing");
_call_packages ("_first");
}
/*
** _call_packages:
**
** This macro is the main event dispatcher for the BRIEF language
** package system. It calls packages specified in the BPACKAGES
** environment variable in response to events generated by the system or
** by the user using some housekeeping information generated by
** _parse_packages that allows rapid access to them.
*/
void _call_packages (string event_name)
{
int old_buf,
loc;
string file_ext;
inq_names (NULL, file_ext);
if (_curr_active != "")
_reset_packages ();
old_buf = set_buffer (_package_buf);
top_of_buffer ();
/*
** First, we check to see if we've already encounted this extension
** and event. If so, the information we need is present in the
** package buffer, and we call the macros therein.
**
** If either the extension or event haven't been encountered before,
** we call _parse_packages to do more work.
*/
if (loc = search_fwd ("." + file_ext + event_name + ";", 0))
{
string to_call,
off_macro;
next_char (loc - 1);
to_call = trim (read ());
set_buffer (old_buf);
while (strlen (to_call))
{
if (!(loc = index (to_call, ",")))
loc = strlen (to_call) + 1;
if (event_name != "_on")
execute_macro (substr (to_call, 1, loc - 1));
else if ((off_macro = execute_macro (substr (to_call, 1, loc - 1))) != "")
_curr_active += (strlen (_curr_active) ? ";" : "") + off_macro;
to_call = substr (to_call, loc + 1);
}
}
else
{
set_buffer (old_buf);
_parse_packages (event_name);
}
}
/*
** _reset_packages:
**
** This macro processes the "off" event. Any macros that returned
** "off" event macros from their event handles have those strings kept
** in the _curr_active global variable. These macros are called here.
**
** Note that "off" macro strings should never contain semicolons.
*/
void _reset_packages ()
{
int loc;
while (strlen (_curr_active))
{
if (!(loc = index (_curr_active, ";")))
loc = strlen (_curr_active) + 1;
execute_macro (substr (_curr_active, 1, loc - 1));
_curr_active = substr (_curr_active, loc + 1);
}
}
/*
** _evaluate_package:
**
** This macro takes a macro name and an extension and constructs a
** package name from it, using all of the possible equivalent extensions.
*/
string _evaluate_package (string extension, string macro_name)
{
int old_buf = set_buffer (_package_buf),
len;
string package_name;
top_of_buffer ();
if (len = search_fwd ("." + extension + macro_name + ";", 0))
{
next_char (len - 1);
package_name = trim (read ());
}
else
{
int loc;
string equivalents;
next_char (search_fwd ("." + escape_re (extension) + "_equivalents") - 1);
equivalents = extension + trim (read ()) + "==";
while (loc = index (equivalents, "="))
if (inq_macro (package_name = (loc != 1 ? "." : "") + substr (equivalents, 1, loc - 1) + macro_name))
break;
else
equivalents = substr (equivalents, loc + 1);
beginning_of_line ();
insert ("." + extension + macro_name + ";" + package_name + "\n");
}
set_buffer (old_buf);
returns (package_name);
}
/*
** _parse_packages:
**
** This macro deals with more extensive package expansion the first time
** a file is read, and the first time an event is executed.
*/
void _parse_packages (string event_name)
{
string bpackages,
to_call,
mac_name,
file_ext,
escaped_ext,
equivalents,
pattern;
int loc,
pass,
file_buf;
/*
** First, we get the event type and the extension of the file.
*/
inq_names (NULL, file_ext);
escaped_ext = escape_re (file_ext);
/*
** The global _package_buf contains housekeeping information that
** allows the language system to keep parsed event information around
** for the duration of the editing session. Each event occupies one
** line in the buffer (per extension), and one additional line is
** taken per extension to save the pre-parsed packages and arguments.
**
** Extensions are always found together in the package buffer; the
** events come first, followed by the pre-parsed information. This
** allows the search pattern to fall through to the pre-parsed
** information if the event hasn't occurred yet.
**
** The format of the strings is:
**
** .[extension][event name, or nothing if pre_parse];[information]
*/
file_buf = set_buffer (_package_buf);
top_of_buffer ();
/*
** This search locates any string in the buffer that corresponds
** to the current extension. If the event is in the buffer,
** _call_packages will have already dealt with it. If not, we try
** to locate the pre_parse information here.
*/
if (loc = search_fwd ("." + file_ext + ";", 0))
{
next_char (loc - 1);
to_call = trim (read ());
file_ext = "." + file_ext;
beginning_of_line ();
}
else
{
/*
** If no pre-parse information is present in the buffer for
** the given extension, the BPACKAGES string must be retrieved
** from the environment and parsed. Note that this will only
** happen once per extension.
**
** Since the BPACKAGES string is quite complex, and a given
** extension can appear more than once (and with a number of
** different packages), the parser loops and searches for the
** extension until it can't be located any more.
**
** If the extension isn't found at all, the "default"
** extension is used and a second pass is made over the
** BPACKAGES string.
**
** If neither the extension nor the "default" extension is
** found, no events are generated.
*/
int located;
pattern = "<|[,;] @\\c" + escaped_ext + " @{[,\\-][~\\-,;:]@}@:[~:\n;]+[\n;]";
bpackages = trim (ltrim (compress (inq_environment ("BPACKAGES")))) + "\n";
while (pass != 2 && !located)
{
while (loc = search_string (pattern, bpackages, NULL, NULL, 0))
{
string curr_ext,
this_package_list;
++located;
bpackages = substr (bpackages, loc);
if (loc = index (bpackages, ";"))
{
this_package_list = substr (bpackages, 1, loc - 1);
bpackages = substr (bpackages, loc + 1);
}
else
{
this_package_list = trim (bpackages);
bpackages = "";
}
/*
** Now we have the "raw" BPACKAGES information.
** At this point, we need to check for extension
** substitution.
*/
if ((loc = index (this_package_list, "-")) && loc < index (this_package_list, ":"))
{
this_package_list = substr (this_package_list, loc + 1);
if (!((loc = index (this_package_list, ",")) && loc < index (this_package_list, ":")))
loc = index (this_package_list, ":");
curr_ext = trim (ltrim (substr (this_package_list, 1, loc - 1)));
equivalents += "=" + curr_ext;
}
else
curr_ext = file_ext;
/*
** All of the pre-expansion packages for the
** current extension are combined together in the
** to_call string separated by commas. This
** string is used later to expand and call the
** individual package macros, and is inserted
** into the buffer as pre-parse information
** once the initial parse has been completed.
*/
to_call += (strlen (to_call) ? ",=" : "=") + curr_ext + ",," + substr (this_package_list, index (this_package_list, ":") + 1);
}
/*
** If we can't find the extension any more and we've
** located some packages to call, the parse is over.
** Otherwise, we use "default" as the extension and try
** one more time.
*/
pattern = "<|[,;] @\\cdefault @{[,\\-][~\\-,;:]@}@:[~:\n;]+[\n;]";
++pass;
}
file_ext = "." + file_ext;
/*
** If the package buffer didn't contain any information about
** the current file extension, we insert the pre-parse information
** at the top of the buffer. This information can be used later
** to avoid doing an additional BPACKAGES parse.
*/
beginning_of_line ();
/*
** The extra comma here is used to generate a "null"
** event, which, for the first event, looks something like:
**
** _first or .c_first
**
** These are generated to allow packages to chain into
** various events without requiring them to be listed in
** the BPACKAGES environment variable. Note that each
** given extension in the parsed BPACKAGES string also checks
** for generic event macros. This ensures that all of the macros
** for a given extension or set of extensions are called.
*/
to_call = "=" + substr (file_ext, 2) + ",," + to_call;
insert (file_ext + ";" + to_call + "\n");
/*
** We move up here because the event information must
** appear before the pre-parse information, and the "\n"
** that was inserted moves us down a line.
*/
up ();
/*
** We also insert the list of equivalent extensions at
** this point in the buffer. This list can be used by other
** extension-type macros that want to know about equivalence.
*/
insert (file_ext + "_equivalents" + equivalents + "\n");
}
set_buffer (file_buf);
bpackages = "";
/*
** At this point, we've got a list of pre-expanded package
** names that look something like "s,pvcs,wp". These have to
** be expanded and converted into the event and extension
** specific variety. Each individual package is separated and
** passed to process_package, which expands the name (if
** necessary), handles extension-specific and generic naming
** convensions, deals with parameters, and the like. Once
** completed, the expanded package name (if any) is returned
** and saved in another string that will be inserted as the
** event-specific information in the package buffer.
*/
while (strlen (to_call))
{
if (!(loc = index (to_call, ",")))
loc = strlen (to_call) + 1;
if (substr (to_call, 1, 1) == "=")
escaped_ext = substr (to_call, 2, loc - 2);
else
{
mac_name = process_package (event_name, ltrim (trim (substr (to_call, 1, loc - 1))), bpackages, escaped_ext);
if (strlen (mac_name))
bpackages += (strlen (bpackages) ? "," : "") + mac_name;
}
to_call = substr (to_call, loc + 1);
}
/*
** Since the event-specific information wasn't found in the buffer,
** it's inserted here.
*/
file_buf = inq_buffer ();
set_buffer (_package_buf);
insert (file_ext + event_name + ";" + bpackages + "\n");
set_buffer (file_buf);
}
/*
** process_package:
**
** This macro converts generic package names into their generic or
** extension-specific macro name counterparts.
*/
string process_package (string event_name, string mac_name, string existing_packages, string file_ext)
{
string real_ext,
initial_mac,
parms;
int loc,
processed,
length;
existing_packages = "," + existing_packages + ",";
inq_names (NULL, real_ext);
file_ext = "." + file_ext;
real_ext = "." + real_ext;
if (loc = index (mac_name, " "))
{
parms = substr (mac_name, loc + 1);
mac_name = substr (mac_name, 1, loc - 1);
}
/*
** If part of the package name is found in the
** abbreviation list, the full name is retrieved and used
** instead. Note that the macros in the abbreviation list
** could be demotable groups (separated by commas).
*/
initial_mac = _package_abbrev ();
if (strlen (mac_name) && (loc = search_string ("[,;]" + mac_name + "*;", initial_mac, length)))
initial_mac = substr (initial_mac, loc + 1, length - 2);
else
initial_mac = mac_name;
/*
** This loop searches for specific and generic event
** handler macros. First, specific macros are searched
** for. If none are found, the last member of the
** demotable group is searched for generically. This is
** because generic higher level demotion macros don't
** make any sense (they'd override anything else, and
** wouldn't leave anything to demote to).
*/
while (!processed)
{
if (!(loc = index (initial_mac, ",")))
loc = strlen (initial_mac) + 1;
mac_name = substr (initial_mac, 1, loc - 1);
initial_mac = substr (initial_mac, loc + 1);
mac_name = (strlen (mac_name) ? "_" : "") + mac_name + event_name;
if (processed = inq_macro (real_ext + mac_name))
mac_name = real_ext + mac_name;
else if (real_ext != file_ext && (processed = inq_macro (file_ext + mac_name)))
mac_name = file_ext + mac_name;
else if (!strlen (initial_mac))
{
processed = inq_macro (mac_name);
break;
}
}
/*
** Here we check to see if the macro has been called
** before. If so, we ignore it.
*/
if (processed && index (existing_packages, "," + mac_name + ","))
processed = 0;
/*
** If the macro has been processed & located, we call it with its
** parameters.
*/
if (processed)
{
string generic_macro_called;
if (strlen (parms))
mac_name += " " + parms;
/*
** If current event is an "on" event, we retain the return
** value (if non-null) as an "off" event macro name.
**
** Note also that we ensure that a generically named generic
** event macro is always called before the specifically named one,
** if any.
*/
if (initial_mac == "" && event_name != mac_name && !index (existing_packages, "," + event_name + ",") && inq_macro (event_name))
{
generic_macro_called = event_name + ",";
if ((initial_mac = execute_macro (event_name)) != "" && event_name == "_on")
_curr_active += (strlen (_curr_active) ? ";" : "") + initial_mac;
}
if ((initial_mac = execute_macro (mac_name)) != "" && event_name == "_on")
_curr_active += (strlen (_curr_active) ? ";" : "") + initial_mac;
returns (generic_macro_called + mac_name);
}
else
returns ("");
}
/*
** _package_abbrev:
**
** This macro is at the terminus of the chain. It returns a string
** consisting of the abbreviations and demotable groups for the built-in
** BRIEF packages (indenting, word processing, pvcs and tlib).
*/
string _package_abbrev ()
{
returns (";template,smart,regular;pvcs;wp;tlib;vc;"); /*vc*/
}