.TITLE TYPE (TYPES A FILE) .IDENT /JN2.1/ ; ; TYPE ; ; DESCRIPTION ; TYPES A FILE ON THE USERS TERMINAL, WITH ^Z ARMED AS AN ; UNCONDITIONAL EXIT. ; USAGE ; TYPe filedescr[,filedescr#2][/-TI][/TR[:nn]] ; meaning: multiple files per command line ; the /-TI switch suppresses the title line ; the /TR switch truncates lines fit on the terminal ; with the default width being terminal buffer-1 ; can be overridden with the :nn specifier ; OR: TYPe /HE for a printout of HELP info. ; NOTES ; 1. WRITTEN 11/21/77 BY C. SOUTH, HRL. ; MODIFICATIONS: ; 1. 780620. BY J. NEELAND TO HANDLE IMBEDDED & FORTRAN CARRIAGE-CONTROL ; 2. 780623. BY J. NEELAND TO DEFAULT TO SY0:TEST.FTN FILENAME ; 3. 780626. BY J. NEELAND TO OUTPUT FILENAME IN LEADING LINE ; 4. 780627. BY J. NEELAND TO INCLUDE TIME OF LAST WRITE IN BANNER ; 5. 780629. BY J. NEELAND TO ADD SWITCHES FOR SUPRESSING BANNER(TITLE) ; AND TRUNCATE (TO PROVIDE FOR THE 'TYPE' FUNCTIONALITY) ; 6. 780705. BY J. NEELAND TO ADD /HELP SWITCH AND SPACE AFTER BANNER. ; 7. 780708. BY J. NEELAND TO REMOVE IOT EXIT AND STACK OVERFLOW ERRORS. ; 8. 780719. BY J. NEELAND TO REMOVE DEFAULT NAME SO THAT FILES WITHOUT ; NAME/EXTENSION CAN BE 'TYPED' ; 9. 781121. BY J. NEELAND TO FIX /HE TEXT TO CORRESPOND TO FIX 8. ;********************************************************************* ; .LIST MEB .ENABL LC ;ALLOW LOWER-CASE IN TEXT MESSAGES ; .MCALL GCMLB$,GCML$,CSI$,CSI$1,CSI$2 .MCALL FDBDF$,FDOP$A,OPEN$R,FDBF$A,NMBLK$ .MCALL FSRSZ$,FINIT$,QIOW$,EXIT$S .MCALL GET$,CLOSE$,FDRC$A,DIR$,GLUN$ .MCALL ASTX$S,FHDOF$,CSI$SW,CSI$SV,CSI$ND ; ; INVOKE DEFINITION MACRO(S) ; FHDOF$ DEF$L ;LOCAL DEFINITIONS ; ; DEFINITION OF LOCAL CONSTANTS ; BUFLEN=140. ;SIZE OF MAXIMUM LINE IN BYTES EFLGIN=1 ;EVENT FLAG # FOR INPUT FROM FILE EFLGOT=2 ;EVENT FLAG # FOR OUTPUT TO TERMINAL LUNIN=1 ;LUN FOR INPUT LUNOT=2 ;LUN FOR OUTPUT ; ; DPB'S ; DETQIO: QIOW$ IO.DET,LUNOT,EFLGOT ;DETACH TI: ASTQIO: QIOW$ IO.ATA,LUNOT,EFLGOT,,,, ;SETS UP AST ON TI: INPUT OUTQIO: QIOW$ IO.WVB,LUNOT,EFLGOT,,IOSB,, ERRQIO: QIOW$ IO.WVB,LUNOT,EFLGOT,,IOSB,,<0,0,40> RATQIO: QIOW$ IO.RAT,LUNIN,EFLGIN,,IOSB,,<0,ATTLST> GLUN: GLUN$ LUNOT,TIMDAT ; ; SETUP FOR GET-COMMAND-LINE AND COMMAND STRING INTERPRETER ; GCML: GCMLB$ 0,TYP,,LUNOT ;ESTABLISH PROMPT CHARS AND AT. DEPTH LEVEL CSI$ .EVEN CSI: .BLKB C.SIZE ;BUFFER FOR CSI ;+ ; DEFINE CSI SWITCHES ;- TTLFLG=1 ;SWITCH FOR PROVIDING TITLES TRNFLG=2 ;SWITCH FOR TRUNCATING LINES HEFLG=4 ;SWITCH FOR DISPLAYING HELP INFO ; CSISWD: CSI$SW TI,TTLFLG,CSIWD,SET,NEG CSI$SW HE,HEFLG,CSIWD,SET,NEG CSI$SW TR,TRNFLG,CSIWD,SET,NEG,TRVAL CSI$ND ; TRVAL: CSI$SV DECIMAL,TRNSIZ,2 CSI$ND ; ; ESTABLISH FCS MACROS FOR FILE PROCESSING ; FSRSZ$ 2 INFDB: FDBDF$ ;DEFINE OFFSET AND OTHER DEFINITIONS FDOP$A LUNIN,CSI+C.DSDS,DFNB,FO.RD FDRC$A ,CHBUF,BUFLEN FDBF$A EFLGIN .EVEN ;+ ; DEFINE LOCAL STORAGE ;- ATTLST: .BYTE -12,BUFLEN ;READ MOST OF HEADER TO GET WHAT WE WANT .WORD CHBUF ;POINTER TO THE LARGEST BUFFER AVAIL. .WORD 0 ;END OF ATTRIBUTE LIST DFNB: NMBLK$ ,,,SY,0 ;DEFINE DEFAULT DEVICE CSIWD: .WORD TTLFLG ;WORD FOR STATE OF COMMAND-LINE SWITCHES ; INITIAL VALUES: TITLE ON, TRUNCATE OFF TRNSIZ: .WORD 0 ;LENGTH OF LINE TO TRUNCATE TO INADDR: .WORD 0 ;INPUT BUFFER POINTER LINCNT: .WORD 0 ;COUNT OF # CHARS. PRINTED ON ONE LINE FTNFLG: .WORD 0 ;FLAG FOR FORTRAN C.C. IOSB: .WORD 0,0 ;I/O STATUS BLOCK RETURN LOCATION QUITCH: .WORD 0 ;FLAG FOR THE ^Z EXIT CHBUF: .BLKB BUFLEN ;STORAGE FOR LINES READ FROM FILE TIMDAT: ;REF. LABEL (USE AREA FOR A COUPLE OF THINGS) OUTBUF: .BLKB BUFLEN ;OUTPUT BUFFER USED WHEN TRUNCATING LINES LF: .BYTE 12 ;A LINEFEED WHEN NEEDED FOR IMBEDDED C.C. FILES BEGEND: .ASCII / ** / BENSIZ=.-BEGEND ASOF: .ASCII / -- Last written / ASOFSZ=.-ASOF OPNMSG: .ASCII "Error in opening file" OPNLEN=.-OPNMSG NSFMSG: .ASCII "NO such file" NSFLEN=.-NSFMSG ECSMSG: .ASCII /Error in Command-line/ ECSSIZ=.-ECSMSG ERDMSG: .ASCII /Error in reading record/ ERDSIZ=.-ERDMSG HELTXT: .ASCII /Command format: TYPe filename1.ext/ .ASCII %[,filename2.ex2][/SW]% .ASCII <15><12><11><11>/where the items in brackets are optional./ .ASCII <15><12>%Switches are: /-TI to suppress the TItle.% .ASCII <15><12><11><11>%/TR[:nn] to TRuncate lines. The default% .ASCII % width is% .ASCII <15><12><11><11>%terminal width-1 and :nn is optional to change% .ASCII / the default./ .ASCII <15><12><11><11>%/HE for this HElp text.% HELSIZ=.-HELTXT NULL: .BYTE 0 ;NULL TO OUTPUT FOR EMPTY RECORD .EVEN TYPE:: FINIT$ ;INITIALIZE FCS REGION NEXT: GCML$ #GCML ;LEAVE HOOKS IN FOR @ PROCESSING TSTB GCML+G.ERR ;ANY ERROR? BEQ GO ;NO IF EQ CMPB GCML+G.ERR,#GE.EOF ;EOF ON INPUT? BNE CSIERR ;NO IF NE EXIT$S ;YES. SIMPLY EXIT ; OPNERR: TST (SP)+ ;REMOVE RETURN FROM STACK CMPB INFDB+F.ERR,#IE.NSF ;IS THE ERROR "NONEXISTENT FILE"? BEQ NSFERR ;YES IF EQ MOV #OPNMSG,ERRQIO+Q.IOPL ;NO, GIVE GENERAL ERROR MSG MOV #OPNLEN,ERRQIO+Q.IOPL+2 BR ERRDIR ;SEND THE MESSAGE TO USER NSFERR: MOV #NSFMSG,ERRQIO+Q.IOPL MOV #NSFLEN,ERRQIO+Q.IOPL+2 BR ERRDIR OUTERR: EXIT$S ;FOR ERROR ON OUTPUT TO TERMINAL CSIERR: MOV #ECSMSG,ERRQIO+Q.IOPL ;SET ADDR & LENGTH OF ERROR MESSAGE MOV #ECSSIZ,ERRQIO+Q.IOPL+2 ERRDIR: DIR$ #ERRQIO BR NEXT ; ; ;GOT DATA FROM A COMMAND LINE OR A RESPONSE TO A PROMPT ;PARSE IT FOR AN 'OUTPUT' FILENAME GO: MOV GCML+G.CMLD,CSI+C.CMLD ;SETUP FOR CSI PROCESSING MOV GCML+G.CMLD+2,CSI+C.CMLD+2 CSI$1 #CSI ;MAKE 1ST PASS TST CSI+C.CMLD ;ANYTHING ON COMMAND LINE AT ALL? BEQ NEXT ;NO IF NE (GO BACK FOR ANOTHER LINE) AGAIN: CSI$2 #CSI,OUTPUT,#CSISWD ;2ND PASS, LOOKING FOR AN 'OUTPUT' FILENAME BCS CSIERR ;C SET IF ERROR (NO OTHER INFO) BIT #HEFLG,CSIWD ;A REQUEST FOR HELP INFO? BEQ NOHELP ;NO IF OFF JMP HELP ;OUTPUT THE HELP STUFF NOHELP: BITB #CS.NMF,CSI+C.STAT ;ANYTHING LEFT ON LINE? BEQ NEXT ;IF NOT, GO GET A NEW LINE OR EXIT OPEN$R #INFDB,,,,,,OPNERR ;+ ;CREATE NAME BANNER (IF DESIRED) ;- BIT #TTLFLG,CSIWD ;DO WE OUTPUT A BANNER? BNE 10$ ;YES, GENERATE TITLE BANNER JMP CCTYP ;NO, GO RECORD-TYPE CHECKING 10$: MOV R0,-(SP) ;YES, SAVE R0 FOR LATER USE MOV R0,R4 ;SAVE LOW REGISTERS FOR CONVERSION USE DIR$ #RATQIO ;READ FILE ATTRIBUTES MOV #,R1 ;SET TO COPY OUT REVISION DATE & TIME MOV #TIMDAT,R0 MOV #13.,R2 ;13. BYTES OF DATE & TIME CALL MBR1R0 ;COPY IT CLR FTNFLG ;INITIALIZE FORTRAN C.C. FLAG OFF MOV #CHBUF,OUTQIO+Q.IOPL ;SET ADDRESS TO BEGINNING OF RECORD MOVB #40,OUTQIO+Q.IOPL+4 ;START W/ IMPLIED C.C. ADD #F.FNB,R4 ;OFFSET FDB POINTER TO FILENAME BLOCK MOV #CHBUF,R0 ;SET POINTER TO OUTPUT AREA CALL INSBEN ;INSERT BEGINNING STRING OF BANNER MOVB N.DVNM(R4),(R0)+ ;MOVE DEVICE NAME TO BANNER FIELD MOVB N.DVNM+1(R4),(R0)+ MOV N.UNIT(R4),R1 ;GET UNIT # CLR R2 ;SET FOR ZERO-SUPPRESSION CALL $CBTMG ;CONVERT TO ASCII OCTAL MOVB #':,(R0)+ ;INSERT COLON SEPARATOR BIT #NB.DIR,N.STAT(R4) ;DID USER SPECIFY A UIC FOR THIS FILE? BEQ GTDFLT ;NO, GO GET DEFAULT MOV CSI+C.DSDS+4,R1 ;YES, GET HIS UIC DESCRIPTOR LENGTH MOV CSI+C.DSDS+6,R2 ; & LOCATION BR CPYUIC ;GO COPY TO OUTPUT BUFFER GTDFLT: CALL .RDFDR ;GET THE DEFAULT UIC LENGTH & LOCATION CPYUIC: MOVB (R2)+,(R0)+ ;COPY A CHARACTER TO OUTPUT SOB R1,CPYUIC ;COPY UNTIL ALL OF UIC IS MOVED MOV N.FNAM(R4),R1 ;CONVERT NAME CALL $C5TA MOV N.FNAM+2(R4),R1 CALL $C5TA MOV N.FNAM+4(R4),R1 CALL $C5TA BACKNM: CMPB -(R0),#40 ;DO WE HAVE TO BACK UP OVER SPACES? BEQ BACKNM ;YES INC R0 ;NO, MOVE POINTER BACK MOVB #'.,(R0)+ ;INSERT '.' BETWEEN NAME & EXTENSION MOV N.FTYP(R4),R1 ;CONVERT EXTENSION CALL $C5TA BACKEX: CMPB -(R0),#40 ;BACK UP OVER SPACES IN EXTENSION? BEQ BACKEX INC R0 ;RESTORE R0 TO PAST LAST NON-SPACE CHAR. MOVB #';,(R0)+ ;INSERT SEMI-COLON SEPARATOR MOV N.FVER(R4),R1 ;CONVERT VERSION # CLR R2 ;ZERO-SUPPRESS FLAG ON CALL $CBOMG ;CONVERT TO OCTAL MOV #ASOF,R1 ;COPY 'AS OF' PART OF MESSAGE MOV #ASOFSZ,R2 CALL MBR1R0 MOV #TIMDAT,R1 ;SET ADDR. FOR SOURCE OF DATE & TIME INFO MOV #2,R2 ;COPY DAY CALL MBR1R0 MOVB #'-,(R0)+ ;INSERT '-' AS DELIMITER MOV #3,R2 CALL MBR1R0 ;COPY MONTH MOVB #'-,(R0)+ ;INSERT ANOTHER DELIMITER MOV #2,R2 ;COPY YEAR CALL MBR1R0 MOVB #40,(R0)+ ;INSERT A SPACE CALL MBR1R0 ;COPY HOUR MOVB #':,(R0)+ ;INSERT APPROPRIATE DELIMITER CALL MBR1R0 ;COPY MINUTES MOVB #':,(R0)+ ;AGAIN A DELIMITER CALL MBR1R0 ;COPY THE SECONDS TOO CALL INSBEN ;APPEND THE END STRING MOVB #12,(R0)+ ;APPEND A LF TO SEPARATE THE BANNER SUB #CHBUF,R0 ;CALC. LENGTH OF BANNER MESSAGE MOV R0,OUTQIO+Q.IOPL+2 ;SET INTO QIO DIR$ #OUTQIO ;DISPLAY NAME & TIME MOV (SP)+,R0 ;RESTORE R0 ;+ ; SELECT RECORD-TYPE PROCESSING (I.E. IMPLIED, IMBEDDED, FORTRAN C.C.) ;- CCTYP: MOV #CHBUF,OUTQIO+Q.IOPL ;INITIALIZE BUFFER LOCATION MOV #40,OUTQIO+Q.IOPL+4 ; AND FORMAT BITB #FD.CR,F.RATT(R0) ;SEE IF INPUT FILE IS IMPLIED BNE ATA ;IF YES, SKIP TO ATTACH W/ AST BITB #FD.FTN,F.RATT(R0) ;CHECK IF FORTRAN C.C. BEQ IMBED ;NO IF BIT OFF MOV #1,FTNFLG ;YES, SET FLAG INC OUTQIO+Q.IOPL ;BUMP POINTER PAST C.C. CHARACTER BR ATA ; & SKIP THE IMBEDDED C.C. CASE IMBED: CLRB OUTQIO+Q.IOPL+4 ;NO, CHANGE TO NO C.C. MOV #LF,ERRQIO+Q.IOPL ; & SEPARATE TEXT BY A LINEFEED MOV #1,ERRQIO+Q.IOPL+2 DIR$ #ERRQIO ATA: DIR$ #ASTQIO,OUTERR ;+ ; SET UP POSSIBLE TRUNCATE CONDITIONS ;- MOV CSIWD,R5 ;SET R5 TO CORRESPOND TO THE TRUNCATE SW. BIC #^CTRNFLG,R5 BEQ GETREC ;JUST OUTPUT BUFFER IF NO-TRUNCATE MOV OUTQIO+Q.IOPL,INADDR ;SAVE THE INPUT RECORD POINTER MOV #OUTBUF,OUTQIO+Q.IOPL ; & REPLACE IT W/ THE OUTPUT POINTER TST TRNSIZ ;HAS THE USER SPECIFIED A TRUNCATE WIDTH? BNE INICPY ;SKIP IF USER GAVE US A VALUE DIR$ #GLUN ; ELSE GET TERMINAL WIDTH MOV TIMDAT+G.LUCW+6,TRNSIZ DEC TRNSIZ ;REDUCE BY 1 FOR FUNNY TERMINALS THAT WRAP INICPY: MOV TRNSIZ,R3 ;GET THE SIZE TO TRUNCATE TO CLR LINCNT ;CLEAR COUNT OF CHARS PRINTED ON A LINE ;+ ; START COPYING INPUT RECORDS TO OUTPUT ;- GETREC: GET$ #INFDB,,,GETERR ;GET A RECORD MOV INFDB+F.NRBD,OUTQIO+Q.IOPL+2 ;RETRIEVE # OF BYTES READ TST FTNFLG ;DO WE HAVE FORTRAN C.C.? BEQ CHKOUT ;NO IF FLAG=0 MOVB CHBUF,OUTQIO+Q.IOPL+4 ;YES, MOVE C.C. CHAR TO QIO FIELD DEC OUTQIO+Q.IOPL+2 ; AND DECR. COUNT OF CHARS TO OUTPUT CHKOUT: TST R5 ;DO WE NEED TO TRUNCATE? BEQ DOOUT ;NO, GO OUTPUT THE INCOMING RECORD ;+ ; HANDLE LINE TRUNCATION ;- MOV OUTQIO+Q.IOPL+2,R4 ;GET THE TOTAL RECORD COUNT BEQ GETREC ;GET ANOTHER IN CASE COUNT WAS ZERO CLR OUTQIO+Q.IOPL+2 ;RESET THE COUNT TO ZERO MOV INADDR,R2 ;SET UP POINTER FOR INCOMING CHARS MOV #OUTBUF,R1 ; & AN OUTPUT POINTER TOO ; TSTCHR: CMPB (R2),#15 ;A CARRIAGE RETURN? BNE NOTCR ;NO MOV TRNSIZ,R3 ;YES, RESET TRUNCATE COUNT & CARRIAGE POSITION CLR LINCNT BR OKCHAR ;GO MOVE CHAR TO OUTPUT ; NOTCR: CMPB (R2),#10 ;A BACKSPACE? BNE NOTBS ;NO INC R3 ;YES, INC. AVAIL. SPACE DEC LINCNT ;AND MOVE CARR. POS. BACK 1 BGE OKCHAR ;GO COPY TO OUTPUT CLR LINCNT ;CAN'T GO BACK PAST BEGINNING OF LINE BR OKCHAR ; NOTBS: CMPB (R2),#11 ;A TAB? BNE NOTTAB ;NO MOV LINCNT,R0 ;YES, GET CARR. POSITION BIC #177770,R0 ;MAKE MODULO 8 SUB #8.,R0 ;NOW HAVE # SPACES TO INSERT FOR THE TAB ; (AS A NEGATIVE VALUE) SUB R0,LINCNT ;ADVANCE CARRIAGE POSITION ADD R0,R3 ;DO WE HAVE ROOM TO REALLY OUTPUT THE TAB? BLT SKPCHR ;NO, SKIP THIS ONE BR OKCHAR ;YES, TRANSFER TAB TO OUTPUT BUFFER ; NOTTAB: CMPB (R2),#31. ;A CONTROL CHAR? BLE OKCHAR ;YES, COPY IT SINCE WON'T MOVE CARRIAGE DEC R3 ;NO, SEE IF THERE'S ROOM FOR IT BLT SKPCHR ;NO ROOM, SKIP THIS ONE INC LINCNT ;YES, MOVE CARRIAGE OKCHAR: INC OUTQIO+Q.IOPL+2 ;COUNT IT FOR THE QIO MOVB (R2),(R1)+ ;COPY IT TO OUTPUT BUFFER SKPCHR: INC R2 ;ADVANCE THE INPUT POINTER (EVEN IF NOT ; COPYING IT TO OUTPUT BUFFER) DEC R4 ;DECR. COUNT OF REMAINING IN INPUT BUFFER BGT TSTCHR ;IF MORE, GO TEST ONE ; DOOUT: TST OUTQIO+Q.IOPL+2 ;MAKE SURE NON-ZERO BYTE COUNT BGT DOQIO MOV #1,OUTQIO+Q.IOPL+2 ;ELSE SET TO OUTPUT 1 NULL CHAR. MOV OUTQIO+Q.IOPL,-(SP) ;SAVE THE OLD BUFFER POINTER MOV #NULL,OUTQIO+Q.IOPL DIR$ #OUTQIO,OUTERR MOV (SP)+,OUTQIO+Q.IOPL ;RESTORE THE BUFFER POINTER BR TSTSTP ; & SKIP TO TEST FOR STOP OUTPUT DOQIO: DIR$ #OUTQIO,OUTERR TSTSTP: TST QUITCH ;DID THE USER TYPE A ^Z YET? BNE QUIT ;YES IF NON-ZERO TST R5 ;TRUNCATING IN PROGRESS? BEQ GETREC ;NO, GO GET ANOTHER RECORD TST OUTQIO+Q.IOPL+4 ;IMBEDDED C.C.? BEQ GETREC ;YES, JUST GET A NEW RECORD BR INICPY ;NO, GO RESET COUNTS FIRST ; QUIT: CLR QUITCH ;CLEAR QUIT FLAG FOR REUSE BR GETEOF ;PRETEND THAT WE HAVE AN EOF ; GETERR: TST (SP)+ ;REMOVE RETURN FROM STACK CMPB INFDB+F.ERR,#IE.EOF ;WAS ERROR AN EOF ON INPUT FILE? BEQ GETEOF ;YES IF EQ MOV #ERDMSG,ERRQIO+Q.IOPL ;NO, OUTPUT GENERAL ERROR MESSAGE MOV #ERDSIZ,ERRQIO+Q.IOPL+2 JMP ERRDIR GETEOF: DIR$ #DETQIO,OUTERR CLOSE$ #INFDB ;CLOSE INPUT FILE BEFORE PROCEEDING BITB #CS.MOR,CSI+C.STAT ;ANY MORE FILES ON CURRENT LINE? BEQ NOMORE ;IF NOT, GO GET NEW LINE (OR EXIT) JMP AGAIN ;YES, SO GO BACK FOR ANOTHER FILENAME NOMORE: JMP NEXT ;DO A JUMP TO GET BACK (BR WON'T REACH) ;+ ; HELP OUTPUT HERE ;- HELP: MOV #HELTXT,ERRQIO+Q.IOPL ;SET ADDR AND LENGTH MOV #HELSIZ,ERRQIO+Q.IOPL+2 DIR$ #ERRQIO ;DO IT BIC #HEFLG,CSIWD ;TURN OFF HELP REQUEST JMP NEXT ;GO GET ANOTHER COMMAND LINE IF NEEDED. ;+ ; *** AST ROUTINE FOR CHARACTER INPUT *** ;- ASTCHR: CMP (SP),#3 ;WE WILL ACCEPT ^C'S AS EXIT...IS THIS ONE? BEQ SETFLG ;YES, IF EQ CMP (SP),#32 ;WE WILL ALSO EXIT ON ^Z'S...IS THIS ONE? BNE ASTEXI ;NO IF NE (IGNORE IT) SETFLG: MOV #1,QUITCH ;YES. RAISE FLAG TO EXIT WHEN CONVENIENT ASTEXI: TST (SP)+ ;GET RID OF CHAR FROM STACK BEFORE EXIT ASTX$S ;EXIT FROM AST ;+ ; SUBROUTINE TO MOVE BEGIN/END MESSAGE TO (R0) ;- ; FALLS THROUGH TO MBR1R0 INSBEN: MOV #BENSIZ,R2 ;SET SIZE MOV #BEGEND,R1 ;SET STRING ADDR. ; ;+ ; SUBROUTINE TO MOVE CHARACTERS FROM (R1) TO (R0) ;- ; COUNT IS IN R2, RESTORED ON EXIT MBR1R0: MOV R2,-(SP) ;SAVE COUNT CPYCHR: MOVB (R1)+,(R0)+ ;COPY A CHARACTER SOB R2,CPYCHR ;COPY UNTIL COUNT IS ZERO MOV (SP)+,R2 ;RESTORE COUNT FOR ANOTHER USE RETURN ;THAT'S ALL THERE IS TO THIS ROUTINE ; .END TYPE