Compare commits

..

3 Commits

16 changed files with 114 additions and 41 deletions

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
LUA=${LUA:-lua} LUA=${LUA:-lua}
rm -r target/* rm -r target/*
mkdir target &>/dev/null mkdir -p target/doc &>/dev/null
$LUA luapreproc.lua module/init.lua target/init.lua $LUA luapreproc.lua module/init.lua target/init.lua
echo _OSVERSION=\"PsychOS 2.0a2-$(git rev-parse --short HEAD)\" > target/version.lua echo _OSVERSION=\"PsychOS 2.0a2-$(git rev-parse --short HEAD)\" > target/version.lua
cat target/version.lua target/init.lua > target/tinit.lua cat target/version.lua target/init.lua > target/tinit.lua
@ -10,4 +10,5 @@ cp -r service/ lib/ cfg/ target/
rm target/version.lua rm target/version.lua
rm -r doc/ rm -r doc/
$LUA finddesc.lua doc/ $(find lib/ module/ -type f|sort) $LUA finddesc.lua doc/ $(find lib/ module/ -type f|sort)
pandoc doc/apidoc.md --template=template.tex -o doc/apidoc.pdf $LUA gendoc.lua target/doc/kernel.dict $(find module/ -type f|sort)
pandoc doc/apidoc.md docs-metadata.yml --template=template.tex -o doc/apidoc.pdf

3
docs-metadata.yml Normal file
View File

@ -0,0 +1,3 @@
---
title: 'PsychOS API Documentation'
---

51
gendoc.lua Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/env lua
local doc = require "lib/doc"
local ser = require "lib/serialization"
local tA = {...}
local outpath = table.remove(tA,1)
print(outpath)
local function formatDocs(fd)
local rs = ""
for name,finfo in pairs(fd) do
if rs:len() > 0 then
rs = rs .. "\n\n"
end
local as = ""
for k,v in pairs(finfo.args) do
if k > 1 then
as = as .. ", "
end
as = as .. v[1]
if v[2] then
as = as .. "^"..v[2].."^"
end
end
local rt = ""
for k,v in pairs(finfo.outtypes or {}) do
if rt:len() > 0 then
rt = rt .. ", "
else
rt = ": "
end
rt = rt .. v
end
rs = string.format("%s## %s(%s)%s\n%s",rs,name,as,rt,finfo.description)
end
return rs
end
local ad = io.open(outpath,"wb")
for k,v in pairs(tA) do
local fd = doc.parsefile(v)
local ds = ser.serialize(fd)
local tn = v:match("/(.+)$")
if ds:len() > 3 then
ad:write(tn.."\t"..ds:gsub("\n",""):gsub(", +",",").."\n")
end
end
ad:close()

View File

@ -1,3 +1,4 @@
local _,serial = pcall(require,"serialization")
local doc = {} local doc = {}
doc.searchers = {} doc.searchers = {}
doc.tctab = { doc.tctab = {
@ -96,6 +97,20 @@ function doc.searchers.lib(name) -- string -- string string -- Tries to find a d
if not dt then return false, "unable to find documentation for "..tostring(name) end if not dt then return false, "unable to find documentation for "..tostring(name) end
return doc.format(dt) return doc.format(dt)
end end
function doc.searchers.cdoc(topic) -- string -- string string -- Searches for documentation labelled as *topic* in .dict files under /boot/doc/
if not serial then return end
for k,v in ipairs(fs.list("/boot/doc")) do
if v:sub(-5) == ".dict" then
local f=io.open("/boot/doc/"..v,"rb")
for line in f:lines() do
local mname, docs = line:match("^(.-)\t(.+)$")
if mname == topic or mname == topic..".lua" then
return doc.format(serial.unserialize(docs))
end
end
end
end
end
function doc.docs(topic) -- string -- boolean -- Displays the documentation for *topic*, returning true, or errors. Also callable as just doc(). function doc.docs(topic) -- string -- boolean -- Displays the documentation for *topic*, returning true, or errors. Also callable as just doc().
local lib = os.getenv("LIB") or "/boot/lib" local lib = os.getenv("LIB") or "/boot/lib"

View File

@ -19,7 +19,7 @@ local function wrapUnits(n)
return tostring(math.floor(n))..(scale[count] or "") return tostring(math.floor(n))..(scale[count] or "")
end end
function shutil.import(lib) function shutil.import(lib) -- string -- boolean -- Imports the functions from library *lib* into the shell environment.
local cE = os.getenv("INCLUDE") or shell.include local cE = os.getenv("INCLUDE") or shell.include
local nE = {} local nE = {}
for k,v in pairs(cE) do for k,v in pairs(cE) do
@ -31,7 +31,7 @@ function shutil.import(lib)
return true return true
end end
function shutil.unimport(lib) function shutil.unimport(lib) -- string -- boolean -- Removes the functions from *lib* from the shell environment.
local cE = os.getenv("INCLUDE") or shell.include local cE = os.getenv("INCLUDE") or shell.include
local nE = {} local nE = {}
for k,v in pairs(cE) do for k,v in pairs(cE) do
@ -43,7 +43,7 @@ function shutil.unimport(lib)
return true return true
end end
function shutil.ls(...) function shutil.ls(...) -- string -- -- Prints contents of directories specified as *...*.
local tA = {...} local tA = {...}
if not tA[1] then tA[1] = "." end if not tA[1] then tA[1] = "." end
for _,d in ipairs(tA) do for _,d in ipairs(tA) do
@ -56,7 +56,7 @@ function shutil.ls(...)
end end
end end
function shutil.cat(...) function shutil.cat(...) -- string -- -- Outputs the contents of files specified in *...* to the standard output.
for _,fn in ipairs({...}) do for _,fn in ipairs({...}) do
local f = io.open(fn,"rb") local f = io.open(fn,"rb")
io.write(f:read("*a")) io.write(f:read("*a"))
@ -64,7 +64,7 @@ function shutil.cat(...)
end end
end end
function shutil.ps() function shutil.ps() -- Prints the processes running on the system.
print("PID# Parent | Name") print("PID# Parent | Name")
for k,v in pairs(os.tasks()) do for k,v in pairs(os.tasks()) do
local t = os.taskInfo(v) local t = os.taskInfo(v)
@ -72,7 +72,7 @@ function shutil.ps()
end end
end end
function shutil.df() function shutil.df() -- Prints free disk space.
local mt = fs.mounts() local mt = fs.mounts()
local ml = 0 local ml = 0
for k,v in pairs(mt) do for k,v in pairs(mt) do
@ -88,7 +88,7 @@ function shutil.df()
end end
end end
function shutil.mount(addr,path) function shutil.mount(addr,path) -- string string -- boolean string -- Mounts filesystem component with address *addr* to *path* in the filesystem.
if not addr then if not addr then
local mt = fs.mounts() local mt = fs.mounts()
for k,v in pairs(mt) do for k,v in pairs(mt) do
@ -114,7 +114,7 @@ function shutil.mount(addr,path)
end end
end end
function shutil.free() function shutil.free() -- Displays used and free memory.
print("Total Used Free") print("Total Used Free")
print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory()))) print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory())))
end end

View File

@ -4,7 +4,7 @@ local function normalise(path)
return table.concat(fs.segments(path),"/") return table.concat(fs.segments(path),"/")
end end
function unionfs.create(...) function unionfs.create(...) -- string -- table -- Returns a unionfs object of the directories specified in *...*.
local paths,fids,fc = {...}, {}, 0 local paths,fids,fc = {...}, {}, 0
for k,v in pairs(paths) do for k,v in pairs(paths) do
paths[k] = "/"..normalise(v) paths[k] = "/"..normalise(v)

View File

@ -1,5 +1,5 @@
local vtansi = {} local vtansi = {}
function vtansi.vtemu(gpu) -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal
local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF} local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
local mx, my = gpu.maxResolution() local mx, my = gpu.maxResolution()
local cx, cy = 1, 1 local cx, cy = 1, 1
@ -142,7 +142,7 @@ function vtansi.vtemu(gpu) -- takes GPU component proxy *gpu* and returns a func
return termwrite return termwrite
end end
function vtansi.vtsession(gpua,scra) -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions. function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions.
local gpu = component.proxy(gpua) local gpu = component.proxy(gpua)
gpu.bind(scra) gpu.bind(scra)
local write = vtansi.vtemu(gpu) local write = vtansi.vtemu(gpu)

View File

@ -181,6 +181,7 @@ env:process(arg[1])
local tmpfile = os.tmpname() local tmpfile = os.tmpname()
if tmpfile:sub(#tmpfile) == "." then tmpfile = tmpfile:sub(1, #tmpfile - 1) end if tmpfile:sub(#tmpfile) == "." then tmpfile = tmpfile:sub(1, #tmpfile - 1) end
local tmpf = io.open(tmpfile, "wb") local tmpf = io.open(tmpfile, "wb")
env.code = env.code:gsub("%-%-.-\n","\n"):gsub("\n\n","\n")
tmpf:write(env.code) tmpf:write(env.code)
tmpf:close() tmpf:close()
--if (os.execute("lua minify.lua "..tmpfile.." > "..arg[2])) then --if (os.execute("lua minify.lua "..tmpfile.." > "..arg[2])) then

View File

@ -2,7 +2,7 @@
buffer = {} buffer = {}
function buffer.new(mode, stream) -- create a new buffer in mode *mode* backed by stream object *stream* function buffer.new(mode, stream) -- string table -- table -- create a new buffer in mode *mode* backed by stream object *stream*
local result = { local result = {
mode = {}, mode = {},
stream = stream, stream = stream,

View File

@ -64,7 +64,7 @@ end
devfs.component.address = "devfs" devfs.component.address = "devfs"
devfs.component.type = "devfs" devfs.component.type = "devfs"
function devfs.register(fname,fopen) -- Register a new devfs node with the name *fname* that will run the function *fopen* when opened. This function should return a function for read, a function for write, function for close, and optionally, a function for seek, in that order. function devfs.register(fname,fopen) -- string function -- -- Register a new devfs node with the name *fname* that will run the function *fopen* when opened. This function should return a function for read, a function for write, function for close, and optionally, a function for seek, in that order.
devfs.files[fname] = fopen devfs.files[fname] = fopen
end end

View File

@ -3,14 +3,14 @@ fs = {}
local fsmounts = {} local fsmounts = {}
-- basics -- basics
function fs.segments(path) -- splits *path* on each / function fs.segments(path) -- string -- table -- Splits *path* on each /
local segments = {} local segments = {}
for segment in path:gmatch("[^/]+") do for segment in path:gmatch("[^/]+") do
segments[#segments+1] = segment segments[#segments+1] = segment
end end
return segments return segments
end end
function fs.resolve(path) -- resolves *path* to a specific filesystem mount and path function fs.resolve(path) -- string -- string string -- Resolves *path* to a specific filesystem mount and path
if not path or path == "." then path = os.getenv("PWD") end if not path or path == "." then path = os.getenv("PWD") end
if path:sub(1,1) ~= "/" then path=(os.getenv("PWD") or "").."/"..path end if path:sub(1,1) ~= "/" then path=(os.getenv("PWD") or "").."/"..path end
local segments, rpath, rfs= fs.segments(path) local segments, rpath, rfs= fs.segments(path)
@ -44,7 +44,7 @@ local function fclose(self)
return fsmounts[self.fs].close(self.fid) return fsmounts[self.fs].close(self.fid)
end end
function fs.open(path,mode) -- opens file *path* with mode *mode* function fs.open(path,mode) -- string string -- table -- Opens file *path* with mode *mode*, returning a file object.
mode = mode or "rb" mode = mode or "rb"
local fsi,path = fs.resolve(path) local fsi,path = fs.resolve(path)
if not fsmounts[fsi] then return false end if not fsmounts[fsi] then return false end
@ -62,7 +62,7 @@ function fs.open(path,mode) -- opens file *path* with mode *mode*
return false return false
end end
function fs.copy(from,to) -- copies a file from *from* to *to* function fs.copy(from,to) -- string string -- boolean -- copies a file from *from* to *to*
local of = fs.open(from,"rb") local of = fs.open(from,"rb")
local df = fs.open(to,"wb") local df = fs.open(to,"wb")
if not of or not df then if not of or not df then
@ -71,33 +71,34 @@ function fs.copy(from,to) -- copies a file from *from* to *to*
df:write(of:read("*a")) df:write(of:read("*a"))
df:close() df:close()
of:close() of:close()
return true
end end
function fs.rename(from,to) -- moves file *from* to *to* function fs.rename(from,to) -- string string -- boolean -- Moves file *from* to *to*
local ofsi, opath = fs.resolve(from) local ofsi, opath = fs.resolve(from)
local dfsi, dpath = fs.resolve(to) local dfsi, dpath = fs.resolve(to)
if ofsi == dfsi then if ofsi == dfsi then
fsmounts[ofsi].rename(opath,dpath) fsmounts[ofsi].rename(opath,dpath)
return true return true
end end
fs.copy(from,to) if not fs.copy(from,to) then return false end
fs.remove(from) if not fs.remove(from) then return false end
return true return true
end end
function fs.mount(path,proxy) -- mounts the filesystem *proxy* to the mount point *path* if it is a directory. BYO proxy. function fs.mount(path,proxy) -- string table -- boolean -- Mounts the filesystem *proxy* to the mount point *path* if it is a directory. BYO proxy.
if fs.isDirectory(path) and not fsmounts[table.concat(fs.segments(path),"/")] then if fs.isDirectory(path) and not fsmounts[table.concat(fs.segments(path),"/")] then
fsmounts[table.concat(fs.segments(path),"/")] = proxy fsmounts[table.concat(fs.segments(path),"/")] = proxy
return true return true
end end
return false, "path is not a directory" return false, "path is not a directory"
end end
function fs.umount(path) function fs.umount(path) -- string -- -- Unmounts filesystem from *path*.
local fsi,_ = fs.resolve(path) local fsi,_ = fs.resolve(path)
fsmounts[fsi] = nil fsmounts[fsi] = nil
end end
function fs.mounts() -- returns a table containing the mount points of all mounted filesystems function fs.mounts() -- -- table -- Returns a table containing the mount points of all mounted filesystems
local rt = {} local rt = {}
for k,v in pairs(fsmounts) do for k,v in pairs(fsmounts) do
rt[#rt+1] = k,v.address or "unknown" rt[#rt+1] = k,v.address or "unknown"
@ -105,11 +106,11 @@ function fs.mounts() -- returns a table containing the mount points of all mount
return rt return rt
end end
function fs.address(path) -- returns the address of the filesystem at a given path, if applicable; do not expect a sensical response function fs.address(path) -- string -- string -- Returns the address of the filesystem at a given path, if applicable; do not expect a sensical response
local fsi,_ = fs.resolve(path) local fsi,_ = fs.resolve(path)
return fsmounts[fsi].address return fsmounts[fsi].address
end end
function fs.type(path) -- returns the component type of the filesystem at a given path, if applicable function fs.type(path) -- string -- string -- Returns the component type of the filesystem at a given path, if applicable
local fsi,_ = fs.resolve(path) local fsi,_ = fs.resolve(path)
return fsmounts[fsi].type or "filesystem" return fsmounts[fsi].type or "filesystem"
end end

View File

@ -1,12 +1,12 @@
io = {} io = {}
function io.open(path,mode) -- Open file *path* in *mode*. Returns a buffer object. function io.open(path,mode) -- string string -- table -- Open file *path* in *mode*. Returns a buffer object.
local f,e = fs.open(path, mode) local f,e = fs.open(path, mode)
if not f then return false, e end if not f then return false, e end
return buffer.new(mode,f) return buffer.new(mode,f)
end end
function io.input(fd) -- Sets the default input stream to *fd* if provided, either as a buffer as a path. Returns the default input stream. function io.input(fd) -- table -- table -- Sets the default input stream to *fd* if provided, either as a buffer as a path. Returns the default input stream.
if type(fd) == "string" then if type(fd) == "string" then
fd=io.open(fd,"rb") fd=io.open(fd,"rb")
end end
@ -15,7 +15,7 @@ function io.input(fd) -- Sets the default input stream to *fd* if provided, eith
end end
return os.getenv("STDIN") return os.getenv("STDIN")
end end
function io.output(fd) -- Sets the default output stream to *fd* if provided, either as a buffer as a path. Returns the default output stream. function io.output(fd) -- table -- table -- Sets the default output stream to *fd* if provided, either as a buffer as a path. Returns the default output stream.
if type(fd) == "string" then if type(fd) == "string" then
fd=io.open(fd,"wb") fd=io.open(fd,"wb")
end end

View File

@ -1,19 +1,19 @@
function loadfile(p) -- reads file *p* and returns a function if possible function loadfile(p) -- string -- function -- reads file *p* and returns a function if possible
local f = io.open(p,"rb") local f = io.open(p,"rb")
local c = f:read("*a") local c = f:read("*a")
f:close() f:close()
return load(c,p,"t") return load(c,p,"t")
end end
function runfile(p,...) -- runs file *p* with arbitrary arguments in the current thread function runfile(p,...) -- string -- -- runs file *p* with arbitrary arguments in the current thread
return loadfile(p)(...) return loadfile(p)(...)
end end
function os.spawnfile(p,n,...) -- spawns a new process from file *p* with name *n*, with arguments following *n*. function os.spawnfile(p,n,...) -- string string -- number -- spawns a new process from file *p* with name *n*, with arguments following *n*.
local tA = {...} local tA = {...}
return os.spawn(function() local res={pcall(loadfile(p), table.unpack(tA))} computer.pushSignal("process_finished", os.pid(), table.unpack(res)) dprint(table.concat(res)) end,n or p) return os.spawn(function() local res={pcall(loadfile(p), table.unpack(tA))} computer.pushSignal("process_finished", os.pid(), table.unpack(res)) dprint(table.concat(res)) end,n or p)
end end
_G.package = {} _G.package = {}
package.loaded = {computer=computer,component=component,fs=fs,buffer=buffer} package.loaded = {computer=computer,component=component,fs=fs,buffer=buffer}
function require(f,force) -- searches for a library with name *f* and returns what the library returns, if possible. if *force* is set, loads the library even if it is cached function require(f,force) -- string boolean -- table -- searches for a library with name *f* and returns what the library returns, if possible. if *force* is set, loads the library even if it is cached
if not package.loaded[f] or force then if not package.loaded[f] or force then
local lib = os.getenv("LIB") or "/boot/lib" local lib = os.getenv("LIB") or "/boot/lib"
for d in lib:gmatch("[^\n]+") do for d in lib:gmatch("[^\n]+") do
@ -29,6 +29,6 @@ function require(f,force) -- searches for a library with name *f* and returns wh
end end
error("library not found: "..f) error("library not found: "..f)
end end
function reload(f) function reload(f) -- string -- table -- Reloads library *f* from disk into memory.
return require(f,true) return require(f,true)
end end

View File

@ -1,4 +1,4 @@
function os.chdir(p) -- changes the current working directory of the calling process to the directory specified in *p*, returning true or false, error function os.chdir(p) -- string -- boolean string -- changes the current working directory of the calling process to the directory specified in *p*, returning true or false, error
if not (p:sub(1,1) == "/") then if not (p:sub(1,1) == "/") then
local np = {} local np = {}
for k,v in pairs(fs.segments(os.getenv("PWD").."/"..p)) do for k,v in pairs(fs.segments(os.getenv("PWD").."/"..p)) do

View File

@ -1,6 +1,6 @@
do do
local tTasks,nPid,nTimeout,cPid = {},1,0.25,0 -- table of tasks, next process ID, event timeout, current PID local tTasks,nPid,nTimeout,cPid = {},1,0.25,0 -- table of tasks, next process ID, event timeout, current PID
function os.spawn(f,n) -- creates a process from function *f* with name *n* function os.spawn(f,n) -- function string -- number -- creates a process from function *f* with name *n*
tTasks[nPid] = { tTasks[nPid] = {
c=coroutine.create(f), -- actual coroutine c=coroutine.create(f), -- actual coroutine
n=n, -- process name n=n, -- process name
@ -16,20 +16,20 @@ function os.spawn(f,n) -- creates a process from function *f* with name *n*
nPid = nPid + 1 nPid = nPid + 1
return nPid - 1 return nPid - 1
end end
function os.kill(pid) -- removes process *pid* from the task list function os.kill(pid) -- number -- -- removes process *pid* from the task list
tTasks[pid] = nil tTasks[pid] = nil
end end
function os.pid() -- returns the current process' PID function os.pid() -- -- number -- returns the current process' PID
return cPid return cPid
end end
function os.tasks() -- returns a table of process IDs function os.tasks() -- -- table -- returns a table of process IDs
local rt = {} local rt = {}
for k,v in pairs(tTasks) do for k,v in pairs(tTasks) do
rt[#rt+1] = k rt[#rt+1] = k
end end
return rt return rt
end end
function os.taskInfo(pid) -- returns info on process *pid* as a table with name and parent values function os.taskInfo(pid) -- number -- table -- returns info on process *pid* as a table with name and parent values
pid = pid or os.pid() pid = pid or os.pid()
if not tTasks[pid] then return false end if not tTasks[pid] then return false end
return {name=tTasks[pid].n,parent=tTasks[pid].P} return {name=tTasks[pid].n,parent=tTasks[pid].P}

View File

@ -9,6 +9,7 @@ syslog.notice = 5
syslog.info = 6 syslog.info = 6
syslog.debug = 7 syslog.debug = 7
-- function syslog(msg, level, service) -- string number string -- -- Output *msg* to the system log, with severity *level*, from *service*.
local rdprint=dprint or function() end local rdprint=dprint or function() end
setmetatable(syslog,{__call = function(_,msg, level, service) setmetatable(syslog,{__call = function(_,msg, level, service)
level, service = level or syslog.info, service or (os.taskInfo(os.pid()) or {}).name or "unknown" level, service = level or syslog.info, service or (os.taskInfo(os.pid()) or {}).name or "unknown"