/*
**		BRIEF -- Basic Reconfigurable Interactive Editing Facility
**
**		pwb.cb:
**
** This macro package permits BRIEF to interface with the Microsoft
** Programmers Workbench.
**
**	It saves and restores the BRIEF state using the PWB State
** File (current.sts).  The state information includes the search and
** translate global variables, the buffers (and positions therein), and
** bookmarks.  Please refer to the Brief DOS/ OS-2 User's Guide,
** Chapter 7 "Third-Party Packages", page 215 for additional details
** on using the pwb macro package.
**
*/

#define REG_EXIT_ACTION 5
#define TRUE				1
#define FALSE				0
#define SYSTEM 			1

extern int	_reg_exp,				//	Current regular expression setting.
				_dir,						//	Current search direction.
				_t_dir,					//	Current translate direction.
				_block_search,			//	Current block search setting.
				_check_warnings,		//	"Check output for warnings" setting.
				_background;			//	Whether or not to compile in the bg.

extern string	_s_pat,				//	Last search pattern.
					_t_pat,				//	Last translate pattern.
					_r_pat;				//	Last translate replacement.

extern string search_path (string pathvar, string filename);

void save_state ();
int _save_state (int start_buf_id);
void _save_marks (int start_buf_id);
void _save_files (int start_buf_id);
void _save_file_info (int start_buf_id);
void .sts ();
void pwb ();
void _restore_pwb (void);
_restore (int);
string _remove_newlines (string trans_str);

/*
**		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 state file is broken up into several sections.  Each section
**	is preceded by a tag that describes the type of information stored in
**	the section.
*/

