Metropoli BBS
VIEWER: string.asm MODE: TEXT (ASCII)
include qlib.inc  ;setup
include dos.inc
include string.inc
include alloc.inc
include stdio.inc
include conio.inc
include key.inc

.data?
  ;used by sscanf & str2num
  _str2num_siz_ dd ?      ;this is how many letters str2num_* used from src
  tss db ?
  ts db 34 dup (?)
align 4
  h db ?  ;('a' or 'A') - 10
  tok dd ?     ;token pos (see strtok())
  tokend dd ?  ;token end

.code
_num2str_:
  ;eax = # to decode
  ;ebx = radix
  mov edi,offset ts+33
  mov byte ptr[edi],0
  dec edi
  mov ecx,32  ;the MAX
num2str_2:
  xor edx,edx
  div ebx
  .if dl<10
    add dl,'0'
  .else
    add dl,h
  .endif
  mov [edi],dl
  dec edi
  dec ecx
  jnz num2str_2
  .while edi!=offset ts
    mov bptr[edi],'0'
    dec edi
  .endw
  mov bptr[edi],'0'
  ret

copyit:
; esi => edi
;copies a string (and removes unneeded 0s)
  mov ebx,edi
  mov al,bptr[esi]
  .if (al=='-')
    movsb
    mov al,bptr[esi]
  .endif
  .if (al=='0')
    .while al=='0'
      lodsb
    .endw
    stosb
  .endif
  .if !al  ;the # is zero
    mov edi,ebx
    mov bptr[edi],'0'
    mov bptr[edi+1],0
    ret
  .endif
  .while al
    lodsb   ;can't use movsb : must get al loaded
    stosb
  .endw
  ret

num2str proc,a:dword,off:dword,rax:byte
  mov h,'a'-10
jumpin1::
  pushad
  xor ebx,ebx
  mov bl,rax
  .if (bl>36) || (bl<2)  ;tolerance
    mov ebx,off
    mov bptr[ebx],0
    popad
    mov eax,off
    ret
  .endif
  mov eax,a
  call _num2str_
  mov edi,off
  mov esi,offset ts
  call copyit

  popad
  mov eax,off
  ret
num2str endp

num2strc proc,a:dword,off:dword,rax:byte
  ;same as num2str except starts with capital letters when # > 9
  mov h,'A'-10
  jmp jumpin1
num2strc endp

;signed output (does not put in '+' symbol when pos)
num2strs proc,a:dword,off:dword,rax:byte
  mov h,'a'-10
jumpin2::
  pushad
  xor ebx,ebx
  mov bl,rax
  .if (bl>36) || (bl<2)  ;tolerance
    mov ebx,off
    mov bptr[ebx],0
    popad
    mov eax,off
    ret
  .endif
  mov eax,a
  .if eax & 80000000h
    neg eax
    mov tss,'-'
  .else
    mov tss,0
  .endif
@@:
  call _num2str_
  mov edi,off
  mov esi,offset ts
  .if tss
    dec esi
  .endif    
  call copyit
  popad
  mov eax,off
  ret
num2strs endp

num2strsc proc,a:dword,off:dword,rax:byte
  ;same as num2str except starts with capital letters when # > 9
  mov h,'A'-10
  jmp jumpin2
num2strsc endp

strcpy proc,s1off:dword,s2off:dword
  ;s1=s2
  pushad
  mov edi,s1off
  mov esi,s2off
  callp strlen,esi
  mov ecx,eax
  inc ecx
  rep movsb
  popad
  mov eax,s1off
  ret
strcpy endp

strcat proc,s1off:dword,s2off:dword
  ;s1=s1+s2
  pushad
  mov edi,s1off
  mov esi,s2off
  callp strlen,esi
  mov ecx,eax
  inc ecx ;include NULL
  callp strlen,edi
  add edi,eax
  rep movsb
  popad
  mov eax,s1off
  ret
strcat endp

strlen proc uses edi ecx,off:dword
  mov edi,off
  or ecx,-1  ;faster than mov ecx,-1 (2 bytes shorter)
  xor al,al
  repnz scasb
  not ecx
  dec ecx
  mov eax,ecx
  ret
strlen endp

strcmp proc,p1:dword,p2:dword
  pushad
  mov esi,p1
  mov edi,p2
@@:
  cmpsb
  ja above
  jb below
  cmp byte ptr[esi-1],0
  jnz @b
  popad
  xor eax,eax
  ret
above:
  popad
  mov eax,1   ;p1 > p2
  ret
below:
  popad
  or eax,-1    ;p1 < p2
  ret
strcmp endp

;this is atol!!
str2num proc,s:dword
  local _neg:byte
  pushad
  mov esi,s
  dec esi
