From 1f2c8d85f3a065249fed56b7117ef5918b22e112 Mon Sep 17 00:00:00 2001 From: Lisa Milne Date: Mon, 27 Nov 2023 19:01:52 +1000 Subject: [PATCH] move libraries to actual libraries (/lib/lib*.so) --- clite/commands.js | 16 ++- clite/core.js | 326 ++++++++++++++-------------------------------- clite/libclite.js | 107 +++++++++++++++ clite/libstd.js | 77 +++++++++++ clite/libstdio.js | 96 ++++++++++++++ clite/libterm.js | 26 ++++ clite/shell.js | 28 +++- 7 files changed, 439 insertions(+), 237 deletions(-) create mode 100644 clite/libclite.js create mode 100644 clite/libstd.js create mode 100644 clite/libstdio.js create mode 100644 clite/libterm.js diff --git a/clite/commands.js b/clite/commands.js index 7b2db11..c8bb11d 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -39,6 +39,7 @@ clite.commands.load('ls',function(args,env,io) { var all = false; var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); + var clite = io.include('clite'); function help() { stdio.printf(` ls - list directory contents @@ -85,7 +86,7 @@ Options: } } }else{ - dirs.push(stdlib.resolvePath(args[i],false)); + dirs.push(clite.resolvePath(args[i],false)); } } @@ -137,6 +138,7 @@ clite.commands.load('cat',function(args,env,io) { var pending = 0; var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); + var clite = io.include('clite'); function help() { stdio.printf(` @@ -169,7 +171,7 @@ Options: } } }else{ - files.push(stdlib.resolvePath(args[i],false)); + files.push(clite.resolvePath(args[i],false)); } } @@ -259,6 +261,7 @@ clite.commands.load('touch',function(args,env,io) { var file = null; var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); + var clite = io.include('clite'); function help() { stdio.printf(` touch - create a new empty file @@ -282,7 +285,7 @@ Options: } } }else if (file == null) { - file = stdlib.resolvePath(args[i],false); + file = clite.resolvePath(args[i],false); }else{ stdio.write(io.stderr,'unknown argument: '+args[i]); } @@ -314,6 +317,7 @@ clite.commands.load('less',function(args,env,io) { var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); var term = io.include('term'); + var clite = io.include('clite'); var file = null; function help() { @@ -339,7 +343,7 @@ Options: } } }else if (file == null) { - file = stdlib.resolvePath(args[i],false); + file = clite.resolvePath(args[i],false); }else{ stdio.write(io.stderr,'unknown argument: '+args[i]); } @@ -476,6 +480,7 @@ clite.commands.load('file',function(args,env,io) { var file = null; var stdlib = io.include('stdlib'); var stdio = io.include('stdio'); + var clite = io.include('clite'); function help() { stdio.printf(` file - determine type of FILE @@ -500,7 +505,7 @@ Options: } }else if (file == null) { short = args[i]; - file = stdlib.resolvePath(args[i],false); + file = clite.resolvePath(args[i],false); }else{ stdio.write(io.stderr,'unknown argument: '+args[i]); } @@ -598,6 +603,7 @@ Options: }); clite.commands.load('uname',function(args,env,io) { + var stdio = io.include('stdio'); var stdlib = io.include('stdlib'); var sysname = false; var nodename = false; diff --git a/clite/core.js b/clite/core.js index ac9d957..5e77254 100644 --- a/clite/core.js +++ b/clite/core.js @@ -372,7 +372,7 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; var f = vfsapi.getNode('/bin/'+name); if (!f) return; - f.perms = '-r-xr-xr-x'; + f.perms = '-rwxr-xr-x'; f.data.content = fn; vfsapi.mkFile('/usr/src/'+name+'.js'); f = vfsapi.getNode('/usr/src/'+name+'.js'); @@ -391,6 +391,48 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; function init4(data) { clite.core.execSafe(clite.commands.data); clite.commands = null; + clite.log.write('Populating /lib'); + clite.libs = { + index:[], + data:null, + load:function(name,header,fn) { + vfsapi.mkFile('/lib/'+name+'.so'); + var f = vfsapi.getNode('/lib/'+name+'.so'); + if (!f) + return; + f.perms = '-rw-r--r--'; + f.data.content = fn; + vfsapi.mkFile('/usr/src/libs/'+name+'.js'); + f = vfsapi.getNode('/usr/src/libs/'+name+'.js'); + if (!f) + return; + f.perms = '-rw-rw-r--'; + f.data.content = 'function init'+fn.toString().substring(8); + clite.libs.index.push({header:header,file:name}); + } + } + clite.core.load.script('clite/libstd.js',init5); + } + + function init5(data) { + clite.core.execSafe(clite.libs.data); + clite.core.load.script('clite/libclite.js',init6); + } + + function init6(data) { + clite.core.execSafe(clite.libs.data); + clite.core.load.script('clite/libstdio.js',init7); + } + + function init7(data) { + clite.core.execSafe(clite.libs.data); + clite.core.load.script('clite/libterm.js',init8); + } + + function init8(data) { + clite.core.execSafe(clite.libs.data); + clite.libs.data = null; + clite.libs.load = null; clite.log.write('Bringing up the process manager'); if (!clite.proc.init(vfsapi)) { clite.log.write('failed'); @@ -421,10 +463,10 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; exit:null, // filled in by fork() include:null, // filled in by fork() }; - clite.lib.fork(env,io,init5); + clite.lib.fork(env,io,init9); } } - function init5(env,io) { + function init9(env,io) { clite.lib.exec('/bin/sh',['sh'],env,io); } @@ -495,6 +537,7 @@ clite.proc = { group.waitAny.forEach(function(w) { w(pid); }); + group.waitAny = []; var c = 0; data.procs.forEach(function(p) { // we want a count of child processes, so ignore the controlling process @@ -506,6 +549,7 @@ clite.proc = { group.waitAll.forEach(function(w) { w(pid); }); + group.waitAll = []; return true; } @@ -1034,7 +1078,7 @@ clite.io = { clite.io.isatty = function(fd) { return fd.node.data.istty; } - clite.io.fprintf = function(fd,fmt) { + clite.io.vfprintf = function(fd,fmt,args) { // TODO: actually support formatting return clite.io.write(fd,fmt); } @@ -1076,7 +1120,7 @@ clite.io = { chmod:null, fchmod:null, isatty:null, - fprintf:null + vfprintf:null }; clite.vfs = { @@ -1267,6 +1311,7 @@ clite.vfs = { vfsdata.api.mkDir('/bin'); vfsdata.api.mkDir('/dev'); vfsdata.api.mkDir('/etc'); + vfsdata.api.mkDir('/lib'); vfsdata.api.mkDir('/proc'); vfsdata.api.mkDir('/usr'); vfsdata.api.mkDir('/usr/clite'); @@ -1275,6 +1320,7 @@ clite.vfs = { vfsdata.api.mkDir('/usr/share'); vfsdata.api.mkDir('/usr/share/site'); vfsdata.api.mkDir('/usr/src'); + vfsdata.api.mkDir('/usr/src/libs'); vfsdata.api.mkDir('/var'); vfsdata.api.mkFile('/var/logs'); @@ -1433,41 +1479,37 @@ clite.term = { return clite.term.data.type.type; return 'text'; }, - api:{ - // clears the terminal - clear:function() { - clite.term.clear(); - }, - ttyctrl:function(fn,v) { - switch (fn) { - case 'iget': // returns the current input string - bypassing tty read - try{ - return clite.term.data.buff; - } catch(err) { - return ''; - } - break; - case 'iset': // sets the current input string - try{ - if (typeof v !== 'string') - v = ''; - clite.term.data.field.value = v; - clite.term.data.buff = v; - return true; - } catch(err) { - return false; - } - break; - case 'prompt': // sets the prompt for input + ttyctrl:function(fn,v) { + switch (fn) { + case 'iget': // returns the current input string - bypassing tty read + try{ + return clite.term.data.buff; + } catch(err) { + return ''; + } + break; + case 'iset': // sets the current input string + try{ if (typeof v !== 'string') v = ''; - clite.term.data.prompt = v; + clite.term.data.field.value = v; + clite.term.data.buff = v; return true; - break; - default: + } catch(err) { return false; } - }, + break; + case 'prompt': // sets the prompt for input + if (typeof v !== 'string') + v = ''; + clite.term.data.prompt = v; + return true; + break; + default: + return false; + } + }, + api:{ // gets an empty element with key events (allows view/less to display content in a clean element) opentty:function() { var tty = { @@ -1557,101 +1599,6 @@ clite.lib = { parts.pop(); return parts.join('/'); }, - // returns an absolute path: ('foo','/etc') -> '/etc/foo': ('foo','bar') -> $PWD/bar/foo - resolvePath:function(txt,base) { - if (txt == '/') - return txt; - var env = clite.user.getEnv(); - if (txt[0] == '~') { - txt = env.HOME+txt.substring(1); - } - var path = txt; - if (txt[0] != '/') { - if (typeof base != 'string') - base = env.PWD; - if (base[0] != '/') - base = env.PWD+'/'+base; - path = base+'/'+txt; - } - var parts = path.split('/'); - path = ''; - var i; - while ((i = parts.indexOf('.')) != -1) { - parts.splice(i,1); - } - while ((i = parts.indexOf('')) != -1) { - parts.splice(i,1); - } - while ((i = parts.indexOf('..')) != -1) { - parts.splice(i-1,2); - } - path = '/'+parts.join('/'); - return path; - }, - // convert a string into an argument array: 'ls /etc' -> ['ls','/etc'], supports "quoted arguments" and `command substitutions` - strToArgs:function(txt) { - var parts = []; - var sp = ''; - var s = ''; - var e = false; - var q = false; - var c = false; - for (var i=0; i 0) - parts.push(s); - // TODO: resolve all paths passed as arguments? - catches ~ and * etc - return parts; - }, // returns an int identifier for the file type getFileType:function(fd) { if (fd.node.data.content == null) { @@ -1690,42 +1637,6 @@ clite.lib = { } return clite.io.types.FT_UNKOWN; }, - getBuffer:function() { - var buff = Object.create({ - buffer:{ - data:'', - pos:0 - }, - read:function() { - if (this.buffer.pos >= this.buffer.data.length) - return null; - var b = this.data.buffer.substring(this.buffer.pos,this.buffer.data.length-this.buffer.pos); - var i = b.indexOf('\n'); - if (b < 0) - return b; - this.buffer.pos += i; - return b.substring(0,i); - }, - write:function(txt) { - this.buffer.data += txt; - } - }); - return buff; - }, - uname:function() { - var o = Object.create({ - sysname:'CLIte', - nodename:'localhost', - release:clite.state.version, - version:clite.state.version, - machine:navigator.userAgent - }); - - if (window.location.protocol != 'file:') - o.nodename = window.location.hostname; - - return o; - }, fork:function(env,io,call) { var pid = clite.proc.add(io.pid,call); if (!pid) @@ -1738,36 +1649,27 @@ clite.lib = { io.exit(pid,v); } catch(err) {} } + // this is esssentially the dynamic linker nio.include = function(name) { - switch (name) { - case 'stdlib': - var stdlib = Object.create(clite.lib.api); - stdlib.wait = function(cb) { - return clite.lib.wait(nio.pid,cb); - } - stdlib.waitpid = function(pid,cb) { - return clite.lib.waitpid(nio.pid,pid,cb); - } - stdlib.waitall = function(cb) { - return clite.lib.waitall(nio.pid,cb); - } - return stdlib; - break; - case 'stdio': - var stdio = Object.create(clite.io); - stdio.printf = function(fmt) { - // TODO: pass arguments through - return stdio.fprintf(nio.stdout,fmt); - } - return stdio; - break; - case 'term': - return Object.create(clite.term.api); - break; - default: + var file = ''; + clite.libs.index.forEach(function(e) { + if (e.header == name) + file = e.file; + }); + if (file == '') return null; - break; - } + + var fd = clite.io.open('/lib/'+file+'.so',false); + if (!fd) + return null; + + var lib = null; + try{ + lib = fd.node.data.content(nio,env); + }catch(err) {} + clite.io.close(fd); + if (lib) + return lib; return null; } clite.core.execSafeAsync(function() { @@ -1780,6 +1682,11 @@ clite.lib = { if (!fd) return -1; + if (!fd.canexec) { + clite.io.close(fd); + return -3 + } + clite.proc.update(args.join(' ')); var r = clite.core.execSafe(function() { @@ -1799,36 +1706,5 @@ clite.lib = { clite.proc.exit(pid); if (clite.term.tty.data != null) clite.term.api.closetty(clite.term.tty.data); - }, - getuid:function() { - return clite.user.getUID(); - }, - getgid:function() { - return clite.user.getGID(); - }, - // wait for any child process to exit - wait:function(cpid,cb) { - return clite.proc.addWaitGroupAny(cpid,cb); - }, - // wait for the process 'pid' to exit - waitpid:function(cpid,pid,cb) { - if (pid < 0) - return clite.lib.wait(cpid,cb); - return clite.proc.addWait(pid,cb); - }, - // wait for all child processes to exit - waitall:function(cpid,cb) { - return clite.proc.addWaitGroupAll(cpid,cb); } } -clite.lib.api = { // this is passed to programs via include('stdlib') - basename:clite.lib.basename, - dirname:clite.lib.dirname, - resolvePath:clite.lib.resolvePath, - strToArgs:clite.lib.strToArgs, - uname:clite.lib.uname, - fork:clite.lib.fork, - exec:clite.lib.exec, - getuid:clite.lib.getuid, - getgid:clite.lib.getgid -}; diff --git a/clite/libclite.js b/clite/libclite.js new file mode 100644 index 0000000..6db0a65 --- /dev/null +++ b/clite/libclite.js @@ -0,0 +1,107 @@ +clite.libs.data = function() { + +clite.libs.load('libclite','clite',function(io,env) { + +return Object.create({ + + // returns an absolute path: ('foo','/etc') -> '/etc/foo': ('foo','bar') -> $PWD/bar/foo + resolvePath:function(txt,base) { + if (txt == '/') + return txt; + var env = clite.user.getEnv(); + if (txt[0] == '~') { + txt = env.HOME+txt.substring(1); + } + var path = txt; + if (txt[0] != '/') { + if (typeof base != 'string') + base = env.PWD; + if (base[0] != '/') + base = env.PWD+'/'+base; + path = base+'/'+txt; + } + var parts = path.split('/'); + path = ''; + var i; + while ((i = parts.indexOf('.')) != -1) { + parts.splice(i,1); + } + while ((i = parts.indexOf('')) != -1) { + parts.splice(i,1); + } + while ((i = parts.indexOf('..')) != -1) { + parts.splice(i-1,2); + } + path = '/'+parts.join('/'); + return path; + }, + // convert a string into an argument array: 'ls /etc' -> ['ls','/etc'], supports "quoted arguments" and `command substitutions` + strToArgs:function(txt) { + var parts = []; + var sp = ''; + var s = ''; + var e = false; + var q = false; + var c = false; + for (var i=0; i 0) + parts.push(s); + // TODO: resolve all paths passed as arguments? - catches ~ and * etc + return parts; + } + +}); + +}); + +} diff --git a/clite/libstd.js b/clite/libstd.js new file mode 100644 index 0000000..d88ea91 --- /dev/null +++ b/clite/libstd.js @@ -0,0 +1,77 @@ +clite.libs.data = function() { + +clite.libs.load('libstd','stdlib',function(io,env) { + +return Object.create({ + + // returns the file name of a path /tmp/test/foo = foo + basename:function(txt) { + var parts = txt.split('/'); + return parts[parts.length-1]; + }, + + // returns the directory name of a path /tmp/test/foo = /tmp/test + dirname:function(txt) { + var parts = txt.split('/'); + parts.pop(); + return parts.join('/'); + }, + + // returns system info + uname:function() { + return Object.create({ + sysname:'CLIte', + nodename:clite.core.hostname(), + release:clite.state.version, + version:clite.state.version, + machine:navigator.userAgent + }); + }, + + // creates a new process + fork:function(env,io,call) { + return clite.lib.fork(env,io,call); + }, + + // executes a new program, replacing the current one + exec:function(path,args,env,io) { + return clite.lib.exec(path,args,env,io); + }, + + // exits the current program + exit:function(pid,v) { + io.exit(pid,v); + }, + + // returns the current user id + getuid:function() { + return clite.user.getUID(); + }, + + // returns the current group id + getgid:function() { + return clite.user.getGID(); + }, + + // wait for any child process to exit + wait:function(cb) { + return clite.proc.addWaitGroupAny(io.pid,cb); + }, + + // wait for the process 'pid' to exit + waitpid:function(pid,cb) { + if (pid < 0) + return clite.proc.addWaitGroupAny(io.pid,cb); + return clite.proc.addWait(pid,cb); + }, + + // wait for all child processes to exit + waitall:function(cb) { + return clite.proc.addWaitGroupAll(io.pid,cb); + } + +}); + +}); + +} diff --git a/clite/libstdio.js b/clite/libstdio.js new file mode 100644 index 0000000..17c9441 --- /dev/null +++ b/clite/libstdio.js @@ -0,0 +1,96 @@ +clite.libs.data = function() { + +clite.libs.load('libio','stdio',function(io,env) { + +return Object.create({ + + types:clite.io.types, + + creat:function(path,type) { + return clite.io.creat(path,type); + }, + + open:function(path,cb,open_link) { + return clite.io.open(path,cb,open_link); + }, + + close:function(fd) { + return clite.io.close(fd); + }, + + read:function(fd,cb) { + return clite.io.read(fd,cb); + }, + + readLine:function(fd,cb) { + return clite.io.readLine(fd,cb); + }, + + readAll:function(fd) { + return clite.io.readAll(fd); + }, + + write:function(fd,data) { + return clite.io.write(fd,data); + }, + + ftruncate:function(fd,len) { + return clite.io.ftruncate(fd,len); + }, + + truncate:function(path,len) { + return clite.io.truncate(path,len); + }, + + seek:function(fd,pos) { + return clite.io.seek(fd,pos); + }, + + remove:function(path) { + return clite.io.remove(path); + }, + + link:function(path,target) { + return clite.io.link(path,target); + }, + + stat:function(path) { + return clite.io.stat(path); + }, + + fstat:function(fd) { + return clite.io.fstat(fd); + }, + + chmod:function(path,mode) { + return clite.io.chmod(path,mode); + }, + + fchmod:function(fd,mode) { + return clite.io.fchmod(fd,mode); + }, + + isatty:function(fd) { + return clite.io.isatty(fd); + }, + + vfprintf:function(fd,fmt,args) { + return clite.io.vfprintf(fd,fmt,args); + }, + + fprintf:function(fd,fmt) { + var args = []; + return clite.io.vfprintf(fd,fmt,args); + }, + + printf:function(fmt) { + var args = []; + return clite.io.vfprintf(io.stdout,fmt,args); + } + + +}); + +}); + +} diff --git a/clite/libterm.js b/clite/libterm.js new file mode 100644 index 0000000..1560a7a --- /dev/null +++ b/clite/libterm.js @@ -0,0 +1,26 @@ +clite.libs.data = function() { + +clite.libs.load('libterm','term',function(io,env) { + +return Object.create({ + + // clears the terminal + clear:function() { + clite.term.clear(); + }, + + ttyctrl:function(fn,v) { + return clite.term.ttyctrl(fn,v); + }, + + // gets an empty element with key events (allows view/less to display content in a clean element) + opentty:function() { + return clite.term.api.opentty(); + }, + closetty:function(tty) { + return clite.term.api.closetty(tty); + } + +}); +}); +} diff --git a/clite/shell.js b/clite/shell.js index 820c054..5ffd373 100644 --- a/clite/shell.js +++ b/clite/shell.js @@ -5,6 +5,7 @@ clite.commands.load('sh',function(args,env,io) { var stdio = io.include('stdio'); var stdlib = io.include('stdlib'); var term = io.include('term'); + var clite = io.include('clite'); var active_pid = 0; var prompt = '$ '; var macro = { @@ -14,7 +15,7 @@ clite.commands.load('sh',function(args,env,io) { cd:function(args,io) { var dir = env.HOME; if (args.length > 1) { - dir = stdlib.resolvePath(args[1]); + dir = clite.resolvePath(args[1]); } var fd = stdio.open(dir,false); if (!fd) { @@ -99,7 +100,7 @@ clite.commands.load('sh',function(args,env,io) { term.ttyctrl('iset',history.getCurrent()); }, down:function() { - if (history.index == history.data.length) + if (history.index >= history.data.length) return; history.index++; term.ttyctrl('iset',history.getCurrent()); @@ -108,13 +109,18 @@ clite.commands.load('sh',function(args,env,io) { history.current = txt; }, getCurrent:function() { - if (history.index == history.data.length) + if (history.index >= history.data.length) return history.current; return history.data[history.index]; }, resetCurrent:function() { history.current = ''; history.index = history.data.length; + }, + clear:function() { + history.data = []; + history.current = ''; + history.index = 0; } } @@ -132,7 +138,7 @@ clite.commands.load('sh',function(args,env,io) { paths.forEach(function(p) { if (path) return; - var rp = stdlib.resolvePath(txt,p); + var rp = clite.resolvePath(txt,p); var fd = stdio.open(rp,false); if (fd) { stdio.close(fd); @@ -197,7 +203,7 @@ clite.commands.load('sh',function(args,env,io) { function tabfill() { var c = term.ttyctrl('iget'); - var parts = stdlib.strToArgs(c); + var parts = clite.strToArgs(c); var ai = parts.length-1; if (ai < 0) return; @@ -258,7 +264,7 @@ clite.commands.load('sh',function(args,env,io) { // clear the tty prompt term.ttyctrl('prompt',''); // split command line into arguments - var args = stdlib.strToArgs(txt); + var args = clite.strToArgs(txt); args.forEach(function(val,i) { args[i] = preprocess(val); }); @@ -303,6 +309,11 @@ clite.commands.load('sh',function(args,env,io) { stdio.write(io.stderr,'Shell: error in command:'+args[0]); io.exit(-1); } + + if (r == -3) { + stdio.write(io.stderr,'Shell: not an executable file:'+args[0]); + io.exit(-3); + } } active_pid = stdlib.fork(env,fio,execFunc); if (active_pid == 0) { @@ -375,7 +386,10 @@ clite.commands.load('sh',function(args,env,io) { } } - stdlib.waitall(inputRead); + stdlib.waitall(function() { + history.clear(); + inputRead(); + }); return null; });