!SQU.TEC V40.00!
! --------------------------------------------------------------------- !
!									!
! TECO macro to squish other TECO macros.  This macro will take a nice,	!
! readable TECO macro and squish it so that it is as small and as fast	!
! as possible (and is completely unreadable).				!
!									!
! Command line:								!
!									!
!	MUNG SQU OUTFILE[.TEC]=INFILE[.TES]/SWITCHES			!
!									!
! For example:								!
!									!
!	MUNG SQU SQU.TEC=SQU.TES/D:N/L:Y/B:Y/T:Y/C:Y/W:N/A:Y/E:N	!
!									!
! Switches:								!
!									!
!	/D	Delete lexical CR/LFs					!
!	/L	Set line lengths					!
!	/B	Delete blank lines					!
!	/T	Delete lexical TAB/FFs					!
!	/C	Delete comments						!
!	/W	Watch progress						!
!	/A	Automatic mode (ie: squish macros loaded w/^U)		!
!	/E	Allow adjacent ESCapes					!
!									!
! Use of Q-registers:							!
!									!
!	A.str = macro to run the squish macro in Z; then, if /L is set, !
!	post-process the squished macro so each line is no longer the	!
!	length set by /L:nn.						!
!									!
!	B.num = TRUE if any command line switches were present.		!
!									!
!	C.num = the buffer pointer while squishing things for error	!
!	reporting purposes.						!
!									!
!	C.str = the set of comment delimiter characters	(/C:set, or	!
!	<SP><TAB> for /C:Y).						!
!									!
!	E.str = macro telling when to break out of squish loop.  either	!
!	on end of file or end of sub-squish loop			!
!									!
!	F.str = SQU initialization and termination macro.		!
!									!
!	H.num = TRUE (-1) if we are allowing adjacent escapes (/E:Y)	!
!									!
!	K.str = the "non-squishable ^U command" character set (/A:set)	!
!	If we run into a @^Q<delim>text<delim>, and <delim> is *not*	!
!	in the "non-squishable ^U command" character set, we'll assume	!
!	that "text" is a macro that we have to recursively squish.	!
!									!
!	O.num = the maximum line width (/L:nn, or 70 for /L)		!
!									!
!	P.str = ???P is cleared if abort-on-error bit is set, and it is	!
!	executed as a macro during cleanup, but I don't see where it is	!
!	loaded anywhere.						!
!									!
!	Q.str = used to contain responses from the user.		!
!									!
!	R.str = "get-response-from-user" macro.				!
!									!
!	S.num, T.num, U.num = used to store the start and end of text	!
!	arguments to TECO commands like FStext1$text2$.			!
!									!
!	W.str = "-1W" scope refresh command if watching progress (/W:Y)	!
!									!
!	Z.str = SQU macro proper					!
!									!
!	1.num = TRUE (-1) if the following command is @-sign modified	!
!									!
!	8.str = a string containing potential delimiting characters	!
!	in case we can't use ESC as a delimiter.  this string will be	!
!	searched for a delimiting character which is not in the string	!
!	we are trying to delimit.					!
!									!
!	9.str = a mask containing labels we'll use in a goto.  Each	!
!	character in the mask corresponds with a TECO command character	!
!	and controls some action the squisher takes when it runs into	!
!	that TECO command.  For example, if the squisher runs into	!
!	<NUL>, the squisher uses the first character in the 9.str mask	!
!	as a label to goto which handles <NUL>'s.  The mask characters	!
!	are:								!
!									!
!		1	command takes character argument		!
!		A	^A command					!
!		B	delete if line is blank				!
!		D	delete character from output			!
!		E	E command					!
!		F	F command					!
!		L	lowercase char (convert to uppercase)		!
!		O	optionally delete character from output		!
!		T	TAB char					!
!		U	^U command					!
!		V	^^ command, leave next char as is		!
!		Z	^Z command, convert to <CARET>-Z		!
!		^	(caret) next char is really CTRL-char		!
!		$	command takes string argument(s)		!
!		.	(dot) pass character through w/o squishing	!
!		@	the next command is '@' modified		!
!									!
! Changes:								!
!									!
!	Nov-89								!
!	added comments							!
! 	changed system specific "n,Stext$" to generic "m,nFBtext$"	!
! --------------------------------------------------------------------- !

! --------------------------------------------------------------------- !
! Load Q-register F with SQU initialization macro.  This macro loads	!
! other macros into various Q-registers and handles the command	line	!
! switches:   either taking them from the command line in the edit	!
! buffer or prompting the user for them.  When this macro is done,  	!
! SQU will be poised to run and the only thing left in the edit buffer	!
! will be the input and output filenames.				!
! --------------------------------------------------------------------- !

^UF			! F.str = initialization macro			!
^D			! set radix to decimal				!
0ED			! zero edit mode flag				!
0^X			! zero search mode flag				!
ET&128"N		! if abort-on-error bit is not zero		!
	0,0XP		!   clear P.str					!
'			! endif						!
0,128ET			! turn on abort-on-error bit			!
J			! jump to beginning of edit buffer		!
< @FS%^ES%%; >		! zap multiple spaces and tabs in edit buffer	!
J			! jump to beginning of edit buffer		!
:@S%/%			! search for '/' command line switch delimiter	!
UB			! put search success into B.num			!
QB"T			! if there are switches				!
	ET&64"E		!   if not detached				!
		@^A%
%			!     display <CR><LF>				!
	'		!   endif					!
'			! endif						!

! --------------------------------------------------------------------- !
! Load Q-register R with a "get-response-from-user" macro.		!
!									!
! Entry:								!
!	The last inserted string is the display prompt.			!
!									!
!	The top of the stack is the Q-register name we will return	!
!	the response in.  If the high bit of the Q-register name	!
!	is set, insist on ESC to terminate the response, otherwise	!
!	allow the response to be terminated with CR-LF .		!
!									!
! Returns:								!
!	Input string in the Q-register you specified on entry.		!
! --------------------------------------------------------------------- !

