; ============================================================================= ; ; Litos8 text string utility ; ; ============================================================================= ; Text strings are allocated using MemAlloc function. ; ----------------------------------------------------------------------------- ; Exported user functions (109): ; Misc (10): ; CharHexToBin - convert ASCII HEX character to a number ; CharDecToBin - convert ASCII decimal character to a number ; IsDigit - check digit character ; IsAlpha - check alpha character ; UpperCase - convert to uppercase letter ; LowerCase - convert to lowercase letter ; UpperLowerCase - convert uppercase/lowercase letter ; UpperCaseNat - convert to uppercase letter with national ; LowerCaseNat - convert to lowercase letter with national ; UpperLowerCaseNat - convert uppercase/lowercase letter with national ; Text managing (6): ; TextZLength - get length of ASCIIZ string ; TextLength - get length of text string ; TextCheckInx - check if character index is valid ; TextDup - duplicate text string ; TextFree - delete text string ; TextResize - resize text string ; New (4): ; TextNew - allocate new text string ; TextNewEmpty - allocate new empty text string ; TextNewZ - create text string from ASCIIZ text ; TextNewBuf - create text string from buffer ; Get/set character (4): ; TextGetChar - get character from text ; TextSetChar - set character in text ; TextGetFirst - get first character from text ; TextGetLast - get last character from text ; Add text/character (11): ; TextAddText - add text string to end of text ; TextAddBuf - add text string from buffer to end of text ; TextAddTextZ - add ASCIIZ text to end of text ; TextAddChar - add character to end of text ; TextAddSpc - add space character to end of text ; TextAddMinus - add minus character to end of text ; TextAddNewLine - add new line CR/LF to end of text ; TextAddDate - add date to end of text ; TextAddTime - add time to end of text ; TextAddDiskSize - add disk size ; TextAddPathSep - add path separator ; Number (15): ; TextAddDig - add one digit character to end of text ; TextAdd2Dig - add two digit characters to end of text ; TextAdd2DigSpc - add two digit characters with space to end of text ; TextAddByte - add unsigned byte number to end of text ; TextAddWord - add unsigned word number to end of text ; TextAddDWord - add unsigned dword number to end of text ; TextAddSByte - add signed byte number to end of text ; TextAddSWord - add signed word number to end of text ; TextAddSDWord - add signed dword number to end of text ; TextAddHByte - add HEX byte to end of text ; TextAddHWord - add HEX word to end of text ; TextAddHDWord - add HEX dword to end of text ; TextAddBByte - add BIN byte to end of text ; TextAddBWord - add BIN word to end of text ; TextAddBDWord - add BIN dword to end of text ; Delete (6): ; TextDel - delete part of text ; TextDelStart - delete start of text ; TextDelFrom - delete rest of text from given position ; TextDelEnd - delete end of text ; TextDelChar - delete one character from text ; TextDelPathSep - delete end path separator ; Extract text (4): ; TextLeft - get left part of text ; TextRight - get right part of text ; TextFrom - get text from given position ; TextMid - get middle part of text ; Conversions (7): ; TextUpper - convert text to uppercase letters ; TextLower - convert text to lowercase letters ; TextUpLow - change uppercase/lowercase letters ; TextUpperNat - convert text to uppercase letters with national chars ; TextLowerNat - convert text to lowercase letters with national chars ; TextUpLowNat - change uppercase/lowercase letters with national chars ; TextCapital - capitalize words ; Compare (2): ; TextEqu - compare text strings to equality ; TextComp - compare text strings alphabeticaly ; Trim text (6): ; TextTrimLeft - trim text from left ; TextTrimRight - trim text from right ; TextTrim - trim text from left and right ; TextTrimMid - trim from the text ; TextTrimList - trim text using list of forbidden characters ; TextTrimUnlist - trim text using list of allowed characters ; Search (33): ; TextFindChFirst - find first character in text ; TextFindChNext - find next character in text ; TextFindChLast - find last character in text ; TextFindChPrev - find previous character in text ; TextFind2ChFirst - find first two characters in text ; TextFind2ChNext - find next two characters in text ; TextFind2ChLast - find last two characters in text ; TextFind2ChPrev - find previous two characters in text ; TextFindFirst - find first string in text ; TextFindNext - find next string in text ; TextFindLast - find last string in text ; TextFindPrev - find previous string in text ; TextFindListFirst - find first character from list in text ; TextFindListNext - find next character from list in text ; TextFindUnlistFirst - find first character not in list in text ; TextFindUnlistNext - find next character not in list in text ; TextFindListLast - find last character from list in text ; TextFindListPrev - find previous character from list in text ; TextFindUnlistLast - find last character not in list in text ; TextFindUnlistPrev - find previous character not in list in text ; TextFind2ListFirst - find first character from 2-character list ; TextFind2ListNext - find next character from 2-character list ; TextFind3ListFirst - find first character from 3-character list ; TextFind3ListNext - find next character from 3-character list ; TextFind4ListFirst - find first character from 4-character list ; TextFind4ListNext - find next character from 4-character list ; TextFind2ListLast - find last character from 2-character list ; TextFind2ListPrev - find previous character from 2-character list ; TextFind3ListLast - find last character from 3-character list ; TextFind3ListPrev - find previous character from 3-character list ; TextFind4ListLast - find last character from 4-character list ; TextFind4ListPrev - find previous character from 4-character list ; TextSubstCh - substitute character ; Parse (1): ; ParseInt - get unsigned number from text ; ----------------------------------------------------------------------------- CODE_SECTION ; ----------------------------------------------------------------------------- ; Convert ASCII HEX character to a number ; ----------------------------------------------------------------------------- ; INPUT: AL = HEX character ("0" to "9", "A" to "F" or "a" to "f") ; OUTPUT: AL = number 0 to 15 (if NC) or AL not changed (if CY) ; CY = invalid HEX character (AL not changed) ; ----------------------------------------------------------------------------- ; ------------- check digit CharHexToBin: cmp al,"0" ; check number MIN jb short CharHexToBin9 ; invalid character cmp al,"9" ; check number MAX jbe short CharHexToBin7 ; character is OK ; ------------- check capital letter cmp al,"A" ; check letter MIN jb short CharHexToBin9 ; invalid character cmp al,"F" ; check letter MAX jbe short CharHexToBin6 ; character is OK ; ------------- check small letter cmp al,"a" ; check letter MIN jb short CharHexToBin9 ; invalid character cmp al,"f" ; check letter MAX ja short CharHexToBin8 ; invalid character ; ------------- convert small letter to BIN (it clears CF) sub al,"0"+("a"-("9"+1)) ; convert ASCII to BIN ret ; here is NC ; ------------- convert capital letter to BIN (it clears CF) CharHexToBin6: sub al,"0"+("A"-("9"+1)) ; convert ASCII to BIN ret ; here is NC ; ------------- convert ASCII digit to BIN (it clears CF) CharHexToBin7: sub al,"0" ; convert ASCII to BIN ret ; here is NC ; ------------- invalid HEX character CharHexToBin8: stc ; set error flag CharHexToBin9: ret ; ----------------------------------------------------------------------------- ; Convert ASCII decimal character to a number ; ----------------------------------------------------------------------------- ; INPUT: AL = ASCII decimal character ("0" to "9") ; OUTPUT: AL = number 0 to 9 (if NC) or AL not changed (if CY) ; CY = invalid decimal character (AL not changed) ; ----------------------------------------------------------------------------- ; ------------- check digit CharDecToBin: cmp al,"0" ; check number MIN jb short CharDecToBin9 ; invalid character cmp al,"9" ; check number MAX ja short CharDecToBin8 ; invalid character ; ------------- convert ASCII digit to BIN (it clears CF) sub al,"0" ; convert ASCII to BIN ret ; here is NC ; ------------- invalid HEX character CharDecToBin8: stc ; set error flag CharDecToBin9: ret ; ----------------------------------------------------------------------------- ; Check if character is digit character (0..9) ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: CY = not digit character ; ----------------------------------------------------------------------------- IsDigit: cmp al,"0" ; is it digit character? jb short IsDigit8 ; not digit character cmp al,"9"+1 ; is it digit character? cmc ; CY = not digit character IsDigit8: ret ; ----------------------------------------------------------------------------- ; Check if character is alpha character (A..Z, a..z) ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: CY = not alpha character ; ----------------------------------------------------------------------------- IsAlpha: cmp al,"A" ; is it capital alpha character? jb short IsAlpha8 ; not alpha character cmp al,"Z"+1 ; is it capital alpha character? jb short IsAlpha6 ; it is capital alpha character cmp al,"a" ; is lower alpha character? jb short IsAlpha8 ; not alpha character cmp al,"z"+1 ; is it lower alpha character? IsAlpha6: cmc ; CY = not alpha character IsAlpha8: ret ; ----------------------------------------------------------------------------- ; Convert to uppercase letter (a..z -> A..Z) ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = uppercase letter (not national characters) ; CY = not converted (not lowercase letter) ; ----------------------------------------------------------------------------- UpperCase: cmp al,"a" ; is lower alpha character? jb short UpperLowerCase8 ; not lower alpha character cmp al,"z" ; is it lower alpha character? ja short UpperLowerCase8 ; not lower alpha character UpperCase2: sub al,"a"-"A" ; convert to uppercase ret ; here is NC flag ; ----------------------------------------------------------------------------- ; Convert to lowercase letter (A..Z -> a..z) ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = lowercase letter (not national characters) ; CY = not converted (not lowercase letter) ; ----------------------------------------------------------------------------- LowerCase: cmp al,"A" ; is upper alpha character? jb short UpperLowerCase8 ; not upper alpha character cmp al,"Z" ; is it upper alpha character? ja short UpperLowerCase8 ; not upper alpha character LowerCase2: add al,"a"-"A" ; convert to lowercase ret ; here is NC flag ; ----------------------------------------------------------------------------- ; Convert lowercase/uppercase letter (A..Z -> a..z, a..z -> A..Z) ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = changed letter (not national characters) ; CY = not converted (not letter) ; ----------------------------------------------------------------------------- UpperLowerCase: cmp al,"A" ; is upper alpha character? jb short UpperLowerCase8 ; not upper alpha character cmp al,"Z" ; is it upper alpha character? jbe short LowerCase2 ; upper alpha character, convert cmp al,"a" ; is lower alpha character? jb short UpperLowerCase8 ; not lower alpha character cmp al,"z" ; is it lower alpha character? jbe short UpperCase2 ; lower alpha character, convert UpperLowerCase8:stc ; CY not valid letter ret ; ----------------------------------------------------------------------------- ; Convert to uppercase letter with national characters ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = uppercase letter ; CY = not converted (not letter) ; ----------------------------------------------------------------------------- ; ------------- convert base ASCII characters UpperCaseNat: call UpperCase ; convert ASCII characters jnc short UpperCaseNat9 ; character converted OK ; ------------- push registers push bx ; push BX push cx ; push CX ; ------------- get characters from table -> CX mov bx,[KeyMapLowUp] ; BX <- conversion table UpperCaseNat2: mov cx,[bx] ; CL <- lower, CH <- upper stc ; preset CY error flag jcxz UpperCaseNat8 ; end of table ; ------------- check characters cmp al,cl ; is it lower character? je short UpperCaseNat6 ; convert to upper character ; ------------- check next character inc bx inc bx ; BX <- increase pointer jmp short UpperCaseNat2 ; check next character ; ------------- convert lower -> upper (here is NC) UpperCaseNat6: mov al,ch ; AL <- upper character ; ------------- pop registers UpperCaseNat8: pop cx ; pop CX pop bx ; pop BX UpperCaseNat9: ret ; ----------------------------------------------------------------------------- ; Convert to lowercase letter with national characters ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = lowercase letter ; CY = not converted (not letter) ; ----------------------------------------------------------------------------- ; ------------- convert base ASCII characters LowerCaseNat: call LowerCase ; convert ASCII characters jnc short LowerCaseNat9 ; character converted OK ; ------------- push registers push bx ; push BX push cx ; push CX ; ------------- get characters from table -> CX mov bx,[KeyMapLowUp] ; BX <- conversion table LowerCaseNat2: mov cx,[bx] ; CL <- lower, CH <- upper stc ; preset CY error flag jcxz LowerCaseNat8 ; end of table ; ------------- check characters cmp al,ch ; is it upper character? je short LowerCaseNat6 ; convert to lower character ; ------------- check next character inc bx inc bx ; BX <- increase pointer jmp short LowerCaseNat2 ; check next character ; ------------- convert upper -> lower (here is NC) LowerCaseNat6: mov al,cl ; AL <- lower character ; ------------- pop registers LowerCaseNat8: pop cx ; pop CX pop bx ; pop BX LowerCaseNat9: ret ; ----------------------------------------------------------------------------- ; Convert lowercase/uppercase letter with national characters ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; OUTPUT: AL = changed letter ; CY = not converted (not letter) ; ----------------------------------------------------------------------------- ; ------------- convert base ASCII characters UpperLowerCaseNat: call UpperLowerCase ; convert ASCII characters jnc short UpperLowerNat9 ; character converted OK ; ------------- push registers push bx ; push BX push cx ; push CX ; ------------- get characters from table -> CX mov bx,[KeyMapLowUp] ; BX <- conversion table UpperLowerNat2: mov cx,[bx] ; CL <- lower, CH <- upper stc ; preset CY error flag jcxz UpperLowerNat8 ; end of table ; ------------- check characters cmp al,cl ; is it lower character? je short UpperLowerNat4 ; convert to upper character cmp al,ch ; is it upper character? je short UpperLowerNat6 ; convert to lower character ; ------------- check next character inc bx inc bx ; BX <- increase pointer jmp short UpperLowerNat2 ; check next character ; ------------- convert lower -> upper (here is NC) UpperLowerNat4: mov cl,ch ; CL <- upper character ; ------------- convert upper -> lower (here is NC) UpperLowerNat6: mov al,cl ; AL <- lower character ; ------------- pop registers UpperLowerNat8: pop cx ; pop CX pop bx ; pop BX UpperLowerNat9: ret ; ----------------------------------------------------------------------------- ; Get length of ASCIIZ string ; ----------------------------------------------------------------------------- ; INPUT: SI = pointer to ASCII string (it can be NULL) ; OUTPUT: AX = length of ASCII string (0 if SI=NULL) ; ----------------------------------------------------------------------------- ; ------------- push registers TextZLength: push cx ; push CX push si ; push SI ; ------------- text with NULL address xor cx,cx ; CX <- 0 or si,si ; NULL address ? jz short TextZLength8 ; NULL address, length = 0 ; ------------- get text length dec cx ; CX <- -1 TextZLength2: inc cx ; CX += 1 lodsb ; AL <- load next character or al,al ; end of string? jnz short TextZLength2 ; next character ; ------------- pop registers TextZLength8: xchg ax,cx ; AX <- length of string pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get length of text string ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure (it can be NULL) ; OUTPUT: AX = length of text string (0 if BX=NULL) ; ----------------------------------------------------------------------------- TextLength: xor ax,ax ; AX <- 0 or bx,bx ; is pointer valid? jz short TextLength2 ; pointer is not valid mov ax,[bx+TEXT_Length] ; AX <- text length TextLength2: ret ; ----------------------------------------------------------------------------- ; Check if character index is valid ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT ; SI = character index ; OUTPUT: CY = index is not valid (it is out of valid range) ; ----------------------------------------------------------------------------- TextCheckInx: cmp si,[bx+TEXT_Length] ; compare character index cmc ; CY = invalid character index ret ; ----------------------------------------------------------------------------- ; Allocate new text string ; ----------------------------------------------------------------------------- ; INPUT: CX = length of text string ; OUTPUT: AX = pointer to TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; ----------------------------------------------------------------------------- TextNew: mov ax,cx ; AX <- required text length inc ax ; AX += 1 inc ax ; AX <- size of memory block call MemAlloc ; allocate memory block jc short TextNew4 ; memory error xchg ax,bx ; BX <- block address, AX <- push BX mov [bx+TEXT_Length],cx ; set length of text xchg ax,bx ; AX <- block address, BX <- pop BX TextNew4: ret ; ----------------------------------------------------------------------------- ; Allocate new empty text string ; ----------------------------------------------------------------------------- ; OUTPUT: AX = pointer to TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; ----------------------------------------------------------------------------- TextNewEmpty: push cx ; push CX xor cx,cx ; CX <- 0, required length call TextNew ; allocate new string pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Allocate new text string from buffer ; ----------------------------------------------------------------------------- ; INPUT: CX = length of text string ; SI = pointer to source text ; OUTPUT: AX = pointer to TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; ----------------------------------------------------------------------------- ; ------------- push registers TextNewBuf: push cx ; push CX push si ; push SI push di ; push DI ; ------------- allocate new text string -> AX mov ax,cx ; AX <- required text length call TextNew ; allocate new text string jc short TextNewBuf8 ; memory error ; ------------- copy text mov di,ax ; DI <- address of TEXT structure lea di,[di+TEXT_Text] ; DI <- start of text shr cx,1 ; CX <- length / 2 rep movsw ; copy text - words adc cx,cx ; CX <- odd byte (it clears CF) rep movsb ; copy rest byte ; ------------- pop registers TextNewBuf8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Create text string from ASCIIZ text ; ----------------------------------------------------------------------------- ; INPUT: SI = pointer to ASCIIZ text (it can be NULL) ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; ----------------------------------------------------------------------------- TextNewZ: push cx ; push CX call TextZLength ; get length of ASCIIZ text xchg ax,cx ; CX <- length of ASCIIZ text call TextNewBuf ; create text from buffer pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Duplicate text string ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure (may be CTEXT) ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; ----------------------------------------------------------------------------- ; ------------- push registers TextDup: push cx ; push CX push si ; push SI push di ; push DI ; ------------- allocate new memory block mov ax,[bx+TEXT_Length] ; AX <- length of text inc ax ; AX += 1 inc ax ; AX <- size of memory block mov cx,ax ; CX <- size of memory block call MemAlloc ; allocate memory block jc short TextDup8 ; memory error ; ------------- copy content mov di,ax ; DI <- new memory block mov si,bx ; SI <- old memory block shr cx,1 ; CX <- length / 2 rep movsw ; copy content by words adc cx,cx ; CX <- odd byte (it clears CF) rep movsb ; copy rest 1 byte ; ------------- pop registers TextDup8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Delete text string ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: BX = old address or NULL on error ; CY = invalid pointer (BX = NULL) ; ----------------------------------------------------------------------------- TextFree: xchg ax,bx ; AX <- text string address call MemFree ; free memory block xchg ax,bx ; BX <- old address or NULL ret ; ----------------------------------------------------------------------------- ; Resize text string ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = required new length of text string ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextResize: push ax ; push AX mov ax,cx ; AX <- required new length inc ax ; AX += 1 inc ax ; AX <- size of memory block call MemResize ; resize memory block jc short TextResize4 ; memory error xchg ax,bx ; BX <- pointer to new text mov [bx+TEXT_Length],cx ; set length of text TextResize4: pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add text string to end of text ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to second TEXT structure ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddText: push cx ; push CX push si ; push SI push di ; push DI ; ------------- resize data buffer mov cx,[bx+TEXT_Length] ; CX <- current length of text mov si,ax ; SI <- second text mov di,cx ; DI <- old length add cx,[si+TEXT_Length] ; CX <- new text length call TextResize ; resize text string jc short TextAddText4 ; memory error ; ------------- copy text of second string (sets NC) mov cx,[si+TEXT_Length]; CX <- length of second text lea di,[bx+di+TEXT_Text] ; DI <- destination text lea si,[si+TEXT_Text] ; SI <- source text shr cx,1 ; CX <- number of WORDS rep movsw ; copy text in words adc cx,cx ; CX <- last byte rep movsb ; copy last byte ; ------------- pop registers TextAddText4: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Add text string from buffer to end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of second text ; SI = pointer to second text ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddBuf: push cx ; push CX push si ; push SI push di ; push DI ; ------------- resize data buffer mov di,cx ; DI <- length of second text add cx,[bx+TEXT_Length] ; CX <- new text length call TextResize ; resize text string jc short TextAddBuf4 ; memory error ; ------------- copy text of second string (sets NC) mov cx,di ; CX <- length of second text mov di,[bx+TEXT_Length] ; DI <- new length sub di,cx ; DI <- old length lea di,[bx+di+TEXT_Text] ; DI <- destination text shr cx,1 ; CX <- number of WORDS rep movsw ; copy text in words adc cx,cx ; CX <- last byte rep movsb ; copy last byte ; ------------- pop registers TextAddBuf4: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Add ASCIIZ text to end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; SI = pointer to second ASCIIZ text (it can be NULL) ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddTextZ: push cx ; push CX xchg ax,cx ; CX <- push AX call TextZLength ; get length of ASCIIZ text xchg ax,cx ; CX <- length of text, AX <- pop AX call TextAddBuf ; add text from buffer pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Add character to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddChar: push cx ; push CX push dx ; push DX push si ; push SI ; ------------- resize text string mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length inc cx ; increase text length call TextResize ; resize text string jc short TextAddChar8 ; memory error ; ------------- store new character mov [bx+si+TEXT_Text],al ; store new character ; ------------- pop registers TextAddChar8: pop si ; pop SI pop dx ; pop DX pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get character from text ; ----------------------------------------------------------------------------- ; INPUT: AL = default character, if index is out of range ; BX = pointer to TEXT structure ; SI = character index (0...) ; OUTPUT: AL = character from the text (or default character if CY) ; CY = error, index is out of range (AL not changed) ; ----------------------------------------------------------------------------- TextGetChar: cmp si,[bx+TEXT_Length] ; check character offset jae short TextGetChar2 ; invalid character offset mov al,[bx+TEXT_Text+si] ; AL <- character TextGetChar2: cmc ; CY = invalid character offset ret ; ----------------------------------------------------------------------------- ; Set character in text ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; BX = pointer to TEXT structure ; SI = character index (0...) (it may be out of range) ; OUTPUT: CY = error, index is out of range (text not changed) ; ----------------------------------------------------------------------------- TextSetChar: cmp si,[bx+TEXT_Length] ; check character offset jae short TextSetChar2 ; invalid character offset mov [bx+TEXT_Text+si],al ; set character TextSetChar2: cmc ; CY = invalid character offset ret ; ----------------------------------------------------------------------------- ; Get first character from text ; ----------------------------------------------------------------------------- ; INPUT: AL = default character, if no text ; BX = pointer to TEXT structure ; OUTPUT: AL = character from the text (or default character if CY) ; CY = error, no text (AL not changed) ; ----------------------------------------------------------------------------- TextGetFirst: push si ; push SI xor si,si ; SI <- index of first character call TextGetChar ; get character from text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Get last character from text ; ----------------------------------------------------------------------------- ; INPUT: AL = default character, if no text ; BX = pointer to TEXT structure ; OUTPUT: AL = character from the text (or default character if CY) ; CY = error, no text (AL not changed) ; ----------------------------------------------------------------------------- TextGetLast: push si ; push SI mov si,[bx+TEXT_Length] ; SI <- length of text dec si ; SI <- index of last character call TextGetChar ; get character from text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Add space character to end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddSpc: push ax ; push AX mov al," " ; AL <- space character call TextAddChar ; add space character to end of text pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add minus character to end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddMinus: push ax ; push AX mov al,"-" ; AL <- minus character call TextAddChar ; add minus character to end of text pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add new line CR/LF to end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddNewLine: push ax ; push AX mov al,CR ; AL <- CR character call TextAddChar ; add character to end of text jc short TextAddNewLine2 ; memory error mov al,LF ; AL <- LF character call TextAddChar ; add character to end of text TextAddNewLine2:pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add one digit character to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = number (in range 0 to 9) ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddDig: push ax ; push AX add al,'0' ; AL <- digit character call TextAddChar ; add digit to end of text pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add two digit characters to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = number (in range 0 to 99) ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAdd2Dig: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- resize data buffer mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length inc cx ; increate text length inc cx ; increate text length call TextResize ; resize text string jc short TextAdd2Dig2 ; memory error ; ------------- store digit characters aam ; AH <- first digit, AL <- second digit add ax,'00' ; AX <- digit characters xchg ah,al ; AL <- first digit, AH <- second digit mov [bx+si+TEXT_Text],ax ; store new characters ; ------------- pop registers TextAdd2Dig2: pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add two digit characters with space to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = number (in range 0 to 99) ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAdd2DigSpc: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- resize data buffer mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length inc cx ; increate text length inc cx ; increate text length call TextResize ; resize text string jc short TextAdd2DigSpc4 ; memory error ; ------------- store digit characters aam ; AH <- first digit, AL <- second digit add ax,'00' ; AX <- digit characters xchg ah,al ; AL <- first digit, AH <- second digit cmp al,"0" ; unsignificant zero? jne short TextAdd2DigSpc2 ; no zero mov al," " ; substitute with space character TextAdd2DigSpc2:mov [bx+si+TEXT_Text],ax ; store new characters ; ------------- pop registers TextAdd2DigSpc4:pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add unsigned byte number to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = unsigned data byte ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddByte: push ax ; push AX mov ah,0 ; AX = data word call TextAddWord ; add unsigned word number pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add signed byte number to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = signed data byte ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddSByte: or al,al ; negative number? jns short TextAddByte ; not negative number push ax ; push AX mov ah,0ffh ; AX = data word call TextAddSWord ; add signed word number pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add signed word number to end of text ; ----------------------------------------------------------------------------- ; INPUT: AX = signed data word ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddSWord: or ax,ax ; negative number? jns short TextAddWord ; not negative number call TextAddMinus ; add minus character push ax ; push AX neg ax ; AX <- positive value call TextAddWord ; add positive number pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add unsigned word number to end of text ; ----------------------------------------------------------------------------- ; INPUT: AX = unsigned data word ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddWord: push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI ; ------------- decode number into stack xor di,di ; DI <- character counter mov si,10 ; SI <- 10, divider TextAddWord2: xor dx,dx ; DX <- 0 div si ; divide one digit add dl,"0" ; DL <- convert to ASCII character push dx ; push digit into stack inc di ; DI <- increase digit counter or ax,ax ; already zero ? jnz short TextAddWord2 ; decode next digit ; ------------- resize data buffer mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length add cx,di ; CX <- new text length call TextResize ; resize text string mov cx,di ; CX <- number of digits jc short TextAddWord9 ; memory error ; ------------- store digits into stack (returns NC) TextAddWord4: pop ax ; pop digit from the stack mov [bx+si+TEXT_Text],al ; store new characters inc si ; increase offset of character loop TextAddWord4 ; next digit ; ------------- pop registers TextAddWord8: pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ------------- destroy digits from stack on error (returns CY) TextAddWord9: pop dx ; destroy digit from the stack loop TextAddWord9 ; next character jmp short TextAddWord8 ; ----------------------------------------------------------------------------- ; Add signed dword number to end of text ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = signed data dword ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- TextAddSDWord: or dx,dx ; negative number? jns short TextAddDWord ; not negative number call TextAddMinus ; add minus character push ax ; push AX push dx ; push DX neg ax ; AX <- negate number LOW adc dx,byte 0 ; DX <- carry neg dx ; DX <- negate number HIGH call TextAddDWord ; add positive number pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add unsigned dword number to end of text ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = unsigned data dword ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddDWord: push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI ; ------------- decode number into stack xor di,di ; DI <- character counter mov si,10 ; SI <- 10, divider TextAddDWord2: xchg ax,cx ; CX <- number LOW xchg ax,dx ; AX <- number high xor dx,dx ; DX <- 0 div si ; divide / 10 xchg ax,cx ; CX <- new high, AX <- low div si ; divide / 10 add dl,"0" ; DL <- convert to ASCII character push dx ; push digit into stack inc di ; DI <- increase digit counter mov dx,cx ; DX <- new high or cx,ax ; check zero result jnz short TextAddDWord2 ; decode next digit ; ------------- resize data buffer mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length add cx,di ; CX <- new text length call TextResize ; resize text string mov cx,di ; CX <- number of digits jc short TextAddDWord9 ; memory error ; ------------- store digits into stack (returns NC) TextAddDWord4: pop ax ; pop digit from the stack mov [bx+si+TEXT_Text],al ; store new characters inc si ; increase offset of character loop TextAddDWord4 ; next digit ; ------------- pop registers TextAddDWord8: pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ------------- destroy digits from stack on error (returns CY) TextAddDWord9: pop dx ; destroy digit from the stack loop TextAddDWord9 ; next character jmp short TextAddDWord8 ; ----------------------------------------------------------------------------- ; Add HEW dword to end of text ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = data dword ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextAddHDWord: xchg ax,dx ; AX <- high word, DX <- low word call TextAddHWord ; add high word xchg ax,dx ; AX <- low word, DX <- high word jc short TextAddHByte8 ; memory error ; --- TextAddHWord must follow! ; ----------------------------------------------------------------------------- ; Add HEX word to end of text ; ----------------------------------------------------------------------------- ; INPUT: AX = data word ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextAddHWord: xchg al,ah ; AL <- high byte, AH <- low byte call TextAddHByte ; add high byte xchg al,ah ; AL <- low byte, AH <- high byte jc short TextAddHByte8 ; memory error ; --- TextAddHByte must follow! ; ----------------------------------------------------------------------------- ; Add HEX byte to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; alternate method: ; add al,90h ; daa ; adc al,40h ; daa ; ------------- push registers TextAddHByte: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- resize text mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length add cx,byte 2 ; CX <- new text length call TextResize ; resize text string jc short TextAddHByte6 ; memory error ; ------------- high nibble (first character) mov cl,al ; AL <- save data byte shr al,1 shr al,1 shr al,1 shr al,1 ; AL <- high nibble cmp al,10 ; hex character A..F ? sbb al,69h das ; AL <- hex digit xchg ax,cx ; CL <- first digit, AL <- data byte ; ------------- low nibble (second character) and al,0fh ; AL <- low nibble cmp al,10 ; hex character A..F ? sbb al,69h das ; AL <- hex digit ; ------------- store characters mov ah,al ; AH <- second character mov al,cl ; AL <- first character mov [bx+si+TEXT_Text],ax ; store new characters clc ; clear error flag ; ------------- pop registers TextAddHByte6: pop si ; pop SI pop cx ; pop CX pop ax ; pop AX TextAddHByte8: ret ; ----------------------------------------------------------------------------- ; Add BIN dword to end of text ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = data dword ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextAddBDWord: xchg ax,dx ; AX <- high word, DX <- low word call TextAddBWord ; add high word xchg ax,dx ; AX <- low word, DX <- high word jc short TextAddBByte8 ; memory error ; --- TextAddBWord must follow! ; ----------------------------------------------------------------------------- ; Add BIN word to end of text ; ----------------------------------------------------------------------------- ; INPUT: AX = data word ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextAddBWord: xchg al,ah ; AL <- high byte, AH <- low byte call TextAddBByte ; add high byte xchg al,ah ; AL <- low byte, AH <- high byte jc short TextAddBByte8 ; memory error ; --- TextAddBByte must follow! ; ----------------------------------------------------------------------------- ; Add BIN byte to end of text ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error (text not changed) ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddBByte: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- resize text mov cx,[bx+TEXT_Length] ; CX <- current lenght of text mov si,cx ; SI <- old length add cx,byte 8 ; CX <- new text length call TextResize ; resize text string jc short TextAddBByte6 ; memory error ; ------------- decide bits (clear error flag NC) mov ah,al ; AH <- data byte mov cx,8 ; CX <- number of bits TextAddBByte2: shl ah,1 ; check highest bit mov al,"0" ; AL <- bit "0" adc al,0 ; change to bit "1" mov [bx+si+TEXT_Text],al ; store new character inc si ; increase number of characters loop TextAddBByte2 ; dispaly next bit ; ------------- pop registers TextAddBByte6: pop si ; pop SI pop cx ; pop CX pop ax ; pop AX TextAddBByte8: ret ; ----------------------------------------------------------------------------- ; Delete part of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of text to delete ; SI = offset of text to delete ; OUTPUT: BX = old or new pointer to TEXT structure ; NOTES: It limits length and offset to a valid range. ; ----------------------------------------------------------------------------- ; ------------- push registers TextDel: push ax ; push AX push cx ; push CX push si ; push SI push di ; push DI ; ------------- check maximal start offset SI mov ax,[bx+TEXT_Length] ; AX <- text length sub ax,si ; AX <- remaining characters jbe short TextDel8 ; nothing to delete ; ------------- limit size of deleted data -> AX, remaining data -> CX cmp ax,cx ; check length of text ja short TextDel2 ; text length is OK mov cx,ax ; CX <- limit text length TextDel2: jcxz TextDel8 ; no data to delete sub ax,cx ; AX <- remaining data xchg ax,cx ; AX <- deleted size, CX <- remaining jz short TextDel4 ; no remaining data ; ------------- delete text lea di,[bx+TEXT_Text+si] ; DI <- destination address mov si,di ; SI <- destination address add si,ax ; SI <- start of remainging text shr cx,1 ; CX <- number of WORDS rep movsw ; copy text in words adc cx,cx ; CX <- last byte rep movsb ; copy last byte ; ------------- resize buffer TextDel4: mov cx,[bx+TEXT_Length] ; CX <- length of text sub cx,ax ; CX <- new length of text call TextResize ; resize buffer mov [bx+TEXT_Length],cx ; set new length (in case of errr) ; ------------- pop registers TextDel8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Delete start of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of text to delete ; OUTPUT: BX = old or new pointer to TEXT structure ; NOTES: It limits length to a valid range. ; ----------------------------------------------------------------------------- TextDelStart: push si ; push SI xor si,si ; SI <- 0, start position call TextDel ; delete start of text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Delete rest of text from given position ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; SI = offset of text to delete ; OUTPUT: BX = old or new pointer to TEXT structure ; NOTES: It limits offset to a valid range. ; ----------------------------------------------------------------------------- TextDelFrom: push cx ; push CX mov cx,0ffffh ; CX <- number of characters to delete call TextDel ; delete characters from text pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Delete end of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of text to delete ; OUTPUT: BX = old or new pointer to TEXT structure ; NOTES: It limits length to a valid range. ; ----------------------------------------------------------------------------- TextDelEnd: push si ; push SI mov si,[bx+TEXT_Length] ; SI <- text length sub si,cx ; SI <- start position jnc short TextDelEnd4 ; position is OK xor si,si ; SI <- 0, limit position TextDelEnd4: call TextDel ; delete characters from text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Delete one character from text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; SI = index of character to delete ; OUTPUT: BX = old or new pointer to TEXT structure ; NOTES: It checks validity of character position. ; ----------------------------------------------------------------------------- TextDelChar: push cx ; push CX mov cx,1 ; CX <- lengt of 1 character call TextDel ; delete character pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get middle part of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of part of text ; SI = start position of part of text ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; NOTES: It limits length and position to a valid range. ; ----------------------------------------------------------------------------- ; ------------- push registers TextMid: push cx ; push CX push si ; push SI push di ; push DI ; ------------- limit start index -> SI mov ax,[bx+TEXT_Length] ; AX <- text length cmp si,ax ; check start offset jb short TextMid2 ; offset is OK mov si,ax ; SI <- limit start offset ; ------------- limit length of text -> CX TextMid2: sub ax,si ; AX <- remaining size cmp ax,cx ; check length of text ja short TextMid4 ; text length is OK mov cx,ax ; CX <- limit text length ; ------------- allocate new text string TextMid4: call TextNew ; allocate new text string jc short TextMid8 ; memory error ; ------------- copy text (it clears CF) mov di,ax ; DI <- new text string lea di,[di+TEXT_Text] ; DI <- start of new text lea si,[bx+TEXT_Text+si] ; SI <- start of part of text shr cx,1 ; CX <- length / 2 rep movsw ; copy content by words adc cx,cx ; CX <- odd byte (it clears CF) rep movsb ; copy rest 1 byte ; ------------- pop registers TextMid8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get left part of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of left part of text ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; NOTES: It limits length to a valid range. ; ----------------------------------------------------------------------------- TextLeft: push si ; push SI xor si,si ; SI <- start position call TextMid ; get middle part of text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Get right part of text from given position ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; SI = start position of right part ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; NOTES: It limits position to a valid range. ; ----------------------------------------------------------------------------- TextFrom: push cx ; push CX mov cx,0ffffh ; CX <- maximum length call TextMid ; get middle part of text pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get right part of text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CX = length of right part of text ; OUTPUT: AX = new TEXT structure or NULL on error ; CY = memory error (AX = NULL) ; NOTES: It limits length to a valid range. ; ----------------------------------------------------------------------------- TextRight: push si ; push SI mov si,[bx+TEXT_Length] ; SI <- length of text sub si,cx ; SI <- start of text jnc short TextRight2 ; position is OK xor si,si ; SI <- 0, limit position TextRight2: call TextMid ; get middle part of text pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Convert text to uppercase letters (only a..z are affected) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; NOTES: It does not convert national characters. ; ----------------------------------------------------------------------------- ; ------------- push registers TextUpper: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextUpper6 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextUpper2: lodsb ; AL <- load character call UpperCase ; convert to uppercase ; jc short TextUpper4 ; not converted mov [si-1],al ; save new character TextUpper4: loop TextUpper2 ; next character ; ------------- pop registers TextUpper6: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Convert text to uppercase letters with national characters ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextUpperNat: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextUpperNat6 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextUpperNat2: lodsb ; AL <- load character call UpperCaseNat ; convert to uppercase ; jc short TextUpperNat4 ; not converted mov [si-1],al ; save new character TextUpperNat4: loop TextUpperNat2 ; next character ; ------------- pop registers TextUpperNat6: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Convert text to lowercase letters (only A..Z are affected) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; NOTES: It does not convert national characters. ; ----------------------------------------------------------------------------- ; ------------- push registers TextLower: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextLower6 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextLower2: lodsb ; AL <- load character call LowerCase ; convert to lowercase ; jc short TextLower4 ; not converted mov [si-1],al ; save new character TextLower4: loop TextLower2 ; next character ; ------------- pop registers TextLower6: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Convert text to lowercase letters with national characters ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextLowerNat: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextLowerNat6 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextLowerNat2: lodsb ; AL <- load character call LowerCaseNat ; convert to lowercase ; jc short TextLowerNat4 ; not converted mov [si-1],al ; save new character TextLowerNat4: loop TextLowerNat2 ; next character ; ------------- pop registers TextLowerNat6: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Change uppercase/lowercase letters (only a..z, A..Z are affected) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; NOTES: It does not convert national characters. ; It changes lowercase letters to uppercase and contrariwise. ; ----------------------------------------------------------------------------- ; ------------- push registers TextUpLow: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextUpLow8 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextUpLow2: lodsb ; AL <- load character call IsAlpha ; check alpha character jc short TextUpLow4 ; not alpha character xor byte [si-1],"a"^"A" ; invert letter TextUpLow4: loop TextUpLow2 ; next character ; ------------- pop registers TextUpLow8: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Change uppercase/lowercase letters with national characters ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; NOTES: It changes lowercase letters to uppercase and contrariwise, ; ----------------------------------------------------------------------------- ; ------------- push registers TextUpLowNat: push ax ; push AX push si ; push SI push cx ; push CX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextUpLowNat8 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string TextUpLowNat2: lodsb ; AL <- load character call UpperLowerCaseNat ; convert to lowercase/uppercase ; jc short TextLowerNat4 ; not converted mov [si-1],al ; save new character TextUpLowNat4: loop TextUpLowNat2 ; next character ; ------------- pop registers TextUpLowNat8: pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Capitalize words (only a..z, A..Z are affected) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; NOTES: It does not convert national characters. ; It changes first letter of words to uppercase, other lowercase. ; ----------------------------------------------------------------------------- ; ------------- push registers TextCapital: push ax ; push AX push si ; push SI push cx ; push CX push dx ; push DX ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- length of text jcxz TextCapital8 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- convert string mov dh,0ffh ; DH <- 0ffh, flag of begin of word TextCapital2: lodsb ; AL <- load character call IsAlpha ; check alpha character sbb dl,dl ; DL <- 0 if alpha, 0ffh otherwise jnz short TextCapital6 ; not alpha character and dh,20h ; DH <- ~bit of lower/upper alpha or al,20h ; set delete old lower/upper flag xor al,dh ; AL <- correct lower/upper character mov [si-1],al ; store new character TextCapital6: mov dh,dl ; DH <- save flag of alpha character loop TextCapital2 ; next character ; ------------- pop registers TextCapital8: pop dx ; pop DX pop cx ; pop CX pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Compare text strings to equality ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to second TEXT structure ; BX = pointer to first TEXT structure ; OUTPUT: CY = strings are not equal ; NOTES: Comparison is case sensitive. ; ----------------------------------------------------------------------------- ; ------------- push registers TextEqu: push cx ; push CX push si ; push SI push di ; push DI ; ------------- identical strings cmp ax,bx ; compare pointers je short TextEqu8 ; identical strings ; ------------- compare length of string mov di,ax ; DI <- secont text mov cx,[bx+TEXT_Length] ; CX <- length of first text cmp cx,[di+TEXT_Length] ; compare length jne short TextEqu6 ; different text length ; ------------- compare strings jcxz TextEqu8 ; zero length strings lea si,[bx+TEXT_Text] ; SI <- first text lea di,[di+TEXT_Text] ; DI <- second text shr cx,1 ; CX <- length in words repe cmpsw ; compare strings in words jne short TextEqu6 ; string are not equal adc cx,cx ; CX <- even byte repe cmpsb ; compare even byte je short TextEqu8 ; string are equal ; ------------- pop registers TextEqu6: stc ; set error flag TextEqu8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Compare text strings alphabetically ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to second TEXT structure ; BX = pointer to first TEXT structure ; OUTPUT: AX = first string is 1:greater (later), -1:smaller, 0:equal. ; flags SF,ZF contains result (as "or ax,ax") ; NOTES: Comparison is not case sensitive (not national characters). ; ----------------------------------------------------------------------------- ; ------------- push registers TextComp: push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI ; ------------- identical strings cmp ax,bx ; compare pointers je short TextComp7 ; identical strings ; ------------- prepare length of strings -> CX first, DX second mov di,ax ; DI <- second text mov cx,[bx+TEXT_Length] ; CX <- length of first text mov dx,[di+TEXT_Length] ; DX <- length of second text ; ------------- prepare text pointers -> SI first, DI second lea si,[bx+TEXT_Text] ; SI <- firt text lea di,[di+TEXT_Text] ; DI <- second text ; ------------- check end of strings TextComp2: cmp cx,dx ; identical length? je short TextComp3 ; identical length jcxz TextComp5 ; shorter first text is smaller or dx,dx ; check second text jz short TextComp6 ; longer first text is greater TextComp3: jcxz TextComp7 ; strings are equal dec cx ; CX <- count first counter dec dx ; DX <- count second counter ; ------------- get character of second string -> AH mov al,[di] ; AL <- load character of second string inc di ; DI <- increase pointer call UpperCase ; convert to uppercase letter mov ah,al ; AH <- character of second string ; ------------- get character of first string -> AL lodsb ; AL <- load character of first string call UpperCase ; convert to uppercase letter ; ------------- compare strings cmp al,ah ; compare first and second string ja short TextComp6 ; string1 > string2 je short TextComp2 ; equal, continue with next character ; ------------- string1 < string2 TextComp5: xor ax,ax ; AX <- 0 dec ax ; AX <- -1 jmp short TextComp8 ; ------------- string1 > string2 TextComp6: xor ax,ax ; AX <- 0 inc ax ; AX <- 1 jmp short TextComp8 ; ------------- strings are equal TextComp7 xor ax,ax ; AX <- 0 ; ------------- pop registers TextComp8: pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX or ax,ax ; test result ret ; ----------------------------------------------------------------------------- ; Trim text from the left and right (delete spaces and control characters) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: CY = memory error (text may be changed) ; ----------------------------------------------------------------------------- TextTrim: call TextTrimRight ; trim text from the right ; === TextTrimLeft must follow ! ; ----------------------------------------------------------------------------- ; Trim text from the left (delete spaces and control characters from start) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextTrimLeft: push cx ; push CX push si ; push SI ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextTrimLeft8 ; nothing to delete lea si,[bx+TEXT_Text] ; SI <- start of text ; ------------- find first valid character TextTrimLeft2: cmp byte [si],32 ; check one byte ja short TextTrimLeft4 ; it is valid character inc si ; increase text pointer loop TextTrimLeft2 ; next byte TextTrimLeft4: mov si,cx ; SI <- remaining bytes ; ------------- delete characters mov cx,[bx+TEXT_Length] ; CX <- text length sub cx,si ; CX <- number of bytes to delete jcxz TextTrimLeft8 ; nothing to delete call TextDelStart ; delete start of text ; ------------- pop registers TextTrimLeft8: pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Trim text from the right (delete spaces and control characters from end) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextTrimRight: push cx ; push CX push si ; push SI ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextTrimRight8 ; nothing to delete mov si,cx ; SI <- text length lea si,[bx+TEXT_Text+si] ; SI <- end of text ; ------------- find first valid character TextTrimRight2: dec si ; decrease text pointer cmp byte [si],32 ; check one byte ja short TextTrimRight4 ; it is valid character loop TextTrimRight2 ; next byte TextTrimRight4: mov si,cx ; SI <- remaining bytes ; ------------- delete characters mov cx,[bx+TEXT_Length] ; CX <- text length sub cx,si ; CX <- number of bytes to delete jcxz TextTrimRight8 ; nothing to delete call TextDelEnd ; delete end of text ; ------------- pop registers TextTrimRight8: pop si ; pop SI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Trim spaces and control characters from the text ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextTrimMid: push ax ; push AX push cx ; push CX push si ; push SI push di ; push DI ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextTrimMid8 ; nothing to delete lea si,[bx+TEXT_Text] ; SI <- source pointer mov di,si ; DI <- destination pointer ; ------------- trim spaces and control characters TextTrimMid2: lodsb ; AL <- load one character cmp al,33 ; check one character stosb ; store character sbb di,byte 0 ; return pointer if invalid character loop TextTrimMid2 ; next byte ; ------------- resize data buffer cmp si,di ; text changed? je short TextTrimMid8 ; text not changed lea ax,[bx+TEXT_Text] ; AX <- start of text sub di,ax ; DI <- new length mov cx,di ; CX <- new length call TextResize ; resize data buffer mov [bx+TEXT_Length],cx ; set new length (in case of errr) ; ------------- pop registers TextTrimMid8: pop di ; pop DI pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Prepare bitmap of character list ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of characters ; DI = pointer to 32-byte array in the stack ; BP = 0 (forbidden characters) or 0ffffh (allowed characters) ; ----------------------------------------------------------------------------- ; ------------- push registers TextPrepMap: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI mov bx,di ; BX <- 32-byte array mov si,ax ; SI <- list of characters ; ------------- clear bitmap array mov cx,32/2 ; CX <- size of array/2 mov ax,bp ; AX <- 0 or 0ffffh rep stosw ; clear bitmap array ; ------------- prepare list of characters mov dx,[si+TEXT_Length] ; DX <- length of list lea si,[si+TEXT_Text] ; SI <- start of list ; ------------- initialize bitmap array TextPrepMap2: lodsb ; AL <- load one character mov ah,0 ; AX = character mov cl,3 ; CL <- number of shifts shr ax,cl ; AX = offset of byte in mask add ax,bx ; AX <- address in bitmap array xchg ax,di ; DI <- address in bitmap array mov al,[si-1] ; AL <- character and al,7 ; AL <- offset in byte xchg ax,cx ; CL <- offset in byte mov al,B0 ; AL <- bit 0 shl al,cl ; AL <- bit mask or [di],al ; set bit and ax,bp ; clear bit if forbidden chars xor [di],al ; clear bit if forbidden chars dec dx ; list counter jnz short TextPrepMap2 ; prepare next character ; ------------- pop registers pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ------------- macro: check one character from bitmap ; %1: inc or dec to shift SI register ; AX,DX,DI = destroy, SI = source pointer, SP=pointer to bitmap ; output: NZ = bit is set %macro TEXTCHECKMAP 1 mov al,[si] ; AL <- load one character mov dx,cx ; DX <- push CX mov ah,0 ; AX = character mov cl,3 ; CL <- number of shifts shr ax,cl ; AX = offset of byte in mask add ax,sp ; AX <- address in bitmap array xchg ax,di ; DI <- address in bitmap array mov al,[si] ; AL <- character and al,7 ; AL <- offset in byte xchg ax,cx ; CL <- offset in byte mov al,B0 ; AL <- bit 0 shl al,cl ; AL <- bit mask %1 si ; shift SI register test [di],al ; test bit mov cx,dx ; CX <- pop CX %endmacro ; ----------------------------------------------------------------------------- ; Trim text using list of allowed characters ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of allowed characters ; BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextTrimUnlist: push bp ; push BP xor bp,bp ; BP <- 0 dec bp ; BP <- 0ffffh, flag - allowed chars jmp short TextTrimList1 ; ----------------------------------------------------------------------------- ; Trim text using list of forbidden characters ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of forbidden characters ; BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextTrimList: push bp ; push BP xor bp,bp ; BP <- 0, flag - forbidden chars TextTrimList1: push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI sub sp,32 ; local variable - 32-byte array ; ------------- prepare bitmap of character list mov di,sp ; DI <- bitmap in stack call TextPrepMap ; prepare bitmap ; ------------- prepare registers mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextTrimList8 ; nothing to delete lea si,[bx+TEXT_Text] ; SI <- source pointer mov di,si ; DI <- destination pointer ; ------------- load and check one character TextTrimList4: mov bp,di ; BP <- push DI TEXTCHECKMAP inc ; check character mov di,bp ; DI <- pop DI jnz short TextTrimList6; forbidden character has been found ; ------------- store character mov al,[si-1] ; AL <- character stosb ; store character TextTrimList6: loop TextTrimList4 ; next byte ; ------------- resize data buffer cmp si,di ; text changed? je short TextTrimList8 ; text not changed lea ax,[bx+TEXT_Text] ; AX <- start of text sub di,ax ; DI <- new length mov cx,di ; CX <- new length call TextResize ; resize data buffer mov [bx+TEXT_Length],cx ; set new length (in case of errr) ; ------------- pop registers TextTrimList8: add sp,32 ; return SP pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX pop bp ; pop BP ret ; ----------------------------------------------------------------------------- ; Find first/next character in text in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character to find ; BX = pointer to TEXT structure ; SI = start offset (TextFindChFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of character TextFindChFirst:xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFindChNext: push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer ; ------------- find data sub cx,si ; CX <- remaining data jbe short TextFindChErr ; data not found repne scasb ; find data jne short TextFindChErr ; data not found ; ------------- get offset of data inc cx ; CX <- return found data mov si,[bx+TEXT_Length] ; SI <- text length sub si,cx ; SI <- data offset (it sets NC) ; ------------- OK: pop registers (here is NC) pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Find last/previous character in text in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character to find ; BX = pointer to TEXT structure ; SI = start offset (TextFindChLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of character TextFindChLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh, find last occurrence ; ------------- push registers TextFindChPrev: push cx ; push CX push di ; push DI ; ------------- get text length -> CX mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextFindChErr ; no text ; ------------- limit maximal offset -> SI cmp si,cx ; check maximal offset jb short TextFindChPrev2 ; offset is OK mov si,cx ; SI <- text length dec si ; SI <- offset of last byte ; ------------- get text address -> DI TextFindChPrev2:lea di,[bx+TEXT_Text+si] ; DI <- start pointer ; ------------- find data mov cx,si ; CX <- remaining data inc cx ; CX <- number of bytes std ; set direction down repne scasb ; find data cld ; set direction up jne short TextFindChErr ; data not found ; ------------- get offset of data (here is NC) mov si,cx ; SI <- remaining bytes ; ------------- OK: pop registers (here is NC) pop di ; pop DI pop cx ; pop CX ret ; ------------- data not found (here jumps from other functions, too) TextFindChErr: xor si,si ; SI <- 0 dec si ; SI <- -1, data not found stc ; set error flag ; ------------- ERROR: pop registers pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Find first/next two characters in text in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AL = first character to find ; AH = second character to find ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ChFirst sets SI to 0) ; OUTPUT: SI = offset of found characters (or SI = -1 if not found) ; CY = characters not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of 2 characters TextFind2ChFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFind2ChNext:push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer jcxz TextFindChErr ; no text dec cx ; CX -= 1, without last byte sub cx,si ; CX <- remaining data jbe short TextFindChErr ; data not found ; ------------- find data TextFind2ChNxt2:repne scasb ; find data jne short TextFindChErr ; data not found cmp ah,[di] ; check second character jne short TextFind2ChNxt2 ; continue searching ; ------------- get offset of data inc cx ; CX <- return found data inc cx ; CX <- return found data TextFind2ChOK: mov si,[bx+TEXT_Length] ; SI <- text length sub si,cx ; SI <- data offset (it sets NC) ; ------------- OK: pop registers (here is NC) pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Find last/previous two characters in text in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AL = first character to find ; AH = second character to find ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ChLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found characters (or SI = -1 if not found) ; CY = characters not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of 2 characters TextFind2ChLast:xor si,si ; SI <- 0 dec si ; SI <- 0ffffh, find last occurrence ; ------------- push registers TextFind2ChPrev:push cx ; push CX push di ; push DI ; ------------- get text length -> CX mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextFindChErr ; no text dec cx ; CX -= 1, without last byte ; ------------- limit maximal offset -> SI cmp si,cx ; check maximal offset jb short TextFind2ChPrv2 ; offset is OK mov si,cx ; SI <- text length dec si ; SI <- offset of last 2 bytes ; ------------- get text address -> DI TextFind2ChPrv2:lea di,[bx+TEXT_Text+si] ; DI <- start pointer ; ------------- find data mov cx,si ; CX <- remaining data inc cx ; CX <- number of bytes TextFind2ChPrv4:std ; set direction down repne scasb ; find data cld ; set direction up jne short TextFindChErr ; data not found cmp ah,[di+2] ; check second character jne short TextFind2ChPrv4 ; continue searching ; ------------- get offset of data (here is NC) mov si,cx ; SI <- remaining bytes ; ------------- OK: pop registers (here is NC) pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Find first/next character from 2-character list in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ListFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of character TextFind2ListFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFind2ListNext: push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer jcxz TextFindChErr ; no text sub cx,si ; CX <- remaining data jbe short TextFindChErr ; data not found ; ------------- find data TextFind2LNext2:cmp [di],al ; check character 1 TextFind2ChOK2: je short TextFind2ChOK ; character found OK cmp [di],ah ; check character 2 je short TextFind2ChOK ; character found OK inc di ; increase text pointer loop TextFind2LNext2 ; next character TextFind2LNext4:jmp short TextFindChErr ; not found ; ----------------------------------------------------------------------------- ; Find first/next character from 3-character list in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; DL = character 3 ; BX = pointer to TEXT structure ; SI = start offset (TextFind3ListFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of character TextFind3ListFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFind3ListNext: push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer jcxz TextFindChErr ; no text sub cx,si ; CX <- remaining data jbe short TextFindChErr ; data not found ; ------------- find data TextFind3LNext2:cmp [di],al ; check character 1 je short TextFind2ChOK ; character found OK cmp [di],ah ; check character 2 je short TextFind2ChOK ; character found OK cmp [di],dl ; check character 3 je short TextFind2ChOK ; character found OK inc di ; increase text pointer loop TextFind3LNext2 ; next character jmp short TextFind2LNext4 ; not found ; ----------------------------------------------------------------------------- ; Find first/next character from 4-character list in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; DL = character 3 ; DH = character 4 ; BX = pointer to TEXT structure ; SI = start offset (TextFind4ListFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of character TextFind4ListFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFind4ListNext: push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer jcxz TextFind2LNext4 ; no text sub cx,si ; CX <- remaining data jbe short TextFind2LNext4 ; data not found ; ------------- find data TextFind4LNext2:cmp [di],al ; check character 1 je short TextFind2ChOK2 ; character found OK cmp [di],ah ; check character 2 je short TextFind2ChOK2 ; character found OK cmp [di],dl ; check character 3 je short TextFind2ChOK2 ; character found OK cmp [di],dh ; check character 4 je short TextFind2ChOK2 ; character found OK inc di ; increase text pointer loop TextFind4LNext2 ; next character jmp short TextFind2LNext4 ; not found ; ----------------------------------------------------------------------------- ; Find last/prev character from 2-character list in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ListLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of character TextFind2ListLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh ; ------------- limit offset -> SI TextFind2ListPrev: cmp si,[bx+TEXT_Length] ; check offset jb short TextFind2LPrev2 ; offset is OK mov si,[bx+TEXT_Length] ; SI <- text length jmp short TextFind2LPrev4 ; ------------- find data TextFind2LPrev2:cmp [bx+TEXT_Text+si],al ; check character 1 je short TextFind2LPrev8 ; character found OK cmp [bx+TEXT_Text+si],ah ; check character 2 je short TextFind2LPrev8 ; character found OK TextFind2LPrev4:sub si,byte 1 ; decrease text pointer jnc short TextFind2LPrev2 ; next character TextFind2LPrev8:ret ; ----------------------------------------------------------------------------- ; Find last/prev character from 3-character list in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; DL = character 3 ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ListLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of character TextFind3ListLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh ; ------------- limit offset -> SI TextFind3ListPrev: cmp si,[bx+TEXT_Length] ; check offset jb short TextFind3LPrev2 ; offset is OK mov si,[bx+TEXT_Length] ; SI <- text length jmp short TextFind3LPrev4 ; ------------- find data TextFind3LPrev2:cmp [bx+TEXT_Text+si],al ; check character 1 je short TextFind3LPrev8 ; character found OK cmp [bx+TEXT_Text+si],ah ; check character 2 je short TextFind3LPrev8 ; character found OK cmp [bx+TEXT_Text+si],dl ; check character 3 je short TextFind3LPrev8 ; character found OK TextFind3LPrev4:sub si,byte 1 ; decrease text pointer jnc short TextFind3LPrev2 ; next character TextFind3LPrev8:ret ; ----------------------------------------------------------------------------- ; Find last/prev character from 4-character list in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AL = character 1 ; AH = character 2 ; DL = character 3 ; DH = character 4 ; BX = pointer to TEXT structure ; SI = start offset (TextFind2ListLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of character TextFind4ListLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh ; ------------- limit offset -> SI TextFind4ListPrev: cmp si,[bx+TEXT_Length] ; check offset jb short TextFind4LPrev2 ; offset is OK mov si,[bx+TEXT_Length] ; SI <- text length jmp short TextFind4LPrev4 ; ------------- find data TextFind4LPrev2:cmp [bx+TEXT_Text+si],al ; check character 1 je short TextFind4LPrev8 ; character found OK cmp [bx+TEXT_Text+si],ah ; check character 2 je short TextFind4LPrev8 ; character found OK cmp [bx+TEXT_Text+si],dl ; check character 3 je short TextFind4LPrev8 ; character found OK cmp [bx+TEXT_Text+si],dh ; check character 4 je short TextFind4LPrev8 ; character found OK TextFind4LPrev4:sub si,byte 1 ; decrease text pointer jnc short TextFind4LPrev2 ; next character TextFind4LPrev8:ret ; ----------------------------------------------------------------------------- ; Substitute character ; ----------------------------------------------------------------------------- ; INPUT: AL = old character (to search for) ; AH = new character (to substitute with) ; BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers TextSubstCh: push cx ; push CX push di ; push DI ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text] ; DI <- start pointer ; ------------- substitute character TextSubstCh2: jcxz TextSubstCh8 ; no text TextSubstCh4: repne scasb ; find character jne TextSubstCh8 ; not found mov [di-1],ah ; substitute character jmp short TextSubstCh2 ; continue ; ------------- pop registers TextSubstCh8: pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Find first/next text in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT to find ; BX = pointer to TEXT where to search ; SI = start offset (TextFindFirst sets SI to 0) ; OUTPUT: SI = offset of found text (or SI = -1 if text not found) ; CY = text not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of the text TextFindFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFindNext: push ax ; push AX push cx ; push CX push dx ; push DX push di ; push DI push bp ; push BP ; ------------- limit start offset -> SI (for case of empty text to find) cmp si,[bx+TEXT_Length] ; check start offset jb short TextFindNext1 ; offset is OK mov si,[bx+TEXT_Length] ; SI <- limit start offset ; ------------- find 1 or 2 characters, TEXT to find -> DI, length-2 -> BP TextFindNext1: mov di,ax ; DI <- text to find mov bp,[di+TEXT_Length] ; BP <- length of text to find or bp,bp ; zero length? jz short TextFindNext9 ; zero length, always return NC mov al,[di+TEXT_Text] ; AL <- first character dec bp ; length 1? jz short TextFindNext2 ; text is one character mov ah,[di+TEXT_Text+1] ; AH <- second character dec bp ; length 2? jnz short TextFindNext3 ; text is too long call TextFind2ChNext ; find two characters jmp short TextFindNext9 TextFindNext2: call TextFindChNext ; find one character jmp short TextFindNext9 ; ------------- get text length -> CX and text address -> DI TextFindNext3: lea dx,[di+TEXT_Text+2] ; DX <- start of text to find + 2 mov cx,[bx+TEXT_Length] ; CX <- length of text sub cx,bp ; CX <- without text length - 2 dec cx ; CX <- without first byte lea di,[bx+TEXT_Text+si] ; DI <- start pointer sub cx,si ; CX <- remaining data jbe short TextFindNext7 ; text not found ; ------------- find begin of data TextFindNext4: repne scasb ; find data jne short TextFindNext7 ; data not found cmp ah,[di] ; check second byte jne short TextFindNext4 ; text not equal ; ------------- compare rest of text push di ; push DI push cx ; push CX mov si,dx ; SI <- start of text + 2 inc di ; DI <- start of text + 2 mov cx,bp ; CX <- text length - 2 shr cx,1 ; CX <- text length in WORDs repe cmpsw ; compare texts in WORDs jne short TextFindNext6 ; texts not equal mov cx,bp ; CX <- text length - 2 and cx,byte 1 ; CX <- rest of text in last DWORD repe cmpsb ; compare byte in last WORD TextFindNext6: pop cx ; pop CX pop di ; pop DI jne short TextFindNext4 ; text not equal ; ------------- get offset of data add cx,bp ; CX <- offset in text add cx,byte 2 ; CX <- including 2 characters mov si,[bx+TEXT_Length] ; SI <- text length sub si,cx ; SI <- data offset (it sets NC) jmp short TextFindNext9 ; ------------- text not found TextFindNext7: xor si,si ; SI <- 0 dec si ; SI <- -1, data not found stc ; set error flag ; ------------- pop registers TextFindNext9: pop bp ; pop BP pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Find last/previous text in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT to find ; BX = pointer to TEXT where to search ; SI = start offset (TextFindLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found text (or SI = -1 if text not found) ; CY = text not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of the text TextFindLast: xor si,si ; SI <- 0 dec di ; SI <- 0ffffh, find last occurrence ; ------------- push registers TextFindPrev: push ax ; push AX push cx ; push CX push dx ; push DX push di ; push DI push bp ; push BP ; ------------- limit start offset -> SI (for case of empty text to find) cmp si,[bx+TEXT_Length] ; check start offset jb short TextFindPrev1 ; offset is OK mov si,[bx+TEXT_Length] ; SI <- limit start offset ; ------------- find 1 or 2 characters, TEXT to find -> DI, length-2 -> BP TextFindPrev1: mov di,ax ; DI <- text to find mov bp,[di+TEXT_Length] ; BP <- length of text to find or bp,bp ; zero length? jz short TextFindPrev9 ; zero length, always return NC mov al,[di+TEXT_Text] ; AL <- first character dec bp ; length 1? jz short TextFindPrev2 ; text is one character mov ah,[di+TEXT_Text+1] ; AH <- second character dec bp ; length 2? jnz short TextFindPrev3 ; text is too long call TextFind2ChPrev ; find two characters jmp short TextFindPrev9 TextFindPrev2: call TextFindChPrev ; find one character jmp short TextFindPrev9 ; ------------- get text length -> CX TextFindPrev3: lea dx,[di+TEXT_Text+2] ; DX <- start of text to find + 2 mov cx,[bx+TEXT_Length] ; CX <- length of text sub cx,bp ; CX <- without text length - 2 dec cx ; CX <- without first byte ; ------------- limit maximal offset -> SI cmp si,cx ; check maximal offset jb short TextFindPrev4 ; offset is OK mov si,cx ; SI <- text length dec si ; SI <- offset of last byte ; ------------- get text address -> DI TextFindPrev4: lea di,[bx+TEXT_Text+si] ; DI <- start pointer mov cx,si ; CX <- remaining data inc cx ; CX <- number of bytes ; ------------- find begin of data TextFindPrev5: std ; set direction down repne scasb ; find data cld ; set direction up jne short TextFindPrev7 ; data not found cmp ah,[di+2] ; check second byte jne short TextFindPrev5 ; text not equal ; ------------- compare rest of text push di ; push DI push cx ; push CX mov si,dx ; SI <- start of text + 2 add di,byte 3 ; DI <- start of text + 2 mov cx,bp ; CX <- text length - 2 shr cx,1 ; CX <- text length in WORDs repe cmpsw ; compare texts in WORDs jne short TextFindPrev6 ; texts not equal mov cx,bp ; CX <- text length - 2 and cx,byte 1 ; CX <- rest of text in last DWORD repe cmpsb ; compare byte in last WORD TextFindPrev6: pop cx ; pop CX pop di ; pop DI jne short TextFindPrev5 ; text not equal ; ------------- get offset of data (here is NC) mov si,cx ; SI <- data offset jmp short TextFindPrev9 ; ------------- text not found TextFindPrev7: xor si,si ; SI <- 0 dec si ; SI <- -1, data not found stc ; set error flag ; ------------- pop registers TextFindPrev9: pop bp ; pop BP pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Find first/next character not from list in text in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of characters to skip ; BX = pointer to TEXT structure ; SI = start offset (TextFindUnlistFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of not characters TextFindUnlistFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFindUnlistNext: push bp ; push BP xor bp,bp ; BP <- 0, flag - forbidden chars jmp short TextFindLNext1 ; ----------------------------------------------------------------------------- ; Find first/next character from list in text in forward direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of characters ; BX = pointer to TEXT structure ; SI = start offset (TextFindListFirst sets SI to 0) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find first occurrence of character TextFindListFirst: xor si,si ; SI <- 0, find first occurrence ; ------------- push registers TextFindListNext: push bp ; push BP xor bp,bp ; BP <- 0 dec bp ; BP <- 0ffffh, flag - allowed chars TextFindLNext1: push ax ; push AX push cx ; push CX push dx ; push DX push di ; push DI sub sp,32 ; local variable - 32-byte array ; ------------- prepare bitmap of character list mov di,sp ; DI <- bitmap in stack call TextPrepMap ; prepare bitmap ; ------------- get text length -> CX and text address -> DI mov cx,[bx+TEXT_Length] ; CX <- text length lea di,[bx+TEXT_Text+si] ; DI <- start pointer sub cx,si ; CX <- remaining data jbe short TextFindLNext3 ; data not found ; ------------- find data mov si,di ; SI <- text TextFindLNext2: TEXTCHECKMAP inc ; check character je short TextFindLNext4 ; character found OK loop TextFindLNext2 ; next character ; ------------- data not found (here jumps from other functions, too) TextFindLNext3: xor si,si ; SI <- 0 dec si ; SI <- -1, data not found add sp,32 ; return SP stc ; set error flag jmp short TextFindLNext8 ; ------------- get offset of data TextFindLNext4: mov si,[bx+TEXT_Length] ; SI <- text length sub si,cx ; SI <- data offset add sp,32 ; return SP (sets NC) ; ------------- pop registers TextFindLNext8: pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX pop bp ; pop BP ret ; ----------------------------------------------------------------------------- ; Find last/previous character not from list in text in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of characters to skip ; BX = pointer to TEXT structure ; SI = start offset (TextFindUnlistLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of not characters TextFindUnlistLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh, find last occurrence ; ------------- push registers TextFindUnlistPrev: push bp ; push BP xor bp,bp ; BP <- 0, flag - forbidden chars jmp short TextFindLPrev1 ; ----------------------------------------------------------------------------- ; Find last/previous character from list in text in reverse direction ; ----------------------------------------------------------------------------- ; INPUT: AX = pointer to TEXT with list of characters ; BX = pointer to TEXT structure ; SI = start offset (TextFindListLast sets SI to 0ffffh) ; OUTPUT: SI = offset of found character (or SI = -1 if not found) ; CY = character not found (SI = -1) ; ----------------------------------------------------------------------------- ; ------------- find last occurrence of character TextFindListLast: xor si,si ; SI <- 0 dec si ; SI <- 0ffffh, find last occurrence ; ------------- push registers TextFindListPrev: push bp ; push BP xor bp,bp ; BP <- 0 dec bp ; BP <- 0ffffh, flag - allowed chars TextFindLPrev1: push ax ; push AX push cx ; push CX push dx ; push DX push di ; push DI sub sp,32 ; local variable - 32-byte array ; ------------- prepare bitmap of character list mov di,sp ; DI <- bitmap in stack call TextPrepMap ; prepare bitmap ; ------------- get text length -> CX mov cx,[bx+TEXT_Length] ; CX <- text length jcxz TextFindLPrev4 ; no text ; ------------- limit maximal offset -> SI cmp si,cx ; check maximal offset jb short TextFindLPrev2 ; offset is OK mov si,cx ; SI <- text length dec si ; SI <- offset of last byte ; ------------- get text address -> DI TextFindLPrev2: lea di,[bx+TEXT_Text+si] ; DI <- start pointer ; ------------- find data mov cx,si ; CX <- remaining data inc cx ; CX <- number of bytes mov si,di ; SI <- text TextFindLPrev3: TEXTCHECKMAP dec ; check character je short TextFindLPrev6 ; character found OK loop TextFindLPrev3 ; next character ; ------------- data not found (here jumps from other functions, too) TextFindLPrev4: xor si,si ; SI <- 0 dec si ; SI <- -1, data not found add sp,32 ; return SP stc ; set error flag jmp short TextFindLPrev8 ; ------------- get offset of data TextFindLPrev6: mov si,cx ; SI <- remaining bytes dec si add sp,32 ; return SP (sets NC) ; ------------- pop registers TextFindLPrev8: pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX pop bp ; pop BP ret ; ----------------------------------------------------------------------------- ; Add date to text ; ----------------------------------------------------------------------------- ; INPUT: AH = date format (DATEFORM_EURO,...) ; BX = pointer to TEXT structure ; DL = day ; DH = month ; SI = year ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error or invalid date format ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddDate: push ax ; push AX ; ------------- Europe format day.month.year cmp ah,DATEFORM_EURO ; Europe format? jne short TextAddDate2 ; no mov al,dl ; AL <- day call TextAddByte ; add day jc short TextAddDate8 ; memory error mov al,"." ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov al,dh ; AL <- month call TextAddByte ; add month jc short TextAddDate8 ; memory error mov al,"." ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov ax,si ; AX <- year call TextAddWord ; add year jmp short TextAddDate8 ; ------------- USA format month/day/year TextAddDate2: cmp ah,DATEFORM_USA ; USA format? jne short TextAddDate4 ; no mov al,dh ; AL <- month call TextAddByte ; add month jc short TextAddDate8 ; memory error mov al,"/" ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov al,dl ; AL <- day call TextAddByte ; add day jc short TextAddDate8 ; memory error mov al,"/" ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov ax,si ; AX <- year call TextAddWord ; add year jmp short TextAddDate8 ; ------------- Japan format year-month-day TextAddDate4: cmp ah,DATEFORM_JAPAN ; Japan format? stc ; set error flag jne short TextAddDate8 ; no mov ax,si ; AX <- year call TextAddWord ; add year jc short TextAddDate8 ; memory error mov al,"-" ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov al,dh ; AL <- month call TextAdd2Dig ; add month jc short TextAddDate8 ; memory error mov al,"-" ; separator call TextAddChar ; add separator jc short TextAddDate8 ; memory error mov al,dl ; AL <- day call TextAdd2Dig ; add day ; ------------- pop registers TextAddDate8: pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add time to text (in format HH:MM:SS) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; CL = minute ; CH = hour ; DH = second ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddTime: push ax ; push AX ; ------------- add hour mov al,ch ; AL <- hour call TextAddByte ; add hour jc short TextAddTime8 ; memory error mov al,":" ; separator call TextAddChar ; add separator jc short TextAddTime8 ; memory error ; ------------- add minute mov al,cl ; AL <- minute call TextAdd2Dig ; add minute jc short TextAddTime8 ; memory error mov al,":" ; separator call TextAddChar ; add separator jc short TextAddTime8 ; memory error ; ------------- add second mov al,dh ; AL <- second call TextAdd2Dig ; add second ; ------------- pop registers TextAddTime8: pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add disk size ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = number of 512 B sectors ; BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- ; ------------- push registers TextAddDiskSize:push ax ; push AX push dx ; push DX push si ; push SI ; ------------- prepare KB or MB mov si,TextKB ; SI <- text "KB" or dx,dx ; big disk? jnz short TextAddDiskSiz2 ; big disk cmp ax,1000h ; small disk < 2 MB jb short TextAddDiskSiz4 ; small disk TextAddDiskSiz2:mov si,TextMB ; SI <- text "MB" ; ------------- convert sectors to MB mov al,ah mov ah,dl mov dl,dh mov dh,0 ; DX:AX <- number of sectors >> 8 shr dx,1 rcr ax,1 ; shift >> 9 (7F0000h) shr dx,1 rcr ax,1 ; shift >> 10 (3F0000h) TextAddDiskSiz4:shr dx,1 rcr ax,1 ; shift >> 11 (1F0000h) ; ------------- decode disk size call TextAddDWord ; add size xchg ax,si ; AX <- text "MB" or "KB" call TextAddText ; add text "MB" or "KB" ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Add path separator ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; OUTPUT: BX = old or new pointer to TEXT structure ; CY = memory error ; ----------------------------------------------------------------------------- TextAddPathSep: push ax ; push AX mov al,0 ; AL <- default character call TextGetLast ; get last character -> AL cmp al,PATHCHAR ; path separator? je short TextAddPathSep2 ; separator is OK cmp al,PATHCHAR2 ; alternative path separator? je short TextAddPathSep2 ; separator is OK mov al,PATHCHAR ; AL <- path separator call TextAddChar ; add character TextAddPathSep2:pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Delete end path separator (except root) ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- TextDelPathSep: push si ; push SI mov si,[bx+TEXT_Length] ; SI <- text length cmp si,byte 2 ; check minimal length jb short TextDelPathSep2 ; leave root cmp byte [bx+TEXT_Text+si-1],PATHCHAR ; check last char je short TextDelPathSep2 ; path separator cmp byte [bx+TEXT_Text+si-1],PATHCHAR2 ; check last char jne short TextDelPathSep4 ; not path separator TextDelPathSep2:cmp byte [bx+TEXT_Text+si-2],":" ; is it root? je short TextDelPathSep4 ; root dec word [bx+TEXT_Length] ; delete last character TextDelPathSep4:pop si ; pop S ret ; ----------------------------------------------------------------------------- ; Get unsigned number from text ; ----------------------------------------------------------------------------- ; INPUT: SI = text ; CX = text length ; OUTPUT: DX:AX = number ; CY = invalid character (not digit) or overflow ; ----------------------------------------------------------------------------- ; ------------- push registers ParseInt: push bx ; push BX push cx ; push CX push si ; push SI push di ; push DI ; ------------- prepare registers xor di,di ; DI <- accumulator HIGH xor bx,bx ; BX <- accumulator LOW jcxz ParseInt9 ; no character ; ------------- load next character ParseInt2: lodsb ; AL <- character sub al,"0" ; AL <- digit jc short ParseInt9 ; invalid character cmp al,9 ; check max. value ja short ParseInt8 ; invalid character ; ------------- shift accumulator cbw ; AX <- digit xchg ax,di ; DI <- push digit, AX <- accum. HIGH mov dx,10 ; DX <- multiplier mul dx ; DX:AX <- accumulator HIGH * 10 or dx,dx ; check overflow jnz short ParseInt8 ; overflow xchg ax,di ; DI <- accumulator HIGH, AX <- digit xchg ax,bx ; AX <- accumulator LOW, BX <- digit mov dx,10 ; DX <- multiplier mul dx ; DX:AX <- accumulator LOW * 10 add bx,ax ; BX <- new accumulator LOW adc di,dx ; DI <- new accumulator HIGH jc short ParseInt9 ; error loop ParseInt2 ; next character jmp short ParseInt9 ; ------------- result ParseInt8: stc ; set error flag ParseInt9: xchg ax,bx ; AX <- accumulator LOW mov dx,di ; DX <- accumulator HIGH ; ------------- pop registers pop di ; pop DI pop si ; pop SI pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Constant data ; ----------------------------------------------------------------------------- CONST_SECTION TextKB: CTEXT "KB" TextMB: CTEXT "MB"