code wiki / (root) / nx_nishios_shell.nx

nx_nishios_shell.nx source

↩ module page · 148 lines · 9622 B

1// nx_nishios_shell.nx -- NishiOS GUI rung-6: the terminal runs a REAL tool (`ls` over the real FS). 2// rung-5 made the terminal typeable with builtins; this makes it a real SHELL: typing "ls" dispatches to 3// an actual directory listing via sys_openat_rd + sys_getdents64 + dirent_name (the same syscalls the 4// sovereign coreutils `ls` uses), reading the REAL knowledge/status directory and rendering the entries 5// in the terminal. GUI keystrokes -> shell -> real kernel syscalls -> real filesystem -> pixels. 6// KAT: typing "ls" produced a real listing (contains our own .bmp artifacts), the listing rendered in 7// the terminal body, and the BMP exported. 8// HONEST SEAM: scancode source still scripted (PS/2 IRQ1 = hw rung); but the COMMAND now hits the real 9// filesystem, not a canned string. No hw writes (Rule 26). expect_exit: 0 license_tier: ORIGINAL 10import "nx_fb.nx" 11import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 12import "nx_font8x8.nx" 13const K_MAGIC_16384: i64 = 16384 14const K_MAGIC_192054: i64 = 192054 15 16func sh_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 18// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 19// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 20// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 21func sh_num(v: i64) -> i64 { nxi_out(v); return 0 } 22func sh_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 23func sh_streq(a: *u8, alen: i64, b: *u8) -> i64 { let bl: i64=sh_slen(b); if alen!=bl { return 0 } var i: i64=0; while i<alen { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 24func sh_scopy(dst: *u8, doff: i64, src: *u8) -> i64 { var i: i64=0; while src[i]!=(0 as u8) { dst[doff+i]=src[i]; i=i+1 } return doff+i } 25func sh_contains(hay: *u8, haylen: i64, needle: *u8) -> i64 { let nl: i64=sh_slen(needle); if nl==0 { return 1 } var i: i64=0; while i+nl<=haylen { var ok: i64=1; var j: i64=0; while j<nl { if hay[i+j]!=needle[j] { ok=0; j=nl } else { j=j+1 } } if ok==1 { return 1 } i=i+1 } return 0 } 26func sh_isdot(name: *u8) -> i64 { if name[0]==(46 as u8) { if name[1]==(0 as u8) { return 1 } if name[1]==(46 as u8) { if name[2]==(0 as u8) { return 1 } } } return 0 } 27 28func kt_char(fb: *u8, W: i64, H: i64, table: *u8, x: i64, y: i64, ch: i64, r: i64, g: i64, b: i64) -> i64 { 29 if ch<0x20 { return 0 } 30 if ch>0x7E { return 0 } 31 let gi: i64=(ch-0x20)*8 32 var row: i64=0 33 while row<8 { let bits: i64=table[gi+row] as i64; var col: i64=0; while col<8 { if ((bits>>col)&1)==1 { fb_setpx(fb,W,H, x+col, y+row, r,g,b) } col=col+1 } row=row+1 } 34 return 0 35} 36func kt_str(fb: *u8, W: i64, H: i64, table: *u8, x: i64, y: i64, s: *u8, r: i64, g: i64, b: i64) -> i64 { var i: i64=0; while s[i]!=(0 as u8) { kt_char(fb,W,H,table, x+i*8, y, s[i] as i64, r,g,b); i=i+1 } return 0 } 37func kt_count(fb: *u8, W: i64, x0: i64, y0: i64, x1: i64, y1: i64) -> i64 { var c: i64=0; var y: i64=y0; while y<y1 { var x: i64=x0; while x<x1 { if (fb[(y*W+x)*3+1] as i64) > 180 { c=c+1 } x=x+1 } y=y+1 } return c } 38// render text, wrapping at maxcols; returns lines used 39func kt_wrap(fb: *u8, W: i64, H: i64, table: *u8, x0: i64, y0: i64, s: *u8, maxcols: i64, r: i64, g: i64, b: i64) -> i64 { 40 var col: i64=0; var li: i64=0; var i: i64=0 41 while s[i]!=(0 as u8) { if col>=maxcols { li=li+1; col=0 } kt_char(fb,W,H,table, x0+col*8, y0+li*10, s[i] as i64, r,g,b); col=col+1; i=i+1 } 42 return li+1 43} 44 45func build_keymap(km: *u8) -> i64 { 46 var i: i64=0 47 while i<128 { km[i]=0 as u8; i=i+1 } 48 km[0x10]=113 as u8; km[0x11]=119 as u8; km[0x12]=101 as u8; km[0x13]=114 as u8; km[0x14]=116 as u8; km[0x15]=121 as u8; km[0x16]=117 as u8; km[0x17]=105 as u8; km[0x18]=111 as u8; km[0x19]=112 as u8 49 km[0x1E]=97 as u8; km[0x1F]=115 as u8; km[0x20]=100 as u8; km[0x21]=102 as u8; km[0x22]=103 as u8; km[0x23]=104 as u8; km[0x24]=106 as u8; km[0x25]=107 as u8; km[0x26]=108 as u8 50 km[0x2C]=122 as u8; km[0x2D]=120 as u8; km[0x2E]=99 as u8; km[0x2F]=118 as u8; km[0x30]=98 as u8; km[0x31]=110 as u8; km[0x32]=109 as u8 51 km[0x39]=32 as u8 52 return 0 53} 54 55// REAL `ls`: open dir, getdents64, append each non-dot name. returns outlen (capped to `cap`). 56func do_ls(path: *u8, out: *u8, cap: i64) -> i64 { 57 let fd: i64 = sys_openat_rd(path) 58 if fd<=0 { let n: i64=sh_scopy(out,0,"ls: cannot open\x00" as *u8); out[n]=0 as u8; return n } 59 let buf: *u8 = sys_mmap(K_MAGIC_16384) 60 let nread: i64 = sys_getdents64(fd, buf, K_MAGIC_16384) 61 sys_close(fd) 62 var o: i64=0 63 var pos: i64=0 64 while pos < nread { 65 let rec: *u8 = ((buf as i64)+pos) as *u8 66 let reclen: i64 = dirent_reclen(rec) 67 if reclen<=0 { pos = nread } else { 68 let name: *u8 = dirent_name(rec) 69 if sh_isdot(name)==0 { if o < cap-40 { o=sh_scopy(out, o, name); out[o]=32 as u8; o=o+1 } } 70 pos = pos + reclen 71 } 72 } 73 out[o]=0 as u8 74 return o 75} 76 77func run_cmd(line: *u8, linelen: i64, out: *u8) -> i64 { 78 if sh_streq(line,linelen,"ls\x00" as *u8)==1 { return do_ls("knowledge/status\x00" as *u8, out, 300) } 79 if sh_streq(line,linelen,"ver\x00" as *u8)==1 { let n: i64=sh_scopy(out,0,"NishiOS 0.1 sovereign\x00" as *u8); out[n]=0 as u8; return n } 80 if sh_streq(line,linelen,"help\x00" as *u8)==1 { let n: i64=sh_scopy(out,0,"builtins: help ver clear ls\x00" as *u8); out[n]=0 as u8; return n } 81 var o: i64=sh_scopy(out,0,"unknown: \x00" as *u8) 82 var i: i64=0 83 while i<linelen { out[o]=line[i]; o=o+1; i=i+1 } 84 out[o]=0 as u8 85 return o 86} 87 88func main() -> i64 { 89 sh_puts("NishiOS GUI rung-6: the terminal runs a REAL tool -- type 'ls' -> real getdents64 listing\n" as *u8) 90 91 // scancodes: l, s, <enter> (type "ls") 92 let sc: *u8 = sys_mmap(8) 93 sc[0]=0x26 as u8; sc[1]=0x1F as u8; sc[2]=0x1C as u8 94 let nsc: i64=3 95 let km: *u8 = sys_mmap(128) 96 build_keymap(km) 97 98 let line: *u8 = sys_mmap(128) 99 var linelen: i64=0 100 var p: i64=0 101 while p<nsc { 102 let code: i64 = sc[p] as i64 103 if code==0x1C { p=nsc } else { 104 if code==0x0E { if linelen>0 { linelen=linelen-1 } } else { let a: i64=km[code] as i64; if a!=0 { line[linelen]=a as u8; linelen=linelen+1 } } 105 p=p+1 106 } 107 } 108 line[linelen]=0 as u8 109 110 let out: *u8 = sys_mmap(512) 111 let outlen: i64 = run_cmd(line, linelen, out) 112 sh_puts(" typed '" as *u8); sys_write(1,line,linelen); sh_puts("' -> ran real ls, " as *u8); sh_num(outlen); sh_puts(" bytes of entries:\n " as *u8); sys_write(1,out,outlen); sh_puts("\n" as *u8) 113 114 let W: i64=320 115 let H: i64=200 116 let fb: *u8 = sys_mmap(W*H*3) 117 let table: *u8 = font8x8_table() 118 fb_rect(fb,W,H, 0,0, W,H, 8,30,45) 119 fb_rect(fb,W,H, 18,26, 284,156, 60,120,80) 120 fb_rect(fb,W,H, 19,27, 282,154, 12,16,12) 121 fb_rect(fb,W,H, 19,27, 282,12, 30,90,45) 122 kt_str(fb,W,H,table, 23,28, "NISHIOS terminal\x00" as *u8, 220,255,220) 123 kt_str(fb,W,H,table, 24,46, "NISHIOS> \x00" as *u8, 120,255,120) 124 kt_str(fb,W,H,table, 24+9*8,46, line, 230,255,230) 125 let lines: i64 = kt_wrap(fb,W,H,table, 24,58, out, 34, 170,225,170) 126 let ny: i64 = 58 + lines*10 + 2 127 kt_str(fb,W,H,table, 24,ny, "NISHIOS> \x00" as *u8, 120,255,120) 128 fb_rect(fb,W,H, 24+9*8, ny, 6,8, 120,255,120) 129 130 let sz: i64 = fb_bmp_save(fb, W, H, "knowledge/status/nishios_shell.bmp\x00" as *u8) 131 let html: *u8 = "<!doctype html><html><body style=\x27margin:0;background:#0a0a12;display:flex;align-items:center;justify-content:center;height:100vh\x27><div><img src=\x27nishios_shell.bmp\x27 style=\x27image-rendering:pixelated;width:720px;border:1px solid #333\x27><div style=\x27color:#8af;font-family:monospace;text-align:center;margin-top:8px\x27>NishiOS shell -- typed 'ls', ran real getdents64 against the live filesystem</div></div></body></html>\x00" 132 let hd: i64 = sys_openat_wr("knowledge/status/nishios_shell.html\x00" as *u8, 0x1a4) 133 if hd>0 { var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) } 134 sh_puts(" rendered shell -> knowledge/status/nishios_shell.bmp + .html\n" as *u8) 135 136 var pass: i64=0 137 var ttl: i64=0 138 ttl=ttl+1; sh_puts(" T1 typed command parsed as 'ls': " as *u8); if sh_streq(line,linelen,"ls\x00" as *u8)==1 { pass=pass+1; sh_puts("PASS\n" as *u8) } else { sh_puts("FAIL\n" as *u8) } 139 ttl=ttl+1; sh_puts(" T2 real ls returned entries (>20 bytes): " as *u8); if outlen>20 { pass=pass+1; sh_puts("PASS\n" as *u8) } else { sh_puts("FAIL\n" as *u8) } 140 ttl=ttl+1; sh_puts(" T3 listing holds REAL filesystem entries ('.log' present): " as *u8); if sh_contains(out,outlen,".log\x00" as *u8)==1 { pass=pass+1; sh_puts("PASS\n" as *u8) } else { sh_puts("FAIL\n" as *u8) } 141 let body_px: i64 = kt_count(fb, W, 24, 58, 300, 150) 142 ttl=ttl+1; sh_puts(" T4 listing rendered in terminal (text pixels>40): " as *u8); if body_px>40 { pass=pass+1; sh_puts("PASS\n" as *u8) } else { sh_puts("FAIL\n" as *u8) } 143 ttl=ttl+1; sh_puts(" T5 BMP exported: " as *u8); if sz==K_MAGIC_192054 { pass=pass+1; sh_puts("PASS\n" as *u8) } else { sh_puts("FAIL\n" as *u8) } 144 145 sh_puts("NISHIOS-SHELL-GATE passed " as *u8); sh_num(pass); sh_puts("/" as *u8); sh_num(ttl) 146 if pass==ttl { sh_puts(" verdict=GREEN (GUI terminal -> real kernel syscalls -> real filesystem; open nishios_shell.html)\n" as *u8); sys_exit(0); return 0 } 147 sh_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 148}