.title k11sub common subroutines for all execs .ident /8.0.01/ ; Brian Nelson 01-Dec-83 13:19:14 ; ; Copyright (C) 1983 Change Software, Inc. ; ; ; This software is furnished under a license and may ; be used and copied only in accordance with the ; terms of such license and with the inclusion of ; the above copyright notice. This software or any ; other copies thereof may not be provided or other- ; wise made available to any other person. No title ; to and ownership of the software is hereby trans- ; ferred. ; ; The information in this software is subject to ; change without notice and should not be construed ; as a commitment by the author. ; define macros and things we want for KERMIT-11 .include /IN:K11MAC.MAC/ .iif ndf, k11inc, .error ; INCLUDE for IN:K11MAC.MAC failed .psect $code .enabl gbl .sbttl cvt$$ basic+ cvt$$ function .enabl lsb ; calls cvt$$ , ; ; returns @ addr(input) trimmed string ; r0 length of whats left ; ; MASK TRIMS ; ---- ----- ; ; 1 DISCARD ALL PARITY BITS ; 2 DISCARD ALL SPACES & TABS ; 4 DISCARD CR LF FF ESC RO ; 10 DISCARD LEADING SPACES & TABS ; 20 REDUCE SPACES & TABS TO A SINGLE SPACE ; 40 CONVERT LC TO UC ; 100 CONVERT [ TO ( AND ] TO ) ; 200 DISCARD TRAILING SPACES & TABS ; 400 PRESERVE QUOTED SUBSTRINGS ; 1000 MODIFY 4 (IF ON) TO DISCARD ALL CHARACTERS < 40 OR =177 ; c.par = 1 c.spac = 2 c.crlf = 4 c.lspa = 10 c.sspa = 20 c.lcuc = 40 c.brac = 100 c.tspa = 200 c.quot = 400 c.prt = 1000 .asect . = 0 pat: .blkw 1 inquo: .blkw 1 lastch: .blkw 1 saddr: .blkw 1 lsize = . + 2 .psect .psect $code .sbttl the real work of cvt$$ edit$:: cvt$$:: save ; the scratch registers to use. sub #lsize ,sp ; allocate some work space mov sp ,r4 ; point to a local work area mov (r5)+ ,r2 ; the string address for output mov r2 ,saddr(r4) ; and save it for a while mov (r5)+ ,r1 ; get the string length also. mov (r5)+ ,pat(r4) ; and finally the bit pattern. clr inquo(r4) ; assume not in a quoted string. clrb lastch(r4) ; no previous character please. mov r2 ,r5 ; where to get the input string tst r1 ; the length beq 130$ ; nothing to do 10$: clr r3 ; avoind the movb sxt please. bisb (r5)+ ,r3 ; get the next character . tstb inquo(r4) ; currently in quoted string? bne usech ; yes, skip all this junk. bit #c.par ,pat(r4) ; Do we trim off the parity ? beq 20$ bicb #200 ,r3 ; yes. clear bit number 7 20$: bit #c.spac!c.lspa,pat(r4) ; How about removing spaces & bne 25$ ; tabs. if ne, yes bit #c.sspa ,pat(r4) ; reduce imbedded ones to beq 30$ ; a single tab/space ? cmpb r3 ,#11 ; yes. if ch eq tab, then make bne 21$ ; it into a space first please. movb #40 ,r3 ; simple 21$: cmpb lastch(r4),#40 ; yes, was the last ch a space beq 25$ ; or a tab ? cmpb lastch(r4),#11 ; please check both out bne 30$ ; no 25$: cmpb r3 ,#40 ; is the current character a beq skipch ; space ? cmpb r3 ,#9. ; not a space. try a horz tab beq skipch ; char was a tab. Then ignore. bic #c.lspa ,pat(r4) ; For leading spaces and tabs. 30$: bit #c.crlf ,pat(r4) ; try for ignoring form feed, beq 50$ ; car ret,line feed,esc,null. mov #junkch ,r0 ; Get the address of the spec tstb r3 ; is the current ch a null ? beq skipch ; yes, please skip it then. 40$: tstb @r0 ; anything left in the list ? beq 50$ ; no cmpb r3 ,(r0)+ ; see if we have a match. If beq skipch ; so, we will skip the char. br 40$ ; no, next check please 50$: bit #c.lcuc ,pat(r4) ; how about converting lower beq 60$ ; case to upper case ? cmpb r3 ,#'z!40 ; try against a lower case Z bhi 60$ cmpb r3 ,#'a!40 ; if less than a lower z,try blo 60$ ; for ge a lower case a bicb #40 ,r3 ; char is in range. translate 60$: bit #c.brac ,pat(r4) ; how about convert [ to ( and beq usech ; and convert ] to ) cmpb r3 ,#'[ ; and so on bne 70$ movb #'( ,r3 ; convert it. fall thru to next 70$: cmpb r3 ,#'] bne usech movb #') ,r3 br usech skipch: br 120$ ; do not want the char, skip it. .sbttl got a good ch, check for quoted string things usech: bit #c.quot ,pat(r4) ; what about leaving quoted beq 110$ ; strings alone ? tstb inquo(r4) ; currently in a quoted string? bne 90$ ; yes, check for the stopper. cmpb r3 ,#'' ; a quote here ? beq 80$ ; yes cmpb r3 ,#'" ; alternate for a quote bne 90$ ; no 80$: movb r3 ,inquo(r4) ; yes, save the terminator br 110$ ; next please 90$: cmpb r3 ,inquo(r4) ; yes, is this the end of a bne 110$ ; quoted string ? clrb inquo(r4) ; yes, turn the flag off then. 110$: bit #c.prt ,pat(r4) ; should we skip nonprintable beq 115$ ; characters now ? cmpb r3 ,#40 ; yes, less than a space blo 120$ ; yes tstb r3 ; greater than 177 (rubout) bmi 120$ ; yes 115$: movb r3 ,(r2)+ ; if all ok, return the char. 120$: movb r3 ,lastch(r4) ; please save the last ch dec r1 ; and go back for some more. bgt 10$ ; next please 130$: mov r2 ,r0 ; current pointer sub saddr(r4),r0 ; return the length of what's ble 160$ ; nothing left to do then. bit #c.tspa ,pat(r4) ; remove trailing blanks ? beq 160$ ; no mov saddr(r4),r1 ; address of the string. add r0 ,r1 ; point to end of string+1. 140$: cmpb -(r1) ,#40 ; Try for a space first. beq 150$ cmpb (r1) ,#9. ; Not a space, try a tab. bne 160$ 150$: sob r0 ,140$ ; Tab or space. Check next 160$: 170$: add #lsize ,sp ; pop small work area unsave ; pop all temps return ; and exit junkch: .byte 13.,10.,12.,27.,0,0 .dsabl lsb .sbttl l$len get length of .asciz string ; L $ L E N ; ; input: r0 = address of .asciz string ; output: r0 = length of it l$len:: mov r0 ,-(sp) ; save it for later. 10$: tstb (r0)+ ; look for a null character. bne 10$ ; keep going sub (sp)+ ,r0 ; subtract start address from dec r0 ; current pointer less 1. return .sbttl write decimal l$wrdec:: dfwidth = 6 ; ; write a decimal number to KB: passed at 0(r5) ; ; save mov 2(r5) ,r1 ; field width bgt 10$ ; good positive value. beq 5$ ; zero, make it 6. neg r1 ; negative means no space fill br 10$ ; and skip this 5$: mov #dfwidth,r1 ; finally, we have the width. 10$: mov r1 ,r4 ; save for a moment add #5 ,r1 ; make it round up to even num. bic #1 ,r1 ; at last.... mov 2(r5) ,-(sp) ; The real field width please. mov @r5 ,-(sp) ; And the number to print out. mov sp ,r5 ; setup the parameter list addr tst -(r5) ; make room for the buffer on sub r1 ,sp ; the stack. mov sp ,@r5 ; insert the buffer address call l$cvtnum ; and convert the number. .print @r5 ,r4 ; and print it out add r1 ,sp ; and fix the stack up. cmp (sp)+ ,(sp)+ ; rest of stack pop. unsave ; thats all for now return ; write out a decimal number at 2(r5) into the buffer ; address passed at 0(r5). All registers saved. l$cvti::save ; call common conversion sub. clr -(sp) ; setup paramter list first. mov 2(r5) ,-(sp) ; calls $cvtnum,<@r5,2(r5),#0> mov @r5 ,-(sp) ; finally the buffer address. mov sp ,r5 ; the parameter list address. call l$cvtnum ; convert it please. add #6 ,sp ; pop stack parameter list. unsave ; restore r5 return ; and exit please. .sbttl the real conversion sub ; input: 0(r5) = buffer address ; 2(r5) = value to print ; 4(r5) = field width ( > 0 ->right, < 0 -> left ) ; ; field width: if < zero, string will be left justified ; if > zero, string will be right justified ; if = zero, field will be set to 6. ; l$cvtnum:: save ; some scratch registers saved mov (r5) ,r2 ; the buffer address to use. mov 4(r5) ,r3 ; the field width to use. bgt 80$ ; nonzero, it is ok (?) beq 70$ ; zero neg r3 ; < 0 br 80$ 70$: mov #dfwidth,r3 ; zero, use default width 6. 80$: mov r3 ,r1 ; put it here to clear buffer. 1$: movb #32. ,(r2)+ ; fill the buffer with blanks sob r1 ,1$ mov r2 ,-(sp) ; save end of buffer here. mov r3 ,r4 ; save buffer size also. mov 2(r5) ,r1 ; Get the value to print out. bpl 2$ neg r1 2$: clr r0 ; set up for the divide by 10. div #10. ,r0 ; remainder in r1, quotient r0 add #'0 ,r1 ; convert remainder to character cmp r2 ,@r5 ; overflowed the buffer at all? beq 100$ ; yes, get out of here ! movb r1 ,-(r2) ; and return the character now. mov r0 ,r1 beq 3$ sob r3 ,2$ ; go back for more tst r1 ; something left over by chance? bne 100$ ; Yes, that's a definite error. 3$: tst 2(r5) ; was this a negative number ? bpl 90$ ; no, exit cmp r2 ,@r5 ; yes, room left for a '-' sym. beq 100$ ; no, flag an error please. movb #'- ,-(r2) ; yes, insert a minus symbol. ;; br 90$ ; thats all. 90$: tst 4(r5) ; negative field width ? bpl 4$ ; no, exit. mov @r5 ,r1 ; start of the buffer here. 95$: movb (r2)+ ,(r1)+ ; move chars to front of buffer. cmp r2 ,(sp) ; end of the buffer yet ? bhis 97$ ; no, keep going please. sob r4 ,95$ ; keep going please 97$: dec r4 ; anything left to zero out? ble 4$ ; no 98$: movb #40 ,(r1)+ ; yes, zero to end of buffer. sob r4 ,98$ ; more please br 4$ ; finally exit this mess. 100$: movb #'* ,@r2 ; field overlfow. place '*' in ; beginning of the buffer. 4$: tst (sp)+ ; pop stack, restore temp regs unsave return ; thats all there is to it. .sbttl mout print text from message macro locmout:: tst remote beq mout mov (sp)+ ,@sp return mout:: save mov 4(sp) ,r0 .print r0 unsave mov (sp)+ ,@sp return .sbttl instr ; I N S T R simple (non-wildcard) version ; input: ; ; (r5) = address of the first string ; 2(r5) = length of the first string . ; 4(r5) = address of the second string, the one to find. ; 6(r5) = length of the second string. ; ; output: ; ; r0 = if > 0 then r0=position of second in first ; else the second is not a substring. ; instr:: save ; we use these here, so save. mov (r5) ,r0 ; the address of first string mov 4(r5) ,r1 ; the address of second one. mov 6(r5) ,r2 ; the length of second one. ble 6$ ; a null string ? mov 2(r5) ,r4 ; the length of first. ble 6$ ; a null string ? sub r2 ,r4 ; convert to looping counter clr r3 ; the real loop counter. 1$: cmp r3 ,r4 ; are we done yet ? bgt 6$ ; yes, if r3 > r4 . cmpb (r0)+ ,(r1) ; see if current character in bne 5$ ; matches first one in second. save ; found first character match. inc r1 ; point to the next character dec r2 ; length of pattern thats left ble 3$ ; in case the len( pattern ) =1 2$: cmpb (r0)+ , (r1)+ ; check the rest of the pattern bne 4$ sob r2 ,2$ ; loop for len( pattern ) - 1 3$: mov r3 ,r0 ; the current loop count inc r0 add #6 ,sp ; fix the stack from save < > br 7$ 4$: unsave ; the match failed. restore the 5$: inc r3 ; pointers and go try the next br 1$ ; character in the first string 6$: clr r0 ; complete failure if get here 7$: unsave ; restore the registers we used return ; and go away. .sbttl convert rad50 word to 3 ascii bytes and back ;rdtoa ; (r5) = address of where to put ascii chars ; input 2(r5) = the value of rad 50 word ; ; ; ;procedure rd_toa( rval: integer ; var aout: array [1..3] of char ) ; ; ; type rlist = array [0..39] of char ; ; const ; r50ch = rlist(' ','A','B','C','D','E','F','G','H','I','J','K', ; 'L','M','N','O','P','Q','R','S','T','U','V','W', ; 'X','Y','Z','$','.','?','0','1','2','3','4','5', ; '6','7','8','9' ); ; var i: integer ; ; begin ; aout[1] := r50ch[ rval div 3100B ]; rval := rval mod 3100B ; ; aout[2] := r50ch[ rval div 50B ] ; aout[3] := r50ch[ rval mod 50B ] ; end ; rdtoa:: radasc: save ; same some registers mov 2(r5) ,r1 ; go get the rad50 character. mov (r5) ,r3 ; where to put the characters. com: clr r0 ; prepare for divide div #3100 ,r0 ; get first char movb radchr(r0),(r3)+ ; put in buffer clr r0 ; another divide div #50 ,r0 ; this one gives char 2 movb radchr(r0),(r3)+ ; put this in buffer movb radchr(r1),(r3)+ ; and also char 3 unsave ; restore the registers we used. return ; bye .nlist bex radchr: .ascii / ABCDEFGHIJKLMNOPQRSTUVWXYZ$.?0123456789:/ .list bex .even .sbttl get decimal number value ; L $ V A L (20-Nov-80) ; ; (r5) = address of .asciz string to convert ; ; r0 = error (-1 for bad number) ; r1 == binary value of the string. l$val:: save clr r1 ; initailize the result. mov (r5) ,r3 ; the address of the string. clr -(sp) ; a positive number for now. clr r0 30$: tstb @r3 ; null. If so, exit please. beq 5$ ; buy. cmpb @r3 ,#space ; we will ignore spaces. beq 50$ ; if equal, then skip. tst r0 ; past the first space yet ? bne 40$ ; yes, skip sign checks. com r0 ; past all the leading spaces. cmpb @r3 ,#'+ ; positive number ? beq 50$ ; yes, skip over the character. cmpb @r3 ,#'- ; negative ? bne 40$ ; no, try for a digit then. mov sp ,(sp) ; neg, set a useful flag up. br 50$ ; and skip it. 40$: cmpb @r3 ,#'0 ; try comparing to '0' . blo 70$ ; not a digit. time to go cmpb @r3 ,#'9 ; try comparing to '9' . bhi 70$ ; not a digit . get out. clr -(sp) ; clr out the scratch reg. bisb @r3 ,(sp) ; copy the character over. sub #48. ,(sp) ; convert char to a digit. mul #10. ,r1 ; multiply accum by 10 first bcs 60$ ; oops add (sp)+ ,r1 ; add on the digit to accum bvs 70$ ; bye 50$: inc r3 ; pointer := succ( pointer ); br 30$ 60$: tst (sp)+ ; came here from multiply overf 70$: clr r0 ; return 0 in case of error. mov #-1 ,r0 ; ?Illegal number tst (sp)+ ; pop sign flag from stack. br 100$ 5$: tst (sp)+ ; pop sign flag on tos. beq 95$ ; positive number ? tst r1 ; negative 0 (-32768) ? bne 90$ ; no bis #100000 ,r1 ; yes, set only the sign bit br 95$ ; and go away. 90$: neg r1 ; no. 95$: clr r0 100$: unsave return ; and time to leave. .sbttl octval return octal vaule in r1, error in r0 octval::save ; save temps please clr r0 ; assume no error clr r1 ; value := 0 mov @r5 ,r2 ; get the buffer address 10$: movb (r2)+ ,r3 ; get the next character please beq 100$ ; all done cmpb r3 ,#'0 ; error if < '0' or > '7' blo 90$ ; oops cmpb r3 ,#'7 ; how about the upper limit bhi 90$ ; oops sub #'0 ,r3 ; get the value asl r1 ; accumulated value times 8 asl r1 ; the long way asl r1 ; r1 = r1 * 8 add r3 ,r1 ; add in the current digit br 10$ ; next 90$: mov #-1 ,r0 ; illegal number 100$: unsave ; pop registers and exit return .sbttl binary to octal conversion ; ; 17-Nov-80 BDN ; ; convert binary number at 2(r5) to ascii string ; at buffer address 0(r5). ; l$otoa::save ; save the scratch regs. mov (r5) ,r2 mov 2(r5) ,r3 add #6 ,r2 ; do it backwards mov #6 ,r0 ; do it 6 times 10$: mov r3 ,r1 ; get the number bic #177770 ,r1 ; leave low order 3 bits on movb 200$(r1),-(r2) ; move an octal digit ash #-3 ,r3 ; shift three bytes bic #160000 ,r3 ; zap propagated sign bits sob r0 ,10$ ; go convert next digit unsave return 200$: .ascii \01234567\ ; ascii/octal 200$ .even ; (r5) = value to write to KB: l$wroc::save sub #10 ,sp mov sp ,r0 ; use stack for a buffer calls l$otoa , print r0 ,#6. add #10 ,sp unsave return .sbttl copyz copyz .asciz string ; C O P Y Z $ ; ; input: 6(sp) max len or zero ; 4(sp) source string address ; 2(sp) destination string address ; ; usage: copyz macro, as in copyz #oldfile,#newfile copyz$::save ; save registers we may use tst 4+6(sp) ; see if a maxlen was passed bne 5$ ; yes mov #77777 ,4+6(sp) ; no, say we can have MAXINT chars 5$: mov 4+4(sp) ,r0 ; source string address mov 4+2(sp) ,r1 ; destination string address 10$: movb (r0)+ ,(r1)+ ; copy a byte beq 20$ ; until a null is found dec 4+6(sp) ; or we have copied MAXLEN number bne 10$ ; of characters over 20$: clrb -(r1) ; insure output .asciz please unsave ; pop temps mov @sp ,6(sp) ; move return address up add #6 ,sp ; fix the stack return ; and exit .sbttl formatted byte dump ; input: 4(sp) size ; 2(sp) address dump$b::save ; save all please mov <4+6>(sp),r1 ; size beq 100$ ; nothing do to today mov <2+6>(sp),r2 ; address to dump 10$: clr r0 ; get the next byte please bisb (r2)+ ,r0 ; get it decout r0 ; and print it sob r1 ,10$ ; next please 100$: .newline ; a cr/lf unsave ; pop all registers we used mov @sp ,4(sp) ; move return address up cmp (sp)+ ,(sp)+ ; pop two words for parameter list return ; and exit .sbttl strcat and strcpy ; input: ; 0(sp) return address ; 2(sp) dst address ; 4(sp) src address ; output: r0 dest address strcpy::save ; save temp registers please mov 2+2(sp) ,r0 ; destination address mov 2+4(sp) ,r1 ; source .asciz address 10$: movb (r1)+ ,(r0)+ ; copy until a null bne 10$ ; not done mov 2+2(sp) ,r0 ; return the dst address unsave ; pop r1 and exit mov (sp) ,4(sp) ; move return address up now cmp (sp)+ ,(sp)+ ; pop junk and exit return strcat::save ; save temp registers please mov 2+2(sp) ,r0 ; destination address mov 2+4(sp) ,r1 ; source .asciz address 5$: tstb (r0)+ ; look for the end of the dst string bne 5$ ; not found yet dec r0 ; found it, fix the pointer 10$: movb (r1)+ ,(r0)+ ; copy until a null bne 10$ ; not done mov 2+2(sp) ,r0 ; return the dst address unsave ; pop r1 and exit mov (sp) ,4(sp) ; move return address up now cmp (sp)+ ,(sp)+ ; pop junk and exit return strcmp::mov 2(sp),r0 ;Pick up 'a' mov 4(sp),r1 ;And 'b' 10$: cmpb (r0)+,(r1) ;Are they the same bne 20$ ;No tstb (r1)+ ;At the end of the string bne 10$ ;No clr r0 ;Equal return br 100$ 20$: blo 30$ ;Br if ab return br 100$ 30$: mov #-1,r0 ;A