Vile 16/17 - vi feel-alike (multi-window)

Paul Fox pgf at cayman.COM
Sat Jun 8 08:10:23 AEST 1991


#!/bin/sh
# this is vileshar.16 (part 16 of Vile)
# do not concatenate these parts, unpack them in order with /bin/sh
# file vile.hlp continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 16; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
echo 'x - continuing file vile.hlp'
sed 's/^X//' << 'SHAR_EOF' >> 'vile.hlp' &&
X		single following digit.)  Note that since the buffer names
X		are displayed in order of use, the list can quickly grow
X		"stale" -- the numbers may be meaningless if buffer
X		switching has been done since the last display of the list. 
X
X		The program version is also displayed with this command.
X
X	^A-*	Always display a list of all buffers.  Useful for updating the
X		list if it's already on the screen but may be out of date.
X		Any argument will cause the list to include _all_ buffers,
X		even those normally considered "invisible".  (For example,
X		macros are stored in "invisible" buffers.)
X
Window manipulation commands:  
-----------------------------
X	^T	Make Two windows.  Splits the current window in half. This
X		is the usual way to create a new window.
X	^K	Get rid of (Kill) this window.
X	^O	Make this the Only window on the screen.
X
X		The emacs-style commands ^X-2, ^X-0, and ^X-1 are also 
X		included, and are synonymous with ^T, ^K, and ^O.
X
X	^N	Go to the next window on the screen.
X	^P	Go to the previous window on the screen.
X
X		These two commands may be disturbing to vi users who use
X		^N and ^P to move between lines.  See the examples under
X		Key Rebinding for how to fix this.
X
X	v	Make the current window smaller.
X	V	Make the current window larger.
X
X	^A-^D	Scroll the next window down half a screen.
X	^A-^U	Scroll the next window up half a screen.
X	^A-^E	Scroll the next window up one line.
X	^A-^Y	Scroll the next window down one line.
X	(The previous four commands are useful when comparing two buffers.
X	 Mnemonic -- think of them as affecting the "A"lternate window.)
X
X	zH zM zL  These are synonyms for vi's 'z+', 'z.', and 'z-', which 
X		position the line holding the cursor at the top, middle, or
X		bottom of the screen, respectively.
X
X	^X-^R	Scroll the window right by 1/3 of a screen, or by the
X		number of lines specifed.
X	^X-^L	Scroll the window left by 1/3 of a screen, or by the
X		number of lines specifed.
X
X	If for some reason you can't get your screen set right via a
X	TERM variable, try the ":screen-rows" or ":screen-columns"
X	commands (which take their args (number of rows or columns
X	respectively) before you type the ":").
X
File manipulation commands:  
---------------------------
X	The usual :e, :r, :f, :w commands are available, though only
X	":e!" is available of the "!" options.  The :r command reads the
X	named file in after the current line.  To read a file before the
X	first line, use ":0r".
X	
X	As in vi, ranges of lines specified by line numbers (including '.',
X	'$', and '%' shorthands) or marks may precede these commands.  
X	Unlike vi, search patterns cannot be used as line specifiers.
X
X	In addition, two non-"colon" commands have been added:
X
X	^R	Prompts for a filename, and then reads it in _above_ the
X		current line.  If a register is specified (e.g. "a^R ), 
X		the file is read into that named register, but not inserted 
X		into the current buffer.
X
X	^W	is a writing operator, which prompts for a filename, and 
X		writes the specified region to that file.  Like all operators,
X		it the command is repeated, as in ^W^W, then lines are 
X		affected.  Use 10^W^W to write 10 lines.
X
X		If a register is specified (e.g. "a^W ) then the command 
X		is _not_ an operator, but writes the specified register to 
X		the named file.  
X
Shell Access
------------
X	Anywhere a filename is valid, a command name is also
X	valid, entered in the form "!shell-command".  The whole line is
X	handed to the shell, and the read or write operation is done on
X	the commands standard input or output, as appropriate.  Thus
X	you can type ":e !date" to edit a copy of today's date.
X
X	The ": !cmd" shell escape works pretty much as it does in vi.
X	The command ":!!" will rerun the previous such shell command.
X
X	The '!' operator works as expected.
X	
X	In addition, the ^X-! command runs a shell command and captures
X	its output in a specific buffer, called "[Output]".  This is
X	almost identical to ":e !cmd", except that in that case the buffer
X	is named according to the command name.
X
X	These output capture commands are most useful in conjunction with
X	the "error finder", described below.
X
X	On systems supporting job control, ^Z will suspend vile.
X
Text manipulation command:
--------------------------
X	Remember, these are only the new or different commands.  The 
X	standard vi set should still work.
X
X	Undo ("u") and line-undo ("U") are available for all commands.
X	They should be a little less capricious than their
X	vi counterparts, since they do not share the default yank register
X	for their operation.  Also, line-undo ("U") is available until
X	the next change anywhere in the file, rather than until you leave
X	the line.  Unfortunately, the cursor position after an undo may not 
X	always be the same as it would be in vi.
X
X	The vi "global" command is present, in its non-interactive form
X	only.  So is the "substitute" command.  These both look pretty
X	different while they're being used than they do in vi, and since
X	the searching is done right after the pattern is entered, there
X	can be a long delay while you're trying to finish typing your
X	complete command.  You can type commands just as you would have
X	in vi, i.e. ":g/oldpat/s//newstring/" will work.  But you won't
X	see any of the '/' characters.  Try it-- you'll get the idea.
X	Line ranges are not possible on ":g", but they are on ":s".
X
X	The ":v" counterpart to ":g" is not implemented.
X
X	The ":g" command can be followed by any of l (list), p (print),
X	< (left shift), > (right shift), r (read file), d (delete),
X	L (lower case), U (upper case), ~ (flip case), put (append
X	yanked text), Put (prepend yanked text), s (substitute),
X	t (trim trailing whitespace).  For example, ":g/pattern/Put"
X	will insert the contents of the default yank register just
X	above every line containing "pattern". 
X
X	Operators
X	---------
X	Vi has a class of commands known as "operators".  Operator
X	commands are always immediately followed by a motion command. 
X	The text affected by an operator is bounded by the initial
X	position, and the cursor position after the motion is
X	completed.  Thus the delete operator ('d') can be followed by
X	the word motion command ('w'), causing the next word to be
X	deleted.  The sequence "dG" will delete through the end of the
X	file, and "d/junk" will delete to the next occurence of the
X	string "junk".  Operators can all be "stuttered" to affect
X	lines.  Thus "dd" deletes one line, "4dd" affects 4 lines,
X	etc. 
X
X	Some operators in vile can be forced to affect whole lines,
X	though the motion wouldn't normally imply it, by using the ^X
X	form of the command.  For example, "d%" (assuming you are on a
X	curly brace) will delete a C-style block of code.  "^X-d%"
X	will delete that same area, plus anything else on the lines
X	containing the curly- brace endpoints.
X
X	Note that some operators always affect whole lines, no matter
X	how the motion is specified.  For instance, "!w" will always
X	filter an entire line, and not just a single word. 
X
X	There are several new operator commands:
X
X	^A-~	Is the operator form of the '~' command, so "^A-~~"
X		changes the case of all characters on the current
X		line, "^A-~w" does it to a word, "3^A-~}" does it for
X		3 paragraphs, etc. 
X	^A-u	Like ^A-~, but converts the region to upper case.
X	^A-l	Like ^A-~, but converts the region to lower case.
X
X	^A-f	Format the region based on the current fill column.  The
X                initial indentation of both the first and second lines
X                of the region are preserved, and all subsequent lines
X                get the second line's indentation.  This makes indented/
X		outdented paragraphs work correctly.  The usual use of
X                this command is "^A-f}", which does it to the current
X                paragraph.  (This is intentionally _not_ the same bevavior
X		obtained by "!fmt", since that behavior is obviously 
X		available elsewhere.)
X
X	^X-d	Delete the region, including the lines it starts and ends on.
X	^X-c	Change the region, including the lines it starts and ends on.
X	^X-y	Yank the region, including the lines it starts and ends on.
X
X	Text insertion
X	--------------
X	^X-p	Causes the previously yanked or deleted text, no matter
X		how it was obtained, to be inserted after the current line.
X		Usually text that did not consist of whole lines where it
X		came from is inserted immediately following the cursor.
X	^X-P	As above, but the text is put before the current line.
X		Thus "dw" followed by a "p" command does a normal insertion
X		of the deleted word, whereas "^X-p" results in the word
X		being inserted on a line by itself.
X
X	Searching
X	---------
X	^X-/	Does a forward search for the "word" located under the
X		cursor.
X	^X-?	Does a reverse search for the "word" located under the
X		cursor.
X	^A-/	Does not do a search, but sets the search pattern to the
X		"word" under the cursor.  Useful for "picking up" a word
X		from one buffer, and searching for it in another.
X
X	The following two commands may not always be present in vile,
X		depeinding on how it was built:
X	^X-S	Incremental forward searching.  As you enter the search 
X		string, the cursor is advanced to the next match with 
X		what you've typed so far.  Use ^F and ^R to continue the
X		search forward or in reverse, using the current pattern.
X	^X-R	As above, but in reverse.
X
X	Tags
X	----
X	Vile supports vi-style "tags" files.
X
X	":ta" or ":tag" allows you to enter a tagname to locate.  Changes
X		to that file and location.
X	^]	Uses the identifier currently under the cursor as the 
X		tagname.
X	^X-^]	"Un-tag" - pops to the file and location just previous to 
X		the last tag command.  (Some versions of vi have this command
X		attached to ^T)
X
X	When one of these commands is used, vile will look for a file named
X	"tags" in the current directory, and load it into a hidden buffer
X	for use during tag searches.  This buffer is editable if you wish
X	(":e tags"), but will not appear in the buffer lists.  If a buffer
X	named "tags" is already available when a tag is first requested, it
X	will be used instead of a file called "tags", and of course will
X	remain visible.
X
X	"Advanced" editing
X	------------------
X	[ Eventually, these will be rewritten to become "operators", similar to
X	those described above. ]
X	^A-<SPACE>	Convert tabs to spaces on the current line. An argument
X		tells how many lines.
X	^A-<TAB>	Convert as many spaces to tabs as possible on the 
X		current line.  Argument tells how many lines.
X	^A-o	Remove all but one blank line at the current spot.
X
Miscellaneous commands
----------------------
X	^X-^X	The "error finder".  Goes to the next file/line error pair 
X		specified in the last buffer captured from a command's
X		output.  This buffer is usually created with the ^X-! command.
X		For example, "-!cc -c junk.c" puts all of the compiler output
X		into the buffer named "[Output]".  Repeatedly hitting ^X-^X 
X		will position the editor at each error in turn, and will
X		eventually start over again at the top..
X	^X-t	Set or report on the tab-stop width.  Tab-stops may only be
X		set to 2, 4, 8, or 16 column spacings.  To set, the spacing
X		must precede the command, as in "4^X-t". The "set tabstop" 
X		command described below does the same thing.
X	^X-f	Set the fill-column to be used with ^A-f and auto-wrap mode on
X		insert.  The default value is 7/8's of the screen size, with
X		a maximum of 70.  Since arguments come before commands, you
X		type: 65^X-f.  The "set fillcol" command does the same thing.
X	^X-x	Set encryption key. (not well tested, but hopefully not broken)
X		The CRYPT mode must be set for this to do anything.
X	K	Count prefix.  The first time you type it, it is equivalent
X		to an argument of 4 to the following command.  If you repeat 
X		it, it becomes worth 16, the next time 64, etc...  
X
Editor modes
------------
X	Modes are associated with buffers, and are inherited from a set of
X	global modes.  To set a mode on a buffer, use ":set", to remove the
X	mode, use ":unset", ":setno", or ":set" with the modename prefixed
X	with "no".  To set and reset global modes, use ":setg", ":unsetg",
X	":setgno".  To display modes, use ":setall", ":modes", or
X	":setgall", ":gmodes".  (The modename "all" is also accepted as a
X	dummy mode, which sets nothing, but display instead.  So vi's "set all"
X	works as well.)  The possible modes are:
X
X	wrap	similar to vi's auto-wrap mode.  While inserting, words are
X		moved to the next line if the current line gets too long.
X		Unlike vi, wrapping is only attempted when a space is typed.
X
X	cmode	C-code mode..  Maintains current indentation level
X		automatically during insert.  If a line ends with a '{',
X		then the next line tabs in further.  If a line begins with
X		a '}', it is lined up with its matching paired brace.  If a
X		line starts with '#' it is started at the beginning of
X		line.  If the global CMODE is set, then the buffer's mode
X		is turned on automatically only for files ending in ".c" or
X		".h".  A common mistake is to put "set cmode" in a .vilerc
X		file.  One almost always wants "setg cmode".
X
X	swrap	Scanwrap mode.  Text searches will continue from past the
X		bottom of the file to the top, and vice-versa.
X
X	exact	Text searches must match the pattern exactly.  Otherwise,
X		searches are case-insensitive.
X
X	view	View the file only.  No changes are permitted.  This is set
X		automatically for the output of shell commands. 
X
X	magic	Allow meta-characters in search strings.  Otherwise,
X		strings are taken literally.  Meta characters available are:
X		^ - matches beginning of line
X		$ - matches end of line
X		. - matches any single character
X		* - matches any number of the previous character
X		[...] - matches a character class
X		\ - take the next character literally
X
X	asave	Automatic file saving.  Writes the file after every 256 
X		characters of inserted text.  Other file changes are not 
X		counted.
X
X	crypt	Causes files to be encrypted.  This is NOT compatible
X		with the UNIX crypt(1) routines.
X
X	list	The buffer will be displayed with tabs and newlines made
X		visible, instead of as whitespace.
X
X	dos	When writing the buffer, terminate lines with CR/LF pairs,
X                rather than the usual single LF.  On input, if the global
X		DOS mode is set, then incoming CR/LF pairs are taken as
X		line terminators, and the local DOS mode is set on the
X		buffer if the majority of lines ended that way.  If global
X		DOS mode is _not_ set, then incoming CR characters will be
X		visible on the screen. 
X
X	aindent Similar to C mode, above, but works for any buffer, and is
X		not sensitive to {, }, or #.  Attempts to align new lines
X		of text with previous lines.
X
X	lazy	If an attempt is made to edit a file (with ":e filename")
X		which does not exist in the current directory, vile will
X		try looking for a file of the same name (but in a different
X		directory) which has been referenced in the tags file. 
X		This mode is global to the editor, and is not "inherited"
X		by buffers.  It's not very fast, either.
X
X	tabstop Will prompt for a new value for spacing of tabstops.  The
X		only supported values are 2, 4, 8, and 16.  This value is,
X		unfortunately, not settable on a per-buffer basis. 
X
X	fillcol Will prompt for a new value for the fill column, where
X		auto-wrapping and region formatting will break lines.  This
X		value is, unfortunately, not settable on a per-buffer
X		basis. 
X
Special Character Expansion
---------------------------
X
X	As in vi, the % and # characters typed while responding to a prompt
X	will expand to the current or "alternate" filename.  In addition,
X	the colon character (":") expands to the identifier name under the
X	cursor.  Expansion of ! to the last command run is not implemented.
X
Key Rebinding
-------------
X
X	The vi "map", "map!", and "abbr" commands are not currently supported.
X
X	There is a key rebinding facility (if vile is built to include it),
X	which is invoked as follows.  One must know the "english" name for the
X	command being rebound.  Use ":describe-bindings" or ":apropos string"
X	to find englishnames containing "string".  Then use the command:
X		":bind-key englishname keyseq"
X	where keyseq is the exact keyboard sequence (i.e. single character,
X	or ^X or ^A followed by a single character) to which the
X	command should be bound.  In a ".vilerc" file, keyseq should be the
X	printable representation of the sequence, e.g. M-a or ^X-S.
X
X	Examples:
X	 To cause the / and ? commands to perform incremental
X	  searches, use:
X		bind-key incremental-search /
X		bind-key reverse-incremental-search ?
X	 To change the default window-switching behavior of ^N and ^P, try
X		bind-key next-line ^N
X		bind-key previous-line ^P
X	 To cause the space bar to move forward by pages, as in them "more"
X	  command, use:
X		bind-key next-page <sp>
X
X	(Space and tab can be represented with the strings: "<sp>" and 
X	"<tab>".)  The englishname "rebind-key" is synonymous with "bind-key".
X
X	Note that even the ^A and ^X prefix characters can be rebound, using
X	the dummy functions "cntl_a-prefix" and "cntl_x-prefix".  Even
X	if they are rebound, however, the binding list and bind-key
X	commands will refer to them as ^A and ^X.
X
Macros
------
X
X	The first type of macro in vile, is for temporary, quick macro
X	usage, and lets you record a macro as you execute vile commands.
X	You can then replay those keystrokes with a single key. 
X
X	^X-(	Begin recording a keyboard macro.  The keystrokes you type
X		are recorded, until you use ^X-).
X	^X-)	Finish recording a keyboard macro.
X	^X-&	Execute the keyboard macro.
X
X	Vile can also be extended (though I confess this has only been
X	lightly used or tested) by defining macros and then binding
X	execution of those macros to key sequences.  For example, if
X	the following lines appear in a .vilerc file:
X
X		1 store-macro
X		5 delete-til next-word
X		endm
X
X		bind-key execute-macro-1 M-1
X
X	then when M-1 is executed, 5 words will be deleted.  The "-til"
X	suffix on an englishname denotes that it is a vi operator style
X	command, and expects to be followed by a motion command.
X
Differences
------------
X	Of course, this really isn't vi.  Some of the following differences
X	deserve changing, others do not.
X
X	The parser for the ':' commands is not very vi-like.  For instance,
X	":e" will prompt you for a file name.  Most commands remember their
X	last argument, and will present it as the default reply to their
X	prompt. 
X
X	The backspace, line kill, job control, etc. characters are not
X	taken from the terminal settings on startup, but are hard-coded.
X	The insert-mode command characters cannot even be rebound.
X
X	In insert mode there is no word kill (^W) or line kill (^U or @).
X
X	Repeated backspacing while in insert mode will move past the point
X	where the insert began, until the beginning of line is reached.
X
X	There is no expansion of ! in filenames or shell escapes.  The
X	command ":!!" does rerun the previous shell command.  Occurences of
X	'#' and '%' are recognized and expanded to the previous or current
X	filename.  Other punctuation (e.g.  '~') may be expanded by your
X	shell (sh, csh), since it is handed filenames for expansion if they
X	contain any of these characters: * ? ~ [ ] $ { }
X
X	Paragraph and section boundaries, for the {, }, [, and ] commands
X	are not configurable, and do not exactly match those in vi.  The
X	current set is:
X	  Paragraphs: blank lines, or lines beginning in .I .L .P .Q or .b
X	  Sections: lines beginning in {, formfeeds, or .S .H .N
X	I think these will find more boundaries than vi, rather than fewer.
X
X	There is no special lisp support.  But then, when was the last time
X	you heard of a lisp programmer that used vi?
X
X	Of course, ex and open mode aren't there.
X
X	There is no concept of shiftwidth.  ^D and ^T are aliased to backspace
X	and tab for those whose fingers are too old for new tricks.
X
X	There are no "sentence" oriented motions. That is, "(" and ")" are
X	missing.
X
X	Most, but not all, of the word-motion-with-operator and end-of-line 
X	anomalies have been recreated.  One missing anomaly: In vile, "dw"
X	on the last word of a line ending in whitespace deletes the
X	trailing whitespace.  Vi does not delete the whitespace. 
X
Credits
-------
X	This code has been written by a _lot_ of people.  Names appearing
X	within comments in the micro-Emacs source code are: Dave
X	Conroy, Daniel Lawrence, John Gamble, Roger Ove, Dana Hoggatt,
X	Jon Reid, Steve Wilhite, George Jones, Adam Fritz, D.R.Banks,
X	Bob McNamara.  In addition, some of the "ex" code is by Steve
X	Kirkendall, author of the vi clone called "elvis".  The
X	changes to create vile from micro-Emacs were all done by Paul
X	Fox, who can be reached at pgf at cayman.com.   (By the way, this is
X	not the same Paul Fox who did the Crisp editor.)
X
X
SHAR_EOF
echo 'File vile.hlp is complete' &&
chmod 0444 vile.hlp ||
echo 'restore of vile.hlp failed'
Wc_c="`wc -c < 'vile.hlp'`"
test 24385 -eq "$Wc_c" ||
	echo 'vile.hlp: original size 24385, current size' "$Wc_c"
# ============= vmalloc.c ==============
echo 'x - extracting vmalloc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'vmalloc.c' &&
#include "estruct.h"
#include "edef.h"
X
/* these routines copied without permission from "The C User's Journal",
X	issue of Feb. 1989.  I assume they are Copyright 1989 by them.
X	They and the accompanying article were written by Eric White */
X
#if VMALLOC
X
#undef malloc
#undef free
#undef realloc
#undef calloc
#undef vverify
X
#include "stdio.h"
#include "string.h"
X
char *malloc(), *calloc(), *realloc();
X
char *vmalloc();
void vfree();
void rvverify();
char *vrealloc();
char *vcalloc();
void vdump();
X
typedef unsigned long ulong;
X
/* max buffers alloced but not yet freed */
#define MAXMALLOCS 20000
X
/* known pattern, and how many of them */
#define KP 0xaaaaaaaaL
#define KPW (2*sizeof(unsigned long))
X
X
static void trace();
static void errout();
X
static int nummallocs = 0;
struct mtype {
X	unsigned char *addr;
X	int size;
};
X
static struct mtype m[MAXMALLOCS];
X
#define VMAL 1
#define VFRE 2
#define VREA 4
int doverifys = VMAL|VREA;  /* |VFRE */
X
static void
dumpbuf(x)
int x;
{
X	unsigned char *c;
X	char s [80];
X	c = (unsigned char *)m[x].addr - 2;
X	/* dump malloc buffer to the vmalloc file */
X	while (c <= m[x].addr + m[x].size + KPW + KPW + 1) {
X		sprintf(s, "%04.4lx : %02x ", (long)c, *c);
X		if (c == m[x].addr)
X			strcat(s," <= leading known pattern");
X		if (c == m[x].addr + KPW)
X			strcat(s," <= addr of malloc buffer");
X		if (c == m[x].addr + m[x].size + KPW)
X			strcat(s," <= trailing known pattern");
X		strcat(s,"\n");
X		trace(s);
X		++c;
X	}
}
X		
void
rvverify(id,f,l)
char *id;
char *f;
{
X	char s[80];
X	register int c;
X	register struct mtype *mp;
X
X	
X	/* verify entire malloc heap */
X	for (mp = &m[nummallocs-1]; mp >= m; mp--) {
X		if (mp->addr != NULL) {
X			if (*(ulong *)mp->addr != KP || 
X				*(ulong *)(mp->addr + sizeof (ulong)) != KP)
X			{
X				sprintf(s, 
X		"ERROR: Malloc area corrupted (%s). %s %d\n",
X							 id,f,l);
X				fputs(s,stderr);
X				trace(s);
X				dumpbuf(mp - m);
X				errout();
X			}
X		}
X	}
}		
X
char *
vmalloc(size,f,l)
char *f;
{
X	unsigned char *buffer;
X	char *sp, s[80];
X	register int c;
X	register struct mtype *mp;
X
X	if (doverifys & VMAL)
X		rvverify("vmalloc",f,l);
X	if (( buffer = (unsigned char *)malloc(size + KPW + KPW)) == NULL) {
X		sp = "ERROR: real malloc returned NULL\n";
X		fprintf(stderr,sp);
X		trace(sp);
X		errout();
X	}
#ifdef VERBOSE
X	sprintf(s,"%04.4lx:vmalloc size = %ld, %s %d\n",
X		(long)buffer,(long)size,f,l);
X	trace(s);
#endif
X	/* find a place for an entry in m */
X	for (mp = m; mp < &m[MAXMALLOCS] && mp->addr != NULL; ++mp)
X		;
X	if (mp == &m[MAXMALLOCS]) {
X		sp = "ERROR: too many mallocs\n";
X		fprintf(stderr,sp);
X		trace(sp);
X		errout();
X	}
X	mp->addr = buffer;
X	mp->size = size;
X	if (mp == &m[nummallocs])
X		++nummallocs;
X	*(ulong *)(mp->addr) = KP;
X	*(ulong *)(mp->addr + sizeof(ulong)) = KP;
X	return (char *)(buffer + KPW);
}
X
char *
vcalloc(n,size,f,l)
int n, size;
char *f;
{
X	return vmalloc(n * size,f,l);
}
X
void
vfree(buffer,f,l)
unsigned char *buffer;
char *f;
{
X	unsigned char *b;
X	char s[80], *sp;
X	register struct mtype *mp;
X
X	b = buffer - KPW;
X	if (doverifys & VFRE)
X		rvverify("vfree",f,l);
X	for (mp = &m[nummallocs-1]; mp >= m && mp->addr != b; mp--)
X		;
X	if (mp < m) {
X		sprintf(s,"ERROR: location to free is not in list. %s %d\n",
X					 f,l);
X		fprintf(stderr,s);
X		trace(s);
X		errout();
X	}
#ifdef VERBOSE
X	sprintf(s,"%04.4lx:vfree %s %d\n",(long)b,f,l);
X	trace(s);
#endif
X	if (*(ulong *)mp->addr != KP || 
X		*(ulong *)(mp->addr + sizeof (ulong)) != KP)
X	{
X		sprintf(s,"ERROR: corrupted freed block. %s %d\n", f,l);
X		fprintf(stderr,s);
X		trace(s);
X		errout();
X	}
X	free(b);
X	mp->addr = NULL;
X	if (mp == &m[nummallocs-1])
X		--nummallocs;
}
X
char *
vrealloc(buffer,size,f,l)
unsigned char *buffer;
int size;
char *f;
{
X	unsigned char *b, *b2;
X	char *sp, s[80];
X	register int c;
X	register struct mtype *mp;
X
X	b = buffer - KPW;
X	if (doverifys & VREA)
X		rvverify("vrealloc",f,l);
X
X	for (mp = &m[nummallocs-1]; mp >= m && mp->addr != b; mp--)
X		;
X	if (mp < m) {
X		sprintf(s,"ERROR: location to realloc is not in list. %s %d\n",
X					 sp,f,l);
X		fprintf(stderr,s);
X		trace(s);
X		errout();
X	}
X
#ifdef VERBOSE
X	sprintf(s,"%04.4lx:vrealloc size = %ld, %s %d\n",
X			(long)b,(long)size,f,l);
X	trace(s);
#endif
X	*(ulong *)(mp->addr) = KP;
X	*(ulong *)(mp->addr + sizeof (ulong)) = KP;
X	b2 = (unsigned char *)realloc(b,size+KPW+KPW);
X	*(ulong *)(mp->addr + mp->size + KPW) = KP;
X	*(ulong *)(mp->addr + mp->size + KPW + sizeof (ulong)) = KP;
X	return (char *)(b2 + KPW);
}
X
void
vdump(id)
char *id;
{
X	char s[80];
X	int x;
X	sprintf(s,"=============Dump of malloc heap==========%s\n",id);
X	trace(s);
X	for (x = 0; x < nummallocs; ++x) {
X		if (m[x].addr != NULL) {
X			sprintf(s,"=========malloc buffer addr: %04.4lx\n",
X				(long)m[x].addr);
X			trace(s);
X			sprintf(s,"=========malloc buffer size: %04x\n",
X				(long)m[x].size + KPW + KPW);
X			trace(s);
X			dumpbuf(x);
X		}
X	}
}
X
static void
trace(s)
char *s;
{
X	static FILE *out = NULL;
X	if (out == NULL) {
X		unlink("vmalloc.log");
X		out = fopen("vmalloc.log", "w");
X		setbuf(out,NULL);
X	}
X	fputs(s,out);
}
X	
static void
errout()
{
X	sleep(1);
X	kill(getpid(),3);
X	pause();
}
X
setvmalloc(f,n)
{
X	register struct mtype *mp;
X	int i,num,found;
X	
X	if (f)
X		doverifys = n;
X	rvverify("requested",__FILE__,__LINE__);
X	for (mp = m, num = 0; mp < &m[MAXMALLOCS]; ++mp) {
X		if (mp->addr != NULL)
X			num++;
X	}
X	found = 0;
X	{ /* windows */
X		register WINDOW *wp;
X		for (wp=wheadp; wp != NULL; wp = wp->w_wndp)
X			found++;
X	}
X	{ /* buffers */
X		register BUFFER *bp;
X		for (bp=bheadp; bp != NULL; bp = bp->b_bufp) {
X			LINE *lp;
X			found++; /* for b_linep */
X			for(lp = bp->b_linep; lp->l_fp != bp->b_linep;
X								lp = lp->l_fp)
X				found++;
X			if (bp->b_nmmarks)
X				found++;
X			if (bp->b_ulinep)
X				found++;
X			found++;  /* for the buffer itself */
X			for (i = 0; i < 2; i++) {
X				for (lp = bp->b_udstks[i]; lp != NULL;
X							lp = lp->l_nxtundo)
X					found++;
X			}
X		}
X	}
X	found += term.t_mrow+1;  /* vscreen and the rows */
#if ! MEMMAP
X	found += term.t_mrow+1;  /* pscreen and the rows */
#endif
X	if (fline)
X		found++;
#if ! SMALLER
X	{ /* user vars */
X		extern UVAR uv[MAXVARS];
X		for (i=0; i < MAXVARS; i++)
X			if (uv[i].u_value) found++;
X	}
#endif
#if	FILOCK
X	need to count lock mallocs...
#endif
X	{ /* searching */
X		register MC	*mcptr;
X
X		if (patmatch)
X			found++;
X			
X		mcptr = &mcpat[0];
X		while (mcptr->mc_type != MCNIL)
X		{
X			if ((mcptr->mc_type & MASKCL) == CCL ||
X			    (mcptr->mc_type & MASKCL) == NCCL)
X				if (mcptr->u.cclmap) found++;
X			mcptr++;
X		}
X	}
X	{ /* kill registers */
X		for (i = 0; i < NKREGS; i++) {
X			KILL *kb;
X			if ((kb = kbs[i].kbufh) != NULL) {
X				while (kb) {
X					found++;
X					kb = kb->d_next;
X				}
X			}
X		}
X	}
X	mlwrite("doverifys %s %d, outstanding mallocs: %d, %d accounted for.",
X		f ? "set to":"is still", doverifys, num, found);
X	return TRUE;
}
X
#endif
SHAR_EOF
chmod 0444 vmalloc.c ||
echo 'restore of vmalloc.c failed'
Wc_c="`wc -c < 'vmalloc.c'`"
test 6798 -eq "$Wc_c" ||
	echo 'vmalloc.c: original size 6798, current size' "$Wc_c"
# ============= vmsvt.c ==============
echo 'x - extracting vmsvt.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'vmsvt.c' &&
/*
X *  Advanced VMS terminal driver
X *
X *  Knows about any terminal defined in SMGTERMS.TXT and TERMTABLE.TXT
X *  located in SYS$SYSTEM.
X *
X *  Author:  Curtis Smith
X *  Last Updated: 07/14/87
X */
X
#include	<stdio.h>		/* Standard I/O package		*/
#include	"estruct.h"		/* Emacs' structures		*/
#include	"edef.h"		/* Emacs' definitions		*/
X
#if	VMSVT
X
#include	 <descrip.h>		/* Descriptor definitions	*/
X
/*  These would normally come from iodef.h and ttdef.h  */
#define IO$_SENSEMODE	0x27		/* Sense mode of terminal	*/
#define TT$_UNKNOWN	0x00		/* Unknown terminal		*/
X
/** Forward references **/
int vmsopen(), ttclose(), vmskopen(), vmskclose(), ttgetc(), ttputc();
int ttflush(), vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev();
int vmscres();
extern int eolexist, revexist;
extern char sres[];
X
#if COLOR
int vmsfcol(), vmsbcol();
#endif
X
/** SMG stuff **/
static char * begin_reverse, * end_reverse, * erase_to_end_line;
static char * erase_whole_display;
static int termtype;
X
#define SMG$K_BEGIN_REVERSE		0x1bf
#define SMG$K_END_REVERSE		0x1d6
#define SMG$K_SET_CURSOR_ABS		0x23a
#define SMG$K_ERASE_WHOLE_DISPLAY	0x1da
#define SMG$K_ERASE_TO_END_LINE		0x1d9
X
X
/* Dispatch table. All hard fields just point into the terminal I/O code. */
TERM	term	= {
X	24 - 1,				/* Max number of rows allowable */
X	/* Filled in */ - 1,		/* Current number of rows used	*/
X	132,				/* Max number of columns	*/
X	/* Filled in */ 0,		/* Current number of columns	*/
X	64,				/* Min margin for extended lines*/
X	8,				/* Size of scroll region	*/
X	100,				/* # times thru update to pause */
X	vmsopen,			/* Open terminal at the start	*/
X	ttclose,			/* Close terminal at end	*/
X	vmskopen,			/* Open keyboard		*/
X	vmskclose,			/* Close keyboard		*/
X	ttgetc,				/* Get character from keyboard	*/
X	ttputc,				/* Put character to display	*/
X	ttflush,			/* Flush output buffers		*/
X	vmsmove,			/* Move cursor, origin 0	*/
X	vmseeol,			/* Erase to end of line		*/
X	vmseeop,			/* Erase to end of page		*/
X	vmsbeep,			/* Beep				*/
X	vmsrev,				/* Set reverse video state	*/
X	vmscres				/* Change screen resolution	*/
#if	COLOR
X	, vmsfcol,			/* Set forground color		*/
X	vmsbcol				/* Set background color		*/
#endif
};
X
/***
X *  ttputs  -  Send a string to ttputc
X *
X *  Nothing returned
X ***/
ttputs(string)
char * string;				/* String to write		*/
{
X	if (string)
X		while (*string != '\0')
X			ttputc(*string++);
}
X
X
/***
X *  vmsmove  -  Move the cursor (0 origin)
X *
X *  Nothing returned
X ***/
vmsmove(row, col)
int row;				/* Row position			*/
int col;				/* Column position		*/
{
X	char buffer[32];
X	int ret_length;
X	static int request_code = SMG$K_SET_CURSOR_ABS;
X	static int max_buffer_length = sizeof(buffer);
X	static int arg_list[3] = { 2 };
X	register char * cp;
X	
X	register int i;
X
X	/* Set the arguments into the arg_list array
X	 * SMG assumes the row/column positions are 1 based (boo!)
X	 */
X	arg_list[1] = row + 1;
X	arg_list[2] = col + 1;
X
X	if ((smg$get_term_data(		/* Get terminal data		*/
X		&termtype,		/* Terminal table address	*/
X		&request_code,		/* Request code			*/
X		&max_buffer_length,	/* Maximum buffer length	*/
X		&ret_length,		/* Return length		*/
X		buffer,			/* Capability data buffer	*/
X		arg_list)		/* Argument list array		*/
X
X	/* We'll know soon enough if this doesn't work		*/
X			& 1) == 0) {
X				ttputs("OOPS");
X				return;
X			}
X
X	/* Send out resulting sequence				*/
X	i = ret_length;
X	cp = buffer;
X	while (i-- > 0)
X		ttputc(*cp++);
}
X
X
/***
X *  vmsrev  -  Set the reverse video status
X *
X *  Nothing returned
X ***/
vmsrev(status)
int status;				/* TRUE if setting reverse	*/
{
X	if (status)
X		ttputs(begin_reverse);
X	else 
X		ttputs(end_reverse);
}
X
/***
X *  vmscres  -  Change screen resolution (which it doesn't)
X *
X *  Nothing returned
X ***/
vmscres()
{
X	/* But it could.  For vt100/vt200s, one could switch from
X	80 and 132 columns modes */
}
X
X
#if	COLOR
/***
X *  vmsfcol  -  Set the forground color (not implimented)
X *
X *  Nothing returned
X ***/
vmsfcol()
{
}
X
/***
X *  vmsbcol  -  Set the background color (not implimented)
X *
X *  Nothing returned
X ***/
vmsbcol()
{
}
#endif
X
/***
X *  vmseeol  -  Erase to end of line
X *
X *  Nothing returned
X ***/
vmseeol()
{
X	ttputs(erase_to_end_line);
}
X
X
/***
X *  vmseeop  -  Erase to end of page (clear screen)
X *
X *  Nothing returned
X ***/
vmseeop()
{
X	ttputs(erase_whole_display);
}
X
X
/***
X *  vmsbeep  -  Ring the bell
X *
X *  Nothing returned
X ***/
vmsbeep()
{
X	ttputc('\007');
}
X
X
/***
X *  vmsgetstr  -  Get an SMG string capability by name
X *
X *  Returns:	Escape sequence
X *		NULL	No escape sequence available
X ***/ 
char * vmsgetstr(request_code)
int request_code;			/* Request code			*/
{
X	register char * result;
X	static char seq_storage[1024];
X	static char * buffer = seq_storage;
X	static int arg_list[2] = { 1, 1 };
X	int max_buffer_length, ret_length;
X
X	/*  Precompute buffer length */
X	
X	max_buffer_length = (seq_storage + sizeof(seq_storage)) - buffer;
X
X	/* Get terminal commands sequence from master table */
X
X	if ((smg$get_term_data(	/* Get terminal data		*/
X		&termtype,	/* Terminal table address	*/
X		&request_code,	/* Request code			*/
X		&max_buffer_length,/* Maximum buffer length	*/
X		&ret_length,	/* Return length		*/
X		buffer,		/* Capability data buffer	*/
X		arg_list)	/* Argument list array		*/
X
X	/* If this doesn't work, try again with no arguments */
X	
X		& 1) == 0 && 
X
X		(smg$get_term_data(	/* Get terminal data		*/
X			&termtype,	/* Terminal table address	*/
X			&request_code,	/* Request code			*/
X			&max_buffer_length,/* Maximum buffer length	*/
X			&ret_length,	/* Return length		*/
X			buffer)		/* Capability data buffer	*/
X
X	/* Return NULL pointer if capability is not available */
X	
X			& 1) == 0)
X				return NULL;
X
X	/* Check for empty result */
X	if (ret_length == 0)
X		return NULL;
X	
X	/* Save current position so we can return it to caller */
X
X	result = buffer;
X
X	/* NIL terminate the sequence for return */
X	
X	buffer[ret_length] = 0;
X
X	/* Advance buffer */
X
X	buffer += ret_length + 1;
X
X	/* Return capability to user */
X	return result;
}
X
X
/** I/O information block definitions **/
struct iosb {			/* I/O status block			*/
X	short	i_cond;		/* Condition value			*/
X	short	i_xfer;		/* Transfer count			*/
X	long	i_info;		/* Device information			*/
};
struct termchar {		/* Terminal characteristics		*/
X	char	t_class;	/* Terminal class			*/
X	char	t_type;		/* Terminal type			*/
X	short	t_width;	/* Terminal width in characters		*/
X	long	t_mandl;	/* Terminal's mode and length		*/
X	long	t_extend;	/* Extended terminal characteristics	*/
};
static struct termchar tc;	/* Terminal characteristics		*/
X
/***
X *  vmsgtty - Get terminal type from system control block
X *
X *  Nothing returned
X ***/
vmsgtty()
{
X	short fd;
X	int status;
X	struct iosb iostatus;
X	$DESCRIPTOR(devnam, "SYS$INPUT");
X
X	/* Assign input to a channel */
X	status = sys$assign(&devnam, &fd, 0, 0);
X	if ((status & 1) == 0)
X		exit (status);
X
X	/* Get terminal characteristics */
X	status = sys$qiow(		/* Queue and wait		*/
X		0,			/* Wait on event flag zero	*/
X		fd,			/* Channel to input terminal	*/
X		IO$_SENSEMODE,		/* Get current characteristic	*/
X		&iostatus,		/* Status after operation	*/
X		0, 0,			/* No AST service		*/
X		&tc,			/* Terminal characteristics buf */
X		sizeof(tc),		/* Size of the buffer		*/
X		0, 0, 0, 0);		/* P3-P6 unused			*/
X
X	/* De-assign the input device */
X	if ((sys$dassgn(fd) & 1) == 0)
X		exit(status);
X
X	/* Jump out if bad status */
X	if ((status & 1) == 0)
X		exit(status);
X	if ((iostatus.i_cond & 1) == 0)
X		exit(iostatus.i_cond);
}
X
X
/***
X *  vmsopen  -  Get terminal type and open terminal
X *
X *  Nothing returned
X ***/
vmsopen()
{
X	/* Get terminal type */
X	vmsgtty();
X	if (tc.t_type == TT$_UNKNOWN) {
X		printf("Terminal type is unknown!\n");
X		printf("Try set your terminal type with SET TERMINAL/INQUIRE\n");
X		printf("Or get help on SET TERMINAL/DEVICE_TYPE\n");
X		exit(3);
X	}
X
X	/* Access the system terminal definition table for the		*/
X	/* information of the terminal type returned by IO$_SENSEMODE	*/
X	if ((smg$init_term_table_by_type(&tc.t_type, &termtype) & 1) == 0)
X		return -1;
X		
X	/* Set sizes */
X	term.t_nrow = ((unsigned int) tc.t_mandl >> 24) - 1;
X	term.t_ncol = tc.t_width;
X
X	/* Get some capabilities */
X	begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE);
X	end_reverse = vmsgetstr(SMG$K_END_REVERSE);
X	revexist = begin_reverse != NULL && end_reverse != NULL;
X	erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE);
X	eolexist = erase_whole_display != NULL;
X	erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY);
X
X	/* Set resolution */
X	strcpy(sres, "NORMAL");
X
X	/* Open terminal I/O drivers */
X	ttopen();
}
X
X
/***
X *  vmskopen  -  Open keyboard (not used)
X *
X *  Nothing returned
X ***/
vmskopen()
{
}
X
X
/***
X *  vmskclose  -  Close keyboard (not used)
X *
X *  Nothing returned
X ***/
vmskclose()
{
}
X
X
/***
X *  fnclabel  -  Label function keys (not used)
X *
X *  Nothing returned
X ***/
#if	FLABEL
fnclabel(f, n)		/* label a function key */
int f,n;	/* default flag, numeric argument [unused] */
{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
}
#endif
X
X
/***
X *  spal  -  Set palette type  (Are you kidding?)
X *
X *  Nothing returned
X ***/
spal()
{
}
X
#else
X
/***
X *  hellovms  -  Avoid error because of empty module
X *
X *  Nothing returned
X ***/
hellovms()
{
}
X
#endif
SHAR_EOF
chmod 0444 vmsvt.c ||
echo 'restore of vmsvt.c failed'
Wc_c="`wc -c < 'vmsvt.c'`"
test 9271 -eq "$Wc_c" ||
	echo 'vmsvt.c: original size 9271, current size' "$Wc_c"
