; pf.asm
bits 16
%define pfasm
%include "printf"

;tmpmain:
;    mov ax,600
;    push ax
;    mov ax,0xff
;    push ax
;    mov ax,buff
;    push ax
;    call dec2str
;    add sp,0x06
;    mov bx,buff
;    breakpoint
; dst src size
;   mov ax,0x0005
;   push ax
;   mov ax,string
;   push ax
;   mov ax,buff
;   push ax
;   call Move
;   mov bx,buff
;   breakpoint
;   mov ax,0xfe99
;   pf "Number is 0x%x EOL",ax
;   breakpoint


; Sprintf :: int8 *buf -> int8 sz -> int8 *fmt -> ... -> int8
Sprintf:
   enter 0x00,0x00
   pusha

   mov di,[bp+4]     ; di=buf
   mov cx,[bp+6]     ; cx=sz
   mov si,[bp+8]     ; si=fmt
   lea bx,[bp+10]    ; bx=stack addr of arg #1

   xor dx,dx
   dec cx
 .loop:
   dec cx
   jz .end

   xor ax,ax
   lodsb
   cmp byte al,0x00
   jz .end

   cmp dl,0x01
   je .fmt

   cmp byte al,'%'
   je .percent
   stosb
   jmp .loop

 .percent:
   mov dl,0x01
   jmp .loop

 .fmt:
   xor dl,dl
   cmp al,'s'    ; %s
   je .percents
   cmp al,'d'     ; %d
   je .percentd
   cmp al,'x'     ; %x
   je .percentx
   jmp .loop

.percents:
   mov dx,[bx]
   sub bx,0x0002
   ;push bp
   ;mov bp,dx
   ;push word [bp]
   push dx
   call Length
   add sp,0x02
   ;pop bp
   push ax
   cmp ax,0x0000
   je .zero
   jmp .nozero

 .zero:
   pop dx
   xor dx,dx
   jmp .loop
   
 .nozero:
   cmp cx,ax   ; sz>len ?
   jl .less
   jmp .percents2

 .less:
   mov ax,cx
   dec ax

 .percents2:
   push ax
   push dx
   push di
   call Move
   add sp,0x06
   pop ax
   add di,ax
   sub cx,ax
   xor dx,dx
   jmp .loop

.percentd:
   mov ax,0x0001
   jmp .percentxd
.percentx:
   xor ax,ax
.percentxd:
   mov dx,[bx]
   sub bx,0x0002
   push dx
   push cx
   push di
   cmp byte al,0x00
   jz .h2s
 .d2c:
   call dec2str
   add sp,0x0006
   sub cx,ax
   add di,ax
   jmp .stub
 .h2s:
   call hex2str
   add sp,0x0006
   sub cx,0x0004
   add di,0x0004
 .stub:
   xor dx,dx
   jmp .loop

 .end:
   mov byte [di],0x00
   mov ax,0x00ff
   sub ax,cx

   popa
   leave
   ret

; Putcharrm :: int8 -> void
Putcharrm:
    enter 0x00,0x000
    push bx

    mov ax,[bp+4]
    mov ah,0x0e
    xor bx,bx
    int 0x10

    pop bx
    leave
    ret

; Putcharpm :: int8 -> void
Putcharpm:
    enter 0x00,0x00

    mov ax,[bp+4]
    out byte 0xe9,al

    leave
    ret

; hex2str :: int8 *buf -> int8 sz -> int16 num -> void
hex2str:
    enter 0x00,0x00
    pusha

    mov di,0x04
    push di
    xor ax,ax
    mov byte al,'0'
    push ax
    mov di,[bp+4]
    push di
    call Set
    add sp,0x06

    add di,0x03        ; di=dst      
    mov ax,[bp+6]
    xor bx,bx
    mov bl,al           ; bl =sz
    mov si,[bp+8]       ; si=num

    mov cx,0x04
    xor dx,dx
 .loop:
    cmp bl,0x00
    jz .end
    dec bl

    mov dx,si
    shr si,0x04
    and dx,0x0f

    cmp dl,0x09
    jg .hex

 .dec:
    add dl,0x30
    jmp .next

 .hex:
    add dl,(0x66-0x0f)

 .next:
    mov byte [di],dl
    dec di
    loop .loop

 .end:
   popa
   leave
   ret