@^UR\			! R.str = response macro 			!
[0 [1 [2 [3		! save Q-reg's 0 through 3			!
+0U3			! 3.num = Q-reg name on top of stack		!
^YX0			! 0.str = display prompt (last inserted string)	!
^YK			! kill display prompt from edit buffer		!
.U1			! 1.num = current buf ptr			!
ZJ			! jump to buf end				!
.U2			! 2.num = current end of buffer			!
Q3&127"R		! if Q-reg name in 3.num is alphanumeric	!
			!   it's a valid Q-reg name			!
|			! else (Q-reg name not alphanumeric)		!
			!   it's not a valid Q-reg name			!
	@^A%?Invalid Q-register in INPLIN
%			!   display error message			!
	@O!EXIT!	!   go down to EXIT				!
'

! --------------------------------------------------------------------- !
! build a mini-macro in Q-reg 1 which will put the user's response	!
! into the Q-reg we are using to return the user's response in.		!
! --------------------------------------------------------------------- !

@I%Q2,.X%		! insert "Q2,.X" into edit buffer		!
Q3&127@I%%		! insert Q-reg name we're loading response in	!
Q2,.X1			! put this mini-macro into 1.str		!
Q2,.K			! and kill it					!

! --------------------------------------------------------------------- !
! display the prompt on a new, clean, line				!
! --------------------------------------------------------------------- !

!PROMPT!

13^T			! display <CR>					!
ET&512"N		! if scope, clear to end of screen		!
	0,1ET		!   inhibit type-out conversions		!
	27^T		!   display ESCAPE				!
	1,0ET		!   enable type-out conversions			!
	0:W-4"E		!   if VT100 in ANSI mode			!
		^^[^T	!     display [					!
	'		!   endif					!
	^^J^T		!   display J					!
|			! else (not scope)				!
	10^T		!   display <LF>				!
'			! endif						!
.-Q2+(0^Q)"G		! if anything on current line			!
	0T		!   display it					!
|			! else						!
	:G0		!   display prompt in 0.str			!
	Q2,ZT		!   plus what we've entered so far		!
'			! endif						!

! --------------------------------------------------------------------- !
! Read characters from the console & insert them into the edit buffer.	!
!									!
!	DEL			delete last char entered		!
!	^U			delete everything entered		!
!	^R			redisplay prompt & what's been entered	!
!	^Z			delete everything entered and return	!
!	<CR>, <LF>, <ESC>	terminate input				!
! --------------------------------------------------------------------- !

!GETCH!

^TU0			! get char from console & put in 0.num		!
Q0-127"E		! if char is DEL				!
	Z-Q2"N		!   if anything has been added to buffer	!
		-D	!     delete last char				!
	'		!   endif					!
	@O!PROMPT!	!   go up to PROMPT				!
'			! endif						!
Q0-21"E			! if char is ^U					!
	Q2,ZK		!   kill everything we've entered up to now	!
	@O!PROMPT!	!   go up to PROMPT				!
'			! endif						!
Q0-18"E			! if char is ^R					!
	13^T		!   display <CR>				!
	10^T		!   display <LF>				!
	:G0		!   display prompt in 0.str			!
	Q2,ZT		!   display everything we've entered up to now	!
	@O!GETCH!	!   go up to GETCH				!
'			! endif						!
Q0-26"E			! if char is ^Z					!
	Q2,ZK		!   kill everything we've entered up to now	!
	%0^[		!   convert ^Z (1Ah) to <ESC> (1Bh)		!
'			! endif						!
Q0-27"E			! if char is <ESC>				!
	13^T		!   display <CR>				!
	10^T		!   display <LF>				!
	@O!DONE!	!   go down to DONE				!
'			! endif						!
Q3&128"E		! if hi-bit of return Q-reg name is zero	!
	Q0-10"E		!   if char is <LF>				!
		13^T	!     display <CR>				!
		@O!DONE! !    go down to DONE				!
	'		!   endif					!
	Q0-13"E		!   if char is <CR>				!
		^T^[	!      suck up <LF> of <CR>-<LF> pair?		!
		@O!DONE! !     go down to DONE				!
	'		!   endif					!
'			! endif						!
Q0@I%%			! insert input char into edit buffer		!
@O!GETCH!		! go up to GETCH to get next character		!

!DONE!

M1			! execute mini-macro to load Q-reg w/response	!
Q2,.K			! kill everything we added to the input buffer	!

!EXIT!

Q1J			! jump back to where we were before we started	!
]3 ]2 ]1 ]0		! restore Q-reg's 0 through 3			!
\			! end of ^UR					!

! --------------------------------------------------------------------- !
! Done loading response macro into Q-register R				!
! --------------------------------------------------------------------- !

! --------------------------------------------------------------------- !
! Check for command line switches.  Basically, each switch is searched	!
! for in the edit buffer:						!
!									!
!	If the switch is not found					!
!		If there were other switches on the command line	!
!			Set the switch to its default value		!
!		else							!
!			Prompt the user for the value of the switch	!
!	else								!
!		If switch followed by ":argument"			!
!			Set switch to "argument"			!
!		else							!
!			Set switch to the opposite of its default	!
!									!
! While we are checking for switches, we will be building the mask in	!
! Q-register 9								!
! --------------------------------------------------------------------- !

! --------------------------------------------------------------------- !
! Check for /D "Delete CR/LF" switch.  /D will delete all lexical CR's	!
! and LF's.  /D:N is the default.  The format for the /D switch is:	!
! /D:Y or /D:N.  /D just by itself is the same as /D:Y.			!
!									!
! A problem with /D:Y is that the output will probably be all on one	!
! line.  If you want to delete all CR's and LF's, yet keep the output	!
! width manageable, use /L:nn.						!
! --------------------------------------------------------------------- !

0,0X9					! clear mask in 9.str		!
J					! jump to beginning of buffer	!
:@FS%/D%%"S				! if "/D" found			!
	::@FS%:%%"S			!   if ":arg" found		!
		0A@^UQ%%		!     Q.str = arg		!
		D			!     delete arg		!
	|				!   else (":" not found)	!
		@^UQ%Y%			!     Q.str = "Y"		! 
	'				!   endif			!
|					! else ("/D" not found)		!
	QB"T				!   if any other switches	!
		@^UQ%%			!      Q.str = ""		!
	|				!   else			!
		@I%Delete CR/LF (Y/N) <N>? %
		^^QMR			!     ask for /D value		!
	'				!   endif			!
'					! endif				!
0QQ"A					! if /D val is alphabetic	!
	0QQ&95-^^Y"E			!   if it's 'y' or 'Y'		!

		! load 9.str with labels for control chars, with <LF>,	!
		! <CR>, and <SP> marked as D.				!
		!							!
		!   %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ %			!
		@^U9%DA.......TD..D.......U....Z...V.D%

	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /L	"Set line lengths" switch.  If you're not explicitly	!
! deleting all CR/LF's (ie: /D:N), you can still delete CR/LF's which	!
! are unecessary yet still keep the width of the output line manageable.!
! The format of the /L switch is: /L, /L:Y, /L:N, or /L:nn where nn is	!
! the line length.  /L just by itself is the same as /L:Y, and /L:Y is	!
! the same as /L:70.   If /D is Y then any /L is ignored.		!
!									!
! Note: the /L switch does delete all lexical CR/LF's; but, after	!
! everything is squished, goes back and inserts CR/LF wherever needed	!
! so the maximum width of the output line doesn't exceed nn chars.	!
! --------------------------------------------------------------------- !

!BADNUM!				! label to re-ask if :nn bad	!
0UO					! clear O.num			!
:Q9"N					! if we had /D:Y above		!
	J				!   jump to beginning of buf	!
	:@FS%/L%%"S			!   if "/L" found, delete it	!
		@^A"%/L specified with /D, /L ignored
"					!     and warn the user 	!
		::@FS%:%%"S		!     if ":arg" found, kill ":"	!
			0A"D		!       if arg is numeric	!
				< D .-Z; 0A"D > '	! delete nn	!
			|		!       else			!
				D	!         delete arg		!
			'		!       endif			!
		'			!     endif			!
	'				!   endif			!
|					! else (no /D:Y above)		!
	J				!   jump to beginning of buf	!
	:@FS%/L%%"S			!   if "/L" found		!
		::@FS%:%%"S		!     if ":arg" found		!
			0A@^UQ%%	!       Q.str = arg		!
			0A"D		!       if arg is numeric	!
				< D .-Z; 0A"D 0A:@^UQ%% > ' ! get nn	!
			|		!       else			!
				D	!         delete arg		!
			'		!       endif			!
		|			!     else, just /L		!
			@^UQ%Y%		!       Q.str = "Y"		!
		'			!     endif			!
	|				!   else			!
		QB"T			!     if any other switches	!
			@^UQ%%		!       Q.str = ""		!
		|			!     else			!
			@I%Set line lengths (Y for 70, N, or length) <N>? %
			^^QMR		!       ask for /L value	!
		'			!     endif			!
	'				!   endif			!
	0QQ"A				!   if /L val is alphabetic	!
		0QQ&95-^^Y"E		!     if it's 'y' or 'Y'	!

			! load 9.str with labels for control chars,	!
			! with <LF>, <CR>, and <SP> marked as O.	!
			!						!
			!   %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ %		!
			@^U9%DA.......TO..O.......U....Z...V.O%

			70UO		!       set line length to 70	!
		'			!     endif			!
	'				!   endif			!
	0QQ"D				!   if /L val is numeric	!
		.UQ			!     save current buf ptr	!
		ZJ			!     jump to buf end		!
		GQ			!     put /L str in buffer	!
		^SC			!     go back to /L str begin	!
		\UO			!     put str value in O.num	!
		^SD			!     and delete str		!
		.-Z"N			!     if anything left over	!
			ZK		!        kill chars \ skipped	!
			QQJ		!        jump back to old cp	!
			@O!BADNUM!	!        bad number		!
		'			!      endif			!
		QQJ			!      jump back to old cp	!
		QO"E			!      if /L arg is 0		!
			@O!BADNUM!	!        bad number		!
		'			!      endif			!

		! load 9.str with labels for control chars, with <LF>,	!
		! <CR>, and <SP> marked as O.				!
		!							!
		!   %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ %			!
		@^U9%DA.......TO..O.......U....Z...V.O%

	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /B "Delete blank lines" switch				!
! --------------------------------------------------------------------- !

:Q9"N					! if we had /D:Y above		!
	J				!   jump to beginning of buf	!
	:@FS%/B%%"S			!   if "/B" found		!
		::@FS%:%%"S		!     if ":arg" found		!
			0A-^^N"E	!       if "/B:N", ignore it	!
				@^A"%/B:N specified with /D or /L, /B:N ignored
"					!         warn user		!
			'		!       endif			!
			D		!       delete arg		!
		'			!     endif			!
	'				!   endif			!
|					! else	(no /D:Y above)		!
	J				!   jump to beginning of buf	!
	:@FS%/B%%"S			!   if "/B" found		!
		::@FS%:%%"S		!     if ":arg" found		!
			0A@^UQ%%	!        Q.str = arg		!
			D		!        delete arg		!
		|			!     else			!
			@^UQ%Y%		!        Q.str = "Y"		!
		'			!     endif			!
	|				!   else			!
		QB"T			!     if any other switches	!
			@^UQ%%		!        Q.str = ""		!
		|			!     else			!
			@I%Delete blank lines (Y/N) <N>? %
			^^QMR		!       ask for /B value	!
		'			!     endif			!
	'				!   endif			!
	0QQ"A				!   if /B val is alphabetic	!
		0QQ&95-^^Y"E		!     if it's 'y' or 'Y'	!

			! load 9.str with labels for control chars,	!
			! with <LF> marked as B and <SP> marked as D.	!
			!						!
			!   %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ %		!
			@^U9%DA.......TB..........U....Z...V.D%

		'			!     endif			!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! at this point, if we've specified /D, /L, or /B above, 9.str should	!
! hold the labels for the control characters, if it doesn't, we'll	!
! supply the default labels which only deletes <NUL> and <SP>.		!
!									!
! Note:  we only have entries for <NUL> to <SP> here.  The entry for	!
! exclamation point will be put in by the /C checking code below.  All	!
! other entries are appended to 9.str after switch parsing is finished.	!
! --------------------------------------------------------------------- !

:Q9"E					! if 9.str is empty		!
	!   %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ %				!
	@^U9%DA.......T...........U....Z...V.D%	! load default mask	!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /T "Delete lexical TABs and FFs" switch.  The format of	!
! the /T switch is: /T, /T:Y, /T:N.  /T by itself is the same as /T:Y.	!
! If TABs are used to format the macro to be squished, instead of being !
! used to start an insert, you'll have to delete them using /T:Y	!
! --------------------------------------------------------------------- !

J					! jump to beginning of buffer	!
:@FS%/T%%"S				! if "/T" found			!
	::@FS%:%%"S			!   if ":arg" found		!
		0A@^UQ%%		!     Q.str = arg		!
		D			!     delete arg		!
	|				!   else			!
		@^UQ%Y%			!     Q.str = "Y"		!
	'				!   endif			!
|					! else				!
	QB"T				!   if any other switches	!
		@^UQ%%			!     Q.str = ""		!
	|				!   else             		!
		@I%Delete lexical TABs and FORM FEEDs (Y/N) <N>? %
		^^QMR			!     ask for /T value		!
	'				!   endif			!
'					! endif				!
0QQ"A					! if /T val is alphabetic	!
	0QQ&95@^UQ%%			!   force it to uppercase	!
'					! endif				!

! --------------------------------------------------------------------- !
! if /T is "Y", the following code takes the existing control char	!
! mask in Q-reg 9 and replaces the TAB and FF entries with "O".  The	!
! new control char mask is then put back in Q-reg 9.			!
! --------------------------------------------------------------------- !

0QQ-^^Y"E				! if /T is 'Y'			!
	J				!  jump to beginning of buffer	!
	G9				!  load mask into edit buffer	!
	9J				!  jump to TAB entry		!
	D				!  delete existing entry	!
	@I%O%				!  insert "O"			!
	12J				!  jump to FF entry		!
	D				!  delete existing entry	!
	@I%O%				!  insert "O"			!
	J				!  jump to beginning of buffer	!
	0,33X9				!  put mask back in 9.str	!
	0,33K				!  and clean up edit buffer	!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /C "Delete comments" switch.  This switch deletes comments	!
! as opposed to labels.  It is easier if comments are distinguishable	!
! from labels by having a special delimiting character immediately	!
! following the initial exclamation point.  The format of the /C	!
! switch is:  /C, /C:Y, /C:N, or /C:? where ? is the special comment	!
! delimiting character.  /C is the same as /C:Y, and /C:Y implies that	!
! SPACE and TAB are the special comment delimiters.  When done, Q-reg	!
! C will contain the special comment delimiting characters.		!
! --------------------------------------------------------------------- !

@^UC%%					! C.str = ""			!
J					! jump to beginning of buffer	!
:@FS%/C%%"S				! if "/C" found			!
	::@FS%:%%"S			!   if ":arg" found		!
		0A@^UQ%%		!     Q.str = arg		!
		D			!     delete arg		!
	|				!   else			!
		@^UQ%Y%			!     Q.str = "Y"		!
	'				!   endif			!
|					! else				!
	QB"T				!   if any other switches	!
		@^UQ%%			!     Q.str = ""		!
	|				!   else			!
		@I%Delete comments (Y for SP/TAB, N, or set) <N>? %
		^^QMR			!     ask for /C value		!
	'				!    endif			!
'					! endif				!
:QQ"E					! if Q.str empty		!
	@^UQ%N%				!   Q.str = "N"			!
'					! endif				!
0QQUQ					! Q.num = ASCII 1st Q.str char	!
QQ"V					! if Q.num lowercase		!
	QQ-32UQ				!   force it to uppercase	!
'					! endif				!
QQ-^^N"E				! if /C == "N"			!
	:@^U9%A%			!   append "A" to 9.str mask	!
|					! else				!
	:@^U9%C%			!   append "C" to 9.str mask	!
	QQ-^^Y"E			!   if /C == "Y"		!
		32@^UC%%		!     C.str = <SP>		!
		9:@^UC%%		!     append TAB to C.str	!
	|				!   else (it's a set?)		!
		GQ			!     put /C set in edit buf	!
		^YXC			!     load it into Q-reg C	!
		^YK			!     clean up edit buffer	!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! append entries for all other TECO commands to the mask in Q-reg 9.	!
! --------------------------------------------------------------------- !

!    %"#$%&'()*+,-./0123456789:;<=>?%			!
:@^U9%1..1..........................%

!    %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_%			!
:@^U9%@....EF1.$...1$$.1.$.1..1..1.1^$%

!    %`abcdefghijklmnopqrstuvwxyz{|}<tilde><sp>%	!
:@^U9%.LLLLLLLLLLLLLLLLLLLLLLLLLL....D%

! --------------------------------------------------------------------- !
! Load Q-register 8 with potential <delim> characters in case ESC can't	!
! be used.  We initially load 8.str with the preferred delimiters:	!
!									!
!	/ # * & \ ? ( ) $ <exclamation pt> @				!
!									!
! in case these can't be used either, we'll also append every ASCII	!
! character to 8.str in the hope that something can be used.		!
! --------------------------------------------------------------------- !

@^U8%/#*&\?()$!@%			! pre-load 8.str		!
1U8					! put 1 in 8.num		!
126<					! this loop appends ASCII chars	!
	Q8:@^U8%% %8^[			! CTRL-A to TILDE to 8.str	!
   >

! --------------------------------------------------------------------- !
! Check for /W "Watch progress" switch					!
! --------------------------------------------------------------------- !

@^UW%%					! clear W.str			!
ET&512"E				! if not scope, ignore /W	!
	J				!   jump to beginning of buf	!
	:@FS%/W%%"S			!   if "/W" found, delete it	!
		::@FS%:%%"S		!     if ":" found		!
			D		!       delete arg		!
		'			!     endif			!
	'				!   endif			!
|					! else (it's a scope)		!
	J				!   jump to beginning of buf	!
	:@FS%/W%%"S			!   if "/W" found		!
		::@FS%:%%"S		!     if ":arg" found		!
			0A@^UQ%%	!       Q.str = arg		!
			D		!       delete arg		!
		|			!     else			!
			@^UQ%Y%		!       Q.str = "Y"		!
		'			!     endif			!
	|				!   else			!
		QB"T			!     if any other switches	!
			@^UQ%%		!       Q.str = ""		!
		|			!     else			!
			@I%Watch progress (Y/N) <N>? %
			^^QMR		!       ask for /W value	!
		'			!     endif			!
	'				!   endif			!
	0QQ"A				!   if /W val is alphabetic	!
		0QQ&95-^^Y"E		!     if it's 'y' or 'Y'	!
			0:W-2"E		!       if VT100 in VT52 mode	!
				4,0:W^[	!         set VT100 in ANSI	!
			'		!       endif			!
			@^UW/-1W/	!       Q.str = "-1W" (refresh)	!
		'			!     endif			!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /A "Automatic mode".  If /A:Y, then if @^U%text% is found,	!
! "text" is assumed to something which should *not* be sub-squished;	!
! any other character used as a special <delim> *will* be sub-squished.	!
! If /A:N, then go into "manual mode" where each time SQU runs into	!
! ^Utext, it will ask if you want to sub-squish it.  If /A:<char> is	!
! a command line switch then use <char> as the "non-squishable" <delim>	!
! char.  If you're asked for the /A value, then you can enter a set of	!
! "non-squishable" <delim> chars.					!
! --------------------------------------------------------------------- !

@^UK%%					! clear K.str			!
J					! jump to beginning of buffer	!
:@FS%/A%%"S				! if "/A" found			!
	::@FS%:%%"S			!   if ":arg" found		!
		0A@^UQ%%		!     Q.str = arg		!
		D			!     delete arg		!
	|				!   else			!
		@^UQ%Y%			!     Q.str = "Y"		!
	'				!   endif			!
|					! else				!
	QB"T				!   if any other switches	!
		@^UQ%Y%			!     Q.str = "Y"		!
	|				!   else			!
		@I/Automatic mode (Y for %, N, or set) <N>? /
		^^QMR			!     ask for /A value		!
	'				!   endif			!
'					! endif				!
:QQ"N					! if any /A val			!
	0QQUQ				!   convert /A val to ASCII 	!
	QQ"V				!   if /A val lowercase		!
		QQ-32UQ			!     force to uppercase	!
	'				!   endif			!
	QQ-^^N"N			!   if /A not "N"		!
		QQ-^^Y"E		!     if /A == "Y"		!
			^^%@^UK%%	!       K.str = "%"		!
		|			!     else (it's a set?)	!
			GQ		!       put /A set in edit buf	!
			^YXK		!	 load it into K.str	!
			^YK		!       clean up edit buffer	!
		'			!     endif			!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! Check for /E "Allow adjacent ESCapes" switch.  Sometimes squishing	!
! will put two escapes together where there weren't two escapes before.	!
! For example, @FS/abc// will be squished to @FSabc$$, the two adjacent	!
! escapes could be a problem this is in a macro which is EI'd.  The	!
! format of the /E switch is: /E, /E:N, or /E:Y.  /E is the same as	!
! /E:Y.  /E:N will direct SQU to never generate adjacent escapes where	!
! there were none before.						!
! --------------------------------------------------------------------- !

0UH					! H.num = 0 (FALSE)		!
J					! jump to beginning of buffer	!
:@FS%/E%%"S				! if "/E" found			!
	::@FS%:%%"S			!   if ":" found		!
		0A@^UQ%%		!     Q.str = arg		!
		D			!     delete arg		!
	|				!   else			!
		@^UQ%Y%			!     Q.str = "Y"		!
	'				!   endif			!
|					! else				!
	QB"T				!   if any other switches	!
		@^UQ%%			!     Q.str = ""		!
	|				!   else			!
		@I%Allow adjacent ESCapes (Y/N) <N>? %
		^^QMR			!     ask for /E value		!
	'				!   endif			!
'					! endif				!
0QQ"A					! if /E val is alphabetic	!
	0QQ&95-^^Y"E			!   if it's 'y' or 'Y'		!
		-1UH			!     H.num = -1 (TRUE)		!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! Load Q-register Z with the squisher macro				!
!									!
! Uses Q-register 1 for @-modified flag while processing and for	!
! an error return when through.						!
! --------------------------------------------------------------------- !

@^UZ*					! Z.str = squish macro		!
[1					! save Q-reg 1			!
0U1					! clear @-modifed flag		!
:QW"N					! if /W was TRUE		!
	-1,3:W^[			!   turn on SEEALL mode		!
	0,4:W^[				!   set no "mark" status	!
	0,5:W^[				!   turn hold mode off		!
'					! endif				!

! --------------------------------------------------------------------- !
! main loop start							!
! --------------------------------------------------------------------- !

<
!..!

MW					! refresh scope			!

!.!

ME;					! break if E macro returns 0	!

0AU0					! 0.num = char in buffer	!
Q0"L					! if char is less than zero	!
	@O!OFFEND!			!   end of file err		!
'					! endif				!
C					! advance one character		!
Q0&128"N				! if char's hi bit is set	!
	Q0&127U0			!   zero hi bit			!
	-D				!   delete hi bit char		!
	Q0@I%%				!   insert zero hi bit char	!
'					! endif				!

! --------------------------------------------------------------------- !
! Use the ASCII value of the current char in 0.num as an index into the	!
! labels in 9.str, and goto that label.					!
! --------------------------------------------------------------------- !

!DISP!					! dispatch			!
Q0Q9@^U0%%				! 0.str = Q0th char of 9.str	!
@O!^EQ0!				! and jump to it		!

! --------------------------------------------------------------------- !
! handle a lowercase character.  convert it to uppercase and process	!
! it again.								!
! --------------------------------------------------------------------- !

!L!

Q0-32U0					! convert to uppercase		! 
-D					! delete lowercase char		!
Q0@I%%					! insert uppercase char		!
@O!DISP!				! try label for uppercase char	!

! --------------------------------------------------------------------- !
! handle '^'.  the next character is really CTRL-char.  we'll delete	!
! the "^char" construct, insert the "real" control char, and go back	!
! and process it again.  we'll watch out for inserting ^[ (<ESC>), we	!
! have to be careful about creating adjacent <ESC>'s.			!
! --------------------------------------------------------------------- !

!^!

0A&31U0					! 0.num = ^char			!
C					! skip past char		!
-2D					! delete both ^ and char	!
QH"F					! if no adjacent ESC's 		!
	Q0-27"E				!   if ^char is ESC		!
		0A-27"E			!     if next char is ESC	!
			@I%^[%		!       insert a single ESC	!
			C		!       skip past next ESC	!
			@O!..!		!       jump to main loop	!
		'			!     endif			!
		! ----------------------------------------------------- !
		! at this point we are trying to insert an ESC; but we	!
		! don't know if by doing so we will inadvertently form	!
		! two adjacent escapes.  the following code searches	!
		! backwards for the last important character (skipping	!
		! CF/LF's) to see if that last important character was	!
		! also an ESC.  if it was, we'll insert a <SP> to keep	!
		! the two ESC's lexically apart.			!
		! ----------------------------------------------------- !
		.US			!     S.num = cur buf ptr	!
		0UT			!     T.num = 0			!
		<			! ----loop begin--------------- !
			-.;		!       break if .==0		!
			R		!       back up one char	!
			0AUT		!       T.num = previous char	!
			QT&128"E	!       if hi bit of char zero	!
				QT-10"N		! if char is not <LF>	!
					0;	!   break out of loop	!
				|		! else (it is <LF>)	!
					-.;	!   break if .==0	!
					-1A-128-13"N ! if not <CR><LF>	!
						0;  ! break out of loop !
					'	!   endif		!
				'		! endif			!
			'		!       endif			!
		>			! ----loop end----------------- !
		QSJ			!       jump to where we startd !
		QT-27"E			!       if last char == ESC	!
			@I% %		!         insert <SP>		!
		'			!       endif			!
	'				!     endif			!
'					!   endif			!
Q0@I%%					! insert ^char			!
@O!DISP!				! try again			!

! --------------------------------------------------------------------- !
! handle 'B'.  we've run into the <LF> portion of CR/LF with the /B	!
! switch (delete blank lines) set.  if there are only two chars on the	!
! current line, assume they are CR/LF and delete them.			!
! --------------------------------------------------------------------- !

!B!

-1^Q+2"E				! if only 2 chars on this line	!
	-2D				!   delete <CR><LF>		!
'					! endif				!
@O!..!					! jump to main loop		!

! --------------------------------------------------------------------- !
! handle 'O'.  we've run into <LF>, <CR>, or <LF> with the /L switch	!
! set.						 			!
! --------------------------------------------------------------------- !

!O!

-D					! delete last char		!
."N					! if not at beginning of buffer	!
	-1A&128"N			!   if last char hi bit set	!
		-D			!     delete it			!
	'				!   endif			!
	.-1"G				!   if 2 chars past buf begin	!
		-1A-10"E		!     if hi bi of last char set	!
			-2A-128-13"E    !       if 2nd last char = <CR>	!
				Q0-13"E	!         if curr char is <CR>  !
					-2D !       delete <CR><CR>	!
				|	!         else			!
					@O!..! !    jump to main loop	!
				'	!         endif			!
			'		!       endif			!
		'			!     endif			!
	'				!   endif			!
	Q0#128@I%%			!   insert char w/hi bit	!
	Q0-13"E				!   if char is <CR>		!
		.-Z"E			!     if at end of buffer	!
			10@I%%		!       insert <LF>		!
			R		!       back up one char	!
		'			!     endif			!
		0A&127-10"E		!     if curr char is <LF>	!
			D		!       delete it		!
		'			!     endif			!
		10@I%%			!   insert <LF>			!
	'				!   endif			!
'					! endif				!
@O!..!					! jump to main loop		!

! --------------------------------------------------------------------- !
! handle 'U'.  we've run into ^Uq.  usually, the string ^Uq is loading	!
! into Q-register q is *not* squished.  the problem with ^Uq is that it	!
! is sometimes used to load a macro into a Q-register.  This macro code	!
! should be squished too.  What we do is if the ^U is @-modified, and	!
! the <delim> is *not* in the "non-squishible ^U command" character set	!
! in Q-register K, we assume it is a macro and should be sub-squished.	!
! Otherwise, the ^U argument is assumed to be a simple string and is	!
! not sub-squished.							!
! --------------------------------------------------------------------- !

!U!

27@^U1%%				! 1.str = ESC (default delim)	!
.UC					! C.num = current buf ptr	!
0AU0					! 0.num = ^U Q-reg name		!
C					! advance past Q-reg name	!
Q0-^^."E				! if it's .q (local Q-reg name)	!
	0AU0				!   0.num = "real" Q-reg name	!
	C				!   advance past "."		!
'					! endif				!
Q0"V					! if Q-reg name is lowercase	!
	Q0-32U0				!   convert it to uppercase	!
	-D				!   delete lowercase char	!
	Q0@I%%				!   insert uppercase char	!
'					! endif				!
Q1"T					! if @-modified			!
	0A-(1A)"E			!   if @^Uq<delim>text<delim>	!
		@O!$$!			!     goto $$			!
	'				!   endif			!
|					! else				!
	0A-27"E				!   if ^Uq<ESC>			!
		@O!$$!			!     goto $$			!
	'				!   endif			!
'					! endif				!
.US					! S.num = current buf ptr	!
Q1"T					! if @-modifed			!
	0A@^U1%%			!   1.str = <delim>		!
	D				!   delete <delim>		!
'					! endif				!
:QW"N					! if /W was TRUE		!
	:@S%^EQ1%"U			!   if search for <delim> fails !
		@O!STRINGFAIL!		!     unterminated string	!
	'				!   endif			!
	.,4:W^[				!   set mark status		!
	QSJ				!   jump back to where we were	!
	MW				!   refresh scope		!
'					! endif				!

! --------------------------------------------------------------------- !
! if there are no "non-squishable ^U command" characters, you used the	!
! /A:N switch.  If this is the case, we'll have to drop into "manual"	!
! mode:  everytime we run into a ^U we'll ask if you want to squish it	!
! or not, Y or N.							!
! --------------------------------------------------------------------- !

:QK"E					! if no non-squishable ^U delim	!
	:QW"E				!   if /W was FALSE		!
		0T			!     display line up to now	!
		10^T			!     display <LF>		!
		T			!     display rest of line	!
	'				!   endif			!
	7^T				!   display <BEL>		!
	ETUQ				!   save ET flags in Q.num	!
	ET#8#4-4ET			!   turn on read w/o echo	!
	^TU0				!   read char into 0.num	!
	QQET				!   restore ET flags		!
|					! else (non-squishable delims)	!
	G1				!   put <delim> in buf		!
	R				!   back up one char		!
	::@S%^EGK%"S			!   if <delim> is non-squish	!
		-D			!     delete <delim>		!
			^^NU0		!     0.num = N			!
	|				!   else			!
		D			!     delete <delim>		!
		^^YU0			!     0.num = Y			!
	'				!   endif			!
'					! endif				!
:QW"N					! if /W was TRUE		!
	0,4:W^[				!   clear "mark" status		!
	32768W				!   set huge # of display lines	!
'					! endif				!

! --------------------------------------------------------------------- !
! at this point, 0.num will be "Y" if we are to sub-squish the ^U text	!
! --------------------------------------------------------------------- !

Q0-^^Y"E				! if 0.num is Y			!
	! ------------------------------------------------------------- !
	! Q-register E originally holds ".-Z" (-number of chars until	!
	! end of the buffer, when zero we're at end of buf).  The E	!
	! macro is executed at the top of the squish loop so we break	!
	! out of the squish loop when we reach the end of the buf. When	!
	! we recursively sub-squish a ^U string, we want the squish	!
	! loop to break out when it reaches the end of the ^U string.	!
	! Therefore, we'll now load Q-register E with a macro to do so.	!
	!								!
	!	-1UE			E.num == -1 (continue flag)	!
	!	0A-^^<delim>"E		if we've run into <delim>	!
	!		0UE		  E.num == 0 (break flag)	!
	!	'			endif				!
	!	QE			push -1 or 0 on stack		!
	! ------------------------------------------------------------- !
	[E [C [S			!   save Q-reg's E, C, & S	!
	@^UE%-1UE0A-^^%			!   load Q-reg E w/macro start	!
	0Q1:@^UE%%			!   append <delim> to Q-reg E	!
	:@^UE%"E0UE'QE%			!   append macro end to Q-reg E	!
	MZ				!   squish recursively		!
	]S ]C ]E			!   restore Q-reg's C, S & E	!
	"N				!   if recursive MZ failed	!
		@O!PRIORFAIL!		!     announce it		!
	'				!   endif			!
	C				!   advance past end ^U delim	!
	@O!$$$$!			!   goto $$$$			!
'					! endif				!
@O!$$$!					! goto $$$			!

! --------------------------------------------------------------------- !
! handle 'T'.  we've run into a TAB character, start an insert.		!
! --------------------------------------------------------------------- !

!T!

0U1					! clear @-modified flag		!

! --------------------------------------------------------------------- !
! handle '$'.  we've run into I, N, O, or S: commands which take a	!
! single string argument (ie: commands which contain one <delim>).	!
! --------------------------------------------------------------------- !

!$!

27@^U1%%				! 1.str = ESC (default delim)	!
.UC					! C.num = current buf ptr	!

! --------------------------------------------------------------------- !
! $$, entry point for commands which take two string arguments (ie:	!
! commands which contain two <delim>'s).				!
! --------------------------------------------------------------------- !

!$$!

.US					! S.num = start of text		!
Q1"T					! if @-modified			!
	0A@^U1%%			!   1.str = <delim>		!
	D				!   delete <delim>		!
'					! endif				!

! --------------------------------------------------------------------- !
! $$$, entry point for the ^U routine when we are not sub-squishing the !
! ^U argument, but we've already handled being @-modified.		!
! --------------------------------------------------------------------- !

!$$$!

:@S%^EQ1%"U				! if search for <delim> fails	!
	@O!STRINGFAIL!			!   unterminated string		!
'					! endif				!

! --------------------------------------------------------------------- !
! $$$$, entry point for the ^U routine after we've sub-squished a ^U	!
! macro.								!
! --------------------------------------------------------------------- !

!$$$$!

-D					! delete trailing <delim>	!
.UT					! T.num = end of text		!
27U0					! 0.num = ESC (default <delim>	!

! --------------------------------------------------------------------- !
! At this point, we have to output a delimited string.			!
!									!
!	0.num = <delim>							!
!	C.num = start of command					!
!	S.num = start of text						!
!	T.num = end of text						!
!									!
! --------------------------------------------------------------------- !

!AA!

Q0@^U0%%				! 0.str = <delim> char		!
QT-QS"G					! if string is not-empty	!
	QSJ				!   jump to start of string	!
	.,.+QT-QS:@FB%^EQ0%"S		!   if <delim> is in string	!
		! ----------------------------------------------------- !
		! find a <delim> we can use, one which is *not* already !
		! in the string.					!
		! ----------------------------------------------------- !
		G8			!     put 8.str into buf	!
		^Y:X1			!     put 8.str into 1.str	!
		^YK			!     kill 8.str from buf	!
		0U0			!     clear 0.num		!
		<			! ----loop begin---------------	!
			Q0Q1@^U0%%	!       0.str = Q0th char of Q1	!
			QSJ		!       jump to start of text	!
			.,.+QT-QS@FB%^EQ0%; !   break if search fails	!
			%0-:Q8"E	!       if next char last char	!
				@O!NOQUOTE!	! can't find " char	!
			'		!       endif			!
		>			! ----loop end----------------- !
		Q0Q1U0			!     0.num = <delim> to use	!
		QSJ			!     jump to start of string	!
		Q0@I%%			!     insert <delim>		!
		QC-1J			!     jump before command	!
		@I%@%			!     insert @			!
		2%T^[			!     T.num (end of text) += 2	!
		! ----------------------------------------------------- !
	'				!   endif			!
'					! endif				!
QTJ					! jump to end of string		!
Q0@I%%					! insert <delim>		!
0U1					! clear @-modified flag		!
@O!..!					! jump to main loop		!

! --------------------------------------------------------------------- !
! handle '1'.  we've run into ", %, G, M, Q, U, X, [, or ].  For ", the	!
! next character is a conditional execution command.  For everything	!
! else, the next character is a Q-register name.  In either case, if	!
! the next char is lowercase, we uppercase it; otherwise, we fall	!
! through to the 'V' code below which simply advances past the char.	!
! --------------------------------------------------------------------- !

!1!

0A-^^."E				! if it's .q (local Q-reg name)	!
	C				!   advance past "."		!
'					! endif				!
0A"V					! if lowercase			!
	0A-32U0				!   convert to uppercase	!
	D				!   delete lowercase char	!
	Q0@I%%				!   insert uppercase char	!
	@O!.!				!   goto .			!
'					! endif				!
! ... fall through ...!

! --------------------------------------------------------------------- !
! handle 'V'.  we've run into <CTRL>-^, simply skip it			!
! --------------------------------------------------------------------- !

!V!

C					! simply advance past it	!
@O!.!					! goto .			!

! --------------------------------------------------------------------- !
! handle '@'.  the following command is @ modified, set a flag in 1.num	!
! so we know to look for the alternate delimiter characters.		!
!									!
! even though <delim> characters will be specified along with the '@'	!
! command, we'll try to use ESC whenever possible and convert the @	!
! modified command back into a "normally" delimited command.		!
! --------------------------------------------------------------------- !

!@!

-1U1					! set @-modified flag		!
! ...fall through ... !

! --------------------------------------------------------------------- !
! handle 'D'.  delete the character from the output file		!
! --------------------------------------------------------------------- !

!D!

-D					! delete last character		!
@O!.!

! --------------------------------------------------------------------- !
! handle 'F'.  we've run into a F', F<. F>, F|, FB, FC, FD, FK, FN, FR,	!
! FS, or F_ command.							!
! --------------------------------------------------------------------- !

!F!

27@^U1%%				! 1.str = ESC (default delim)	!
.UC					! C.num = current buf ptr	!
0AU0					! 0.num = 2nd command char	!
C					! advance past 2nd cmd char	!
Q0"V					! if 2nd cmd char is lowercase	!
	Q0-32U0				!   convert it to uppercase	!
	-D				!   delete lowercase char	!
	Q0@I%%				!   insert uppercase char	!
'					! endif				!

! --------------------------------------------------------------------- !
! the FB and FR commands take a single string argument, goto $$		!
! the FC, FS, FN, and F_ commands take two string arguments, goto F$$	!
!									!
! ???What about FD and FK taking 1 string argument			!
! --------------------------------------------------------------------- !

Q0-^^B"E				! if it's FB			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^C"E				! if it's FC			!
	@O!F$$!				!   goto F$$			!
'					! endif				!
Q0-^^R"E				! if it's FR			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^S"E				! if it's FS			!
	@O!F$$!				!   goto F$$			!
'					! endif				!
Q0-^^N"E				! if it's FN			!
	@O!F$$!				!   goto F$$			!
'					! endif				!
Q0-^^_"E				! if it's F_			!
	@O!F$$!				!   goto F$$			!
'					! endif				!
@O!.!

! --------------------------------------------------------------------- !
! handle FC, FS, FN, and F_ commands which take two string arguments,	!
! there are three possible formats for these commands:			!
!									!
!	Fx <delim> <delim>						!
!	Fx text <delim> <delim>						!
!	Fx text1 <delim> text2 <delim>					!
!									!
! we first have to find the starting and ending points of the text	!
! arguments.  we set S.num to be the start of text1, we look for the	!
! 1st <delim>, delete it, and set T.num to be the start of text2.  we	!
! then look for the 2nd <delim>, delete it, and set U.num to be the	!
! end of text2.								!
!									!
! if S.num == T.num & T.num == U.num, then we have: FS$$		!
! if S.num <> T.num & T.num == U.num, then we have: FStext$$		!
! if S.num <> T.num & T.num <> U.num, then we have: FStext1$text2	!
! --------------------------------------------------------------------- !

!F$$!

.US					! S.num = start of text1	!
27@^U1%%				! 1.str = ESC (default delim)	!
Q1"T					! if @-modified			!
	0A@^U1%%			!   1.str = <delim>		!
	D				!   delete <delim>		!
'					! endif				!
:@S%^EQ1%"U				! if search for 1st delim fails !
	@O!STRINGFAIL!			!   unterminated string		!
'					! endif				!
-D					! delete 1st <delim>		!
.UT					! T.num = start of text2	!
:@S%^EQ1%"U				! if search for 2nd delim fails	!
	@O!STRINGFAIL!			!   unterminated string		!
'					! endif				!
-D					! delete 2nd <delim>		!
.UU					! U.num = end of text2		!
QH"T					! if allow adjacent escapes	!
	27U0				!   0.num = ESC			!
	Q0@^U0%%			!   0.str = ESC			!
	QU-QS"G				!   if we have text1 & text2	!
		QSJ			!     jump to start of text1	!
		.,.+QU-QS:@FB%^EQ0%"U	!     if search for ESC fails	!
			@O!F0!		!       use ESC as <delim>	!
		'			!     endif			!
	|				!   else (no text arguments)	!
		@O!F0!			!     use ESC as DELIM		!
	'				!   endif			!
|					! else (don't allow adjacent $)	!
	QU-QT"G				!   if we have text2		!
		27U0			!     0.num = ESC		!
		Q0@^U0%%		!     0.str = ESC		!
		QSJ			!     jump to start of text1	!
		.,.+QU-QS:@FB%^EQ0%"U	!     if search for ESC fails	!
			@O!F0!		!       done w/F		!
		'			!     endif			!
	'				!   endif			!
'					! endif				!

! --------------------------------------------------------------------- !
! if we reach this point, there is a danger of putting adjacent ESC's	!
! in the output.  we will try to find a character that's not in the	!
! string we're delimiting and use that as a <delim> character instead	!
! of ESC.  basically, we search "text1text2" looking for each character	!
! in G8, trying to find a delimiter char that's not already in the	!
! string.								!
! --------------------------------------------------------------------- !

G8					! put 8.str into buf		!
^Y:X1					! put 8.str into 1.str		!
^YK					! kill 8.str from buf		!
0U0					! 0.num = 0			!
<					! loop begin------------------- !
	Q0Q1@^U0%%			!   0.str = 0.num'th char of Q1	!
	QSJ				!   jump to start of text1	!
	.,.+QU-QS@FB%^EQ0%;		!   break if 0.str search fails	!
	%0-:Q8"E			!   inc 0.num, if end of 8.str	!
		@O!NOQUOTE!		!     can't find " char		!
	'				!   endif			!
>					! loop end--------------------- !

! --------------------------------------------------------------------- !
! at this point, we've found our <delim> char, it's index is in 0.num	!
! --------------------------------------------------------------------- !

Q0Q1U0					! 0.num = Q0th char of Q1	!
QSJ					! jump to start of text1	!
Q0@I%%					! insert <delim>		!
QC-1J					! jump 1 char before F command	!
@I%@%					! insert @			!
2%T^[					! T.num (end of text1) += 2	!
2%U^[					! U.num (end of text2) += 2	!

!F0!

QTJ					! jump to end of text1		!
Q0@I%%					! insert <delim>		!
QU-QTC					! advance to end of text2	!
Q0@I%%					! insert <delim>		!
0U1					! clear @-modified flag		!
@O!..!					! jump to main loop		!

! --------------------------------------------------------------------- !
! handle 'A'.  we've run into ^Atext^A or @^A/text/.  This is also the	!
! entry point for the 'C' routine:  if we're not deleting the comment	!
! we handle <exclamation-point>comment<exclamation-point> just like     !
! ^Atest^A.                                                             !
! --------------------------------------------------------------------- !

!A!

Q0@^U1%%				! 1.str = ^A or exclamation pt.	!
.UC					! C.num = start of text		!
.US					! S.num = start of text		!
Q1"T					! if @-modified			!
	0A@^U1%%			!   1.str = <delim>		!
	D				!   delete <delim>		!
'					! endif				!
:@S%^EQ1%"U				! if search for <delim> fails	!
	@O!STRINGFAIL!			!   unterminated string		!
'					! endif				!
-D					! delete second <delim>		!
.UT					! T.num = end of text		!
@O!AA!					! goto AA			!

! --------------------------------------------------------------------- !
! handle 'C'.  we've run into an exclamation point with the /C switch	!
! set.  Q-register C contains the special comment delimiter characters. !
! --------------------------------------------------------------------- !

!C!

::@S%^EGC%"U				! if not special comment delim	!
	@O!A!				!   handle like ^Astring^A	!
'					! endif				!
R					! back up past special <delim>	!
.UC					! C.num = current buf ptr	!
Q0@^U1%%				! 1.str = exclamation point	!
Q1"T					! if @-modified			!
	0A@^U1%%			!   1.str = <delim>		!
	D				!   delete <delim>		!
'					! endif				!
:@S%^EQ1%"U				! if search for <delim> failed	!
	@O!STRINGFAIL!			!   unterminated string		!
'					! endif				!
QC-1,.K					! kill entire comment		!
0U1					! clear @-modified flag		!
@O!..!					! jump to main loop		!

! --------------------------------------------------------------------- !
! handle 'E'.  we've run into an E command.                             !
! --------------------------------------------------------------------- !

!E!

27@^U1%%				! 1.str = ESC (default delim)	!
.UC					! C.num = current buf ptr	!
0AU0					! 0.num = 2nd command char	!
C					! advance past 2nd cmd char	!
Q0"V					! if 2nd cmd char is lowercase	!
	Q0-32U0				!   convert to uppercase	!
	-D				!   delete lowercase char	!
	Q0@I%%				!   insert uppercase char	!
'					! endif				!

! --------------------------------------------------------------------- !
! the EB, EG, EI, EN, ER, EW, E_ commands take a string argument, they	!
! have to be passed to the $$ routine.					!
! ???What about EL, EQq, EZ, and E%q taking a string argument		!
! --------------------------------------------------------------------- !

Q0-^^B"E				! if it's EB			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^G"E				! if it's EG			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^I"E				! if it's EI			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^N"E				! if it's EN			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^R"E				! if it's ER			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^W"E				! if it's EW			!
	@O!$$!				!   goto $$			!
'					! endif				!
Q0-^^_"E				! if it's E_			!
	@O!$$!				!   goto $$			!
'					! endif				!
@O!.!

! --------------------------------------------------------------------- !
! handle 'Z'.  we've run into a ^Z, replace it with <CARET>-Z		!
! --------------------------------------------------------------------- !

!Z!

-D					! delete <CTRL>-Z		!
@I%^Z%					! insert <CARET>-Z		!
@O!..!					! jump to main loop		!

>					! main loop end----------------	!

! --------------------------------------------------------------------- !
! At this point, everything should be squished and Q1 will be -1 if	!
! an error occurred, or 0 if everything is OK.				!
! --------------------------------------------------------------------- !

Q1"T					! if error flag			!
	@^U1%Trailing, pending @%	!				!
	@O!ERROR!			!   goto error display		!
'					! endif				!
0U1					! clear Z-macro return value	!

! --------------------------------------------------------------------- !
! the only way the following error reporting code is executed is if we	!
! jump to a label inside of it.  if we arrive here by any other means	!
! then things are OK, skip down to the "endif".				!
! --------------------------------------------------------------------- !

0"N					! skip the following code	!
!OFFEND!
	@^U1%End of buffer while sub-squishing%
	@O!ERROR!

!NOQUOTE!
	@^U1%Can't find a quote character%
	@O!SETPOS!

!PRIORFAIL!
	@^U1%Prior recursion level failed%
	@O!SETPOS!

!STRINGFAIL!
	@^U1%Unterminated string%

! --------------------------------------------------------------------- !
! the following code finishes building an error string in Q-register 1.	!
! 1.str already contains the type of error, this code appends the	!
! position where the error occurred and the line before and after the	!
! error, like so:							!
!									!
!	<error message> from squished .=<error position>		!
!	<line up to error>|						!
!			   |<line after error>				!
!									!
! --------------------------------------------------------------------- !

!SETPOS!
	:@^U1% from squished .=%	!   append msg to 1.str		!
	QC\				!   position in C.num to buf	!
	^Y:X1				!   append position in buf	!
	^YK				!   delete position from buf	!
	13:@^U1%%			!   append <CR>			!
	10:@^U1%%			!   append <LF>			!
	QCJ				!   jump to where error starts	!
	0^Q+.,.:X1			!   append line up to error	!
	^^|:@^U1%%			!   append |			!
	10:@^U1%%			!   append <LF>			!
	^^|:@^U1%%			!   append |			!
	.,^Q+.:X1			!   append rest of line		!

!ERROR!
	ZJ				!  jump to buf end		!
	MW				!  refresh scope		!
	0,0XW				!  clear W.str (/W switch)	!
	7^T				!  sound bell			!
	^^?^T				!  display "?"			!
	:G1				!  display 1.str		!
	7^T				!  sound bell			!
	13^T				!  display <CR>			!
	10^T				!  display <LF>			!
	-1U1				!  set Z-macro return to -1	!
'					! endif				!
Q1					! push Z-macro return val	!
]1					! restore Q-reg 1		!
*					! end of ^UZ			!

! --------------------------------------------------------------------- !
! Done loading squisher macro into Q-register Z				!
! --------------------------------------------------------------------- !

! --------------------------------------------------------------------- !
! Load squish driver macro into Q-register A				!
! --------------------------------------------------------------------- !

@^UA*					! A.str = squish driver macro	!
-1^X					! search flag = exact matches	!
@^UE%.-Z%				! E.str = -# chars to buf end	!
QO"N					! if max line length not 0	!
	ZJ				!   jump buf end		!
	@I% %				!   insert <SP>, insure we halt	!
'					! endif				!
J					! jump to beginning of buffer	!
MZ"E					! if squish macro returns OK	!
	! ------------------------------------------------------------- !
	! at this point, everything is squished; but, if the /L switch	!
	! was set, we've deleted all lexical CR/LF's and have to go	!
	! back and insert CR/LF wherever needed so the line is no	!
	! longer than the width specified with /L:nn.			!
	! ------------------------------------------------------------- !
	QO"N				!   if max line length not 0	!
		:QW"N			!     if /W was TRUE		!
			-1,3:W^[	!       turn on SEEALL mode	!
			0,4:W^[		!       clear "mark" status	!
			0,5:W^[		!       turn off hold mode	!
		'			!     endif			!
		J			!     jump to beginning of buf	!
		<			! ----loop begin--------------- !
			MW		!       refresh scope		!
			! --------------------------------------------- !
			! the following loop advances through the edit	!
			! buffer, looking for a character with the high	!
			! bit set.					!
			! --------------------------------------------- !
			<		! ------loop begin------------- !
				0A&128"N	! if high bit is set	!
					0;	!   break out of loop	!
				'		! endif			!
				C	!         advance 1 char	!
			>		! ------loop end--------------- !
			0A&127-13"E	!       if char is <CR>		!
				D	!         delete it		!
			'		!       endif			!
			D		!	delete <LF>		!
			.-Z;		!       break if at end of buf	!
			.U0		!       0.num = current buf ptr	!
			! --------------------------------------------- !
			! --------------------------------------------- !
			<		! ------loop begin------------- !
				0A&128"N	! if hi bit clear	!
					0;	!   break out of loop	!
				'		! endif			!
				C	!         advance 1 char	!
			>		! ------loop end--------------- !
			! --------------------------------------------- !
			! --------------------------------------------- !
			<		! ------loop begin------------- !
				.U1	!         1.num = cur buf ptr	!
				0L	!         go to begin of line	!
				.-Q0-1"L	! if			!
					0;	!   break out of loop	!
				'		! endif			!
				R	!         back up one char	!
			>		! ------loop end--------------- !
			Q1J
			-(0^Q)-QO"G	!       if			!
				Q0J	!				!
				-1A-27"E	! if last char was ESC	!
					@I% %	!   insert <SP>		!
				'		! endif			!
				@I%
%					!       insert <CR><LF>		!
			'		!       endif			!
		>			! ----loop end----------------- !
		! ----------------------------------------------------- !
		! the following loop deletes trailing CR's, LF's, and	!
		! <SP>'s from the end of the buffer			!
		! ----------------------------------------------------- !
		<			! ----loop begin--------------- !
			ZJ		!       jump to buf end		!
			-Z;		!       break if buf empty	!
			-1A-10"N	!       is it LF?		!
				-1A-13"N	! is it CR?		!
					-1A-32"N	!   is it <SP>?	!
						0;	!     break	!
					'		!   endif	!
				'		! endif			!
			'		!       endif			!
			-D		!       delete it		!
		>			! ----loop end----------------- !
		MW			!     refresh scope		!
	'				!   endif			!
	! ------------------------------------------------------------- !
	! make sure the edit buffer ends in a CR/LF.			!
	! ------------------------------------------------------------- !
	QH"F				!   if no adjacent escapes	!
		ZJ			!     jump to buf end		!
		."E			!     if at beginning of buf	!
			10@I%%		!       insert <LF>		!
		'			!     endif			!
		-1A-10"N		!     if prev char is not <LF>	!
			10@I%%		!       insert <LF>		!
		'			!     endif			!
		R			!     back up one char		!
		."E			!     if at beginning of buf	!
			13@I%%		!       insert <CR>		!
		'			!     endif			!
		-1A-13"N		!     if prev char is not <CR>	!
			13@I%%		!       insert <CR>		!
		'			!     endif			!
	'				!   endif			!
	ZJ				!   jump to buf end		!
	! ------------------------------------------------------------- !
	! clean up the scope						!
	! ------------------------------------------------------------- !
	:QW"N				!   if /W was TRUE		!
		0:W-4"E			!     if VT100 in ANSI mode	!
			2,0:W^[		!       set VT100 in VT52 mode	!
		'			!     endif			!
		-1,3:W^[		!     turn on SEEALL mode	!
		0,4:W^[			!     clear "mark" status	!
		MW			!     refresh scope		!
	'				!   endif			!
|					! else (Z macro returned err)	!
	@^A/?Squish run failed; aborting any output
/					!   warn user			!
	0,0XF				!   clear F.str			!
'					! endif				!
0^X					! reset search mode flag	!
*					! end of ^UA			!

! --------------------------------------------------------------------- !
! Done loading squish driver macro into Q-register A			!
! --------------------------------------------------------------------- !

! --------------------------------------------------------------------- !
! If nothing is in the edit buffer, as them to input the name of the	!
! input file and insert it into the buffer.				!
! --------------------------------------------------------------------- !

Z"E					! if edit buffer is empty	!
	@I%File <.TES or .TEC>? %	!   ask for input file		!
	^^QMR				!   get response in Q.str	!
	GQ				!   and put it into the buffer	!
'					! endif				!
0,0XR					! clear R.str (response macro)	!
0,0XQ					! clear Q.str (user responses)	!
					! end of ^UF			!

! --------------------------------------------------------------------- !
! Done loading initialization macro into Q-register F			!
! --------------------------------------------------------------------- !

			! execute everything up until this point	!

! --------------------------------------------------------------------- !
! S t a r t   H e r e							!
! --------------------------------------------------------------------- !

@EI%%			! close current EI command			!
MF			! execute initialization macro in F.str		!
0,0XF			! clear F.str					!

Z"E			! if no command line in buffer			!
	@^A%Enter your macro then type MA$$
%			!   ask them to input a macro to squeeze	!
|			! else (the buffer isn't empty)			!

	! ------------------------------------------------------------- !
	! If the edit buffer isn't empty, it must contain the input	!
	! filename, and it might contain the output filename like so:	!
	!								!
	!	[OUTFILE[.TEC]=]INFILE[.TES]				!
	!								!
	! Executing the F macro above has stripped all the switches	!
	! from the command line in the edit buffer.			!
	!								!
	! First, deal with an output filename.  If an output filename	!
	! exists on the command line, we might append a .TEC filetype	!
	! to it if a filetype wasn't specified.  Then we'll load Q-reg	!
	! F with "EWfilename$" to open it for output and remove the	!
	! output filename from the buffer.				!
	! ------------------------------------------------------------- !

	J				! jump to start of buffer	!
	:@FS%=%%"S			! if "=" found, have output fn	!
		@^UF%EW%		!   put "EW" in F.str		!
		0,.:XF			!   append fn to F.str		!
		.UF			!   put cp in F.num		!
		-:@S%.%"U		!   if no ".", no file type	!
			:@^UF%.TEC%	!     append ".TEC"		!
		'			!   endif			!
		QFJ			!   jump to end of filename	!
		27:@^UF%%		!   append ESC to F.str		!
		QB"T			!   if any switches		!
			ET&64"E		!     if not detached		!
				:@^UF/	!       append create msg to F	!
				@^A%Creating "%
				:G*	!       append last filespec	!
				@^A%"
%					!       append "<CR><LF>	!
				/	!       done loading F.str	!
			'		!     endif			!
		'			!   endif			!
		0,.K			!   kill output fn in buffer	!
	'				! endif				!

	! ------------------------------------------------------------- !
	! Now, deal with an input filename.  If the filename doesn't	!
	! have a filetype, first we'll try .TES; and, if there is no	!
	! .TES file, we'll try .TEC.  Once we have an input filename,	!
	! we'll ER it.							!
	! ------------------------------------------------------------- !

	J				! jump to start of buf		!
	:@S%.%"U			! if no ".", no filetype	!
		ZJ			!   jump to buf end		!
		@I%.TES%		!   insert ".TES"		!
		HXQ			!   put input fn in Q.str	!
		:@ER%^EQQ%"U		!   if ".TES" doesn't exist	!
			-@FS%.TES%.TEC%	!     try ".TEC"		!
		'			!   endif			!
	'				! endif				!
	HXQ				! Q.str = input filename	!
	HK				! kill buffer			!
	@ER%^EQQ%			! open input file		!
	QB"T				! if any switches		!
		ET&64"E			!   if not detached		!
			@^A%Squishing "%!     display squish message"	!
			:G*		!     display filespec buffer	!
			@^A%"
%					!     display "<CR><LF>		!
		'			!   endif			!
	'				! endif				!

	! ------------------------------------------------------------- !
	! If there's no output filename, we'll stay in TECO after	!
	! squishing the input file.  If there is an output file, we'll	!
	! exit TECO after squishing.					!
	! ------------------------------------------------------------- !

	:QF"E				! if no output filename		!
		Y			!   yank 1st page		!
		128,0ET			!   turn off abort-on-error	!
		<			! ----loop begin--------------- !
			^E"T		!     if formfeed flag		!
				ZJ	!       jump to buf end		!
				12@I%%	!       insert <FF>		!
			'		!     endif			!
			:A;		!     break if append fails	!
		>			! ----loop end----------------- !
		MA			!   squeeze page		!
		MP			!   ??? what's in Q-reg P ???	!
	|				! else (we have an output fn)	!
		Y			!   yank 1st page		!
		QB"F			!   if no switches		!
			128,0ET		!     turn off abort-on-error	!
		'			!   endif			!

		! ----------------------------------------------------- !
		! if we're at end-of-file after yanking in the first	!
		! page, then squeeze what we've read in and write it	!
		! out.  If we're not at end-of-file, then we'll have	!
		! to go into a loop: squeezing the page we have, and	!
		! then reading in the next page.			!
		! ----------------------------------------------------- !

		^N"T			!   if at end-of-file		!
			^E"T		!     if formfeed flag		!
				ZJ	!       jump to buf end		!
				12@I%%	!       insert <FF>		!
			'		!     endif			!
			MA		!     squeeze page		!
			MF		!     open output file		!
			HPW		!     write page		!
			HK		!     kill page			!
		|			!   else			!
			MF		!     open output file		!
			<		! ------loop begin------------- !
			^E"T		!     if formfeed flag		!
				ZJ	!       jump to buf end		!
				12@I%%	!       insert <FF>		!
			'		!     endif			!
			MA		!     squeeze current page	!
			HPW		!     write current page	!
			HK		!     kill current page		!
			:Y;		!     break if yank fails	!
			>		! ------loop end--------------- !
		'			!   endif			!
		EF			!   close output file		!
		EX			!   exit			!
	'				!   endif			!
'					! endif				!

