; Grok printf 1.0 · pure NASM x86_64 Linux · LINEAR · NO children
; BAPHOMET · A=FORMAT B=ARGS · no invent C
; EZZIE thrift · ESSIE optional /usr/bin/printf seat under SOUL
; usage: printf FORMAT [ARG...]
; thrift formats: %% %s %c %d %i %u %x %X %o \n \t \\ \' \"
; law: free thrift · Always Hostess 7 · Always the One · always 1
        global  _start
        global  printf_fn
        global  printf

        section .bss
numbuf: resb 64
        section .data
vmsg:   db "bgrtx-printf 1.0 pure ASM · LINEAR · %s %d %x thrift · EZZIE/ESSIE/BAPHOMET · NO children",10
vlen    equ $-vmsg
umsg:   db "usage: printf FORMAT [ARG...]",10
ulen    equ $-umsg
hexlo:  db "0123456789abcdef"
hexup:  db "0123456789ABCDEF"
nl:     db 10
tab:    db 9

        section .text
printf_fn:
printf:
        mov     eax, 1
        ret

_start:
        pop     rcx                     ; argc
        pop     rax                     ; argv0
        dec     rcx
        jle     usage
        mov     rbx, rsp                ; argv
        mov     r12, [rbx]              ; format string
        add     rbx, 8
        dec     rcx                     ; remaining args
        mov     r13, rcx                ; arg count
        mov     r14, rbx                ; arg vector
        ; r15 = arg index
        xor     r15, r15

        mov     rsi, r12
.loop:
        mov     al, [rsi]
        test    al, al
        jz      .done
        cmp     al, '\'
        je      .esc
        cmp     al, '%'
        je      .fmt
        ; literal char
        call    putc
        inc     rsi
        jmp     .loop
.esc:
        inc     rsi
        mov     al, [rsi]
        test    al, al
        jz      .done
        cmp     al, 'n'
        jne     .e1
        mov     al, 10
        jmp     .eout
.e1:    cmp     al, 't'
        jne     .e2
        mov     al, 9
        jmp     .eout
.e2:    cmp     al, '\'
        je      .eout
        cmp     al, "'"
        je      .eout
        cmp     al, '"'
        je      .eout
        ; unknown escape · print as-is
.eout:  call    putc
        inc     rsi
        jmp     .loop
.fmt:
        inc     rsi
        mov     al, [rsi]
        test    al, al
        jz      .done
        cmp     al, '%'
        jne     .f1
        call    putc
        inc     rsi
        jmp     .loop
.f1:    cmp     al, 's'
        je      .fs
        cmp     al, 'c'
        je      .fc
        cmp     al, 'd'
        je      .fd
        cmp     al, 'i'
        je      .fd
        cmp     al, 'u'
        je      .fu
        cmp     al, 'x'
        je      .fx
        cmp     al, 'X'
        je      .fX
        cmp     al, 'o'
        je      .fo
        ; unknown · print % and char
        push    rax
        mov     al, '%'
        call    putc
        pop     rax
        call    putc
        inc     rsi
        jmp     .loop
.fs:    ; next arg string
        call    next_arg                ; rsi → arg in rax? use r8
        test    r8, r8
        jz      .fadv
        mov     rdi, r8
        call    puts
        jmp     .fadv
.fc:    call    next_arg
        test    r8, r8
        jz      .fadv
        mov     al, [r8]
        call    putc
        jmp     .fadv
.fd:    call    next_arg
        call    arg_to_num              ; rax = signed
        call    p_int
        jmp     .fadv
.fu:    call    next_arg
        call    arg_to_num
        call    p_uint
        jmp     .fadv
.fx:    call    next_arg
        call    arg_to_num
        mov     r9, 0                   ; lower
        call    p_hex
        jmp     .fadv
.fX:    call    next_arg
        call    arg_to_num
        mov     r9, 1
        call    p_hex
        jmp     .fadv
.fo:    call    next_arg
        call    arg_to_num
        call    p_oct
        jmp     .fadv
.fadv:  inc     rsi
        jmp     .loop
.done:
        xor     rdi, rdi
        mov     rax, 60
        syscall

; next_arg → r8 = ptr or 0 · advances r15
next_arg:
        cmp     r15, r13
        jge     .na0
        mov     r8, [r14+r15*8]
        inc     r15
        ret
