From 932b72f93101474eb5d34023fac5f6f503017689 Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Sat, 30 Aug 2025 16:56:44 +0200 Subject: [PATCH] feat: sort the entries before printing them --- main.S | 80 +++++++++++++++++++++++++++++++++++++++++++++++--------- string.S | 35 ++++++++++++++++++++----- 2 files changed, 97 insertions(+), 18 deletions(-) diff --git a/main.S b/main.S index 2316e5b..47336fd 100644 --- a/main.S +++ b/main.S @@ -82,6 +82,12 @@ _start: @ r0 needs the fd, which it should already be since the call to open() set r0 to the fd. ldr r1, =buffer @ pointer to linux_dirent structure @ TODO: we can allocate the required memory on the stack instead of in the bss section I think. + /* + TODO: this only reads up to 16KB of directory entries. if a directory we pass has entries with a sum larger + than 16KB then we don't end up printing those. + Solution: a nested loop. one for reading until the syscall returns 0 to indicate end of directory, and one for + looping the directories + */ mov r2, #16384 @ how many bytes to read mov r7, #SYS_GETDENTS svc 0 @@ -93,19 +99,14 @@ _start: mov r4, #0 @ initialize r4 to 0 ldr r5, =buffer + + sub sp, sp, #4096 @ allocate 4KB of mem to store the directory entries. + mov r1, sp + mov r10, #0 @ dir entry counter 1: - push {r0} - - add r1, r5, #10 @ offset 10 bytes into the dirent struct to reach d_name. - bl strlen - mov r2, r0 - bl print - - ldr r1, =NEWLINE - mov r2, #1 - bl print - - pop {r0} + add r2, r5, #10 @ offset 10 bytes into the dirent struct to reach d_name. + str r2, [r1, r10, lsl #2] @ store the value in r2 in the memory address pointed to by r1[r10 << 2]. The shift is just (r10 * 4) + add r10, r10, #1 @ load the value (as 16-bits zero-extended as opposed to loading 32-bits and then extending that ourselves with UXTH) @ in the memory address of r5 offset by 8 bytes to get us the d_reclen @@ -117,6 +118,61 @@ _start: cmp r4, r0 blt 1b +/* bubble sort + TODO: improvements: + - a case-insensitive strcmp should be used when sorting + - dots at the beginning of a file name should be ignored when sorting/comparing to match ls' behavior +*/ + mov r5, r1 @ save the array pointer in r5 because we'll be using r1 a lot + mov r3, #0 @ outer loop counter +outer: + mov r4, #0 @ inner loop counter + sub r8, r10, r3 + sub r8, r8, #1 + push {r3} + +inner: + ldr r1, [r5, r4, lsl #2] + add r6, r4, #1 + ldr r2, [r5, r6, lsl #2] + push {r1-r2} + bl strcmp_ascii + pop {r1-r2} + + cmp r0, #1 + bne 2f + @ swap if a > b + mov r7, r1 + str r2, [r5, r4, lsl #2] + str r7, [r5, r6, lsl #2] + +2: + add r4, r4, #1 + cmp r4, r8 + blt inner + + pop {r3} + add r3, r3, #1 + cmp r3, r10 + blt outer + +print_entries: + ldr r1, [r5], #4 + bl bytelen + + mov r2, r0 + bl print + + ldr r1, =NEWLINE + mov r2, #1 + bl print + + sub r10, r10, #1 + cmp r10, #0 + bgt print_entries + + add sp, sp, #4096 + mov r0, #0 bl exit diff --git a/string.S b/string.S index 45a285f..f7d2dd7 100644 --- a/string.S +++ b/string.S @@ -1,6 +1,4 @@ /* - Current implementation only counts the bytes instead of characters. - @args: r1 => pointer to the string @returns: @@ -8,7 +6,7 @@ @clobbers: r2 */ -strlen: +bytelen: mov r0, #0 1: ldrb r2, [r1, r0] @@ -19,7 +17,32 @@ strlen: b 1b /* - @input r1, r2 - pointers to the strings to compare - @return r0 - 0 if equal, -1 if a < b, 1 if a > b + @args: + r1 => pointer to first string + r2 => pointer to second string + @returns: + r0 => 0 if equal, -1 if a < b, 1 if a > b + @clobbers: + r1, r2, r3 */ -strcmp: @ TODO: implement +strcmp_ascii: +@ comparison loop +1: + ldrb r0, [r1], #1 + ldrb r3, [r2], #1 + cmp r0, r3 + bne 2f + cmp r0, #0 + bne 1b + + @ strings are equal + mov r0, #0 + bx lr + +@ if we found a different byte then return the appropriate integer +2: + sub r0, r0, r3 + cmp r0, #0 + movlt r0, #-1 + movgt r0, #1 + bx lr