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

639 lines
18 KiB
Objective-C

;**
;** BRIEF -- Basic Reconfigurable Interactive Editing Facility
;**
;** Written by Dave Nanian and Michael Strickman.
;**
;**
;** restore.m:
;**
;** This macro saves and restore search and translate global
;** variables, as well as the buffers (and positions therein)
;** active when BRIEF was last exited. There are five parts/macros:
;** part one (save_state) saves the fixed state information, part two
;** (_save_state) saves the variable information (and can be replaced
;** by the user), part three (.rst) restores the list of files and
;** their positions, part four (restore) restores the fixed editing
;** information, and part five (_restore) restores the variable
;** editing information (and can be replaced by the user).
;**
#define REG_EXIT_ACTION 5
#define TRUE 1
#define FALSE 0
#define SYSTEM 1
(extern _reg_exp
_s_pat
_r_pat
_t_pat
_dir
_t_dir
_block_search
_check_warnings
)
;**
;** save_state:
;**
;** This macro, when registered as an EXIT_ACTION (type 5)
;** registered macro, saves the state of the search variables
;** as well as the names and positions of the current files.
;**
;** The layout of the state file is as follows:
;**
;**  Search direction, regular expression setting,
;** search block setting, translate direction and
;** warnings-only compile setting.
;**  Search pattern.
;**  Translate pattern.
;**  Replacement string.
;**  Optional user save information.
;**  The string "[FILES]".
;**  A variable number of file records, which contain:
;**  The full, qualified path of the file.
;**  The line and column the cursor was on, and any bookmarks.
;** The bookmarks are of the form <number> <line> <column>.
;**
(macro save_state
(
(int save_buf_id
start_buf_id
old_backup
)
(string file_name
info
)
;**
;** If the user hasn't specified a BFILE as yet (if there
;** isn't any BFILE in the environment, (inq_environment) returns
;** the null string), or the given BFILE is invalid in some other
;** way, we can't save the state. We display a message to this
;** effect and exit.
;**
(if (== (= file_name (lower (inq_environment "BFILE"))) "")
(error "No BFILE specified, state not saved.")
;else
(
;**
;** Here we create a buffer for the state file. It's created
;** as a system buffer to prevent it from appearing in the buffer
;** list (and getting saved along with the other files).
;**
;** We delete the file first to make sure it's empty.
(del file_name)
(if (! (= save_buf_id (create_buffer "State" file_name SYSTEM)))
(error "Invalid BFILE, state not saved.")
;else
(
;**
;** We need to reset the current buffer later, since
;** other macros could run after we do and we don't want
;** to leave BRIEF in an unstable state. We save its
;** buffer id before continuing.
;**
(= start_buf_id (inq_buffer))
(set_buffer save_buf_id)
;**
;** First, we save the "global" save information.
;** This includes the search and translate directions,
;** the regular expression setting, the block search
;** setting, and the search and translate patterns.
;**
(sprintf info "%d %d %d %d %d\n" _dir _reg_exp _block_search _t_dir _check_warnings)
(insert info)
;**
;** The search and translate patterns could,
;** potentially, have newline characters in them.
;** The _remove_newlines subroutine replaces those
;** newline characters with \n, the regular expression
;** that means "newline".
;**
(insert (_remove_newlines _s_pat))
(insert (_remove_newlines _t_pat))
(insert (_remove_newlines _r_pat))
;**
;** Now we call the _save_state macro to save the
;** remainder of the state information. Note that
;** this macro can be replaced to extend restore's
;** capabilities.
;**
(_save_state start_buf_id)
(set_buffer save_buf_id)
;**
;** Finally, we write the restore file to disk.
;** Since we don't want backup files created, we
;** turn those off. We put it back the way it was
;** before exiting, since other macros could run
;** once we're through.
;**
(= old_backup (set_backup FALSE))
(write_buffer)
(set_backup old_backup)
(delete_buffer save_buf_id)
(set_buffer start_buf_id)
)
)
)
)
)
)
;**
;** _save_state:
;**
;** This macro gets called to save the variable length
;** state information. Other macros can replace it to
;** save additional information.
;**
(macro _save_state
(
(int save_buf_id
start_buf_id
curr_buf_id
)
(string info)
;**
;** Now that the global state information is
;** saved, we insert the file separator and loop
;** through the buffer list.
;**
;** This loop goes through each non-system buffer
;** in the buffer list, using (set_buffer) and (next_buffer).
;** Note that we skip over the first buffer and save
;** it last: this ensures that the buffer list is
;** restored in the correct order when it comes time to do
;** so.
;**
;** We skip the system buffer manually, rather than
;** with the (next_buffer) parameter, because we could
;** have been entered with the current buffer being a
;** system buffer. If this were the case, and we used
;** (next_buffer), we would never come back to the starting
;** buffer and would infinite loop.
;**
;**
(get_parm 0 start_buf_id)
(= save_buf_id (inq_buffer))
(insert "[FILES]")
(set_buffer start_buf_id)
(while (!= start_buf_id curr_buf_id)
(
(set_buffer (= curr_buf_id (next_buffer 1)))
(if (! (inq_system))
(
(int i
temp_buf
line
col
)
(inq_names info)
(inq_position line col)
(set_buffer save_buf_id)
(sprintf info "\n%s\n%u %u" info line col)
(insert info)
(= info "")
(while (< i 10)
(
(if (&& (goto_bookmark i temp_buf line col) (== temp_buf curr_buf_id))
(sprintf info "%s %d %u %u" info i line col)
)
(++ i)
)
)
(insert info)
)
)
(set_buffer curr_buf_id)
)
)
)
)
;**
;** .rst:
;**
;** This macro is, quite frankly, a mite strange. When the
;** user types "b" with no arguments, BRIEF automatically loads
;** the file specified by the BFILE environment variable. If
;** that file has the extension ".rst", this macro runs.
;**
;** This macro then restores the files that were active
;** during the last editing session. The state file buffer
;** (specified in the BFILE) isn't deleted -- the restore macro,
;** which runs after the file loading sequence, does that after
;** restoring the state of the search and translate variables.
;**
(macro .rst
(
(string file_name)
;**
;** We need the name of the current file for the next test.
;** All we need is the buffer name, which is the last parameter.
;** The NULL placeholder is used to omit the additional information.
;**
(inq_names NULL NULL file_name)
;**
;** This logic only makes sense the first time this
;** file extension macro is called. If we're running
;** it for the second time, or the file isn't the same
;** as the state file (maintained in the BFILE environment
;** variable), we skip it. Initialization logic for "real"
;** .rst files can be placed in the "true" clause of the
;** if statement (replacing or supplementing the (tabs)
;** statement).
;**
;** We use "index" here because the only thing we really
;** care about is that the file name matches the name of the
;** file specified in BFILE -- remember that the path specified
;** could be relative.
;**
(if (! (&& (first_time) (index (lower (inq_environment "BFILE")) file_name)))
(tabs 9)
;else
(
(int buffer_id
current_buffer
line
col
old_msg_level
)
(string file_line)
(= old_msg_level (inq_msg_level))
;**
;** BRIEF has already edited the state file (because
;** of normal BFILE processing) and made it the current
;** buffer. We get its buffer id for future use, search
;** for the [FILES] string that tells us where the file
;** data starts, and process the file information, which
;** is in the following format (each field is on a separate
;** line):
;**
;**  Full, qualified path of the file name.
;**  Line number.
;**  Column number.
;**
(= buffer_id (inq_buffer))
;**
;** Note that if the telltale [FILES] string isn't
;** found, we can't process the .rst file.
;**
(if (search_fwd "[FILES]" 0)
(
(down)
;**
;** Here's the loop that processes the file
;** information. We continue restoring files
;** until there's no more information in the
;** file to restore (signaled by EOF).
;**
;** Note that the macro that saved the state
;** does so in such a way that the files are in
;** reverse order -- the last file in the .rst
;** file is the one that was current when the
;** user left BRIEF.
;**
(while (! (inq_position))
(
(= file_name (trim (read)))
(down)
(= line (atoi (= file_line (trim (ltrim (compress (read)))))))
(= col (atoi (substr file_line (+ (index file_line " ") 1))))
(down)
;**
;** The edit_file call is used to load
;** the file back in because it deals with
;** all the details of attaching the buffer
;** to the window, calling the proper init
;** macros, setting the current buffer, etc.
;**
;** If the call to edit_file fails, we
;** know something has gone wrong. So we
;** ignore this file and continue to the
;** next.
;**
(set_msg_level 0)
(if (> (edit_file file_name) 0)
(
(move_abs line col)
(= current_buffer (inq_buffer))
;**
;** At this point, the restored
;** file has been made the current
;** buffer. We have to make our
;** state file current so the top
;** of the loop works correctly.
;**
(set_buffer buffer_id)
)
)
(set_msg_level old_msg_level)
)
)
;**
;** If any files were restored properly, we
;** set the current buffer to the buffer in the
;** current window. And we're done!
;**
(if current_buffer
(set_buffer current_buffer)
)
)
)
)
)
)
)
;**
;** restore:
;**
;** This macro restores the state of the search and translate
;** global variables, as well as the list of bookmarks for each
;** currently edited file.
;**
;** Note that if the ".rst" macro ran when BRIEF was started,
;** the state file (BFILE) has already been loaded. In this case,
;** (create_buffer) just gives us its buffer ID, and doesn't bother
;** loading the file again.
;**
(macro restore
(
(if (first_time)
(
(string file_name)
;**
;** First, we register the macro that will end up
;** saving the state of the session for the next time
;** around.
;**
(register_macro REG_EXIT_ACTION "save_state")
;**
;** If this macro runs, and no BFILE is specified,
;** we can't restore the state (you can't restore
;** what isn't there). So we put up an error message
;** and exit. If the file doesn't exist, we don't
;** proceed -- once again there's nothing to restore!
;**
(if (== (= file_name (lower (inq_environment "BFILE"))) "")
(error "No BFILE specified, state not restored.")
;else
(if (exist file_name)
(
(int buffer_id
old_buffer
)
(string file_line)
;**
;** Before we make the state file buffer current,
;** we have to ensure the old buffer (which is
;** in the main window) is saved away. Before
;** we exit the macro, we have to reset it --
;** otherwise, BRIEF gets very unhappy.
;**
(= old_buffer (inq_buffer))
;**
;** If the buffer creation fails ((create_buffer)
;** returns 0), we tell the user about the problem
;** and stop. Otherwise, we continue with the restore.
;**
(if (! (= buffer_id (create_buffer "Restore" file_name)))
(error "Invalid BFILE specified.")
;else
(
;**
;** Here we make the restore buffer current
;** and parse the information in the state file.
;** This information is in the following format,
;** with each group on a separate line:
;**
;**  The search direction, regular expression setting,
;** search block setting, translate direction and
;** warnings-only compile setting.
;**  The search pattern.
;**  The translate pattern.
;**  The replacement string.
;**
;** No error checking is done on the results
;** of the parse: if the numbers aren't right,
;** the (atoi) call will fail and everything will
;** default to 0 (if the strings don't exist,
;** they'll be null).
;**
(set_buffer buffer_id)
(top_of_buffer)
(= file_line (trim (ltrim (compress (read)))))
(= _dir (atoi file_line))
(= file_line (substr file_line (+ (index file_line " ") 1)))
(= _reg_exp (atoi file_line))
(= file_line (substr file_line (+ (index file_line " ") 1)))
(= _block_search (atoi file_line))
(= file_line (substr file_line (+ (index file_line " ") 1)))
(= _t_dir (atoi file_line))
(= file_line (substr file_line (+ (index file_line " ") 1)))
(= _check_warnings (atoi file_line))
(down)
;**
;** Note that we can't use (trim) here --
;** the saved string could have trailing spaces.
;**
(= _s_pat (read))
(= _s_pat (substr _s_pat 1 (- (strlen _s_pat) 1)))
(down)
(= _t_pat (read))
(= _t_pat (substr _t_pat 1 (- (strlen _t_pat) 1)))
(down)
(= _r_pat (read))
(= _r_pat (substr _r_pat 1 (- (strlen _r_pat) 1)))
;**
;** Now we call the _restore macro to finish
;** up the restoration. Note that this macro
;** can be replaced to extend restore's
;** capabilities.
;**
(_restore old_buffer)
(set_buffer buffer_id)
;**
;** Here we make sure the state file buffer
;** isn't the same as the buffer that was current
;** when we entered the macro. This shouldn't
;** happen, but it could.
;**
(if (!= old_buffer buffer_id)
(
(set_buffer old_buffer)
(delete_buffer buffer_id)
)
)
)
)
)
)
)
)
)
)
)
;**
;** _restore:
;**
;** This macro restores the variable editing information.
;** It can be replaced by the user to extend restore's
;** capabilities.
;**
(macro _restore
(
(int save_buf_id)
;**
;** Now, we restore the list of bookmarks.
;** We check to see if each buffer in the file
;** list is being editing in this session. If
;** so, its bookmarks are restored.
;**
(= save_buf_id (inq_buffer))
(top_of_buffer)
(if (search_fwd "[FILES]" 0)
(
(int bookmark_num
loc
curr_buf
line
col
)
(string file_line)
(down)
(= curr_buf (next_buffer 1))
(while (!= curr_buf save_buf_id)
(
(set_buffer curr_buf)
(if (! (inq_system))
(
(inq_names file_line)
(set_buffer save_buf_id)
(save_position)
(if (search_fwd file_line 0)
(
(down)
(= file_line (trim (ltrim (compress (read)))))
(= file_line (substr file_line (+ (index file_line " ") 1)))
(while (= loc (index file_line " "))
(
(= bookmark_num (atoi (= file_line (substr file_line (+ loc 1)))))
(= line (atoi (= file_line (substr file_line (+ (index file_line " ") 1)))))
(= col (atoi (= file_line (substr file_line (+ (index file_line " ") 1)))))
(drop_bookmark bookmark_num "y" curr_buf line col)
)
)
)
)
(restore_position)
(set_buffer curr_buf)
)
)
(= curr_buf (next_buffer 1))
)
)
(set_buffer save_buf_id)
)
)
)
)
;**
;** _remove_newlines:
;**
;** This macro replaces all newline characters with the
;** character sequence "\n". This prevents problems when a
;** search pattern with a newline in it is inserted.
;**
(macro _remove_newlines
(
(int loc)
(string trans_str)
(get_parm 0 trans_str)
;**
;** This loop checks for newlines in the passed string. If
;** once is found, the string is split into two parts: the part
;** before the newline, and the part after. The two halves are
;** then put back together again, with a newline regular expression
;** ("\n") in between.
;**
(while (= loc (index trans_str "\n"))
(= trans_str (+ (+ (substr trans_str 1 (- loc 1)) "\\n")
(substr trans_str (+ loc 1))))
)
(returns (+ trans_str "\n"))
)
)