; Copyright (C) Reston Publishing Company, Inc. 1983 ; #start CheckDigit -------------------------------------------- ; ; CheckDigit: return the truth of whether HL-->a digit or not. ; preserves -- BC, DE, HL ; output -- Z set if HL-->Ascii digit "0".."9" ; Z false if not ; A contains the character ;--------------------------------------------------------------- CheckDigit: mov a,m cpi '0' ; eliminate the case of m<"0" rc cpi '9' ; eliminate the case of m = "9" rz cmc ; if carry set, m > "9" rc xra a ; m must be in "0".."8" ret ; #end CheckDigit ; #start CmpStrText ------------------------------------------- ; ; CmpStrText: DE addresses a string terminated by 00h. HL points ; to raw text. Compare the string, up to the 00h or the first ; inequality, to the text. Treat the text as uppercase. ; preserves : BC ; returns: flags set as for first inequality, or for equal ; A = 00h, or last HL byte compared ; DE, HL incremented to last bytes examined ; Note: when equality is returned, the HL byte is unknown. Call ; Delimiter immediately to see if it is a blank, CR, or other ; delimiter character. ;--------------------------------------------------------------- CmpStrText: push b CmpStrText1: ldax d ora a ; reached the terminator? JRZ CmpStrText2 ; ..exit if so mov b,a ; test bytes, mov a,m call UpperCase cmp b JRNZ CmpStrText2 ; ..exit if unequal inx d inx h JMPR CmpStrText1 ; CmpStrText2: pop b ret ; #start UpperCase -------------------------------------------- ; ; UpperCase: convert the byte in A from lowercase to uppercase. ; Be careful to convert only the letters a..z, not the specials ; that lie between 60h and 7Eh. ; preserves : BC, DE, HL ; returns: A = converted byte ;--------------------------------------------------------------- UpperCase: cpi 'a' rc cpi 'z'+1 rnc sui 'a'-'A' ret ; ; #end UpperCase ; #end CmpStrText ; #start CmpString --------------------------------------------- ; ; CmpString: DE and HL address two "strings," that is, strings ; of characters that terminate in 00h bytes. Compare them until ; an inequality is found or until the 00h bytes are reached. ; preserves -- BC ; returns -- DE, HL incremented ; machine flags set as for the last byte checked ; A = last DE byte checked ; ; Note: the comparison is DE :: HL. When the strings are equal ; up to the first 00h byte, the shorter string appears "less." ;--------------------------------------------------------------- CmpString: ldax d cmp m ; [DE] :: [HL] rnz ; exit at first difference ora a ; equality -- of terminators? rz ; yes, exit inx d inx h JMPR CmpString ; ; #end CmpString ; #start CopyString -------------------------------------------- ; CopyString: copy HL->string to DE->space. ; preserves -- all ; Note: unlike MoveHtoD, which this resembles, the D and H regs ; are preserved. That is because a string seems a unitary thing ; to be treated as a scalar value rather than as a series of ; bytes that would be part of a larger grouping. ;--------------------------------------------------------------- CopyString: push psw push d push h IF Z80CPU push b CopyString2: mov a,m db 0EDh,0A0h ; Z80 "LDI" instruction ora a JRNZ CopyString2 pop b ELSE CopyString2: mov a,m stax d inx d inx h ora a jnz CopyString2 ENDIF pop h pop d pop psw ret ; #end CopyString ; #start Delimiter -------------------------------------------- ; ; Delimiter: HL adresses a byte. Find out if it is one of the ; standard CP/M token delimiters. ; preserves : BC, DE, HL ; returns: Z flag true if byte is a delimiter ; A = the byte itself ; Note: the tests are made in descending order by ASCII value. ; Thus "rnc" returns if the byte is equal, or if it is greater ; and hence cannot possibly be one of the bytes tested later. ;--------------------------------------------------------------- Delimiter: mov a,m cpi ']' ; delimiters for option lists rnc cpi '[' rnc cpi '=' ; delimits filerefs in e.g. ren rnc cpi ';' ; delimits passwords (BDOS 3) rnc cpi '/' ; delimits optional parameters rnc cpi '.' ; delimits filetypes rnc cpi ',' ; delimits tokens (supposedly) rnc cpi ' ' ; only token delimiter that works rnc cmp a ; control character -- force Z true ret ; ; #end Delimiter ; #start SkipWhite -------------------------------------------- ; ; SkipWhite: HL adresses raw text. Advance it to a byte that is ; not whitespace (blank or tab). ; preserves -- BC, DE ; returns -- HL-->a non-white byte ; A = that byte ;--------------------------------------------------------------- SkipWhite: call WhiteSpace rnz inx h JMPR SkipWhite ; #start WhiteSpace -------------------------------------------- ; ; WhiteSpace: HL addresses a byte. Return the Z flag true if ; that byte is a blank or a tab. ; preserves -- BC, DE, HL ; returns -- A = the byte ; Z flag set ;--------------------------------------------------------------- WhiteSpace: mov a,m cpi AsciiBlank rnc ; return -- blank or anyway not tab cpi AsciiTAB ret ; #end WhiteSpace ; #end SkipWhite ; #start StringLength ------------------------------------------ ; StringLength: HL addresses a string terminated by 00h. Return ; the length of the string (excluding the terminator) in A. ; preserves -- BC, DE, HL ; returns -- A has string length ; Note: obviously, a string over 255 bytes will cause an error. ;--------------------------------------------------------------- StringLength: push b push h mvi b,0 JMPR StringLength1 ; StringLength2: inr b inx h StringLength1: mov a,m ora a JRNZ StringLength2 ; mov a,b pop h pop b ret ; #end StringLength ; #start FillZero (includes FillA, MoveHtoD) ------------------- ; ; FillZero: replicate 00h, beginning at DE, for BC bytes ;--------------------------------------------------------------- FillZero: push psw xra a jmp FillX ; #start FillA (includes MoveHtoD) ----------------------------- ; ; FillA: replicate the byte in A, beginning at DE, for BC bytes. ; If the length is 2 or greater, use MoveHtoD to do the work. If ; the length is 1, that won't work. ; preserves -- A, BC, HL ; returns -- DE advanced by BC ;--------------------------------------------------------------- FillA: push psw FillX:; FillZero joins here. push h stax d ; fill one byte inx d ; ..step, dcx b ; ..count the one. mov h,a ; save fill byte mov a,b ; guard against case of BC=0001 ora c JRZ FillZ mov a,h ; recover fill byte mov h,d ; create address of fill data mov l,e ; ..in storage dcx h ; HL-->first byte, DE-->second call MoveHtoD; do propogation-move FillZ: inx b ; restore entry value of b pop h pop psw ret ; #start MoveHtoD ---------------------------------------------- ; MoveHtoD is a software simulation of the Z80 LDIR instruction. ; It does [HL++] --> [DE++] for BC times. BC must be 1 or more. ; Unlike the Z80, however, BC is preserved. That is handy for ; repetitive use of the routine. ;--------------------------------------------------------------- MoveHtoD: push b IF Z80CPU db 0EDh,0B0h ; a z80 instruction ELSE push psw MoveHD1: mov a,m stax d inx h inx d dcx b mov a,b ora c jnz MoveHD1 pop psw ENDIF pop b ret ; #end MoveHtoD ; #end FillA ; #end FillZero ; #start ScanForA --------------------------------------------- ; ; ScanForA: scan BC bytes of HL-->text, looking for a match to ; the byte in A. Return BC and HL updated, and the Z flag true ; if a match is found or false if it is not. ; ; input -- HL-->text ; BC = count of bytes to scan (0000h means 65536) ; A = the byte to search for ; ; preserves -- A, DE ; returns -- HL incremented from 1 to BC bytes (HL points to ; the byte after the match, or to the byte after ; the scanned field if no match was found). ; BC decremented by at least 1 (BC decremented to ; zero if no match was found). ; Z flag true if a match was found. ; ; Note: this is a simulation of the Z80 "CPIR" instruction, with ; the exception that when the 8080 code is generated, the Parity ; flag is not set. Note also that input of BC=0000 will cause a ; scan of all of storage. ;--------------------------------------------------------------- ScanForA: IF NOT Z80CPU cmp m ; set flags for A :: M[HL] inx h ; and increment HL, dcx b ; decrement BC, regardless rz ; exit on a match push psw ; otherwise test for BC=0000 mov a,b ora c jz ScanForA2 pop psw jmp ScanForA ; and continue if BC>0 ScanForA2: pop psw ; restore A, Z from comparison ret ELSE db 0EDh,0B1h ; the real thing ret ENDIF ; #end ScanForA