!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 FILE[.TES] (assumes FILE.TEC=FILE.TES/L:70/T/C/A) MUNG SQU FILE[.TES]/SWITCHES (assumes FILE.TEC=FILE.TES) 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`macro`) /E Allow adjacent ESCapes Rules for TECO "source" code files: (files with .TES extensions) 1) If at all possible the source code files should not have embedded Escape or control characters. One of the goals of the .TES file is that it will print on any printer. And embedded Escape or control characters would interfere with this goal. Note that the goal of SQU.TES is to convert when possible the @ sign delimited form into Escape delimited form and ^character to Ctrl-character so direct use of these characters is not required. 2) If at all possible the macro.TES file should be directly runable There are a few exceptions and SQU.TES is one of them. This means that if you use for indentation then the macro.TES file should self strip the tabs (and any comments it can). 3) The use of the in command context (with /T:Y) will be either removed or converted to space and thus will not be usable for the insert with tab command. If you wish to insert with tab then use @I%text% construction. 4) Conditional assembly directives will be performed prior to any compression. 5) SQU will attempt to optimize your code by converting, whenever possible, @ modified commands into delimited commands. It will also try to convert text arguments that are permitted to have string build characters or match control characters from the ^x format into the Control-x format unless the @ modified delimiter is one of the "non-squishable" delimiters. Changes: Nov-89 added comments changed system specific "n,Stext$" to generic "m,nFBtext$" Jan-91 (James G. Dempsey) Change /W:Y so that it detects the type of scope you have and constructs the macro accordingly. Add: .iif (teco-expression) teco commands.... where the teco expression is evaluated. If the result is 0 the entire line is deleted. If the result is not zero the command line remains. The .iif must be at left margin and eclosed in exclamation points. Example: --------------------------------------------------------------------- ! !.iif 0 ! @^A%Please wait, squishing SQU.TES...% ! if running SQU.TES ! !.iif 0 ! @^A\ ! *** NOTICE *** ! ! SQU.TES is not runable in source form. If SQU.TEC is not available ! ! to squish SQU.TES use SQUSQU.TEC to produce SQU.TEC. If SQUSQU.TEC ! ! is not available then SQUSQU.TES is directly runable to produce ! ! SQUSQU.TEC and SQU.TEC. ! !.iif 0 ! \ ! --------------------------------------------------------------------- In addition the following restrictions are placed on comments embedded into SQU.TES: a) the first exclamation point MUST be followed by a space or tab b) you may optionally preceed the first exclamation point with spaces or tabs In addition to the comment restrictions to SQU.TES all tabs in this source will be treated as space. Tabs in other sources will be handled as indicated by the command line switches. Finaly you will note the use of .iif 0 conditional compile directives which will not exist in SQU.TEC in it's final form. However, these lines will be present in the intermiediary SQU.TEC that is used to squish itself. The use of these .iif 0's permit a non-optimal but usable version of SQU.TEC that will work on all systems. Once SQU.TES is squished with this version it will become optimal for the target system. Use of Q-registers: A.str = macro to handle ^A B.num = /B delete blank lines switch B.str = the set of comment delimiter characters (/C:set, or for /C:Y). C.num = the buffer pointer while squishing things for error reporting purposes. C.str = macro to run for comment (exclamation point) D.str = macro to run to delete deleteable characters from output this macro actualy replaces the character(s) with When the edit buffer has been processed and block deletes have been performed then these nulls will be squished out. E.num = true (-1) if command is escape delimiter pending E.str = macro to run for E command F.str = macro to run for F command G.str = macro to run if we must gripe about an error 0MG Trailing, pending @ 1MG End of buffer while sub-squishing 2MG Can't find a quote character 3MG Prior recursion level failed 4MG Unterminated string H.num = TRUE (-1) if we are allowing adjacent escapes (/E:Y) H.str = macro to run for horizontal tab I.str = macro to run for ^^ command, leaves next char as Is J.str = macro to run for Junk, high bit set, clear high bit K.str = the "non-squishable text delimiters". This is a list of delimiters (% by default or set by /A:set) that indicates that the text enclosed inside the delimiters is not to be altered in any way. If a text delimiter is not one of this set then the text may be squished. The squishing action performed upon the text is context dependant. If squishing is performed on text that will NOT contain string build characters or match control characters then the text will be left as-is, however, the @ and 's would possibly be replaces with the delimited format. If the text MAY contain match control or string build characters then the the squish process takes into consideration these characteristics and attempts to convert the ^x format into the Control-x format. And finaly if the text is a TECO macro as in: @^Uqtext Where is *not* one of the un-squishables, then the text will be recursivly squished as would a file. Note that SQU will not know the context of ED bit 1 (uparrow means uparrow) an as such if you wish to use uparrow as text in in text arguments where match control characters or string build characters could occure then you would be required to use a "non-squishable" or pass the character as ^Q^ if you must pass a control character following the ^Q (such as ^[) then use the ^E format (e.g. ^E<27> to match the ). Please note that the ^ character must always be non-squishable" L.num = desired line length (set with /L:nn) L.str = if /B:Y (without /L:nn or /D:Y) is macro to delete blank lines. M.num = buffer position of @ sign modifier (0 if not active) M.str = macro for '@' modifier N.num = start of previous line N.str = macro to do Nothing, pass character w/o squishing O.num = end of previous line O.str = macro to Optimize caret, next char is really CTRL-char P.num = temporary P.str = P is cleared if abort-on-error bit is set, and it is executed as a macro during cleanup. P.str may be loaded prior to calling SQU.TEC with EIsqu$ Q.num = Location of 1st on @^Umacro Q.str = scratch R.num = replace mode flag (for S.str) R.str = process text arguments for search and replace as in @FStext1text2 S.num = buffer position of start of text argument S.str = macro for commands that take search string argument (those that have search string build characters) as in @Stext and @Otext and @ERtext T.num = buffer position of middle/end of text argument T.str = macro to handle text arguments that are not of the replace or search format U.num = buffer position of end of text argument U.str = macro to handle ^U command V.str = macro to handle lowercase char (convert to uppercase) W.num = initialy used as result of /W for building macros that modify text buffer. Then at squish time W.num gets incrimented each time the buffer gets modified. If /W was true at macro build time then periodicly the screen will be updated. W.str = scope refresh command if watching progress (/W:Y) if ET&512 (VT52/VT100) "-1W" if ET&1024 (VT11/VS60) "W" if none "V" X.str = macro for commands that takes a character argument. That is to say that the character immediately following this command is an argument. The only action to be performed is a possible upcase of the next character (after testing for local Q-reg) Y.str = used in Z.str for command macro Z.str = macro to handle ^Z command, convert to -Z 0.num = scratch, but also used to contain last command char 0.str = scratch 1.num = scratch 1.str = scratch 2.num = scratch 2.str = scratch 3.num = scratch 3.str = macro to perform one of two functions: a) If the character following . is ^ then convert the two characters ^x into the two characters and <1A&63> (Ctrl-x). b) If the character following . is NOT ^ then replace the character with (or entry arg) After the buffer is squished then all s will be squished out. The reason for replacement is that the @FS`^X^X`` and @FS`^X`` will perform much faster because the search and replacement text are of the same size. At the time these replace- ments occure the probability is high that there are large ammounts of comments to be stripped out. By deferring the squish of nulls till after the comments are removed there will be less text moved on each saquish operation. 4.num = scratch 4.str = macro to replace the character following . with 5.num = scratch 5.str = macro to process conditional assembly directives. then macro to perform block deletes 6.str = macro to parse /s, /s:N, /s:Y, /s:nn and /s:text after parsing... macro to overstrike with n (nM6) 7.str = a list of deleteable characters nul, sp, tab, del etc. (used by the D.str macro) 8.str = macro to replace anything with 9.str = A list of macro names to execute for a character. 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 , the squisher uses the first character in the 9.str mask as a macro name which handles 's. The macro names are: A ^A process C Comment (exclamation point) D delete character from output nul,sp(,tab) E E command F F command H Horizontal tab char I ^^ command, leave next char as Is J Junk, high bit set, clear high bit L cr, lf, ff, vt M At sign (the next command is '@' modified) N do Nothing, pass character w/o squishing O Optimize caret, next char is really CTRL-char Q Quit macro. Determines when to quit R command takes search&replace arguments S command takes search argument T command takes text argument U ^U command V lowercase char (convert to uppercase) X command takes character argument. That is to say that the character immediately following this command is an argument. The only action to be performed is a possible upcase of the next character (after testing for local Q-reg) Z ^Z command, convert to -Z --------------------------------------------------------------------- ! ! --------------------------------------------------------------------- 6.str = macro to parse: /s, /s:N, /s:Y, /s:nn and /s:text Calling sequence: @^U0%default% ^^sM6 Exit conditions: 0 = No nn= nn -1= Yes (0.str is default or text) Note, if default text is null then no text can be accepted --------------------------------------------------------------------- ! ! (the following produces a when /D:Y or /L:nn ! @^U6` ! load 6.str ---------------------------------- ! U0 ! save switch letter ! 0^X ! either case match to search mode flag ! ZJ ! go to end of buffer ! @I%/% ! insert trailing / ! 0J ! go to beginning of buffer ! :@S~/^EU0~"U ! if no /s ! :Q0"E ! if no default ! @O!N! ! take /N exit ! ' ! endif ! @O!doY! ! return yes after checking for numeric ! ' ! endif ! ^SC ! to beginning of /s ! :@FS~/^EU0/~/~"S ! if /s/ remove /s then... ! @O!doY! ! return yes after checking for numeric ! ' ! endif ! :@FS~/^EU0:Y/~/~"S ! if /s:Y/ remove /s:Y then... ! !doY! 0Q0"D ! if default is numeric ! ZJ ! to end of buffer ! G0 ! get text ! ^SC ! backup ! \U0 ! convert text to number, store in 0.num ! ^SD ! delete the text string ! @O!nn! ! take the nn exit ! ' ! endif default numeric ! @O!Y! ! if default not numeric take /Y exit ! ' ! endif ! :@FS~/^EU0:N/~/~"S ! if /s:N/ remove /s:N then... ! 0,0X0 ! clearout any default text ! @O!N! ! return no ! ' ! endif ! :@FS~/^EU0:~~"S ! if /s: remove /s: then... ! .U0 ! rember position ! @S~/~ ! position to / of next (or eob) switch ! R ! backup over / ! Q0,.X0 ! replace the default switch ! Q0,.K ! kill the replacement switch ! @O!doY! ! make believe we got a /Y ! ' ! endif ! @^A% ?Illegal switch setting? % !N! ! take /s:N return ! 1 ! 1-1=0=no ! !Y! ! take /s:Y return ! -1 ! -1=success ! U0 ! save flag ! !nn! ! have nn in 0.num ! ZJ ! go to end of buffer ! -1D ! delete trailing / ! -1^X ! exact match to search mode flag ! Q0 ! return with exit condition ! ` ! end load 6.str -------------------------------------- ! ^D ! set radix to decimal ! 0ED ! zero edit mode flag ! -1^X ! exact match to 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 ! :@FS~ ~~"S ! if command ends if CR/LF delete CR/LF ! .,ZK ! then delete to end of buffer ! J ! jump to beginning of edit buffer ! ' ! endif ! ! --------------------------------------------------------------------- At this point we have one line (w/o CR/LF) that could be empty or of one of the following formats: assumes file file.TEC=file.TES/defaults file/switches file.TEC=file.TES/switches outfile=infile outfile.TEC=infile.TES/defaults outfile=infile/switches outfile.TEC=infile.TES/switches /H /switches /H Load S.str temporarill with default switches (in text form) --------------------------------------------------------------------- ! @^US%/L:70/T:Y/C:Y/W:Y/A:Y/E:N% Z"E ! if nothing in buffer ! @I%/H% ! insert /Help ! ' ! endif ! J ! go to start of buffer ! :@FS%/?%/H%$ ! /? same as /H ! :@S%/H%"S ! if option /Help... ! !HELP! !.iif ET&1024 ! 0W ! if refresh scope, turn it off ! @^A\ SQU.TEC - V40.01 MUNG SQU outfile[.TEC]=infile[.TES]/switches Switches: /H Help on switches /D Delete lexical CR/LFs /L:nn 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%macro%) /E Allow adjacent ESCapes Default switches: \ ! end of help message ! :GS ! type out the default switches ! @^A\ \ ! end of help message ! EX$$ ! exit ! ' ! endif /H ! J ! jump to beginning of edit buffer ! :@S%/%"F ! search for '/' command line switch delimiter ! ZJ ! if no '/' jump to end of edit buffer ! GS ! get default switches ! ' ! endif ! ! --------------------------------------------------------------------- Build 9.str to contain a list of macro names to be executed on the occurance of the character. The initial contents 9.str will only cause the , ^char and @x%xxx% to be compressed. All other functions will be added/changed while we analyse the /switches. Note that this table is 256 bytes long and contains enteries for case and sign bit conversions. --------------------------------------------------------------------- ! ! Load up values for , the control characters, and ! ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! @^U9%DANNNNNNNHNNNNNNNNNNNUNNNNZNNNIND% ! load default mask ! ! n tlvfc e s ! ! u aftfr s p ! ! l b c ! :@^U9%C% ! Comment (exclamation point) ! ! --------------------------------------------------------------------- append entries for all other TECO commands to the mask in Q-reg 9. --------------------------------------------------------------------- ! ! %"#$%&'()*+,-./0123456789:;<=>?% ! :@^U9%XNNXNNNNNNNNNNNNNNNNNNNNNNNNNN% ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_% ! :@^U9%MNNNNEFXNTNNNXSSNXNSNXNNXNNXNXOS% ! %`abcdefghijklmnopqrstuvwxyz{|}% ! :@^U9%NVVVVVVVVVVVVVVVVVVVVVVVVVVNNNND% ! At this point 9.str has first 128 codes. Fill up the rest with Junks ! 4< ! repeat 4 times ! :@^U9%JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ% ! append 32 J's ! > ! end repeat ! ! --------------------------------------------------------------------- Check for /W "Watch progress" switch in front of building macros that may be modified by /W --------------------------------------------------------------------- ! ^^WM6UW ! result of /W in W.num ! ! --------------------------------------------------------------------- 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. --------------------------------------------------------------------- ! @^U0%Y% ! set /D switch value to /D:Y ! ^^DM6UD ! check out /D put value into D.num ! ! --------------------------------------------------------------------- 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. --------------------------------------------------------------------- ! QD"T ! if /D:Y ! @^U0%N% ! set default switch value to /L:N ! | ! else ! @^U0%70% ! set default switch value to /L:70 ! ' ! endif ! ^^LM6UL ! check out /L put value into L.num ! QL"N ! if any /L:nn ! 0UD ! /D goes off ! QL"L ! if /L:trashy ! 64000UL ! use something relevant ! ' ! endif ! ' ! endif ! QD"N ! if /D:Y ! 0J ! go to beginning fo buffer ! G9 ! get 9.str ! 10J ! position to lf, vt, ff, cr ! @FS~^X^X^X^X~DDDD~ ! use D for lf, vt, ff and cr ! 0,256X9 ! back into 9.str ! 0,256K ! delete from buffer ! ' ! endif ! QL"N ! if /D:Y .or. /L:nn ! 0J ! go to beginning fo buffer ! G9 ! get 9.str ! 10J ! position to lf, vt, ff, cr ! @FS~^X^X^X^X~DDDL~ ! use D for lf, vt, ff and cr ! 0,256X9 ! back into 9.str ! 0,256K ! delete from buffer ! @^UL~ ! Load L.str ! 254M6 ! overstrike with line break ! MD ! iif followed by take it out ! ~ ! end load of L.str ! ' ! 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 --------------------------------------------------------------------- ! @^U0%Y% ! set default switch value to /s:Y ! ^^TM6UT ! check out /T put value into T.num ! QT"T ! if /T:Y ! 0J ! go to beginning fo buffer ! G9 ! get 9.str ! 9J ! position to tab ! @FS~^X~D~ ! use D for tab ! 0,256X9 ! back into 9.str ! 0,256K ! delete from buffer ! ' ! endif ! ! --------------------------------------------------------------------- 7.str = list of deletable characters this depends on /D, /L and /T switches --------------------------------------------------------------------- ! 0,0X7 ! initialize to null string ! ^O ! set octal radix ! QT"T ! if /T(:Y) ! 11:@^U7%% ! horizontal tab (should be most frequent) ! ' ! endif ! 40:@^U7%% ! space ! QD#QL"N ! if /D:Y .or. /L:nn ! 15:@^U7%% ! cr /D ! 12:@^U7%% ! lf /D ! 14:@^U7%% ! ff /D ! 13:@^U7%% ! vt /D ! ' ! endif ! ^D ! set decimal radix ! ! --------------------------------------------------------------------- Check for /B "Delete blank lines" switch If /D:Y or /L:nn then /B is ignored --------------------------------------------------------------------- ! 0,0X0 ! no default ! ^^BM6UB ! save /B value ! QD#QL"E ! if neither /D:Y .nor. /L:nn ! 0J ! go to beginning fo buffer ! G9 ! get 9.str ! 10J ! position to lf, vt, ff, cr ! @FS~^X^X^X^X~DDDL~ ! use D for lf, vt, ff and cr ! 0,256X9 ! back into 9.str ! 0,256K ! delete from buffer ! @^UL~ ! Load L.str ! 0^Q"N ! if line not empty ... ! C ! keep ! 0A-10"E ! if follows ! C ! keep ! ' ! endif ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! all done ! ' ! endif line not empty ! M8 ! replace with ! 0A-10"E ! if follows ! M8 ! replace with ! ' ! endif ! !.iif 0 ! !SUCCESS! ! iif not compiled ! -1 ! exit with success ! ~ ! End Load L.str ! ' ! 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 *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: is a command line switch then use as the "non-squishable" char. If you're asked for the /A value, then you can enter a set of "non-squishable" chars. Please note that the ^ character must always be non-squishable" --------------------------------------------------------------------- ! ^^%@^U0%% ! set default to /A:% ! 94:@^U0%% ! set default to /A:%^ ! ^^AM6"S ! if /A:Y or /A:set ! [0 ! push or set ! ]K ! load K.str ! | ! else ! @^UK%% ! clear K.str ! ' ! endif ! 94@I%% ! insert ^ ! R ! backup over the ^ ! ::@S~^EGK~"S ! if the ^ inside K.str ! R ! backup over the ^ ! | ! else ! 94:@^U0%% ! add ^ to set ! ' ! endif ! D ! delete the ^ from the buffer ! ! --------------------------------------------------------------------- A.str = macro to handle ^A command. We've run into ^Atext^A or @^A/text/. The text argument will be handled either as-is of filtered thru the ^x control char filter depending on weather the delimiter locate in the unsquishable caracter set. --------------------------------------------------------------------- ! @^UA~ ! load macro A.str (use tilda not % so we will ! ! squish the @^Umacro ! 1MT ! execute Text macro w/ ^A as ! ~ ! end load macro A.str ! ! --------------------------------------------------------------------- B.str = list of comment delimiter characters Q-register B contains the special comment delimiter characters. If the exclamation point is followed by one (or more) of these delimiter characters then this is a comment that is subject to deletion. If it is not followed by one of the delimiters then it is not to be deleted. Also note that @ modified comments are never deleted. You will note that comments most frequently appear in two formats: a) comments that come after commands and b) comment blocks such as the text that you are reading here. Format "a" comments are of the format: []comment[] []command... or []comment[] ... []comment[] []command... Format "b" comments are of the format: comment[] ... comment[] Since any time we squish the edit buffer consumes a large portion of processing time we will try to delete as much as we can in one shot. --------------------------------------------------------------------- ! QW"T ! if /W:Y display ! @^UC~%W-10"GMW'~ ! display refresh at every 10 comments ! | ! else ! 0,0XC ! clear out C.str ! ' ! endif ! 32@^U0%% ! set 0.str to ! 9:@^U0%% ! then to ! ^^CM6"N ! if /C:Y ! [0 ! put comment delimiter list on stack ! ]B ! copy to B.str ! @O!Delete comments! ! go to section to build C.str for /C:Y ! ' ! end if ! ! --------------------------------------------------------------------- C.str = macro to handle comments when *NO* comment stripping occures --------------------------------------------------------------------- ! :@^UC\ ! load C.str ---------------------------------- ! C ! advance past the exclamation point ! QM"E ! if not @ modified comment ! :@S~!~"S ! if end of comment found ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! -1$^[ ! exit with success ! ' ! endif ! 4MG ! if 2nd excl. missing, String fail ! !.iif 0 ! @O!FAIL! ! iif not properly compiled ! 0$^[ ! iif compiled exit with Fail ! ' ! endif not @ modified comment ! 0AU0 ! here if @ modified comment, pickup ! C ! advance past ! 0UM ! clear @ modifier flag ! :@S~^EU0~"S ! if end of comment found ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! -1$^[ ! iif compiled exit with success ! ' ! endif ! 4MG ! if 2nd excl. missing, String fail ! 0 ! return Failure ! !.iif 0 ! !FAIL! ! iif not properly compiled failure tag ! !.iif 0 ! +1 ! iif not properly compiled (0+1-1=0=Fail) ! !.iif 0 ! !SUCCESS! ! iif not properly compiled Success tag ! !.iif 0 ! -1 ! iif not properly compiled 0-1=-1=Success ! \ ! C.str end of load-------------------------------------------- ! @O!C.str Loaded! ! --------------------------------------------------------------------- C.str = macro to handle comments when comment stripping occures --------------------------------------------------------------------- ! !Delete comments! :@^UC\ ! load C.str ---------------------------------- ! .US ! mark start of comment ! C ! advance past the exclamation point ! QM"E ! if not @ modified comment ! ::@S~^EGB~"S ! if special comment delimiter follows ! 0UT ! clear end of comment position ! < ! loop for multiple comments ! :@S~!~; ! find end of comment, else exit ! ::@S~^EM^EG7~$ ! span possible , ignore result ! .UT ! remember end of comment+1 ! ::@S~!^EGB~; ! exit if not comment following comment ! > ! end loop ! QTJ ! go to end of block of comments ! ."N ! if no error ! R ! backup to last expendable character ! .UT ! save position of end of comment (+) ! QSJ ! go to start of comment ! M8 ! overstrike with ! 255M6 ! overstrike with 255 ! QTJ ! go past block delete ! M8 ! overstrike with ! ! Note, !! becomes , all other! ! deleted comments become: ! ! <255>text ! ^N"T ! if end-of-file ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! ^N$^[ ! exit with success ! ' ! endif end-of-file ! .+.-Z"L ! if processed less than 32000 characters ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! -1$^[ ! exit with success ! ' ! endif more than 500 characters left ! QQ"L ! if looking for end of buffer ! QS"E ! if the buffer starts with this comment ! 0,.K ! kill from start to here ! | ! elseif comment starts after location 0 ! M5 ! squish comments ! ' ! endif ! ' ! endif ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! -1$^[ ! exit with success ! ' ! endif no error ! 4MG ! if 2nd excl. missing, String fail ! !.iif 0 ! @O!FAIL! ! iif not properly compiled ! 0$^[ ! exit with Fail ! ' ! endif deletable comment ! R ! backup to the exclamation point ! 0UM ! clear @ modifier flag ! ' ! endif not @ modified comment ! 0AU0 ! here if @ modified comment, pickup ! C ! advance past ! :@S~^EU0~"S ! if end of comment found ! !.iif 0 ! @O!SUCCESS! ! iif not properly compiled ! -1$^[ ! iif compiled exit with success ! ' ! endif ! 4MG ! if 2nd excl. missing, String fail ! 0 ! return Failure ! !.iif 0 ! !FAIL! ! iif not properly compiled failure tag ! !.iif 0 ! +1 ! iif not properly compiled (0+1-1=0=Fail) ! !.iif 0 ! !SUCCESS! ! iif not properly compiled Success tag ! !.iif 0 ! -1 ! iif not properly compiled 0-1=-1=Success ! \ ! C.str end of load-------------------------------------------- ! !C.str Loaded! ! --------------------------------------------------------------------- D.str = macro to run when we come across a deleteable character Note, if space and or tabs are used for whitespace it will be used for comment alignment and therefore it is a high probability that multiple whitespaces will occure together therefor we will delete any number of deletable characters that appear together. Note, what we are actually doing is replacing the character(s) with a (s). This way we deferr squishing the buffer until later. --------------------------------------------------------------------- ! ! load D.str with... ! @^UD%.US% ! save start of delete zone ! :@^UD%::S% ! ::S loop, anchored search ! ^^E&63:@^UD%% ! ::S^E ! :@^UD%M% ! ::S^EM ! ^^E&63:@^UD%% ! ::S^EM^E ! :@^UD%G7% ! ::S^EM^EG7 any # char in 7.str ! 27:@^UD%% ! ::S^EM^EG7 ! :@^UD~ "S ! if successful (should be however, MD may be ! ! issued on the speculation that deleteables ! ! follow something. ! R ! backup to last expendable character ! .UT ! save position of end of zone (+) ! QSJ ! go to start of delete zone ! ^S+1"G ! if more than one deleteable ! M8 ! overstrike with ! QT-QS-1"G ! if more than 2 in a row ! 255M6 ! overstrike with 255 ! QTJ ! go past block delete ! ' ! endif ! ' ! endif ! M8 ! overstrike with ! ' ! endif ! -1 ! return success ! ~ ! end load of D.str---------------------------- ! ! --------------------------------------------------------------------- E.num = escape delimiter pending flag, -1 if true, 0 if false This flag is tested by the code that attempts to replace @ modified delimiters with the Escape delimited format. If E.num is true then someone is not following the rules and is expecting a real live Esc to terminate the text argument. --------------------------------------------------------------------- ! 0UE ! Set Escape delimiter expected to False ! ! --------------------------------------------------------------------- E.str = macro to run for Ex --------------------------------------------------------------------- ! @^UE~ .UC ! C.num = current buf ptr ! C ! advance past the E ! 0A^_"N ! if not end of buffer ! 0A"V ! if 2nd cmd char is lowercase! MV$ ! convert to uppercase ! ' ! 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 --------------------------------------------------------------------- ! 0A-^^B"E ! if it's EB ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^G"E ! if it's EG ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^I"E ! if it's EI ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^N"E ! if it's EN ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^R"E ! if it's ER ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^W"E ! if it's EW ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^_"E ! if it's E_ ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! exit with code ! ' ! endif ! C ! ignore second letter of Ex ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! success ! | ! else end of buffer ! 4MG ! unterminated string ! ' ! endif ! !.iif 0 ! !FAIL! 1 ! fail exit ! !.iif 0 ! !SUCCESS! -1 ! success exit ! !.iif 0 ! U0 !.iif 0 ! !Q0! Q0 ~ ! end E.str load ! ! --------------------------------------------------------------------- F.str = macro to run for Fx We've run into a F', F<, F>, F|, FB, FC, FD, FK, FN, FR, FS, or F_ --------------------------------------------------------------------- ! @^UF~ .UC ! C.num = current buf ptr ! C ! advance past the F ! 0A^_"N ! if not end of buffer ! 0A"V ! if 2nd cmd char is lowercase! MV$ ! convert to uppercase ! ' ! endif ! ! --------------------------------------------------------------------- the FB and FR commands take a single string argument the FC, FS, FN, and F_ commands take two string arguments --------------------------------------------------------------------- ! 0A-^^B"E ! if it's FBtext$ ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^C"E ! if it's FCtext$text$ ! MR ! call FS string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^D"E ! if it's FDtext$ ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^K"E ! if it's FKtext$ ! MS ! call search string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^R"E ! if it's FRtext$ ! MT ! call text string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^S"E ! if it's FStext$text$ ! MR ! call FS string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^N"E ! if it's FNtext$text$ ! MR ! call FS string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! 0A-^^_"E ! if it's F_text$text$ ! MR ! call FS string build ! !.iif 0 ! U0 @O!Q0! ! if not compiled ! $^[ ! exit with code ! ' ! endif ! !.iif 0 ! C @O!SUCCESS! ! ! :C $^[ ! take success exit ! ' ! endif ! 4MG ! unterminated string ! !.iif 0 ! !FAIL! 1 ! fail exit ! !.iif 0 ! !SUCCESS! -1 ! success exit ! !.iif 0 ! U0 !.iif 0 ! !Q0! Q0 ~ ! end F.str load ! ! --------------------------------------------------------------------- G.str = macro to run when sometning has Gone wrong --------------------------------------------------------------------- ! @^UG~ ! Load G.str ! ! The following conditionals do the following: a) if SQU is not properly compiled it assumes you do not have the computed goto form of nOtag0,tag1,...$ b) if SQU is compiled it will use the computed goto if available ! UG ! save code # in case it is out of range ! !.iif 0 ! @O!NOT COMPILED! ! if not compiled go to... ! !.iif (nO) ! QG@O!0,1,2,3,4! ! if nO available dispatch via err # ! !.iif (nO)^_ ! UG ! if nO not available save error code # ! !.iif 0 ! !NOT COMPILED! ! if not compiled ! !.iif (nO)^_ ! QG-0"E@O!0!' ! if error code #0 ! !.iif (nO)^_ ! QG-1"E@O!1!' ! if error code #1 ! !.iif (nO)^_ ! QG-2"E@O!2!' ! if error code #2 ! !.iif (nO)^_ ! QG-3"E@O!3!' ! if error code #3 ! !.iif (nO)^_ ! QG-4"E@O!4!' ! if error code #4 ! @^A% !! Unknown Error code % QG= ! say what it was ! @^U1%???% @O!ERROR! ! goto error display ! !0! @^U1%Trailing, pending @% @O!ERROR! ! goto error display ! !1! @^U1%End of buffer while sub-squishing% @O!ERROR! !2! @^U1%Can't find a quote character% @O!SETPOS! !3! @^U1%Prior recursion level failed% @O!SETPOS! !4! @^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: from squished .= | | --------------------------------------------------------------------- ! !SETPOS! :@^U1% from squished .=% ! append msg to 1.str ! QS\ ! position in S.num to buf ! ^Y:X1 ! append position in buf ! ^YK ! delete position from buf ! 13:@^U1%% ! append ! 10:@^U1%% ! append ! QCJ ! jump to where error starts ! .-(0^Q),.:X1 ! append line up to error ! ^^|:@^U1%% ! append | ! 10:@^U1%% ! append ! ^^|:@^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 ! 10^T ! display ! -1U1 ! set Z-macro return to -1 ! ~ ! end load of G.str ! ! --------------------------------------------------------------------- H.num = -1 if /E:Y (allow adjacient Escapes) 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// can 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. --------------------------------------------------------------------- ! !.iif (TECO-86) ! @^U0%Y% ! default /E:Y ! !.iif (TECO-86)^_ ! @^U0%N% ! default /E:N ! ^^EM6UH ! H.num = 0 (FALSE) or -1 (TRUE)! ! --------------------------------------------------------------------- H.str = macro to run for text$ or @text --------------------------------------------------------------------- ! @^UH~ ! load H.str ! 27MT ! process text argument, default is ! ~ ! end load H.str ! ! --------------------------------------------------------------------- I.str = macro to leave next character as-is --------------------------------------------------------------------- ! @^UI~ ! load I.str ! C ! advance past ^^ ! :C ! conditionaly advance 1 char, return success/fail ! ~ ! end load I.str ! ! --------------------------------------------------------------------- J.str = macro to execute when we find the 0200 bit set The 0200 bit will be considered expendable in .TES files. Since we found one of these with the 200 bit set we will replace all occurances of this character with its counter part with the 200 bit clear --------------------------------------------------------------------- ! @^UJ~ ! load J.str ! .U0 ! rember where it was ! @^U0%<:@FS% ! build first part of a search and replace loop ! 0A+1:@^U0%% ! use the character+1 as the ! 0A:@^U0%% ! use the character as the search for ! 0A+1:@^U0%% ! use the character+1 as the ! 0A&127:@^U0%% ! use the character w/o 0200 bit as the replacement ! 0A+1:@^U0%% ! use the character+1 as the ! :@^U0%;>% ! finish off the loop ! M0 ! <:@FScharchar&127;> ! Q0J ! restore the buffer pointer ! -1 ! return success ! ~ ! end load J.str ! ! --------------------------------------------------------------------- M.num = @ flag When @ modified commands M.num = location of @ --------------------------------------------------------------------- ! 0UM ! clear @ flag ! ! --------------------------------------------------------------------- M.str = macro to handle '@'. The following command is @ modified set a flag in M.num to indicate that we should look for the alternate delimiter characters. even though 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. --------------------------------------------------------------------- ! @^UM~ ! load M.str ! .UM ! set @-modified flag M.num to location of @ ! :C ! exit with "success" flag ! ~ ! end load of M.str ! ! --------------------------------------------------------------------- N.str = macro to leave current character as-is --------------------------------------------------------------------- ! @^UN~ ! load N.str ! C ! conditionaly advance past current char ! 0A-QQ"N ! if not terminator ! 0AQ9-^^N"EF<' ! iif next command also a "N" type, redo N ! ' ! endif not terminator ! -1 ! otherwise exit ! ~ ! end load N.str ! ! --------------------------------------------------------------------- O.str = macro to 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 ^[ () because we may not wish to create adjacent 's. Note the preferred way of escaping from a macro is $^[ After you have read the above in reality if the ^char is to be replaced with Ctrl-char we will us 3.str to perform the replace. See comments on 3.str as to how and why it is performed the way it is. --------------------------------------------------------------------- ! @^UO~ ! *Load O.str ! 1A+1"G ! if a character follows ! ~ ! *end Load of O.str ! QH"T ! *if allowing adjacient Escapes ! :@^UO~ ! *continue Load O.str ! M3 ! replace the ^x with ! R ! backup to the Ctrl-x to reprocess it ! !.iif 0 ! @O!SUCCESS! ! (IF NOT COMPILED) ! -1$^[ ! we are all done exit with success ! ~ ! *end continue Load of O.str ! | ! *else we are NOT allowing adjacient Escapes ! :@^UO~ ! *continue Load O.str ! 1A-^^["N ! if NOT to become Escape ! M3 ! replace the ^x with ! R ! backup to the Ctrl-x to reprocess it ! !.iif 0 ! @O!SUCCESS! ! (IF NOT COMPILED) ! -1$^[ ! we are all done exit with success ! ' ! endif not to become Escape ! ! here if we are called to make an ! -1A-27"E ! if previous number and ! 2C ! skip past the ^[ ! | ! else ! M8 M4 ! replace the ^[ with ! R ! backup to the Ctrl-x to reprocess it ! ' ! end if previous number and ! !.iif 0 ! @O!SUCCESS! ! (IF NOT COMPILED) ! -1$^[ ! we are all done exit with success ! ~ ! end Load of O.str ! ' ! *end if allowing adjacient Escapes ! :@^UO~ ! *continue Load O.str ! ' ! endif a character follows ! 1MG ! report error ! !.iif 0 ! !FAIL! 1 ! (IF NOT COMPILED) ! !.iif 0 ! !SUCCESS! -1 ! (IF NOT COMPILED) ! 0 ! take failure exit ! ~ ! end Load of O.str ! ! --------------------------------------------------------------------- Q.num = 0A value for quit time --------------------------------------------------------------------- ! -1UQ ! quit on end of buffer ! ! --------------------------------------------------------------------- R.num = replace mode flag (for S.str) --------------------------------------------------------------------- ! 0UR ! initialize to 0 (not from replace) ! ! --------------------------------------------------------------------- R.str = macro to span text arguments that may contain string build or match control characters such as int @FS~text1~text2~ Note, R.str is a combination of S.str and T.str. --------------------------------------------------------------------- ! @^UR~ ! Load R.str ! QM"N ! if @ sign modified ! C ! advance past command character ! 0AUR ! call MS with comming from MR flag ! ::@S`^EGK`"F ! if squishable ! R ! backup to instruction ! MS"F ! if unsuccessfully process search arg ! !.iif 0 ! @O!FAIL! ! iif not compiled ! 0 $^[ ! take fail exit ! ' ! endif (MS successful) ! | ! elseif unsquishable ! .-1US ! mark 1st ! :@S`^EUR`"F ! if 2nd not found ! 4MG ! string not terminated ! !.iif 0 ! @O!FAIL! ! iif not compiled ! 0 $^[ ! take fail exit ! ' ! endif 2nd not found ! .-1UT ! mark 2nd delim (don't backup) ! ' ! endif unsquishable ! :@S`^EUR`"S ! if 3rd found ! R ! backup to 3rd ! .UR ! remember where 3rd is located ! QS,QR:@FB`^[`"F ! if not found ! QT+1-QR#QH"T ! if xxx .or. ok ! QMJ ! position to @ ! M8 ! replace it with ! QSJ ! position to first ! M8 ! replace it with ! QTJ ! position to 2nd ! M4 ! overstrike with ! QRJ ! position to 3rdd ! M4 ! overstrike with ! ' ! endif we can replace with s ! ' ! endif not found ! 0UM ! clear @ modifier ! QRJ ! position to last ! C ! +1 ! 0UR ! clear the comming from MR flag ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif last delimiter found ! 4MG ! unterminated string ! ' ! end if @ modifier ! MS"S ! if replace string processed ok ! :@S`^[`"S ! if terminating ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif last delimiter found ! 4MG ! unterminated string ! ' ! endif text ok from MS ! 0 ! return fail ! !.iif 0 ! !FAIL! +1 ! if not compiled take fail exit ! !.iif 0 ! !SUCCESS! -1 ! if not compiled take success exit ! ~ ! end Load of R.str ! ! --------------------------------------------------------------------- S.str = macro to span text arguments that may contain string build or match control characters such as int @S~text~ Note, S.str is similar to T.str except an additional test is made to see if the is *NOT* in the non-squishable text delimiter set and if the text is squishable then ^x will be replaced with its Ctrl-x member. Note, @S^text^ has to be non-squishable. --------------------------------------------------------------------- ! @^US~ ! Load S.str ! QM"N ! if @ sign modified ! C ! advance past command character ! ::@S`^EGK`"S ! if NOT squishable ! QR"E ! if we are NOT coming from MR ! 2R ! backup to instruction ! MT ! process text arg, return success/fail ! !.iif 0 ! U0 @O!Q0! ! iif not compile ! $^[ ! return success/fail to caller ! ' ! endif we are NOT coming from MR ! .-1US ! save start of text ! :@S`^EUR`"S ! if we find the 2nd ! .-1UT ! save it's location ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif we find the 2nd ! 4MG ! string not terminated ! !.iif 0 ! @O!FAIL! ! iif not compiled ! 0$^[ ! take success exit ! ' ! end if NOT squishable ! 0AU1 ! squishable, place into 0.num ! .US ! save position of ! C ! advance over ! | ! elseif not @ sign modified ! 27U1 ! use as ! ' ! end if @ sign modified ! < ! repeat... ! 0A-Q1"N ! if not ! 0A^_; ! iif no more text exit loop ! 0A-^^^"N ! if not ^ ! C ! advance ! F< ! continue ! ' ! endif not ^ (i.e. it was a ^) ! 1A-^^["E ! if ^[ ! 2C ! skip over the ^[ save to undo @ modifier ! F< ! continue ! ' ! endif ^[ ! M3 ! convert ^x into Ctrl-x ! F< ! continue ! | ! else if ! Q1-27"N ! if .not. ! .UT ! save position of ! QR"N ! if we are coming from MR ! C ! go over 2nd ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif coming from MR ! QS,.:@FB`^[`"F ! if not found ! QMJ ! position to @ ! M8 ! replace it with ! QSJ ! position to first ! M8 ! replace it with ! QTJ ! position to 2nd ! M4 ! overstrike with ! 0UM ! clear @ modifier ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! end if not found ! QTJ ! position to ! C ! position after ! ' ! endif .not. ! 0UM ! clear @ modifier if set ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif end of buffer ! 0; ! escape loop ! > ! end of loop ! 0 ! take error exit ! !.iif 0 ! !FAIL! +1 ! iif not compiled take fail exit ! !.iif 0 ! !SUCCESS! -1 ! iif not compiled take success exit ! !.iif 0 ! U0 ! iif not compiled ! !.iif 0 ! !Q0! Q0 ! iif not compiled ! ~ ! end Load of S.str ! ! --------------------------------------------------------------------- T.str = macro to span text arguments: tags, Itext$, ^Atext^A etc. call: ^^MT where is the default delimiter. If @ is pending then the alternate is picked up from the text buffer. There are no character building constructions to be checked for. If the @ format is used and the default is not "in_use" then the @ format will be replaced with the format. --------------------------------------------------------------------- ! @^UT~ ! Load T.str ! +0U1 ! save or 0 ! Q1"E 27U1 ' ! iif 0 then assume ! C ! advance past command character ! .US ! save start of text argument in case of error ! QM"N ! if @ modifier ! 0AU0 ! pickup alternate delimiter ! :C$ ! advance past alternate delimiter /wo ?POP ! | ! else ! Q1U0 ! specified delimiter to 0.num ! ' ! endif ! ! --------------------------------------------------------------------- At this point: 0.num = alternate or default depending on @ 1.num = default M.num > 0 if @ modified S.num = address of alternate or address of text --------------------------------------------------------------------- ! :@S`^EU0`"S ! if last delimiter found ! .UT ! save end of text argument ! QM"N ! if @ modifier ! QS,QT:@FB`^EU1`"F ! if default not found ! QMJ ! positon to the @ ! 0UM ! clear the @ modifier ! M8 ! replace with ! QSJ ! position at 1st ! M8 ! replace with ! QT-1J ! position to 2nd ! Q1-27"E ! if default is ! M4 ! overstrike with ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! endif default is ! Q1M6 ! overstrike with ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! end if default not found ! QTJ ! position to end of text argument ! 0UM ! clear the @ modifier ! ' ! endif @ modifier ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1$^[ ! take success exit ! ' ! end if last delimiter found ! 4MG ! display string arg error message ! 0 ! take failure exit ! !.iif 0 ! !FAIL! 1 ! if not compiled ! !.iif 0 ! !SUCCESS! -1 ! if not compiled ! ~ ! end Load of T.str ! ! --------------------------------------------------------------------- U.str = macro to handle ^Utext or @^Utext If of @ format AND is from the "un-squishable" set then text will be passed "as-is" and the @ format may possibly be converted to delimited format. If, on the otherhand, the text is squishable then it will assume that the text is a teco macro and file level squishing will be performed. --------------------------------------------------------------------- ! @^UU~ ! Load U.str -------------------------------------------------- ! MX"S ! upcase the Q-register, throw out ! QM"N ! if @ modified ! ::@S`^EGK`"S ! if "un-squishable" ! 2R ! backup over the and command char! MT ! process text "as-is" ! !.iif 0 ! U0 @O!Q0! ! iif not compiled ! $^[ ! return success/fail to caller ! ' ! end if "un-squishable" ! [M ! save location of @ ! .UM [M ! save location of 1st ! [Q ! save current quit condition ! 0AUQ ! get value of for use as quit value! C ! skip past ! 0UM ! clear @ modifier ! !.iif 0 ! @O!SUCCESS! ! iif not compiled ! -1 $^[ ! return success to caller ! ' ! endif not @ modified ! [M ! save 0 (not @ modified ! [M ! save 0 no 1st ! [Q ! save current quit condition ! 27UQ ! value of is ! !.iif 0 ! !SUCCESS! ! iif not compiled success exit ! -1 ! take success exit ! ' ! end if error in q-register name ! !.iif 0 ! !FAIL! ! iif not compiled take fail exit ! +0 ! return error ! !.iif 0 ! U0 ! iif not compiled ! !.iif 0 ! !Q0! Q0 ! iif not compiled ! ~ ! End Load U.str ---------------------------------------------- ! ! --------------------------------------------------------------------- V.str = macro to handle lower case character (upcase it) --------------------------------------------------------------------- ! @^UV\ ! Load V.str -------------------------------------------------- ! !.iif 0 ! @O!SLOW! ! iif not compiled do it the slow way ! !.iif (TECO-86) ! :^W ! upcase next char return success/fail ! !.iif 0 ! !SLOW! ! iif not compiled do it the slow way ! !.iif (TECO-86)^_ ! 0A-32U0 ! convert to uppercase ! !.iif (TECO-86)^_ ! D ! delete lowercase char ! !.iif (TECO-86)^_ ! Q0@I%% ! insert uppercase char ! !.iif (TECO-86)^_ ! R ! backup ! !.iif (TECO-86)^_ ! -1 ! exit with success ! \ ! end load V.str ---------------------------------------------- ! ! --------------------------------------------------------------------- W.str = macro to watch progress Note, /W tested for earlier (other macros are modified by it) W.num has value of /W (0=no, -1=yes) --------------------------------------------------------------------- ! ET&(1024+512)"E ! if no refresh or VTxx scope ! @^UW%V% ! use the V command ! | ! else ! ET&1024"N ! if refresh scope ! @^UW%W% ! use the W command ! | ! else ! 0:W-2"E ! if VT100 in VT52 mode ! 4,0:W^[ ! set VT100 in ANSI ! ' ! endif ! @^UW%-1W% ! W.str = "-1W" (refresh) ! ' ! endif ! ' ! endif ! :@^UW%0UW% ! change screen modified flag ! ! --------------------------------------------------------------------- X.str, 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 then advance past the char --------------------------------------------------------------------- ! @^UX\ ! load X.str ! C ! skip command char ! 0A"W ! if uppercase (most often) ! !.iif 0 ! @O!:C! ! iif not compiled ! :C$^[ ! exit with success ! ' ! endif uppercase ! 0A"D ! if numeric (next most often) ! !.iif 0 ! @O!:C! ! iif not compiled ! :C$^[ ! exit with success ! ' ! endif uppercase ! ! here if lower case, "." or some other punctuation ! !.iif (TECOC) ! 0A-^^."E C ' ! if it's .q (local Q-reg name) skip "."! 0A-QQ"E ! if terminator ! 4MG ! error, unterminated string ! 0F> ! exit with fail ! ' ! endif ! !.iif 0 ! @O!:C! ! iif not compiled don't care about lc ! !.iif (TECO-86) ! :^W$ ! upcase next char ignore success/fail ! !.iif (TECO-86)^_ ! 0A"V ! if lowercase ! !.iif (TECO-86)^_ ! 0A-32U0 ! convert to uppercase ! !.iif (TECO-86)^_ ! D ! delete lowercase char ! !.iif (TECO-86)^_ ! Q0@I%% ! insert uppercase char ! !.iif (TECO-86)^_ ! R ! backup for :C ! !.iif (TECO-86)^_ ! ' ! endif ! !.iif 0 ! !:C! ! iif not compiled ! :C ! exit with success ! \ ! end load X.str ---------------------------------------------- ! ! --------------------------------------------------------------------- 3.str = macro to perform... The character following . is ^ so convert the two characters ^x into the two characters and <1A&63> (Ctrl-x). Note the Ctrl-x character may be Ctrl-[ which is therefore we must use @ format --------------------------------------------------------------------- ! @^U3~ ! Load 3.str ! !.iif (nFR)^_ ! @^U0%@FS`% ! 0.str = @FS` ! !.iif (nFR)^_ ! 24:@^U0%% ! 0.str = @FS`^X ! !.iif (nFR)^_ ! 24:@^U0%% ! 0.str = @FS`^X^X ! !.iif (nFR)^_ ! ^^`:@^U0%% ! 0.str = @FS`^X^X` ! !.iif (nFR)^_ ! 0:@^U0%% ! 0.str = @FS`^X^X` ! !.iif (nFR)^_ ! 1A&63:@^U0%% ! 0.str = @FS`^X^X` ! !.iif (nFR)^_ ! ^^`:@^U0%% ! 0.str = @FS`^X^X`` ! !.iif (nFR)^_ ! M0 ! perform the replacement ! !.iif 0 ! F> ! exit 3.str ! !.iif (nFR) ! @^U0%2@FR`% ! 0.str = 2@FR` ! !.iif (nFR) ! 0:@^U0%% ! 0.str = 2@FR` ! !.iif (nFR) ! 1A&63:@^U0%% ! 0.str = 2@FR` ! !.iif (nFR) ! ^^`:@^U0%% ! 0.str = 2@FR`` ! !.iif (nFR) ! M0 ! perform the replacement ! ~ ! end load of 3.str ! ! --------------------------------------------------------------------- 4.str = macro to replace the character following . with --------------------------------------------------------------------- ! ! Load 4.str ! !.iif (nFR)^_ ! @^U4%@FS`% ! @FS` ! !.iif (nFR)^_ ! ^^X&63:@^U4%% ! @FS`^X ! !.iif (nFR)^_ ! ^^`:@^U4%% ! @FS`^X` ! !.iif (nFR)^_ ! 27:@^U4%% ! @FS`^X` ! !.iif (nFR)^_ ! ^^`:@^U4%% ! @FS`^X`` ! !.iif 0 ! @O!U4ok! ! if not compiled ! !.iif (nFR) ! @^U4%1@FR`% ! 1@FR` ! !.iif (nFR) ! 27:@^U4%% ! 1@FR` ! !.iif (nFR) ! ^^`:@^U4%% ! 1@FR`` ! !.iif 0 ! !U4ok! ! if not compiled ! ! --------------------------------------------------------------------- Getting ready to startup the squish process Prior to starting let's see what type of TECO commands we have. This is so we can calculate the conditional assembly directives. The conditional assembly parser will be placed into 5.str and will be called any time we pull in a new buffer of data. It's function is to evaluate the .iif expressions and take the apropriate course of action Conditional assembly directives must appear on the left margin as a comment as follows: --------------------------------------------------------------------- ! !.iif 0 ! $ ! comments ! ! --------------------------------------------------------------------- where 0 can be replaced with a numeric expression (including keywords) and $ can be replaced with TECO commands. The expression is evaluated (after replacement of keywords) and if the result is 0 the entire .iif line will be removed. If the result is non-zero then only the .iif comment will be removed. The keywords that can be used evaluate to -1 if true or 0 if false (TECO-10) if PDP-10 TECO (TECO-11) if PDP-11 TECO (TECOC) if DECUS TECOC (TECO-86) if TECO-86 As of this writing we will make (TECO-10)=(TECO-11)=(TECOC) (VT52) (ET&512"N-1'+0) (if VT52 scope support) (VT61) (ET&512"N0:W-1"E-1''+0) (VT100) (ET&512"N0:W+2&6"N-1''+0) (either VT52 or ANSII) (VT11) (ET&1024"N-1'+0) (if "refresh" scope) (nO) if nOtag0,tag2,...$ available (computed goto) (n^V) if change n chars from pointer to lower case avail. (n^W) if change n chars from pointer to upper case avail. (nFR) if nFRtext$ (replace n chars from . with text) --------------------------------------------------------------------- ! @^U5~ ! load 5.str ------------------------------------------ ! [0 [1 [2 [3 ! save some registers ! [W ! (W.num gets trashed if /W:Y) ! J ! beginning of buffer ! < ! begin outer loop (search for .iif) ! :@N\!.iif^ES\; ! find next conditional else escape loop ! 0^Q+^S"N ! if not at beginning of line ! F< ! ignore it ! ' ! endif ! MW ! if we are watching ! .+^SU1 ! rember start of line with condition ! .U2 ! rember start of expression ! :@S\^ES!\"F ! if no end of conditional ! 4MG ! ?Unterminated string ! @O!FAIL! ! take failure exit ! ' ! end if ! Q2,.+^SX2 ! place conditional expression into 2.str ! 0X3 ! place the .iif comment into 3.str ! ::@S\^ES\$ ! throw out possible ! .U2 ! remember end of .iif comment ! ZJ ! go to end of buffer ! .U3 ! Save current Z position ! G2 ! place the expression at the end of the buffer ! 1ED ! ^ means ^ in search ! < ! start inner loop ! Q3J ! go to start of expression ! ~ ! end load of 5.str (first part) ! ! --------------------------------------------------------------------- Now resources are available (TECO-10) if PDP-10 TECO (TECO-11) if PDP-11 TECO (TECOC) if DECUS TECOC (TECO-86) if TECO-86 As of this writing we will make (TECO-10)=(TECO-11)=(TECOC) --------------------------------------------------------------------- ! :@^U5%:@FS~(TECO-10)~(TECOC)~"SF<'% :@^U5%Q3J :@FS~(TECO-11)~(TECOC)~"SF<'% :@^U5%Q3J :@FS~(TECOC)~(% EO&255-86"E ! if TECO-86 ! :@^U5%0% ! TECOC = 0 ! | ! else ! :@^U5%-1% ! TECOC = -1 ! ' ! endif ! :@^U5%)~"SF<'% :@^U5%Q3J :@FS~(TECO-86)~(% EO&255-86"E ! if TECO-86 ! :@^U5%-1% ! TECO-86 = -1 ! | ! else ! :@^U5%0% ! TECO-86 = 0 ! ' ! endif ! :@^U5%)~"SF<'% ! (VT52) (ET&512"N-1'+0) (if VT52 scope support) ! :@^U5%Q3J :@FS~(VT52)~(% ET&512"N ! if VT52 ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% ! (VT61) (ET&512"N0:W-1"E-1''+0) ! :@^U5%Q3J :@FS~(VT61)~(% ET&512"N0:W-1"E ! if VT61 ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% ! (VT100) (ET&512"N0:W+2&6"N-1''+0) (either VT52 or ANSII) ! :@^U5%Q3J :@FS~(VT100)~(% ET&512"N0:W+2&6"N ! if VT100 ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% ! (VT11) (ET&1024"N-1'+0) (if "refresh" scope) ! :@^U5%Q3J :@FS~(VT11)~(% ET&1024"N ! if VT11 ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% ! (nO) if nOtag0,tag2,...$ available (computed goto) ! :@^U5%Q3J :@FS~(nO)~(% 1@O!0,1! !0,1! :@^U5%0% ! 0 ! @O!No nO! !1! :@^U5%-1% ! -1 ! !No nO! :@^U5%)~"SF<'% ! (n^V) if change n chars from pointer to lower case avail. ! :@^U5%Q3J :@FS~(n^V)~(n^W)~"SF<'% ! (n^W) if change n chars from pointer to upper case avail. ! :@^U5%Q3J :@FS~(n^W)~(% @I%X% ! insert upper case X ! R ! back over it ! ^V ! convert X to x ! 0A"V ! if lower case ^V worked ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% D ! delete the x ! ! (nFR) if nFRtext$ (replace n chars from . with text) ! :@^U5%Q3J :@FS~(nFR)~(% @I%XY% ! put XY into buffer ! 2R ! backup ! .U0 ! save here ! @S%X% ! position between the X and Y ! 1@FR%% ! if nFR available Y goes away else X goes away ! Q0J ! back in front of X or Y ! 0A-^^X"E ! if its X we have nFR ! :@^U5%-1% ! -1 ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% D ! delete the X or Y ! ! (::D) if anchored delete avail. ! :@^U5%Q3J :@FS~(::D)~(% .U0 ! save here ! @I%XX% ! put XX into buffer ! Q0,Q0+1::D ! delete the first X ! Q0-."N ! if m,n::D worked in anchored way ! :@^U5%-1% ! -1 ! R ! backup over other X ! | ! else ! :@^U5%0% ! 0 ! ' ! endif ! :@^U5%)~"SF<'% D ! delete the x ! :@^U5~ 0; ! exit loop, condition expression has been parsed ! > ! end of loop ! 0ED ! back to ^ means Ctrl in search ! Q3,ZX2 ! place expression into 2.str ! Q3,ZK ! delete the expression ! ! --------------------------------------------------------------------- now before and after the evaluation of the expression we will build into the edit buffer and then into 3.str a loop that will test for all identical .iif statements and perform the same edit task. This will be much faster than re-evaluating identical expressions. Note, that one might be tempted to use a :S^EQ3$ in this macro. However, the .iif expression may at times contain the ^ character as in ^_ (not) therefore the search must be made with ED&1 set (^ means ^) --------------------------------------------------------------------- ! @I\<:S\ ! Q3,Z = <:S loop, :Search ! G3 ! Q3,Z = <:S(.iif comment) Same conditional ! 27@I\\ ! Q3,Z = <:S(.iif comment)$ end of string ! @I\;0^Q+^S"E\ ! Q3,Z = <:S(.iif comment)$;0^Q+^S"E if at left margin ! Q3,ZX3 ! store this part of command loop into 3.str ! Q3,ZK ! delete the partial command loop ! Q1J ! go to start of line with conditional ! M2"E ! if expression = 0 ! K ! kill line with conditional ! MW ! refresh screen if we are watching ! :@^U3\^SC\ ! <:S(.iif comment)$;0^Q+^S"E^SC ! | ! else ! .,Q2K ! kill just the conditional comment ! MW ! refresh screen if we are watching ! :@^U3\.+^SU2\ ! <:S(.iif comment)$;0^Q+^S"E.+^SU2 2.num=beg. line ! :@^U3%::S% ! <:S(.iif comment)$;0^Q+^S"E.+^SU2::S anchored search ! ^^E&63:@^U3%% ! <:S(.iif comment)$;0^Q+^S"E.+^SU2::S<^E> match ! :@^U3%S% ! <:S(.iif comment)$;0^Q+^S"E.+^SU2::S<^E>S ! 27:@^U3%% ! <:S(.iif comment)$;0^Q+^S"E.+^SU2::S<^E>S ! :@^U3%$Q2,.%! <:S(.iif comment)$;0^Q+^S"E.+^SU2::S<^E>S$Q2,. ! ' ! endif ! :@^U3%KMW'>% ! kill, refresh, endif, end loop ! 1ED ! set search mode to uparrow means uparrow ! M3 ! perform same operation on all like conditionals ! 0ED ! set search mode to uparrow means Ctrl-ize ! Q1J ! go to start of line with 1st conditional ! MW ! if we are watching ! > ! end loop, all conditionals are taken care of ! !SUCCESS! -1 ! return success ! !FAIL! +0 ! return failure ! ]W ]3 ]2 ]1 ]0 ! restore registers ! ~ ! end load of 5.str ! ! --------------------------------------------------------------------- 6.str = macro to overstrike character with input value nM6 overstrikes character at right of . with ASCII(n) Note n MUST not be --------------------------------------------------------------------- ! @^U6~ ! Load 6.str ! U0 ! save character ! !.iif (nFR)^_ ! @^U0%FS% ! 0.str = FS ! !.iif (nFR)^_ ! 24:@^U0%% ! 0.str = FS^X ! !.iif (nFR)^_ ! 27:@^U0%% ! 0.str = FS^X$ ! !.iif (nFR)^_ ! Q0:@^U0%% ! 0.str = FS^X$ ! !.iif (nFR)^_ ! 27:@^U0%% ! 0.str = FS^X$$ ! !.iif (nFR)^_ ! M0 ! perform the replacement ! !.iif 0 ! F> ! exit 6.str ! !.iif (nFR) ! @^U0%1FR% ! 0.str = 1FR ! !.iif (nFR) ! Q0:@^U0%% ! 0.str = 1FR ! !.iif (nFR) ! 27:@^U0%% ! 0.str = 1FR$ ! !.iif (nFR) ! M0 ! perform the replacement ! ~ ! end load of 6.str ! ! --------------------------------------------------------------------- 8.str = macro to overstrike char with --------------------------------------------------------------------- ! !.iif (nFR)^_ ! @^U8%FS% ! 8.str = FS ! !.iif (nFR)^_ ! ^^X&63:@^U8%% ! 8.str = FS^X ! !.iif (nFR)^_ ! 27:@^U8%% ! 8.str = FS^X$ ! !.iif (nFR)^_ ! 0:@^U8%% ! 8.str = FS^X$ ! !.iif (nFR)^_ ! 27:@^U8%% ! 8.str = FS^X$$ ! !.iif 0 ! @O!U8slow! ! iif not compiled ! !.iif (nFR) ! @^U8%1FR% ! 8.str = 1FR ! !.iif (nFR) ! 0:@^U8%% ! 8.str = FR ! !.iif (nFR) ! 27:@^U8%% ! 8.str = FR$ ! !.iif 0 ! !U8slow! ! iif not compiled ! ! --------------------------------------------------------------------- Z.str = Squish main loop macro --------------------------------------------------------------------- ! @^UZ` ! load of Z.str ! < ! loop ! 0A^_; ! exit loop if end of buffer ! 0A-QQ"N ! if not quit time ! @^UY%M% ! insert the M part of Mq ! 0A ! char code of next char ! Q9 ! index 9.str by char code and get char code ! :@^UY%% ! append 9.str to Y.str, we now have q of Mq ! MY; ! do process, escape on error ! F< ! go to top of loop ! ' ! end if not quit time ! QM"N ! if current @ not satisfied ! 4MG ! unterminated string ! !.iif 0 ! @O!FAIL! ! iif not compiled ! 0$^[ ! take fail exit ! ' ! endif ! ]Q ! get previous level quit ! ]1 ! get previous level 1st ! ]M ! get previous level @ flag ! QM"N ! if @ pending ! QE"F ! if not pending ! .U2 ! save . of ending ! Q1+1,.:@FB~^[~"F ! if not found in text ! QMJ ! position to @ ! M8 ! replace @ with ! Q1J ! position to 1st ! M8 ! replace with ! Q2J ! position to last ! M4 ! replace with ! | ! elseif found in text ! Q2J ! reposition to 2nd ! C ! +1 ! ' ! endif not found in text ! 0UM ! clear @ pending ! ^N"T F< ' ! iif end-of-file, condinue ! .+.-Z"L F< ' ! iif processed less than Z/2 ! QQ"L ! if looking for end of buffer ! M5 ! squish marked text ! ' ! endif ! F> ! continue ! ' ! endif not pending ! ' ! endif @ pending ! C ! position after or ! > ! main loop end---------------------------------------- ! 0A"L ! if end of buffer ! QQ"G ! if still looking for something ! 1MG ! End of buffer while sub squishing ! !.iif 0 ! !FAIL! ! iif not compiled ! 1 ! 1-1=0=fail ! ' ! end if still looking for something ! ' ! end if end of buffer ! -1 ! success ! ` ! end Load of Z.str ! ! --------------------------------------------------------------------- Done loading squisher macro into Q-register Z --------------------------------------------------------------------- --------------------------------------------------------------------- S t a r t H e r e --------------------------------------------------------------------- ! Z"E ! if no command line in buffer ! @^A%Enter your macro then type MZ$$ % ! 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] All the switches have been stripped 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 0 with "EWfilename$" to open it for output and remove the output filename from the buffer. --------------------------------------------------------------------- ! J ! jump to start of buffer ! :@FS~=~~"F ! if "=" not found ! :@S~.~"S ! if ".", file type ! R ! position in front of . ! | ! else ! ZJ ! to end of buffer ! ' ! endif ! 0X0 ! get file name ! 0J ! to start of buffer ! G0 ! make copy of it ! @I~.TEC~ ! append ".TEC" ! .U0 ! update = position ! | ! else "=" found ! .U0 ! update = position ! -:@S~.~"U ! if "." not found ! Q0J ! back to position ! @I~.TEC~ ! append ".TEC" ! .U0 ! update = position ! ' ! endif ! Q0J ! back to position ! ' ! endif ! @^U0%EW% ! 0.str = "EW" ! 0,Q0:X0 ! 0.str = "EWfilename[.TEC]" ! 27:@^U0%% ! append ESC to 0.str ! Q0J ! position where the input is ! :@S~.~"U ! if no ".", no file type ! ZJ ! go to end of buffer ! @I~.TES~ ! append ".TES" ! ' ! endif ! @^U1%:ER% ! 1.str = ":ER" ! Q0,Z:X1 ! 1.str = ":ERfilespec[.TES] ! 27:@^U1%% ! append ESC to 1.str ! ET&64"E ! if not detached ! @^A~Opening "~ ! display Opening " ! Q0,ZT ! display infilespec ! @^A~" ~ ! display " ! ' ! endif ! M1"U ! open input file, if fail ! @^A~Open failed ~ ^C ! abort ! ' ! endif ! ET&64"E ! if not detached ! @^A~Creating "~ ! display Creating " ! 0,Q0T ! display outfilespec ! @^A~" ~ ! display " ! ' ! endif ! M0 ET&64"E ! if not detached ! @^A~Squishing "~ ! display squish message" ! Q0,ZT ! display infilespec ! @^A~" ~ ! display " ! ' ! endif ! HK Y ! yank 1st page ! 128,0ET ! turn off abort-on-error ! 0J ET&64"E ! if not detached ! @^A~Conditional assembly pass... ~ ' ! end if not detached ! M5"F ! remove .iif conditionals ! ^C ' EC ! close out first pass ! G0 ! get the EWfile$ ! J @FS%W%B% ! change the W to B ! HX0 ! back to 0.str ! HK ! kill buffer ! M0 ! re-open file ! ET&64"E ! if not detached ! @^A~Squish pass... ~ ' ! end if not detached ! ! --------------------------------------------------------------------- Now that .iif's have been processed 5.str is available. We will use 5.str to contain a macro used in the comment process and used as a cleanup process. This macro will do the block deletes of the comments, deletes of s and do any line breaks (/L:nn). A block delete is indicated by: <255>[text] Line breaks, if any, will only occure where block deletes were located. --------------------------------------------------------------------- ! @^U5* ! Load 5.str ---------------------------------- ! 254@I%% ! insert breaking line position ! J ! go to start of buffer ! 0X0 ! kill out text in 0.str ! < ! loop ! .US ! remember positon before search ! * ! suspend load of 5.str ----------------------- ! :@^U5%:S% ! :S ! 0:@^U5%% ! :S"<0> ! 27:@^U5%% ! :S<0>$ find 1st <0> quickly ! :@^U5%;0A"ERS% ! :S<0>$;0A"ERS if next is null, backup ! 5:@^U5%% ! :S<0>$;0A"ERS^E ! :@^U5%M% ! :S<0>$;0A"ERS^EM ! 0:@^U5%% ! :S<0>$;0A"ERS^EM<0> ! 27:@^U5%% ! :S<0>$;0A"ERS^EM<0>$ span nulls ! :@^U5%'% ! :S<0>$;0A"ERS^EM<0>$' span nulls ! :@^U5* ! continue Load 5.str ------------------------- ! QS,.+^S:X0 ! append text to 0.str ! * ! suspend load of 5.str ----------------------- ! QW"T :@^U5~%W-16"GMW'~ ' ! iif /W:Y display as we go ! :@^U5* ! continue Load 5.str ------------------------- ! 0A-255"N ! if NOT block delete ! F< ! go back to loop start ! ' ! endif ! * ! suspend load of 5.str ----------------------- ! QL"G ! if line limit ! :@^U5* ! continue Load 5.str ------------------------- ! 254:@^U0%% ! line break marker ! * ! suspend load of 5.str ----------------------- ! ' ! endif line limit ! :@^U5* ! continue Load 5.str ------------------------- ! < ! loop for possible multiple block del ! * ! suspend load of 5.str ----------------------- ! :@^U5%S% ! S ! 0:@^U5%% ! S<0> ! 27:@^U5%% ! S<0>$ find 1st <0> quickly ! :@^U5%0A"ERS% ! S<0>$0A"ERS if next is null, backup ! 5:@^U5%% ! S<0>$0A"ERS^E ! :@^U5%M% ! S<0>$0A"ERS^EM ! 0:@^U5%% ! S<0>$0A"ERS^EM<0> ! 27:@^U5%% ! S<0>$0A"ERS^EM<0>$ span nulls ! :@^U5%'% ! S<0>$0A"ERS^EM<0>$' span nulls ! :@^U5* ! continue Load 5.str ------------------------- ! 0A-255"N ! if NOT block delete ! 0; ! exit loop ! ' ! end if NOT block delete ! > > ! end loop ! * ! suspend load of 5.str ----------------------- ! QL"G ! if no line limit ! :@^U5* ! continue Load 5.str ------------------------- ! 254:@^U0%% ! insert position marker ! * ! suspend load of 5.str ----------------------- ! ' ! endif line limit ! :@^U5* ! continue Load 5.str ------------------------- ! 0,QSK ! kill the front trash ! G0 ! bring in the squished text ! -1A-254"ER' ! iif line break preceeds . backup 1 char ! .US ! QS has moved ! * ! suspend load of 5.str ----------------------- ! QL"G ! if line limit ! :@^U5* ! continue Load 5.str ------------------------- ! ! --------------------------------------------------------------------- Now wherever there is a <254> delete it but also test for line break --------------------------------------------------------------------- ! J ! start of buffer ! < ! Loop ! * ! suspend load of 5.str ! :@^U5%:FD% ! :FD find next... ! 254:@^U5%% ! :FD<254> ! 27:@^U5%% ! :FD<254>$ ! :@^U5* ; ! :FD<254>$; continue load of 5.str ! .UT ! remember last known <254> ! 0^Q-QL"L ! if line shorter than limit ! .US ! this becomes new break spot ! F< ! continue ! ' ! endif line .GE. than limit ! QSJ ! go to break position ! @I~ ~ ! insert ! 2%TJ ! position to continuation point ! .US ! indicate valid break spot ! * ! suspend load of 5.str ! QW"T ! if /W:Y display ! :@^U5* ! continue load of 5.str ! MW ! display only at line breaks ! * ! suspend load of 5.str ! ' ! endif ! :@^U5* ! continue load of 5.str ! > ! End of Loop ! QTJ ! position to continuation point ! * ! suspend load of 5.str ! ' ! endif line limit ! :@^U5* ! continue load of 5.str ! ^E"T ! if formfeed flag ! .US ! remember . ! ZJ ! jump to buf end ! 12@I%% ! insert ! QSJ ! back to where we were ! ' ! endif ! A ! append more to buffer ! * ! End Load of 5.str ------------------------------------------- ! QW"T ! if /W:Y display ! :@^U5* ! continue load of 5.str ! MW ! display only at line breaks ! * ! suspend load of 5.str ! ' ! endif ! ! Continue on with start of file process ! Y ! fill up the first buffer ! MW ! display ! MZ"S ! if squeeze ok ! ZJ ! end of buffer ! M5 ! perform final squish ! MW ! display ! EX ! exit ! ' ! endif MZ ok ! ' ! endif file squeeze !