; move :: int8 *dst -> int8 src -> int16 n -> int16
Move:
   enter 0x00,0x00
   push cx
   push di
   push si

   mov di,[bp+4]     ; di=dest
   mov si,[bp+6]     ; si=src
   mov cx,[bp+8]     ; cx=counter
   mov ax,cx

   rep movsb

   pop si
   pop di
   pop cx

   leave
   ret

; Set :: int8 *dst -> int8 ch -> int16 n -> void
Set:
   enter 0x00,0x00
   push bx
   push cx
   push di

   mov di,[bp+4]     ; di=dst
   mov bx,[bp+6]
   xor ax,ax
   mov al,bl         ; al=ch
   mov cx,[bp+8]     ; cx=count

   rep stosb

   pop di
   pop cx
   pop bx

   leave
   ret

; Length :: int8 *str -> int8
Length:
   enter 0x00,0x00
   push cx
   push di

   mov di,[bp+4]     ; di=str
   mov cx,0x00ff
   xor ax,ax
   repne scasb
   cmp cx,0x0000
   je .fail

   mov ax,0x00fe
   sub ax,cx
   and ax,0x00ff
   jmp .end

 .fail:
   mov ax,0x0000
 .end:
   pop di
   pop cx
   leave
   ret

; Printf :: int8 *fmt -> ... -> void
Printf:
   enter 0xff,0x00
   %define buf    bp-0xff
   push bx
   push cx

   mov cx,28  ; last arg is 6+(10*2)

   .loop:
      sub cx,0x0002
      cmp cx,0x0002
      je .end

      mov bx,bp
      add bx,cx
      push word [bx]
      jmp .loop
   .end:
      mov ax,0x00fe  ; (sz-1)
      push ax
      lea cx,[buf]
      push cx
      call Sprintf
      add sp,26      ; 26=args+fmt+sz+buf

      pop bx
      push cx
      call Putstring
      add sp,0x02

      xor ax,ax
      pop cx
      add sp,0x00ff
      leave
      ret

; Putstring :: int8 *str -> void
Putstring:
   enter 0x00,0x00
   push si

   mov si,[bp+4]  ; ax=str

 .loop:
   xor ax,ax
   lodsb
   cmp byte al,0x00
   je .end
   push ax
   call Putchar
   add sp,0x02
   jmp .loop

 .end:
   mov ax,0x000a
   push ax
   call Putchar
   add sp,0x02
   mov ax,0x000d
   push ax
   call Putchar
   add sp,0x02

   pop si
   xor ax,ax
   leave
   ret

; dec2str :: int8 *buf -> int8 sz -> int16 num -> int8 len
dec2str:
   enter 0x0a,0x00
   %define buf       bp-6
   %define divisor   bp-8
   %define retval    bp-9
   pusha

   mov ax,10000
   mov word [divisor],ax

   mov di,0x0005
   push di
   xor ax,ax
   mov byte al,'0'
   push ax
   lea di,[buf]
   push di
   call Set
   add sp,0x06

   lea di,[buf]
   add di,0x05
   mov byte [di],0x00

   lea di,[buf]       ; di=buf
   mov ax,[bp+6]
   xor bx,bx
   mov bl,al           ; bl =sz
   mov si,[bp+8]       ; si=num

   mov cx,0x04
   xor dx,dx

 .loop:
    cmp bl,0x00
    jz .end
    dec bl

    mov ax,si
    mov word si,[divisor]
    xor dx,dx
    div si
    mov si,dx
    add al,0x30
    and ax,0x00ff
    stosb

    mov word ax,[divisor]
    xor dx,dx
    push cx
    mov cx,10
    div cx
    pop cx
    mov word [divisor],ax
    loop .loop

 .end:
   mov ax,si
   add al,0x30
   and ax,0x00ff
   stosb

   lea di,[buf]
   mov bx,di
   xor ax,ax
   mov al,'0'
   mov cx,0x0004
   repe scasb
   mov dx,di
   sub dx,bx       ; dl = # of zeroes to remove
   jz .nozero
   dec dx
 .nozero:
   ;sub dl,bl       ; dl = # of zeroes to remove
   xor bx,bx
   mov bl,0x05
   sub bl,dl       ; bl = # bytes to copy
   mov byte [retval],bl
   mov si,di       ; si = src
   dec si
   mov di,[bp+4]   ; di = dst

   push bx
   push si
   push di
   call Move
   add sp,0x06

   popa
   xor ax,ax
   mov byte al,[retval]
   add sp,0x0a
   leave
   ret
