source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Libraries/string.asm @ 76

Last change on this file since 76 was 76, checked in by aitotat, 13 years ago

Changes to XTIDE Universal BIOS:

  • Optimizations to old string library (thanks to Krille).
File size: 18.4 KB
Line 
1; File name     :   string.asm
2; Project name  :   String library
3; Created date  :   7.10.2009
4; Last update   :   20.12.2009
5; Author        :   Tomi Tilli,
6;               :   Krille (optimizations)
7; Description   :   ASM library to work as Standard C String and Character.
8
9;--------------- Equates -----------------------------
10
11; String library function to include
12;%define USE_STR_ISCHAR
13;%define USE_STR_ISBASECHAR
14;%define USE_STR_BUFFHASCHAR
15;%define USE_STR_BUFFCMP
16;%define USE_STR_TOUINT
17;%define USE_STR_LEN
18;%define USE_STR_TOKEN
19;%define USE_STR_WITHIN
20;%define USE_STR_TOLOWER
21;%define USE_STR_TOUPPER
22
23; Special characters for strings
24STOP                EQU     0   ; String ending character
25BELL                EQU     7   ; Bell
26BS                  EQU     8   ; Backspace
27TAB                 EQU     9   ; Horizontal tab
28LF                  EQU     10  ; Line feed       \ Combine to...
29CR                  EQU     13  ; Carriage return / ...get a newline
30ESC                 EQU     27  ; ESC
31
32; Misc characters
33UARROW              EQU     24  ; Up arrow
34DARROW              EQU     25  ; Down arrow
35RARROW              EQU     26  ; Right arrow
36LARROW              EQU     27  ; Left arrow
37
38; Characters for printing boxes
39B_V                 EQU     186 ; Bold vertical border (Y-axis)
40B_H                 EQU     205 ; Bold horizontal border (X-axis)
41B_TL                EQU     201 ; Bold top left border
42B_TR                EQU     187 ; Bold top right border
43B_LR                EQU     188 ; Bold lower right border
44B_LL                EQU     200 ; Bold lower left border
45
46T_V                 EQU     179 ; Thin vertical border (Y-axis)
47T_H                 EQU     196 ; Thin horizontal border (X-axis)
48T_TL                EQU     218 ; Thin top left border
49T_TR                EQU     191 ; Thin top right border
50T_LR                EQU     217 ; Thin lower right border
51T_LL                EQU     192 ; Thin lower left border
52
53BVL_THR             EQU     199 ; Bold vert on left, Thin horiz on right (||-)
54THL_BVR             EQU     182 ; Thin horiz on left, Bold vert on right (-||)
55TVL_BHR             EQU     198 ; Thin vert on left, Bold horiz on right (|=)
56BHL_TVR             EQU     181 ; Bold horiz on left, Thin vert on right (=|)
57
58; Blocks
59MIN_BLCK            EQU     176 ; Few character pixels set
60FULL_BLCK           EQU     219 ; All character pixels set
61
62
63;-------------- Private global variables -------------
64; Section containing initialized data
65;SECTION .data
66
67
68;-------------- Public functions ---------------------
69; Section containing code
70SECTION .text
71
72;--------------------------------------------------------------------
73; Checks if character is some type of character.
74; 
75; String_IsAlphaNum (checks if alphanumeric letter, isalnum on C)
76; String_IsAlpha (checks if alphabetic letter, isalpha on C)
77; String_IsDigit (checks if decimal digit, isdigit on C)
78; String_IsLower (checks if lowercase letter, islower on C)
79; String_IsSpace (checks if any space character, isspace on C)
80; String_IsUpper (checks if uppercase letter, isupper on C)
81; String_IsHexDigit (checks if hexadecimal digit, isxdigit on C)
82;   Parameters:
83;       AL:     Character to check
84;   Returns:
85;       CF:     Set if character is the type to check
86;               Cleared if character is not the type to check
87;   Corrupts registers:
88;       Nothing
89;--------------------------------------------------------------------
90%ifdef USE_STR_ISCHAR
91ALIGN JUMP_ALIGN
92String_IsAlphaNum:
93    call    String_IsAlpha
94    jnc     SHORT String_IsDigit
95    ret
96
97ALIGN JUMP_ALIGN
98String_IsAlpha:
99    call    String_IsLower
100    jnc     SHORT String_IsUpper
101    ret
102
103ALIGN JUMP_ALIGN
104String_IsDigit:
105    cmp     al, '0'             ; At least first dec digit?
106    jb      _String_IsRetFalse  ;  If not, return FALSE
107    cmp     al, '9'+1           ; At most last dec digit?
108    ret
109
110ALIGN JUMP_ALIGN
111String_IsLower:
112    cmp     al, 'a'             ; At least first lower case letter?
113    jb      _String_IsRetFalse  ;  If not, return FALSE
114    cmp     al, 'z'+1           ; At most last lower case letter?
115    ret
116
117ALIGN JUMP_ALIGN
118String_IsSpace:
119    cmp     al, ' '+1           ; Space or non-visible character?
120    ret
121
122ALIGN JUMP_ALIGN
123String_IsUpper:
124    cmp     al, 'A'             ; At least first upper case letter?
125    jb      _String_IsRetFalse  ;  If not, return FALSE
126    cmp     al, 'Z'+1           ; At most last upper case letter?
127    ret
128
129ALIGN JUMP_ALIGN
130String_IsHexDigit:
131    call    String_IsAlphaNum   ; Is alphabetic letter or digit?
132    jc      .CheckHex           ;  If so, jump to check A...F
133    ret
134.CheckHex:
135    push    ax                  ; Store character
136    call    String_ToLower      ; Convert to lower case letter
137    cmp     al, 'f'+1           ; Last valid hex alphanumeric?
138    pop     ax                  ; Restore character
139    ret
140
141ALIGN JUMP_ALIGN
142_String_IsRetFalse:
143    clc                         ; Clear CF since false
144    ret
145%endif ; USE_STR_ISCHAR
146
147
148;--------------------------------------------------------------------
149; Checks if character belongs to specified numeric base.
150; 
151; String_IsBaseChar
152;   Parameters:
153;       AL:     Character to check
154;       CL:     Numeric base (10=dec, 16=hex etc.)
155;   Returns:
156;       AH:     Integer value for character
157;       CF:     Set if character belongs to base
158;               Set if character does not belong to base
159;   Corrupts registers:
160;       Nothing
161;--------------------------------------------------------------------
162%ifdef USE_STR_ISBASECHAR
163ALIGN JUMP_ALIGN
164String_IsBaseChar:
165    mov     ah, al              ; Copy char to AH
166    call    String_IsDigit      ; Is '0'...'9'?
167    jc      .ConvertDigit       ;  If so, jump to convert
168    call    String_IsAlpha      ; Is alphabetic letter?
169    jnc     .RetFalse           ;  If not, return FALSE
170    call    String_ToLower      ; Convert to lower case
171    xchg    al, ah              ; Converted char to AH
172    sub     ah, 'a'-10          ; From char to integer: a=10, b=11...
173    cmp     ah, cl              ; Belongs to base?
174    jae     .RetFalse           ; If not, return FALSE
175    stc                         ; Set CF since belongs to base
176    ret
177ALIGN JUMP_ALIGN
178.ConvertDigit:
179    sub     ah, '0'             ; Convert char to integer
180    cmp     ah, cl              ; Belongs to base?
181    jae     .RetFalse           ; If not, return FALSE
182    stc                         ; Set CF since belongs to base
183    ret
184ALIGN JUMP_ALIGN
185.RetFalse:
186    clc                         ; Clear CF since char doesn't belong to b
187    ret
188%endif
189
190
191;--------------------------------------------------------------------
192; Finds first occurrence of character from buffer (memchr on C).
193; 
194; String_BuffHasChar
195;   Parameters:
196;       AL:     Character to check
197;       CX:     Buffer length in bytes (1...65535, 0 clears CF)
198;       ES:DI:  Pointer to buffer
199;   Returns:
200;       AX:     Index of character in buffer (if char found)
201;       ES:BX:  Pointer to character location (if char found)
202;       CF:     Set if character found
203;               Cleared if character not found
204;   Corrupts registers:
205;       Nothing
206;--------------------------------------------------------------------
207%ifdef USE_STR_BUFFHASCHAR
208ALIGN JUMP_ALIGN
209String_BuffHasChar:
210    jcxz    .Return             ; Check length so no need to initialise ZF
211    push    di                  ; Store offset to buffer
212times 2 push    cx              ; Store CX         
213    cld                         ; Set SCASB to increment DI
214    repne scasb                 ; Compare bytes to AL until found or CX=0
215    jne     .CharNotFound       ; Character not found, return FALSE
216
217    ; Character found
218    pop     ax                  ; Pop buffer length
219    sub     ax, cx              ; Subtract number of chars left
220    dec     ax                  ; Number of chars scanned to found index
221    lea     bx, [di-1]          ; Load character offset to BX
222    pop     cx                  ; Restore CX
223    pop     di                  ; Restore DI
224    stc                         ; Set CF since char found
225    ret
226.CharNotFound:
227times 2 pop cx                  ; Restore CX
228    pop     di                  ; Restore DI
229.Return:
230    clc                         ; Clear CF since char not found
231    ret
232%endif
233
234
235;--------------------------------------------------------------------
236; Compares two buffers (memcmp on C).
237; 
238; String_BuffCmp
239;   Parameters:
240;       CX:     Buffer length in bytes (1...65535, 0 clears ZF)
241;       DS:SI:  Pointer to buffer 1
242;       ES:DI:  Pointer to buffer 2
243;   Returns:
244;       AX:     Index of unequal character (if buffers are not equal)
245;       ZF:     Set if buffers are equal
246;               Cleared if buffers are not equal
247;   Corrupts registers:
248;       Nothing
249;--------------------------------------------------------------------
250%ifdef USE_STR_BUFFCMP
251ALIGN JUMP_ALIGN
252String_BuffCmp:
253    jcxz    .ReturnUnequal      ; Check length so no need to initialise ZF
254    push    di                  ; Store offset to buffer 2
255    push    si                  ; Store offset to buffer 1
256times 2 push    cx              ; Store CX         
257    cld                         ; Set CMPSB to increment SI and DI
258    repe cmpsb                  ; Compare bytes until not equal or CX=0
259    jne     .BuffersUnequal     ; Unequal byte found, return FALSE
260    times 2 pop cx              ; Restore CX
261    pop     si                  ; Restore SI
262    pop     di                  ; Restore DI
263    ret
264.BuffersUnequal:
265    pop     ax                  ; Pop buffer length
266    sub     ax, cx              ; Subtrack number of chars left
267    dec     ax                  ; Number of chars compared to unequal idx
268    xor     cx, cx              ; Zero CX
269    dec     cx                  ; ZF=0
270    pop     cx                  ; Restore CX
271    pop     si                  ; Restore SI
272    pop     di                  ; Restore DI
273    ret
274.ReturnUnequal:
275    xor     ax, ax              ; Zero AX
276    dec     ax                  ; AX = FFFFh, ZF=0
277    ret
278%endif
279
280
281;--------------------------------------------------------------------
282; Converts a string buffer to unsigned 32-bit integer.
283; 
284; String_BuffToUInt
285;   Parameters:
286;       ES:DI:  Pointer to string buffer to convert
287;       CX:     Base (10=dec, 16=hex etc.)
288;       SI:     Buffer length in characters
289;   Returns:
290;       DX:AX:  32-bit unsigned integer
291;       CF:     Set if converted successfully
292;               Cleared if error
293;   Corrupts registers:
294;       Nothing
295;--------------------------------------------------------------------
296%ifdef USE_STR_TOUINT
297ALIGN JUMP_ALIGN
298String_BuffToUInt:
299    ; Copy ES:DI to DS:SI
300    push    ds                  ; Store DS
301    push    si                  ; Store SI
302    push    di                  ; Store DI
303    push    bx                  ; Store BX
304    xchg    si, di              ; Offset to SI, lenght to DI
305    push    es
306    pop     ds
307
308    ; Prepare to read chars
309    xor     dx, dx              ; Zero DX (HIWORD)
310    xor     bx, bx              ; Zero BX (LOWORD)
311ALIGN JUMP_ALIGN
312.CharLoop:
313    lodsb                       ; Load char to AL
314    call    String_IsBaseChar   ; Is valid character? (AH=digit)
315    jnc     .RetFalse           ;  If not, return FALSE
316    xchg    ax, bx              ; AX=LOWORD, BX=digit and char
317    call    Math_MulDWbyW       ; DX:AX *= CX
318    xchg    ax, bx              ; AX=digit and char, BX=LOWORD
319    mov     al, ah              ; Copy digit to AL
320    xor     ah, ah              ; Zero AH, AX=digit
321    add     bx, ax              ; Add digit to LOWORD
322    adc     dx, 0               ; Add carry to HIWORD
323    dec     di                  ; Decrement characters left
324    jnz     .CharLoop           ; Loop while characters left
325
326    mov     ax, bx              ; Copy loword to AX
327    pop     bx                  ; Restore BX
328    pop     di                  ; Restore DI
329    pop     si                  ; Restore SI
330    pop     ds                  ; Restore DS
331    stc                         ; Set CF since success
332    ret
333ALIGN JUMP_ALIGN
334.RetFalse:
335    mov     ax, bx              ; Copy (likely incomplete) loword to AX
336    pop     bx                  ; Restore BX
337    pop     di                  ; Restore DI
338    pop     si                  ; Restore SI
339    pop     ds                  ; Restore DS
340    clc                         ; Clear CF since error
341    ret
342%endif
343
344
345;--------------------------------------------------------------------
346; Returns string lenght. Strings must end to STOP character (strlen on C).
347; 
348; String_StrLen
349;   Parameters:
350;       ES:DI:  Pointer to string
351;   Returns:
352;       AX:     String length in characters excluding STOP char
353;       CF:     Set if STOP character was found
354;               Cleared if STOP character was not found
355;   Corrupts registers:
356;       Nothing
357;--------------------------------------------------------------------
358%ifdef USE_STR_LEN
359ALIGN JUMP_ALIGN
360String_StrLen:
361    push    cx                  ; Store CX
362    mov     al, STOP            ; Load string end char to AL
363    mov     cx, -1              ; Scan for maximum string length
364    call    String_BuffHasChar  ; Find offset for string ending char
365    pop     cx                  ; Restore CX
366    ret
367%endif
368
369
370;--------------------------------------------------------------------
371; Returns length for token string. Token strings ends to any whitespace
372; character or to STOP.
373; 
374; String_TokenLen
375;   Parameters:
376;       ES:DI:  Pointer to token string
377;   Returns:
378;       AX:     Token length in characters
379;   Corrupts registers:
380;       Nothing
381;--------------------------------------------------------------------
382%ifdef USE_STR_TOKEN
383ALIGN JUMP_ALIGN
384String_TokenLen:
385    push    bx                  ; Store BX
386    xor     bx, bx              ; Zero BX for token length
387ALIGN JUMP_ALIGN
388.CharLoop:
389    mov     al, [es:di+bx]      ; Load character to AL
390    cmp     al, STOP            ; End of token?
391    je      .Return             ;  If so, return
392    call    String_IsSpace      ; End of token?
393    jc      .Return             ;  If so, return
394    inc     bx                  ; Increment token length
395    jmp     .CharLoop           ; Loop while characters left
396ALIGN JUMP_ALIGN
397.Return:
398    mov     ax, bx              ; Copy string length to AX
399    pop     bx                  ; Restore BX
400    ret
401%endif
402
403
404;--------------------------------------------------------------------
405; Returns index and ptr to first occurrence of
406; string 2 in string 1 (strstr on C).
407; Strings must be STOP terminated strings.
408; 
409; String_StrWithin
410;   Parameters:
411;       DS:SI:  Pointer to string 1
412;       ES:DI:  Pointer to string 2
413;   Returns:
414;       AX:     Index to first occurrence of string 2 in string 1
415;       DS:BX:  Pointer to first occurrence of string 2 in string 1
416;       CF:     Set if string 2 was found in string 1
417;               Cleared if string 2 was not found
418;   Corrupts registers:
419;       Nothing
420;--------------------------------------------------------------------
421%ifdef USE_STR_WITHIN
422ALIGN JUMP_ALIGN
423String_StrWithin:
424    push    cx                  ; Store CX
425    push    si                  ; Store SI
426    call    String_StrLen       ; Load str2 length to AX
427    mov     cx, ax              ; Copy str2 length to CX
428
429ALIGN JUMP_ALIGN
430.Str1CharLoop:
431    cmp     BYTE [si], STOP     ; End of string?
432    je      .Str2NotFound       ;  If so, return FALSE
433    call    String_BuffCmp      ; str2 found in str1?
434    je      .Str2Found          ;  If so, break loop
435    add     si, ax              ; Add index to first unmatching char
436    inc     si                  ; Increment str1 ptr
437    jmp     .Str1CharLoop       ; Loop while characters left
438
439ALIGN JUMP_ALIGN
440.Str2Found:
441    mov     bx, si              ; Copy ptr to BX
442    mov     ax, si              ; Copy ptr to AX
443    pop     si                  ; Restore SI
444    pop     cx                  ; Restore CX
445    sub     ax, si              ; Calculate index to str2 in str1
446    stc                         ; Set CF since str2 found
447    ret
448ALIGN JUMP_ALIGN
449.Str2NotFound:
450    xor     bx, bx              ; Zero BX
451    pop     si                  ; Restore SI
452    pop     cx                  ; Restore CX
453    clc                         ; Clear CF since str2 was not found
454    ret
455%endif
456
457
458;--------------------------------------------------------------------
459; Returns pointer to wanted token inside STOP terminated string.
460; Tokens are separated by any white space characters.
461; 
462; String_StrToken
463;   Parameters:
464;       CX:     Index of token to return
465;       ES:DI:  Pointer to string
466;   Returns:
467;       AX:     Token string length (if token found)
468;       ES:DI:  Pointer to token (if token found)
469;       CF:     Set if token found
470;               Cleared if token not found
471;   Corrupts registers:
472;       Nothing
473;--------------------------------------------------------------------
474%ifdef USE_STR_TOKEN
475ALIGN JUMP_ALIGN
476String_StrToken:
477    push    cx                  ; Store CX
478    push    si                  ; Store SI
479    push    ds                  ; Store DS
480    push    es                  ; Copy ES:DI to DS:SI
481    pop     ds
482    mov     si, di
483    inc     cx                  ; Increment to number of tokens to search
484    cld                         ; LODSB to increment SI
485ALIGN JUMP_ALIGN
486.ConsumeWhite:
487    lodsb                       ; Load char to AL from [DS:SI]
488    cmp     al, STOP            ; End of string?
489    je      .NotFound           ;  If so, token was not found
490    call    String_IsSpace      ; Any whitespace character?
491    jc      .ConsumeWhite       ;  If so, skip it
492    dec     si                  ; Decrement SI to point first non-space
493    mov     di, si              ; Copy offset to token to DI
494ALIGN JUMP_ALIGN
495.TokenLoop:
496    lodsb                       ; Load char to AL
497    cmp     al, STOP            ; End of string?
498    je      .EndOfString        ;  If so, end token
499    call    String_IsSpace      ; Any whitespace character?
500    jnc     .TokenLoop          ;  If not, loop
501    loop    .ConsumeWhite       ; Loop until wanted token found
502.RetToken:
503    pop     ds                  ; Restore DS
504    pop     si                  ; Restore SI
505    pop     cx                  ; Restore CX
506    call    String_TokenLen     ; Get token length to AX
507    stc                         ; Set CF since token found
508    ret
509ALIGN JUMP_ALIGN
510.EndOfString:
511    dec     si                  ; Offset to STOP
512    cmp     di, si              ; STOP only char in token?
513    je      .NotFound           ;  If so, then it is not valid token
514    loop    .NotFound           ; If last token was not wanted
515    jmp     .RetToken
516ALIGN JUMP_ALIGN
517.NotFound:
518    pop     ds                  ; Restore DS
519    pop     si                  ; Restore SI
520    pop     cx                  ; Restore CX
521    clc                         ; Clear CF since token not found
522    ret
523%endif
524
525
526;--------------------------------------------------------------------
527; Converts a STOP terminated string to unsigned 32-bit integer.
528; 
529; String_StrToUInt
530;   Parameters:
531;       ES:DI:  Pointer to string to convert
532;       CX:     Base (10=dec, 16=hex etc.)
533;   Returns:
534;       DX:AX:  32-bit unsigned integer
535;       CF:     Set if converted successfully
536;               Cleared if error
537;   Corrupts registers:
538;       Nothing
539;--------------------------------------------------------------------
540%ifdef USE_STR_TOUINT
541ALIGN JUMP_ALIGN
542String_StrToUInt:
543    push    si
544    call    String_StrLen       ; Get string length to AX
545    mov     si, ax              ; Copy length to SI
546    call    String_BuffToUInt   ; Convert to integer in DX:AX
547    pop     si
548    ret
549%endif
550%if 0
551String_StrToUInt:       ; Faster but we want to minimize size
552    ; Copy ES:DI to DS:SI
553    push    ds                  ; Store DS
554    push    si                  ; Store SI
555    push    bx                  ; Store BX
556    mov     si, di              ; Copy ES:DI to DS:SI
557    push    es
558    pop     ds
559
560    ; Prepare to read chars
561    xor     dx, dx              ; Zero DX (HIWORD)
562    xor     bx, bx              ; Zero BX (LOWORD)
563ALIGN JUMP_ALIGN
564.CharLoop:
565    lodsb                       ; Load char to AL
566    cmp     al, STOP            ; End of string?
567    je      .ConvComplete       ;  If so, break loop
568    call    String_IsBaseChar   ; Is valid character? (AH=digit)
569    jnc     .RetFalse           ;  If not, return FALSE
570    xchg    ax, bx              ; AX=LOWORD, BX=digit and char
571    call    Math_MulDWbyW       ; DX:AX *= CX
572    xchg    ax, bx              ; AX=digit and char, BX=LOWORD
573    mov     al, ah              ; Copy digit to AL
574    xor     ah, ah              ; Zero AH, AX=digit
575    add     bx, ax              ; Add digit to LOWORD
576    adc     dx, 0               ; Add carry to HIWORD
577    jmp     .CharLoop           ; Loop while valid characters
578ALIGN JUMP_ALIGN
579.ConvComplete:
580    mov     ax, bx              ; Copy loword to AX
581    pop     bx                  ; Restore BX
582    pop     si                  ; Restore SI
583    pop     ds                  ; Restore DS
584    stc                         ; Set CF since success
585    ret
586ALIGN JUMP_ALIGN
587.RetFalse:
588    mov     ax, bx              ; Copy (likely incomplete) loword to AX
589    pop     bx                  ; Restore BX
590    pop     si                  ; Restore SI
591    pop     ds                  ; Restore DS
592    clc                         ; Clear CF since error
593    ret
594%endif
595
596
597;--------------------------------------------------------------------
598; Converts upper case character to lower case character.
599; 
600; String_ToLower
601;   Parameters:
602;       AL:     Character to convert
603;   Returns:
604;       AL:     Character with possible conversion
605;   Corrupts registers:
606;       Nothing
607;--------------------------------------------------------------------
608%ifdef USE_STR_TOLOWER
609ALIGN JUMP_ALIGN
610String_ToLower:
611    call    String_IsUpper      ; Is upper case character?
612    jnc     .Return             ;  If not, return
613    add     al, 'a'-'A'         ; Convert to lower case
614.Return:
615    ret
616%endif
617
618
619;--------------------------------------------------------------------
620; Converts lower case character to upper case character.
621; 
622; String_ToUpper
623;   Parameters:
624;       AL:     Character to convert
625;   Returns:
626;       AL:     Character with possible conversion
627;   Corrupts registers:
628;       Nothing
629;--------------------------------------------------------------------
630%ifdef USE_STR_TOUPPER
631ALIGN JUMP_ALIGN
632String_ToUpper:
633    call    String_IsLower      ; Is lower case character?
634    jnc     .Return             ;  If not, return
635    sub     al, 'a'-'A'         ; Convert to upper case
636.Return:
637    ret
638%endif
Note: See TracBrowser for help on using the repository browser.