# ============= vt52.c ==============
echo 'x - extracting vt52.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'vt52.c' &&
/*
X * The routines in this file
X * provide support for VT52 style terminals
X * over a serial line. The serial I/O services are
X * provided by routines in "termio.c". It compiles
X * into nothing if not a VT52 style device. The
X * bell on the VT52 is terrible, so the "beep"
X * routine is conditionalized on defining BEL.
X */
#define	termdef	1			/* don't define "term" external */
X
#include        <stdio.h>
#include        "estruct.h"
#include	"edef.h"
X
#if     VT52
X
#define NROW    24                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define	NPAUSE	100			/* # times thru update to pause */
#define BIAS    0x20                    /* Origin 0 coordinate bias.    */
#define ESC     0x1B                    /* ESC character.               */
#define BEL     0x07                    /* ascii bell character         */
X
extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern  int     vt52move();
extern  int     vt52eeol();
extern  int     vt52eeop();
extern  int     vt52beep();
extern  int     vt52open();
extern	int	vt52rev();
extern	int	vt52cres();
extern	int	vt52kopen();
extern	int	vt52kclose();
X
#if	COLOR
extern	int	vt52fcol();
extern	int	vt52bcol();
#endif
X
/*
X * Dispatch table. All the
X * hard fields just point into the
X * terminal I/O code.
X */
TERM    term    = {
X	NROW-1,
X        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        &vt52open,
X        &ttclose,
X	&vt52kopen,
X	&vt52kclose,
X        &ttgetc,
X        &ttputc,
X        &ttflush,
X        &vt52move,
X        &vt52eeol,
X        &vt52eeop,
X        &vt52beep,
X        &vt52rev,
X        &vt52cres
#if	COLOR
X	, &vt52fcol,
X	&vt52bcol
#endif
};
X
vt52move(row, col)
{
X        ttputc(ESC);
X        ttputc('Y');
X        ttputc(row+BIAS);
X        ttputc(col+BIAS);
}
X
vt52eeol()
{
X        ttputc(ESC);
X        ttputc('K');
}
X
vt52eeop()
{
X        ttputc(ESC);
X        ttputc('J');
}
X
vt52rev(status)	/* set the reverse video state */
X
int status;	/* TRUE = reverse video, FALSE = normal video */
X
{
X	/* can't do this here, so we won't */
}
X
vt52cres()	/* change screen resolution - (not here though) */
X
{
X	return(TRUE);
}
X
spal()		/* change palette string */
X
{
X	/*	Does nothing here	*/
}
X
#if	COLOR
vt52fcol()	/* set the forground color [NOT IMPLIMENTED] */
{
}
X
vt52bcol()	/* set the background color [NOT IMPLIMENTED] */
{
}
#endif
X
vt52beep()
{
#ifdef  BEL
X        ttputc(BEL);
X        ttflush();
#endif
}
X
vt52open()
{
#if     V7 | BSD
X        register char *cp;
X        char *getenv();
X
X        if ((cp = getenv("TERM")) == NULL) {
X                puts("Shell variable TERM not defined!");
X                exit(1);
X        }
X        if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
X                puts("Terminal type not 'vt52'or 'z19' !");
X                exit(1);
X        }
#endif
X        ttopen();
}
X
vt52kopen()
X
{
}
X
vt52kclose()
X
{
}
X
X
#if	FLABEL
fnclabel(f, n)		/* label a function key */
X
int f,n;	/* default flag, numeric argument [unused] */
X
{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
}
#endif
#else
X
vt52hello()
X
{
}
X
#endif
SHAR_EOF
chmod 0444 vt52.c ||
echo 'restore of vt52.c failed'
Wc_c="`wc -c < 'vt52.c'`"
test 3386 -eq "$Wc_c" ||
	echo 'vt52.c: original size 3386, current size' "$Wc_c"
