From fcd9109ef636a4afff2648d71c587e32a8905232 Mon Sep 17 00:00:00 2001 From: lexzach Date: Sun, 13 Sep 2026 16:42:39 -0400 Subject: [PATCH] Add stdin cat --- src/args.S | 27 ++++++++++++++++----------- src/file.S | 33 +++++++++++++++++++++++++++------ src/main.S | 49 +++++++++++++++++++++---------------------------- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/args.S b/src/args.S index c5009c7..c44e602 100644 --- a/src/args.S +++ b/src/args.S @@ -107,9 +107,9 @@ has_switch: mv s1, a1 call fetch_argc - bnez a0, 1f + bnez a0, .LHasSwitchNoParse li t0, 2 - blt a1, t0, 1f # if we have no commands other than the binary, we know there will be no switches + blt a1, t0, .LSwitchNotFoundNoParse # if we have no commands other than the binary, we know there will be no switches addi sp, sp, -24 sd s4, 16(sp) @@ -118,7 +118,7 @@ has_switch: li s2, 1 # load first non-base command arg mv s4, a1 # put argc in s4 - 2: + .LSwitchProcessNextArg: mv a0, s2 call fetch_argv mv s3, a1 # save argv buff addr @@ -126,32 +126,37 @@ has_switch: mv a0, s3 # load argv buff addr into a0 (string 0) mv a1, s0 # move switch ptr 1 addr into a1 (string 1) call _str_cmp - bnez a1, 5f # if the strings match, exit loop + bnez a1, .LSwitchFound # if the strings match, exit loop mv a0, s3 # move argv buff addr into a0 (string 0) mv a1, s1 # move switch ptr 2 addr into a1 (string 1) call _str_cmp - bnez a1, 5f # if the strings match, exit loop + bnez a1, .LSwitchFound # if the strings match, exit loop addi s2, s2, 1 # if string doesn't match we inc to the next arg - blt s2, s4, 2b # keep going while we have untested args + blt s2, s4, .LSwitchProcessNextArg # keep going while we have untested args - 4: + .LSwitchNotFound: li a0, 0 li a1, 0 - j 3f + j .LSwitchFreeSP - 5: + .LSwitchNotFoundNoParse: + li a0, 0 + li a1, 0 + j .LHasSwitchNoParse + + .LSwitchFound: li a0, 0 li a1, 1 - 3: + .LSwitchFreeSP: ld s3, 0(sp) ld s2, 8(sp) ld s4, 16(sp) addi sp, sp, 24 - 1: + .LHasSwitchNoParse: ld ra, 16(sp) ld s1, 8(sp) ld s0, 0(sp) diff --git a/src/file.S b/src/file.S index cac568f..97ffae8 100644 --- a/src/file.S +++ b/src/file.S @@ -2,7 +2,7 @@ cat_buf: .space 4096 .section .text -.globl cat_file, open_fd +.globl cat_file, open_fd, cat_stdin # Cat out the given file to stdout # @param[in] a0: ptr to null-terminated file str. @@ -17,12 +17,12 @@ cat_file: addi sp, sp, 8 mv t0, a1 # put fd in t0 - beqz a0, .LReadBlock # if we don't have an error, jump to reading + beqz a0, .LReadFileBlock # if we don't have an error, jump to reading li a0, 1 - j .LRet + j .LCatFileRet - .LReadBlock: + .LReadFileBlock: mv a0, t0 la a1, cat_buf li a2, 4096 @@ -35,16 +35,37 @@ cat_file: la a1, cat_buf li a7, 64 ecall - j .LReadBlock + j .LReadFileBlock .LCloseFD: mv a0, t0 li a7, 57 # close fd ecall - .LRet: + .LCatFileRet: ret +# Cat out stdin to stdout +# @param[in] a0: Not used. +# @param[out] a0: result code. +cat_stdin: + .LReadStdinBlock: + li a0, 0 + la a1, cat_buf + li a2, 4096 + li a7, 63 + ecall + blez a0, .LCatStdinRet # if we haven't read any bytes, EOF, close FD + mv a2, a0 # move bytes read into bytes needed to write + + li a0, 1 + la a1, cat_buf + li a7, 64 + ecall + j .LReadStdinBlock + + .LCatStdinRet: + ret # Open fd # @param[in] a0: ptr to null-terminated file str. diff --git a/src/main.S b/src/main.S index ca91101..badcf02 100644 --- a/src/main.S +++ b/src/main.S @@ -10,6 +10,7 @@ file_err: .asciz ": No such file or directory\n" help: .ascii "Usage: cat [OPTION]... [FILE]...\n" .ascii "Concatenate FILE(S) to standard output.\n\n" + .ascii "With no FILE, or when FILE is -, read standard input.\n\n" .ascii " -h, --help | Show this help page.\n\n" .asciz "Written by lexzach in RISC-V assembly: \n" .equ HELP_LEN, . - help @@ -29,45 +30,37 @@ _start: call save_sp call fetch_argc - li t0, 1 - ble a1, t0, .Lreturn_err # return 1 if no args mv s0, a1 # store argc li s1, 1 la a0, flag_h la a1, flag_help call has_switch - bnez a0, .Lreturn_err - beqz a1, .Lskip_disp_help + bnez a0, .LMainReturnErr + beqz a1, .LSkipDispHelp call _disp_help - j .Lreturn_ok - .Lskip_disp_help: + j .LMainReturnOk + .LSkipDispHelp: - - # 5: #iterate through and check that all files exist first - # mv a0, s1 - # call fetch_argv - # bnez a0, 1f # error if failed - # mv a0, a1 - # call file_exists - # bnez a0, 4f - # addi s1, s1, 1 - # blt s1, s0, 5b - - # li s1, 1 # reset counter now that we've verified all files exist, skip command - - .Lprocess_file: + li t0, 1 + ble s0, t0, .LProcessStdin # return 1 if no args + + .LProcessFile: mv a0, s1 call fetch_argv - bnez a0, .Lreturn_err # error if failed + bnez a0, .LMainReturnErr # error if failed mv a0, a1 call cat_file - bnez a0, .Lreturn_file_err # error if failed + bnez a0, .LReturnFileErr # error if failed addi s1, s1, 1 - blt s1, s0, .Lprocess_file - j .Lreturn_ok - - .Lreturn_file_err: + blt s1, s0, .LProcessFile + j .LMainReturnOk + + .LProcessStdin: + call cat_stdin + j .LMainReturnOk + + .LReturnFileErr: li a0, 2 la a1, cat_prefix li a2, CAT_PREFIX_LEN @@ -88,12 +81,12 @@ _start: ecall - .Lreturn_err: #1 + .LMainReturnErr: #1 li a0, 1 li a7, 93 ecall # return 1 - .Lreturn_ok: #2 + .LMainReturnOk: #2 li a0, 0 li a7, 93 ecall # return 0 -- 2.54.0