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

;FIX v2.00 Beta #8 : this has been heavily updated
; scanf() can now input data on multiple lines

.data
  r8 REAL8 ?  ;used in scanf %f thingy
  noscans dd ?  ;no of scans
  tns dd ?      ;total # of scans (w/ scanf())

.code
scanf proc,format:dword,vars:vararg
  ;ADDED in Ver 2.0
  local tsiz:dword  ;TOTAL size
  local asiz:dword  ;totol allocated
  local bsiz:dword  ;size of current block in use
  local hand:dword  ;memory
  bufsiz equ 1024

  pushad

  lea ebx,vars
  mov esi,format
  mov tns,0

@@top:
  mov al,[esi]
  cmp al,0
  .if zero?
    popad
    mov eax,tns
    ret
  .endif
  mov tsiz,0          ;total size (of chars inside block)
  mov asiz,bufsiz     ;actual size (of byte alloced currently)
  callp malloc,bufsiz
  .if eax==NULL
    jmp bad
  .endif
  mov hand,eax
  mov bsiz,0          ;current buffer size
@@:
  callp _getch
  .if al==KB_ENTER
    callp putch,13   ;FIX : v2.00 Beta #7 : these were needed
    callp putch,10   ; "
    mov eax,hand
    add eax,tsiz
    mov bptr[eax],0
    mov edi,hand
    call _sscanf
    push eax
    mov eax,noscans
    add tns,eax
    callp free,hand
    pop eax
    .if eax==ERROR
      jmp bad
    .endif
    jmp @@top
  .endif
  .if al==KB_ESC   ;ignore this line
    callp putch,'\'
    callp putch,13
    callp putch,10
    callp free,hand
    jmp @@top
  .endif
  .if ((al==KB_BS) || (ax==KB_LEFT)) && tsiz ;BackSpace  FIX : v2.04 Beta #2
    callp putch,8                            ; this was using old key codes
    callp putch,32                           ; and so was gets()
    callp putch,8
    dec tsiz
    jmp @b
  .endif
  .if (al>31)
    mov cl,al
    inc tsiz
    inc bsiz
    .if bsiz > bufsiz
      add asiz,bufsiz
      invoke realloc,hand,asiz
      mov hand,eax
      .if eax==ERROR
        jmp bad
      .endif
    .endif
    mov eax,hand
    add eax,tsiz
    dec eax ;pt to new loc
    mov [eax],cl
    callp putch,cl
  .endif
  jmp @b
bad:
  popad
  mov eax,tns
  ret
scanf endp

sscanf proc,buf:dword,format:dword,vars:vararg
  ;ADDED in Ver 1.1
  pushad
  mov esi,format
  mov edi,buf
  lea ebx,vars
  call _sscanf
  popad
  mov eax,noscans
  ret
sscanf endp


;in : esi=format string
;   : edi=buffer (input data)
;   : ebx=varargs
;out: noscans = no of scans successful and data filled in varargs

; seeks thru esi until hits %? and then seeks thru edi until it's not a space

_sscanf:
  mov noscans,0

  .if bptr[edi]==0
    jmp __end  ;no more data
  .endif
@@top:
  ;seek for %?
  lodsb
  cmp al,0
  jz __done
  cmp al,'%'
  jz @@per
@@per1:
  inc edi
  .if bptr[edi]==0
    jmp __end  ;no more data
  .endif
  jmp @@top
@@per:                            ; % in use
  lodsb

  .if al=='s'
    callp strcpy,dptr ss:[ebx],edi
    callp strlen,edi
    add edi,eax
    inc edi  ;there better be more stuff after the 0 if you still have more
             ;fields to fill in
    add ebx,4
    .if bptr[edi]==0
      jmp __end  ;no more data
    .endif
    jmp @@top
  .endif

  cmp al,0
  jz __done ;not enough stuff!

  cmp al,'i'
  jz @@peru
  cmp al,'u'
  jz @@peru

  cmp al,'b'
  jz @@perb
  cmp al,'d'
  jz @@perd
  cmp al,'x'
  jz @@perx
  cmp al,'X'
  jz @@perx
  cmp al,'c'
  jz @@perc
  cmp al,'o'
  jz @@pero
  cmp al,'e'
  jz @@perf
  cmp al,'f'
  jz @@perf
  jmp @@per1 ;ignore % and go on
@@peru:
@@perd:
  invoke str2num,edi
  mov ecx,ss:[ebx]
  mov [ecx],eax
  jmp addstr
@@perb:
  invoke str2numb,edi
  mov ecx,ss:[ebx]
  mov [ecx],eax
  jmp addstr
@@perx:
  invoke str2numx,edi
  mov ecx,ss:[ebx]
  mov [ecx],eax
  jmp addstr
@@pero:
  invoke str2numo,edi
  mov ecx,ss:[ebx]
  mov [ecx],eax
  jmp addstr
@@perc:
  mov ecx,ss:[ebx]
  mov al,[edi]
  mov [ecx],al
  inc edi
  add ebx,4    ;no byte pushes possible
  inc noscans
  .if bptr[edi]==0
    jmp __end  ;no more data
  .endif
  jmp @@top
@@perf:
  invoke atof,edi
  mov ecx,ss:[ebx]
  .if _math_typ
    mov [ecx],eax       ;Watcom style
    mov [ecx+4],edx     ;EAX:EDX = double
  .else
    ;borland style
    fstp r8
    fwait
    mov eax,dptr [r8]
    mov [ecx],eax
    mov eax,dptr [r8+4]
    mov [ecx+4],eax
  .endif
  .if !_str2num_siz_  ;bad conversion
    jmp __done
  .endif
  add ebx,4              ;move to next var.  ;FIX v2.00 Beta #8 : this was 8
  add edi,_str2num_siz_  ;size of last str2num call
  inc noscans
  .if bptr[edi]==0
    jmp __end  ;no more data
  .endif
  jmp @@top
__end:
  xor eax,eax
  ret
__done:
  mov eax,ERROR
  ret
addstr:
  .if !_str2num_siz_  ;bad conversion
    jmp __done
  .endif
  inc noscans
  add ebx,4      ;move to next var.
  add edi,_str2num_siz_  ;size of last str2num call
  .if bptr[edi]==0
    jmp __end  ;no more data
  .endif
  jmp @@top

end

[ RETURN TO DIRECTORY ]