diff --git a/README.md b/README.md index 5e8c9abf..d5d2a016 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ from scratch. - CHTN, CFTP, Chaosnet TELNET and FTP support - FIND, search for files. - TTLOC, Advertises physical location of logged in users + - SRCCOM, Compares/merges source files, compares binary files 6. A brand new host table is built from the host table source and installed into SYSBIN; HOSTS3 > using H3MAKE. diff --git a/build/build.tcl b/build/build.tcl index e4c5c436..6edcc82b 100644 --- a/build/build.tcl +++ b/build/build.tcl @@ -424,6 +424,9 @@ respond "*" ":link sys2;ts chtn,sysbin;supdup bin\r" respond "*" ":midas sys;ts ttloc_sysen1;ttloc\r" expect ":KILL" +respond "*" ":midas sys;ts srccom_sysen2;srccom\r" +expect ":KILL" + respond "*" ":link kshack;good ram,.;ram ram\r" respond "*" ":link kshack;ddt bin,.;@ ddt\r" respond "*" $emulator_escape diff --git a/doc/info/srccom.9 b/doc/info/srccom.9 new file mode 100644 index 00000000..79988f85 --- /dev/null +++ b/doc/info/srccom.9 @@ -0,0 +1,519 @@ +SRCCOM command strings look like _, +Just , outputs to the terminal. defaults +to except that the 2nd filename defaults to ">". + +SRCCOM switches are: + +/digit number of consecutive matching lines it takes to tell + SRCCOM that the changes have stopped. +/@ Indirect. Take switches and file name from a previous + SRCCOM output file. Must go with output file or 1st input. +/A Archive. Concatenate the differences to the front of the + output file instead of overwriting it. +/B don't ignore Blank lines. +/C ignore Comments. +/D Disown self and keep running, logging out when finished. +/E follow each run of changed lines with the next (unchanged) + line, if any. +/F output a copy of file 2, with changed lines Flagged. +/I automatic merge mode. +/K ignore differences in Kase. +/L try to detect Labels (MIDAS style). +/M Manual Merge Mode. +/S ignore differences in Spacing. +/W say Which file (1 or 2) on each line of changes +/X eXecute commands from a file. +/Y try to detect labels, in a general way. +/! Force comparison even if the two filespecs specify the + same file. +/# Do binary compare of files. +/$ Do binary compare of executable file address space. This should + be the first thing (preceding filenames). + +For further details, or for an introductory description, +do :INFO SRCCOM + + +File: SRCCOM Node: TOP Up: (DIR) Next: Generalities + +SRCCOM is a program for comparing or merging similar ascii text files; +for example, two versions of the same program. + +You can see the whole documentation file in INFO now by typing +a series of "N"'s. + +* Menu: + +* Gen: Generalities Overview of using SRCCOM + +* Com: Commands Details of SRCCOM command lines + +* Switch: Switches Commands contain switches which say what + sort of comparison and output is wanted + +* Smart: Smart Telling SRCCOM to ignore certain kinds of changes + +* Format: Format Requesting optional info in the output file + +* Merge: Merge Merging two input files (manual or automatic) + +* Binary: Binary Comparing binary file + +* Archive: Archive Keeping an archival record of changes of one + file, from version to version. + +* Xfile: Com Files Taking commands from a file + +* Output: Output What everything in a SRCCOM output file means. + +File: SRCCOM, Node: GENERALITIES, Up: Top, Previous: Top, Next: Commands + +What you can do with SRCCOM: + +Comparing produces a file listing the places where the two input files +differ, and what text each file has. There are two methods of merging: +one finds each place where the input files differ, prints out each +file's version, and asks the user to choose between them for the +merge file. The other produces automatically a file in which each +point of difference has the two alternate versions both present and +identified by which file they came from. Searching for *** will find +all of them. It is also made easy to compare two files and append +the differences to the front of a CMPARC file - this is good for +keeping a record of all changes in a program from version to version. + +If SRCCOM is given a command via DDT, as in :SRCCOM , +SRCCOM will execute the one command and then commit suicide, +if there was no error. If SRCCOM is run without a command, as +in SRCCOM^K, it will read commands from the terminal, prompting for +each one with a "*", until a command ending in "^C" is typed, or +SRCCOM is otherwise exited. A command ending in ^C is executed +normally, but when it is finished SRCCOM will commit suicide. + +Whenever SRCCOM reads input from the terminal, cancels one +character, and ^U cancels a whole line. + +The easiest thing to do with SRCCOM is to compare two files and type the +differences on the terminal. Just give the command + +:SRCCOM , + +to do this. + +At the bottom of the page on the terminal, SRCCOM will print +"--MORE--" (unless :TCTYP NOMORE or ^_M was used to turn off +this feature). At that point, the user has these alternatives: + space -- causes SRCCOM to continue typing. + ^C -- causes SRCCOM to kill itself. + rubout -- causes the rest of the current set of differences + not to be printed. + other -- is like rubout, but remains in the input buffer + acting as normal input. It will eventually be + read by SRCCOM, or some other program. + +File: SRCCOM, Node: COMMANDS, Up: Top, Previous: Generalities, Next: Switches + +Details of Command Strings: + +A command string for SRCCOM should have the format + + _, + +or + + _ + +where is the output file spec, +and and are the input file specs. +Switches, preceded by slashes, may also be present in between names. +The short form is an abbreviation causing to be completely +defaulted. + +The filename defaults are as follows: +the SNAME default is sticky, starting out as the user's MSNAME. +The FN1 default is also sticky, but at least one FN1 must be +specified in the command line, unless no device needs one, +and the output FN1 will default to the real FN1 of the first input +file, or that of the second in the case that the first is on a +non-directory device. +The device default starts as DSK: for the input files, and is sticky. +For the output file, it is DSK:. +The input fn2's default individually to ">". +The output fn2 defaults to "COMPAR" normally, but in merge +mode the default is ">", and when /A is specified the default +is "CMPARC". In /F mode, the default is "FLAGGD". + +if the output device is to be TTY:, that can be specified +by omitting the output spec and the backarrow ("_"), thus: + + , or + + + +Command String Examples: + +_SYSENG;TECO < compares SYSENG;TECO < with SYSENG;TECO >, + and outputs to ;TECO COMPAR. +FOO;UGH CMP_SYSENG;TECO 500,^X501 + compares SYSENG;TECO 500 with SYSENG;TECO 501, + and outputs to FOO;UGH CMP. +FOO;_BLETCH,MUMBLE compares FOO;BLETCH > with FOO;MUMBLE >, + and outputs to FOO;MUMBLE COMPAR. + +File: SRCCOM, Node: SWITCHES, Up: Top, Previous: Commands, Next: Smart + +Switches: + +Switches are used to select a mode of operation (merging verses +comparison, for example), and to enable bells and whistles. They +are all explained in more detail in the following sections. +Each switch in this list is the name of a footnote that leads to +the node containg the description of the switch. +The switches are: + +/digit number of consecutive matching lines it takes to tell + SRCCOM that the changes have stopped. *Note /digit: Smart +/@ Indirect. Take switches and file name from a previous + SRCCOM output file. *Note /@: Archive +/A Archive. Concatenate the differences to the front of the + output file instead of overwriting it. + *Note /A: Archive +/B don't ignore Blank lines. *Note /B: Smart +/C ignore Comments. *Note /C: Smart +/D Disown self and keep running, logging out when finished. +/E follow each run of changed lines with the next (unchanged) + line, if any. *Note /E: Format +/F output a copy of file 2, with changed lines Flagged. + *Note /F: Format +/I automatic merge mode. *Note /I: Merge +/K ignore differences in Kase. *Note /K: Smart +/L try to detect Labels (MIDAS style). *Note /L: Format +/M Manual Merge Mode. *Note /M: Merge +/S ignore differences in Spacing. *Note /S: Smart +/W say Which file on each line of changes *Note /W: Format +/X eXecute commands from a file. *Note /X: Com File +/Y try to detect labels, in a general way *Note /Y: Format +/# Binary compare (word by word) *Note /#: Binary +/$ Binary compare of executable files *Note /$: Binary +/! Force comparison even if the two filespecs specify the + same file. If you ask to compare FOO < and FOO > when there + is only one version of FOO, SRCCOM will normally see this + instantly and just say "NO DIFFERENCES ENCOUNTERED". + This switch would force a comparison. I am not sure + if it is ever necessary; I put it in to make sure nobody + would be screwed by the feature. + +File: SRCCOM, Node: SMART, Up: Top, Previous: Switches, Next: FORMAT + +More Intelligent Comparison -- /C: + +/C causes differences in the text of comments to be ignored, but +only when they are isolated. In other words, if a whole run of +differences, preceded and followed by matching lines, consists of +nothing but changes in comments, it is ignored, but changes in +comments are not ignored when other, more serious, changes are nearby. + +Unless /B was specified, lines containing nothing but comments will +be treated as blank lines and will be ignored if inserted or deleted. + + + +Less Stringent Comparison -- /K, /S: + +/K causes SRCCOM to ignore differences in case, so that "a" and +"A" will be considered identical. /S causes SRCCOM to ignore changes +in spacing (and tabs, as well), so that MOVE A and MOVE A will +be considered identical. Unlike comment changes, spacing and case +changes are ignored even if there is a more serious change nearby. +However, if the space- or case-changed lines are actually printed +because of more serious changes, the space or case changes will be +visible in the printout. The intent is to allow comparison of files +which have been thoroughly reformatted or converted from all upper +case to all lower case. + +If /S has been specified, and /B has not been (blank lines are still +ignored), then a line containing nothing but spaces is considered +blank and its insertion or deletion is ignored. If /S and /C are +both specified, lines containing only spaces and comments are +ignored. + + + +Less Intelligent Comparison -- /B: + +/B causes SRCCOM not to ignore blank lines. More precisely, +SRCCOM normally considers all sequences of ^J's, ^L's and ^M's +equivalent. /B disables that. /B is automatically implied +by /I or /M, to prevent blank lines from being lost in the merging +process. /B is also useful if the difference file is to be read +by some other program that will process the input files with it. + + +"In Phase" Criterion -- /digit: + +Normally, SRCCOM does not consider that a run of changes has +ended just because it finds a pair of lines that match. There +have to be three lines in a row from both files, matching. You +can change the number of lines in a row that have to match by +specifying /1 ... /9, /3 thus being the default. The time when +it may help to increase the number of consecutive matching lines +required is when SRCCOM is confused by changes occurring near +places where parts of one of the input files are repeated +identically, and SRCCOM is triggering on the wrong one. + +File: SRCCOM, Node: FORMAT, Up: Top, Previous: Smart, Next: Merge + +Formatting Options -- /L, /Y, /W, /E. + +/W causes each line of differences to begin with "1)" or "2)", saying +which of the two input files the line came from. That information is +redundant, but may be a useful reminder inside a long run of differences +when the header line that gives the file name is off the screen. + +/L or /Y tells SRCCOM to try to find the labels in the files, and for +each run of differences to give the most recent preceding label in +each of the files. This may make it easier to find the place in the +files where the change occurred. /L looks for assembler labels, +ending with a colon. /Y treats any unindented line as a label, +unless it starts with a ";". It is good for LISP files and is +likely to be good for other sorts. + +/E tells SRCCOM that after each set of differing lines is printed +the first following line (which DOES match a line from the other +file) should be printed. This provides slightly more context for +the human reader. Old versions of SRCCOM had this mode only. + + +Flagging Mode -- /F: + +/F says "flag all the lines in file 2 that don't match file 1". +Instead of a list of the differences between the two input files, +you get a copy of file 2, with marks to indicate which lines were +changed from file 1. The lines of file 2 are indented with tabs, +and at the front of each changed or inserted line there is a "|". +Places where lines form file 1 were deleted in file 2 are indicated +by four uparrows ("^") at the beginning of the next line of output. +/F automatically turns on /B, and prints nothing on the tty. +The default FN2 of the output file is "FLAGGD". + +File: SRCCOM, Node: MERGE, Up: Top, Previous: Format, Next: Binary + +Merge Mode -- /M and /I: + +/M specifies Manual merge mode. In this mode, all the differences +are typed on the TTY, rather than output to the specified +output file; all the identical portions of the input files go +in the output file, as well as such versions of the different +portions as the user specifies. Thus the output file comes +to contain a merge of the two input files. + +When differences are encountered in merge mode, they will be typed +out. The user will then be asked for input. If "1" is typed in, +the first input file's version will go in the merge. +"2" selects the second file's version. "12" or "21" +says that both versions should go in the output file +in the spec'd order. +"I" says that both versions should go in the merge file, +surrounded by easily identified headers and trailers, as follow: + +*** MERGE LOSSAGE *** +*** FILE DSK:SYSENG;FOO 1 HAS: + +*** FILE DSK:SYSENG;FOO 69 HAS: + +*** END OF MERGE LOSSAGE *** + +The other character that may go in the +input is "T", which will cause SRCCOM to copy from the TTY +to the output file up to an altmode. "T" may be accompanied by +"1", "2" or "I", and may appear more than once. For example, +"T1T2T" could be used to simulate "I", if the appropriate strings +are typed in afterward for the three "T"'s. + +Also, if anyone cares, "C###" sets the number of columns printed out, +and "L###" sets the number of lines of differences printed out +(### should be replaced by 3 digits) - again, when merge mode is +asking for tty input. + + + +Automatic Merge Mode -- /I: + +/I selects automatic merge mode. This differs from manual merge mode +only in that instead of asking the user what to do, SRCCOM assumes +"I" as an answer, and doesn't bother to print out the differences. +See above under manual merge mode for what "I" does as an answer. +The result is that all the points of difference may be found by +searching through the merge file for "*** MERGE LOSSAGE ***"; +The user may then edit the file to select the desired combination +of the two versions. + +File: SRCCOM, Node: BINARY, Up: Top, Previous: Merge, Next: Archive + +Binary Compares -- /# and /$: + +It is possible to use SRCCOM for doing a "binary compare" of two files, +by using either the /# or /$ switch. These are almost the same, +except that /$ requires the files to be executable program files; +it will load each into a process and compare the process address spaces. +Thus, differences due to symbol tables, word blocking, file formats, +and other misc info are eliminated. /# on the other hand treats each +file as a bunch of 36-bit words and compares those one by one. + +Binary compares do not search for a match when a difference is seen. +Thus, the word at location 100 of file 1 is always compared with +the word at location 100 of file 2, never with any other. + +Notes: If used, /$ must be the FIRST thing in the command line, preceding + any file specs. + These switches interact very poorly with most others. In + particular, /I and /M will likely blow up SRCCOM. + /$ is unlikely to work for files saved with PDUMP or SSAVE + which have "holes" in their page maps. + +These are considered bugs which eventually may be fixed. + +File: SRCCOM, Node: ARCHIVE, Up: Top, Previous: Binary, Next: Com Files + +Archiving -- /A: + +/A selects archiving. In this mode, the output file is assumed to +be an archive of all changes to a single program from version to +version, and another page is added to the front of it describing +the new set of changes. It is ok for the file not to exist - it +will be created. Archiving makes a difference only when the file +already exists, in appending instead of overwriting. +When archiving, the default output FN2 is "CMPARC". + +To avoid certain rare screws, the /A should always be mentioned with +the output file or the first input file - never with the second input +file. + + + +Indirection -- /@: + +The first input file, , may be specified "indirectly". That +means that the name of the output file from a previous comparison +is specified, that file is read to discover the names of the files +used to generate it, and what was then the second input file is used +as the first input file now. From the second line of the previous +comparison's output come the switches used for that comparison; they +are automatically turned on again (only the switches ABCELSW are hacked). +An indirect specification is indicated by the switch "/@". +Thus, after FOO 1 and FOO 2 are compared into FOO COMP2, specifying +"FOO COMP2/@" in a subsequent command will cause FOO 2 to be the +first input file. Not only the filenames but also the device and +sname are obtained from the indirect file, and they become the +defaults for the second input file. In the previous example, +if the second input file weren't specified, FOO > would be used. + +All the names of the indirect file (the previous output file, +indirected through) default to the names of the output file. Thus, +if the command + +FOOCMP 1_FOO 1 + +compares FOO 1 with FOO 30, and FOO 31 is generated, the command + +FOOCMP >_/@ + +will compare FOO 30 with FOO 31 to give FOOCMP 2. +This mode works well with archiving; if FOO CMPARC is an archive +whose last comparison is FOO 29 against FOO 30, + +FOO_/@/A + +will compare FOO 30 and FOO >, appending the differences to the front +of FOO CMPARC. When using /@ and /A, if the second input file is +explicitly specified the /A must come no later in the command string +than the first input file; otherwise the defaulting of the indirect +file's FN2 will not work properly (this doesn't apply if either the +output file or the indirect file has its FN2 explicitly specified). + +File: SRCCOM, Node: COM FILES, Up: Top, Previous: Archive, Next: Output + +Command Files -- /X: + +If a program consists of several files, it is convenient to be able +to compare all of them against old versions automatically. This +requires that SRCCOM be able to find out what all the files' names +are. That is done by putting a command to compare each of the files +in the desired way in a single command file. SRCCOM may then be +given a command to take successive commands from that command file, +which may be the same file as the main file of the program! That is +because the command file contains not bare SRCCOM commands, but +SRCCOM commands surrounded and identified by prefixes and suffixes, +and all text in the file not so identified (the program, for example) +is ignored. + +The prefix that identifies a command is ";;SRCCOM COMMAND ;;". +The suffix that marks the end of it is ";;" (or ). +Only the first page of the command file will be scanned. +If the prefix by itself doesn't suffice to +make the SRCCOM commands into comments for all other purposes, then +surely suitable characters in front of it will do so. + +For example, if the MIDAS program FOO has files FOO, and BAR, the +following text could be put in the FOO file to make it into a SRCCOM +command file, telling SRCCOM to archive-compare both files: + +;;SRCCOM COMMAND ;;FOO_/@/A +;;SRCCOM COMMAND ;;BAR_/@/A + +The way to tell SRCCOM to read from a command file is to use the /X +switch, and specify the command file alone as an input file. For +example, just "FOO/X" would cause the commands in FOO to be executed. +Each command read from a command file is typed on the terminal. If +an error (such as an open failure) occurs, the reading of the command +file will terminate. It is an error to try to nest command files. + +Filename defaulting works slightly differently while a command file +is in use. The command that specifies the command file also sets +up default devices and snames for the commands read from the file. +The output device and sname specifed with the command file (they may +be defaulted, of course, but will default to DSK: rather than TTY:) +become the defaults for output files while the command file is being +read. Those files will never default to TTY: either, even if no +arrow appears in the command. The device and sname that the command +file came from are the defaults for the first input file while the +command file is being read. The second input file still defaults to +the first, and the handling of FN1's and FN2's is unchanged. Also, +indirect files still default to the output files, and still override +the defaults for the input files. + +File: SRCCOM, Node: OUTPUT, Up: Top, Previous: Com Files + +SRCCOM's Output Format for Difference Files: + +Each difference file begins with a blank line, followed +by some number of comments describing the files and switches +that controlled SRCCOM's operation - currently two. Then +comes another blank line. Programs should ignore all up to +the second blank line. An example is + +;SOURCE COMPARE OF DSK:SYSENG;SRCCOM 40 AND DSK:SYSENG;SRCCOM 42 +;OPTIONS ARE /3 /L + + +Each set of differences looks like this: + +**** FILE DSK:SYSENG;SRCCOM 40, 2-41 (2009) + +**** FILE DSK:SYSENG;SRCCOM 42, 2-47 (2315) + +*************** + +In "2-41 (2009)", the "2" is the page number, the "41" is the +line number on the page, and the "2009" is the character position +in the file (0-origin, suitable for a TECO J command) +of the start of the first line of text. + +When /L is set, header lines look like this, after the first label: + +**** FILE DSK:SYSENG;SRCCOM 40, 2-41 (2009) AFTER FOOBAR: + +where FOOBAR is the most recent label before the first following line. + +Local Modes: +Mode:Text +End: diff --git a/src/sysen2/srccom.129 b/src/sysen2/srccom.129 new file mode 100644 index 00000000..5c7f8e6a --- /dev/null +++ b/src/sysen2/srccom.129 @@ -0,0 +1,3804 @@ + +; -*-MIDAS-*- + +TITLE SRCCOM + +;;SRCCOM COMMAND ;; SRCCOM_/@/A/L/C/S +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; NOTE: THE CANONICAL SOURCE FOR THIS PROGRAM LIVES IN +;;; [MIT-AI] SYSENG;SRCCOM > +;;; ALL CHANGES, BUG FIXES, ETC SHOULD BE REFLECTED THERE. +;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;WAS ONCE DEC SRCCOM VERSION 16, MINIMALLY ADAPTED TO ITS. +;ALMOST TOTALLY REWRITTEN BY RMS, DEC '75. +;MUNGED FOR 10X/20X ASSEMBLY BY KLH, MAR '79. + +IF1 [ +IFE .OSMIDAS-SIXBIT/ITS/,ITS==1 +IFE .OSMIDAS-SIXBIT/TENEX/,TNX==1 +IFE .OSMIDAS-SIXBIT/TWENEX/,TNX==1 ? TWX==1 +IFNDEF ITS,ITS==0 +IFNDEF TNX,TNX==0 +IFE ITS,IFE TNX,DEC==1 +IFNDEF DEC,DEC==0 +IFNDEF TWX,TWX==0 +] + +IFN TNX,[ +.DECSAV ; Why go through LINK? +DEFINE HLPFIL ; SPECIFIES LOC OF HELP FILE +ASCIZ "INFO:SRCCOM.INFO"!TERMIN +] + +;I/O CHANNELS. FOR TNX THESE ARE INDICES INTO JFNCHS. + +CHTTI==0 ;TTY INPUT. +CHIN1==1 ;FIRST INPUT FILE +CHIN2==2 ;SECOND INPUT FILE. +CHIN3==3 ;THIRD INPUT FILE, FOR 3-WAY MERGES. +CHMRG==4 ;/M OUTPUT DEVICE FOR MERGE FILE +CHTTO==5 ;ITS NEEDS TYO CHANNEL +CHERR==6 ;FOR ERR DEVICE. +CHOUT==7 ;OUTPUT CHNL FOR DIFFERENCES. +CHCMD==10 ;COMMAND FILE READING CHANNEL. +CHUIN1==11 ;/$ USR INPUT +CHUIN2==12 ;/$ USR INPUT +CHUO1==13 ;/$ and output chans, since need both. +CHUO2==14 ;/$ + +;MAIN AC DEFINITIONS + +W1=1 +W2=2 +W3=3 +F1=4 ;LINE POINTER FILE 1 (CONTAINS ADDRESS OF LINE BLOCK) +F2=5 ;DITTO FILE 2 +F3=6 ;DITTO FILE 3 +FR=7 ;FLAG REGISTER (LH) AND FILE #(0 OR 1 OR 2)(RH) +CS=10 +C=11 ;CONTAINS 1 CHAR FOR PROCESSING +T=12 ;TEMPORARY AC (MUNGED BY XJSYS CALLS) +TT=13 ;TEMP AC +BP=14 ; (RDLIN AC LOOP) BYTE POINTER IN FILENAME READER. +FP=15 ; BP+1 (RDLIN AC LOOP) ADDR OF FILE BLK +;=16 ; BP+2 (RDLIN AC LOOP) +P=17 ;PUSH DOWN POINTER + + ; ACC DEFS FOR TNX JSYS CODE +IFN TNX, R1=1 ? R2=2 ? R3=3 ? R4=4 ? R5=5 + ; ACC DEFS FOR STUFF BORROWED FROM MIDAS +IFN TNX, AA=6 ? A=1 ? B=2 ? D=4 ? E=5 ? F=FP ; NOTE A NOT AA+1 + + + ;ASCII CHARACTERS + +TAB==11 +ALTM==33 ;/M ALT-MODE TO END TTY INPUT FOR MERGE(/M) + +;FLAGS - LH OF AC FR: + +FL==1,,525252 ;BIT TYPEOUT MODE MASK. +FLINDR==1 ;/@ - FILE NAME FOLLOWS THE STRING ";COMPARISON OF " IN SPEC'D FILE. + ;APPLIES TO 1ST INPUT FILE ONLY. +FLXCTF==2 ;/X - OPEN A COMMAND FILE AND START EXECUTING FROM IT. +FLISWT==4 ;/I - MERGE, BUT AUTOMATICALLY ANSWER "I" TO EVERY QUESTION + ;AND DON'T TYPE ON THE TTY. +FLARCH==10 ;/A SWITCH - "ARCHIVE". APPEND OUTPUT TO FRONT OF EXISTING FILE. +FLLABL==20 ;/L SWITCH - REMEMBER FOR EACH FILE AND LINE THE PREVIOUS LABEL, + ;AND PRINT IT IN THE HEADER LINE. +FLENDL==40 ;/E SWITCH - PRINT OUT THE FIRST MATCHING LINE FROM EACH FILE + ;AFTER EACH RUN OF DIFFERENCES. +FLSPAC==100 ;/S SWITCH - IGNORE SPACING +FLCMNT==200 ;/C SWITCH - IGNORE COMMENTS +FLALL==400 ;/B OR /M SWITCH (ALLOWS COMPARING BLANK LINES) + ; CR,LF,FF STORED LIKE DATA AND COMPARED +FLEOF1==1000 ;EOF SEEN ON FILE 1 +FLEOF2==2000 ;EOF SEEN ON FILE 2 +FLEOF3==4000 ;EOF SEEN ON FILE 3 +FLFNUM==10000 ;/W SAYS PRINT FILE # ON EACH LINE OF DIFFERENCES. +FLFLAG==20000 ;/F SAYS MAKE COPY OF FILE 2, FLAGGING CHANGED LINES WITH VERT. BARS. +FLCASE==40000 ;/K SAYS IGNORE DIFFERENCES IN ALPHABETIC CASE +FLOVRD==100000 ;/! SAYS DO THE COMPARISON EVEN IF FILE1 AND FILE2 ARE SAME FILE. +FLXLBL==200000 ;/Y SAYS ANY UNINDENTED LINE NOT STARTING WITH A ";" IS A LABEL. +FLMERG==400000 ;/M SWITCH-MERGE 2 FILES INTO ONE CONVERSATIONALLY + +;RH OF FR TELLS CERTAIN FUNCTIONS WHICH INPUT FILE TO OPERATE ON: 0 => FILE 1, 1 => FILE 2. + +; Memory flags (cuz no more room in LH of FR!) +.SCALAR FVBIN ; -1 if doing binary compare (like FILCOM /W) +.SCALAR FSBIN ; -1 if doing SBLK/CSAVE compare +.SCALAR QFLAG ; -1 if doing /Q message at end of compare + +;NAMES OF THE HEADER WORDS OF A FILE LINE + +LNNEXT==0 ;MUST BE 0! ADDR OF HEADER OF NEXT LINE, OR 0 FOR LAST LINE. +LNSIZE==1 ;# OF CHARACTERS IN THE LINE, NOT COUNTING TERMINATING ZERO. +LNLLBL==2 ;1ST WORD OF ASCIZ OF MOST RECENT LABEL, OR 0. +LNLLB1==3 ;2ND WORD OF ASCIZ. COLON IS INCLUDED. +LNLLB2==4 ;4 WORDS IN ALL FOR HOLDING A LABEL. +LNLLB3==5 + LNLBLN==4 +LNPGNM==6 ;PAGE # THIS LINE STARTED ON +LNLNNM==7 ;LINE NUMBER THIS LINE STARTED ON +LNCHNM==10 ;CHARACTER NUMBER IN FILE OF 1ST CHARACTER IN LINE +LNDATA==11 ;INDEX OF THE FIRST DATA WORD. THE DATA ARE AN ASCIZ STRING + ;THERE ARE ASSUMED TO BE JUST ENOUGH DATA WORDS + ;TO HOLD THE NUMBER OF CHARACTERS THAT LNSIZE SAYS THERE ARE. + + +;PARAMETERS + +IFNDEF MATCH,MATCH==3 ;# LINES TO BE MATCHED BEFORE RUN OF DIFFERENCES ENDS. +IFNDEF WPL,WPL==<40.*4>/5+1 ;# WORDS FOR FILENAMES FOR HEADER LINES. +IFNDEF LPDL,LPDL==30 ;LENGTH OF PUSH DOWN LIST +IFNDEF FILBFL,FILBFL==100 ;LENGTH OF INPUT FILE BUFFERS. +MRGBSZ==FILBFL*5 ;MERGE OUTPUT BUFFER LENGTH IN CHARS. + +;/M THIS SRCCOM ALSO PERFORMS A MERGE FUNCTION IF /M IS TYPED +;/M DESTINATION FILE BECOMES MERGE OF 2 SOURCE FILES. +;/M DIFFERENCES ARE TYPED ON TTY, USER SELECTS WHICH HE WANTS +;/M AND IN WHAT ORDER BY TYPING IN 1 LINE COMMAND AFTER EACH PAIR +;/M OF DIFFERENCES IS TYPED OUT. +;/M HE MAY TYPE 1, 2, AND/OR T IN ANY ORDER FOLLOWED BY CR +;/M OR HE MAY CHANGE THE LAST COLUMN TYPED OUT TO ### BY TYPING +;/M C### FOLLOWED BY CR AS A SEPARATE COMMAND AFTER ANY PAIR OF DIFFERENCES +;/M TYPED OUT. SRCCOM WILL RESPOND WITH ANOTHER *, SO THE USER CAN TYPE +;/M ANOTHER COMMAND TO SELECT WHICH DIFFERENCES HE WANTS. INITIALLY THE +;/M MAX. COLUMN IS SET TO 72 WHENEVER SRCCOM IS RESTARTED WITH START COMMAND +;/M IT IS NOT RESET AFTER EACH FILE COMPARED. +;/M SIMILARLY THE USER MAY SET THE MAXIMUM +;/M NUMBER OF LINES TYPED FROM EACH FILE WITH L###. + +;OPDEFS + +CALL=PUSHJ P, +RET=POPJ P, +SAVE=PUSH P, +REST=POP P, +PJRST==JRST +IFN ITS,ERRHLT==.LOSE +IFN TNX,ERRHLT==HALT + +;MACROS + +IFN ITS,[ +DEFINE SYSCAL A,B + .CALL [ SETZ ? SIXBIT/A/ ? B ((SETZ))] +TERMIN +] +; This may not work right on TENEX anymore, if so, fix the opsys flags +; so that we can tell 10x from 20x. +IFN TNX, .INSRT MID:XJSYS + +DEFINE DBP7J AC,TAG=.+2 + ADD AC,[070000,,] + JUMPGE AC,TAG + SUB AC,[430000,,1] +IFSN [TAG].+2,JRST TAG +TERMIN + +DEFINE INSIRP INSN,ADDRS +IRPS ADDR,,[ADDRS] + INSN,ADDR +TERMIN TERMIN + +;ADVANCE TO THE NEXT LINE IN FILE FILN, READING IT FROM THE FILE IF NECESSARY. +;GO TO EOFA IF THERE IS NO LINE DUE TO EOF. +DEFINE NEXTLN FILN,(EOFA) + SKIPE LNNEXT(F1+FILN-1) + JRST .+4 + HRRI FR,FILN-1 + CALL RDLIN +IFNB EOFA, JRST EOFA +.ELSE CAIA + MOVE F1+FILN-1,LNNEXT(F1+FILN-1) +TERMIN + + ; SOME MACROS TO MAKE I/O A LITTLE LESS SYSTEM DEPENDENT. + ; OPTIMIZED IN FAVOR OF ITS. +IFN ITS,[ +DEFINE M.CLS CH ; CLOSE CHAN +.CLOSE CH, +TERMIN + +DEFINE M.MVCH CH1,CH2 ; MOVE CHANNEL FROM CH1 TO CH2 +.IOPUS CH1, +.IOPOP CH2, +TERMIN + +DEFINE MOUTC CH,?LOC ; SINGLE CHAR OUTPUT +.IOT CH,LOC +TERMIN + +DEFINE M.BIN CH,LOC +.IOT CH,LOC +TERMIN + +DEFINE M.SOUT CH,BPA,CNTA +SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA] + .LOSE %LSFIL +TERMIN + +DEFINE M.SIN CH,BPA,CNTA +SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA] + .LOSE %LSFIL +TERMIN +] ;IFN ITS + +IFN TNX,[ +DEFINE M.CLS CH ; CLOSE CHAN + SAVE R1 + SKIPLE R1,JFNCHS+CH + CLOSF + ERJMP .+1 + SETZM JFNCHS+CH + REST R1 +TERMIN + +DEFINE M.MVCH CH1,CH2 ; MOVE CHANNEL FROM CH1 TO CH2 + SAVE R1 + SETZ R1, + EXCH R1,JFNCHS+CH1 + EXCH R1,JFNCHS+CH2 + CAILE R1, + CLOSF + ERJMP .+1 + REST R1 +TERMIN + +DEFINE MOUTC CH,?LOC ; OUTPUT BYTE AT LOC +CALL [ PUSH P,JFNCHS+CH + PUSH P,LOC + PJRST TOUTC] +TERMIN + +DEFINE M.BIN CH,LOC ; INPUT BYTE TO LOC +CALL [ PUSH P,JFNCHS+CH + PUSH P,[LOC] + JRST TINC] +TERMIN + +DEFINE M.SOUT CH,BPA,CNTA ; OUTPUT STRING +MOVNS CNTA +SYSCAL SOUT,[JFNCHS+CH ? BPA ? CNTA][JUNK ? BPA ? CNTA] +MOVNS CNTA +TERMIN + +DEFINE M.SIN CH,BPA,CNTA ; INPUT STRING +MOVEI T,[JFNCHS+CH ? BPA ? CNTA] +CALL TINS +TERMIN + +] ;IFN TNX + +DEFINE MOUTI CH,VAL ; OUTPUT IMMEDIATE VALUE +MOUTC CH,[VAL] +TERMIN + + ; SO MIDAS-BORROWED CODE WILL INTEGRATE BETTER. +DEFINE ETF ?ASCZ +JRST [ JSP T,ERRMSG + ASCZ +] +TERMIN +DEFINE TYPE &STR +CALL [ PUSH P,[[ASCIZ STR]] + PJRST TYPM] +TERMIN + +DEFINE PRINTI &STR& + MOVEI C,.LENGTH STR + MOVE W2,[440700,,[ASCIZ STR]] + CALL PNTCNT +TERMIN + +SUBTTL File Description Storage (FILBLK's) + + + ; Definitions for indices into a FILBLK. + + ; Scratch block FB is formed while defining indices... + OFFSET -. + ; Lots of crocks depend on the exact order of these 4 items. +IFN ITS\DEC,[ +$F6DEV:: 0 ; SIXBIT Device name +$F6FN1:: 0 ; SIXBIT Filename (on ITS, FN1) +$F6FN2:: 0 ; SIXBIT Extension (on ITS, FN2) +$F6DIR:: 0 ; SIXBIT Directory (may be numerical PPN) +$FDEV==:$F6DEV ; These definitions made so some common code can do +$FDIR==:$F6DIR ; the right things. +$FNAME==:$F6FN1 +$FEXT==:$F6FN2 +$FVERS==:$F6FN2 +] +IFN TNX,[ ; Almost all entries here are BP's to ASCIZ strings. +$FDEV:: 0 ; Device name +$FDIR:: 0 ; Directory name +$FNAME:: 0 ; File name (i.e. main name) +$FEXT:: 0 ; File type (or extension) +$FVERS:: 0 ; File version (or generation). NUMBER, not string. +$FTEMP:: 0 ; -1 => File is a temporary file. +$FACCT:: 0 ; Account string +$FPROT:: 0 ; Protection string +$FJFN:: 0 ; JFN for file (may be ,,) +] + L$FBLK==. ; Length of a FILBLK. + OFFSET 0 ; End of index definitions. + + +INFB: BLOCK L$FBLK +LSTFB: BLOCK L$FBLK + +IFN TNX,[ +JFNCHS: BLOCK 20 ; INDEXED BY CHAN #, HOLDS JFNS +] + +;SRCCOM STARTS HERE + +BEG: MOVE P,[-LPDL,,PPSET-1] ;SET UP PDL. + +IFN ITS,[ + .OPEN CHTTI,[.UAI,,'TTY] + ERRHLT + .OPEN CHTTO,[.UAO,,'TTY] + ERRHLT + .SUSET [.RSNAM,,DEFDIR] ;GET DEFAULT DIR. + .SUSET [.ROPTIO,,W1] + TLO W1,OPTOPC + .SUSET [.SOPTIO,,W1] + .SUSET [.SMASK,,[%PIMPV]] + .SUSET [.SMSK2,,[1_CHTTO+1_CHOUT]] ;ENABLE --MORE-- INTERRUPTS +] ;IFN ITS + +IFN TNX,[ + RESET + CALL SEE20X ; SEE IF 10X OR 20X. + MOVEI W1,.PRIIN + MOVEM W1,JFNCHS+CHTTI + MOVEI W1,.PRIOU + MOVEM W1,JFNCHS+CHTTO +] + CALL GETJCL ; LOOK FOR JCL, SKIP IF FOUND + CAIA ; NONE + JRST RESTR1 ; HAVE SOME, GO EXECUTE. + + MOVE 0,[SIXBIT/SRCCOM/] ;NO COMMAND STRING FROM SUPERIOR: + CALL TTOSIX ;IDENTIFY SELF TO USER. + MOUTI CHTTO,40 ;SPACE +IFDEF .FVERS,[ + MOVE 0,[.FVERS] + CALL TTODEC +] +.ELSE [ + MOVE 0,[.FNAM2] ;PRINT VERSION NUMBER. + CALL TTOSIX +] + JRST RESTRT + +;COME HERE FOR A NEW COMMAND, AFTER FINISHED OR ERROR. + +RESTRT: SETZM TTIBUF +RESTR1: MOVE P,[-LPDL,,PPSET-1] ;SET UP PUSH DOWN LIST +IFN ITS,.SUSET [.SWHO1,,[0]] ;CLEAR USER-SPEC'D WHOLINE FIELDS. +IFN ITS,.SUSET [.SMEMT,,[ENDCOR]] + SETZB FR,BEGP ;THIS IS THE ZERO WHICH WILL + ;BE "BLT"ED TO CLEAR CORE + MOVE 0,[BEGP,,BEGP+1] + BLT ENDP-1 +IFN TNX,[ + MOVE 0,[FNBUF,,FNBUF+1] + SETZM FNBUF + BLT 0,FNBUF+LFNBUF-1 +];TNX + + MOVE W1,[440700,,MRGBF] + MOVEM W1,MRGBP + MOVEI W1,MRGBSZ + MOVEM W1,MRGCT + MOVE W1,SEG1 + MOVEM W1,LBUFP1 + MOVE W1,SEG2 + MOVEM W1,LBUFP2 + MOVE W1,SEG3 + MOVEM W1,LBUFP3 + AOS PAGNUM+0 ;ZEROED BY BLT ABOVE-1ST PAGE IS 1 + AOS PAGNUM+1 ;DITTO FOR SECOND FILE + AOS PAGNUM+2 + AOS LINNUM+0 ;SAME TRUE FOR 1ST LINE + AOS LINNUM+1 + AOS LINNUM+2 + SKIPE TTIBUF ;IF HAVE A JCL COMMAND, + SETOM CTLCF ;SAY RETURN AFTER JUST THIS CMD. + SKIPN TTIBUF + CALL CMDLIN ;NO DDT CMD, READ TTY LINE. + CALL TRYHLP ;IF COMMAND IS JUST "?" OR "HELP", PRINT HELP. + MOVE C,FSTTY ;OUTPUT DEFAULTS TO TTY IF NOT SPEC'D, + SKIPN CMDFIL ;UNLESS WE'RE IN A COMMAND FILE. + MOVEM C,LSTFB+$FDEV + MOVEI FP,INFB + CALL RFILE ;READ FILE NAME + CAIE C,"= +IFE TWX,[ ;Don't recognize "_" on Twenex, screws filenames + CAIN C,"_ ;IF FOLLOWED BY "_", IS OUTPUT SPEC, + CAIA +] + JRST CMD3 + MOVE C,[INFB,,LSTFB] + BLT C,LSTFB+L$FBLK-1 ;SO USE AS LST FILE NAMES. + SETOM LSTEXP ;SAY LST FILE WAS EXPLICITLY SPECIFIED. + SETZM INFB+$FDEV + SKIPE CMDFIL ;IF NOT IN A COMMAND FILE, 1ST INPUT FILE SNAME + SETZM INFB+$FDIR ;DEFAULTS TO OUTPUT FILE SNAME. + CALL RFILE ;AND READ ANOTHER SPEC FOR 1ST INPUT FILE. + JRST CMD3 + +;NOW HAVE READ WHAT IS CERTAINLY THE 1ST INPUT SPEC. +CMD3: MOVE W2,DEFDIR ;DEFAULT THE OUTPUT FILE DEV AND SNAME NOW. + SKIPE CMDFIL ;CAN DO IT SINCE IT DOESN'T DEPEND ON SWITCH SETTINGS + MOVE W2,CMDOS ;AND MUST DO IT SINCE MIGHT GO TO CMDXCT AND WANT + SKIPN LSTFB+$FDIR ;TO KNOW THEIR FINAL VALUES. + MOVEM W2,LSTFB+$FDIR + MOVE W2,FSDSK + SKIPE CMDFIL + MOVE W2,CMDOD + SKIPN LSTFB+$FDEV + MOVEM W2,LSTFB+$FDEV + TLNN FR,FLINDR ;IF THE FIRST INPUT FILE IS INDIRECT, DEFAULT THE FN2 + JRST CMD6 ;OF THE FILE TO GO INDIRECT THROUGH TO + MOVE W1,FSCMP ;TO THE FN2 OF THE LISTING FILE, AS WELL AS WE CAN. + TLNE FR,FLARCH ;CAN LOSE IN OBSCURE SITUATIONS THAT THE DOCUMENTATION + MOVE W1,FSCMPA ;WARNS USERS TO AVOID. + SKIPE LSTFB+$FEXT + MOVE W1,LSTFB+$FEXT + SKIPN INFB+$FEXT + MOVEM W1,INFB+$FEXT + MOVE W1,LSTFB+$FDIR ;ALSO DEFAULT SNAME AND DEV THAT WAY, BUT NEVER USE TTY: + SKIPN INFB+$FDIR ;NOTE THAT THE FN1 WILL DEFAULT TO THE LIST FILE'S + MOVEM W1,INFB+$FDIR ;ANYWAY. + MOVE W1,LSTFB+$FDEV + CAMN W1,FSTTY + MOVE W1,FSDSK + SKIPN INFB+$FDEV + MOVEM W1,INFB+$FDEV +CMD6: MOVE W1,CMDIS + SKIPN CMDFIL + MOVE W1,DEFDIR + SKIPN INFB+$FDIR + MOVEM W1,INFB+$FDIR + MOVE W1,CMDID ;DEFAULT DEVICE FOR 1ST INPUT FILE DEPENDS ON + SKIPN CMDFIL ;WHETHER WE'RE IN A COMMAND FILE. + MOVE W1,FSDSK + SKIPN INFB+$FDEV + MOVEM W1,INFB+$FDEV + SKIPN W1,INFB+$FVERS + MOVE W1,FVLOW ;IF ONLY ONE INPUT FILE SPECIFIED, DEFAULT ITS FN2 TO "<", + SKIPG TTICNT ;SINCE 2ND INPUT FILE WILL BE THE ">" OF THE SAME FILE. + MOVEM W1,INFB+$FVERS +RFIND1: MOVEI W1,CHIN1 + CALL INOPEN ;NOW OPEN CHANNEL CHIN1. + TLNE FR,FLXCTF ;IS THIS AN EXECUTE FILE? + JRST CMDXCT + TLNE FR,FLINDR ;MAYBE THE FILE WE OPENED JUST HAS THE NAMES OF THE + JRST RFINDR ;REAL 1ST INPUT FILE. IF SO, READ THEM. + CALL RFILE ;READ NAMES OF & OPEN 2ND INPUT. + MOVEI W1,CHIN2 + CALL INOPEN + TLNE FR,FLINDR\FLXCTF + JRST ERRIN2 ;FILE 2 INDIRECT? THAT ISN'T ALLOWED. + SKIPG TTICNT ;MORE FILES? MUST BE A 3-WAY MERGE. + JRST CMD4 + CALL RFILE ;READ THE THIRD FILE'S NAME. + TLNN FR,FLMERG + JRST ERR3NM ;ERROR IF /M NOT SPECIFIED. + SETOM 3WAY + MOVEI W1,CHIN3 + CALL INOPEN + TLNE FR,FLINDR\FLXCTF ;ERROR IF THIRD FILE IS INDIRECT. + JRST ERRIN3 + SKIPG TTICNT ;ERROR IF ANYTHING LEFT AFTER THIRD FILE NAME. + JRST ERRXTRA + JRST CMD4 + +;NOW OPEN THE OUTPUT FILE. +CMD4: MOVEI FP,LSTFB + MOVE W2,FSCMP ;NORMAL DEFAULT OUTPUT FN2. + TLNE FR,FLARCH + MOVE W2,FSCMPA + MOVEI W1,CHOUT ;NORMALLY, SPEC'D FILE IS OUTPUT FILE, + TLNN FR,FLMERG + JRST CMD5 + TLNE FR,FLARCH + JRST ERRARC + MOVEI W1,CHMRG ;BUT IF /M, IT IS MERE FILE NAME, +IFN ITS,[ + .OPEN CHOUT,[.UAO,,'TTY] ;AND OUTPUT IS TO TTY: + ERRHLT +] +IFN TNX,[ + PUSH P,JFNCHS+CHTTO + POP P,JFNCHS+CHOUT +] + MOVE W2,FSDMF2 + TLNE FR,FLFLAG ;ALSO, WE HAVE DIFFERENT DEFAULT FN2'S + MOVE W2,FSFLGD + MOVE T,FSTTY + SKIPL LSTEXP ;AND DON'T DEFAULT TO TTY:; USE DSK: INSTEAD. + CAME T,LSTFB+$FDEV + JRST CMD5 + MOVE T,FSDSK + MOVEM T,LSTFB+$FDEV +CMD5: SKIPN LSTFB+$FEXT ;DEFAULT THE FN2 IF NEC. + MOVEM W2,LSTFB+$FEXT +IFN ITS,[ + SYSCAL TRANS,[ + $FDEV(FP) ? $FNAME(FP) ? $FEXT(FP) ? $FDIR(FP) + MOVEI .UAO + MOVEM $FDEV(FP) ? MOVEM $FNAME(FP) + MOVEM $FEXT(FP) ? MOVEM $FDIR(FP)] + CALL OPENL + SYSCAL OPEN,[5000,,.UAO ? W1 + $FDEV(FP) ? ['_SRCCO] ? ['OUTPUT] ? $FDIR(FP)] + CALL OPENL ;ERROR RTN, IN CASE FAILED. + SYSCAL TTYGET,[MOVEI CHOUT ? MOVEM TTYST1 ? MOVEM TTYST2 ? MOVEM W1] + JRST CMD2 ;JUMP IF OUTPUT FILE ISN'T A TTY. + SETOM OUTTTY + MOVEM W1,TTYSTS ;IT IS A TTY; SAVE THE TTYSTS TO RESTORE LATER + TLZE W1,%TSMOR ;AND TURN ON **MORE**'ING NOW. + SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1] + JFCL +] ;IFN ITS +IFN TNX,[ + MOVE T,FSTTY + CAMN T,LSTFB+$FDEV ; ABOUT TO OPEN TTY FOR OUTPUT? + JRST [ PUSH P,JFNCHS+CHTTO ; IF SO JUST DUPLICATE TTY JFN + POP P,JFNCHS+CHOUT + SETOM OUTTTY + JRST CMD20] + MOVEI FP,LSTFB + HRLI FP,(W1) ; GET ,, + CALL OPNWR + CALL OPENL +CMD20: +] + +;FINAL INITIALISATION, AND PRINTING OF THE FILE HEADER. +CMD2: SETZB F1,F2 ;RIGHT NOW WE HAVE NO LINES OF EITHER FILE IN CORE. + TLNE FR,FLMERG ;IF MERGING, LINES FLUSHED FROM FILE 1 + SETOM MRGOUT+0 ;GO OUT TO THE MERGE FILE. + SETZ 0, +IFN ITS,[ + .SUSET [.SWHO1,,[.BYTE 8 ? 166 ? 0 ? 55 ? ",]] + .SUSET [.SWHO3,,[1,,1]] ;INITIALIZE THE USER WHO-LINE FIELDS. + .SUSET [.SWHO2,,['HEADER]] +] + SKIPE 3WAY ;3-WAY MERGES HAVE A SPECIAL MAIN LOOP. + JRST 3LOOP + TLNE FR,FLMERG + JRST ENTER + MOVSI W1,-WPL + MOVE T,HBUF1(W1) ;LOOK FOR DIFFERENCES BETWEEN REAL FILE NAMES + CAMN T,HBUF2(W1) ;OF OUR TWO INPUT FILES. + AOBJN W1,.-2 + TLNN FR,FLOVRD ;UNLESS FORCED BY /!, + JUMPGE W1,FIN5 ;IF THE NAMES ARE THE SAME, DON'T WASTE TIME COMPARING. + MOVEI W1,[ASCIZ / +;COMPARISON OF /] + CALL PRINT + MOVE W1,RCHSTP + CALL PRINT + MOVEI W1,[ASCIZ / AND /];RFINDR DEPENDS ON EXACT STRINGS USED HERE. + CALL PRINT + MOVE W1,RCHSTP+1 + CALL PRINT + MOVEI W1,[ASCIZ / +;OPTIONS ARE /] ;NOTE RFINDR DEPENDS ON PRECISE STRING USED HERE. + CALL PRINT +IRPS X,,FLARCH FLALL FLCMNT FLENDL FLCASE FLLABL FLSPAC FLFNUM FLXLBL,Y,,A B C E K L S W Y + MOVEI W1,[ASCIZ * /Y*] + TLNE FR,X + CALL PRINT +TERMIN + MOVEI W1,[ASCIZ " /#"] + SKIPE FVBIN + CALL PRINT + MOVEI W1,[ASCIZ " /$"] + SKIPE FSBIN + CALL PRINT + MOVEI W1,[ASCIZ * /*] + CALL PRINT + MOVE T,NUMLIN + AOS T + CALL PNTDEC + CALL PCRLF + CALL PCRLF + JRST ENTER + +ENTER: +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]] + SKIPE FVBIN ; Normally no binary compare + JRST BSAME ; Gadzooks! Use special routine. + SKIPE FSBIN + JRST SBSAME ; Use special SBLK compare routine + +;THIS IS THE MAIN LOOP OF SRCCOM. + +;COME HERE WHEN THE LAST TWO LINES MATCHED, TO TRY THE NEXT TWO. +SAME: SKIPE F1,LNNEXT(F1) ;ADVANCE PAST THE LINE THAT MATCHED + JRST SAME1 + TRZ FR,-1 ;IF NO MORE LINES IN CORE, FLUSH ALL + SKIPE MRGOUT+0 ;THE LINES WE PASSED BY, + CALL MOVEUP + SETZM NLINE1 ;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST) + CALL RDLIN ;AND READ ANOTHER. + JRST END0 ;EOF => CHECK FILE 2 FOR EOF. + ERRHLT +SAME1: SKIPE F2,LNNEXT(F2) ;SIMILAR FOR F2, + JRST SAME2 + SETZM NLINE2 ;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE. + HRRI FR,1 + CALL RDLIN + JRST DIFF ;EOF IN FILE 2 BUT NOT IN FILE 1 => IT'S A DIFFERENCE. + ERRHLT +SAME2: CALL COMPL + JRST SAME ;THE TWO LINES ARE IDENTICAL; KEEP SCANNING. + JRST DIFF ;ELSE SEE HOW BIG THIS RUN OF DIFFERENCES IS. + +; BINARY COMPARE - Main loop. + +BSAME: TRZ FR,-1 + CALL RDWRD ; Get word in W1 + JRST BEND0 ; EOF => check file 2 for EOF + MOVE W2,W1 + HRRI FR,1 + CALL RDWRD ; Get another word from file 2 + JRST BEND1 ; EOF on file 2, it"s a difference. + CAMN W1,W2 ; Compare words + JRST BSAME ; Won, get next one. + JRST BDIFF +BEND0: MOVE W2,W1 ; EOF on file 1, check file 2 + HRRI F1,1 + CALL RDWRD + JRST FIN2 ; If EOF on file 2 also, win! + PRINTI " EOF on file 1 +" + AOS ERRCNT + JRST FIN2 +BEND1: PRINTI " EOF on file 2 +" + AOS ERRCNT + JRST FIN2 + + ; Words are different. Must print out and show + ; addr: +BDIFF: AOS ERRCNT ; Bump count of diffs + PUSH P,W1 + PUSH P,W2 + MOVE T,GWORDL(FR) + SUB T,GWORDC(FR) ; Find # words read thus far + CALL PNTOCT + PRINTI ": " + MOVE T,(P) + CALL PNTHWD + PRINTI " " + MOVE T,-1(P) + CALL PNTHWD + PRINTI " XOR= " + POP P,T + XOR T,(P) + CALL PNTHWD + POP P,T + CALL PCRLF + JRST BSAME + +; Program ("SBLK") BINARY COMPARE - Main loop. + +.SCALAR GWADR ; Address of word to get + + +SBSAME: TRZ FR,-1 + CALL RDUWRD ; Get word in W1 + JRST SBEND0 ; EOF => check file 2 for EOF + MOVE W2,W1 + HRRI FR,1 + CALL RDUWRD ; Get another word from file 2 + JRST SBEND1 ; EOF on file 2, it"s a difference. + CAME W1,W2 ; Compare words + JRST SBDIFF +SBSAM0: AOS W1,GWADR + CAIG W1,-1 + JRST SBSAME + JRST FIN2 + +SBEND0: MOVE W2,W1 ; EOF on file 1, check file 2 + HRRI F1,1 + CALL RDWRD + JRST FIN2 ; If EOF on file 2 also, win! + PRINTI " EOF on file 1 +" + AOS ERRCNT + JRST FIN2 +SBEND1: PRINTI " EOF on file 2 +" + AOS ERRCNT + JRST FIN2 + + ; Words are different. Must print out and show + ; addr: +SBDIFF: AOS ERRCNT ; Bump count of diffs + PUSH P,W2 + PUSH P,W1 + MOVE T,GWADR ; Find # words read thus far + CALL PNTOCT + PRINTI ": " + MOVE T,-1(P) ; Get wd from file 1 + CALL PNTHWD + PRINTI " " + MOVE T,(P) ; Then wd from file 2 + CALL PNTHWD + PRINTI " XOR= " + POP P,T + XOR T,(P) + CALL PNTHWD + POP P,T + CALL PCRLF + JRST SBSAM0 + +;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING +;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. +DIFF: CALL MOVEUP ;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO. + TRC FR,1 + CALL MOVEUP + SKIPE 0 ;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE. + ERRHLT +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]] + SETZM NCOMP1 ;NCOMP1 GETS NUMBER OF LINES OF FILE 1 WE HAVE FOR + SKIPE F1 ;CONSIDERATION. + AOS NCOMP1 + SETZM NCOMP2 ;NCOMP2 GETS THE SAME THING FOR FILE 2. + SKIPE F2 + AOS NCOMP2 +DIFFRD: NEXTLN 1,END2 ;READ ANOTHER LINE FROM EACH FILE. + AOS NCOMP1 + NEXTLN 2,DIFF2 ;NO NEW LINE FROM FILE 2 => DON'T COMPARE FILE 1 WITH IT +DIFF3: AOS NCOMP2 + SKIPN CS,NCOMP1 ;HOW MANY FILE 1 LINES SHOULD WE CONSIDER? + JRST DIFFRD ;NONE? + SKIPA F1,LBUFP1 ;ELSE COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME, +DIFF0: MOVE F1,W1 ;WITH THE NEW LINE FROM FILE 2. + CALL COMPL + CALL MULTI ;MATCH => CHECK FOR MULTI-LINE MATCH, GO TO SAME IF FOUND. + SKIPE W1,LNNEXT(F1) + SOJG CS,DIFF0 +;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW +;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES. +;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT. +;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI). +DIFF2: SKIPE EOFFL1 ;BUT DON'T DO IT IF NO NEW FILE 1 LINE. + JRST DIFFRD + SKIPN CS,NCOMP2 ;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2? + JRST DIFFRD ;NONE => NOTHING TO COMPARE WITH THE NEW LINE FROM 1. + SKIPA F2,LBUFP2 ;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.) +DIFF1: MOVE F2,W1 ;ELSE LOOP HERE OVER THE FILE 2 LINES. + CALL COMPL + CALL MULTI + SKIPE W1,LNNEXT(F2) + SOJG CS,DIFF1 + JRST DIFFRD ;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM. + +END0: SKIPE F2,LNNEXT(F2) ;HERE WHEN EOF IN FILE 1 AT SAME. + JRST DIFF ;MORE LINES IN FILE 2 => THEY'RE DIFFERENT. + SETZM NLINE2 + HRRI FR,1 + CALL RDLIN + JRST FIN2 ;EOF IN FILE 2 => ALL DONE. + ERRHLT + JRST DIFF + +END2: NEXTLN 2,FINDIF ;NO NEW FILE 1 LINE IN DIFFRD. NO NEW FILE 2 LINE EITHER => + JRST DIFF3 ;ALL THE NON-MATCHING LINES WE HAVE ARE DIFFERENCES. + ;NEW LINE FROM FILE 2 => TRY MATCHING IT AGAINST FILE 1 LINES. + +;AT THIS POINT NEITHER FILE HAS ANY MORE LINES TO BE READ. +;PRINT AS DIFFERENCES ANY LINES REMAINING FOR EITHER FILE. + +FINDIF: SETZB F1,F2 ;MAKE SURE ALL LINES PRINTED IN CASE NO /E. + CALL COMSPC ;SEE IF DIFFERENCES VANISH IF WE IGNORE SPACES AND COMMENTS. + JRST FIN2 ;THEY DO; DON'T PRINT AS DIFFERENCES. + CALL PNTBTH ;PRINT ANY LINES + CALL TRYMRG + JRST FIN2 + MOVEI W1,[ASCIZ/*************** +/] + CALL PRINT + +;COME HERE WHEN THE OUTPUT AND MERGE FILES ARE ALL GENERATED. +FIN2: TRZ FR,-1 ;OUTPUT THE STUFF IN FILE 1, IN CASE IN /M MODE. + CALL MOVEUP + TLNN FR,FLARCH ;IF SUPOSED TO BE ARCHIVING, DO THE APPEND NOW. + JRST FIN3 + SKIPN ERRCNT ;BUT IF NO NEW STUFF TO APPEND, DO NOTHING, + JRST FIN5 ;AND THROW AWAY OUR 0-BLOCK FILE. + MOVE FP,[CHIN1,,LSTFB] + CALL OPNRDA + JRST FIN3 ;NO OLD FILE => JUST MAKE NEW ONE. + MOUTI CHOUT,^L +FIN4: MOVE W2,GCHARB ;IF SO, IF WE'RE ABOUT TO OVERWRITE A FILE, + MOVEI C,FILBFL*5 ;APPEND ITS OLD CONTENTS TO OUR OUTPUT, WITH ^L BETWEEN. + M.SIN CHIN1,W2,C ; INPUT + MOVNS C + ADDI C,FILBFL*5 + JUMPE C,FIN3 + MOVE W2,GCHARB + CALL PNTCNT + JRST FIN4 + +FIN5: + M.CLS CHOUT +IFN ITS,[ + SYSCAL DELETE,[LSTFB+$FDEV ? ['_SRCCO] ? ['OUTPUT] ? LSTFB+$FDIR] + JFCL +] + +FIN3: TLNE FR,FLMERG + CALL MRGFRC ;IF MERGING, FORCE OUT OUR BUFFER. + MOVEI W1,CHOUT ;WHICH CHANNEL IS OUR MOST IMPORTANT OUTPUT FILE ON? + TLNE FR,FLMERG + MOVEI W1,CHMRG + CALL RENMLO + MOVEI T,[ASCIZ /NO DIFFERENCES ENCOUNTERED/] + SKIPN ERRCNT ;ANY DIFFERENCES? + CALL TYPMS0 ;NO, PRINT MESSAGE + MOVEI T,[ASCIZ /? FILES ARE DIFFERENT/] + SKIPE QFLAG ;/Q MODE ON? + SKIPN ERRCNT ;/Q YES, ANY DIFFERNCES + SKIPA ;/Q NO + CALL TYPMS0 ;/Q YES + SKIPE ERRCNT ;/M ANY DIFFERENCES? + TLNN FR,FLMERG ;/M YES, MERGE IN PROGRESS? + JRST RELDEV ;/M NO, END OF SOURCE COMPARE + MOVEI T,[ASCIZ /END OF MERGE/] + TLNN FR,FLISWT\FLFLAG + CALL TYPMSG ;/M YES, PRINT END OF MERGE + JRST RELDEV ;END OF SOURCE COMPARE + +;CALL MULTI TO CHECK FOR A MULTI-LINE MATCH, IF NECESSARY. +;IF THERE IS ONE, OR IT ISNT NECESSARY (NUMLIN = 0), RETURNS TO SAME +;AFTER PRINTING THE DIFFERENCES. IF THE MATCH FAILS, IT RETURNS +;NON-SKIPPING TO ITS CALLER. + +;IN A 3-WAY MERGE, WE ARE USED TO COMPARE FILES 1 AND 2. +;WHEN WE FIND A MULTI-LINE MATCH, WE PUSH AN ENTRY ON +;12MTAB, THE TABLE OF PLACES WHERE FILES 1 AND 2 MATCH. +;EACH SUCH PLACE GETS COMPARED AGAINST FILE 3 LATER. + +MULTI: SAVE CS + MOVEM F1,TEMPF1 ;SAVE CURRENT POINTERS + MOVEM F2,TEMPF2 + SKIPG NUMLIN ;MULTIPLE LINE TEST? + JRST MULT8 ;NO + SETZM NUMTMP ;INIT MULTI-LINE COUNTER +MULT2: NEXTLN 1,MULTE ;MUST GET A NEW LINE FROM BOTH FILES + NEXTLN 2,MULT4 ;TO CONTINUE THE MULTI-LINE MATCH. + CALL COMPL ;COMPARE THEM + JRST MULT6 ;MATCH, TEST MULTI COUNTER +MULT4: SKIPE F1,TEMPF1 ;NO MATCH, RESET REGS + SETZM EOFFL1 ;IF NO LONGER AT LAST LINE, CAN'T BE AT EOF. + SKIPE F2,TEMPF2 + SETZM EOFFL2 + REST CS + RET + +MULTE: NEXTLN 2,MULT8 + JRST MULT4 + +MULT6: AOS W1,NUMTMP ;INDEX MULTI-LINE COUNTER + CAMGE W1,NUMLIN ;TEST FOR ENOUGH LINES MATCHED + JRST MULT2 ;COMPARE NEXT TWO. +MULT8: SKIPE 3WAY + JRST [ MOVE W1,TEMPF2 ;IN A 3-WAY MERGE, RECORD THIS MATCH OF FILES 1 AND 2 + HRL W1,TEMPF1 + IDPB W1,12MTBP + JRST MULT4] ;AND RETURN TO OUR CALLER (JUST AS IF WE HAD FAILED). + EXCH F1,TEMPF1 ;REMEMBER WHERE THE MULTI-LINE MATCH STOPPED, + EXCH F2,TEMPF2 ;GO BACK TO WHERE IT STARTED. + SUB P,[2,,2] ;FLUSH MULTI'S RETURN ADDRESS. + CALL COMSPC ;SEE IFF ALL DIFFERENCES VANISH WHEN IGNORE SPACES & COMMENTS. + JRST MULT10 + CALL PNTBTH ;PRINT DIFFERENCES + +;THE TEXT OF DIFFERENCES HAS BEEN PRINTED--PUT IN ****** +;AND A CARRIAGE RETURN-LINE FEED AND GO BACK AND START COMPARING +;WHEN WE START COMPARING AGAIN THE LINE POINTERA WILL +;BE POINTING TO THE FIRST TWO LINES AFTER THE MATCHING LINES + + CALL TRYMRG ;/M CHECK IF /M IN EFFECT, ASK FOR COMMAND + ;/M AND OUTPUT IF YES + JRST MULT10 ;/M IN EFFECT + MOVE W1,[440700,,[ASCIZ /*************** + +/]] + CALL PRINT +MULT10: SKIPE F1,TEMPF1 ;NOW MOVE FORWARD PAST THE LINES MATCHED + SETZM EOFFL1 ;IN THE MULTI-LINE MATCH. + SKIPE F2,TEMPF2 + SETZM EOFFL2 + JRST ENTER + +;AFTER FINDING A RUN OF DIFFERENCES, SEE WHETHER THE FILES ARE IDENTICAL +;WHEN WE IGNORE SPACES AND COMMENTS ACCORDING TO THE /S AND /C SWITCHES. +;IF SO, RETURNS NON-SKIPPING. SKIPS IF THE DIFFERENCE SHOULD BE PRINTED. +;EVEN IF /S AND /C ARE NOT SET, THIS ROUTINE TAKES CARE OF IGNORING +;DIFFERENCES IN BLANK LINES. ALSO, IF /K, IGNORES DIFFERENCES IN CASE. + +COMSPC: TLNE FR,FLSPAC ;THIS ROUTINE CAN MAKE A DIFFERENCE IF + TLNE FR,FLALL ;WE ARE IGNORING BOTH SPACING AND BLANK LINES + TLNE FR,FLCMNT ;OR WE ARE IGNORING COMMENTS. + CAIA + JRST POPJ1 ;NOTHING IGNORED => DO PRINT. + SAVE F1 + SAVE F2 + SKIPE F1,NLINES+0 ;MAKE F1 AND F2 POINT AT THE FIRST DIFFERING LINES. + MOVE F1,LBUFP+0 + SKIPE F2,NLINES+1 + MOVE F2,LBUFP+1 +COMSPL: CAMN F1,-1(P) ;HAVE WE CONSIDERED ALL THE LINES FROM FILE 1? + JRST COMSP2 + HRRI FR,0 ;NO. + TLNN FR,FLALL ;DON'T SKIP LINES WITH JUST COMMENTS IF NOT IGNORING BLANK LINES! + CALL BLANKP ;FIRST, TRY TO IGNORE ESSENTIALLY BLANK LINES + JRST COMSP2 ;IN FILE 1. + MOVE F1,LNNEXT(F1) ;FOUND ONE => SKIP PAST IT. + JRST COMSPL + +COMSP2: CAMN F2,(P) ;THEN TRY FOR BLANK LINES IN FILE 2 + JRST COMSPX ;NO LINES IN FILE 2 => CAN'T WIN. + HRRI FR,1 + TLNN FR,FLALL + CALL BLANKP + JRST COMSP3 + MOVE F2,LNNEXT(F2) + JRST COMSPL + +COMSP3: CAMN F1,-1(P) ;IF BOTH FILES HAVE LINES, + JRST COMSPX + CALL COMPCS ;SEE IF THEY ARE EQUAL WHEN SPACES & COMMENTS ARE IGNORED. + JRST COMSPF +;HERE WHEN WE CAN'T ELIMINATE ANY MORE LINES BY IGNORING SPACES & COMMENTS +COMSPX: CAMN F1,-1(P) ;IF NO LINES LEFT FROM EITHER FILE, WE WIN + CAME F2,(P) + AOS -2(P) ;OTHERWISE, THE DIFFERENCES ARE ESSENTIAL. + REST F2 + REST F1 + RET + +;COME HERE IF TWO LINES MATCH WHEN WE IGNORE APPROPRIATE STUFF. +COMSPF: MOVE F1,LNNEXT(F1) ;SKIP BOTH LINES. + MOVE F2,LNNEXT(F2) + JRST COMSPL + +;SKIP IF THE LINE F1(FR) POINTS AT IS BLANK WHEN +;SPACES AND COMMENTS ARE IGNORED ACCORDING TO SWITCH SETTINGS. +BLANKP: HRRZ W1,F1(FR) + MOVE C,LNSIZE(W1) + ADD W1,[440700,,LNDATA] +BLANK1: ILDB T,W1 + SOJLE C,POPJ1 ;WE WIN IF EXHAUST THE LINE AFTER JUST SPACES AND CRLFS. + CAIE T,^M + CAIN T,^J + JRST BLANK1 + CAIE T,40 + CAIN T,^I + TLNN FR,FLSPAC + CAIA + JRST BLANK1 + TLNE FR,FLCMNT ;IF /C, WE ALSO WIN IF WE FIND A SEMICOLON. + CAIE T,"; + RET + JRST POPJ1 + +3LOOP: +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]] + +;THIS IS THE MAIN LOOP OF 3-WAY MERGING. + +;COME HERE WHEN THE LAST LINES OF ALL 3 FILES MATCHED, TO TRY THE NEXT LINES OF ALL 3. +3SAME: SKIPE F1,LNNEXT(F1) ;ADVANCE PAST THE LINE THAT MATCHED + JRST 3SAME1 + TRZ FR,-1 ;IF NO MORE LINES IN CORE, FLUSH ALL + SKIPE MRGOUT+0 ;THE LINES WE PASSED BY, + CALL MOVEUP + SETZM NLINE1 ;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST) + CALL RDLIN ;AND READ ANOTHER. + CAIA + JFCL +3SAME1: SKIPE F2,LNNEXT(F2) ;SIMILAR FOR F2, + JRST 3SAME2 + SETZM NLINE2 ;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE. + HRRI FR,1 + CALL RDLIN + CAIA + JFCL +3SAME2: SKIPE F3,LNNEXT(F3) ;FOR F3, JUST LIKE F2. + JRST 3SAME3 + SETZM NLINE3 + HRRI FR,3 + CALL RDLIN + CAIA + JFCL +3SAME3: MOVE W1,EOFFL1 ;UNLESS EITHER ALL 3 FILES ARE ENDING OR NONE, + CAMN W1,EOFFL2 ;IT'S A DIFFERENCE. + CAME W1,EOFFL3 + JRST 3DIFF + CALL COMPL ;COMPARE LINE FROM FILE 1 WITH THAT FROM FILE 2. + CAIA + JRST 3DIFF + EXCH F2,F3 + CALL COMPL ;COMPARE FILE 1 WITH FILE 3. + CAIA + JRST [ EXCH F2,F3 + JRST 3DIFF] + EXCH F2,F3 ;1 MATCHES 2 AND MATCHES 3 => ALL 3 STILL THE SAME. + SKIPE EOFFL1 + JRST FIN2 + JRST 3SAME + +;COME HERE, DURING A 3-WAY MERGE, WHEN A DIFFERENCE IS SEEN. +;THAT IS, WHEN ALL 3 FILES CEASE TO BE IDENTICAL. +;F1, F2, F3 POINT AT THE FIRST NON-MATCHING LINES, +;OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. +;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING +;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. +3DIFF: HRRI FR,0 + CALL MOVEUP ;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO. + HRRI FR,1 + CALL MOVEUP + HRRI FR,2 + CALL MOVEUP + SKIPE 0 ;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE. + ERRHLT +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]] + SETZM NCOMP1 + SKIPL EOFFL1 + AOS NCOMP1 + SETZM NCOMP2 + SKIPL EOFFL2 + AOS NCOMP2 + SETZM NCOMP3 + SKIPL EOFFL3 + AOS NCOMP3 + MOVE W1,12MTBB ;CLEAR THE TABLE OF MATCHES BETWEEN FILES 1 AND 2. + MOVEM W1,12MTBP +3DIFFR: NEXTLN 1 ;READ ANOTHER LINE FROM EACH FILE. + SKIPL EOFFL1 + AOS NCOMP1 + NEXTLN 2 + SKIPL EOFFL2 + AOS NCOMP2 + NEXTLN 3 + SKIPL EOFFL3 + AOS NCOMP3 + SKIPE EOFFL2 + JRST 3DIFF2 + SKIPN CS,NCOMP1 ;HOW MANY FILE 1 LINES SHOULD WE CONSIDER? + JRST 3DIFF2 + SKIPA F1,LBUFP1 ;COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME, +3DIFF0: MOVE F1,W1 ;WITH THE NEW LINE FROM FILE 2. + CALL COMPL + CALL MULTI ;MATCH => CHECK FOR MULTI-LINE MATCH, PUT IN 12MTAB IF FOUND. + SKIPE W1,LNNEXT(F1) + SOJG CS,3DIFF0 +;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW +;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES. +;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT. +;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI). +3DIFF2: SKIPE EOFFL1 ;BUT DON'T DO IT IF NO NEW FILE 1 LINE. + JRST 3DIFF3 + SKIPN CS,NCOMP2 ;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2? + JRST 3DIFF3 + SKIPA F2,LBUFP2 ;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.) +3DIFF1: MOVE F2,W1 ;ELSE LOOP HERE OVER THE FILE 2 LINES. + CALL COMPL + CALL MULTI ;IF MULTI-LINE MATCH FOUND, PUT IT IN 12MTAB. + SKIPE W1,LNNEXT(F2) + SOJG CS,3DIFF1 +;NOW WE KNOW ABOUT THE PLACES WHERE FILES 1 AND 2 MATCH. +;EACH SUCH PLACE (WITHIN THE RANGE BEING CONSIDERED) IS LISTED IN 12MTAB. +;WE NOW COMPARE EACH OF THOSE PLACES AGAINST WHAT WE HAVE OF FILE 3. +3DIFF3: PUSH P,F1 + PUSH P,F2 + MOVE W1,12MTBB +3DIFF6: CAMN W1,12MTBP + JRST 3DIFF4 ;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM. + ILDB F2,W1 + PUSH P,W1 + ANDI F2,-1 ;FIND THE FILE 2 LOCATION OF THE NEXT 1-2 MATCH. + MOVE CS,NCOMP3 + SKIPA F1,LBUFP3 +3DIFF5: MOVE F1,W1 + CALL COMPL ;COMPARE THAT AGAINST EACH POINT OF FILE 3. + CALL 3MULTI ;NOTE THAT WE ARE USING F1 TO HOLD THE FILE 3 POINTER. + SKIPE W1,LNNEXT(F1) + SOJG CS,3DIFF5 + POP P,W1 + JRST 3DIFF6 + +3DIFF4: POP P,F2 + POP P,F1 ;NO MATCH FOUND. + SKIPE EOFFL1 ;NORMALLY, READ ANOTHER LINE FROM EACH FILE. + SKIPL EOFFL2 + JRST 3DIFFR + SKIPL EOFFL3 + JRST 3DIFFR + JRST 3ALDIF ;BUT IF ALL ARE AT EOF, TAKE ALL REMAINING LINES OF ALL FILES AS DIFFS. + + ; THIS IS A COLLECTION OF STUFF THAT WAS UNDEFINED AT THE + ; TIME CONVERSION TO TNX WAS DONE. VALUES ARE FURNISHED HERE + ; JUST TO MINIMIZE ASSEMBLY BARFAGE, BUT SOMEDAY PRESUMABLY + ; SOMEONE WILL REPLACE WITH THE PROPER THINGS. +3ALDIF: +3MULTI: RET ; NOP FOR NOW +.SCALAR 3WAY ; -1 IF DOING 3-WAY COMPARE +.SCALAR 12MTBP ; SOMETHING TO DO WITH 3WAY MERGE? +.SCALAR 12MTBB ; DITTO + +;/M ROUTINE TO TEST IF MERGE IN EFFECT AND IF YES +;/M ACCPT COMMAND AND PASS TO MERGE OUTPUT FILE +;/M COMMANDS ARE ANY COMBINATION OF 1,2,I AND/OR T (WITH NO COMMAS) +;/M ALL OTHER CHARACTERS ARE ILLEGAL +;/M CALL: CALL TRYMRG +; MERGER DONE RETURN +; /M NOT IN EFFECT RETURN + +TRYMRG: TLNN FR,FLMERG ;/M /M SWITCH IN EFFECT? + JRST POPJ1 ;/M NO, SKIP RETURN +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/MERGE/]] + TLNE FR,FLISWT ;/I => ASSUME "I" AS AN ANSWER. + JRST MRGI1 + TLNE FR,FLFLAG ;/F => PUT OUT THE FILE 2 STUFF WITH FLAGS. + JRST MRGU1 + CALL GETMRG ;/M TYPE *,GET ALL OF MERGE COMMAND(CHECK SYNTAX) +LISTEN: CALL MRGIN ;/M GET NEXT MERGE COMMAND INPUT CHAR + CAIE C,"1 ;/M DID HE TYPE 1? + CAIN C,"2 ;/M DID HE TYPE 2? + JRST MRG5 ;YES FOR ONE OF THEM! + CAIN C,"I + JRST MRGI ;"I"=> PUT IN BOTH FILES' TEXTS AND IDENTIFYING MARKS. + CAIE C,"T ;/M "T" TYPED? + JRST MRG4 ;/M NO, CHECK FOR END OF COMMAND +MRG3B: CALL TTILIN +MRG3A: CALL TTICHR ;GET TTY INPUT CHAR. + CAIE C,^C ;/M EOF OR + CAIN C,ALTM ;/M ALT-MODE? + JRST LISTEN ;/M YES, END OF INSERT FROM TTY + CALL MRGO ;/M NO, OUTPUT CHAR TO MERGE FILE + CAIE C,^M ;CR -> SPECIAL. + JRST MRG3A ;ELSE GET MORE + MOVEI C,^J ;PUT IN ^J AFTER ^M. + CALL MRGO + JRST MRG3B ;GET NEXT TTY LINE. + +MRG4: CAIE C,0 ;/M MUST BE NULL(END OF COMMAND) + ERRHLT ;/M NO SOME THING IS VERY WRONG + HRRI FR,0 ;/M FLUSH DIFFERENCES IN FILE ONE IF NOT ALREADY + SETZM MRGOUT(FR) ;/M BUT DO NOT OUTPUT ON MERGE FILE + CALL MOVEUP ;/M NO, OUTPUT DIFFERENCES AND FLUSH + HRRI FR,1 ;/M FLUSH DIFFERENCES IN FILE TWO IF NOT ALREADY + SETZM MRGOUT(FR) ;BUT DO NOT OUTPUT ON MERGE FILE + CALL MOVEUP ;/M NO, OUTPUT DIFFERENCES AND FLUSH + SETOM MRGOUT+0 + RET ;/M RETURN, LEAVING MATCH LINES STILL IN BUFFER + +MRG5: HRRI FR,-"1(C) + SETOM MRGOUT(FR) ;/M YES, SET FLAG SO MOVEUP WILL OUTPUT + CALL MOVEUP ;/M MOVE BUFFER UP OVER DIFFERENCES USER WANTS + JRST LISTEN ;/M GO GET ANOTHER CHARACTER + +;/F => WHEN DIFFERENCES ARE FOUND, OUTPUT THE LINES FROM FILE 2 +;WITH A "|" AT THE FRONT OF EACH ONE. +MRGU1: SETOM MRGOUT+1 + HRRI FR,1 + SETOM MRGUFL ;TELL MOVEUP TO INSERT "|"'S + PUSH P,F1(FR) + CALL MOVEUP ;OUTPUT THE STUFF FROM FILE 2 + REST W1 + MOVEI W2,[ASCIZ /^^^^/] ;THEN OUTPUT "^^^^" IN FRONT OF NEXT LINE + CAMN W1,F1(FR) ;IF THERE WERE NO LINES FROM FILE 2 (A DELETION). + CALL MRGPNT + SETZB C,MRGUFL + JRST MRG4 ;THROW AWAY STUFF FROM FILE 1 AND RETURN. + +;"I" MERGE COMMAND - PUT IN THE MERGE FILE THE FOLLOWING: +;*** MERGE LOSSAGE *** +;*** FILE FOOBAR 1001 HAS: +; +;*** FILE FOOBAR 1002 HAS: +; +;*** END OF MERGE LOSSAGE *** + +MRGI: SAVE [LISTEN] +MRGI1: MOVEI W2,[ASCIZ /*** MERGE LOSSAGE *** +*** FILE /] + CALL MRGPNT + MOVE W2,RCHSTP ;-> NAMES OF FILE 1. + CALL MRGPNT + MOVEI W2,[ASCIZ / HAS: +/] + CALL MRGPNT + SETOM MRGOUT ;OUTPUT THE TEXT OF FILE 1 + HRRI FR,0 + CALL MOVEUP + MOVEI W2,[ASCIZ /*** FILE /] + CALL MRGPNT + MOVE W2,RCHSTP+1 ;-> NAMES OF FILE 2. + CALL MRGPNT + MOVEI W2,[ASCIZ / HAS: +/] + CALL MRGPNT + SETOM MRGOUT+1 ;OUTPUT TEXT FROM FILE 2. + HRRI FR,1 + CALL MOVEUP + SETZM MRGOUT+1 ;CLEAR THIS OR WE'D GET 2 COPIES OF FURTHER UNCHANGED TEXT! + MOVEI W2,[ASCIZ /*** END OF MERGE LOSSAGE *** +/] + JRST MRGPNT + +;PRINT ASCIZ STRING <- W2 ON THE MERGE FILE. +MRGPNT: HRLI W2,440700 +MRGPN1: ILDB C,W2 + JUMPE C,CPOPJ + CALL MRGO + JRST MRGPN1 + +;OUTPUT STRING <- W2 WITH # CHARS IN C. +MRGCNT: SAVE W1 + SKIPN W1,C + JRST POPW1J +MRGCN1: ILDB C,W2 + CALL MRGO + SOJG W1,MRGCN1 + JRST POPW1J + +;HERE TO OUTPUT ONE CHARACTER TO CHMRG VIA BUFFER. +MRGO: IDPB C,MRGBP + SOSLE MRGCT + RET + +;EMPTY OUT OUR CHMRG BUFFER. +MRGFRC: SAVE W1 + SAVE W2 + MOVE W1,[440700,,MRGBF] + MOVEM W1,MRGBP + MOVEI W2,MRGBSZ + SUB W2,MRGCT ;# CHARS FILLED IN IT. + ADDM W2,MRGCT ;MARK IT EMPTY (AFTER WE WRITE DATA). + JUMPE W2,MRGFR1 + M.SOUT CHMRG,W1,W2 ; OUTPUT STRING +MRGFR1: REST W2 +POPW1J: REST W1 + RET + +;/M ROUTINE TO GET INPUT FOR MERGE COMMAND +;/M STORES ENTIRE COMMAND IN SPECIAL BUFFER +;/M IN CASE USER TYPES T COMMAND AS ONE OF COMMANDS +;/M WHICH WILL SLAO REQUIRE TTY INPUT +;/M CHECK SYSTAX, DO NOT RTURN UNTIL GOOD COMMAND LINE TYPED IN + +GTMRG0: HLRZ C,(P) + MOVEM W1,(C) +GETMRG: CALL TTILNA ;READ TTY LINE, PROMPTING WITH A "*". + MOVE W1,[440700,,MRGCOM] ;/M SET UP BYTE POINTER TO MERGE + ;/M COMMAND BUFFER +GTMRG1: MOVEI C,0 ;/M IN CASE TOO LONG COMMAND + CAME W1,[350700,,MRGCOM+MRGLEN-1] + CALL TTICHU + CAIGE C,40 ;/M ALTM,LF? + MOVEI C,0 ;/M YES, FLAG END OF MERGE COMAND WITH NULL + IDPB C,W1 ;/M STORE CHAR + CAIE C,"1 ;/M IS IT "1"? + CAIN C,"2 ;/M OR "2"? + JRST GTMRG1 ;/M YES, GET ANOTHER + CAIE C,"I + CAIN C,"T ;/M NO, IS IT "T"? + JRST GTMRG1 ;/M YES, GET ANOTHER + CAIN C,"L + JRST GTMRGL + CAIE C,"C ;/M C? + JRST GTMRG3 ;/M NO + SKIPA W1,[COLMAX] +GTMRGL: MOVEI W1,LINMAX + HRLM W1,(P) + MOVEI W1,0 +GTMRG2: CALL TTICHR ;/M GE CHAR + CAIGE C,40 ;/M END OFLINE CHAR? + JRST GTMRG0 ;/M YES STORE NEW MAX. + CAIL C,"0 ;/M NO, A DECIMAL DIGIT? + CAILE C,"9 ;/M + JRST GTMRG4 ;/M NO, PRINT ERROR + IMULI W1,12 ;/M YES CONVERT TO BINARY + ADDI W1,-"0(C) ;/M ADD IN THIS DIGIT + JRST GTMRG2 ;/M GO GET NEXT DIGIT + +GTMRG3: MOVE W1,[440700,,MRGCOM] ;/M ASSUME IT IS END OF LINE + MOVEM W1,MRGBYT ;/M AND STORE BYTE POINTER TO SCANNED STRING + JUMPE C,CPOPJ ;/M IS IT? +GTMRG4: MOVE W1,[440700,,[ASCIZ "?ONLY 1, 2, I, AND/OR T ARE LEGAL IN MERGE COMMANDS +OR C### TO SET MAX. COL. OR L### TO SET MAX. LINES TYPED. +"]] + CALL PRINT ;/M PRINT ERROR + JRST GETMRG ;/M AND ASK FOR COMMAND OVER AGAIN + +;/M ROUTINE TO GET NEXT CHAR FROM MERGE COMMAND BUFFER +;/M CALL: CALL MRGIN +;/M RETURN WITH CHAR IN C + +MRGIN: ILDB C,MRGBYT ;/M GET NEXT CHAR + RET + +;MOVEUP FLUSHES ALL THE LINES OF THE FILE SPECIFIED BY RH(FR) +;THAT ARE BEFORE THE LINE POINTED BY F1 OR F2 OR F3. +;IF THERE ARE ANY LINES AFTER F1 OR F2 OR F3, THEY HAVE TO BE BLT'ED DOWN +;TO THE BEGINNING OF THE FILE'S SEGMENT. IF THERE ARE NONE, +;ONLY POINTER RELOCATION TAKES PLACE. +;F1 OR F2 OR F3 CONTINUES TO POINT AT THE SAME LINE, OR REMAINS 0. +;IF MRGOUT(FR) IS NONZERO, THE FLUSHED LINES ARE OUTPUT TO THE +;MERGE FILE. + +MOVEUP: SKIPN FSBIN + SKIPE FVBIN + RET ; Ignore if doing binary compare. + SKIPE MRGOUT(FR) ;SKIP IF SHOULD OUTPUT TO MERGE FILE, + CALL MOVEU1 ;DO SO. + SKIPE W1,F1(FR) ;GET ADDR OF 1ST LINE NOT TO FLUSH. + JRST MOVEU5 + SETZM NLINES(FR) ;FLUSHING ALL LINES => JUST SAY THERE ARE NONE. + RET + +MOVEU5: MOVEI T,1 ;T COUNTS THE NUMBER OF LINES LEFT. + MOVN C,W1 ;WE MUST BLT FROM C(W1) TO C(LBUFP(FR)) + ADD C,LBUFP(FR) ;HOW FAR IS THAT? +MOVEU3: MOVE W2,W1 ;W2 REMEMBERS THE LAST LINE'S ADDR + CAMN W1,TEMPF1(FR) ;RELOCATE TEMPF1 IF IT POINTS AT THIS LINE. + ADDM C,TEMPF1(FR) + SKIPN W1,LNNEXT(W1) ;FIND THE NEXT LINE WHERE IT NOW IS + JRST MOVEU4 + ADDM C,LNNEXT(W2) ;RELOCATE POINTER -> WHERE IT WILL BE BLT'ED TO. + AOJA T,MOVEU3 ;ANOTHER LINE => COUNT IT. + +MOVEU4: MOVEM T,NLINES(FR) + HRLZ W1,F1(FR) ;LH(W1) GETS CURRENT ADDRESS OF 1ST LINE TO KEEP + HRR W1,LBUFP(FR) ;RH GETS NEW ADDR + MOVE T,LNSIZE(W2) ;FIND END OF LAST LINE + ADDI T,5 + IDIVI T,5 ;FIRST FIND LENGTH IN WORDS + ADDI W2,LNDATA-1(T) ;ADD ADDR OF START OF LINE + ADD W2,C ;FIND WHERE THAT END IS BEING RELOCATED TO. + BLT W1,(W2) ;COPY THE LINES THAT ARE LEFT TO THEIR NEW HOMES. + MOVE W1,LBUFP(FR) + MOVEM W1,F1(FR) ;NOW RELOCATE F1(FR). + RET + +;OUTPUT THE LINES UP THE FILE IN FR THAT ARE BEFORE F1 OR F2 OR F3 TO THE MERGE FILE. +MOVEU1: MOVE W1,LBUFP(FR) ;GET ADDR OF 1ST LINE TO BE FLUSHED. + SKIPN NLINES(FR) + SETZ W1, +MOVEU2: CAMN W1,F1(FR) ;REACHED 1ST LINE NOT TO BE FLUSHED? + RET ;NO, OUTPUT LINE W1 POINTS AT. + TLNE FR,FLFLAG + SKIPGE LPHONY ;IF THIS LINE IS PHONY (NOT FIRST AFTER A CRLF) + JRST MOVEU6 ;OMIT ANY /F HACKERY. + SKIPLE LPHONY ;IF FOLLOWS A STRAY CR, JUST PUT IN A TAB. + JRST MOVEU7 + MOVEI C,"| + SKIPE MRGUFL ;IF OUTPUTTING DIFFERENCES IN /F MODE, PREFIX WITH "|". + CALL MRGO + TLNN FR,FLFLAG ;IN /F MODE, PUT A TAB BEFORE EVERY LINE + JRST MOVEU6 + +MOVEU7: MOVEI C,^I ;SO "|"'S AND "^"'S CAN STAND OUT. + CALL MRGO +MOVEU6: MOVEI W2,LNDATA(W1) + HRLI W2,440700 ;GET ADDR OF 1ST DATA WORD + MOVE C,LNSIZE(W1) ;AND # OF CHARACTERS. + SETZM LPHONY ;SET LPHONY FOR NEXT LINE UNLESS THIS ONE ENDS IN A CRLF. + CAIGE C,2 + SETOM LPHONY + CALL MRGCNT ;TRANSFER THE CHARACTERS. + SOS W2 + REPEAT 3,IBP W2 ;DECREMENT W2 TWICE. + ILDB C,W2 + CAIE C,^M + SETOM LPHONY ;CHECK FOR THE TERMINAL CRLF. + ILDB C,W2 + CAIE C,^J + SETOM LPHONY + CAIN C,^M + MOVNS LPHONY ;LEAVE 1 IN LPHONY IF LINE ENDS IN JUST CR. + MOVE W1,LNNEXT(W1) ;GO TRY THE NEXT LINE. + JRST MOVEU2 + +;SKIP UNLESS THE TWO CURRENT LINES ARE EQUAL. IGNORES CASE CHANGES AND +;SPACING CHANGES IF SPECIFIED, BUT NEVER IGNORES COMMENTS. +;MUSTN'T CLOBBER CS. +COMPL: MOVE C,LNSIZE(F1) ;FIRST TEST FOR EXACT MATCH. + CAME C,LNSIZE(F2) + JRST COMPUL ;LINE LENGTHS DIFFER => NO EXACT MATCH, + MOVEI W1,5(C) ;ELSE COMPARE THE LINES WORD-BY-WORD. + IDIVI W1,5 + MOVNS W1 ;-<# WDS OF DATA IN LINE> + HRLZS W1 + HRRI W1,LNDATA(F1) ;AOBJN POINTER TO DATAT IN FILE 1 LINE. + MOVEI W2,LNDATA(F2) ;AND POINTER TO DATA OF FILE 2 LINE. + SUB W2,W1 + HRRM W2,COMPLX +COMPL1: MOVE C,(W1) ;COMPARE WORD BY WORD, IGNORING LOW BITS. +COMPLX: XOR C,(W1) ;ADDR FIELD MAKES E.A. POINT TO SECOND FILE'S LINE. + TDNE C,[-2] + JRST COMPUL ;JUMP IF NO EXACT MATCH. + AOBJN W1,COMPL1 + RET + +COMPUL: TLNN FR,FLCASE\FLSPAC ;NO EXACT MATCH. CAN WE TRY IGNORING STUFF? + JRST POPJ1 ;NO, SO MUST RETURN "NO MATCH". +;IGNORING CASE OR SPACING => WE GET A SECOND CHANCE. + MOVEI W1,LNDATA(F1) + MOVEI W2,LNDATA(F2) + HRLI W1,440700 + HRLI W2,440700 +COMPU1: ILDB T,W1 ;GET A CHARACTER FROM LINE FROM FIRST FILE + ILDB TT,W2 ;AND ONE FROM SECOND FILE + CAME T,TT ;THEY'RE EXACTLY EQUAL => KEEP LOOKING + JRST COMPU2 + JUMPN T,COMPU1 ;BUT DON'T LOOK PAST ENDS OF THE LINES. + POPJ P, ;REACH ENDS OF LINES => LINES MATCH. + +COMPU2: TLNN FR,FLSPAC + JRST COMPU4 + CAIE T,40 ;IF SUPPOSED TO IGNORE CHANGES IN SPACING, DO SO + CAIN T,^I ;BY SKIPPING ALL SPACES & TABS IN BOTH FILES. + JRST [ILDB T,W1 + JRST .-2] + CAIE TT,40 + CAIN TT,^I + JRST [ILDB TT,W2 + JRST .-2] +COMPU4: TLNN FR,FLCASE + JRST COMPU3 + CAIL T,"A+40 ;IF SUPPOSED TO IGNORE CHANGES IN CASE, CONVERT TO U.C. + CAILE T,"Z+40 + CAIA + SUBI T,40 + CAIL TT,"A+40 + CAILE TT,"Z+40 + CAIA + SUBI TT,40 +COMPU3: CAMN T,TT ;DO THEY MATCH NOW? + JRST COMPU1 + JRST POPJ1 ;NO => LINES DON'T MATCH. + +;SKIP UNLESS THE TWO CURRENT LINES ARE THE SAME WHEN APPROPRIATE +;STUFF IS IGNORED (SPACES AND COMMENTS, OR ALPHABETIC CASE, +; ACCORDING TO SWITCHES). +COMPCS: MOVEI W1,LNDATA(F1) + MOVEI W2,LNDATA(F2) + HRLI W1,440700 + HRLI W2,440700 +COMPL3: ILDB T,W1 ;GET A CHARACTER FROM LINE FROM FIRST FILE +COMPL6: ILDB TT,W2 ;AND ONE FROM SECOND FILE + CAME TT,T ;THIS IS THE BIG TEST--ARE THEY EQUAL + JRST COMPL4 ;NO +COMPL7: CAIN T,"; ;YES, COMMENT? + TLNN FR,FLCMNT ;YES, SUPPRESS COMMENTS? + JUMPN T,COMPL3 ;NO,NO. TEST FOR END OF LINE + RET ;LINES MATCH, RETURN + +COMPL4: TLNN FR,FLSPAC ;CHARS DIFFER: MAYBE TRY IGNORING SPACING + JRST COMPL8 + CAIE TT,40 ;SPACE IN FILE 2, OR TAB? + CAIN TT,TAB + JRST COMPL6 ;IF SO, SKIP IT. +COMPL5: CAIE T,40 ;SPACE IN FILE 1? + CAIN T,TAB ;OR TAB? + JRST [ILDB T,W1 ;SKIP TO FIRST NON-SPACE NON-TAB. + JRST COMPL5] + CAMN T,TT ;ARE THE CHARACTERS NOW THE SAME? + JRST COMPL7 ;YES, TEST FOR END OF LINES +COMPL8: TLNN FR,FLCASE ;SPACES DIDN'T HELP - ARE WE IGNORING CASE? + JRST COMPL2 + CAIL T,"A+40 ;CHARS DON'T MATCH => WE STILL HAVE A CHANCE + CAILE T,"Z+40 ;IF THEY'RE BOTH LETTERS; CONVERT BOTH TO UPPER CASE. + CAIA + SUBI T,40 + CAIL TT,"A+40 + CAILE TT,"Z+40 + CAIA + SUBI TT,40 + CAMN T,TT ;IF THIS HELPED, KEEP GOING + JRST COMPL3 ;NO USE CHECKING FOR EOL - THESE MUST BE BOTH LETTERS. +;LAST CHANCE - MAYBE ONE FILE HAS A COMMENT AND THE OTHER IS AT END OF LINE. +COMPL2: CAIE T,"; ;COMMENT IN FILE 1? + CAIN TT,"; ;OR IN FILE 2? + TLNN FR,FLCMNT ;AND ARE COMMENTS BEING IGNORED? + JRST POPJ1 ;NO, FILES DON'T MATCH, SKIP RETURN + JUMPE T,CPOPJ ;YES, OTHER CHAR MUST BE NULL OR ELSE ONE + JUMPE TT,CPOPJ ; LINE IS LONGER THAN OTHER AND FILES DIFFER +POPJ1: AOS (P) +APOPJ: +CPOPJ: RET + +;WHEN WE GET TO THIS POINT WE HAVE FOUND +;THE EXTENT OF THE DIFFERENCES AND WE ARE READY TO PRINT +;THESE DIFFERENCES OUT. F1 AND F2 POINT AT THE TWO MATCHING LINES +;THAT END THE RUN OF DIFFERENCES. + +PNTBTH: AOS ERRCNT ;INCREMENT # OF RUNS OF DIFFERENCES. + TLNE FR,FLISWT+FLFLAG + RET ;DON'T TYPE ON TTY IF /I OR /F. +IFN ITS,.SUSET [.SWHO2,,[SIXBIT/PRINT/]] + MOVEM P,FLUSHP ;SUPPLY P FOR --MORE--FLUSHED TO POPJ FROM. + TRZ FR,-1 ;OUTPUT FILE 1 + CALL PNTTXT ;PRINT FILE 1 DIFFERENCES + HRRI FR,1 ;THEN PRINT FILE 2 DIFFERENCES + CALL PNTTXT + SETZM FLUSHP + RET + +;OUTPUT THE LINES OF FILE (FR) BEFORE F1(FR), WITH A HEADER LINE. +;IF FLENDL=1, ALSO PRINTS THE LINE F1(FR) POINTS AT, IF ANY. +PNTTXT: CALL PNTHDL ;FIRST, THE HEADER LINE. + SKIPN NLINES(FR) + RET ;NO LINES => THAT'S ALL. + MOVE W1,LBUFP(FR) + SETZ W3, + SKIPE CS,F1(FR) ;CS GETS LINE TO STOP AT. + TLNN FR,FLENDL + CAIA + MOVE CS,LNNEXT(CS) +PNTTX1: CAME W1,CS ;REACHED 1ST LINE NOT TO OUTPUT => DONE. + CAML W3,LINMAX ;PRINTED MAX # OF LINES => STOP. + RET + TLNN FR,FLFNUM ;IF USER WANTS FILE # ON EVERY LINE, + JRST PNTTX2 + SAVE W1 + MOVEI W1,FNUMBR(FR) ;PRINT IT FOR HIM. + CALL PRINT + REST W1 +PNTTX2: MOVEI W2,LNDATA(W1) + HRLI W2,440700 + MOVE C,LNSIZE(W1) + CAML C,COLMAX ;IN /M MODE, LIMIT CHARS PRINTED TO COLMAX. + MOVE C,COLMAX + TLNN FR,FLMERG + MOVE C,LNSIZE(W1) + CALL PNTCNT ;OUTPUT THE TEXT OF THE LINE. + TLNN FR,FLALL ;IN /B MODE, THE CRLF IF ANY IS IN THE LINE. + CALL PCRLF ;OTHERWISE, MUST SUPPLY IT. + MOVE W1,LNNEXT(W1) ;MOVE TO NEXT LINE. + AOJA W3,PNTTX1 ;COUNT # LINES OUTPUT SO FAR. + +FNUMBR: ASCIZ /1) / ;FILE NUMBER OF FILE, FOR PRINTING. + ASCIZ /2) / +IFN .-FNUMBR-2,.ERR STRING TOO LONG + + +;OUTPUT A CRLF TO THE DIFFERENCE FILE. +PCRLF: MOVE W2,[440700,,[.BYTE 7 ? ^M ? ^J]] + MOVEI C,2 +PNTCNT: M.SOUT CHOUT,W2,C + RET + +;OUTPUT A HEADER LINE TO THE DIFFERENCE FILE, FOR INPUT FILE (FR). +PNTHDL: MOVE W2,[440700,,[ASCIZ/**** FILE /]] + MOVEI C,10. + CALL PNTCNT + MOVE W1,RCHSTP(FR) + CALL PRINT ;PRINT THE ASCIZ STRING CONTAINING THE FILE'S NAMES. + MOVE W2,[440700,,[ASCIZ /, /]] + MOVEI C,2 + CALL PNTCNT + MOVE W1,LBUFP(FR) ;GET THE PAGE # OF THE FIRST LINE FROM THE FILE. + SKIPN NLINES(FR) + SKIPA T,PAGNUM(FR) ;OR THE .IOT'ING PAGE # IF THERE AR NONE. + MOVE T,LNPGNM(W1) + CALL PNTDEC + MOUTI CHOUT,"- + SKIPN NLINES(FR) ;THEN THE LINE NUMBER + SKIPA T,LINNUM(FR) + MOVE T,LNLNNM(W1) + CALL PNTDEC + MOVEI W1,[ASCIZ/ (/] ;AND, IN PARENS, THE CHARACTER NUMBER. + CALL PRINT + MOVE W1,LBUFP(FR) + SKIPN NLINES(FR) + SKIPA T,CHRNUM(FR) + MOVE T,LNCHNM(W1) + CALL PNTDEC + MOUTI CHOUT,51 ; RIGHT PAREN (SCREWS MACRO) + TLNN FR,FLLABL\FLXLBL + JRST PCRLF + MOVE W1,LBUFP(FR) ;IF THE LAST LABEL IS KNOWN, PRINT IT TOO. + SKIPN NLINES(FR) + JRST [ MOVEI T,(FR) + IMULI T,LNLBLN + ADDI T,LLABEL + JRST PNTHD1] + MOVEI T,LNLLBL(W1) +PNTHD1: SKIPN (T) + JRST PCRLF + MOVEI W1,[ASCIZ / AFTER /] + SAVE T + CALL PRINT + REST W1 + TLNE FR,FLXLBL + MOUTI CHOUT,"" + SAVE LNLBLN(W1) + SETZM LNLBLN(W1) ;SUPPLY A ZERO TO END THE ASCIZ. + CALL PRINT + REST LNLBLN(W1) + TLNE FR,FLXLBL + MOUTI CHOUT,"" + JRST PCRLF + +; PNTHWD - Output number in T in halfword format. + +PNTHWD: PUSH P,T + HLRZS T + CALL PNTOCT + MOVEI C,2 + MOVE W2,[440700,,[ASCIZ /,,/]] + CALL PNTCNT + POP P,T + JRST PNTOCT + +; Print number in T in octal to difference file +; Use RH only, pad to 6 positions. +PNTOCT: MOVE W2,[440700,,PNTDBF] + PUSH P,T + MOVE TT,[220300,,(P)] + MOVSI C,-6 +PNTOC2: ILDB T,TT + JUMPN T,PNTOC3 + MOVEI T,40 + IDPB T,W2 ; PAD OUT WITH SPACES + AOBJN C,PNTOC2 + MOVEI T,"0 + DPB T,W2 + JRST PNTOC5 +PNTOC4: ILDB T,TT +PNTOC3: ADDI T,"0 + IDPB T,W2 + AOBJN C,PNTOC4 +PNTOC5: MOVEI C,6 + MOVE W2,[440700,,PNTDBF] + POP P,T + JRST PNTCNT + + +;PRINT NUMBER IN T IN DECIMAL TO DIFFERENCE FILE +PNTDEC: MOVE W2,[440700,,PNTDBF] + SETZ C, + CALL PNTDE1 + MOVE W2,[440700,,PNTDBF] + JRST PNTCNT + +PNTDE1: IDIVI T,10. + HRLM TT,(P) + SKIPE T + CALL PNTDE1 + HLRZ TT,(P) + ADDI TT,"0 + IDPB TT,W2 + AOJA C,CPOPJ + +;RH(W1) IS ADDR OF ASCIZ STRING; PRINT IT ON DIFFERENCE FILE. +PRINT: MOVEI W2,(W1) + HRLI W2,440700 + SETZ C, ;FIRST COUNT CHARS IN THE STRING, + ILDB T,W2 + SKIPE T + AOJA C,.-2 + MOVEI W2,(W1) ;THEN OUTPUT THE STRING. + HRLI W2,440700 + JRST PNTCNT + +;ASSUMING THAT F1(FR) POINTS TO THE LAST LINE IN FILE (FR), +;READ ANOTHER LINE AND MAKE F1(FR) POINT AT IT. +;ALSO OK IS IF WE HAVE NO LINES FROM THAT FILE AND F1(FR) IS 0. +;SKIPS TWICE IF SUCCESSFUL. CAN FAIL AND NOT SKIP IF CAN'T GET A LINE +;BECAUSE OF EOF; WILL RETURN WITH F1(FR) UNCHANGED AND EOFFL1(FR) NONZERO. +;WE DON'T EXPLICITLY GET CORE - THE MPV INT HANDER DOES THAT. +;THE MPV INT HANDLER CHECKS THE PC - ANY INSN THAT CAN LEGITIMATELY GET AN MPV +;SHOULD HAVE A LABEL SUCH AS "MPVOK1" AND BE MADE KNOWN TO THE INT HANDLER. + +RDLIN: TDNE FR,EOFTBL(FR) ;GIVE UP IF AT EOF IN FILE. + JRST [ SETOM EOFFL1(FR) + RET] + MOVE W1,LBUFP(FR) ;IF NO LINES IN CORE, NEXT LINE GOES AT START OF SEG. + SKIPN NLINES(FR) + JRST RDLIN0 + SKIPN W1,F1(FR) ;ELSE, GET POINTER TO CURRENT LINE + ERRHLT + MOVE T,LNSIZE(W1) ;FIND WORD AFTER THE END OF IT + ADDI T,5 + IDIVI T,5 + ADDI W1,LNDATA(T) ;THAT WILL BE THE ADDRESS OF THE NEW LINE. +RDLIN0: SETZ W3, ;COUNT # OF CHARS WE SKIP IN T. + MOVE CS,@GCHARP(FR) ;SWAP THE FILE B.P. INTO AN AC FOR SPEED. +RDLIN1: ILDB C,CS + CAIG C,^M + XCT RDLT1(C) ;LOOP TILL 1ST CHAR OF NON-NULL LINE SEEN. +RDLIN4: ADDB W3,CHRNUM(FR) ;INITIALIZE THE LINE'S DATA, +MPVOK0: MOVEM W3,LNCHNM(W1) ;STORING THE LAST WORD FIRST TO MAKE SURE CORE EXISTS. +IFN LNDATA-LNCHNM-1,.ERR + TLNN FR,FLLABL\FLXLBL ;SAVE TIME IF LABEL FEATURE NOT IN USE. + JRST RDLIN5 + MOVEI W3,LNLLBL(W1) + DPB FR,[240100,,W3] ;PUT 4*RH(FR) IN LH(W3) + ADD W3,[LLABEL,,] .SEE LNLBLN ;4 WORDS OF LABEL STRING. + BLT W3,LNLLB3(W1) +RDLIN5: MOVE W2,PAGNUM(FR) + MOVEM W2,LNPGNM(W1) + MOVE W2,LINNUM(FR) + MOVEM W2,LNLNNM(W1) + SETZM LNNEXT(W1) + MOVEI W2,LNDATA(W1) + HRLI W2,440700 ;THEN MAKE W2 A B.P. TO IDPB THE DATA AREA, + MOVE RDLIN7,[RDLIN6,,BP] + BLT RDLIN7,RDLIN7 + TDZ W3,W3 ;AND COUNT CHARS STORED IN LINE IN W3. + JRST MPVOK1 + +RDLIN6: OFFSET BP-. +RDLIN2:: ILDB C,CS +MPVOK1:: XCT RDLT2(C) ;USUALLY IDPB C,W2, BUT MAY EXIT TO RDLIN3. +RDLIN7:: AOJA W3,RDLIN2 + OFFSET 0 + +RDLIN3: AOS NLINES(FR) ;WHEN WE GET HERE, THE LINE REALLY EXISTS, + SKIPE F1(FR) ;SO PUT IT IN THE CHAIN + MOVEM W1,@F1(FR) +IFN LNNEXT,.ERR + MOVEM W1,F1(FR) ;AND POINT AT IT. + MOVEM W3,LNSIZE(W1) ;REMEMBER # CHARS IN THIS LINE. + ADDM W3,CHRNUM(FR) ;UPDATE CHAR POSITION IN FILE + MOVEM CS,@GCHARP(FR) ;STORE BACK THE FILE'S BUFFER B.P. + SETZB T,TT +MPVOK6: IDPB T,W2 ;STORE A TRAILING ZERO, THEN + LDB T,[360600,,W2] ;ZERO OUT REST OF LAST WORD. + DPB T,[301400,,W2] + DPB TT,W2 + TLNE FR,FLXLBL ;IF ANY UNINDENTED NON-COMMENT LINE IS A LABEL + CALL LABEL ;GO SET UP LLABEL WITH THIS LINE'S LABEL IF IT HAS ONE. + AOS (P) + JRST POPJ1 + +;DISPATCH TABLE FOR FINDING A NON-NULL LINE. +RDLT1: JFCL + JFCL + JFCL + JRST RDLINC ;^C +REPEAT 6,JFCL + JRST RDLINJ ;^J + JFCL + JRST RDLINL ;^L + JRST RDLINM ;^M +IFN .-RDLT1-^M-1,.ERR WRONG LENGTH TABLE + +;DISPATCH TABLE FOR ADDING MORE CHARS TO A LINE. +RDLT2: REPEAT 200,IDPB C,W2 +LOC RDLT2+^C ? JRST RDLILC +LOC RDLT2+^J ? JRST RDLILJ +LOC RDLT2+^L ? JRST RDLILL +LOC RDLT2+^M ? JRST RDLILM +LOC RDLT2+": ? JRST RDLCLN +LOC RDLT2+200 + +;^J, ^L OR ^M WHEN LOOKING FOR START OF LINE: +;UPDATE PAGE OR LINE NUMBER, AND IGNORE CHAR UNLESS /B. +RDLINL: TLNE FR,FLALL + JRST RDLIN4 + SETZM LINNUM(FR) + AOS PAGNUM(FR) + AOS LINNUM(FR) +IFN ITS,[ + HRLZ T,PAGNUM+0 + HRR T,PAGNUM+1 + .SUSET [.SWHO3,,T] +] + AOJA W3,RDLIN1 + +RDLINJ: TLNE FR,FLALL + JRST RDLIN4 + AOS LINNUM(FR) + AOJA W3,RDLIN1 + +RDLINM: TLNN FR,FLALL + AOJA W3,RDLIN1 ;NO /B; SKIP THE CHAR, BUT COUNT IT IN # THAT WERE SKIPPED. + JRST RDLIN4 ;/B, ANY CHAR STARTS A LINE. + +;^J, ^L OR ^M WHEN ADDING TO A NON-NULL LINE: +;UPDATE PAGE OR LINE NUM, AND END THE LINE, STORING CHAR IFF /B. +RDLILL: SETZM LINNUM(FR) + AOS PAGNUM(FR) +IFN ITS,[ + HRLZ T,PAGNUM+0 + HRR T,PAGNUM+1 + .SUSET [.SWHO3,,T] +] +RDLILJ: AOS LINNUM(FR) + TLNN FR,FLALL + JRST RDLIL1 +MPVOK2: IDPB C,W2 + AOJA W3,RDLIN3 + +RDLIL1: AOS CHRNUM(FR) ;NOT /B: MUST UPDATE # CHARS FROM FILE SINCE RDLIN3 WON'T. + JRST RDLIN3 + +RDLILM: TLNN FR,FLALL ;^M INSIDE A LINE. + JRST RDLIL1 +MPVOK3: IDPB C,W2 ;IN /B MODE, STORE IT AND LOOK FOR FOLLOWING ^J. +RDLIL2: ILDB C,CS + CAIN C,^J + AOJA W3,RDLILJ ;FOUND => STORE IT TOO. + CAMN CS,GCHARE(FR) ;DON'T LOSE BECAUSE OF WRAPAROUND IN BUFFER. + JRST [ CALL RELOAD + JRST RDLIL2] + AOJ W3, + DBP7J CS,RDLIN3 + +;HANDLE COLON IN A LINE. IF /L, MAYBE SET THE FILE'S LLABEL VARIABLE. +RDLCLN: TLNN FR,FLLABL + JRST MPVOK4 ;COLON JUST GOES INTO LINE IF LABEL FEATURE OFF. + JUMPE W3,MPVOK4 ;COLON AT BEGINNING OF LINE ISN'T A LABEL. + MOVEI T,LNDATA(W1) ;MAKE SURE THERE ARE NO SPACES, TABS, COLONS OR SEMIS + HRLI T,440700 ;BEFORE THIS COLON. +RDLCL0: ILDB TT,T + CAIG TT,40 + JRST MPVOK4 + CAIE TT,": + CAIN TT,"; + JRST MPVOK4 ;IT LOSES - IT'S JUST A NORMAL COLON. + CAME T,W2 ;SKIP IF IT WINS. MAKE IT THIS FILE'S LAST LABEL. + JRST RDLCL0 +MPVOK5: MOVES LNDATA+1(W1) ;MAKE SURE AT LEAST 2 WORDS OF CORE EXIST +MPVOK7: MOVES 1(T) ;MAKE SURE THERE'S SPACE FOR THE COLON AND TRAILING 0. + MOVEI TT,": + IDPB TT,T ;STORE THE COLON IN THE LINE. + SETZ TT, ;STORE A ^@ AFTER THE COLON. IT WILL GET OVERWRITTEN + IDPB TT,T ;BY LINE'S NEXT CHAR, BUT WILL LIVE ON IN LLABEL. + HRRZ T,FR + LSH T,2 + ADDI T,LLABEL-1 ;T GETS LLABEL-1, PLUS 4 TIMES FILE NUMBER. + PUSH T,LNDATA(W1) ;STORE 1ST 2 WORDS OF THIS LINE'S DATA THERE. + PUSH T,LNDATA+1(W1) +REPEAT LNLBLN-2,PUSH T,[0] ;2 WORDS ARE ENOUGH FOR A MIDAS LABEL, SO ZERO OUT THE REST. + JRST MPVOK4 + +;HERE IF /Y, AFTER READING IN THE LINE, TO SEE IF IT HAS A LABEL. +;A LINE HAS A LABEL IN /Y MODE IF IT STARTS WITH ANYTHING BUT A SPACE, TAB OR ;. +;W1 POINTS AT THE LINE. +LABEL: SKIPN W3,LNSIZE(W1) + RET ;IGNORE EMPTY LINES. + LDB T,[350700,,LNDATA(W1)] ;GET THE LINE'S FIRST CHARACTER. + CAILE T,40 + JRST LABEL1 ;STARTS WITH NON-CONTROL NOT SPACE => PROBABLY A LABEL. + CAIN T,40 + RET + CAIE T,^I + CAIN T,^L ;BUT LINES STARTING WITH FORMATTERS AREN'T. + RET + CAIE T,^M ;IN /B MODE A LINE CAN BE JUST ONE OF THESE. THEY AREN'T. + CAIN T,^J + RET +LABEL1: CAIN T,"; ;CHECK ; HERE - SAVES TIME FOR INDENTED LINES. + RET + HRRZ T,FR + IMULI T,LNLBLN + ADDI T,LLABEL-1 ;GET -1 + ADDR OF PLACE TO PUT LABEL. + MOVE TT,T ;SAVE THIS FOR LABEL2 WHICH ALSO NEEDS IT. +REPEAT LNLBLN,[ + CAIL W3,.RPCNT*5+1 ;COPY START OF LINE INTO IT, BUT DON'T GO PAST END OF LINE + PUSH T,.RPCNT+LNDATA(W1) ;IF IT IS A SHORT ONE. +] ;NO NEED TO ZERO OUT REST OF WORDS CAUSE IF LINE IS SHORT + TLNN FR,FLALL ;THEN THE REAL DATA MUST HAVE A ^@ AFTER IT ANYWAY. + RET + MOVEI T,1(TT) ;IN /B MODE, THE LINE MAY HAVE A REAL ^M^J IN IT, + HRLI T,440700 ;AND IF IT IS SHORT THEN THE ^M^J WAS COPIED INTO THE LABEL. + MOVEI W3,5*LNLBLN ;SO REPLACE IT WITH A NULL, IN THE LABEL. +LABEL2: ILDB TT,T + JUMPE TT,CPOPJ ;LABEL ENDS WITH NULL AND HAS NO ^M OR ^J? + CAIE TT,^M + CAIN TT,^J + CAIA + SOJG W3,LABEL2 ;MAYBE WE EXHAUST THE WORDS OF LABEL AND THERE IS NONE. + JUMPE W3,CPOPJ + SETZ TT, ;IF THERE IS A ^M OR ^J, TRUNCATE LABEL AT THAT POINT. + DPB TT,T + RET + +;HANDLE ^C WHEN LOOKING FOR START OF LINE. +RDLINC: CAMN CS,GCHARE(FR) ;IS THIS THE ^C AFTER THE BUFFER? + JRST [ CALL RELOAD ;YES, RELOAD THE BUFFER AND TRY AGAIN. + JRST RDLIN1] + CAME CS,@GCHARZ(FR) ;IS THIS EOF, OR A ^C IN THE FILE? + JRST RDLIN4 ;^C IN FILE STARTS A LINE. + IOR FR,EOFTBL(FR) ;IT IS EOF. +RDLIL5: SETOM EOFFL1(FR) + MOVEM CS,@GCHARP(FR) + RET + +;HANDLE ^C WHEN ADDING TO A LINE. +RDLILC: CAMN CS,GCHARE(FR) + JRST [ CALL RELOAD + JRST RDLIN2] + CAME CS,@GCHARZ(FR) ;^C IN FILE GOES IN THE LINE. + JRST MPVOK4 + IOR FR,EOFTBL(FR) ;EOF IN MIDDLE OF LINE: SAY EOF WAS REACHED. + MOVEI T,LNDATA-1(W1) +RDLIL4: CAIN T,(W2) ;FLUSH ALL ^C'S AND ^@'S OFF THE END OF THE LINE. + JRST RDLIL5 ;LINE WAS NOTHING BUT ^C'S AND ^@'S? SAY THERE WAS NO LINE. + LDB C,W2 + CAIE C,^C + JUMPN C,RDLIN3 ;LINE HAS SOMETHING ELSE, SO RETURN IT. + SOJ W3, + DBP7J W2,RDLIL4 + +MPVOK4: IDPB C,W2 ;COME HERE TO INSERT A ^C OR : IN A LINE, + AOJA W3,RDLIN2 ;WITHOUT THE SPECIAL HANDLING THEY SOMETIMES GET. + +; RDWRD - Read a word from file. This is completely independent of +; RDLIN and RELOAD. +; Returns .+1 if EOF +; Returns .+2 otherwise, +; W1/ word + +RDWRD: SOSGE GWORDC(FR) ; Decrement total cnt for file + JRST [ SETOM EOFFL1(FR) ; Hit EOF. + SETOM GWORDB(FR) + SETZM GWORDC(FR) ; Keep this normalized. + RET] + AOSE W1,GWORDB(FR) ; Skip for initial loadup + CAMLE W1,GWORDE(FR) + JRST RDWRD2 ; Load up the buffer. + MOVE W1,(W1) + AOS (P) + RET +RDWRD2: MOVEI CS,FILBFL + MOVE C,GWORDI(FR) + HRRZM C,GWORDB(FR) + CALL @GCHARX(FR) ; Read another bufferful + MOVE W1,@GWORDB(FR) ; Get 1st wd of buffer + AOS (P) + RET + +GWORDL: BLOCK 3 ; # words length of file +GWORDC: BLOCK 3 ; # words left in file +GWORDB: -1 ? -1 ? -1 +GWORDI: 444400,,FILBF1 + 444400,,FILBF2 + 444400,,FILBF3 +GWORDE: FILBE1 ? FILBE2 ? FILBE3 + +; RUDWRD - Read a word from inferior process. +; This is completely independent of RDLIN and RELOAD. +; Returns .+1 if EOF +; Returns .+2 otherwise, +; W1/ word + +RDUWRD: SOSGE GWORDC(FR) ; Decrement total cnt for file + JRST [ SETOM EOFFL1(FR) ; Hit EOF. + SETOM GWORDB(FR) + SETZM GWORDC(FR) ; Keep this normalized. + RET] + AOSE W1,GWORDB(FR) ; Skip for initial loadup + CAMLE W1,GWORDE(FR) + JRST RDUWD2 ; Load up the buffer. + MOVE W1,(W1) + AOS (P) + RET +RDUWD2: MOVEI CS,FILBFL + MOVE C,GWORDI(FR) + HRRZM C,GWORDB(FR) + CALL RDUBUF + MOVE W1,@GWORDB(FR) ; Get 1st wd of buffer + AOS (P) + RET + +RDUBUF: +IFN ITS,[ + M.SIN CHUIN1(FR),C,CS + RET +] ;IFN ITS +IFN TNX,[ + TYPE "Error - TNX version doesn't have /$ feature yet +" + HALT +] ;IFN TNX + + +;REFILL THE BUFFER OF THE FILE (FR). WORKS WHETHER READING IN CHAR +;OR WORD MODE, ON BOTH ITS AND TNX (WHICH UPDATE BP'S DIFFERENTLY). +RELOAD: MOVE C,GCHARI(FR) ;YES, JUST REFILL THE BUFFER. GET BP + MOVEI CS,FILBFL ;AND COUNT + CALL @GCHARX(FR) ;INPUT THE STUFF + TLZ C,7700 + TLO C,0700 ;MAKE BP A CHAR B.P. (IF NOT ALREADY) + MOVEI CS,^C + IDPB CS,C ;PUT A ^C AFTER WHAT WE INPUT. + MOVEM C,@GCHARZ(FR) ;AND SAVE BP TO EOF CHAR. + MOVE CS,GCHARB(FR) ;RE-INIT THE B.P. + RET + +GCHARP: FILPT1 ;ADDRESS OF BUFFER BP OF FILE. + FILPT2 + FILPT3 + +GCHARZ: FILEP1 ;ADDR OF B.P. TO THE ^C AFTER WHAT WAS READ IN. + FILEP2 + FILEP3 + +GCHARI: 444400,,FILBF1 ; BP TO IDPB 1ST WD OF BUFFER. + 444400,,FILBF2 + 444400,,FILBF3 + +GCHARB: 440700,,FILBF1 ;B.P. TO ILDB 1ST CHAR OF BUFFER. + 440700,,FILBF2 + 440700,,FILBF3 + +GCHARE: 350700,,FILBE1+1 ;B.P. TO ^C AFTER END OF BUFFER. + 350700,,FILBE2+1 + 350700,,FILBE3+1 + +GCHARX: [M.SIN CHIN1,C,CS ;INSTRS TO INPUT ON CHIN1 + RET] + [M.SIN CHIN2,C,CS ;DITTO FOR CHIN2 + RET] + [M.SIN CHIN3,C,CS + RET] + +EOFTBL: FLEOF1,, ;EOF FLAG FOR FILE 1 + FLEOF2,, ;EOF FLAG FOR FILE 2 + FLEOF3,, + +RCHSTP: 440700,,HBUF1 ;BYTE POINTERS TO HEADER TABLES + 440700,,HBUF2 + 440700,,HBUF3 + +; INT HANDLER, ITS ONLY - HANDLES MPV AND --MORE-- INTERRUPTS. +; TNX DOESN'T NEED MPV HANDLER (ALTHO IT MAKES ERRORS HARDER TO FIND) +; AND DOESN'T HAVE --MORE-- INTERRUPTS... + +IFN ITS,[ + +TSINT: + LOC 42 ? JSR TSINT ? LOC TSINT ; ENSURE INT VECTOR SET UP + 0 + 0 + EXCH W1,TSINT + JUMPL W1,MORINT + CAIE W1,%PIMPV + ERRHLT + HRRZ W1,TSINT+1 ;MPV INTERRUPTS TO GET MORE CORE ARE LEGAL + CAIE W1,MPVOK7 ;ONLY FROM CERTAIN SPOTS. + CAIN W1,MPVOK6 + JRST TSINT2 + CAIE W1,MPVOK5 + CAIN W1,MPVOK4 + JRST TSINT2 + CAIE W1,MPVOK3 + CAIN W1,MPVOK2 + JRST TSINT2 + CAIE W1,MPVOK1 + CAIN W1,MPVOK0 + CAIA + ERRHLT +TSINT2: .SUSET [.RMPVA,,W1] + LSH W1,-10. + SYSCAL CORBLK,[MOVEI 400000 ? MOVEI -1 ? W1 ? MOVEI 400001] + JRST [ CALL TYLERR ? JRST ERRFIN] + MOVE W1,TSINT + .DISMI TSINT+1 + +MORINT: MOVE W1,TSINT + INSIRP PUSH P,C T + MOVEI T,[ASCIZ /--MORE--/] + CALL TYPMS0 + SYSCAL IOT,[MOVEI CHTTI ? MOVE C ? 5000,,%TIPEK] + .LOSE 1000 + CAIN C,^C + JRST MORKIL + CAIE C,40 + CAIN C,177 + .IOT CHTTI,C ;SPACE OR RUBOUT IS GOBBLED. + SKIPE FLUSHP + CAIN C,40 ;IF IT ISN'T SPACE, AND WE CAN FLUSH, DO SO. + JRST MORPRC + MOVEI T,[ASCIZ /FLUSHED +/] + CALL TYPMS0 + MOVE P,FLUSHP + SETZM FLUSHP + .DISMI [CPOPJ] + +MORKIL: .IOT CHTTI,C ;^C => GOBBLE IT AND KILL THE SRCCOM. + .LOGOUT + .BREAK 16,160000 + +MORPRC: MOVEI T,[ASCIZ / +/] + CALL TYPMS0 + INSIRP POP P,T C + .DISMI TSINT+1 + +] ;IFN ITS + +;OPEN INPUT FILE ON CHNL IN W1. + +INOPEN: MOVEI FP,INFB + HRLI FP,(W1) ;MAKE ,, +IFN ITS,[ + MOVSI W2,(SIXBIT/>/) + SKIPN $F6FN2(FP) ;DEFAULT THE FN2 TO ">". + MOVEM W2,$F6FN2(FP) +] + MOVEI W2,OPNRDA ;USE UNIT MODE FOR /X FILES, + TLNN FR,FLXCTF + MOVEI W2,OPNRDW ;USE BLOCK MODE FOR OTHER INPUT FILES. + CALL (W2) + CALL OPENL ; LOST?? REPORT ERROR. + MOVE W2,INOPT3-CHIN1(W1) ;GET ADDR OF LAST WORD OF BUFFER. + MOVEI W1,(W2) + HRLI W1,10700 ;MAKE B.P. TO END OF BUFFER, + MOVEM W1,FILPT1-FILBE1(W2) + MOVE W1,[ASCIC//] + MOVEM W1,1(W2) + HRRI FR,0 ;PUT NUMBER OF FILE INTO FR. + CAIE W2,FILBE1 + HRRI FR,1 + PJRST RCHST ;SET UP FILE'S HEADER. + +INOPT3: FILBE1 + FILBE2 + FILBE3 + +;COME HERE WHEN /@ IS SPECIFIED FOR THE 1ST INPUT FILE. +;THAT MEANS TO TREAT THE SPECIFIED 1ST INPUT FILE AS A COMPARISON +;FILE, EXTRACT THE NAME OF THE SECOND FILE USED IN THAT COMPARISON, +;AND USE THAT FILE AS OUR 1ST INPUT FILE THIS TIME. +;JUMPS BACK TO THE COMMAND PROCESSING LEVEL TO OPEN THE REAL 1ST INPUT FILE. +RFINDR: MOVE W1,GCHARI + MOVEI W2,FILBFL + M.SIN CHIN1,W1,W2 ;READ IN SOME OF THE FILE. + ADDI W1,1 + ANDI W1,-1 ;MAKE SURE IT LOOKS LIKE A COMPARISON FILE. + CAIGE W1,FILBF1+10. + JRST ERRIND + MOVE W1,FILBF1 + MOVE W2,FILBF1+1 + CAMN W1,[ASCII / +;CO/] + CAME W2,[ASCII /MPARI/] + JRST ERRIND + MOVE W1,FILBF1+2 + CAME W1,[ASCII /SON O/] + JRST ERRIND + MOVE W1,[350700,,FILBF1+3] ;POINT AT THE SPACE AFTER THE "OF". + MOVEI W2,4 +RFIND2: ILDB C,W1 ;THEN SKIP PAST 3 SPACES, TO BE AFTER THE "AND". + CAIE C,40 + JRST RFIND2 + SOJG W2,RFIND2 + SAVE TTIPNT ;WHICH IS JUST AT THE SECOND COMPARED FILE'S NAME. + SAVE TTICNT + HRLZM P,TTICNT + MOVEM W1,TTIPNT ;READ IN THAT FILE NAME + CALL RFILE ;RFILE RETURNS AFTER THE FN2 SINCE FLINDR=1. + ILDB C,TTIPNT + CAIE C,^J + JRST .-2 ;PASS THE LINEFEED OF THAT LINE + MOVEI C,3 + ADDM C,TTIPNT ;SKIP THE ";OPTIONS ARE " + CALL RFILSW ;READ THE SWITCHES FROM THE COMPARISON FILE + REST TTICNT + REST TTIPNT + TLZ FR,FLINDR + JRST RFIND1 + +IFN ITS,[ + +;PUT FILE DESCRIPTION IN ASCII INTO HBUF FOR THIS FILE +RCHST: SYSCAL RFNAME,[ MOVEI CHIN1(FR) + 2000,,RCHSTB + 2000,,RCHSTB+1 + 2000,,RCHSTB+2 + 2000,,RCHSTB+3] + .LOSE 1000 + SYSCAL FILLEN,[MOVEI CHIN1(FR) ? MOVEM W2] + .LOSE 1000 + MOVEM W2,GWORDL(FR) ; Set length of file + MOVEM W2,GWORDC(FR) ; Also # of words left to read + + MOVE W2,RCHSTP(FR) ;NOW SET UP BYTE POINTER TO HEADER AREA TO READ INTO + MOVE T,RCHSTB ;GET THE CHOSEN DEVICE NAME + JSP W1,RCHST6 ;DEVICE NAME + ": ;END WITH COLON + MOVE T,RCHSTB+3 + JSP W1,RCHST6 ;SYSTEM NAME + "; ;TERMINATED BY SEMICOLON + SKIPN T,RCHSTB+1 + MOVE T,INFB+$FNAME ;IF REALLY NONE, USE SPEC'D. + SKIPN LSTFB+$FNAME ;DEFAULT OUTPUT FN1 TO INPUT. + MOVEM T,LSTFB+$FNAME + JSP W1,RCHST6 ;FNAM1 + 40 ;TERMINATED (ITS CONVENTION) BY SPACE + SKIPN T,RCHSTB+2 + MOVE T,INFB+$FEXT + JSP W1,RCHST6 ;FNAM2 + 0 ;DON'T PRINT TERMINATING CHAR + MOVEI C,0 + IDPB C,W2 ;MARK END OF STRING + SKIPN FSBIN ; If hacking inferior process addr space, skip + RET ; else return, done. + + SKIPN UNQNAM + .SUSET [.RJNAME,,UNQNAM] + AOS UNQNAM + MOVEI T,CHUO1(FR) + HRLI T,.UIO + SYSCAL OPEN,[T ? ['USR,,] ? [0] ? UNQNAM] + .LOSE 1000 + MOVEI T,CHUIN1(FR) + HRLI T,.UII + SYSCAL OPEN,[T ? ['USR,,] ? [0] ? UNQNAM] + .LOSE 1000 + SYSCAL LOAD,[MOVEI (T) ? MOVEI CHIN1(FR)] + .LOSE 1000 + SYSCAL ACCESS,[MOVEI (T) ? [0]] + .LOSE 1000 + SYSCAL USRVAR,[MOVEI (T) ? [SIXBIT /MEMT/] ? MOVEM W2] + .LOSE 1000 + MOVEM W2,GWORDL(FR) + MOVEM W2,GWORDC(FR) + RET +.SCALAR UNQNAM + + ;JSP W1,RCHST6 ;PRINT (IDPB ASCII VIA W2) SIXBIT WORD IN T + ; " ;FOLLOW WITH TERMINATING CHAR UNLESS SIXBIT IS NULL + ; ^ DOESN'T PRINT TRAILING SPACES + +RCHST6: JUMPE T,1(W1) ;RETURN ON NULL ARG +RCHS6A: MOVEI C,0 ;CLEAR OUT C TO RECEIVE CHAR + LSHC C,6 ;SHIFT IN NEXT CHAR + ADDI C,40 ;CONVERT TO ASCII + IDPB C,W2 ;DEPOSIT WHEREVER IT'S GOING + JUMPN T,RCHS6A ;LOOP UNTIL WORD EMPTY + SKIPE C,(W1) ;NOW GET TERMINATOR + IDPB C,W2 ;NOT NULL, USE IT + JRST 1(W1) +] ;IFN ITS + +;READ IN A COMMAND, PROCESSING RUBOUTS, PROMPTING WITH "#". +CMDLIN: SKIPE CMDFIL + JRST TTIFIL ;IF IN COMMAND FILE, READ FROM IT INSTEAD OF TTY. +TTILIN: HRROS (P) ;PROMPT WITH "#". + JRST TTILI1 + +TTILNA: HRRZS (P) ;FOR /M INPUT, PROMPT WITH "*" + JRST TTILI1 + +;READ A CHAR OF TTY INPUT (OR ^M IF NONE LEFT). +TTICHR: SOSGE TTICNT ;IF NO CHARS LEFT, + SKIPA C,[^M] ;SAY EOL. + ILDB C,TTIPNT ;ELSE GET NEXT CHAR FROM BUFFER. + RET + +;READ AND UPCASE A CHAR OF INPUT. +TTICHU: CALL TTICHR ;GET CHAR + CAIL C,"A+40 ;SKIP IF LESS THAN LOWER CASE A + CAILE C,"Z+40 ;SKIP IF IN RANGE A-Z + CAIA ;SKIP IF NOT A-Z (LC) + SUBI C,40 ;LOWER CASE TO UPPER CASE + RET + +IFN ITS,[ +RUBOUT"A=1 +RUBOUT"B=2 +RUBOUT"C=3 +RUBOUT"D=4 + +RUBOUT"$$PROMPT==1 + +.INSRT SYSENG;RUBOUT + +RUBOUT"INCHR: + .IOT CHTTI,RUBOUT"A + RET + +RUBOUT"OUTCHR: + SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR] + .LOSE %LSFIL + RET + +RUBOUT"DISPLAY: + SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR+%TJDIS] + .LOSE %LSFIL + RET + +RUBOUT"PROMPT: + MOVEI RUBOUT"A,"# + SKIPL PRMNUM + MOVEI RUBOUT"A,"* + JRST RUBOUT"OUTCHR + +RUBOUT"DISPATCH: + CAIN RUBOUT"A,%TXCTL+"Q ;MAKE ^Q NOT SPECIAL FOR RUBOUT PROCESSING. + JRST RUBOUT"INSECH ;THAT IS, IT WON'T QUOTE A RUBOUT. + CAIN RUBOUT"A,%TXCTL+"M ;^M SHOULD JUST INSERT A ^M, NOT ^M^J + JRST RUBOUT"BRKINS + JRST RUBOUT"RB$DSP + +.SCALAR PRMNUM ;NEGATIVE => PROMPT WITH #. POS OR ZERO => PROMPT WITH *. +.VECTOR RBBLK(RUBOUT"RB.LEN) ;RUBOUT PROCESSOR ARGUMENT BLOCK. + +;READ A LINE BY CALLING THE RUBOUT PACKAGE. ASSUMES LH OF (P) NEGATIVE => PROMPT WITH #. +TTILI1: CALL CRLF + MOVE W1,(P) + MOVEM W1,PRMNUM +TTILI9: CALL RUBOUT"PROMPT + MOVE W1,[010700,,TTIBUF-1] + MOVEM W1,TTIPNT ;SET UP FOR FETCHING CHARS LATER. + MOVEM W1,RBBLK+RUBOUT"RB.BEG + ADDI W1,TTIBFL + MOVEM W1,RBBLK+RUBOUT"RB.END + MOVEI RUBOUT"A,CHTTO + MOVEI RUBOUT"B,RBBLK + CALL RUBOUT"INIT +TTILI8: CALL RUBOUT"READ ;READ CHARACTERS UP TO BREAK CHAR. + CAMN RUBOUT"A,[-1] + JRST [ .IOT CHTTO,[^G] ;BUFFER FULL: DING, AND LET USER RUB OUT SOME. + JRST TTILI8] + JUMPL RUBOUT"A,TTILI1 ;OVER-RUBOUT => CRLF AND TRY AGAIN. + MOVEI W2,0 + DPB W2,RBBLK+RUBOUT"RB.PTR ;REPLACE BREAK CHAR WITH 0. + CAIN RUBOUT"A,%TXCTL+"M + JRST TTILI4 + CALL CRLF ;IF BREAK WASN'T A CR, TYPE A CR, + TLNN FR,FLMERG ;AND IF READING A COMMAND, REMEMBER TO RETURN TO DDT + SETOM CTLCF ;AFTER EXECUTING IT. +TTILI4: MOVE W1,TTIPNT ;COUNT THE CHARACTERS WE GOT. SET UP TTICNT. + SETZM TTICNT +TTILI2: CAMN W1,RBBLK+RUBOUT"RB.PTR + JRST TTILI3 + IBP W1 + AOS TTICNT + JRST TTILI2 + +TTILI3: SOSE TTICNT ;DON'T COUNT THE TERMINAL 0 IN TTICNT. + RET ;RETURN IF LINE IS NON NULL. + SKIPL (P) ;IF IT ISN'T A COMMAND, RETURN IT EVEN THOUGH NULL. + RET + SKIPGE CTLCF ;NULL COMMAND LINE ENDED BY ^C MEANS EXIT. + JRST QUIT + JRST TTILI9 ;OTHERWISE READ ANOTHER COMMAND LINE. +] + +IFN TNX,[ +TTILI1: CALL CRLF +TTILI2: SKIPE FLG20X ;ON A 20? + JRST TTIL20 ;YES +;COME HERE AFTER NULL LINE. + SETZM TTICNT ;NO CHARS READ YET. + SKIPGE (P) + MOUTI CHTTO,"# + SKIPL (P) + MOUTI CHTTO,"* + MOVE C,[440700,,TTIBUF] + MOVEM C,TTIPNT +TTILUP: CALL TYI ;READ A CHAR FROM TTY. + CAIN C,^M + JRST TTICR ;^M MEANS ALL READ. + CAIE C,^D + CAIN C,^U + JRST TTILI1 ;^U CANCELS CMD. + CAIN C,177 + JRST TTIRUB + CAIN C,^L ;IF USER TYPES ^L, RETYPE THE BUFFERED INPUT. + JRST TTICTL + CAIE C,^Z + CAIN C,^C + JRST TTICTC ;^C MEANS DO CMD, THEN VALRET :KILL. + IDPB C,TTIPNT ;NORMAL CHAR. + AOS TTICNT + JRST TTILUP + +TTICTC: CALL CRLF ;INDICATE COMMAND HAS BEEN TERMINATED. + TLNN FR,FLMERG ;^C DOES NOTHING IF INPUT TO MERGE. + SETOM CTLCF ;REMEMBER TO VALRET WHEN CMD DONE. +;HERE AFTER ORDINARY LINE TERMINATOR. +TTICR: SKIPL (P) + JRST TTICR1 + SKIPN TTICNT ;IF NULL COMMAND LINE, RETRY. + JRST TTILI3 +TTICR1: SETZ C, + IDPB C,TTIPNT ; TERMINATE WITH ASCIZ + MOVE C,[440700,,TTIBUF] + MOVEM C,TTIPNT ;SET UP FOR REMOVAL OF CHARS. + RET + +TTILI3: SKIPE CTLCF ;NULL LINE: + JRST QUIT ;...IF ^C ENDED LINE. + JRST TTILI2 + +TTICTL: MOVEI T,[ASCIZ /#/] ;COME HERE FOR ^L. SCREEN ALREADY CLEARED ON DISPLAY. + SKIPL (P) + MOVEI T,[ASCIZ /*/] + CALL TYPMSG ;PRINT CRLF AND ASTERISK. + MOVE TT,[440700,,TTIBUF] + MOVE C,TTICNT ;THEN RETYPE THE BUFFERED INPUT. + M.SOUT CHTTO,TT,C + JRST TTILUP + +TTIRUB: SOSGE TTICNT ;IF NO CHAR TO RUB, RETRY. + JRST TTILI1 + LDB C,TTIPNT + MOUTC CHTTO,C ;PRINT RUBBED CHAR. + MOVSI C,070000 + ADD C,TTIPNT + JUMPGE C,TTIRU1 ;IF STILL IN SAME WD. + MOVEI C,-1(C ) ;ELSE, MOVE TO END OF PREV. WD. + HRLI C,010700 +TTIRU1: MOVEM C,TTIPNT + JRST TTILUP + +;USE SYSTEM ROUTINES ON A 20 +TTIL20: HRROI R3,[ASCIZ /#/] ;PROMPTING TEXT + SKIPL (P) + HRROI R3,[ASCIZ /*/] + MOVE R1,R3 ;HAVE TO OUTPUT PROMPT BY HAND, SIGH + PSOUT + HRROI R1,TTIBUF + MOVE R2,[RD%TOP+5*TTIBFL] + RDTTY + JRST RESTRT + TLZ R2,-1 ;FIGURE COUNT + SUBI R2,5*TTIBFL + LDB C,R1 + CAIE C,^J + JRST TTIL21 + MOVNI R3,1 + ADJBP R3,R1 + LDB C,R3 + CAIE C,^M + JRST TTIL21 + MOVE R1,R3 + ADDI R2,1 +TTIL21: MOVNI R3,1 + ADJBP R3,R1 + MOVEM R3,TTIPNT + SETCAM R2,TTICNT ; TTICNT := -R2-1 + CAIE C,^Z + JRST TTICR + JRST TTICTC +] ;IFN TNX + +;COME HERE TO SEE IF THE COMMAND STRING IS JUST "?" OR "HELP". +;IF NOT, RETURNS. IF SO, PRINTS HELP (FROM INFO;SRCCOM >) +;AND RETURNS TO RELDEV. +TRYHLP: SAVE TTIPNT + SAVE TTICNT + CALL TTINSP ;GO PAST INITIAL SPACES. + CAIN C,"? + JRST TRYHL1 ;"?" MIGHT BE START OF GOOD STUFF + CAIE C,"H ;SO MIGHT "H". + JRST TRYHLL ;ANYTHING ELSE => USER ISN'T ASKING FOR HELP. + CALL TTICHU + CAIE C,"E + JRST TRYHLL + CALL TTICHU + CAIE C,"L + JRST TRYHLL + CALL TTICHU + CAIE C,"P + JRST TRYHLL +TRYHL1: CALL TTINSP + CAIE C,^M + CAIN C,^C + CAIA + JRST TRYHLL +;USER WANTS HELP - GIVE IT TO HIM. + CALL OPNHLP + JRST ERRHLP +TRYHL3: M.BIN CHIN1,C + CAIN C,^L + JRST RELDEV + JUMPL C,RELDEV + MOUTC CHTTO,C + JRST TRYHL3 + +TRYHLL: REST TTICNT + REST TTIPNT + RET + +;READ 1 CHAR FROM THE COMMAND STRING, THEN KEEP READING TILL READ A NON-SPACE. +;CONVERTS TO UPPER CASE. +TTINSP: CALL TTICHU + CAIN C,40 + JRST TTINSP + RET + +;COME HERE TO HANDLE A COMMAND WITH /X IN IT. +CMDXCT: SKIPE CMDFIL + JRST ERRXCT ;/X INSIDE AN EXECUTE FILE?? + SKIPLE TTICNT ;ANY EXTRA FILES SPECIFIED? + JRST ERRXTRA + M.MVCH CHIN1,CHCMD ;MAKE THE ALREADY OPEN 1ST INPUT FILE BE OUR COMMAND FILE. + MOVE W1,INFB+$FDIR + MOVEM W1,CMDIS ;MAKE INPUT DEV AND SNAME THE INPUT DEFAULTS + MOVE W1,INFB+$FDEV + MOVEM W1,CMDID + MOVE W1,LSTFB+$FDIR + MOVEM W1,CMDOS ;AND OUR OUTPUT DEV AND SNAME THE OUTPUT DEFAULTS + MOVE W1,LSTFB+$FDEV + CAMN W1,FSTTY + MOVE W1,FSDSK + MOVEM W1,CMDOD + SETOM CMDFIL ;SAY WE ARE NOW EXECUTING A COMMAND FILE. + JRST RELDEV ;GO READ THE NEXT COMMAND. + +;COME HERE TO READ A COMMAND LINE FROM A COMMAND FILE. +TTIFIL: SETZM TTICNT ;INITIALIZE THE COMMAND BUFFER EMPTY. + MOVE BP,[440700,,TTIBUF] + MOVEM BP,TTIPNT +;NOW SEE IF THERE ARE ANY MORE COMMANDS IN THE FILE. +TTIFI0: M.BIN CHCMD,C +TTIFI1: ANDI C,-1 + CAIE C,^C ;EOF OR END OF 1ST PAGE => COMMAND FILE IS OVER. + CAIN C,^L + JRST TTIEOF + CAIE C,"; ;ELSE, A COMAND LINE IS IDENTIFIED BY + JRST TTIFI0 ;STARTING WITH ";;SRCCOM COMMAND ;;" +IRPC X,,[;SRCCOM COMMAND ;;] + M.BIN CHCMD,C + CAIE C,"X + JRST TTIFI1 +TERMIN +;WE FOUND ANOTHER COMMAND LINE'S BEGINNING. +;NOW, EVERYTHING UP TO NEXT ^C, ^L, ^M OR ";;" IS PART OF THE COMMAND. + TDZA W1,W1 +TTIFI2: MOVE W1,C ;REMEMBER THE PREVIOUS CHAR FOR FINDING ";;". + M.BIN CHCMD,C + ANDI C,-1 + CAIE C,^C + CAIN C,^M + JRST TTIFI3 + CAIN C,^L ;STOP BEFORE A ^C, ^L OR ^M. + JRST TTIFI3 + CAIN C,"; ;BEFORE THE SECOND ";" OF A ";;", + CAIE W1,"; + AOSA TTICNT + JRST TTIFI4 ;MUST STOP, AND FLUSH THE PREVIOUS ";". + IDPB C,BP ;ELSE STORE THE CHAR AND COUNT IT. + JRST TTIFI2 + +TTIFI4: SOS TTICNT + DBP7J BP, +TTIFI3: SETZ C, ;NOW WE HAVE READ IN A WHOLE LINE. + IDPB C,BP ;SO MAKE IT ASCIZ + MOVEI T,TTIBUF ;AND TYPE IT ON THE TTY SO USER CAN MONITOR PROGRESS. + CALL TYPMS0 + JRST CRLF + +TTIEOF: M.CLS CHCMD ;HERE AT END OF COMMAND FILE. + SETZM CMDFIL ;STOP TRYING TO USE IT, AND COMMIT SUICIDE IF A ^C + SKIPE CTLCF ;IS STILL LEFT FROM WHEN IT WAS SPECIFIED. + JRST QUIT + JRST TTILIN ;ELSE, READ FROM TTY. + +SUBTTL ITS - FILESPEC READER + +;READ FILE SPEC. + +IFN ITS,[ + +RFILE: SETZM $F6FN2(FP) ;DEFAULT FN2 UP TO CALLER. +RFILSW: SETZ CS, +RFNAME: MOVE BP,[440600,,0] + MOVEI 0,6 ;SET UP TO READ IN A FILENAME. + MOVEM 0,RFILC + SETZ 0, +RFLOOP: CALL TTICHU ;READ A CHAR. UPPER CASE + CAIN C,^Q + JRST RFCTQ ;^Q QUOTES NEXT CHAR. + CAIE C,"= + CAIN C,", + JRST RFSPAC ;COMMAS TERMINATE SPEC. + CAIE C,"_ + CAIG C," + JRST RFSPAC ;THESE ALSO. + CAIN C,": + JRST RFCOL ;COLON SETS DEV. + CAIN C,"; + JRST RFSEM ;SEMI SETS SNAME. + CAIN C,"/ + JRST RFSPAC ;SLASH ENDS NAME. + JRST RFNORM ;ALL OTHER CHARS. + +RFCTQ: CALL TTICHU ;READ UPPER CASE CHAR + CAIGE C,40 + JRST RFSPAC ;DON'T TRY TO QUOTE A CONTROL CHARACTER. +RFNORM: MOVEI C,-40(C) ;CONV. TO SIXBIT. + SOSL RFILC ;PUT IN NAME IF ROOM LEFT. + IDPB C,BP + JRST RFLOOP + +RFXCTB: MOVEM 0,$F6FN1(FP) + MOVEM 0,$F6FN2(FP) + MOVEM 0,$F6DEV(FP) + MOVEM 0,$F6DIR(FP) + SKIPA + +RFCOL: SKIPE 0 + MOVEM 0,$F6DEV(FP) ;SET DEVICE FIELD. + JRST RFNAME + +RFSEM: SKIPE 0 + MOVEM 0,$F6DIR(FP) + JRST RFNAME + +RFSPAC: JUMPE 0,RFSPA0 ;IF NAME WAS READ, + XCT RFXCTB(CS) ;STORE IT, + AOJ CS, ;INCR. STORING POS. + TLNN FR,FLINDR + JRST RFSPA0 + CAIN CS,2 + RET +RFSPA0: CAIN C,^X ;AS 1ST NAME AVOIDS SETTING IT, ALLOWS FN2 TO BE SET. + JRST [ JUMPN CS,RFNAME + AOJA CS,RFNAME] + CAIN C,40 + JRST RFNAME ;SPACE -- GET ANOTHER NAME. + CAIN C,^C + MOVEI C,^M + CAIE C,"/ + RET ;NOT SLASH, RETURN. + CALL RDSW ; AHA, READ SWITCH. + JRST RFNAME ; THEN RETURN TO LOOP. +] ;IFN ITS + +SUBTTL TNX - FILESPEC READER + +IFN TNX,[ + +RFILE: SETZM $FVERS(FP) ; DEFAULT VERSION UP TO CALLER +RFILSW: SETZM RDFLG ; SAY HAVEN'T READ FILESPEC YET. +RFILE2: CALL TTICHR ; READ CHAR FROM LINE + CAIE C,^J + CAIN C,^M ; EOL? + JRST RFILE8 ; YES, EXIT + CAIE C,^C + CAIN C,0 + JRST RFILE8 + CAIN C,", ; COMMA? + JRST RFILE8 ; ALSO EXIT +IFE TWX,CAIE C,"_ ; Not on Twenex, thank you + CAIN C,"= ; EITHER OF THESE ARE VALID OUTPUT FILSPEC INDICATORS. + JRST RFILE8 + CAIN C,"/ ; START OF SWITCH? + JRST [ CALL RDSW ; YES, READ IT & CONTINUE. + JRST RFILE2] + CAIE C,^I + CAIN C,40 + JRST RFILE2 ; FLUSH WHITESPACE + + ; HERE HAVE FIRST CHAR OF FILENAME... + MOVE W2,[440700,,RFLBUF] +RFILE3: IDPB C,W2 + CALL TTICHR ;ACCUMULATE CHARACTERS VALID IN FILE NAME + CAIE C,^J + CAIN C,^M + JRST RFILE4 + CAIE C,^C + CAIN C,0 + JRST RFILE4 + CAIE C,", + CAIN C,"/ + JRST RFILE4 +IFE TWX,CAIE C,"_ ; Not on Twenex, thank you + CAIN C,"= + JRST RFILE4 + CAIE C,^I + CAIN C,40 + JRST RFILE4 + CAIE C,^V + JRST RFILE3 + IDPB C,W2 + CALL TTICHR + JRST RFILE3 + +RFILE4: MOVEI A,0 ;MARK END OF ASCIZ STRING + IDPB A,W2 + MOVE W2,TTIPNT + DBP7J W2, ; SKIP BACK ONE + MOVEM W2,TTIPNT + AOS TTICNT +RFILE5: SKIPE RDFLG ; ALREADY READ A FILESPEC? + JRST RFILE8 ; YES, DON'T READ THIS SPEC YET... + HRROI W2,RFLBUF + SYSCAL GTJFN,[[GJ%OFG+GJ%SHT] ? W2][$FJFN(FP) ? W2] + JRST RFILE9 ; SOME SORT OF SYNTAX ERROR + ;HERE COULD COMPARE W2 AGAINST TTIPNT IN CASE EXTRA GARBAGE IN FILENAME + CALL JFNSTB ; STORE FILENAME SPEC IN FB + SYSCAL RLJFN,[$FJFN(FP)] + JFCL + SETZM $FJFN(FP) + + ; FILESPEC READ... + SETOM RDFLG ; SAY SO, SO IF SEE ANOTHER WILL STOP + JRST RFILE2 + +RFILE8: RET ; RETURN + +RFILE9: HRROI W1,RFLBUF + PSOUT + MOUTI CHTTO,^I + CALL TYLERR ;TYPE LAST ERROR + JRST ERRFIN + +.SCALAR RDFLG ; -1 WHEN FILESPEC READ +.VECTOR RFLBUF(20.) ;BUFFER FOR READING FILENAME INTO FOR GTJFN +] ;IFN TNX + +SUBTTL SWITCH PROCESSING + +;FOR SWITCH "A, SET OR CLEAR BIT D ACCORDING TO B. +DEFINE SWITCH A,B,D + CAIN C,"A + HRR!B!I BP,D +TERMIN + +RDSW: CALL TTICHU ; READ A SWITCH (SHOULD BE NEXT CHAR). + SETZ BP, + SWITCH !,O,FLOVRD ;/! - FORCE COMPARISON BETWEEN A FILE AND ITSELF + SWITCH @,O,FLINDR ;/@ - GO INDIRECT THROUGH A COMPARISON FILE + ;TO FIND THE FILE NAMES TO USE. + CAIN C,"# ;/# - Binary compare (= FILCOM /W) + JRST [ SETOM FVBIN ; Set memory flag (sigh) + RET] + CAIN C,"$ ;/$ - SBLK or CSAVE compare + JRST [ SETOM FSBIN + RET] + CAIN C,"Q ;/Q - Like FILCOM /Q, gives error + JRST [ SETOM QFLAG ; if files are different + RET] ; (for BATCON, mostly) + SWITCH B,O,FLALL ;/B - DON'T IGNORE BLANK LINES. + SWITCH C,O,FLCMNT ;/C - IGNORE COMMENTS. + CAIN C,"D + PJRST SWDISN ;/D - DISOWN SELF. + SWITCH E,O,FLENDL ;/E - PRINT THE MATCHING LINES THAT END THE + ;RUN OF DIFFERENCES. + SWITCH F,O,FLFLAG+FLALL+FLMERG ;/F - GEN COPY OF FILE 2 WITH CHANGED LINES + ;FLAGGED WITH VERTICAL BARS. + SWITCH I,O,FLMERG+FLISWT+FLALL ;/I - /M, BUT ANSWER ALL QUESTIONS WITH "I". + SWITCH K,O,FLCASE ;/K - IGNORE ALPHABETIC CASE DIFFERENCES + SWITCH L,O,FLLABL ;/L - EACH HEADER LINE MENTIONS PREVIOUS LABEL. + SWITCH M,O,FLALL+FLMERG ;/M - MERGE FILES. + SWITCH S,O,FLSPAC ;/S - IGNORE SPACES. + SWITCH W,O,FLFNUM ;/W - PRINT FILE # ON EACH LINE. + SWITCH X,O,FLXCTF ;/X - EXECUTE COMMANDS FROM FILE + SWITCH Y,O,FLXLBL ;/Y - ANY UNINDENTED TEXT IS A LABEL. + CAIL C,"1 ;DIGIT - SET NUMLIN. + CAILE C,"9 + CAIA + JRST [MOVEI C,-"1(C) ;SET NUM. EXTRA LINES TO MATCH + MOVEM C,NUMLIN ;TO THE DIGIT, -1. + RET] + JUMPE BP,ERRSW ;ERROR UNLESS ONE OF ABOVE SWITCHES. + TLO FR,(BP) ;SET THE FLG. + RET ;SWITCH DONE, RETURN. + +SUBTTL ERROR MESSAGES/HANDLING + +;COME HERE AFTER FAILING INPUT OR OUTPUT OPEN. + +OPENL: +IFN ITS,.LOGOUT + CALL LSTFIL ;PRINT NAME OF LOSING FILE (WHAT FP POINTS TO). + MOUTI CHTTO,^I + CALL TYLERR ;TYPE LAST ERROR + JRST ERRFIN + + +ERRXTR: JSP T,ERRMSG + ASCIZ "Extra input files specified" + +ERRHLP: MOVEI T,[ASCIZ "Can't find help file!"] + CALL TYPMSG +; JRST OPENL + JRST ERRFIN + +ERRIND: JSP T,ERRMSG + ASCIZ "Bad format /@ indirect file" + +ERRIN2: JSP T,ERRMSG + ASCIZ "Can't use /@ or /X with second input file" + +ERRIN3: JSP T,ERRMSG + ASCIZ "Can't use /@ or /X with third input file" + +ERR3NM: JSP T,ERRMSG + ASCIZ "Three input files but /M not specified" + +ERRXCT: JSP T,ERRMSG + ASCIZ "Recursive /X attempted" + +ERRARC: JSP T,ERRMSG + ASCIZ "Can't archive and merge at once" + +ERRSW: JSP T,ERRMSG + ASCIZ "Illegal switch" + + + +ERRMSG: CALL TYPMSG ;FOR SIMPLE ERROR MESSAGES; TYPE & DROP THRU + +;ALL ERROR MESSAGES COME THROUGH HERE. + +ERRFIN: +IFN ITS,.RESET CHTTI, ; FLUSH TTY INPUT BUFFER +IFN TNX,CFIBF + SETZM CMDFIL ;STOP READING COMMAND FILE. + M.CLS CHCMD + SETZM CTLCF ;DON'T KILL SELF; READ ANOTHER CMD STRING INSTEAD. + +;COMMAND TERMINATION, SUCCESSFUL OR NOT, ALWAYS COMES THROUGH HERE. + +RELDEV: M.CLS CHIN1 + M.CLS CHIN2 + M.CLS CHMRG +IFN ITS,[ + MOVE W1,TTYSTS + TLNE W1,%TSMOR + SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1] + JFCL +] + M.CLS CHOUT + SKIPE CMDFIL ;EXECUTING A FILE => READ MORE FROM IT. + JRST RELDE1 +IFN ITS,.LOGOUT ;CAN'T GET ANOTHER CMD IF DISOWNED. + SKIPE CTLCF ;EXIT IF USER GAVE ^C. + JRST QUITX + +RELDE1: CALL CRLF + JRST RESTRT ;ELSE, GET NEW CMD. + + +;ROUTINES FOR OUTPUTING ERROR MESSAGES + +TYPMSG: +IFN ITS,.LOGOUT ;CAN'T PRINT MSG WITHOUT TTY. + CALL CRLF ;OUTPUT A CARRIAGE RETURN +TYPMS0: HRLI T,440700 ;THIS IS POINTER FOR ERROR MESSAGE +TYPMS1: ILDB C,T + JUMPE C,CPOPJ + CALL TYO + JRST TYPMS1 + +; TYPM - FOR USE WITH "TYPE" MACRO. STACK HAS ADDR OF ASCIZ STR. +TYPM: PUSH P,C + PUSH P,T + MOVE T,-2(P) ; GET ADDR OF ASCIZ + CALL TYPMSG ; OUTPUT + POP P,T + POP P,C + SUB P,[1,,1] ; FLUSH ARG + RET + +;OUTPUT 6BIT WD IN 0 TO TTY. +TTOSIX: MOVE BP,0 +TTOSI0: SETZ TT, + ROTC TT,6 ;GET NEXT CHAR. + MOVEI TT," (TT) ;CONV. 6BIT TO ASCII. + MOUTC CHTTO,TT + JUMPN BP,TTOSI0 + RET + +; OUTPUT DECIMAL # IN 0 TO TTY. + +TTODEC: IDIVI 0,10. + HRLM W1,(P) + SKIPE 0 + CALL TTODEC + HLRZ W1,(P) + ADDI W1,"0 + MOUTC CHTTO,W1 + RET + +TYO: MOUTC CHTTO,C + RET + +CRLF: MOUTI CHTTO,^M + MOUTI CHTTO,^J + RET + +SUBTTL Auxiliary ITS Routines + +IFN ITS,[ + +; GETJCL - Get JCL input +; W1/ <.OPTION var> + +GETJCL: SETZM TTIBUF + TLNE W1,OPTCMD ; Don't do the .BREAK unless superior says so. + .BREAK 12,[5,,TTIBUF] + SKIPN TTIBUF + RET + MOVE W1,[440700,,TTIBUF] ; If have command string from superior, + MOVEM W1,TTIPNT ; set up to read from it. + SETZ CS, +GTJCL2: ILDB C,W1 ; Count chars. in it. + CAIE C,^M + CAIN C,0 + CAIA + AOJA CS,GTJCL2 + MOVEM CS,TTICNT ; Save num. chars to read. + AOS (P) ; Success return. + RET + + +; TYLERR - Type last error + +TYLERR: .SUSET [.RBCHN,,C] + SYSCAL STATUS,[C ? MOVEM ERRFIL+2] + ERRHLT + .OPEN CHERR,ERRFIL + ERRHLT +TYLER2: M.BIN CHERR,C + CAIN C,^M + RET + MOUTC CHTTO,C + JRST TYLER2 + +ERRFIL: SIXBIT/ ERR/ + 3 ? 0 + + +; LSTFIL - Print name of current file on LST ior TTY. + +LSTFIL: MOVE 0,$F6DEV(FP) + CAMN 0,FSDSK + JRST LSTFI1 + CALL TTOSIX ; Print dev if not DSK. + MOUTI CHTTO,": +LSTFI1: MOVE 0,$F6DIR(FP) ; Print sname + CAMN 0,DEFDIR ; If different from user's. + JRST LSTFI2 + CALL TTOSIX + MOUTI CHTTO,73 ; "; +LSTFI2: MOVE 0,$F6FN1(FP) + CALL TTOSIX ; Print 1st name. + MOUTI CHTTO,40 ; Space + MOVE 0,$F6FN2(FP) + JRST TTOSIX ; , 2nd name. + + +SWDISN: .OPEN CHTTI,[SIXBIT/ NUL/] + ERRHLT + .OPEN CHTTO,[SIXBIT/ !NUL/] + ERRHLT + .VALUE [ASCIZ/:DISOWN :VK /] ; Give back tty. + RET + +; TYI - Read char from TTY, return in C + +TYI: .IOT CHTTI,C + RET + +; OPNRDW - Open filblk for reading, word mode +; OPNRDA - Open filblk for reading, ascii mode +; FP/ ,, +; Skip returns if opened. + +OPNRDW: SAVE W1 + HRLZI W1,.UII + JRST OPNRD2 +OPNRDA: SAVE W1 + HRLZI W1,.UAI ; Actually 0 +OPNRD2: HLR W1,FP + SYSCAL OPEN,[W1 ? $F6DEV(FP) ? $F6FN1(FP) ? $F6FN2(FP) ? $F6DIR(FP)] + CAIA + AOS -1(P) + REST W1 + RET + +; RENMLO - Rename listing file +; W1/ + +RENMLO: SYSCAL RENMWO,[W1 ? LSTFB+$FNAME ? LSTFB+$FEXT] + JFCL + RET + +QUIT: .BREAK 16,140000 ; Die and echo ":KILL" +QUITX: .BREAK 16,160000 ; Die, announce "Finished" if not current + +OPNHLP: SYSCAL OPEN,[MOVEI CHIN1 ? ['DSK,,] + ['SRCCOM] ? [SIXBIT/>/] ? [SIXBIT/INFO/]] + RET + AOS (P) + RET +] ;IFN ITS + +SUBTTL TNX - Auxiliary Routines + +IFN TNX,[ + +; SEE20X - See if running under 20x or 10x + +.SCALAR FLG20X ; -1 if 20x, 0 if 10x. +SEE20X: SETZM FLG20X + SYSCAL SYSGT,[['LOADTB]][B ? B] + SKIPN B ; If LOADTB is not defined + SETOM FLG20X ; It must be a twenex + RET + +QUIT: +QUITX: + +; Tell an MIT EXEC to flush this fork, like .BREAK 16,160000 on ITS +; This PRARG% code should be meaningless to (and ignored by) non-MIT EXECs. + +IFDEF PRARG%,{ ; I don't know if PRARG% exists on 10X or not + +IFNDEF .PRKIL, .PRKIL==:2 + + MOVE 1,[.PRAST,,.FHSLF] + MOVEI 2,[.PRKIL,,0] + MOVEI 3,1 + PRARG% ; Tell the EXEC that we have a death wish + ERJMP .+1 ; Oh well + +};IFNDEF PRARG% + + HALTF + JRST RESTRT + +; OPNWR - Open filblk for writing, ascii mode +; FP/ ,, + +OPNWR: SAVE W1 + SAVE W2 + MOVE W2,[070000,,OF%WR] ; Mode for char write + CALL GETJFO ; Get output jfn + JRST OPNRD8 + JRST OPNRD5 ; Rest is same as OPNRD. + +; OPNRDW - Open filblk for reading, word mode +; OPNRDA - Open filblk for reading, ascii mode +; FP/ ,, +; Skip returns if opened. + +OPNRDW: SAVE W1 + SAVE W2 + MOVE W2,[440000,,OF%RD] ; Mode for full-wd + JRST OPNRD2 +OPNRDA: SAVE W1 + SAVE W2 + MOVE W2,[070000,,OF%RD] ; Mode for char +OPNRD2: CALL GETJFI ; Get input jfn + JRST OPNRD8 ; Failed +OPNRD5: SYSCAL OPENF,[$FJFN(FP) ? W2] + JRST [ SYSCAL CLOSF,[$FJFN(FP)] + JFCL + JRST OPNRD8] + PUSH P,$FJFN(FP) + HLRZ W1,FP + POP P,JFNCHS(W1) + CALL JFNSTB + AOS -2(P) +OPNRD8: REST W2 + REST W1 + RET + +OPNHLP: PUSH P,R1 + PUSH P,R2 + MOVSI R1,(GJ%OLD+GJ%SHT) + HRROI R2,[HLPFIL] ; Filename defined as macro + GTJFN + JRST OPNHL7 ; Failed. + HRRZS R1 + PUSH P,R1 + MOVE B,[070000,,OF%RD] + OPENF + JRST [ POP P,R1 + CLOSF + JFCL + JRST OPNHL7] + POP P,R1 + MOVEM R1,JFNCHS+CHIN1 + AOS -2(P) +OPNHL7: POP P,R2 + POP P,R1 + POPJ P, + +; RENMLO - Rename listing file +; For moment, we don't hack temp filename, so this is a no-op. + +RENMLO: RET + +TYI: SAVE R1 +TYI2: PBIN + CAIN R1,37 + MOVEI R1,^M + CAIN R1,^J ; Actually for 20x only + JRST TYI2 + MOVE C,R1 + REST R1 + RET + +SWDISN: TYPE "Cannot disown on this losing system; continuing." + RET + +LSTFIL: PJRST TYPFB + +; TYLERR - Type last error + +TYLERR: SKIPA A,[-1] +TERSTR: MOVE A,ERRCOD + HRLI A,.FHSLF + SYSCAL ERSTR,[[-1,,ERSTRB] ? A ? [-LERSTR,,]][A ? B ? B] + JRST TERST7 ; undefined err #? + HALT ; destination bad? + SETZ B, + IDPB B,A ; Ensure ASCIZ. + MOVEI T,ERSTRB + PJRST TYPMSG +; TYPR ERSTRB +; POPJ P, +TERST7: TYPE "Unknown error" + POPJ P, + + LERSTR==80. +.VECTOR ERSTRB(/5) + + +; RCHST - Set up filename string of input file as part of header output. +; Also set length vars. + +RCHST: MOVEI A,CHIN1(FR) ; What a crock. + MOVE A,JFNCHS(A) ; Get jfn for file + PUSH P,A + MOVE B,RCHSTP(FR) ; Get bp to dest buffer + SYSCAL JFNS,[B ? A ? [111110,,1]][B] + SETZ A, + IDPB A,B ; Ensure asciz + POP P,A ; Get JFN again + SYSCAL SFPTR,[A ? [-1]][A] ; Set pointer to EOF + JFCL + SYSCAL RFPTR,[A][A ? B] ; Get # words to read + JFCL + MOVEM B,GWORDL(FR) ; Set length of file + MOVEM B,GWORDC(FR) ; Also # of words left to read + SYSCAL SFPTR,[A ? [0]] ; Point back to beg of file + JFCL + RET + +] ;IFN TNX + +SUBTTL TNX JCL reading + +; This routine is taken from MIDAS and so has some CCL hackery that +; currently is commented out, but at some future time might prove useful. +IFN TNX,[ + +; GETJCL - Read "JCL" - RSCAN buffer or nnnMID.TMP file (from CCL) + +GETJCL: SETZM TTIPNT +IFN 0,[ + SKIPE CCLFLG ; Started at CCL location? + JRST JCLIN5 ; Yep, go snarf stuff specially. +] + SKIPN FLG20X ; Is this Tenex? + JRST [ MOVEI R1,.PRIIN ; Yes + BKJFN ; see what previous character was + RET ; *Gasp* + PBIN + CAIE R1,^_ ; Tenex newline? + SETOM TTIPNT ; No, set flag saying "TTY but no prompt" + RET] ; and skip the Twenex hackery below + SETZ R1, ; If not, check RSCAN. + RSCAN ; See if have anything in RSCAN buffer. + RET ; Huh? Shouldn't happen, but ignore it. + JUMPLE R1,APOPJ ; Also return if char cnt says nothing there. + MOVNI R3,(R1) ; Aha, set up cnt for SIN + HRROI R2,TTIBUF + MOVEI R1,.PRIIN ; Now ready for business... + SIN + LDB R1,R2 ; Now examine wages thereof + CAIE R1,^J ; Last char LF? + JRST [ MOVEI R1,^J + IDPB R1,R2 ; If not, make it so. + JRST .+1] + +;;; Don't try to change the terminating character from LF to CR without +;;; giving it careful thought. GTJFN likes the filename to be terminated +;;; with LF, and can be quite intransigent in its behavior. +;;; Instead, make the other scan routines accept LF. --WBA + + SETZ R1, + IDPB R1,R2 ; Must also ensure ASCIZ. + MOVE B,[440700,,TTIBUF] ; If the rescan line starts with "RUN ", skip that. +IRPC X,,[RUN ] + ILDB A,B + TRZ A,40 ; Convert to upper case + CAIE A,"X + JRST JCLIN4 +TERMIN + CAIA +JCLIN4: MOVE B,[440700,,TTIBUF] ; Now flush the name of the file we were run from. + ILDB A,B + CAILE A,40 + JRST .-2 ; Flush until random ctl seen (space, ^M) + CAIE A,40 ; If it wasn't a space, + RET ; then forget about the whole thing. +JCLIN3: MOVE C,B ; Now flush spaces. Save last ptr for chars. + ILDB A,B + CAIN A,40 + JRST JCLIN3 + CAIN A,^J ; And is first non-space something besides LF? + RET ; Bah, there wasn't anything in the JCL!! + MOVEM C,TTIPNT ; Else save ptr to start of real goods. + + MOVE W1,C + SETZ CS, +GTJCL2: ILDB C,W1 ; Count chars. in it. + JUMPE C,GTJCL3 ; Null? (Shouldn't happen, but...) + CAIE C,^M ; CR or LF? + CAIN C,^J + CAIA ; Yes, must convert to null + AOJA CS,GTJCL2 ; Otherwise just count it + SETZ C, + DPB C,W1 +GTJCL3: MOVEM CS,TTICNT ; Save num. chars to read. + AOS (P) ; Success return. + RET + +IFN 0,[ + ; TNX snarf of CCL file. No such thing as tmpcor, so just + ; look for real file with appropriate name. +JCLIN5: SETZM CCLFLG ; Want 0 in case abort out, will reset if win. + GJINF ; Get job # in R3 + HRROI R1,CMBUF ; Use CMBUF to form filename string. + MOVEI R2,(R3) + MOVE R3,[NO%LFL+NO%ZRO+<3_18.>+10.] + NOUT ; ship out job num in 3 digits, radix 10. + HALT + HRROI R2,[ASCIZ /MID.TMP/] + SETZ R3, + SOUT ; Flesh out rest of filename string. + SETZ R2, ; Make sure it's ASCIZ. + BOUT + MOVE R1,[GJ%OLD+GJ%SHT] ; Use short-form GTJFN + HRROI R2,CMBUF ; and gobble name from CMBUF. + GTJFN + RET ; If failed, forget it. + MOVE R2,[070000,,OF%RD] ; Read 7-bit bytes + OPENF + RET ; Bah + HRROI R2,CMBUF ; Gobble stuff up. + MOVEI R3,CMBFL*5 ; Read until buffer full, + MOVEI R4,^J ; or LF seen. + SIN + JUMPLE R3,APOPJ ; Forget it if too big for buffer!! + + MOVE R2,[440700,,CMBUF] ; Aha, we've got something, so set + MOVEM R2,CMPTR ; pointer to slurped stuff. + SETOM CCLFLG + HRROI R2,UTIBUF ; Slurp rest into larger buffer, + MOVNI R3,UTIBFL*5 ; using count only. + SIN + JUMPGE R3,APOPJ ; Refuse to hack grossly large file. + ADDI R3,UTIBFL*5 + JUMPLE R3,APOPJ ; if nothing read, need write nothing out. + HRLI R1,(CO%NRJ) ; Don't release JFN, + CLOSF ; but stop reading from file. + RET + MOVE R2,[070000,,OF%WR] ; Now try to hack write access. + OPENF + RET + MOVE R2,R1 ; Source becomes destination... + HRROI R1,UTIBUF ; and UTIBUF becomes source, + MOVNS R3 ; for just as many bytes as were read. + SOUT + MOVEI R1,(R2) ; done, now just close file. + CLOSF ; (this time, release JFN). + RET + SETOM CCLMOR ; say that more CCL remains. + RET +] ;IFN 0 FOR NOW + +] ;IFN TNX + +SUBTTL TENEX misc. Filename Routines, FS string storage + +IFN TNX,[ .SEE FSDSK ; Part of this page is NOT conditionalized!! + +; To handle filenames of ASCIZ strings instead of SIXBIT words, each +; word has instead a byte pointer to an ASCIZ string. For purposes of +; easy comparison, all of these bp's point into FNBUF, and a routine +; (FNCHK) is provided which checks a just-stored string and returns a bp +; to either this string, if unique, or to a previously stored string if +; it is the same as the one just stored (which is then flushed). Thus +; strings can be compared for equality simply by a comparison of their +; byte pointers. While not necessary, strings are stored beginning on +; word boundaries for easier hacking. + + ; <# files>**+<# wds for constants> +IFNDEF MAXIND,MAXIND==10 ; # files +LFNBUF==*5*3+20 ; Enough to hold strings for all output files, + ; all translated files, and all .insrt files encountered. + ; Later a GC'er can be hacked up so that of the latter only + ; enough for the max .insrt level need be allocated. + +FNBUF: BLOCK LFNBUF + + ; Macro to easily define constant strings for comparison purposes +DEFINE DEFSTR &STR& +440700,,%%FNLC +%%LSAV==. +LOC %%FNLC +ASCIZ STR +%%FNLC==. +LOC %%LSAV +TERMIN + %%FNLC==FNBUF +] ; IFN TNX!!! + + ; If not assembling for TENEX, the following strings become + ; simple SIXBIT values. This makes it possible to write simple + ; code to work for both TENEX and non-TENEX without messy conditionals. + +IFE TNX,[ +DEFINE DEFSTR &X& +.1STWD SIXBIT X!TERMIN +] + + ; This stuff defines various BP's into FNBUF to + ; use for comparison purposes later. +FSDSK: DEFSTR /DSK/ +FSTTY: DEFSTR /TTY/ +FSNUL: DEFSTR /NUL/ +FSCMP: DEFSTR /COMPARE/ +FSCMPA: DEFSTR /CMPARC/ +FSFLGD: DEFSTR /FLAGGD/ + +IFN ITS, FSDMF2:DEFSTR />/ ; default merge FN2 +IFN TNX, FSDMF2:DEFSTR // +IFN ITS, FVLOW: DEFSTR /-<010700,,>] ; bump BP to point canonically at next. + MOVEM B,FNBWP + +FNCHK: HRRZ B,FNBWP ; See if write ptr + CAML B,FNBEP ; has hit end of FNBUF, and + ETF [ASCIZ /Filename buffer overflow/] ; barf horribly if so. + MOVE A,FNBBP ; A - bp to start of existing string + MOVE AA,FNBLWP ; AA - bp to start of new string to store +FNCHK2: MOVEI T,(A) ; T - current addr being checked, existing str + MOVEI TT,(AA) ; TT - current addr, new str + CAIL T,(TT) ; If addrs are same, or overran somehow, + JRST [ MOVE A,AA ; didn't find any match, accept new string. + MOVE B,FNBWP + MOVEM B,FNBLWP ; Set up new last-write-ptr + POPJ P,] +FNCHK3: MOVE B,(T) + CAMN B,(TT) ; Compare strings, full word swoops. + JRST [ TRNE B,377 ; equal, last char zero? + AOJA T,[AOJA TT,FNCHK3] ; no, continue for whole string + ; Found it! Flush just-stored string, don't want duplicate. + MOVEM AA,FNBWP ; Clobber write ptr to previous value. + POPJ P,] + ; Not equal, move to next string to compare + MOVEI B,377 ; Check for ASCIZ, + TDNE B,(T) ; moving to end of current string + AOJA T,.-1 + HRRI A,1(T) ; and updating BP to point at new string. + JRST FNCHK2 ; (T gets pointed there too at FNCHK2). +] ;IFN TNX + +IFN TNX,[ + +; TYPFB - Type out FB pointed to by F + +TYPFB: SKIPE B,$FDEV(F) ; First, device name? + JRST [ PUSHJ P,TYPZ + MOVEI A,": + PUSHJ P,TYOERR + JRST .+1] + SKIPE B,$FDIR(F) ; Directory? + JRST [ MOVEI A,"< + PUSHJ P,TYOERR + PUSHJ P,TYPZ + MOVEI A,"> + PUSHJ P,TYOERR + JRST .+1] + SKIPE B,$FNAME(F) + PUSHJ P,TYPZ + MOVEI A,". + PUSHJ P,TYOERR + SKIPE B,$FEXT(F) + PUSHJ P,TYPZ + MOVEI A,". ; 20X uses "." to set off version, + SKIPN FLG20X ; but 10X uses ";". + MOVEI A,"; + PUSHJ P,TYOERR + HRRE A,$FVERS(F) + JUMPL A,[MOVM B,A ; Is possible to have -1, -2, etc. + MOVEI A,"- + PUSHJ P,TYOERR + MOVE A,B + JRST .+1] + PUSHJ P,DPNT ; Version # output in decimal. + SKIPE $FTEMP(F) + TYPE ";T" ; May be temporary. + SKIPE B,$FPROT(F) + JRST [ TYPE ";P" + PUSHJ P,TYPZ + JRST .+1] + SKIPE B,$FACCT(F) + JRST [ TYPE ";A" + PUSHJ P,TYPZ + JRST .+1] + POPJ P, + + ; Takes BP in B, outputs to TYOERR until zero byte seen. +TYPZ: CAIA + PUSHJ P,TYOERR + ILDB A,B + JUMPN A,TYPZ+1 + POPJ P, + +DPNT: MOVE 0,A ; This entry pt for code borrowed from midas + PJRST TTODEC + +TYOERR: MOVE C,A ; Ditto. + PJRST TYO +] ; IFN TNX + +IFN TNX,[ +; JFNSTR - Get filename strings for active JFN. +; A/ active JFN +; F/ addr of filename block to clobber. +; JFNSTB - Same, but ignores A and assumes JFN is already stored in block. +; Clobbers A,C + +JFNSTB: SKIPA A,$FJFN(F) ; JFNSTB gets the JFN from block itself. +JFNSTR: MOVEM A,$FJFN(F) ; whereas JFNSTR stores it there... + MOVSI D,-NJSTRF ; Set up aobjn thru table. +JFNST2: PUSH P,T + SYSCAL JFNS,[FNBWP ? $FJFN(F) ? JSTRFX+1(D)][FNBWP] + POP P,T + MOVE C,JSTRFX(D) ; Now get index to place it belongs in file block, + CAIN C,$FVERS ; and check for this, because + JRST [ MOVE A,FNBLWP ; it wants to be a number, not a string. + MOVEM A,FNBWP ; Zap write pointer back to forget string, + PUSHJ P,CVSDEC ; and quickly convert before anything clobbers it. + JRST JFNST4] ; Skip over the FNCHKZ call. + + MOVE A,FNBLWP ; Get previous write ptr + CAMN A,FNBWP ; and compare to make sure something written. + TDZA A,A ; If nothing, store zero. + PUSHJ P,FNCHKZ ; Fix up string, and get BP to it. +JFNST4: ADDI C,(F) ; make it an addr, and + MOVEM A,(C) ; store BP. (or value, for $FVERS) + ADDI D,1 + AOBJN D,JFNST2 + POPJ P, + + ; Filblk idx, output format wd for JFNS call +JSTRFX: $FDEV ? 100000,, + $FDIR ? 010000,, + $FNAME ? 001000,, + $FEXT ? 000100,, + $FVERS ? 000010,, +NJSTRF==<.-JSTRFX>/2 + +; CVSDEC - Converts ASCIZ string to decimal, assumes only digits seen, with +; a possible minus-sign prefix (ie negative # is allowed). +; A/ BP to ASCIZ +; Returns value in A, clobbers nothing else. + +CVSDEC: PUSH P,B + PUSH P,C + MOVE C,A + SETZ A, + ILDB B,C ; Get 1st char + JUMPE B,CVSDC9 + CAIN B,"- ; Minus sign? + JRST [ MOVE A,C ; Yes, parse rest of number + PUSHJ P,CVSDEC + MOVNS A ; and negate result. + JRST CVSDC9] +CVSDC2: IMULI A,10. + ADDI A,-"0(B) + ILDB B,C + JUMPN B,CVSDC2 +CVSDC9: POP P,C + POP P,B + POPJ P, + +; CVSSIX - Converts ASCIZ string to SIXBIT word. +; A/ BP to ASCIZ string, +; Returns SIXBIT word in A. Clobbers nothing else. + +CVSSIX: PUSH P,B + PUSH P,C + PUSH P,D + MOVE D,A + SETZ A, + MOVE B,[440600,,A] + JRST CVSSX3 +CVSSX2: CAIL C,140 + SUBI C,40 ; Uppercase force + SUBI C,40 ; cvt to 6bit + IDPB C,B ; deposit + TLNN B,770000 ; If BP at end of word, + JRST CVSSX5 ; leave loop. +CVSSX3: ILDB C,D + JUMPN C,CVSSX2 +CVSSX5: POP P,D + POP P,C + POP P,B + POPJ P, + +] ; IFN TNX + +IFN TNX,[ + ; Get a JFN for current FILBLK (in F) and stick it into $FJFN(F). + ; A should hold flags in LH to use in 1st wd of block. + ; GETJFI - sets usual flags for input + ; GETJFO - sets " " output + ; GETJFN - takes whatever A holds. + +GETJFO: SKIPA A,[GJ%FOU+GJ%NEW] ; If hacking output, ask for new version. +GETJFI: MOVSI A,(GJ%OLD) ; If hacking input, file must exist. +GETJFN: PUSHJ P,TFMAP ; Stick filblk stuff into GTJFN scratch block. + PUSH P,R1 + PUSH P,R2 + MOVEI R1,GTJBLK + SETZ R2, + GTJFN + JRST [ MOVEM R1,ERRCOD ; failure, save error code. + JRST GETJF5] + HRRM R1,$FJFN(F) ; Win, save JFN. + AOS -2(P) +GETJF5: POP P,R2 ; Can't return in ACs cuz don't know what R1 etc are, + POP P,R1 ; and might clobber them here. + POPJ P, +.SCALAR ERRCOD + +; TFMAP - Map Tenex filenames from filblk pointed to by F into +; standard scratch block for long-form GTJFN. +; A/ ,,0 ; flags will go into LH of .GJGEN. +; Clobbers only A. + +TFMAP: HRR A,$FVERS(F) ; Put version # in RH + SKIPE $FTEMP(F) ; If asking for temp file, + TLO A,(GJ%TMP) ; set appropriate flag. + MOVEM A,GTJBLK+.GJGEN +IRP FROM,,[$FDEV,$FDIR,$FNAME,$FEXT,$FPROT,$FACCT,$FJFN]TO,,[.GJDEV,.GJDIR,.GJNAM,.GJEXT,.GJPRO,.GJACT,.GJJFN] + MOVE A,FROM(F) + MOVEM A,GTJBLK+TO +TERMIN + MOVE A,[.NULIO,,.NULIO] + MOVEM A,GTJBLK+.GJSRC ; Don't hack I/O in gtjfn. + POPJ P, + +.VECTOR GTJBLK(10.) ; Need exactly this many wds for non-extended long call +] ;IFN TNX + +SUBTTL TNX - SUPPORT FOR I/O MACROS + +IFN TNX,[ + ; TAKES -1(P)/ , (P)/ AND OUTPUTS +TOUTC: EXCH R1,-1(P) ; GET JFN + EXCH R2,(P) ; AND CHAR + BOUT ; OUT IT GOES. + REST R2 ; RESTORE ACS AND RETURN + REST R1 + RET + +; TINC - TAKES -1(P)/ , (P)/ AND INPUTS FROM CHAN TO LOC + +TINC: EXCH R1,-1(P) ; GET JFN + PUSH P,R2 + BIN + ERJMP [HRROI R2,^C ; EOF (20X ONLY) + JRST .+1] + MOVEM R2,@-1(P) ; STORE BYTE IN DESIRED LOC + POP P,R2 + SUB P,[1,,1] ; FLUSH LOC FROM STACK + POP P,R1 + RET + +; TINS - INPUT STRING +; TAKES T/ ADDR--> ? ? + +TINS: SAVE R1 + SAVE R2 + SAVE R3 + MOVE R1,@(T) ; GET JFN + MOVE R2,@1(T) ; AND BP + MOVN R3,@2(T) ; AND -COUNT + SIN + ERJMP .+1 ; ASSUME EOF AND PTRS UPDATED PROPERLY. + ; THIS ONLY WINS ON 20X! + MOVNM R3,@2(T) ; RESTORE NEW CNT + MOVEM R2,@1(T) ; AND NEW BP + REST R3 + REST R2 + REST R1 + RET +] ;IFN TNX + +PATCH: BLOCK 100 + +CONSTA ;ITS + +BEGP:: ;BEGINNING OF STORAGE ZEROED AT INIT. +JUNK: 0 +PPSET: BLOCK LPDL ;PUSH DOWN LIST STORAGE + BLOCK 20 + + +FLUSHP: BLOCK 1 ;P SAVED FOR RESTORATION IF A --MORE-- IS FLUSHED. + ;0 => NOT POSSIBLE TO FLUSH NOW. + +ERRCNT: BLOCK 1 ;DIFFERENCES COUNTER (0 MEANS NO DIFFERENCES) + +LBUFP: +LBUFP1::BLOCK 1 ;POINTER TO BEGINNING OF LINE STORAGE FOR FILE #1 +LBUFP2: BLOCK 1 ;DITTO FILE #2 +LBUFP3: BLOCK 1 + +NLINES: +NLINE1::BLOCK 1 ;# OF LINES OF FILE 1 NOW IN CORE +NLINE2: BLOCK 1 +NLINE3: BLOCK 1 + +EOFFL1: BLOCK 1 ;-1 => LAST NEXTLN ON FILE 1 WAS NO-OP'ED DUE TO EOF. +EOFFL2: BLOCK 1 +EOFFL3: BLOCK 1 + +NCOMP1: BLOCK 1 ;HOW MANY LINES DIFF IS CONSIDERING FROM FILE 1 +NCOMP2: BLOCK 1 +NCOMP3: BLOCK 1 + +HBUF1: BLOCK WPL ;HOLDS TITLE FROM FIRST FILE +HBUF2: BLOCK WPL ;FROM SECOND FILE +HBUF3: BLOCK WPL +IFN ITS,[ +RCHSTB: BLOCK 10. ;BLOCK WRITTEN INTO BY .RCHST + ;WORD 0 RH DEV NAME, LH IF NON-ZERO THEN DEVICE NAME TO PRINT + ;WRD 1 FNAM1 + ;WRD 2 FNAM2 + ;WRD 3 SYSTEM NAME + ;WRD 4 NON-NEGATIVE => .ACCESS POINTER + ;REST ROOM FOR EXPANSION OF SYSTEM CALL +] +PAGNUM: BLOCK 3 ;PAGE NUMBERS FOR THE TWO FILES, AT THE LEVEL OF RDLINE. + ;THAT IS, THE PAGE # THAT THE NEXT LINE READ WILL START ON. +LINNUM: BLOCK 3 ;LINE NUMBERS FOR THE FILES, AT RDLINE LEVEL. +CHRNUM: BLOCK 3 ;# OF CHARS RDLINE HAS READ SO FAR FROM EACH FILE. +LLABEL: BLOCK 3*LNLBLN ;LNLBLN (4) WDS/FILE, 0 OR ASCIZ OF LAST LABEL AND A COLON. +MRGOUT: BLOCK 3 ;/M NON-ZERO MEANS OUTPUT TO MERGE FILE ALL + ;/M LINES BEFORE WIPING OUT IN "MOVEUP" ROUTINE + ;/M ALWAYS 0 IF /M NOT TYPED +LPHONY: BLOCK 1 ; -1 IFF LAST LINE OUTPUT BY MOVEUP DIDN'T END IN A CRLF, + ;EXCEPT 1 => ENDED IN JUST A CR. 0 => ENDED IN A CRLF. +MRGLEN==2 ;/M LEAVE ROOM FOR 2 WORDS (10 CHAR) OF MERGE COMMAND. +MRGCOM: BLOCK MRGLEN ;/M BUFFER FOR MERGE COMMAND + BLOCK 1 ;/M GUARANTEE A NULL TERMINATION +MRGBYT: BLOCK 1 ;/M BYTE POINTER TO MERGE COMMAND STRING +MRGUFL: BLOCK 1 ;-1 => OUTPUTTING DIFFERENCES IN /F MODE; FROM MRGU1 TO MOVEUP. + +OUTTTY: BLOCK 1 ;-1 => CHOUT IS OUTPUTTING TO A TTY. +IFN ITS,[ +TTYSTS: BLOCK 1 ;SAVED TTYSET OF CHANNEL CHOUT, FOR RESTORATION AT RELDEV. +TTYST1: BLOCK 1 +TTYST2: BLOCK 1 +] + +NUMTMP: BLOCK 1 ;TEMP FOR NUMLIN +TEMPF1: BLOCK 1 ;TEMP FOR F1 +TEMPF2: BLOCK 1 ;TEMP FOR F2 +TEMPF3: BLOCK 1 +RFILC: 0 ;TEMP. FOR RFILE. +LSTEXP: 0 ;-1 => A BACKARROW WAS PRESENT IN COMMAND STRING. + + +FILBF1: BLOCK FILBFL ;FILE 1 BUFFER. +FILBE1=.-1 + ASCIC// +FILPT1: 0 ;FILE 1 BUFFER PTR. +FILEP1: 0 ;FILE 1 B.P. TO THE ^C AFTERWHAT WAS READ IN. + +FILBF2: BLOCK FILBFL ;FILE 2 BUFFER, +FILBE2=.-1 + ASCIC// +FILPT2: 0 ;FILE 2 BUFFER PTR. +FILEP2: 0 + +FILBF3: BLOCK FILBFL ;FILE 3 BUFFER. +FILBE3=.-1 + ASCIC// +FILPT3: 0 ;FILE 3 BUFFER PTR. +FILEP3: 0 ;FILE 3 B.P. TO THE ^C. + +MRGBF: BLOCK MRGBSZ/5 ;BUFFER FOR MERGE OUTPUT +MRGBP: 0 ;B.P. FOR STUFFING BUFFER. +MRGCT: 0 ;# CHARS SPACE LEFT IN BUFFER. + +PNTDBF: BLOCK 12./5+1 ;BUFFER FOR DECIMAL PRINT. + +ENDP:: ;END OF STORAGE THAT'S ZEROED BEFORE EVERY COMMAND. + +DEFDIR: 0 ;INITIAL (DEFAULT) DIRECTORY. + +CMDFIL: 0 ;-1 => READING FROM THE FILE OPEN ON CHCMD +CMDIS: 0 ;DEFAULT INPUT DIR WHILE EXECUTING COMMAND FILE +CMDID: 0 ;DEFAULT INPUT DEVICE +CMDOS: 0 ;DEFAULT OUTPUT DIR +CMDOD: 0 ;DEFAULT OUTPUT DEVICE + +CTLCF: 0 ;IF NOT 0, COMMIT SUICIDE AFTER FINISHING COMMAND. + +COLMAX: <-1>_-1 ;/M MAX COLUMN TYPED OUT ON /M DIALOG + ;/M CHANGED BY C COMMAND +LINMAX: <-1>_-1 ;/M MAX LINS TO TYPE OUT ON /M +NUMLIN: MATCH-1 ;# LINES FOR A MATCH + +SEG1: 10000 ;START OF SEGMENT FOR FILE 1 LINES +SEG2: 201000 ;START OF SEGMENT FOR FILE 2 LINES +SEG3: 401000 ;START OF SEGMENT FOR FILE 3 LINES + +TTIBUF: BLOCK 30 ;COMMAND BUFFER. +TTIBFL==.-TTIBUF +TTIPNT: 0 ;BYTE POINTER INTO TTIBUF. +TTICNT: 0 ;NUM. UNREAD CHARS LEFT IN TTIBUF. + + +CONSTANTS + +FOO: +VARIABLES + + -1 +ENDCOR: + +END BEG + \ No newline at end of file diff --git a/src/syseng/rubout.3 b/src/syseng/rubout.3 new file mode 100644 index 00000000..b1cdf430 --- /dev/null +++ b/src/syseng/rubout.3 @@ -0,0 +1,787 @@ + +.BEGIN RUBOUT ;Rubout processor routine for -*-MIDAS-*- programs. + +.AUXIL ;Don't mention all my symbols in crefs of programs that use me. + + ;PRINT VERSION NUMBER + .TYO6 .IFNM1 + .TYO 40 + .TYO6 .IFNM2 + PRINTX/ INCLUDED IN THIS ASSEMBLY. +/ + +;The main entry points of the RUBOUT package are INIT and READ. +;Each time you want to start reading one object, you should call INIT. +;After that, you call READ one or more times until you have enough +;input to act on. When you wish to start reading a "new" object -- and not +;allow the old one to be rubbed out any longer -- call INIT again. + +;There are also subsidiary entry points called character service routines. +;These handle the display updating for one input character. The +;rubout-processing significance of all characters is determined by +;a routine which you supply, called DISPATCH, which examines the +;character and goes to the appropriate service routines. +;We supply a default definition of DISPATCH for you to use as +;all or part of your dispatch routine, and also as a guide to what +;dispatch routines should do. + + +;Calling Conventions: + +;All subroutines herein are called by PUSHJ P,. They normally do NOT skip-return. +;Character service routines skip, with a return code in A, +;to tell READ to return with that code. + +;Arguments are passed in ACs A,B,C and D. D must be C+1. +;Subroutines may alter A-D as documented with each routine. + + +;These switches may be set by the caller to request optional features. +;They may be defined local to the block RUBOUT. + +IFNDEF $$MULTI,$$MULTI==0 ;Be efficient for CRs, BSs and TABs in the text. + ;$$MULTI==1 makes the code larger but makes + ;rubbing out these characters do less display. +IFNDEF $$FCI,$$FCI==1 ;Handle full char set input + ;(distinguish Alpha from C-B). + ;$$FCI==1 works for ASCII input streams too. +IFNDEF $$PROMPT,$$PROMPT==0 ;1 => call PROMPT to type a prompt string when needed. +IFNDEF $$HELP,$$HELP==0 ;1 => call HELP when the user types Top-H. +IFNDEF $$CTLBRK,$$CTLBRK==0 ;1 => the default dispatch routine + ;makes all random control characters break. +IFNDEF $$CTLECH,$$CTLECH==1 ;1 => control chars that perform editing functions + ;also echo, and must be erased. Doesn't include Rubout. +IFNDEF $$BRKINS,$$BRKINS==1 ;1 => break characters insert themselves first, + ;in the default dispatch routine. +IFNDEF $$FFCLR,$$FFCLR==1 ;1 => ^L echoes as clear screen. + ;0 => it echoes as uparrow-L, and we re-use the same lines. + +;These exits must be defined by the user. They may be defined local +;to the block RUBOUT: + +;INCHR reads a character, returning it in A. +;OUTCHR outputs the character in A. --MORE-- should, for +; most applications, be inhibited +; by having %TJMOR set in the channel used for output, +; if it is a terminal. If you want to do --MORE--, +; you should make sure that when the --MORE-- is proceeded +; its line is re-used so that the screen is as if +; the --MORE-- had never been. +;DISPLAY outputs the character in A in display mode (%TJDIS). +; It can be any stream that knows the meaning of ^P. +; If outputting to a terminal, set %TJMOR. +;PROMPT types a prompt-string. Called at appropriate times. +; Needed only if $$PROMPT==1. Not called when READ is +; entered; if you want that, do it yourself. +;HELP types a help-string when the user typed Top-H. +; Needed only if $$HELP==1. On displays, +; HELP may wish to wait for input to be available +; and then jump to REDISP without reading it. +;DISPATCH takes a character in A, and jumps off to the service +; routine for it, which may be one of those provided +; by RUBOUT (such as RUBOUT, INSERT, BREAK, etc.). +; A sample dispatch routine is called RB$DSP. +; You can use it, if it is right, by doing +; RUBOUT"DISPATCH==RUBOUT"RB$DSP +; after the .INSRT SYSENG;RUBOUT, or your dispatch +; can jump off to it, after handling a few cases specially. + +;Service routines provided in this file include +;INSERT, BREAK, BRKCR, BRKINS, INSCR, QUOTE, QUIT, CANCEL, RUBOUT, +;IGNORE, REDISP, CLRLIN, CTLU. + + +;Each call to the rubout processor must give the address of an argument +;block, called the rubout processor block, in B. +;This block enables you to carry on several transactions with +;RUBOUT at the same time (or one inside another). If you wish, +;you can make your DISPATCH, OUTCHR, etc. entries jump through +;extra words at the end of the rubout processor block (words which +;normally are not used), and thus have different routines for +;each transaction. + +;These are the words in the rubout processor argument block +;that are used by this package: + +RB.==777777 ;Bit typeout mode prefix. +RB.POS==0 ;Vpos,,Hpos of 1st character in buffer. +RB.WID==1 ;Width of line on terminal. +RB.TYP==2 ;TTY characteristics. + ;positive => printing terminal. + RB%FIL==2 ; bit 3.2 => not even that, just reading from a file. + ;0 => glass teletype (character erase only, no move up). + ;negative => full display. + RB%CID==1 ; bit 3.1 => can insert/delete as well. + RB%SAI==2 ; BIT 3.2 => SAIL mode on, ctl chars echo as one pos. +RB.BEG==3 ;B.P. to ILDB start of buffer. +RB.END==4 ;B.P. to ILDB 1st character after end buffer. + ;Actually, you should leave space for two characters + ;to be stored past RB.END. +RB.PTR==5 ;B.P. for storing into buffer. +RB.PRS==6 ;B.P. to last character parsed at next level up. +RB.STAT==7 ;Word of flags indicating temporary state of editing + +RB.LEN==10 ;Number of words in the rubout block + +;The caller should set up RB.BEG and RB.END, then call INIT which will +;initialize RB.TYP, RB.WID, and RB.POS and RB.PTR. + +;The use of RB.PRS: +;Complicated break-conditions do not need to be expressed in the DISPATCH routine. +;If you use $$BRKINS==1 (Insert break characters in the buffer), then +;if the higher level parser decides it needs more characters it can just call +;READ again to get more. It could then re-parse the whole input string. +;To save time, it can put in RB.PRS the pointer to the last character that +;it actually parsed. On return from READ, if RB.PRS is unchanged, all +;characters up to that point were not changed (ie, not rubbed out) +;and the parser can continue from where it left off. +;Otherwise, RB.PRS will be zero, to indicate that the parser must +;rescan the entire string as returned by READ. +;If you like, you can keep the parser's fetch-pointer in RB.PRS, +;calling READ when it reaches RB.PTR, and noticing when it is zeroed. + +DEFINE SYSCAL NAME,ARGS + .CALL [SETZ ? SIXBIT/NAME/ ? ARGS ((SETZ))] +TERMIN + +;Get a character's graphic type. Takes character in A, returns type in A. + +;Type codes are: + ;0 - 1-POSITION CHARACTER. + ;1 - ORDINARY CTL CHAR - USUALLY 2-POSITION, BUT 1-POSITION IN SAIL MODE. + ;2 - BACKSPACE. + ;3 - CR + ;4 - LF + ;5 - TAB. + ;6 - SPECIAL CTL CHARACTER - 2-POSITION EVEN IN SAIL MODE. + ;7 - ^G + +CHRTYP: +IFN $$FCI,[ + PUSH P,C ;If storing 9-bit bytes in the buffer, + LDB C,[300600,,RB.PTR(B)] + CAIN C,7 + JRST CHRTY1 + CAIGE A,177 ;assume that anything + JRST [ SETZ A, ;below 177 is either an ASCII graphic or a SAIL graphic. + JRST POPCJ] +CHRTY1: PUSHJ P,CHRASC ;Other things were echoed by converting them to ASCII. + POP P,C +];IFN $$FCI + CAIN A,177 + JRST [ MOVEI A,6 ;Assume rubout is a 2-position character, + POPJ P,] ;even though we shouldn't be echoing them. + PUSH P,C + PUSH P,D + MOVE C,A + IDIVI C,6 + CAIL A,40 + TDZA A,A + LDB A,RRCHBP(D) + JRST POPDCJ + +;TABLES USED BY CHRTYP THE ENTRY FOR EACH +;CHARACTER IS AN INDEX INTO RRFORT OR RRBACT. + +RRCHBP: REPEAT 6,<360600-<6*.RPCNT>_12.>,,RRCHTB(C) + +RRCHTB: .BYTE 6 + 6 ;^@ + 1 ;^A + 1 ;^B + 1 ;^C + 1 ;^D + 1 ;^E + 1 ;^F + 7 ;^G + 2 ;^H + 5 ;^I + 4 ;^J + 1 ;^K + 1 ;^L + 3 ;^M + 1 ;^N + 1 ;^O + 1 ;^P + 1 ;^Q + 1 ;^R + 1 ;^S + 1 ;^T + 1 ;^U + 1 ;^V + 1 ;^W + 1 ;^X + 1 ;^Y + 1 ;^Z + 0 ;ALTMODE, 1 POSITION. + 1 ;^^ + 1 ;[ ;^] + 1 ;^\ + 1 ;^_ + .BYTE + +;INIT empties the buffer and also tells RUBOUT about +;the characteristics of the output stream used +;for echoing of output during rubout processing. +;If it is a terminal, the capabilities of it are also remembered for use +;in chosing display strategies. If it is not a terminal, or if -1 is +;passed as the channel number, we assume that no echoing of input or rubbed +;out characters is desired. + +;INIT takes the output channel in A and the rubout processing block address in B. +;It sets RB.TYP, RB.WID and RB.POS. It also initializes the buffer to be empty. + +INIT: PUSHJ P,INITB + +;Learn about a new output source, without marking the buffer empty. +INITO: PUSH P,C + PUSH P,D + SYSCAL CNSGET,[A ? MOVEM D ? MOVEM RB.WID(B) ;Read tty width into RB.WID. + REPEAT 3,[ ? MOVEM D]] ;Read TTYOPT of TTY into D. + JRST INIT1 ;Jump if not really a TTY. + SETZ C, ;First assume it's a glass TTY. + TLNN D,%TOMVU + TLNE D,%TOOVR ;If it isn't one, try a printing TTY. + MOVSI C,200000 ;RB.TYP should be positive. + TLNE D,%TOERS + MOVSI C,600000 ;For erasable display, it should be negative. + TLNE D,%TOCID + TLO C,RB%CID ;If we can insert/delete chars, remember that. + MOVEM C,RB.TYP(B) + SYSCAL RCPOS,[A ? MOVEM RB.POS(B)] + .LOSE %LSFIL +POPDCJ: POP P,D +POPCJ: POP P,C +CPOPJ: POPJ P, + +INIT1: MOVSI C,200000+RB%FIL + MOVEM C,RB.TYP(B) + JRST POPDCJ + +;Set up to do some rubout processing. Takes the Rubout processing block addr in B +;and marks the buffer empty. +INITB: PUSH P,C + MOVE C,RB.BEG(B) + MOVEM C,RB.PTR(B) + JRST POPCJ + +IFN $$FCI,[ +;Normalize a 9-bit character so we can do comparisons on it. +CHRNRM: ;ANDCMI A,%TXSFT+%TXSFL + TRNE A,%TXCTL+%TXMTA ;Convert lower case controls/metas to upper case, + TRNN A,100 + JRST CHRNR1 + TRC A,177 + TRCN A,177 ;but don't turn Control-Rubout into Control-_. + TRZ A,40 +CHRNR1: TRNE A,%TXTOP+%TXCTL+140 ;ASCII control chars must be turned into %TXCTL+char. + POPJ P, + CAIE A,33 ;except for altmode. + ADDI A,%TXCTL+100 + POPJ P, + +;Convert a 9-bit character in A to ASCII, if necessary for insertion in the buffer +;(that is, if the buffer is 7-bit). +CHRASI: PUSH P,C + LDB C,[300600,,RB.PTR(B)] + CAIE C,7 + JRST POPCJ + POP P,C +;Convert a 9-bit character in A to ASCII. +CHRASC: ANDI A,%TXCTL+%TXASC + TRZN A,%TXCTL + POPJ P, + CAIN A,177 + POPJ P, + CAIE A,40 + CAIL A,140 + SUBI A,40 + ANDCMI A,100 + POPJ P, +];IFN $$FCI + +SUBTTL Main rubout processing routine + +;The main function of the rubout package is READ. +;It takes the pointer to a rubout processor argument block in B. +;It reads characters and processes them until either a break character +;is read, the buffer becomes full, or an attempt is made to rub out +;past the beginning of the buffer. +;On return, A contains -1 if the buffer is full; -2, in case of +;over-rubout; otherwise, it contains the break character that caused +;the exit. No other accumulator is clobbered. + +READ: PUSH P,C + PUSH P,D +RBLOOP: PUSHJ P,INCHR ;Read next character into A. + SKIPLE RB.TYP(B) ;After a CR coming form a file, flush the LF. + CAIE A,^M + JRST RBLOO2 + PUSHJ P,INCHR + MOVEI A,^M +RBLOO2: +IFN $$HELP,[ + CAIN A,%TXTOP+"H ;If user supplied a HELP routine, call it for Top-H. + JRST [ PUSHJ P,HELP ;Must check for Top-H before the CHRNRM, which makes it H. + JRST RBLOOP] +];IFN $$HELP +IFN $$FCI,PUSHJ P,CHRNRM + PUSHJ P,DISPATCH ;Let user decide what to do with the character. + JRST RBLOO1 + JRST POPDCJ ;His routine skips => it wants to exit. + ;It should have put the return code in A. + +RBLOO1: MOVE C,RB.PTR(B) ;User didn't ask to return, + CAME C,RB.END(B) ;but return anyway if the buffer has become full. + JRST RBLOOP + MOVNI A,1 + JRST POPDCJ + +IFE $$FCI,[ +;Here is the default RB.DSP character dispatch routine which we provide. +RB$DSP: CAIN A,177 + JRST RUBOUT + CAIN A,^U + JRST CTLU + CAIN A,^D + JRST CANCEL + CAIN A,^G + JRST QUIT + CAIN A,^M +IFN $$BRKINS, JRST BRKCR +IFE $$BRKINS, JRST BREAK + CAIE A,^_ + CAIN A,^C +IFN $$BRKINS, JRST BRKINS +IFE $$BRKINS, JRST BREAK + CAIN A,^Q + JRST QUOTE + CAIN A,^L + JRST REDISP +IFN $$CTLBRK,[ + CAIGE A,40 +IFN $$BRKINS, JRST BRKINS +IFE $$BRKINS, JRST BREAK +] + JRST INSECH +];IFE $$FCI + +IFN $$FCI,[ +;Default dispatch for 9-bit characters. +RB$DSP: CAIN A,177 + JRST RUBOUT + CAIN A,%TXCTL+"U + JRST CTLU + CAIN A,%TXCTL+"D + JRST CANCEL + CAIN A,%TXCTL+"G + JRST QUIT + CAIN A,%TXCTL+"M +IFN $$BRKINS, JRST BRKCR +IFE $$BRKINS, JRST BREAK + CAIE A,%TXCTL+"_ + CAIN A,%TXCTL+"C +IFN $$BRKINS, JRST BRKINS +IFE $$BRKINS, JRST BREAK + CAIN A,%TXCTL+"Q + JRST QUOTE + CAIN A,%TXCTL+"L + JRST REDISP +IFN $$CTLBRK,[ + TRNE A,%TXCTL+%TXMTA +IFN $$BRKINS, JRST BRKINS +IFE $$BRKINS, JRST BREAK +] + JRST INSECH +];IFN $$FCI + +SUBTTL Various action routines for input characters. + +;Dispatch here for a character that quotes the next one (eg, ^Q). +;The quoting character goes in the buffer so that it can quote +;the next character at the next level of parsing. +QUOTE: +IFE $$CTLECH,PUSHJ P,OUTECH +IFN $$FCI,PUSHJ P,CHRASI + IDPB A,RB.PTR(B) ;Store the ^Q. + PUSHJ P,INCHR ;Read the quoted character. + +;Insert a character, echoing it if it was a non-echoed control-character. +INSECH: CAIE A,177 +IFN $$CTLECH,CAIA +.ELSE [ +IFN $$FCI, TRNE A,%TXCTL +.ELSE CAIGE A,40 +] + PUSHJ P,OUTECH + JRST INSERT + +;Insert char followed by a LF. For CR, when it isn't a break. +INSCR: MOVEI A,^M + IDPB A,RB.PTR(B) + MOVEI A,^J + MOVE C,RB.END(B) ;Note that the buffer may become full + CAMN C,RB.PTR(B) ;after just the CR. + JRST [ MOVEI B,1 + AOS (P) + POPJ P,] + +;Dispatch here for an ordinary character, that should just be inserted, +;and has already been echoed. +INSERT: +IFN $$FCI,PUSHJ P,CHRASI ;If char is 9-bit and buffer is 7-bit, convert. + IDPB A,RB.PTR(B) + POPJ P, + +;Insert char and a LF, then break. +BRKCR: PUSH P,A + MOVEI A,^M + IDPB A,RB.PTR(B) + MOVEI A,^J + IDPB A,RB.PTR(B) + POP P,A + JRST BREAK + +;Dispatch here for a break character. We store it and a null, +;then signal READ to return the break character. +;If the character is a control char which didn't echo, we echo it. +BRKINS: PUSH P,A + PUSHJ P,INSECH ;Insert, maybe echoing or converting 9-bit to 7-bit. + POP P,A + +;Dispatch here for a break character that should not be stored +;in the buffer. +BREAK: SETZ C, ;Store a 0 to make it ASCIZ, + MOVE D,RB.PTR(B) ;but don't make RB.PTR point after it. + IDPB C,D + AOS (P) + POPJ P, + +;Here to "quit". Acts like too many rubouts, flushing any amount of input. +QUIT: MOVE C,RB.BEG(B) ;Mark the buffer empty. + MOVEM C,RB.PTR(B) + SETZM RB.PRS(B) ;Tell user his old parsing work is no use. + MOVNI A,2 ;Make READ return -2. + AOS (P) + POPJ P, + +;Empty the entire buffer. The same as exactly enough rubouts +;but types out differently. +CANCEL: SETZM RB.PRS(B) ;Tell user his old parsing is no longer any use. + SKIPGE D,RB.TYP(B) ;On a display, clear the display window first, + JRST CANCE1 ;while we can still tell how long it is. + MOVE C,RB.BEG(B) ;Empty the buffer. + MOVEM C,RB.PTR(B) + TLNE D,RB%FIL + POPJ P, ;If reading from file, don't type anything. + MOVEI A,40 ;Printing terminal, type "XXX?" and CRLF. + PUSHJ P,OUTCHR + MOVEI A,"X + PUSHJ P,OUTCHR + PUSHJ P,OUTCHR + PUSHJ P,OUTCHR + MOVEI A,"? + PUSHJ P,OUTCHR + JRST WCLEAR ;CRLF, and prompt if appropriate. + +CANCE1: PUSHJ P,WCLEAR ;Clear out the display window. + MOVE C,RB.BEG(B) ;Empty the buffer. + MOVEM C,RB.PTR(B) + POPJ P, + +CTLU: +IFN $$CTLECH,PUSHJ P,IGNORE ; If the ^U echoed, must erase it too. +;Delete one line backwards. Deletes at least one character. +CLRLIN: PUSHJ P,RUBOUT ; DELETE AT LEAST ONE CHAR, STOPPING ONLY AT LINE BEG. + CAIA + JRST POPJ1 ; Beginning of buffer => propagate the skip. + MOVE C,RB.PTR(B) + CAMN C,RB.BEG(B) ; Else stop rubbing if now at start of line. + POPJ P, + LDB A,C + CAIE A,^J + JRST CLRLIN + POPJ P, + +;Dispatch here to ignore a character. On a display, erase it if it echoed. +IGNORE: +IFE $$CTLECH,[ +IFE $$FCI,CAIGE A,40 +IFN $$FCI,TRNE A,%TXCTL + POPJ P, +] + SKIPL RB.TYP(B) + POPJ P, + JRST RUBOU1 + +SUBTTL Various display operations + +;Here to retype the entire contents of the buffer. +REDISP: +IFN $$FFCLR,IFN $$PROMPT, PUSHJ P,PROMPT ;If ^L clears the screen, just re-prompt. +IFE $$FFCLR,PUSHJ P,WCLEAR ;Else, erase all the lines that are in use + ;and put cursor after the previous prompt. + MOVE C,RB.BEG(B) +REDIS1: CAMN C,RB.PTR(B) + POPJ P, + ILDB A,C + PUSHJ P,OUTECH + JRST REDIS1 + +;Clear the display window. On printing terminal, just CRLF and prompt. +WCLEAR: SKIPL RB.TYP(B) + JRST [ PUSHJ P,CRLF + IFN $$PROMPT, PUSHJ P,PROMPT + POPJ P,] +;Here for clearing buffer on a display. +IFN $$MULTI,[ + PUSHJ P,RESYNCH ;Compute vpos,,hpos of end of buffer in D. + PUSH P,D + PUSHJ P,CRSHOME ;Move cursor to beginning of rubout processor area. + MOVEI A,"L + PUSHJ P,DISP2 ;Clear rest of that line. + HLRZS (P) + POP P,D ;Then CRLF down thru the lines that were occupied. + HLRZ C,RB.POS(B) + CAMN C,D + POPJ P, +WCLEA1: CAMN C,D + JRST CRSHOM ;Then move cursor to beginning of area again. + MOVEI A,"D + PUSHJ P,DISP2 ;Move down one line + MOVEI A,"L + PUSHJ P,DISP2 ;and clear the one we get to. + AOJA C,WCLEA1 +];IFN $$MULTI +.ELSE [ + PUSHJ P,CRSHOME ;Move cursor to beginning of rubout processor area. + MOVEI A,"L + JRST DISP2 ;Clear rest of that line. +];IFN $$MULTI + +;On a display only, move the cursor to the beginning of the window area. +CRSHOM: MOVEI A,"V + PUSHJ P,DISP2 + HLRZ A,RB.POS(B) + ADDI A,10 + PUSHJ P,DISPLAY + MOVEI A,"H + PUSHJ P,DISP2 + HRRZ A,RB.POS(B) + ADDI A,10 + PUSHJ P,DISPLAY + POPJ P, + +;Output a ^P followed by the character in A, using DISPLAY supplied by user. +DISP2: + PUSH P,A + MOVEI A,^P + PUSHJ P,DISPLAY + POP P,A + PUSHJ P,DISPLAY + POPJ P, + +;Output the character in A as it should be echoed, preserving A. +OUTECH: PUSH P,A + PUSHJ P,OUTEC1 + POP P,A + POPJ P, + +OUTEC1: CAIGE A,177 + JRST OUTPUT +IFN $$FCI,PUSHJ P,CHRASC + CAIN A,177 + JRST OUTRUB + CAIN A,^M + JRST CRLF + JRST OUTPUT + +OUTRUB: MOVEI A,"^ + PUSHJ P,OUTPUT + MOVEI A,"? + JRST OUTPUT + +;Type a CRLF via the output 1 character instruction. +CRLF: MOVEI A,^M + PUSHJ P,OUTCHR + MOVEI A,^J + PUSHJ P,OUTCHR + POPJ P, + +SUBTTL The operation of rubbing out one character + +;This is the character action routine for Rubout, which we assume +;was not echoed. +RUBOUT: PUSHJ P,DBPPTR ;Back up RB.PTR one byte. + JRST QUIT ;It was at beginning => return -2 ("overrrubout") from READ. + MOVE A,C + ILDB A,A ;What character are we rubbing out? + LDB D,C + CAIN A,^J ;If rubbing out a ^J which follows a ^M, + CAIE D,^M + JRST RUBOU3 + CAMN C,RB.BEG(B) + JRST RUBOU3 + SKIPG RB.TYP(B) ;Rub out the ^M too. + JRST RUBOU4 ;On display, just call rubout again after this call is done. + PUSHJ P,DBPPTR ;On printing TTY, type a CRLF and flush both characters. + JRST CRLF + +RUBOU4: PUSH P,[RUBOUT] +RUBOU3: SKIPLE RB.TYP(B) ;Printing terminal? +OUTPUT: JRST OUTCHR ;on printing terminal, just echo the character. + +;Here to rub the character in A out on a display screen. +RUBOU1: PUSHJ P,CHRTYP + XCT RUBTAB(A) +RUBOU2: MOVEI A,"X + JRST DISP2 + +RUBTAB: JFCL ;Normal character; fall through to RUBOU2 and send ^PX. + JRST RUBCTL ;Control char may be one position or two. + JRST RUBBS ;Backspace rubs out by moving forward. + JRST RUBCR ;CR rubs out requiring redisplay. + JRST RUBLF ;LF is simple, but maybe also rub preceding CR + JRST RUBHT ;Tab is hard to rub out. + PUSHJ P,RUBOU2 ;Rubout and ^@ take two positions always. + JRST OUTPUT ;^G takes no positions; echo it to rub it out. + +RUBCTL: MOVSI D,RB%SAI ;Control chars are one pos or two according to sail mode. + TDNN D,RB.TYP(B) + PUSHJ P,RUBOU2 + JRST RUBOU2 + +RUBBS: RUBCR: RUBHT: +IFN $$MULTI,[ + PUSHJ P,RESYNCH ;Compute current vpos,,hpos in D. + MOVEI A,"H + PUSHJ P,DISP2 ;Move cursor to that position. + MOVEI A,10(D) + PUSHJ P,DISPLAY + POPJ P, +] +.ELSE JRST REDISP + +RUBLF: MOVEI A,"U ;Rubbing out LF: move up one line. + JRST DISP2 + +;Decrement RB.PTR by one byte, updating RB.PRS as necessary. +;Skips unless RB.PTR was pointing at the beginning of the buffer, +;in which case it was not changed. RB.PTR is left in C, either way. +DBPPTR: MOVE C,RB.PTR(B) + CAMN C,RB.BEG(B) + POPJ P, + CAMN C,RB.PRS(B) + SETZM RB.PRS(B) + PUSHJ P,DBPC + MOVEM C,RB.PTR(B) +POPJ1: AOS (P) + POPJ P, + +;Decrement the byte pointer in C. If $$FCI, we handle 7-bit and 9-bit byte pointers. +;Otherwise, we handle only 7-bit byte pointers. +DBPC: +IFN $$FCI,[ + LDB D,[300600,,C] + CAIE D,7 + JRST DBP9 +] + ADD C,[070000,,] + SKIPGE C + SUB C,[430000,,1] ;Decrement byte pointer. + POPJ P, + +IFN $$FCI,[ +DBP9: ADD C,[110000,,] + SKIPGE C + SUB C,[440000,,1] + POPJ P, +] + +IFN $$MULTI,[ + +;Compute current Vpos,,hpos at RB.PTR and return it in D, +;by assuming that RB.POS is valid for beginning of buffer +;and scanning through the buffer, seeing what the characters do to the cursor. +;Clobbers A and C. +RESYNCH: + HRRZI C,1(P) ;C points to 3-word block on stack. + MOVE D,RB.BEG(B) ;(C) holds b.p. to scan with. + PUSH P,D + HRRZ D,RB.POS(B) ;1(C) holds HPOS. + PUSH P,D + HLRZ D,RB.POS(B) ;2(C) holds VPOS. + PUSH P,D +RBCRS1: MOVE D,(C) + CAMN D,RB.PTR(B) ;Scan till reach end of occupied region. + JRST RBCRS2 + PUSHJ P,RBFORW + JRST RBCRS1 + +RBCRS2: HRRZ D,1(C) ;D gets the new Vpos,,Hpos. + HRL D,2(C) ;Flush the block of temporary variables. + SUB P,[3,,3] + POPJ P, + +;Cursor position calculating routines. + +;Move pointer in (C) one character forward, adjusting VPOS in 2(C) +;and HPOS in 1(C) for the character moved over. +RBFORW: ILDB A,(C) + PUSHJ P,CHRTYP ;Get the character's "type code". + XCT RRFORT(A) ;DISPATCH ON TYPE OF CHAR. +RRFOR1: AOS A,1(C) +RRFOR3: CAMGE A,RB.WID(B) ;HAVE WE MOVED PAST RIGHT MARGIN? + POPJ P, + CAMN A,RB.WID(B) ;CHECK FOR JUST REACHING THE RIGHT MARGIN. + JRST RRCNTN +RRCNT1: SUB A,RB.WID(B) + MOVEM A,1(C) +RRFORV: AOS 2(C) + POPJ P, + +RRCNTN: MOVE D,(C) + ILDB D,D + CAIN D,^M + POPJ P, + JRST RRCNT1 + +RRFORT: AOSA A,1(C) ;ORDINARY CHAR, MOVE FWD 1 POS. + JRST RRFORC ;NON-FORMATTING CONTROLS. + JRST RRFORH ;MOVE FWD OVER ^H - CHECK ^HPRINT FLAG. + JRST RRFWCR ;^M, SPECIAL. + JRST RRFORL ;^J, DOWN 1 LINE. + JRST RRFOTB ;^I + JRST RRFOR2 ;2-POS CTL CHRS NOT AFFECTED BY FS SAIL (Rubout and ^@) + POPJ P, ;^G takes up no space. + +RRFOTB: MOVE D,1(C) + MOVEI A,10(D) + ANDCMI A,7 ;A HAS NEXT TAB STOP'S POSITION. + CAMLE A,RB.WID(B) ;BUT IF THAT'S OFF THE SCREEN, TAB STOP IS RIGHT MARGIN, + CAMN D,RB.WID(B) ;UNLESS WE'RE ALREADY AT THE MARGIN, IN WHICH CASE + CAIA ;WE CAN TAB 8 SPACES INTO NEXT LINE VIA CONTINUATION. + MOVE A,RB.WID(B) + MOVEM A,1(C) + JRST RRFOR3 + +RRFORL: AOS 2(C) + POPJ P, + +RRFWCR: SETZM 1(C) + POPJ P, + +RRFORH: SKIPN 1(C) + JRST RRFOR2 + SOS 1(C) + POPJ P, + +;NON-FORMATTING CONTROLS, CHECK FS SAIL FLAG. +RRFORC: MOVE D,RB.TYP(B) + TLNN D,RB%SAI ;SAIL mode => it is a one-position character. +RRFOR2: AOS 1(C) ;Else treat as 2-pos ctl char. + JRST RRFOR1 + +] ;IFN $$MULTI + +.END RUBOUT