void save_state ()
{
	int	save_buf_id,
			start_buf_id,
			old_backup;

	string	file_name;


	/*
	**		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.
	*/

	file_name = trim (ltrim (lower (inq_environment ("BFILE"))));

	if (substr (file_name, strlen (file_name) - 3) != ".sts")
		error ("Invalid 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).
		*/

		if (!strlen (file_name))
		{
			/*
			** In reality, right here is where we would create a current.sts if
			**	we couldn't find one where it belonged.
			*/

			file_name = "current.sts";
		}

		if (!(save_buf_id = create_buffer ("State", file_name, SYSTEM)))
			error ("Invalid BFILE specified, state not saved.");
		else
		{
			int	screen_lines,
					screen_cols;

			/*
			**		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 = set_buffer (save_buf_id);

			/*
			**		First, we make sure the PWB state file version is one we
			** support.  If it isn't, we bail.
			*/

			top_of_buffer ();

			if (!(search_fwd ("<[\t ]@\\[shared-\\]", TRUE, TRUE) &&
				 search_fwd ("<[\t ]@version=2", TRUE, TRUE)))
			{
				error ("Unsupported BFILE specified, state not saved.");
				return;
			}

			/*
			**		First, we save the "global" information: [shared-]
			** This includes the bookmarks and the primary mark (current file
			** and position within the current file).
			*/

			_save_marks (start_buf_id);

			/*
			**		 Next, we save the "common tool" information: [edit-]
			** This is only the files we are currently editing.
			*/

			_save_files (start_buf_id);

			/*
			**		Finally, we save the BRIEF state information: [brief]
			** This includes the screen size, search and translate directions,
			** regular expression setting, block search setting, and search
			** and translate patterns.
			*/

			top_of_buffer ();

			if (search_fwd ("<[\t ]@\\[brief\\]", TRUE, TRUE))
			{
				/*
				**		Remove any existing BRIEF state information first.
				*/

				down ();
				drop_anchor ();

				if (search_fwd ("<[\t ]@\\[", TRUE, TRUE))
					prev_char ();
				else
					end_of_buffer ();

				delete_block ();
			}
			else
			{
				end_of_buffer ();
				insert ("\n[brief]\n");
			}

			inq_screen_size (screen_lines, screen_cols);

			insert ("\tscreen=%d %d\n\ttoggles=%d %d %d %d %d %d\n",
									screen_lines, screen_cols,
									_dir, _reg_exp, _block_search,
									_t_dir, _check_warnings, _background);

			/*
			**		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 ("\tsrch=" + _remove_newlines (_s_pat));
			insert ("\tsrc=" + _remove_newlines (_t_pat));
			insert ("\trpl=" + _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_file_info (start_buf_id);
			_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 is the end of the save_state chain; other macros can
**	replace it to save state information in the state file.
*/

int _save_state (int)
{
	returns (0);
}

/*
**		_save_marks:
**
**		This macro saves the the bookmarks and the primary mark in the
** [shared-] section of the state file.
*/

void _save_marks (int start_buf_id)
{
	int 		save_buf_id = inq_buffer (),
				i, curr_buf_id, line, col,
				mark_line1, mark_line2;
	string	info;

	top_of_buffer ();
	search_fwd ("<[\t ]@\\[shared-\\]", TRUE, TRUE);
	down ();
	inq_position (mark_line1);

	while (search_fwd ("<[\t ]@\\c{\\[}|{mark=edit}|{pmark=}"))
		if (read (1) == "[")
			break;
		else
		{
			if (!mark_line2)
				inq_position (mark_line2);

			delete_line ();
			beginning_of_line ();
		}

	/*
	**		Finally, we save the bookmarks and the primary mark.
	*/

	goto_line (mark_line2 ? mark_line2 : mark_line1);

	for ( ; i < 10 ; i++)
		if (goto_bookmark (i, curr_buf_id, line, col))
			{
			set_buffer (curr_buf_id);
			inq_names (info);
			set_buffer (save_buf_id);
			insert ("\tmark=edit %s %u %u bnumber=%u\n", info, line, col, i);
			}
	set_buffer (start_buf_id);
	inq_position (line, col);
	inq_names (info);
	set_buffer (save_buf_id);
	insert ("\tpmark=\"%s\" %u %u\n", info, line, col);
}

/*
**		_save_files:
**
**		This macro gets called to save the "common tool" state information.
*/

void _save_files (int start_buf_id)
{
	int	save_buf_id = inq_buffer (),
			curr_buf_id = start_buf_id,
			line,
			col,
			top_line,
			top_col,
			mark_line1, mark_line2;

	string	info;

	top_of_buffer ();
	search_fwd ("<[\t ]@\\[edit-\\]", TRUE, TRUE);
	down ();
	inq_position (mark_line1);

	while (search_fwd ("<[\t ]@\\c{\\[}|{file=}"))
		if (read (1) == "[")
			break;
		else
		{
			if (!mark_line2)
				inq_position (mark_line2);

			delete_line ();
			beginning_of_line ();
		}

	/*
	**		Finally, we save the files.
	*/

	goto_line (mark_line2 ? mark_line2 : mark_line1);

	set_buffer (start_buf_id);

	do
	{
		if (!inq_system ())
		{
			inq_position (line, col);
			inq_top_left (top_line, top_col, NULL, NULL, NULL, curr_buf_id);
			inq_names (info);
			set_buffer (save_buf_id);
			insert ("\tfile=\"%s\" %u %u %u %u\n", info, top_line, top_col, line, col);
			set_buffer (curr_buf_id);
		}
		set_buffer (curr_buf_id = next_buffer (1));
	}
	while (curr_buf_id != start_buf_id);

	set_buffer (save_buf_id);
}

/*
**		_save_file_info:
**
**		This macro gets called to save the variable length state information.
*/

void _save_file_info (int start_buf_id)
{
	int	save_buf_id = inq_buffer (),
			curr_buf_id,
			curr_win_id = inq_window (),
			start_win_id = curr_win_id,
			line,
			col,
			top_line,
			top_col,
			cursor_line,
			cursor_col,
			lx,
			by,
			rx,
			ty,
			i;

	string	info;

	/*
	**		Now that the global state information has been saved, we save the
	**	information about the buffers and windows in the [brief] section.
	**
	**		First, we save all the buffers that are being displayed in tiled
	**	windows.  These windows are recreated along with the buffers if no
	**	filename is specified.
	**
	**		Then, we save information about the buffers that aren't being
	**	viewed in a window.
	**
	**		We skip system buffers manually, rather than with the (next_buffer)
	**	parameter, because we could have been entered with a system buffer as
	**	the current buffer.  If we made use of the (next_buffer) parameter,
	**	we'd never come back to the starting buffer and would infinite loop.
	*/

	do
		{
		/*
		**		We don't save the state of overlapping windows.  Exit if there's
		**	one on the screen.
		*/

		if (inq_window_info (curr_win_id, curr_buf_id, lx, by, rx, ty))
			break;

		/*
		**		If there's a buffer in the window, save all the appropriate
		**	information, including:
		**
		**			The fully qualified filename.
		**			The line and column of the file in the top left corner
		**			of the window.
		**			The line and column of the file the cursor's on.
		**			The window's coordinates (lx, by, rx, ty).
		**			The window's colors.
		*/

		if (curr_buf_id)
			{
			set_buffer (curr_buf_id);
			inq_names (info);
			inq_top_left (top_line, top_col, curr_win_id, cursor_line, cursor_col);
			set_buffer (save_buf_id);
			insert ("\tfile=%s %u %u %u %u %d %d %d %d c=%d\n", info,
										top_line, top_col, cursor_line, cursor_col,
										lx, by, rx, ty, inq_window_color (curr_win_id));
			}
		curr_win_id = next_window (curr_win_id);
		}
	while (start_win_id != curr_win_id);

	/*
	**		Now we save all the buffers that aren't viewed in windows.
	*/

	set_buffer (start_buf_id);

	do
		{
		/*
		**		If there was an overlapping window on the screen, we save
		**	_all_ the buffers, not just the ones that weren't being viewed.
		*/

		if (!inq_system () && (!inq_views (curr_buf_id) || inq_window_info ()))
			{
			inq_names (info);
			inq_position (line, col);
			inq_top_left (top_line, top_col, NULL, NULL, NULL, curr_buf_id);

			set_buffer (save_buf_id);
			insert ("\tfile=%s %u %u %u %u\n", info, top_line, top_col, line, col);
			set_buffer (curr_buf_id);
			}
		set_buffer (curr_buf_id = next_buffer (1));
		}
	while (start_buf_id != curr_buf_id);

	set_buffer (save_buf_id);
}

/*
**		.sts:
**
**		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 ".sts", 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.
*/

void .sts ()
{
	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 (trim (lower (inq_environment ("BFILE"))) + "\xff", file_name + "\xff")))
		tabs (9);
	else
	{
		int	save_buf_id = inq_buffer (),
				curr_buf,
				line,
				col,
				top_line,
				top_col,
				lx,
				by,
				rx,
				ty,
				bg_color,
				loc,
				has_window,
				window_to_select,
				old_msg_level = inq_msg_level ();

		string	file_line;

		/*
		**		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 [brief] string that tells us where
		**	the file data starts, and process the file information, which
		**	is in the following format:
		**
		**		The string "file=".
		**		Full, qualified filename.
		**		The line displayed at the top of the last/this window.
		**		The column at the left hand side of the last/this window.
		**		The current line number in this window/in the buffer.
		**		The current column number in this window/in the buffer.
		**
		**		The rest of the information is optional, and is only there if
		**	there were views of the buffer.
		**
		**		The coordinates of the window (lx, by, rx, ty).
		**		The string "c=".
		**		The window color.
		**
		**		Note that if the telltale [brief] string isn't found, we can't
		**	process the .rst file.  In addition, if the screen size specified
		**	in the [edit-] section isn't the same as the current screen size,
		**	we can't continue.
		*/

		if (search_fwd ("<[\t ]@\\[brief\\]", TRUE, TRUE) >= 1)
		{
			int	curr_win_lines,
					curr_win_cols,
					old_win_lines,
					old_win_cols,
					create_windows;

			inq_screen_size (curr_win_lines, curr_win_cols);
			search_fwd ("<[\t ]@screen=\\c", TRUE, TRUE);
//			next_char (7);
			old_win_lines = atoi (file_line = trim (ltrim (compress (read ()))));
			old_win_cols = atoi (substr (file_line, index (file_line, " ") + 1));

			if (search_fwd ("<[\t ]@\\cfile=", TRUE, TRUE))
			{
				lx = 1;
				rx = curr_win_cols - 2;
				ty = 1;
				by = curr_win_lines - 3;
				bg_color = inq_window_color ();
				create_windows = ((curr_win_lines == old_win_lines) && (curr_win_cols == old_win_cols));

//				down ();
				display_windows (FALSE);

				/*
				**		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 or another section).
				*/
			
				while (substr (file_line = ltrim (trim (read ())), 1, 5) == "file=")
				{
					/*
					**		The string "c=" is only present if this is a window/file
					**	declaration.
					*/

					if (loc = rindex (file_line, " c="))
					{
						has_window = TRUE;

						if (create_windows)
						{
							bg_color = atoi (substr (file_line, loc + 3));
							loc = rindex (substr (file_line, 1, loc - 1), " ");
							ty = atoi (substr (file_line, loc + 1));
							loc = rindex (substr (file_line, 1, loc - 1), " ");
							rx = atoi (substr (file_line, loc + 1));
							loc = rindex (substr (file_line, 1, loc - 1), " ");
							by = atoi (substr (file_line, loc + 1));
							loc = rindex (substr (file_line, 1, loc - 1), " ");
							lx = atoi (substr (file_line, loc + 1));
							file_line = substr (file_line, 1, loc - 1);
						}
						else
						{
							int	i;

							for ( ; i < 5 ; i++)
							{
								file_line = substr (file_line, 1, loc - 1);
								loc = rindex (file_line, " ");
							}
						}
					}
					else if (!window_to_select)
						has_window = TRUE;

					loc = rindex (file_line, " ");
					col = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					line = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					top_col = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					top_line = atoi (substr (file_line, loc + 1));

					file_name = trim (ltrim (substr (file_line, 6, loc - 6)));
					down ();

					/*
					**		edit_file 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 initialization routines, 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 (curr_buf = inq_buffer (file_name))
						set_buffer (curr_buf);

					if (curr_buf || edit_file (file_name) > 0)
					{
						if (has_window && (create_windows || !window_to_select))
						{
							int	window_id = create_tiled_window (lx, by, rx, ty, inq_buffer ());

							if (!window_to_select)
								window_to_select = window_id;

							set_top_left (top_line, top_col, window_id, line, col);
							window_color (bg_color, window_id);
						}
						else
						{
							move_abs (line, col);
							set_top_left (top_line, top_col, NULL, NULL, NULL, 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 (save_buf_id);
					}
					else if (has_window && (create_windows || !window_to_select))
					{
						int	window_id = create_tiled_window (lx, by, rx, ty, save_buf_id);

						if (!window_to_select)
							window_to_select = window_id;
					}
					set_msg_level (old_msg_level);
					has_window = FALSE;
				}

				display_windows (1);
				set_window (window_to_select);
			}
		}

		curr_buf = set_buffer (save_buf_id);
		top_of_buffer ();

		if (search_fwd ("<[\t ]@\\[edit-\\]"))
		{
			int	buffer_id,
					line, col, top_line, top_col;

			do
			{
				down ();
				file_line = trim (ltrim (read ()));

				if (substr (file_line, 1, index (file_line, "=")) == "file=")
				{
					int	loc = rindex (file_line, " ");
					string	file;

					file = substr (file_line, index (file_line, "\"") + 1);
					file = substr (file, 1, rindex (file, "\"") - 1);

					col = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					line = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					top_col = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					top_line = atoi (substr (file_line, loc + 1));

					if (edit_file (file) > 0)
					{
						move_abs (line, col);
						set_top_left (top_line, top_col, NULL, NULL, NULL, inq_buffer ());
						set_buffer (save_buf_id);
					}
				}
			} while (substr (file_line, 1, 1) != "[" && !inq_position ());
		}

		attach_buffer (curr_buf);

		/*
		**		Restore the primary mark.
		*/

		set_buffer (save_buf_id);
		top_of_buffer ();
		
		if (search_fwd ("<[\t ]@\\[shared-\\]", TRUE, TRUE) &&
				search_fwd ("<[\t ]@pmark=\"\\c", TRUE, TRUE))
		{
			loc = rindex (file_line = read (), " ");
			col = atoi (substr (file_line, loc + 1));
			loc = rindex (substr (file_line, 1, loc - 1), " ");
			line = atoi (substr (file_line, loc + 1));
			file_line = substr (file_line, 1, rindex (file_line, "\"") - 1);

			if (edit_file (file_line))
				move_abs (line, col);
			else
				set_buffer (curr_buf);
		}
	}
}

/*
**		pwb:
**
**		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 ".sts" 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.
*/

void pwb ()
{
	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!
		*/

		file_name = trim (ltrim (lower (inq_environment ("BFILE"))));

		if (substr (file_name, strlen (file_name) - 3) != ".sts")
			error ("Invalid BFILE specified, state not restored.");
		else if (exist (file_name))
		{
			/*
			**		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.
			*/

			int	buffer_id,
					old_buffer = inq_buffer ();

			string	file_line;

			/*
			**		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 includes:
				**
				**	 The size of the screen.
				**	 The search direction, regular expression setting,
				**	  search block setting, translate direction, warnings-only
				**	  and background compile settings.
				**	 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
				**	things will default to 0 (if the strings don't exist, they'll
				**	probably be null).
				*/

				set_buffer (buffer_id);
				top_of_buffer ();

				if (search_fwd ("<[\t ]@\\[brief\\]", TRUE, TRUE))
				{
					down ();

					while (substr (file_line = ltrim (read ()), 1, 1) != "[" && !inq_position ())
					{
						switch (substr (file_line, 1, index (file_line, "=")))
						{
							case "toggles=":
							{
								file_line = trim (compress (file_line));
								_dir = atoi (substr (file_line, 9));
								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);
								file_line = substr (file_line, index (file_line, " ") + 1);
								_background = atoi (file_line);
							}
							case "srch=":
								_s_pat = substr (file_line, 6, strlen (file_line) - 6);

							case "src=":
								_t_pat = substr (file_line, 5, strlen (file_line) - 5);

							case "rpl=":
								_r_pat = substr (file_line, 5, strlen (file_line) - 5);
						}
						down ();
					}
					/*
					**		Now we call the _restore macro to finish up the
					**	restoration.  Note that this macro can be replaced to
					**	extend restore's capabilities.
					*/

					_restore_pwb ();
					_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 && !inq_views (buffer_id))
			{
				set_buffer (old_buffer);
				delete_buffer (buffer_id);
			}
		}
	}
}

/*
**		_restore_pwb:
**
**		This macro restores the "common tool" state information.
*/

void _restore_pwb (void)
{
	int	use_srch, use_rpl;
	string	srch, rpl, src, file_line;

	top_of_buffer ();

	if (search_fwd ("<[\t ]@\\[edit-\\]"))
	{
		do
		{
			down ();
			file_line = trim (ltrim (read ()));

			switch (substr (file_line, 1, index (file_line, "=")))
			{
				case "srch=":
					srch = substr (file_line, index (file_line, "=") + 1);

				case "fSrchRe=":
					use_srch = !atoi (substr (file_line, index (file_line, "=") + 1));

				case "rpl=":
					rpl = substr (file_line, index (file_line, "=") + 1);

				case "src=":
					src = substr (file_line, index (file_line, "=") + 1);

				case "fRplRe=":
					use_rpl = !atoi (substr (file_line, index (file_line, "=") + 1));
			}
		} while (substr (file_line, 1, 1) != "[" && !inq_position ());

		if (use_srch)
			_s_pat = srch;

		if (use_rpl)
		{
			_t_pat = src;
			_r_pat = rpl;
		}
	}
}

/*
**		_restore:
**
**		This macro restores the variable editing information.  It can be
**	replaced by the user to extend restore's capabilities.
*/

_restore (int)
{
	/*
	**		Now, we restore the list of bookmarks.  We check to see if each
	**	buffer in the file list is being edited in this session.  If so, its
	**	bookmarks are restored.
	*/

	top_of_buffer ();

	if (search_fwd ("<[\t ]@\\[shared-\\]", TRUE, TRUE))
	{
		int	bookmark_num,
				loc,
				mark_buf,
				line,
				col;

		string	file_line;

		down ();

		while (!inq_position () && read (1) != "[")
		{
			file_line = trim (ltrim (compress (read ())));

			if (substr (file_line, 1, 9) == "mark=edit")
			{
				file_line = substr (file_line, 11);

				if ((mark_buf = inq_buffer (substr (file_line, 1, index (file_line, " ") - 1)))
						&& (loc = rindex (file_line, " bnumber=")))
				{
					bookmark_num = atoi (substr (file_line, loc + 9));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					col = atoi (substr (file_line, loc + 1));
					loc = rindex (substr (file_line, 1, loc - 1), " ");
					line = atoi (substr (file_line, loc + 1));
					drop_bookmark (bookmark_num, "y", mark_buf, line, col);
				}
			}
			down ();
		}
	}
}

/*
**		_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.  Note that a hard carriage return is also inserted at the
**	end of the line as a step saver.
*/

string _remove_newlines (string trans_str)
{
	int	loc;

	/*
	**		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");
}