@@:
  inc esi
  cmp bptr[esi],0
  jz bad
  cmp bptr[esi],'+'
  jz start
  cmp bptr[esi],'-'
  jz start
  cmp bptr[esi],'0'
  jb @b
  cmp bptr[esi],'9'
  ja @b
  jmp start
bad:
  popad
  mov _str2num_siz_,0
  xor eax,eax
  ret
start:
  mov _neg,0
  .if bptr[esi]=='-'
    inc _neg
    inc esi
  .elseif bptr[esi]=='+'
    inc esi ;ignore it
  .endif
  xor ebx,ebx
  mov edi,esi
  dec edi
@@:
  cmp bptr[esi],0
  jz cont
  cmp bptr[esi],'0'
  jb cont
  cmp bptr[esi],'9'
  ja cont
  inc esi
  inc bl
  jmp @b
cont:
  cmp bl,10
  ja bad ;to many digits!
  cmp bl,0
  jz bad ;no digits (could happen eg: + w/o any #s )
  dec esi
  mov _str2num_siz_,esi
  mov eax,s
  sub _str2num_siz_,eax
  inc _str2num_siz_  ;total size!
  ;go till esi=edi
  mov ebx,1
  xor ecx,ecx  ;total
@@:
  xor eax,eax
  mov al,[esi]
  sub al,'0'
  mul ebx
  add ecx,eax
  mov eax,10
  mul ebx
  mov ebx,eax
  dec esi
  cmp esi,edi
  jnz @b
done:
  mov eax,ecx
  .if _neg
    neg eax
  .endif
  mov [esp+7*4],eax
  popad
  ret
str2num endp

;this is atoh???  Hex version
str2numx proc,s:dword
  pushad
  mov esi,s
@@:
  mov ax,[esi]
  cmp al,0
  jz bad
  .if ax=='x0' || ax=='X0'   ;these are 0x and 0X
    add esi,2
    jmp @b
  .endif
  .if (al>='0') && (al<='9')
    jmp start
  .endif
  .if (al>='A') && (al<='F')
    jmp start
  .endif
  .if (al>='a') && (al<='f')
    jmp start
  .endif
  inc esi
  jmp @b
bad:
  popad
  mov _str2num_siz_,0
  xor eax,eax
  ret
start:
  xor bl,bl
  mov edi,esi
  dec edi
@@:
  cmp bl,8
  ja bad     ;to many digits!
  mov al,[esi]
  cmp bptr[esi],0
  jz cont
  .if (al>='A') && (al<='F')
    inc bl
    inc esi
    jmp @b
  .endif
  .if (al>='a') && (al<='f')
    inc bl
    inc esi
    jmp @b
  .endif
  .if (al>='0') && (al<='9')
    inc bl
    inc esi
    jmp @b
  .endif
cont:
  cmp bl,0
  jz bad     ;no digits
  mov _str2num_siz_,esi      ; # chars used (including white chars)
  mov eax,s
  sub _str2num_siz_,eax
  dec esi
;go till esi=edi
  xor cl,cl    ;shift #
  xor edx,edx  ;total
@@:
  xor eax,eax
  mov al,[esi]
  .if (al>='A') && (al<='F')
    add al,'a'-'A'
  .endif
  .if (al>='0') && (al<='9')
    sub al,'0'
  .endif
  .if (al>='a') && (al<='f')
    sub al,'a'-10              ;FIX v2.05 Beta #1 : was 'a'+10
  .endif
  shl eax,cl
  add edx,eax
  add cl,4
  dec esi
  cmp esi,edi
  jnz @b
done:
  mov [esp+7*4],edx  ;save EAX for ret
  popad
  ret
str2numx endp

;binary version
str2numb proc,s:dword
  pushad
  mov esi,s
@@:
  mov al,bptr[esi]
  cmp bptr[esi],0
  jz bad
  .if al=='0' || al=='1'
    jmp start
  .endif
  inc esi
  jmp @b
bad:
  popad
  mov _str2num_siz_,0
  xor eax,eax
  ret
start:
  xor ebx,ebx
  mov edi,esi
  dec edi ;go till here
@@:
  cmp bl,32
  ja bad ;to many digits!
  cmp bptr[esi],0
  jz cont
  cmp bptr[esi],'0'
  jb cont
  cmp bptr[esi],'1'
  ja cont
  inc esi
  inc bl
  jmp @b
cont:
  cmp bl,0
  jz bad ;no digits
  mov _str2num_siz_,esi
  mov eax,s
  sub _str2num_siz_,eax
  dec esi
 ;go till esi=edi
  mov ebx,1
  xor ecx,ecx  ;total
@@:
  xor eax,eax
  mov al,[esi]
  sub al,'0'
  mul ebx
  add ecx,eax
  mov eax,2
  mul ebx
  mov ebx,eax
  dec esi
  cmp esi,edi
  jnz @b
done:
  mov [esp+7*4],ecx  ;save eax
  popad
  ret
str2numb endp

;this is atoo???  Octal version
str2numo proc,s:dword
  pushad
  mov esi,s
@@:
  mov al,bptr[esi]
  cmp al,0
  jz bad
  .if (al>='0') && (al<='7')
    jmp start
  .endif
  inc esi
  jmp @b
bad:
  popad
  mov _str2num_siz_,0
  xor eax,eax
  ret
start:
  xor bl,bl
  mov edi,esi
  dec edi
@@:
  cmp bl,8
  ja bad     ;to many digits!
  mov al,[esi]
  cmp bptr[esi],0
  jz cont
  .if (al>='0') && (al<='7')
    inc bl
    inc esi
    jmp @b
  .endif
cont:
  cmp bl,0
  jz bad     ;no digits
  dec esi
  mov _str2num_siz_,esi
  mov eax,s
  sub _str2num_siz_,eax
  inc _str2num_siz_
  ;go till esi=edi
  mov ebx,1
  xor ecx,ecx  ;total
@@:
  xor eax,eax
  mov al,[esi]
  .if (al>='0') && (al<='7')
    sub al,'0'
  .endif
  mul ebx
  add ecx,eax
  mov eax,8
  mul ebx
  mov ebx,eax
  dec esi
  cmp esi,edi
  jnz @b
done:
  mov [esp+7*4],ecx  ;save EAX for ret
  popad
  ret
str2numo endp

strchr proc uses edi ecx,s1:dword,c1:byte
  mov edi,s1
  callp strlen,edi
  mov ecx,eax
  mov al,c1
  repnz scasb
  .if zero?
    dec edi    ;go back to c1
    mov eax,edi
    ret
  .endif
  xor eax,eax  ;else ret NULL
  ret
strchr endp

strcspn proc,s1:dword,s2:dword
  local pos:dword
  pushad
  mov edx,s2
  mov edi,edx
  mov esi,s1
  callp strlen,edi
  mov ebx,eax
  inc ebx  ;must count NULL too
  mov pos,0
@@:
  mov ecx,ebx
  lodsb
  repnz scasb
  .if zero?
    popad
    mov eax,pos
    ret
  .endif
  inc pos
  mov edi,edx
  jmp @b
strcspn endp

strspn proc,s1:dword,s2:dword
  local pos:dword
  pushad
  mov edx,s2
  mov edi,edx
  mov esi,s1
  callp strlen,edi
  mov ebx,eax
  inc ebx  ;must count NULL too
  mov pos,0
@@:
  mov ecx,ebx
  lodsb
  repnz scasb
  .if !zero?
    popad
    mov eax,pos
    ret
  .endif
  inc pos
  mov edi,edx
  jmp @b
strspn endp

strdup proc,s1:dword
  callp strlen,s1
  inc eax  ;for NULL
  callp malloc,eax
  .if eax==NULL
    ret
  .endif
  callp strcpy,eax,s1    ;will return eax
  ret
strdup endp

strlwr proc uses esi edi ecx,s1:dword
  callp strlen,s1
  mov esi,s1
  mov edi,esi
  mov ecx,eax
@@:
  lodsb
  .if (al>='A') && (al<='Z')
    add al,'a'-'A'  ;lower it
    mov [edi],al
  .endif
  inc edi
  dec ecx
  jnz @b
  mov eax,s1
  ret
strlwr endp

strupr proc uses esi edi ecx,s1:dword
  callp strlen,s1
  mov esi,s1
  mov edi,esi
  mov ecx,eax
@@:
  lodsb
  .if (al>='a') && (al<='z')
    add al,'A'-'a'  ;capitilize
    mov [edi],al
  .endif
  inc edi
  dec ecx
  jnz @b
  mov eax,s1
  ret
strupr endp

strpbrk proc,s1:dword,s2:dword
  local pos:dword
  pushad
  mov edi,s2
  mov esi,s1
  callp strlen,edi
  mov ebx,eax
  callp strlen,esi
  mov edx,eax
;  inc ebx  ;DO NOT count NULL
  mov pos,0
@@:
  mov ecx,ebx
  lodsb
  repnz scasb
  .if zero?
    popad
    mov eax,pos
    add eax,s1
    ret
  .endif
  inc pos
  mov edi,s2
  dec edx
  jnz @b
  popad
  xor eax,eax
  ret
strpbrk endp

strrchr proc uses edi ecx,s1:dword,c1:byte
  mov edi,s1
  callp strlen,edi
  mov ecx,eax
  mov al,c1
  std
  repnz scasb
  .if zero?
    inc edi    ;go back to c1
    mov eax,edi
    ret
  .endif
  cld
  xor eax,eax  ;else ret NULL
  ret
strrchr endp

strrev proc,s1:dword
  pushad
  mov esi,s1
  callp strlen,esi
  .if !eax
    popad
    ret
  .endif
  mov edi,s1
  add edi,eax
  mov ecx,eax
  shr ecx,1
@@:
  mov al,[esi]
  mov ah,[edi]
  mov [esi],ah
  mov [edi],al
  inc esi
  dec edi
  dec ecx
  jnz @b
  popad
  mov eax,s1
  ret
strrev endp

strset proc uses edi ecx,s1:dword,c1:byte
  mov edi,s1
  callp strlen,edi
  mov ecx,eax
  mov al,c1
  rep stosb
  mov eax,s1
  ret
strset endp

strstr proc,s1:dword,s2:dword
  pushad
  mov esi,s1
  callp strlen,esi
  mov ecx,eax
  callp strlen,s2
  mov edx,eax
@@:
  callp memcmp,esi,s2,edx
  .if !eax
    mov [esp+7*4],esi
    popad
    ret
  .endif
  inc esi
  dec ecx
  jnz @b
  popad
  xor eax,eax
  ret
strstr endp

strtok proc,s1:dword,s2:dword
  pushad
  mov edi,s1
  cmp edi,NULL
  jz get_next_tok
;find 1st token
  callp strlen,s1
  add eax,s1
  mov tokend,eax
  call find_tok
  mov [esp+7*4],eax
  popad
  ret
get_next_tok:
  mov edi,tok
  .if !edi
    popad
    xor eax,eax
    ret
  .endif
  call find_tok
  mov [esp+7*4],eax
  popad
  ret

find_tok:
  ;edi=string (s1)
  mov esi,s2
  .if !esi    ;s2 should not be NULL
    xor eax,eax
    db 0c3h  ;ret
  .endif
  .if edi > tokend
    xor eax,eax
    mov tok,eax
    db 0c3h  ;ret
  .endif
  callp strlen,esi
  mov ebx,eax
  mov edx,edi
@@:
  callp memcmp,edi,esi,ebx
  .if !eax
    mov ecx,ebx
    mov al,0
    rep stosb
    mov tok,edi  ;tok=next tok area for next time
  .else
    inc edi
    jmp @b
  .endif
@@:
;ret edi
  mov edi,edx
@@:
  .if ! bptr[edi]
    ;gotta move to next thing
    inc edi
    .if edi>tokend
      xor eax,eax
      mov tok,eax
      db 0c3h  ;ret
    .endif
    jmp @b
  .endif
  mov eax,edi
  db 0c3h  ;ret
strtok endp

;have no idea what this is for
;BC help was nohelp in explaining what it even does
;got this from BCv5.0 LIB hacks

strxfrm proc,dest:dword,src:dword,len:dword
  callp strlen,src
  .if eax>=len
    ret    ;return EAX as is
  .endif
  push eax
  inc eax
  callp memcpy,dest,src,eax
  pop eax
  ret
strxfrm endp

stricmp proc,s1:dword,s2:dword
  pushad
  mov esi,s1
  mov edi,s2
@@:
  lodsb
  .if (al>='a') && (al<='z')
    add al,'A'-'a'
  .endif
  mov bl,al
  mov al,[edi]
  inc edi
  .if (al>='a') && (al<='z')
    add al,'A'-'a'
  .endif
  cmp bl,al
  ja above
  jb below
  cmp byte ptr[esi-1],0
  jnz @b
  popad
  xor eax,eax
  ret
above:
  popad
  mov eax,1   ;p1 > p2
  ret
below:
  popad
  or eax,-1    ;p1 < p2
  ret
stricmp endp

gets proc,str1:dword  ;ADDED : v2.01
  pushad              ;FIX : v2.04 Beta #2 
@@top:
  mov edi,str1        ; this was using old key codes
@@:                   ; and so was scanf()
  callp _getch
  .if al==KB_ESC   ;ignore this line
    callp putch,'\'
    callp putch,13
    callp putch,10
    jmp @@top
  .endif
  .if al==KB_ENTER
    mov al,0
    stosb
    callp putch,10  ;print a \n
    callp putch,13  
    popad
    mov eax,str1
    ret
  .endif
  .if ((al==KB_BS) || (ax==KB_LEFT)) && (edi!=str1)
    callp putch,8
    callp putch,' '
    callp putch,8
    dec edi
    jmp @b
  .endif 
  .if (al<32)  ;don't allow certain codes
    jmp @b
  .endif
  stosb
  callp putch,al
  jmp @b
gets endp

puts proc,str1:dword  ;ADDED : v2.01
  callp print,str1
  callp putch,10
  callp putch,13
  xor eax,eax
  ret
puts endp

end
[ RETURN TO DIRECTORY ]