.TITLE MENU .IDENT /150683/ .Enabl lc ; ; ; Written by Ray Di Marco ; 29-Apr-82. ; ; ; Version 290482/04. ; ; ;--------------------------------------------------------------------------- ; ; ; This is the main module for the MENU program, that when linked with DBSLIB ; produces a program that can be used to tie a set of CUSPs together to ; provide support for a database application. The program is in reality a ; simple intepretor that accepts a user FORMAT file. The major advantage of ; the program is that it allows commands to be passed to the CUSPS via core ; common. ; ; At start-up time, the program requests that the name of the FORMAT file and ; the type of CRT being used be supplied. Once this has been done, a properly ; structured application will not require that the operator ever communicate ; with the monitor, as all function may be achieved by having MENU envoke a ; CUSP in such a manner that upon completion the CUSP exits back to the MENU. ; A sample FORMAT file that can be simply modified to suit most applications ; is included as part of the documentation in this module. ; ; This version of the program operates correctly under the following ; operating system ; ; RT-11 ; TSX-plus ; RSTS/E under RT-11 emulator ; .SBTTL Modifications ; ; ; 4-Oct-82 ; ; Change ..CHAN routine so that clears screen at entry (instead of ; when terminating); also change decode table used by ..CHAN so ; that allows $) (ie output to TTY) operation. This was done so ; could output a message/instructions as part of a CUSP chain. ; Could not do this before as screen was erased before CUSP ; chain was started. ; ; 28-Feb-83 ; ; Improve error handling by including ABORT macro and routine; upon ; occurance of an error next 70 characters in format file are dumped ; to indicate cause of error. ; ; Upon recieving a or a sequence the screen ; is erased and the menu redisplayed. Key codes 161 to 172 are treated ; as equivalent digit codes 60 to 71; codes 161 to 172 are generated ; by the RDM1EM/ISC terminal special function keys. ; ; The $=, $# and $% operators are now allowed within format files; ; The $= and $# operators are used to indicate the start of conditional ; section of the format file and the $% operator marks its end. The ; sequence [$=][XXX][bytes][$%] results in the [bytes] in the format ; file being processed iff [XXX] is the three letter terminal type ; code for the user's terminal type. The CONIO module stores the ; user's terminal type code in core-common at start-up time; valid ; terminal type codes a V10 (VT100), V52 (VT52), ADM, ISC and TVI. ; The sequence [$#][XXX][bytes][$%] causes [bytes] to be processed ; iff XXX does not match the terminal type! ; ; The / character may now be used as a function initiator as well ; as the digit keys (ie a $/ [function] $$ sequence may be included ; in the menu format file). MENU will always execute the commands ; within the $/ sequence a) whenever the / key is pressed, b) when ; the menu is first displayed and c) whenever a or ; input character is recieved. Note that this sequence, being always ; executed on start-up allows certain menus from being accessed ; on given terminals etc. ; ; 15-Jun-83 ; ; Perform a .SRESET prior to chaining to a CUSP. This has been done ; to insure that Ken's FORTRAN programs don't bomb when called from ; MENU. ; .SBTTL Documentation .IF EQ,-1 The menu program requires that the user answer two questions before it can commence. These question must be answered the first time that the program is started, but proper design of the FORMAT file will eliminate having to answer these questions when the MENU is entered after exitting a CUSP. The two questions asked are Format file: In response to this query, the name of the FORMAT file that holds the menu format definition must be supplied. If the application is being started via a LOGON command file, the name of the file may be supplied to the program by the command file. In the case of nested menus, where one menu envokes another menu, the format file name may be passed via core common. CRT type: This question is really asked by the CONIO module, and must be answered so that the correct terminal driver can be used. This question is normally only asked upon the first activation of any of the database utilities, as it is passed through core common. In this documentation, the term core common is used. Under RT-11 and TSX, core common is the region of virtual address space starting at octal 500 and extending to 777. Programs that chain may use this region to exchange data. The format of the data passed in core common is documented in the CONIO module. The function of MENU is to allow the database manager to link together all the desired CUSPs needed to carry out desired objectives. Some functions can be readily achieved by envoking only one CUSP (viz editting), while others can only be achieved by envoking a number of CUSPs to process data in series (viz report production). If a UNIX operating system was used, there would not be any need for this type of program. The following section describes the format of the file intepreted by MENU, and details a typical format file. A MENU format file consists of two sections. The text section starts with the first byte in the file, and is terminated by the occurance of the sequence of characters $* (ie an ESCAPE followed by a STAR). At startup, MENU clears the screen and will dump out the text section starting at the third line on the screen. This text should contain and instructions etc needed by users, and is best created with a screen editor such as KED. The second section of the file starts dirrectly after the $* sequence, and is terminated by a second $* sequence. This section is called the sequence section, and allows MENU to determine what operations are to be performed in response to user input. Once MENU has output the text it clears the top line of the screen and leaves the cusor at the home position; it then waits for user input. Only the digit keys 0 to 9 are acknowledged; all other characters are ignored. Upon reciept of a digit character, the sequence section is scanned, and any commands associated with the digit (called a command sequence) are executed. Upon completion of the commands, or if no sequence is associated with the selected key, the cusor is again moved to the home position, and MENU waits for another character. A command sequence is associated with a digit key by including the sequence of characters $N (N=0..9) in the sequence section of the format file. Upon detection of digit N, MENU scans through the sequence section looking for an $N that indicates the start of commands associated with the digit. The $! sequence of characters indicates the end of the commands associated with a particular digit. Within the $N and $! delimiters are placed all the commands that are to be executed when digit key N is pressed. Before descibing the commands that can be included in a sequence, it is important to note that the MENU intepretor ignores the , and characters, so these may be used to format the sequences to improve readibilty and maintainability. The intepretor also recognises the semi-colan character as the start of comment marker, and it is strongly advised that use be made of the commenting facility. Two commands can be included within a sequence. These commands allow output to be dirrected to terminal and a CUSP to be envoked. The command $) .... $$ causes all characters between the $) and $$ delimiters to be typed on the terminal. This is a simple command and can be readily used to interact with the user when using nested menus etc. The second command is slightly more complexe, and is initiated upon detection of the $@ operator. The format of this command is $@[CUSP] {$I[INP]$$} or {$C[CUSP]} $! where [CUSP] is the name of a CUSP that is to be envoked. $I[INP]$$ can be optionally included to cause the line of text INP to be supplied to the CUSP when it request a line of input. $C[CUSP] can be optionally included to dirrect the CUSP to chain to another database program. $! is the command terminator, upon detection of which a chain to the specified cusp is performed. The $C and $I are very useful in that they allow the database manager the option of chaining cusps togther and answer question asked by the CUSPs. A $@ command may include as many $I and $C operations as desired, and in what ever order needed, as long as core common space is not exceeded. The last two operators in a chain command are normally $CLB:MENU.SAV$$ ; envoke menu $IDEMO.FRM$$ ; tell it format file being used thereby ensuring that control is passed back to the menu after the CUSPs have completed execution. The following is a sample format file that would be used as the menu for a simple database application. It is assumed that the database is called FAULTS, that standard DBS naming conventions apply, and that the CUSPs have been linked with the user template and are, along with the data files on logical unit DK:. ----------------------------------------------------------------------------- Fault Analysis System Menu ========================== 1 Record occurance of a fault 2 Edit existing fault card 3 Delete a fault card 4 Display fault report on terminal 5 Produce a hard copy fault report 6 Allow fault cards to be inspected and printed. 7 Analysis fault data The desired function may be envoked by typing the corresponding digit. $* ; mark end of header $1 ; mark start of sequence $@DK:FAULTS.SAV$$ ; envoke editor $INEW$$ ; order create a new record $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $2 ; mark start of sequence $@DK:FAULTS.SAV$$ ; envoke editor $IEDIT$$ ; order edit record $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $3 ; mark start of sequence $@DK:FAULTS.SAV$$ ; envoke editor $IDELETE$$ ; order delete record $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $4 $@SELECT$$ ; want to select records $ISELECT.FRM$$ ; tell selection criterions $ISORTER.DAT$$ ; output selected data to this file $I0$$ ; allowed select to chose size $CLB:SORTER$$ ; Envoke sorter $ISORTER.DAT$$ ; tell file want sorted $CREPORT$$ ; want to produce report $IREPORT.FRM$$ ; format of report $ISORTER.DAT$$ ; sort data file to use $ITT:$$ ; send output to TTY $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $5 $@SELECT$$ ; want to select records $ISELECT.FRM$$ ; tell selection criterions $ISORTER.DAT$$ ; output selected data to this file $I0$$ ; allowed select to chose size $CLB:SORTER$$ ; Envoke sorter $ISORTER.DAT$$ ; tell file want sorted $CREPORT$$ ; want to produce report $IREPORT.FRM$$ ; format of report $ISORTER.DAT$$ ; sort data file to use $ILP:$$ ; send output to TTY $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $6 $@SELECT$$ ; want to select records $ISELECT.INX$$ ; tell selection criterions $ISORTER.INX$$ ; output selected data to this file $I0$$ ; allowed select to chose size $CLB:SORTER$$ ; Envoke sorter $ISORTER.INX$$ ; tell file want sorted @CINSPECT$$ ; Envoke inspector $ISORTER.INX$$ ; tell where to find indexs $CLB:MENU$$ ; chain back to ourself $IFAULTS.MEN$$ ; remind ourselves about menu $! ; activate sequence $7 $)Sorry, not yet debugged^G!$$ ; tell not ready $! $*--------------------------------------------------------------------------- .ENDC .SBTTL DECLARATIONS ; ; ; .MCALL .PRINT,.EXIT,.TTYOUT ; RT-11 error reporting .MCALL .PUSH,.POP ; stacking .MCALL .CHAIN,.SRESET ; chaining .MCALL .GTLIN ; for special initialization .MCALL FILSPT ; want file support ; FILSPT ; setup file support ; ; .GLOBL CON.ST,CON.CI,CON.CO,CON.LI,CON.LO ; "CONIO" .GLOBL CON.XY,CON.ES,CON.EL ; "CONIO" .GLOBL FRMINT,FRMINC,FRMMRK,FRMRST ; "FRMFIO" entries .GLOBL FRMNME ; "FRMFIO" data structure ; ; JSW = 44 ; RT-11 JSW J.CHN = 400 ; set -> chained to CC.CMD = 546 ; set to ^RCMD -> CC loaded CC.PNT = 550 ; point to CC input ; ; .PSECT CODE ; open code area ; ====== ==== ; ; .SBTTL Macro Definitions ; ; .MACRO PRINT STR=R0 .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDM PRINT ; ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; ; .MACRO DECODE TABLE MOV #TABLE,R1 CALL DECODE .ENDM DECODE ; ; ; ABORT is used to abort execution if CND is true; MES is printed out ; .MACRO ABORT MES,CND,FILERR=NO,?LB,?LC .IF NB,CND B'CND LB BR LC LB': .ENDC .IIF IDN,FILERR,NO, JSR R1,ABORT .IIF DIF,FILERR,NO, JSR R1,ABORTF .ASCII /'MES'/<200> .EVEN .IIF NB,CND, LC': .ENDM ABORT ; .SBTTL Initialization Code ; ; ; Initialize TTY interface and get name of menu format file. Note that if ; re-envoking ourselves after envoking a cusp it is possible to pass format ; file name to ourselves through core common. When first run ask for format ; file name and then initialize TTY, but when chained to do things in reverse ; order. A little thinking shows why this is necessary to ensure that ; start-up command files can be best utilized. ; ; START: PRINT #M.PROG ; identify self BIT #J.CHN,@#JSW ; chained to? BNE 100$ ; yes -> revers order .GTLIN #MNUNME,#M.FILE ; get file name CALL CON.ST ; initialize TTY BR RESTRT ; normal code 100$: CALL CON.ST ; set up for CRT GTLIN #MNUNME,#M.FILE ; request menu name BR RESTRT ; normal code ; ; .nlist bin M.IDEN: .ASCII <12><11><11><11><11><11><11><11>/ / M.PROG: .ASCIZ /Menu RDM150683/ M.FILE: .ASCII / Format file: /<200> .even .list bin ; ; .SBTTL Main Loop code ; ; Get to RESTRT from initialization code and whenever a or ; character is entered from the keyboard; The RESTRT code is used to ; redisplay the menu on the screen. This is needed in case the screen ; display was corrupted. ; ; Clear screen and reopen input file ; RESTRT: CALL CON.ES ; erase all of screen PRINT #M.IDEN ; identify self MOV #FRMNME,R0 ; R0 -> destination MOV #MNUNME,R1 ; R1 -> source 1000$: MOVB (R1)+,(R0)+ ; setup BNE 1000$ ; menu file name CALL FRMINT ; open format file BR 1210$ ; enter loop ; ; display menu text ; 1200$: CALL CON.CO ; output char 1210$: CALL INPUT ; input a byte CMPB R0,#200+'* ; hit EOH BNE 1200$ ; no -> loop 1700$: CALL FRMMRK ; mark rewind point ; ; ; ; In some cases may want to activate a function for a particular type ; of terminal without waiting for operator input (ie menu not usable ; from that type of terminal); 'FORCE' a / to keyboard ; CALL FRMRST ; reset format file CLR R0 ; Y:X = 0:0 CALL CON.XY ; home cusor MOV #'/,R0 ; R0 = / BR PROCESS ; process it ; ; ; Get here after have processed last input character. Reset things. ; LOOP: CALL FRMRST ; reset format file CLR R0 ; Y:X = 0:0 CALL CON.XY ; home cusor ; ; Ready for user input; wait for character and then enter process loop. ; A or character causes the menu to be redisplayed. ; NEXT: CALL CON.CI ; input a character PROCES: CMP R0,#215 ; ? BEQ RESTRT ; yes -> redraw menu CMP R0,#15 ; ? BEQ RESTRT ; yes -> redraw menu ; ; make RDM1EM/ISC special function keys PF0-PF9 equivalent to digit keys ; CMP R0,#161 ; RDM1EM Special Function Key? BLO 120$ ; no --> skip SUB #101,R0 ; yes -> map to equivalent digit key ; ; ignore invalid keys ; 120$: CMP R0,#'/ ; in range? BLO NEXT ; no -> ignore CMP R0,#'9 ; in range? BHI NEXT ; no -> ignore ; ; ; search through format file till find function for selected key ; ADD #200,R0 ; convert to $n equivalent MOV R0,R1 ; save for search CLR R0 ; Y:X = 0:0 CALL CON.EL ; erase top line 140$: CALL INPUT ; input character CMPB R0,#'*+200 ; eof? BEQ LOOP ; yes -> try again CMPB R0,R1 ; found match? BNE 140$ ; no -> loop ; ; Use 700$ to decode format file and envoke required routines. ; 400$: CALL INPUT ; get next input character DECODE 700$ ; decode via 700$, error = 600$ BR 400$ ; loop ; ; Actioning routines 500$ envoked to terminate processing ; 570$ envoked if character to be ignored ; 600$ envoked if character is illegal ; 500$: ADD #2,SP ; discard 'process' return address BR LOOP ; start over 570$: RETURN ; return to caller 600$: ABORT ; ; Table used to decode input. Call routine when encounter char. ; 700$: .WORD '!+200, 500$ ; end of this squence .WORD 11, 570$ ; ignore 'TB' .WORD 12, 570$ ; ignore 'LF' .WORD 15, 570$ ; ignore 'CR' .WORD 40, 570$ ; ignore 'spaces' .WORD ';, ..COMM ; comment .WORD ')+200, ..SEND ; send output to terminal .WORD '@+200, ..CHAN ; chain to CUSP now .WORD 0, 600$ ; abort address ; .SBTTL Process Routine '..COMM' ... Comment ; ; Discard all input untill hit end of comment marker, a 'LF'! ; ..COMM: CALL INPUT ; get a character CMP R0,#12 ; hit a 'LF'? BNE ..COMM ; no -> loop RETURN ; loop ; ; .SBTTL Process Routine '..SEND' ... Send output to terminal ; ; All characters upto but excluding terminator are to be sent to terminal. ; ..SEND: CALL INPUT ; get character CMP R0,#'$+200 ; terminator? BEQ 1000$ ; yes -> skip CALL CON.CO ; output BR ..SEND ; loop 1000$: RETURN ; exit ; ; .SBTTL Process Routine '..CHAN' ... Chain to program ; ; ; We are here to chain to the program whose name follows in the ; format file. We buffer up the file name, do a NAME and LOOKUP ; to ensure it exists and then chain to it. Very simple. ; ; ..CHAN: MOV #TMPBF,R1 ; R1 -> buffer 100$: CALL INPUT ; get a character CMPB R0,#15 ; ? BEQ 200$ ; yes -> skip CMPB R0,#'$+200 ; EOS? BEQ 200$ ; yes -> exit MOVB R0,(R1)+ ; save char BR 100$ ; loop 200$: CLRB (R1)+ ; terminate PURGE #FDBMEN ; ensure FDB free NAME STRING=#TMPBF,EXTENS=#^RSAV,ERROR=600$ LOOKUP ERROR=600$ MOV (R5),R0 ; R0 = RAD50 file spec MOV #500,R1 ; R1 = destination MOV #4,R2 ; R2 = number words to move 210$: MOV (R0)+,(R1)+ ; copy SOB R2,210$ ; loop CALL CON.ES ; clear screen ; ; Use 700$ to decode format file and envoke required routines. ; 400$: CALL INPUT ; get next input character DECODE 700$ ; decode via 700$, error = 600$ BR 400$ ; loop ; ; Actioning routines 500$ envoked to terminate processing ; 570$ envoked if character to be ignored ; 600$ envoked if character is illegal ; 500$: .SRESET ; close channels .CHAIN ; chain to program 570$: RETURN ; return to caller 600$: ABORT <..CHAN:cannot chain to CUSP!> 610$: ABORT <..CHAN:illegal character in format file!> ; ; Table used to decode input. Call routine when encounter char. ; 700$: .WORD '!+200, 500$ ; end of this squence .WORD 11, 570$ ; ignore 'TB' .WORD 12, 570$ ; ignore 'LF' .WORD 15, 570$ ; ignore 'CR' .WORD 40, 570$ ; ignore 'spaces' .WORD ';, ..COMM ; comment .WORD ')+200, ..SEND ; send output to TTY .WORD 'I+200, ...INP ; load instruction for CUSP .WORD 'C+200, ...CHN ; order CUSP to chain .WORD 0, 610$ ; abort address ; .SBTTL Chain support '...INP' ... load core common ; ; ; This routine will load core common will all data from the format ; untill a $$ terminator is hit. ; ...INP: MOV #^RCMD,@#CC.CMD ; indicate have commands MOV #CC.PNT+2,@#CC.PNT ; reset pointer MOV $$LOAD,R1 ; R1 -> buffer 100$: CALL INPUT ; get next byte MOVB R0,(R1)+ ; save CMPB R0,#'$+200 ; eoi BNE 100$ ; no loop ; 200$: CLRB -1(R1) ; null terminate line MOVB #'A+200,(R1) ; idicate EOD MOV R1,$$LOAD ; save pointer RETURN ; all done ; ; .SBTTL Chain support '...CHN' ... load CC with a chain command ; ; We are here to load core common with a ; ; Chain to X ; ; command. We decode the name of the file that is to be chained ; to from following characters in the input stream. ; ...CHN: MOV #TMPBF,R1 ; R1 -> buffer 100$: CALL INPUT ; get a character CMPB R0,#'$+200 ; EOS? BEQ 200$ ; yes -> exit MOVB R0,(R1)+ ; save char BR 100$ ; loop 200$: CLRB (R1)+ ; terminate PURGE #FDBMEN ; ensure FDB free NAME STRING=#TMPBF,EXTENS=#^RSAV,ERROR=600$ LOOKUP ERROR=600$ MOV (R5),R0 ; R0 = RAD50 file spec MOV $$LOAD,R1 ; R1 -> buffer MOV #10,R2 ; R2 = number words to move MOVB #'C+200,(R1)+ ; load CHAIN command 210$: MOVB (R0)+,(R1)+ ; copy SOB R2,210$ ; loop MOVB #'A+200,(R1) ; idicate EOD MOV R1,$$LOAD ; save pointer MOV #^RCMD,@#CC.CMD ; indicate have commands MOV #CC.PNT+2,@#CC.PNT ; reset pointer RETURN ; all done ; 600$: ABORT <...CHN:invalid chain file> .SBTTL Primitive - 'DECODE' ... used to decode input ; ; Routine called with R1 pointing to table. Table consists ; of two word entries. Control passed to routine whose address ; is in secon word iff R0 matchs first word in entry. Table ; is terminated with an entry that has first word of 0. If cannot ; find matching entry in table, pass control to routine whose ; address is specified in terminating (null word 1) entry. ; DECODE: TST (R1) ; eot? BEQ 1200$ ; yes -> abort CMP R0,(R1) ; match? BEQ 1200$ ; yes -> skip ADD #4,R1 ; bump pointer BR DECODE ; loop ; 1200$: JMP @2(R1) ; pass over control ; .SBTTL Primitive - "INPUT" ... return next input character ; ; This routine returns the next character from the input stream. If INPUT$ is ; non-zero the character stored in INPUT$ is returned. This allows a routine ; to push an unwanted character back into the input stream. The routine also ; supports conditional input using the $= and $# operators to allow parts of ; the input file to be conditionally skipped. ; ; if INPUT$ <> 0 return 'pushed' character ; INPUT$: .WORD 0 ; used to push char back INPUT: TST INPUT$ ; pushed char available? BEQ 100$ ; no -> skip MOV INPUT$,R0 ; return it CLR INPUT$ ; clear for next time RETURN ; all done ; ; get next char from input stream; $=, $# and $% are processed specially ; 100$: CALL FRMINC ; get a stream character ABORT ,CS ; trap EOF CMPB R0,#'%+200 ; End test character? BEQ INPUT ; yes -> ignore it CMPB R0,#'=+200 ; If equal test? BEQ 1000$ ; yes -> skip CMPB R0,#'#+200 ; If not equal test? BEQ 2000$ ; yes -> skip RETURN ; bye ; ; have conditional test to perform; if test suceeds pass conditional input ; 1000$: CALL TSTTYP ; is equal? BEQ INPUT ; yes -> return next byte BR 3000$ ; no --> discard cond code 2000$: CALL TSTTYP ; is not equal? BNE INPUT ; no --> return next byte ; yes -> discard cond code ; ; test failed; ignore all input till $% ; 3000$: CALL FRMINC ; get a stream character ABORT ,CS CMPB R0,#'%+200 ; end of condition test? BNE 3000$ ; no --> loop BR INPUT ; yes -> return next byte ; .SBTTL Primitive - "TSTTYP" ... test terminal type ; ; This routine will check to see if the user's terminal type code is setup ; by CONIO in core common (in rad50) matches the terminal type specification ; specified by the user as the next three characters in the format file; the ; Z flag is set on exit iff the comparision suceeds. ; ; re-use the start-up code as a buffer to hold the three letter term type ; TSTTYP: .PUSH ; save MOV #START,R1 ; R1 -> buffer MOV #3,R2 ; R2 = counter 100$: CALL INPUT ; R0 = character MOVB R0,(R1)+ ; save char SOB R2,100$ ; loop CLRB (R1)+ ; terminate ; ; convert to rad50 ; PURGE #FDBMEN ; ensure FDB free BIS #F.NERR,FDB.FL(R5) ; disable errors NAME STRING=#START ; convert to RAD50 ABORT <..TERM:invalid terminal type>,CS; insure valid ; ; have correct terminal type ; MOV (R5),R0 ; R0 -> input .POP ; restore CMP @#542,2(R0) ; correct terminal type RETURN ; done ; .SBTTL Primitive - "ABORT" ... abort program execution ; ; get here if program is to be aborted; at entry R1 holds address of ; .ASCIZ string that gives reason of abort. This string is printed along ; with data from format file to allow error point to be found. ; ; ABORT: .PRINT #7000$ ; header .PRINT R1 ; reason for abort .PRINT #7100$ ; trailer ; MOV #70.,R2 ; R2 = counter 1000$: CALL FRMINC ; input char BCS 1700$ ; abort if EOS .TTYOUT ; output character SOB R2,1000$ ; loop 1700$: .EXIT ; done ; .nlist bin 7000$: .ASCII <15><12>|MENU-fatal-|<200> 7100$: .ASCIZ <15><12>| error in format file before:| .even .list bin ; .SBTTL Data area ; ; .PSECT DATA ; open data area ; ====== ==== ; $$LOAD: .WORD CC.PNT+2 ; where next CCC is to load FDB FDBMEN,CHANNEL=1 ; set up FDB for ..CHAN MNUNME: .BLKB 20 ; holds menu file name TMPBF: .BLKB 100 ; buffer for ..CHAN ; ; .END START