aboutsummaryrefslogtreecommitdiffstats
path: root/usr/du.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-24 23:08:46 +0200
committeruser <user@clank>2026-09-24 23:08:46 +0200
commit4bfe20f88b93645f9a277c9903620d75f0ddc179 (patch)
treeba8af4184f10645fecc59adc9b0b0454658ad278 /usr/du.c
parentterm: ESC[2J, so clear(1) can actually clear (diff)
downloadgbos-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.c85
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);
+}