lib/flags: more progress + test script
This commit is contained in:
parent
44d953a322
commit
c541d5fa08
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,4 +5,5 @@
|
|||||||
/env
|
/env
|
||||||
/hexdump
|
/hexdump
|
||||||
/prtest
|
/prtest
|
||||||
|
/flagtest
|
||||||
*.o
|
*.o
|
||||||
|
|||||||
18
flagtest.s
18
flagtest.s
@ -9,9 +9,17 @@ flags:
|
|||||||
.dword 0 # value / default
|
.dword 0 # value / default
|
||||||
.byte 1 # type: <end>, bool, string, int
|
.byte 1 # type: <end>, bool, string, int
|
||||||
.byte 5 # flag length
|
.byte 5 # flag length
|
||||||
#.short 16 # help length
|
.ascii "-bool"
|
||||||
.ascii "-help"
|
|
||||||
#.ascii "prints help text"
|
.dword 0
|
||||||
|
.byte 2 # type=string
|
||||||
|
.byte 4
|
||||||
|
.ascii "-str"
|
||||||
|
|
||||||
|
.dword 0
|
||||||
|
.byte 3 # type=string
|
||||||
|
.byte 4
|
||||||
|
.ascii "-int"
|
||||||
|
|
||||||
# last flag
|
# last flag
|
||||||
.dword 0
|
.dword 0
|
||||||
@ -30,6 +38,8 @@ _start:
|
|||||||
la a0, flags
|
la a0, flags
|
||||||
call parse_flags
|
call parse_flags
|
||||||
|
|
||||||
|
|
||||||
li a7, 93 # sys_exit
|
li a7, 93 # sys_exit
|
||||||
li a0, 0
|
snez a0, a0
|
||||||
|
#li a0, 0
|
||||||
ecall
|
ecall
|
||||||
|
|||||||
39
lib/flags.s
39
lib/flags.s
@ -1,12 +1,9 @@
|
|||||||
|
|
||||||
.option norelax
|
.option norelax
|
||||||
|
.option rvc
|
||||||
.global init_flags
|
.global init_flags
|
||||||
.global parse_flags
|
.global parse_flags
|
||||||
|
|
||||||
.macro subi dst, src, imm
|
|
||||||
addi \dst, \src, -\imm
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
@ -29,9 +26,9 @@ saved_argv: .dword 0
|
|||||||
|
|
||||||
.section .rodata
|
.section .rodata
|
||||||
|
|
||||||
flag_failure_msg: .ascii "flag parsing failed\n\0"
|
flag_failure_msg: .ascii "flag parsing failed\n"
|
||||||
.equ flag_failure_msg_len, (.) - flag_failure_msg
|
.equ flag_failure_msg_len, (.) - flag_failure_msg
|
||||||
unknown_flag_msg: .ascii "unknown flag\n\0"
|
unknown_flag_msg: .ascii "unknown flag\n"
|
||||||
.equ unknown_flag_msg_len, (.) - unknown_flag_msg
|
.equ unknown_flag_msg_len, (.) - unknown_flag_msg
|
||||||
|
|
||||||
.text
|
.text
|
||||||
@ -75,6 +72,10 @@ parse_flags:
|
|||||||
tail parse_flags_args
|
tail parse_flags_args
|
||||||
# n.b. tail clobbers t1
|
# n.b. tail clobbers t1
|
||||||
|
|
||||||
|
.macro subi dst, src, imm
|
||||||
|
addi \dst, \src, -\imm
|
||||||
|
.endm
|
||||||
|
|
||||||
# a0 - flag definition struct
|
# a0 - flag definition struct
|
||||||
# a1 - argc
|
# a1 - argc
|
||||||
# a2 - argv
|
# a2 - argv
|
||||||
@ -113,6 +114,7 @@ parse_flags_args:
|
|||||||
|
|
||||||
.Ldone:
|
.Ldone:
|
||||||
mv ra, a7
|
mv ra, a7
|
||||||
|
mv a0, x0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.Lunknown_flag:
|
.Lunknown_flag:
|
||||||
@ -160,11 +162,15 @@ find_flag:
|
|||||||
1:# \0
|
1:# \0
|
||||||
# is this a boolean flag? then there's no value
|
# is this a boolean flag? then there's no value
|
||||||
beqz t3, handle_flag
|
beqz t3, handle_flag
|
||||||
# if not, set s1 to the next arg and advance s2
|
# if not, advance to the next arg
|
||||||
ld s1, 8(s2)
|
# a missing arg is an error
|
||||||
addi s2, s2, 8
|
addi s2, s2, 8
|
||||||
subi a1, a1, 1
|
subi a1, a1, 1
|
||||||
# TODO: if it's null, that's an error
|
beqz a1, .Lbadarg
|
||||||
|
# load arg into s1
|
||||||
|
# a null arg is an error
|
||||||
|
ld s1, 0(s2)
|
||||||
|
beqz s1, .Lbadarg
|
||||||
# fallthrough
|
# fallthrough
|
||||||
|
|
||||||
# s1 now points to the value of the flag
|
# s1 now points to the value of the flag
|
||||||
@ -189,7 +195,7 @@ boolflag:
|
|||||||
lbu t0, 0(s1)
|
lbu t0, 0(s1)
|
||||||
# if arg is empty, set value to true
|
# if arg is empty, set value to true
|
||||||
# TODO: should -bool and -bool= be treated differently?
|
# TODO: should -bool and -bool= be treated differently?
|
||||||
beqz t0, 0f
|
beqz t0, 1f
|
||||||
# check for "true" and "false"
|
# check for "true" and "false"
|
||||||
li t1, 'f'
|
li t1, 'f'
|
||||||
beq t0, t1, .Lboolcmpfalse
|
beq t0, t1, .Lboolcmpfalse
|
||||||
@ -200,23 +206,23 @@ boolflag:
|
|||||||
|
|
||||||
.Lboolcmpfalse:
|
.Lboolcmpfalse:
|
||||||
lbu t0, 1(s1)
|
lbu t0, 1(s1)
|
||||||
beqz t0, .Lbadbool
|
#beqz t0, .Lbadbool
|
||||||
li t1, 'a'
|
li t1, 'a'
|
||||||
bne t1, t0, .Lbadbool
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 2(s1)
|
lbu t0, 2(s1)
|
||||||
beqz t0, .Lbadbool
|
#beqz t0, .Lbadbool
|
||||||
li t1, 'l'
|
li t1, 'l'
|
||||||
bne t1, t0, .Lbadbool
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 3(s1)
|
lbu t0, 3(s1)
|
||||||
beqz t0, .Lbadbool
|
#beqz t0, .Lbadbool
|
||||||
li t1, 's'
|
li t1, 's'
|
||||||
bne t1, t0, .Lbadbool
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 4(s1)
|
lbu t0, 4(s1)
|
||||||
beqz t0, .Lbadbool
|
#beqz t0, .Lbadbool
|
||||||
li t1, 's'
|
li t1, 'e'
|
||||||
bne t1, t0, .Lbadbool
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 5(s1)
|
lbu t0, 5(s1)
|
||||||
@ -269,10 +275,11 @@ intflag:
|
|||||||
j .L_next_arg
|
j .L_next_arg
|
||||||
|
|
||||||
.Lbad_flag_def:
|
.Lbad_flag_def:
|
||||||
|
.Lbadarg:
|
||||||
.Lbadint:
|
.Lbadint:
|
||||||
.Lbadbool:
|
.Lbadbool:
|
||||||
mv ra, a7
|
mv ra, a7
|
||||||
li a7, 64
|
li a7, 64 # sys_write
|
||||||
li a0, 2
|
li a0, 2
|
||||||
la a1, flag_failure_msg
|
la a1, flag_failure_msg
|
||||||
li a2, flag_failure_msg_len
|
li a2, flag_failure_msg_len
|
||||||
|
|||||||
71
test/flags.sh
Executable file
71
test/flags.sh
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -eu
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
: ${BIN:=..}
|
||||||
|
: ${EMU:=qemu-riscv64}
|
||||||
|
|
||||||
|
cmd=$BIN/flagtest
|
||||||
|
name=flagtest
|
||||||
|
|
||||||
|
fail=0
|
||||||
|
err() {
|
||||||
|
echo "FAIL $name: $*"
|
||||||
|
fail=1
|
||||||
|
}
|
||||||
|
|
||||||
|
flagtest() {
|
||||||
|
"$EMU" "$cmd" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_fail() {
|
||||||
|
set +e
|
||||||
|
out=$(flagtest "$@" 2>&1)
|
||||||
|
if [[ "$?" -eq 0 ]]; then
|
||||||
|
err "expected command to fail: $cmd $*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_ok() {
|
||||||
|
set +e
|
||||||
|
flagtest "$@"
|
||||||
|
if [[ "$?" -ne 0 ]]; then
|
||||||
|
err "expected command to succeed: $cmd $*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# invalid
|
||||||
|
check_fail -int # missing arg
|
||||||
|
check_fail -str
|
||||||
|
check_fail -int x # invalid int
|
||||||
|
check_fail -int abc
|
||||||
|
check_fail -int 0x10 # not yet supported
|
||||||
|
check_fail -int "" # empty string is not a valid number
|
||||||
|
check_fail -int=
|
||||||
|
check_fail -xxx # invalid flag
|
||||||
|
check_fail -bool=x # invalid bool
|
||||||
|
|
||||||
|
# valid
|
||||||
|
check_ok
|
||||||
|
check_ok -bool
|
||||||
|
check_ok -bool=true
|
||||||
|
check_ok -bool=false
|
||||||
|
check_ok -int 0
|
||||||
|
check_ok -int=1
|
||||||
|
check_ok -int 987654321
|
||||||
|
check_ok -str=x
|
||||||
|
check_ok -str=
|
||||||
|
check_ok -str ""
|
||||||
|
check_ok -str -xxx # 2nd arg should be treated as a value not a flag
|
||||||
|
check_ok -str x -str y # duplicates are allowed
|
||||||
|
check_ok -int 1 -int 2
|
||||||
|
check_ok -bool -bool
|
||||||
|
check_ok X -bool Y # flags can be interspered with arguments
|
||||||
|
check_ok -bool -str x -int 1
|
||||||
|
|
||||||
|
# valid, but maybe it shouldn't be?
|
||||||
|
check_ok -bool=
|
||||||
|
|
||||||
|
# valid. and bool should not consume the "false"
|
||||||
|
# (but we don't have a way to check that just yet)
|
||||||
|
check_ok -bool false
|
||||||
Loading…
x
Reference in New Issue
Block a user