diff options
| author | user <user@clank> | 2026-09-24 23:08:46 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-24 23:08:46 +0200 |
| commit | 4bfe20f88b93645f9a277c9903620d75f0ddc179 (patch) | |
| tree | ba8af4184f10645fecc59adc9b0b0454658ad278 /usr/du.c | |
| parent | term: ESC[2J, so clear(1) can actually clear (diff) | |
| download | gbos-4bfe20f88b93645f9a277c9903620d75f0ddc179.tar.gz gbos-4bfe20f88b93645f9a277c9903620d75f0ddc179.tar.xz gbos-4bfe20f88b93645f9a277c9903620d75f0ddc179.zip | |
usr: sort, cmp, strings, du, time
- sort [-r] [-n]: everything in RAM, which bounds it - a task has 8 KiB and a
file caps at 3 KiB, so 96 lines of 2400 bytes with room for the stack.
Insertion sort over an index; at that size the simple thing is fast and
costs far less ROM. `uniq -c f | sort -n -r` finally works.
NB the key needs a scratch SLOT of its own: gt() compares table entries, so
reusing slot i as scratch overwrites the entries being shifted into it.
- cmp: reports the first differing byte, silent when the files match. There
was no way to check a copy on the machine - you had to haul both to a host.
- strings [-n N]: pairs with xxd now that /bin/<prog> is readable. It finds
"gbos sm83 (Game Boy Color)" inside /bin/uname.
- du [dir]: 256-byte blocks, the unit df and the filesystem use. Bytes
overflow - /bin alone is 52 x 16 KiB, which wrapped a 16-bit counter and
printed 32768. Recurses by re-opendir'ing, since the kernel keeps only one
"directory being listed" cursor.
- time CMD: 1/64 s resolution from the tick counter. It rebuilds the child's
command line at $A000 - which is its own argument area, so everything is
copied to the stack first.
Diffstat (limited to 'usr/du.c')
| -rw-r--r-- | usr/du.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/usr/du.c b/usr/du.c new file mode 100644 index 0000000..2667159 --- /dev/null +++ b/usr/du.c @@ -0,0 +1,85 @@ +#include "stat.h" +/* du [dir]: disk usage per entry, and a total, in 256-byte blocks. + * + * Blocks, not bytes, for two reasons: it is the unit df(1) and the filesystem + * itself use, and bytes overflow - /bin alone is 52 programs x 16 KiB, which + * wraps a 16-bit counter (it printed 32768). + * + * Recurses by re-opendir'ing: the kernel keeps ONE "directory being listed" + * (wListDir), so walking into a child loses the parent's cursor - the parent + * has to be re-opened and re-indexed on the way back up. With 32 inodes and + * shallow trees that costs nothing. */ + +#define MAXDEPTH 3 + +static unsigned int total; /* 256-byte blocks */ + +static void pad(unsigned int n, unsigned char w) { + unsigned char d = 1; + unsigned int v = n; + while (v >= 10) { + v = v / 10; + d++; + } + while (d++ < w) putc(' '); + putu(n); +} + +/* sum one directory, printing each entry; returns its byte total */ +static unsigned int walk(char *path, unsigned char depth) { + char name[16]; + char child[40]; + struct gstat st; + unsigned int sum = 0; + unsigned char i, j, k; + + for (i = 0;; i++) { + if (opendir(path)) return sum; /* re-open: flist has one cursor */ + if (!flist(i, name)) break; + name[15] = 0; + j = 0; + for (k = 0; path[k] && j < 30; k++) child[j++] = path[k]; + if (j && child[j - 1] != '/') child[j++] = '/'; + for (k = 0; name[k] && j < 38; k++) child[j++] = name[k]; + child[j] = 0; + if (!gstat(child, &st)) continue; + if (st.type == ST_DIR && depth < MAXDEPTH) { + sum += walk(child, (unsigned char)(depth + 1)); + } else { + { + unsigned int blk = (unsigned int)((st.size + 255) / 256); + sum += blk; + pad(blk, 6); + } + putc(' '); + puts(child); + nl(); + } + } + pad(sum, 6); + putc(' '); + puts(path); + nl(); + return sum; +} + +void main(void) { + char dir[32]; + char *argv[4]; + unsigned char argc = argv_parse(argv, 4); + unsigned char i, j, have = 0; + + /* copy the argument before gstat's static request block lands on $A000 */ + for (i = 0; i < argc; i++) + if (argv[i][0] != '-') { + for (j = 0; argv[i][j] && j < 31; j++) dir[j] = argv[i][j]; + dir[j] = 0; + have = 1; + break; + } + if (!have) { + dir[0] = '/'; + dir[1] = 0; + } + total = walk(dir, 0); +} |
