.data line_count: .space 6 .section .text .globl add_endings, add_line_numbers, zero_line_count # Print to stdout while adding "$" characters. # @param[in] a0: ptr to null-terminated str. # @param[in] a1: length of str. # @param[in] a2: mod buf addr. # @param[out] a0: result code. # @param[out] a1: bytes written to mod buf. 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) mv s0, a0 # put the str buf ptr in s0 mv s1, a1 li s2, 0 # set the str buf char counter to 0 li s3, 0 # set the mod buf char counter to 0 mv s5, a2 .LEndingsProcessChunk: 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 = mod buf[s2] li t5, '$' sb t5, 0(s4) # mod buf[s2] = $ li t5, '\n' addi s4, s4, 1 sb t5, 0(s4) # mod buf[s2] = \n addi s3, s3, 2 j 2f 1: add s4, s5, s3 # s4 = mod buf[s2] sb t6, 0(s4) # mod buf[s2] = t6 addi s3, s3, 1 # inc mod buf pointer 2: addi s2, s2, 1 # inc str buf pointer blt s2, s1, .LEndingsProcessChunk li a0, 0 mv a1, s3 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 # Prefix newlines with ######+TAB line count # @param[in] a0: ptr to null-terminated str. # @param[in] a1: length of str. # @param[in] a2: mod buf addr. # @param[in] a3: skip empty. # @param[out] a0: result code. # @param[out] a1: bytes written to mod buf. add_line_numbers: addi sp, sp, -72 sd s7, 64(sp) #unused sd s6, 56(sp) # mod buf ptr sd s5, 48(sp) # mod buf bp sd s4, 40(sp) # str buf ptr sd ra, 32(sp) sd s3, 24(sp) # mod buf offset sd s2, 16(sp) # str buf offset sd s1, 8(sp) # len of str sd s0, 0(sp) # str buf addr mv s0, a0 # put the str ptr in s0 mv s1, a1 # move length of str into s1 li s2, 0 # set the str buf char offset to 0 li s3, 0 # set the mod buf char offset to 0 mv s5, a2 # move mod buf addr into s5 # there is always one line number at the very start call _inc_line_count li t2, 0 # lc char buf offset li t3, 6 # lc char buf max offset la t1, line_count # load the line count buffer addr add s6, s5, s3 # update mod buf + offset addr 4: add t4, t1, t2 lb t5, 0(t4) sb t5, 0(s6) # mod buf[s4] = t4 addi t2, t2, 1 addi s3, s3, 1 add s6, s5, s3 # update mod buf + offset addr blt t2, t3, 4b li t5, 0x9 # tab character sb t5, 0(s6) addi s3, s3, 1 .LLineNumbersProcessChunk: 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 mv t0, s2 addi t0, t0, 1 # move ahead one char and see if EOF bge t0, s1, 1f # if the newline is at the veyr end, we don't indicate a new line number call _inc_line_count addi s3, s3, 1 # we want the ptr at the spot right after the newline add s6, s5, s3 # update mod buf + offset addr li t2, 0 # lc char buf offset li t3, 6 # lc char buf max offset la t1, line_count # load the line count buffer addr li t5, 0xA # newline character sb t5, 0(s6) addi s3, s3, 1 add s6, s5, s3 # update mod buf + offset addr 3: add t4, t1, t2 lb t5, 0(t4) sb t5, 0(s6) # mod buf[s4] = t4 addi t2, t2, 1 addi s3, s3, 1 add s6, s5, s3 # update mod buf + offset addr blt t2, t3, 3b li t5, 0x9 # tab character sb t5, 0(s6) addi s3, s3, 1 j 2f 1: add s6, s5, s3 # s4 = mod buf[s2] sb t6, 0(s6) # mod buf[s2] = t6 addi s3, s3, 1 # inc mod buf pointer 2: addi s2, s2, 1 # inc str buf pointer blt s2, s1, .LLineNumbersProcessChunk li a0, 0 mv a1, s3 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 # Increment the line count string # @param[in] a0: not used # @param[out] a0: result code _inc_line_count: la t0, line_count # load the line count buffer address li t1, 5 # current offset, we move from right to left first .LIncLine: bltz t1, .LLineCountDoneInc add t2, t0, t1 # load the correct offset address into t2 lb t3, 0(t2) # load the current ascii character into t3 li t4, 32 # load space character bne t3, t4, .LLineCountNotSpaceChar # if the character is not a space, skip setting to zero li t4, 48 # ascii '0' sb t4, 0(t2) # store this at the current pointer .LLineCountNotSpaceChar: add t2, t0, t1 # load the correct offset address into t2 lb t3, 0(t2) # load the current ascii character into t3 li t4, 58 # ascii ':', right after ascii '9', overflow addi t3, t3, 1 beq t3, t4, .LLineCountOverflow sb t3, 0(t2) j .LLineCountDoneInc .LLineCountOverflow: li t4, 48 # ascii '0' sb t4, 0(t2) # store that ascii '0' li t4, 1 sub t1, t1, t4 # move to the next digit to the left j .LIncLine .LLineCountDoneInc: ret # Set the line count to all space characters # @param[in] a0: not used # @param[out] a0: result code zero_line_count: la t0, line_count # load the line count buffer address li t1, 0 # char ptr li t2, 6 # max char li t3, 32 # space character 1: add t4, t0, t1 # load offset addr sb t3, 0(t4) # store the space char in offset addr addi t1, t1, 1 blt t1, t2, 1b li a0, 0 ret