From 71c9a4fb3664483fa3ac04a23b06db20fe8c3c6e Mon Sep 17 00:00:00 2001 From: lexzach Date: Sun, 13 Sep 2026 21:30:17 -0400 Subject: [PATCH] Initial show ends --- src/file.S | 131 +++++++++++++++++++++++++++++++++++++++++++++-------- src/main.S | 22 ++++++--- 2 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/file.S b/src/file.S index 97ffae8..eabfa18 100644 --- a/src/file.S +++ b/src/file.S @@ -1,5 +1,6 @@ .data -cat_buf: .space 4096 +cat_buf: .space 4096 +endings_buf: .space 4097 .section .text .globl cat_file, open_fd, cat_stdin @@ -8,6 +9,11 @@ cat_buf: .space 4096 # @param[in] a0: ptr to null-terminated file str. # @param[out] a0: result code. cat_file: + addi sp, sp, -24 + sd s0, 0(sp) + sd ra, 8(sp) + sd s1, 16(sp) + mv a1, a0 # since the function takes in a0, move it to a1 for syscall addi sp, sp, -8 @@ -16,21 +22,30 @@ cat_file: ld ra, 0(sp) addi sp, sp, 8 - mv t0, a1 # put fd in t0 + mv s0, a1 # put fd in s0 + la t1, show_ends + lb s1, 0(t1) # store if we show ends into s1 + beqz a0, .LReadFileBlock # if we don't have an error, jump to reading li a0, 1 j .LCatFileRet .LReadFileBlock: - mv a0, t0 + mv a0, s0 la a1, cat_buf li a2, 4096 li a7, 63 ecall blez a0, .LCloseFD # if we haven't read any bytes, EOF, close FD - mv a2, a0 # move bytes read into bytes needed to write + beqz s1, .LNoEndingsWrite + mv a1, a0 + la a0, cat_buf + call _stdout_add_endings + j .LReadFileBlock + .LNoEndingsWrite: + mv a2, a0 # load the amount of bytes read in previous step into bytes needed to write li a0, 1 la a1, cat_buf li a7, 64 @@ -38,11 +53,15 @@ cat_file: j .LReadFileBlock .LCloseFD: - mv a0, t0 + mv a0, s0 li a7, 57 # close fd ecall .LCatFileRet: + ld s0, 0(sp) + ld ra, 8(sp) + ld s1, 16(sp) + addi sp, sp, 24 ret # Cat out stdin to stdout @@ -89,19 +108,91 @@ open_fd: 2: ret -# # Check if the given file exists without opening fd -# # @param[in] a0: ptr to null-terminated file str. -# # @param[out] a0: result code (0-exists 1-doesn't exist). -# file_exists: -# mv a1, a0 -# li a0, -100 # relative/absolute path -# li a2, 0 -# li a7, 48 -# ecall -# beqz a0, 1f -# li a0, 1 -# ret +# Print to stdout while adding "$" characters. +# @param[in] a0: ptr to null-terminated str. +# @param[in] a1: length of str. +# @param[out] a0: result code. +_stdout_add_endings: + addi sp, sp, -72 + sd s7, 64(sp) + sd s6, 56(sp) + sd s5, 48(sp) + sd s4, 40(sp) + sd ra, 32(sp) + sd s3, 24(sp) + sd s2, 16(sp) + sd s1, 8(sp) + sd s0, 0(sp) -# 1: -# li a0, 0 -# ret + + mv s0, a0 # put the cat_buf ptr in s0 + mv s1, a1 + li s2, 0 # set the cat_buf char counter to 0 + li s3, 0 # set the endings_buf char counter to 0 + + la s5, endings_buf + .LStdoutEndingsProcessChunk: + add s4, s0, s2 # Calculate the offset address + lb t6, 0(s4) + li t4, 0xA # newline + bne t6, t4, 1f # if the current byte is not a newline, skip to writing + + add s4, s5, s3 # s4 = endings_buf[s2] + li t5, '$' + sb t5, 0(s4) # endings_buf[s2] = $ + li t5, '\n' + addi s4, s4, 1 + sb t5, 0(s4) # endings_buf[s2] = \n + addi s3, s3, 2 + + li a0, 1 + la a1, endings_buf + mv a2, s3 + li a7, 64 + ecall + call _zero_endings_buf + li s3, 0 # reset endings_buf char counter + j 2f + + 1: + add s4, s5, s3 # s4 = endings_buf[s2] + sb t6, 0(s4) # endings_buf[s2] = t6 + + addi s3, s3, 1 # inc endings_buf pointer + 2: + addi s2, s2, 1 # inc cat_buf pointer + blt s2, s1, .LStdoutEndingsProcessChunk + beqz s3, .LSkipEndingsPrint + li a0, 1 + la a1, endings_buf + mv a2, s3 + li a7, 64 + ecall + .LSkipEndingsPrint: + + li a0, 0 + + ld s0, 0(sp) + ld s1, 8(sp) + ld s2, 16(sp) + ld s3, 24(sp) + ld ra, 32(sp) + ld s4, 40(sp) + ld s5, 48(sp) + ld s6, 56(sp) + ld s7, 64(sp) + addi sp, sp, 72 + ret + +_zero_endings_buf: + li t0, 0 + li t1, 4097 + + .LZeroEndingsBufByte: + la t2, endings_buf + add t2, t2, t0 + sb x0, 0(t2) + addi t0, t0, 1 + blt t0, t1, .LZeroEndingsBufByte + + ret diff --git a/src/main.S b/src/main.S index 3bb30b4..d0d05d3 100644 --- a/src/main.S +++ b/src/main.S @@ -1,5 +1,6 @@ .data argc: .space 8 +show_ends: .space 1 cat_prefix: .ascii "cat: " .equ CAT_PREFIX_LEN, . - cat_prefix @@ -11,13 +12,14 @@ 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 " --help display this help and exit\n" - .ascii " --version output version information and exit\n\n" + .ascii " -E, --show-ends display $ at end of each line\n" + .ascii " --help display this help and exit\n" + .ascii " --version output version information and exit\n\n" .asciz "Git repository: \n" .equ HELP_LEN, . - help version: - .ascii "cat 1.0.0\n" + .ascii "cat 1.1.0\n" .ascii "Copyright (C) 2026 lexzach\n" .ascii "License MIT\n" .ascii "This is free software: you are free to change and redistribute it.\n" @@ -26,10 +28,12 @@ version: .equ VERSION_LEN, . - version flag_help: .asciz "--help" -flag_version: .asciz "--version" +flag_version: .asciz "--version" +flag_show_ends: .asciz "--show-ends" +flag_E: .asciz "-E" .section .text -.globl _start +.globl _start, show_ends _start: .option push @@ -113,7 +117,7 @@ _check_flags: .LSkipDispHelp: - la a0, flag_version # help flag + la a0, flag_version # version flag li a1, 0 # no second flag call has_switch bnez a0, .LMainReturnErr @@ -126,6 +130,12 @@ _check_flags: j .LMainReturnOk .LSkipDispVersion: + la a0, flag_show_ends # show ends flag + la a1, flag_E # show ends -E flag + call has_switch + bnez a0, .LMainReturnErr + sb a1, show_ends, t1 # since the return for has switch is either 0 for not found or 1 for found, we can just write it directly into the buf + ld ra, 0(sp) addi sp, sp, 8 ret