!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 ! ! 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 @^Qtext, and 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 ! ! , the squisher uses the first character in the 9.str mask ! ! as a label to goto which handles '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 -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 ! ' ! 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 ! 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 ! ' ! 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 ! ! , , 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 ! 10^T ! display ! :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 (1Bh) ! ' ! endif ! Q0-27"E ! if char is ! 13^T ! display ! 10^T ! display ! @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 ! 13^T ! display ! @O!DONE! ! go down to DONE ! ' ! endif ! Q0-13"E ! if char is ! ^T^[ ! suck up of - 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) ? % ^^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 , ! ! , and 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) ? % ^^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 , , and 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 , ! ! , and 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) ? % ^^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 marked as B and 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 and . ! ! ! ! Note: we only have entries for to 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) ? % ^^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) ? % ^^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 = ! 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{|}% ! :@^U9%.LLLLLLLLLLLLLLLLLLLLLLLLLL....D% ! --------------------------------------------------------------------- ! ! Load Q-register 8 with potential characters in case ESC can't ! ! be used. We initially load 8.str with the preferred delimiters: ! ! ! ! / # * & \ ? ( ) $ @ ! ! ! ! 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) ? % ^^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 *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. ! ! --------------------------------------------------------------------- ! @^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) ? / ^^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) ? % ^^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 ^[ (), we ! ! have to be careful about creating adjacent '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 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 ! 0; ! break out of loop ! | ! else (it is ) ! -.; ! break if .==0 ! -1A-128-13"N ! if not ! 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 ! ' ! endif ! ' ! endif ! ' ! endif ! Q0@I%% ! insert ^char ! @O!DISP! ! try again ! ! --------------------------------------------------------------------- ! ! handle 'B'. we've run into the 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 ! ' ! endif ! @O!..! ! jump to main loop ! ! --------------------------------------------------------------------- ! ! handle 'O'. we've run into , , or 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 = ! Q0-13"E ! if curr char is ! -2D ! delete ! | ! else ! @O!..! ! jump to main loop ! ' ! endif ! ' ! endif ! ' ! endif ! ' ! endif ! Q0#128@I%% ! insert char w/hi bit ! Q0-13"E ! if char is ! .-Z"E ! if at end of buffer ! 10@I%% ! insert ! R ! back up one char ! ' ! endif ! 0A&127-10"E ! if curr char is ! D ! delete it ! ' ! endif ! 10@I%% ! insert ! ' ! 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 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 @^Uqtext ! @O!$$! ! goto $$ ! ' ! endif ! | ! else ! 0A-27"E ! if ^Uq ! @O!$$! ! goto $$ ! ' ! endif ! ' ! endif ! .US ! S.num = current buf ptr ! Q1"T ! if @-modifed ! 0A@^U1%% ! 1.str = ! D ! delete ! ' ! endif ! :QW"N ! if /W was TRUE ! :@S%^EQ1%"U ! if search for 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 ! T ! display rest of line ! ' ! endif ! 7^T ! display ! 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 in buf ! R ! back up one char ! ::@S%^EGK%"S ! if is non-squish ! -D ! delete ! ^^NU0 ! 0.num = N ! | ! else ! D ! delete ! ^^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-^^"E if we've run into ! ! 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 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 ). ! ! --------------------------------------------------------------------- ! !$! 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 's). ! ! --------------------------------------------------------------------- ! !$$! .US ! S.num = start of text ! Q1"T ! if @-modified ! 0A@^U1%% ! 1.str = ! D ! delete ! ' ! 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 fails ! @O!STRINGFAIL! ! unterminated string ! ' ! endif ! ! --------------------------------------------------------------------- ! ! $$$$, entry point for the ^U routine after we've sub-squished a ^U ! ! macro. ! ! --------------------------------------------------------------------- ! !$$$$! -D ! delete trailing ! .UT ! T.num = end of text ! 27U0 ! 0.num = ESC (default ! ! --------------------------------------------------------------------- ! ! At this point, we have to output a delimited string. ! ! ! ! 0.num = ! ! C.num = start of command ! ! S.num = start of text ! ! T.num = end of text ! ! ! ! --------------------------------------------------------------------- ! !AA! Q0@^U0%% ! 0.str = char ! QT-QS"G ! if string is not-empty ! QSJ ! jump to start of string ! .,.+QT-QS:@FB%^EQ0%"S ! if is in string ! ! ----------------------------------------------------- ! ! find a 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 = to use ! QSJ ! jump to start of string ! Q0@I%% ! insert ! 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 ! 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 -^, 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 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 ! ! Fx text ! ! Fx text1 text2 ! ! ! ! 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 , delete it, and set T.num to be the start of text2. we ! ! then look for the 2nd , 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 = ! D ! delete ! ' ! endif ! :@S%^EQ1%"U ! if search for 1st delim fails ! @O!STRINGFAIL! ! unterminated string ! ' ! endif ! -D ! delete 1st ! .UT ! T.num = start of text2 ! :@S%^EQ1%"U ! if search for 2nd delim fails ! @O!STRINGFAIL! ! unterminated string ! ' ! endif ! -D ! delete 2nd ! .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 ! ' ! 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 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 char, it's index is in 0.num ! ! --------------------------------------------------------------------- ! Q0Q1U0 ! 0.num = Q0th char of Q1 ! QSJ ! jump to start of text1 ! Q0@I%% ! insert ! 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 ! QU-QTC ! advance to end of text2 ! Q0@I%% ! insert ! 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 comment 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 = ! D ! delete ! ' ! endif ! :@S%^EQ1%"U ! if search for fails ! @O!STRINGFAIL! ! unterminated string ! ' ! endif ! -D ! delete second ! .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 ! .UC ! C.num = current buf ptr ! Q0@^U1%% ! 1.str = exclamation point ! Q1"T ! if @-modified ! 0A@^U1%% ! 1.str = ! D ! delete ! ' ! endif ! :@S%^EQ1%"U ! if search for 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 -Z ! ! --------------------------------------------------------------------- ! !Z! -D ! delete -Z ! @I%^Z% ! insert -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: ! ! ! ! from squished .= ! ! | ! ! | ! ! ! ! --------------------------------------------------------------------- ! !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 ! 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 ! ' ! 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 , 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 ! D ! delete it ! ' ! endif ! D ! delete ! .-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 ! ' ! endif ! @I% % ! insert ! ' ! endif ! > ! ----loop end----------------- ! ! ----------------------------------------------------- ! ! the following loop deletes trailing CR's, LF's, and ! ! '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 ? ! 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 ! ' ! endif ! -1A-10"N ! if prev char is not ! 10@I%% ! insert ! ' ! endif ! R ! back up one char ! ."E ! if at beginning of buf ! 13@I%% ! insert ! ' ! endif ! -1A-13"N ! if prev char is not ! 13@I%% ! insert ! ' ! 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 " ! / ! 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 " ! ' ! 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 ! ' ! 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 ! ' ! 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 ! ' ! 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 !