# ============= window.c ==============
echo 'x - extracting window.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'window.c' &&
/*
X * Window management. Some of the functions are internal, and some are
X * attached to keys that the user actually types.
X */
X
#include        <stdio.h>
#include        "estruct.h"
#include	"edef.h"
X
#if	MEGAMAX & ST520
overlay	"window"
#endif
X
/*
X * Reposition dot's line to line "n" of the window. If the argument is
X * positive, it is that line. If it is negative it is that line from the
X * bottom. If it is 0 the window is centered around dot (this is what 
X * the standard redisplay code does). Defaults to 0.
X */
reposition(f, n)
{
X    if (f == FALSE)	/* default to 0 to center screen */
X	n = 0;
X    curwp->w_force = n;
X    curwp->w_flag |= WFFORCE;
X    return (TRUE);
}
X
/*
X * Refresh the screen. With no argument, it just does the refresh. With an
X * argument it recenters "." in the current window.
X */
refresh(f, n)
{
#if	NeWS	/* see if the window has changed size */
X    newsrefresh() ;
#endif	
X
X	if (f == FALSE) {
X		sgarbf = TRUE;
X	} else {
X	        curwp->w_force = 0;             /* Center dot. */
X	        curwp->w_flag |= WFFORCE;
X	}
X
#if     NeWS
X	newsreportmodes() ;
#endif
X	return (TRUE);
}
X
/*
X * The command make the next window (next => down the screen) the current
X * window. There are no real errors, although the command does nothing if
X * there is only 1 window on the screen.
X *
X * with an argument this command finds the <n>th window from the top
X *
X */
nextwind(f, n)
int f, n;	/* default flag and numeric argument */
{
X	register WINDOW *wp;
X	register int nwindows;		/* total number of windows */
X
X	if (f) {
X
X		/* first count the # of windows */
X		wp = wheadp;
X		nwindows = 1;
X		while (wp->w_wndp != NULL) {
X			nwindows++;
X			wp = wp->w_wndp;
X		}
X
X		/* if the argument is negative, it is the nth window
X		   from the bottom of the screen			*/
X		if (n < 0)
X			n = nwindows + n + 1;
X
X		/* if an argument, give them that window from the top */
X		if (n > 0 && n <= nwindows) {
X			wp = wheadp;
X			while (--n)
X				wp = wp->w_wndp;
X		} else {
X			mlwrite("Window number out of range");
X			return(FALSE);
X		}
X	} else {
X		if ((wp = curwp->w_wndp) == NULL)
X			wp = wheadp;
X	}
X	curwp = wp;
X	make_current(curwp->w_bufp);
X	upmode();
X	return (TRUE);
}
X
poswind(f,n)
{
X	register int c;
X	register int rows;
X	int s;
X
X	c = kbd_key();
X	if (c == abortc)
X		return FALSE;
X
X	if (c == '+' || c == '\r' || c == 'H') {
X		rows = 1;
X	} else if (c == '.' || c == 'M') {
X		rows = 0;
X	} else if (c == '-' || c == 'L') {
X		rows = -1;
X	} else {
X		TTbeep();
X		return FALSE;
X	}
X
X	if (f == TRUE) {
X		s = gotoline(f,n);
X		if (s != TRUE)
X			return(s);
X	}
X	return(reposition(TRUE,rows));
}
X
/*
X * This command makes the previous window (previous => up the screen) the
X * current window. There arn't any errors, although the command does not do a
X * lot if there is 1 window.
X */
prevwind(f, n)
{
X	register WINDOW *wp1;
X	register WINDOW *wp2;
X
X	/* if we have an argument, we mean the nth window from the bottom */
X	if (f)
X		return(nextwind(f, -n));
X
X	wp1 = wheadp;
X	wp2 = curwp;
X
X	if (wp1 == wp2)
X		wp2 = NULL;
X
X	while (wp1->w_wndp != wp2)
X		wp1 = wp1->w_wndp;
X
X	curwp = wp1;
X	make_current(curwp->w_bufp);
X	upmode();
X	return (TRUE);
}
X
/*
X * This command moves the current window down by "arg" lines. Recompute the
X * top line in the window. The move up and move down code is almost completely
X * the same; most of the work has to do with reframing the window, and picking
X * a new dot. We share the code by having "move down" just be an interface to
X * "move up". Magic.
X */
mvdnwind(f, n)
int n;
{
X	return (mvupwind(f, -n));
}
X
/*
X * Move the current window up by "arg" lines. Recompute the new top line of
X * the window. Look to see if "." is still on the screen. If it is, you win.
X * If it isn't, then move "." to center it in the new framing of the window
X * (this command does not really move "." (except as above); it moves the 
X * frame).
X */
mvupwind(f, n)
int n;
{
X    register LINE *lp;
X    register int i;
X    int was_n = n;
X
X    lp = curwp->w_linep;
X
X    if (n < 0) {
X        while (n++ && lforw(lp) != curbp->b_linep)
X            lp = lforw(lp);
X    } else {
X        while (n-- && lback(lp)!=curbp->b_linep)
X            lp = lback(lp);
X    }
X
X    curwp->w_linep = lp;
X    curwp->w_flag |= WFHARD|WFMODE;
X
X	/* is it still in the window */
X    for (i = 0; i < curwp->w_ntrows; ++i) {
X        if (lp == curwp->w_dotp)
X            return (TRUE);
X        if (lforw(lp) == curbp->b_linep)
X            break;
X        lp = lforw(lp);
X    }
X	/* now lp is either just past the window bottom, or
X		it's the last line of the file */
X
X	/* preserve the current column */
X    if (curgoal < 0)
X        curgoal = getccol(FALSE);
X
X    if (was_n < 0)
X	    curwp->w_dotp  = curwp->w_linep;
X    else
X	    curwp->w_dotp  = lback(lp);
X    curwp->w_doto  = getgoal(curwp->w_dotp);
X    return (TRUE);
}
X
mvdnnxtwind(f, n)
{
X	nextwind(FALSE, 1);
X	mvdnwind(f, n);
X	prevwind(FALSE, 1);
}
X
mvupnxtwind(f, n)
{
X	nextwind(FALSE, 1);
X	mvupwind(f, n);
X	prevwind(FALSE, 1);
}
X
mvrightwind(f,n)
{
X	int move, col;
X
X	if (f)
X		move = n;
X	else
X		move = term.t_ncol/3;
X
X	if (curwp->w_sideways + move > (col = getccol(FALSE)) - 1) {
X		TTbeep();
X		return FALSE;
X	}
X
X	curwp->w_sideways += move;
X
X        curwp->w_flag  |= WFHARD|WFMOVE;
X
X	return TRUE;
}
X
mvleftwind(f,n)
{
X	if (f)
X		curwp->w_sideways -= n;
X	else
X		curwp->w_sideways -= term.t_ncol/3;
X
X	if (curwp->w_sideways < 0)
X		curwp->w_sideways = 0;
X
X        curwp->w_flag  |= WFHARD|WFMOVE;
X
X	return TRUE;
}
X
/*
X * This command makes the current window the only window on the screen.
X * Try to set the framing so that "." does not have to move on the
X * display. Some care has to be taken to keep the values of dot and mark in
X * the buffer structures right if the distruction of a window makes a buffer
X * become undisplayed.
X */
onlywind(f, n)
{
X        register WINDOW *wp;
X        register LINE   *lp;
X        register int    i;
X
X        wp = wheadp;
X        while (wp != NULL) {
X		register WINDOW *nwp;
X		nwp = wp->w_wndp;
X        	if (wp != curwp) {
X	                if (--wp->w_bufp->b_nwnd == 0)
X	                        undispbuff(wp->w_bufp,wp);
X	                free((char *) wp);
X	        }
X                wp = nwp;
X        }
X        wheadp = curwp;
X        wheadp->w_wndp = NULL;
X        lp = curwp->w_linep;
X        i  = curwp->w_toprow;
X        while (i!=0 && lback(lp)!=curbp->b_linep) {
X                --i;
X                lp = lback(lp);
X        }
X        curwp->w_toprow = 0;
X        curwp->w_ntrows = term.t_nrow-1;
X        curwp->w_linep  = lp;
X        curwp->w_flag  |= WFMODE|WFHARD;
X        return (TRUE);
}
X
/*
X * Delete the current window, placing its space in the window above,
X * or, if it is the top window, the window below.
X */
X
delwind(f,n)
int f, n;	/* arguments are ignored for this command */
{
X	return delwp(curwp);
}
X
delwp(thewp)
WINDOW *thewp;
{
X	register WINDOW *wp;	/* window to recieve deleted space */
X	register LINE *lp;	/* line pointer */
X	register int i;
X
X	/* if there is only one window, don't delete it */
X	if (wheadp->w_wndp == NULL) {
X		mlwrite("Cannot delete the only window");
X		return(FALSE);
X	}
X
X	/* find recieving window and give up our space */
X	if (thewp == wheadp) { /* there's nothing before */
X		/* find the next window down */
X		wp = thewp->w_wndp;
X                lp = wp->w_linep;
X                /* the prev. window (thewp) has wp->w_toprow rows in it */
X                for (i = wp->w_toprow;
X                		 i > 0 && lback(lp) != wp->w_bufp->b_linep; --i)
X                        lp = lback(lp);
X                wp->w_linep  = lp;
X		wp->w_ntrows += wp->w_toprow;  /* add in the new rows */
X		wp->w_toprow = 0;	/* and we're at the top of the screen */
X		wheadp = wp;	/* and at the top of the list as well */
X	} else {
X		/* find window before thewp in linked list */
X		for (wp = wheadp; wp->w_wndp != thewp; wp = wp->w_wndp)
X			;
X		/* add thewp's rows to the next window up */
X		wp->w_ntrows += thewp->w_ntrows+1;
X		
X		wp->w_wndp = thewp->w_wndp; /* make their next window ours */
X	}
X
X	/* get rid of the current window */
X	if (--thewp->w_bufp->b_nwnd == 0)
X		undispbuff(thewp->w_bufp,thewp);
X	free((char *)thewp);
X	if (thewp == curwp) {
X		curwp = wp;
X		curwp->w_flag |= WFHARD;
X		make_current(curwp->w_bufp);
X	}
X	upmode();
X	return(TRUE);
}
X
/*
X	Split the current window.  A window smaller than 3 lines cannot be
X	split.  An argument of 1 forces the cursor into the upper window, an
X	argument of two forces the cursor to the lower window.  The only other
X	error that is possible is a "malloc" failure allocating the structure
X	for the new window.
X */
splitwind(f, n)
{
X        register WINDOW *wp;
X        register LINE   *lp;
X        register int    ntru;
X        register int    ntrl;
X        register int    ntrd;
X        register WINDOW *wp1;
X        register WINDOW *wp2;
X	register int i;
X
X        if (curwp->w_ntrows < 3) {
X                mlwrite("Cannot split a %d line window", curwp->w_ntrows);
X                return (FALSE);
X        }
X        if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
X                mlwrite("[OUT OF MEMORY]");
X                return (FALSE);
X        }
X        ++curbp->b_nwnd;                        /* Displayed twice.     */
X        wp->w_bufp  = curbp;
X        wp->w_dotp  = curwp->w_dotp;
X        wp->w_doto  = curwp->w_doto;
X        wp->w_mkp = curwp->w_mkp;
X        wp->w_mko = curwp->w_mko;
X        wp->w_linep = curwp->w_linep;
X        wp->w_ldmkp = curwp->w_ldmkp;
X        wp->w_ldmko = curwp->w_ldmko;
X        wp->w_sideways  = curwp->w_sideways;
X        wp->w_flag  = 0;
X        wp->w_force = 0;
#if	COLOR
X	/* set the colors of the new window */
X	wp->w_fcolor = gfcolor;
X	wp->w_bcolor = gbcolor;
#endif
X        ntru = (curwp->w_ntrows-1) / 2;         /* Upper size           */
X        ntrl = (curwp->w_ntrows-1) - ntru;      /* Lower size           */
X        lp = curwp->w_linep;
X        ntrd = 0;
X        while (lp != curwp->w_dotp) {
X                ++ntrd;
X                lp = lforw(lp);
X        }
X	/* ntrd is now the row containing dot */
X        if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) {
X                /* Old is upper window. */
X	        /* Adjust the top line if necessary */
X                if (ntrd == ntru)               /* Hit mode line.       */
X			if (ntrl > 1) {
X				ntru++;
X				ntrl--;
X			} else
X	                        curwp->w_linep = lforw(curwp->w_linep);
X                curwp->w_ntrows = ntru; /* new size */
X		/* insert new window after curwp in window list */
X                wp->w_wndp = curwp->w_wndp;
X                curwp->w_wndp = wp;
X		/* set new window's position and size */
X                wp->w_toprow = curwp->w_toprow+ntru+1;
X                wp->w_ntrows = ntrl;
X		/* try to keep lower from reframing */
X		for (i = ntru+1; i > 0 &&
X				 wp->w_linep != wp->w_bufp->b_linep; i--) {
X			wp->w_linep = lforw(wp->w_linep);
X		}
X		wp->w_dotp = wp->w_linep;
X		wp->w_doto = 0;
X        } else {
X		/* Old is lower window  */
X                wp1 = NULL;
X                wp2 = wheadp;
X                while (wp2 != curwp) {
X                        wp1 = wp2;
X                        wp2 = wp2->w_wndp;
X                }
X                if (wp1 == NULL)
X                        wheadp = wp;
X                else
X                        wp1->w_wndp = wp;
X                wp->w_wndp   = curwp;
X                wp->w_toprow = curwp->w_toprow;
X                wp->w_ntrows = ntru;
X                ++ntru;                         /* Mode line.           */
X                curwp->w_toprow += ntru;
X                curwp->w_ntrows  = ntrl;
X		wp->w_dotp = wp->w_linep;
X		/* move upper window dot to bottom line of upper */
X		for (i = ntru-2; i > 0 && wp->w_dotp!=wp->w_bufp->b_linep; i--)
X			wp->w_dotp = lforw(wp->w_dotp);
X		wp->w_doto = 0;
X		/* adjust lower window topline */
X                while (ntru--)
X                        curwp->w_linep = lforw(curwp->w_linep);
X        }
X        curwp->w_flag |= WFMODE|WFHARD;
X        wp->w_flag |= WFMODE|WFHARD;
X        return (TRUE);
}
X
/*
X * Enlarge the current window. Find the window that loses space. Make sure it
X * is big enough. If so, hack the window descriptions, and ask redisplay to do
SHAR_EOF
true || echo 'restore of window.c failed'
echo 'End of Vile part 16'
echo 'File window.c is continued in part 17'
echo 17 > _shar_seq_.tmp
exit 0
-- 
		paul fox, pgf at cayman.com, (617)494-1999
		Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139



More information about the Alt.sources mailing list