.na0:   xor     r8, r8
        ret

; arg_to_num: r8 string → rax signed parse
arg_to_num:
        push    rbx
        push    rcx
        push    rdx
        push    rsi
        xor     eax, eax
        test    r8, r8
        jz      .anout
        mov     rsi, r8
        xor     ebx, ebx                ; neg
        cmp     byte [rsi], '-'
        jne     .anp
        mov     ebx, 1
        inc     rsi
.anp:   mov     ecx, 10
.anl:   mov     dl, [rsi]
        cmp     dl, '0'
        jb      .and
        cmp     dl, '9'
        ja      .and
        imul    eax, ecx
        sub     dl, '0'
        movzx   edx, dl
        add     eax, edx
        inc     rsi
        jmp     .anl
.and:   test    ebx, ebx
        jz      .anout
        neg     rax
.anout: pop     rsi
        pop     rdx
        pop     rcx
        pop     rbx
        ret

putc:
        push    rax
        push    rdi
        push    rsi
        push    rdx
        mov     [rel numbuf], al
        mov     rax, 1
        mov     rdi, 1
        lea     rsi, [rel numbuf]
        mov     rdx, 1
        syscall
        pop     rdx
        pop     rsi
        pop     rdi
        pop     rax
        ret

puts:
        push    rax
        push    rcx
        push    rdx
        push    rsi
        push    rdi
        mov     rsi, rdi
        xor     rdx, rdx
.ps:    cmp     byte [rsi+rdx], 0
        je      .pw
        inc     rdx
        jmp     .ps
.pw:    mov     rax, 1
        mov     rdi, 1
        ; rsi already
        syscall
        pop     rdi
        pop     rsi
        pop     rdx
        pop     rcx
        pop     rax
        ret

p_int:
        push    rax
        test    rax, rax
        jns     .pi
        push    rax
        mov     al, '-'
        call    putc
        pop     rax
        neg     rax
.pi:    call    p_uint
        pop     rax
        ret

p_uint:
        push    rax
        push    rbx
        push    rcx
        push    rdx
        push    rsi
        push    rdi
        lea     rsi, [rel numbuf+63]
        mov     byte [rsi], 0
        mov     rbx, 10
        test    rax, rax
        jnz     .d
        dec     rsi
        mov     byte [rsi], '0'
        jmp     .w
.d:     xor     rdx, rdx
        div     rbx
        add     dl, '0'
        dec     rsi
        mov     [rsi], dl
        test    rax, rax
        jnz     .d
.w:     mov     rdi, rsi
        call    puts
        pop     rdi
        pop     rsi
        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

p_hex:
        push    rax
        push    rbx
        push    rcx
        push    rdx
        push    rsi
        push    rdi
        lea     rsi, [rel numbuf+63]
        mov     byte [rsi], 0
        test    rax, rax
        jnz     .h
        dec     rsi
        mov     byte [rsi], '0'
        jmp     .hw
.h:     mov     rbx, 16
.hl:    xor     rdx, rdx
        div     rbx
        test    r9, r9
        jnz     .hu
        lea     rcx, [rel hexlo]
        jmp     .hd
.hu:    lea     rcx, [rel hexup]
.hd:    mov     dl, [rcx+rdx]
        dec     rsi
        mov     [rsi], dl
        test    rax, rax
        jnz     .hl
.hw:    mov     rdi, rsi
        call    puts
        pop     rdi
        pop     rsi
        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

p_oct:
        push    rax
        push    rbx
        push    rdx
        push    rsi
        push    rdi
        lea     rsi, [rel numbuf+63]
        mov     byte [rsi], 0
        test    rax, rax
        jnz     .o
        dec     rsi
        mov     byte [rsi], '0'
        jmp     .ow
.o:     mov     rbx, 8
.ol:    xor     rdx, rdx
        div     rbx
        add     dl, '0'
        dec     rsi
        mov     [rsi], dl
        test    rax, rax
        jnz     .ol
.ow:    mov     rdi, rsi
        call    puts
        pop     rdi
        pop     rsi
        pop     rdx
        pop     rbx
        pop     rax
        ret

usage:
        mov     rax, 1
        mov     rdi, 2
        lea     rsi, [rel umsg]
        mov     rdx, ulen
        syscall
        mov     rdi, 2
        mov     rax, 60
        syscall
