;******************************************************************************** ; @module string ; @type utility ; @details ; String utility ;******************************************************************************** .ifndef INCLUDE_STRING INCLUDE_STRING = 1 .scope str .code .macro _StrfStoreArg arg .if (.not .blank(arg)) .if .match(arg, x) stx ARG4 + @N_ARGS .elseif .match(arg, y) sty ARG4 + @N_ARGS .else lda arg sta ARG4 + @N_ARGS .endif @N_ARGS .set (@N_ARGS + 1) .endif .endmacro ;******************************************************************************** ; @function Macro for passing arguments to strf ; @param fmt: Format string address ; @param out: Output string address ; @param x0-x9: Additional parameters ; @warning Addresses as additional paramteres must be passed like this `#addr` ; @modifies: A, X, Y ; @see strf ;******************************************************************************** .macro Strf fmt,out,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9 @N_ARGS .set 0 ; @ so that it doesnt break cheap labels lda #fmt sta ARG1 lda #out sta ARG3 _StrfStoreArg x0 _StrfStoreArg x1 _StrfStoreArg x2 _StrfStoreArg x3 _StrfStoreArg x4 _StrfStoreArg x5 _StrfStoreArg x6 _StrfStoreArg x7 jsr strf .out .sprintf("info: Strf: called with %d arguments", @N_ARGS) .endmacro ; TODO allocate zp memory fmt_idx = $30 out_idx = $31 ;******************************************************************************** ; @function Format a string ; @details ; If there is no value to be read, the Pz will be set ; Formats: ; - x: unsigned hex integer (1 byte) -> 2 chars ; - X: unsigned hex integer (2 byte) -> 4 chars TODO ; - u: unsigned decimal integer (1 byte) TODO ; - U: unsigned decimal integer (2 bytes) TODO ; @param ARG0-1: Format string address ; @param ARG2-3: Output string address ; @param ARG4+: Additional parameters ; @returns ; @modifies: A, X, Y ;******************************************************************************** .proc strf stz out_idx stz fmt_idx ldy #0 ; position in string ldx #0 ; index of format args @loop: ldy fmt_idx lda (ARG0),y beq @null cmp #'%' beq @percent @normal_char: ; store A in output string ldy out_idx sta (ARG2),y inc fmt_idx inc out_idx beq @out_overflow bra @loop @percent: ; check for format in next position iny sty fmt_idx lda (ARG0),y beq @null ; formats cmp #'x' beq @format_hex1 bra @normal_char @format_hex1: ; 1 byte hex -> 2 chars lda ARG4,x phx jsr int8_to_hex_str ldy out_idx sta (ARG2),y ; most sig digit iny beq @out_overflow txa sta (ARG2),y ; least sig digit iny beq @out_overflow sty out_idx plx inx ; 1 byte of args handeled ; bra @format_return @format_return: ; increment fmt_idx to swallow the formating char inc fmt_idx bra @loop @out_overflow: ; store 0 in last position ldy #$ff sty out_idx @store_null: lda #0 @null: ; store and return ldy out_idx sta (ARG2),y @rts: rts .endproc ;******************************************************************************** ; @function Convert a 1 byte number into two hex characters ; @param A: Number to convert ; @returns A: Most significant digit ; @returns X: Least significant digit ; @modifies A,X,Y ;******************************************************************************** .proc int8_to_hex_str pha and #%00001111 tay ldx HEX_CHARS_UPPER,y pla div A,16 and #%00001111 tay lda HEX_CHARS_UPPER,y rts .endproc .rodata HEX_CHARS_UPPER: .byte "0123456789ABCDEF" HEX_CHARS_LOWER: .byte "0123456789abcdef" .export strf .endscope .endif ; guard