YARUPACK 1 325 1354949 D /bin D /boot D /etc D /etc/rc.d D /home D /home/Music D /home/Pictures D /home/Videos D /home/Videos/demo D /home/Videos/demo-hd D /lib D /lib/core D /lib/core/devfs D /lib/core/devfs/adapters D /lib/tools D /lib/yaru D /mnt D /usr D /usr/man D /usr/misc D /usr/share D /usr/share/applications D /usr/share/doc D /usr/share/doc/composer D /usr/share/doc/ocbrowser D /usr/share/doc/ocv D /usr/share/doc/pictures D /usr/share/optimize D /usr/share/optimize/orig D /usr/share/optimize/orig/boot D /usr/share/optimize/orig/etc D /usr/share/optimize/orig/lib D /usr/share/yaru D /usr/share/yaru/apps D /usr/share/yaru/icons D /usr/share/yaru/shell F 791 /init.lua do local addr,invoke=computer.getBootAddress(),component.invoke local function loadfile(file) local handle=assert(invoke(addr,"open",file)) local buffer,n={},0 repeat local data=invoke(addr,"read",handle,math.maxinteger or math.huge) n=n+1 buffer[n]=data until not data invoke(addr,"close",handle) return load(table.concat(buffer),"="..file,"bt",_G) end loadfile("/lib/core/boot.lua")(loadfile) end do local f=loadfile("/lib/yaru/autostart.lua") if f then f()end end while true do local result,reason=xpcall(require("shell").getShell(),function(msg) return tostring(msg).."\n"..debug.traceback() end) if not result then io.stderr:write((reason~=nil and tostring(reason)or"unknown error").."\n") io.write("Press any key to continue.\n") os.sleep(0.5) require("event").pull("key") end end F 69 /bin/address.lua local computer=require("computer") io.write(computer.address(),"\n") F 1126 /bin/alias.lua local shell=require("shell") local args,options=shell.parse(...) local ec,error_prefix=0,"alias:" if options.help then print(string.format("Usage: alias: [name[=value] ... ]")) return end local function validAliasName(k) return k:match("[/%$`=|&;%(%)<> \t]")==nil end local function setAlias(k,v) if not validAliasName(k)then io.stderr:write(string.format("%s `%s': invalid alias name\n",error_prefix,k)) else shell.setAlias(k,v) end end local function printAlias(k) local v=shell.getAlias(k) if not v then io.stderr:write(string.format("%s %s: not found\n",error_prefix,k)) ec=1 else io.write(string.format("alias %s='%s'\n",k,v)) end end local function splitPair(arg) local matchBegin,matchEnd=arg:find("=") if matchBegin==nil or matchBegin==1 then return arg else return arg:sub(1,matchBegin-1),arg:sub(matchEnd+1) end end local function handlePair(k,v) if v then return setAlias(k,v) else return printAlias(k) end end if not next(args)then for k,v in shell.aliases()do print(string.format("alias %s='%s'",k,v)) end else for _,v in ipairs(args)do checkArg(1,v,"string") handlePair(splitPair(v)) end end return ec F 674 /bin/backup.lua local B=require("yaru.backuplib") local args,opts=require("shell").parse(...) local cfg=B.config() if not cfg.dst then io.stderr:write("backup: no destination set (open the Backups app)\n")return 1 end if opts.list then for _,s in ipairs(B.snapshots(cfg.dst))do local i=B.info(cfg.dst,s)print(s,(i.files or"?").." files")end return end local stamp=os.date("%Y-%m-%d_%H%M%S") local n,b=B.run(cfg,nil,stamp) if not n then io.stderr:write("backup failed: "..tostring(b).."\n")return 1 end print(string.format("backup %s: %d files, %d bytes",stamp,n,b)) local core=package.loaded["yaru.core"] if core and core.running then core.notify("Backup finished",n.." files saved")end F 9066 /bin/browser.lua local component=require("component") local computer=require("computer") local event=require("event") local keyboard=require("keyboard") local term=require("term") local unicode=require("unicode") local fs=require("filesystem") local shell=require("shell") local W=require("ocweb") local gpu=component.gpu local inet=component.isAvailable("internet")and component.internet or nil local args=shell.parse(...) local SW,SH=gpu.getResolution() local C={ bar=0x16213e,urlBox=0x0f3460,urlFocus=0x533483,urlText=0xe0e0e0,btnFg=0xffffff,off=0x6c7086, accent=0x533483,pageBg=0x1e1e2e,status=0xa6adc8,scrollbar=0x313244,scrollFg=0x585b70,sel=0x533483, find=0x45475a, } local PAGE_COLORS={text=0xcdd6f4,heading=0xcba6f7,link=0x89b4fa,dim=0x6c7086,accent=0xf5c2e7, code=0xa6e3a1,strong=0xffffff,em=0xf9e2af} local PAGE_Y=4 local PAGE_H=SH-PAGE_Y+1 local PAGE_W=SW-1 local BTN={{" ◄ ","back",2},{" ► ","fwd",6},{" ↺ ","reload",10},{" ⌂ ","home",14},{" ◇ ","mark",18}} local URL_X,URL_W=23,SW-26 local GO_X=SW-2 local ui={editing=false,addr="",cur=0,find=nil,findLine=nil,dirtyBar=true,dirtyPage=true} local S=W.session{inet=inet,width=PAGE_W-1,colors=PAGE_COLORS, onChange=function()ui.dirtyBar,ui.dirtyPage=true,true end, download=function(u,body) fs.makeDirectory("/home/Downloads") local name=(u:match("([^/?#]+)[?#]?[^/]*$")or"download"):gsub("[^%w%._%-]","_") local f=io.open("/home/Downloads/"..name,"wb") if f then f:write(body or"");f:close()end S.status="Saved /home/Downloads/"..name end} local function set(x,y,s,fg,bg)if bg then gpu.setBackground(bg)end if fg then gpu.setForeground(fg)end gpu.set(x,y,s)end local function clamp(s,w)if unicode.len(s)<=w then return s end return unicode.sub(s,1,math.max(0,w-1)).."…"end local function drawBar() gpu.setBackground(C.bar) gpu.fill(1,1,SW,3," ") set(2,1,clamp(S.title or"OCBrowser",SW-2),C.status,C.bar) for _,b in ipairs(BTN)do local on=(b[2]~="back"or#S.back>0)and(b[2]~="fwd"or#S.fwd>0) local label=b[2]=="reload"and S.job and" × "or b[2]=="mark"and(S.isBookmarked()and" ◆ "or" ◇ ")or b[1] set(b[3],2,label,on and C.btnFg or C.off,C.urlBox) end local bg=ui.editing and C.urlFocus or C.urlBox gpu.setBackground(bg) gpu.fill(URL_X,2,URL_W,1," ") local text=ui.editing and ui.addr or S.url local off=ui.editing and math.max(0,ui.cur-(URL_W-3))or 0 set(URL_X+1,2,clamp(unicode.sub(text,off+1),URL_W-2),C.urlText,bg) if ui.editing then local ch=unicode.sub(ui.addr,ui.cur+1,ui.cur+1) set(URL_X+1+ui.cur-off,2,ch==""and" "or ch,bg,C.urlText) end set(GO_X,2," ▶",C.btnFg,C.accent) gpu.setBackground(C.bar) local status=ui.find and("Find: "..ui.find.."_ (Enter next, Esc close)")or(S.status or"") local sel=S.page and S.page.links[S.sel or 0] if sel and not ui.find then status="→ "..W.resolve(S.url,sel.href)end set(2,3,clamp(status,SW-24),C.status,C.bar) if S.job then local bw=20 local p=S.job.progress or((computer.uptime()*0.7)%1) local n=math.floor((bw-2)*p) set(SW-bw,3,"["..string.rep("■",n)..string.rep(" ",bw-2-n).."]",C.status,C.bar) end end local function drawPage() gpu.setBackground(C.pageBg) gpu.fill(1,PAGE_Y,PAGE_W,PAGE_H," ") local page=S.page if not page then return end local lines=page.lines S.scroll=math.max(0,math.min(S.scroll or 0,math.max(0,#lines-PAGE_H))) local sel=page.links[S.sel or 0] for row=1,PAGE_H do local li=S.scroll+row local line=lines[li] if not line then break end local y=PAGE_Y+row-1 local rowBg=ui.findLine==li and C.find or C.pageBg if rowBg~=C.pageBg then gpu.setBackground(rowBg);gpu.fill(1,y,PAGE_W,1," ")end local x=2+(line.indent or 0) for _,seg in ipairs(line.segs)do local isSel=sel and seg.href and sel.line==li and sel.href==seg.href set(x,y,seg.text,isSel and 0xffffff or seg.fg or PAGE_COLORS.text,isSel and C.sel or rowBg) x=x+unicode.len(seg.text) end end gpu.setBackground(C.scrollbar) gpu.fill(SW,PAGE_Y,1,PAGE_H," ") if#lines>PAGE_H then local h=math.max(1,PAGE_H*PAGE_H//#lines) local y=(PAGE_H-h)*S.scroll//math.max(1,#lines-PAGE_H) gpu.setBackground(C.scrollFg) gpu.fill(SW,PAGE_Y+y,1,h," ") end end local function redraw() if ui.dirtyBar then drawBar();ui.dirtyBar=false end if ui.dirtyPage then drawPage();ui.dirtyPage=false end end local function dirty(page)ui.dirtyBar=true;if page then ui.dirtyPage=true end end local function scrollBy(n)if S.page then S.scroll=(S.scroll or 0)+n;dirty(true)end end local function selectLink(dir) local links=S.page and S.page.links or{} if#links==0 then return end S.sel=((S.sel or 0)-1+dir)%#links+1 local li=links[S.sel].line if li<=S.scroll then S.scroll=li-1 elseif li>S.scroll+PAGE_H then S.scroll=li-PAGE_H end dirty(true) end local function follow(href)if href then ui.editing=false;S.navigate(W.resolve(S.url,href));dirty(true)end end local function editAddress()ui.editing,ui.addr=true,S.url;ui.cur=unicode.len(ui.addr);dirty()end local function findNext() local i=S.find(ui.find or"",ui.findLine or S.scroll) ui.findLine=i if i then S.scroll=math.max(0,i-3)end dirty(true) end local function savePage() fs.makeDirectory("/home/Downloads") local p="/home/Downloads/"..((S.title or"page"):gsub("[^%w%-_]","_"):sub(1,24))..".html" local f=io.open(p,"w") if f then f:write(S.body or"");f:close();S.status="Saved "..p end dirty() end local function onClick(x,y,btn) if y==2 then for _,b in ipairs(BTN)do if x>=b[3]and x=URL_X and x=GO_X then if ui.editing then ui.editing=false;S.navigate(ui.addr)end return dirty(true)end end if y>=PAGE_Y and S.page then local li=(S.scroll or 0)+y-PAGE_Y+1 for _,l in ipairs(S.page.links)do if l.line==li and x-2>=l.x1 and x-20 then ui.addr=unicode.sub(ui.addr,1,ui.cur-1)..unicode.sub(ui.addr,ui.cur+1);ui.cur=ui.cur-1 end elseif code==K.delete then ui.addr=unicode.sub(ui.addr,1,ui.cur)..unicode.sub(ui.addr,ui.cur+2) elseif code==K.left then ui.cur=math.max(0,ui.cur-1) elseif code==K.right then ui.cur=math.min(unicode.len(ui.addr),ui.cur+1) elseif code==K.home then ui.cur=0 elseif code==K["end"]then ui.cur=unicode.len(ui.addr) elseif char>=32 then ui.addr=unicode.sub(ui.addr,1,ui.cur)..unicode.char(char)..unicode.sub(ui.addr,ui.cur+1);ui.cur=ui.cur+1 end return dirty(true) end if ui.find then if code==K.enter then return findNext() elseif code==K.escape then ui.find,ui.findLine=nil,nil;return dirty(true) elseif code==K.back then ui.find=unicode.sub(ui.find,1,-2);return dirty() elseif char>=32 and not ctrl then ui.find=ui.find..unicode.char(char);return dirty()end end if ctrl then if code==K.l then editAddress() elseif code==K.f then ui.find="";dirty() elseif code==K.d then S.toggleBookmark();dirty() elseif code==K.u then S.toggleSource();dirty(true) elseif code==K.s then savePage() elseif code==K.b then S.navigate("about:bookmarks") elseif code==K.h then S.navigate("about:history") elseif code==K.q then return"quit"end return end if alt and code==K.left then S.goBack()elseif alt and code==K.right then S.goForward() elseif code==K.f5 then S.reload() elseif code==K.escape then S.stop();dirty() elseif code==K.up then scrollBy(-1)elseif code==K.down then scrollBy(1) elseif code==K.pageUp then scrollBy(-PAGE_H+1)elseif code==K.pageDown or char==32 then scrollBy(PAGE_H-1) elseif code==K.home then S.scroll=0;dirty(true)elseif code==K["end"]then scrollBy(1e9) elseif code==K.tab then selectLink(keyboard.isShiftDown()and-1 or 1) elseif code==K.enter then local l=S.page and S.page.links[S.sel or 0]if l then follow(l.href)end elseif code==K.back then S.goBack()end dirty(true) end local function main() local fg0,bg0=gpu.getForeground(),gpu.getBackground() gpu.setBackground(C.pageBg) gpu.fill(1,1,SW,SH," ") if not inet then S.status="No Internet Card: only about: pages work"end S.navigate(args[1]or"about:home",false) while true do redraw() local name,_,a,b,c=event.pull(S.job and 0.05 or 1) if name=="interrupted"then break elseif name=="key_down"then if onKey(a,b)=="quit"then break end elseif name=="touch"then onClick(math.floor(a),math.floor(b),c) elseif name=="scroll"then scrollBy(c>0 and-3 or 3) elseif name=="clipboard"then if ui.editing then ui.addr=ui.addr..a;ui.cur=unicode.len(ui.addr);dirty()end end if S.job then S.step();dirty(S.job==nil)end end S.stop() gpu.setForeground(fg0);gpu.setBackground(bg0) gpu.fill(1,1,SW,SH," ") term.setCursor(1,1) end local ok,err=pcall(main) if not ok then gpu.setBackground(0);gpu.setForeground(0xffffff) term.clear() io.stderr:write("browser: "..tostring(err).."\n") end F 752 /bin/cat.lua local shell=require("shell") local fs=require("filesystem") local args=shell.parse(...) if#args==0 then args={"-"} end local input_method,input_param="read",require("tty").getViewport() for i=1,#args do local arg=shell.resolve(args[i]) if fs.isDirectory(arg)then io.stderr:write(string.format('cat %s: Is a directory\n',arg)) os.exit(1) else local file,reason if args[i]=="-"then file,reason=io.stdin,"missing stdin" input_method,input_param="readLine",false else file,reason=fs.open(arg) end if not file then io.stderr:write(string.format("cat: %s: %s\n",args[i],tostring(reason))) os.exit(1) else repeat local chunk=file[input_method](file,input_param) if chunk then io.write(chunk) end until not chunk file:close() end end end io.stdout:close() F 907 /bin/cd.lua local shell=require("shell") local fs=require("filesystem") local args,ops=shell.parse(...) local path=nil local verbose=false if ops.help then print( [[Usage cd [dir] For more options, run: man cd]]) return end if#args==0 then local home=os.getenv("HOME") if not home then io.stderr:write("cd: HOME not set\n") return 1 end path=home elseif args[1]=='-'then verbose=true local oldpwd=os.getenv("OLDPWD"); if not oldpwd then io.stderr:write("cd: OLDPWD not set\n") return 1 end path=oldpwd else path=args[1] end local resolved=shell.resolve(path) if not fs.exists(resolved)then io.stderr:write("cd: ",path,": No such file or directory\n") return 1 end path=resolved local oldpwd=shell.getWorkingDirectory() local result,reason=shell.setWorkingDirectory(path) if not result then io.stderr:write("cd: ",path,": ",reason) return 1 else os.setenv("OLDPWD",oldpwd) end if verbose then os.execute("pwd") end F 36 /bin/clear.lua local tty=require("tty") tty.clear()F 1020 /bin/components.lua local component=require("component") local shell=require("shell") local text=require("text") local args,options=shell.parse(...) local count=tonumber(options.limit)or math.huge local components={} local padTo=1 if#args==0 then args[1]="" end for _,filter in ipairs(args)do for address,name in component.list(filter)do if name:len()>padTo then padTo=name:len()+2 end components[address]=name end end padTo=padTo+8-padTo%8 for address,name in pairs(components)do io.write(text.padRight(name,padTo)..address..'\n') if options.l then local proxy=component.proxy(address) local padTo=1 local methods={} for name,member in pairs(proxy)do if type(member)=="table"or type(member)=="function"then if name:len()>padTo then padTo=name:len()+2 end table.insert(methods,name) end end table.sort(methods) padTo=padTo+8-padTo%8 for _,name in ipairs(methods)do local doc=component.doc(address,name)or tostring(proxy[name]) io.write(" "..text.padRight(name,padTo)..doc..'\n') end end count=count-1 if count<=0 then break end end F 833 /bin/cp.lua local shell=require("shell") local transfer=require("tools/transfer") local args,options=shell.parse(...) options.h=options.h or options.help if#args<2 or options.h then io.write([[Usage: cp [OPTIONS] -i: prompt before overwrite (overrides -n option). -n: do not overwrite an existing file. -r: copy directories recursively. -u: copy only when the SOURCE file differs from the destination file or when the destination file is missing. -P: preserve attributes, e.g. symbolic links. -v: verbose output. -x: stay on original source file system. --skip=P: skip files matching lua regex P ]]) return not not options.h end options= { cmd="cp", i=options.i, f=options.f, n=options.n, r=options.r, u=options.u, P=options.P, v=options.v, x=options.x, skip={options.skip}, } return transfer.batch(args,options) F 33 /bin/date.lua io.write(os.date("%F %T").."\n") F 1354 /bin/desktop.lua local shell=require("shell") local computer=require("computer") local fs=require("filesystem") local args,opts=shell.parse(...) local MARK="/etc/yaru.crash" local function unload() for k in pairs(package.loaded)do if k:match("^yaru%.")then package.loaded[k]=nil end end end local nologin=opts.nologin or opts.n while true do unload() local Y=require("yaru.core") local f=io.open(MARK,"w")if f then f:write("starting")f:close()end local ok,res=xpcall(Y.run,debug.traceback,{nologin=nologin,onStarted=function()fs.remove(MARK)end}) fs.remove(MARK) unload() if not ok then local lf=io.open("/tmp/desktop.log","a")if lf then lf:write(tostring(res),"\n")lf:close()end local mf=io.open("/tmp/.desktop_msg","w") if mf then mf:write("Desktop error: "..tostring(res):match("[^\n]*").." (details: /tmp/desktop.log)")mf:close()end local gpu=require("component").gpu gpu.setBackground(0)gpu.setForeground(0xFFFFFF) local w,h=gpu.getResolution() gpu.fill(1,1,w,h," ") require("term").setCursor(1,1) io.stderr:write("The desktop stopped with an error:\n"..tostring(res).."\n") io.write("Falling back to the text shell. Run 'desktop' to try again.\n") return 1 end if res=="reboot"then computer.shutdown(true) elseif res=="shutdown"then computer.shutdown() elseif res=="restart-shell"then nologin=true else nologin=false if res=="exit"then return 0 end end end F 1607 /bin/df.lua local fs=require("filesystem") local shell=require("shell") local text=require("text") local args,options=shell.parse(...) local function formatSize(size) if not options.h then return tostring(size) elseif type(size)=="string"then return size end local sizes={"","K","M","G"} local unit=1 local power=options.si and 1000 or 1024 while size>power and unit<#sizes do unit=unit+1 size=size/power end return math.floor(size*10)/10 ..sizes[unit] end local mounts={} if#args==0 then for proxy,path in fs.mounts()do if not mounts[proxy]or mounts[proxy]:len()>path:len()then mounts[proxy]=path end end else for i=1,#args do local proxy,path=fs.get(shell.resolve(args[i])) if not proxy then io.stderr:write(args[i],": no such file or directory\n") else mounts[proxy]=path end end end local result={{"Filesystem","Used","Available","Use%","Mounted on"}} for proxy,path in pairs(mounts)do local label=proxy.getLabel()or proxy.address local used,total=proxy.spaceUsed(),proxy.spaceTotal() local available,percent if total==math.huge then used=used or"N/A" available="unlimited" percent="0%" else available=total-used percent=used/total if percent~=percent then available="N/A" percent="N/A" else percent=math.ceil(percent*100).."%" end end table.insert(result,{label,formatSize(used),formatSize(available),tostring(percent),path}) end local m={} for _,row in ipairs(result)do for col,value in ipairs(row)do m[col]=math.max(m[col]or 1,value:len()) end end for _,row in ipairs(result)do for col,value in ipairs(row)do local padding=col==#row and 0 or 2 io.write(text.padRight(value,m[col]+padding)) end print() end F 949 /bin/dmesg.lua local event=require("event") local tty=require("tty") local args={...} local gpu=tty.gpu() local interactive=io.output().tty local color,isPal,evt if interactive then color,isPal=gpu.getForeground() end io.write("Press 'Ctrl-C' to exit\n") pcall(function() repeat if#args>0 then evt=table.pack(event.pullMultiple("interrupted",table.unpack(args))) else evt=table.pack(event.pull()) end if interactive then gpu.setForeground(0xCC2200)end io.write("["..os.date("%T").."] ") if interactive then gpu.setForeground(0x44CC00)end io.write(tostring(evt[1])..string.rep(" ",math.max(10-#tostring(evt[1]),0)+1)) if interactive then gpu.setForeground(0xB0B00F)end io.write(tostring(evt[2])..string.rep(" ",37-#tostring(evt[2]))) if interactive then gpu.setForeground(0xFFFFFF)end if evt.n>2 then for i=3,evt.n do io.write(" "..tostring(evt[i])) end end io.write("\n") until evt[1]=="interrupted" end) if interactive then gpu.setForeground(color,isPal) end F 2530 /bin/du.lua local shell=require("shell") local fs=require("filesystem") local args,options,reason=shell.parse(...) if#args==0 then args[1]='.' end local TRY=[[ Try 'du --help' for more information.]] local VERSION=[[ du (OpenOS bin) 1.0 Written by payonel, patterned after GNU coreutils du]] local HELP=[[ Usage: du [OPTION]... [FILE]... Summarize disk usage of each FILE, recursively for directories. -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G) -s, --summarize display only a total for each argument --help display this help and exit --version output version information and exit]] if options.help then print(HELP) return true end if options.version then print(VERSION) return true end local function addTrailingSlash(path) if path:sub(-1)~='/'then return path..'/' else return path end end local function opCheck(shortName,longName) local enabled=options[shortName]or options[longName] options[shortName]=nil options[longName]=nil return enabled end local bHuman=opCheck('h','human-readable') local bSummary=opCheck('s','summarize') if next(options)then for op,v in pairs(options)do io.stderr:write(string.format("du: invalid option -- '%s'\n",op)) end io.stderr:write(TRY..'\n') return 1 end local function formatSize(size) if not bHuman then return tostring(size) end local sizes={"","K","M","G"} local unit=1 local power=options.si and 1000 or 1024 while size>power and unit<#sizes do unit=unit+1 size=size/power end return math.floor(size*10)/10 ..sizes[unit] end local function printSize(size,rpath) local displaySize=formatSize(size) io.write(string.format("%s%s\n",string.format("%-12s",displaySize),rpath)) end local function visitor(rpath) local subtotal=0 local dirs=0 local spath=shell.resolve(rpath) if fs.isDirectory(spath)then local list_result=fs.list(spath) for list_item in list_result do local vtotal,vdirs=visitor(addTrailingSlash(rpath)..list_item) subtotal=subtotal+vtotal dirs=dirs+vdirs end if dirs==0 then if not bSummary then printSize(subtotal,rpath) end end elseif not fs.isLink(spath)then subtotal=fs.size(spath) end return subtotal,dirs end for i,arg in ipairs(args)do local path=shell.resolve(arg) if not fs.exists(path)then io.stderr:write(string.format("du: cannot access '%s': no such file or directory\n",arg)) return 1 else if fs.isDirectory(path)then local total=visitor(arg) if bSummary then printSize(total,arg) end elseif fs.isLink(path)then printSize(0,arg) else printSize(fs.size(path),arg) end end end return true F 494 /bin/echo.lua local args,options=require("shell").parse(...) if options.help then io.write([[ `echo` writes the provided string(s) to the standard output. -n do not output the trialing newline -e enable interpretation of backslash escapes --help display this help and exit ]]) return end if options.e then for index,arg in ipairs(args)do args[index]=assert(load("return \""..arg:gsub('"',[[\"]]).."\""))() end end io.write(table.concat(args," ")) if not options.n then io.write("\n") end F 14641 /bin/edit.lua local fs=require("filesystem") local keyboard=require("keyboard") local shell=require("shell") local term=require("term") local text=require("text") local unicode=require("unicode") if not term.isAvailable()then return end local gpu=term.gpu() local args,options=shell.parse(...) if#args==0 then io.write("Usage: edit ") return end local filename=shell.resolve(args[1]) local file_parentpath=fs.path(filename) if fs.exists(file_parentpath)and not fs.isDirectory(file_parentpath)then io.stderr:write(string.format("Not a directory: %s\n",file_parentpath)) return 1 end local readonly=options.r or fs.get(filename)==nil or fs.get(filename).isReadOnly() if fs.isDirectory(filename)then io.stderr:write("file is a directory\n") return 1 elseif not fs.exists(filename)and readonly then io.stderr:write("file system is read only\n") return 1 end local function loadConfig() local env={} local config=loadfile("/etc/edit.cfg",nil,env) if config then pcall(config) end env.keybinds=env.keybinds or{ left={{"left"}}, right={{"right"}}, up={{"up"}}, down={{"down"}}, home={{"home"}}, eol={{"end"}}, pageUp={{"pageUp"}}, pageDown={{"pageDown"}}, backspace={{"back"},{"shift","back"}}, delete={{"delete"}}, deleteLine={{"control","delete"},{"shift","delete"}}, newline={{"enter"}}, save={{"control","s"}}, close={{"control","w"}}, find={{"control","f"}}, findnext={{"control","g"},{"control","n"},{"f3"}}, cut={{"control","k"}}, uncut={{"control","u"}} } if not config then local root=fs.get("/") if root and not root.isReadOnly()then fs.makeDirectory("/etc") local f=io.open("/etc/edit.cfg","w") if f then local serialization=require("serialization") for k,v in pairs(env)do f:write(k.."="..tostring(serialization.serialize(v,math.huge)).."\n") end f:close() end end end return env end term.clear() term.setCursorBlink(true) local running=true local buffer={} local scrollX,scrollY=0,0 local config=loadConfig() local cutBuffer={} local cutting=false local getKeyBindHandler local function helpStatusText() local function prettifyKeybind(label,command) local keybind=type(config.keybinds)=="table"and config.keybinds[command] if type(keybind)~="table"or type(keybind[1])~="table"then return""end local alt,control,shift,key for _,value in ipairs(keybind[1])do if value=="alt"then alt=true elseif value=="control"then control=true elseif value=="shift"then shift=true else key=value end end if not key then return""end return label..": [".. (control and"Ctrl+"or"").. (alt and"Alt+"or"").. (shift and"Shift+"or"").. unicode.upper(key).. "] " end return prettifyKeybind("Save","save").. prettifyKeybind("Close","close").. prettifyKeybind("Find","find").. prettifyKeybind("Cut","cut").. prettifyKeybind("Uncut","uncut") end local function setStatus(value) local x,y,w,h=term.getGlobalArea() value=unicode.wlen(value)>w-10 and unicode.wtrunc(value,w-9)or value value=text.padRight(value,w-10) gpu.set(x,y+h-1,value) end local function getArea() local x,y,w,h=term.getGlobalArea() return x,y,w,h-1 end local function removePrefix(line,length) if length>=unicode.wlen(line)then return"" else local prefix=unicode.wtrunc(line,length+1) local suffix=unicode.sub(line,unicode.len(prefix)+1) length=length-unicode.wlen(prefix) if length>0 then suffix=(" "):rep(unicode.charWidth(suffix)-length)..unicode.sub(suffix,2) end return suffix end end local function lengthToChars(line,length) if length>unicode.wlen(line)then return unicode.len(line)+1 else local prefix=unicode.wtrunc(line,length) return unicode.len(prefix)+1 end end local function isWideAtPosition(line,x) local index=lengthToChars(line,x) if index>unicode.len(line)then return false,false end local prefix=unicode.sub(line,1,index) local char=unicode.sub(line,index,index) return unicode.isWide(char),unicode.wlen(prefix)==x end local function drawLine(x,y,w,h,lineNr) local yLocal=lineNr-scrollY if yLocal>0 and yLocal<=h then local str=removePrefix(buffer[lineNr]or"",scrollX) str=unicode.wlen(str)>w and unicode.wtrunc(str,w+1)or str str=text.padRight(str,w) gpu.set(x,y-1+lineNr-scrollY,str) end end local function getCursor() local cx,cy=term.getCursor() return cx+scrollX,cy+scrollY end local function line() local _,cby=getCursor() return buffer[cby]or"" end local function getNormalizedCursor() local cbx,cby=getCursor() local wide,right=isWideAtPosition(buffer[cby],cbx) if wide and right then cbx=cbx-1 end return cbx,cby end local function setCursor(nbx,nby) local x,y,w,h=getArea() nbx,nby=math.floor(nbx),math.floor(nby) nby=math.max(1,math.min(#buffer,nby)) local ncy=nby-scrollY if ncy>h then term.setCursorBlink(false) local sy=nby-h local dy=math.abs(scrollY-sy) scrollY=sy if h>dy then gpu.copy(x,y+dy,w,h-dy,0,-dy) end for lineNr=nby-(math.min(dy,h)-1),nby do drawLine(x,y,w,h,lineNr) end elseif ncy<1 then term.setCursorBlink(false) local sy=nby-1 local dy=math.abs(scrollY-sy) scrollY=sy if h>dy then gpu.copy(x,y,w,h-dy,0,dy) end for lineNr=nby,nby+(math.min(dy,h)-1)do drawLine(x,y,w,h,lineNr) end end term.setCursor(term.getCursor(),nby-scrollY) nbx=math.max(1,math.min(unicode.wlen(line())+1,nbx)) local wide,right=isWideAtPosition(line(),nbx) local ncx=nbx-scrollX if ncx>w or(ncx+1>w and wide and not right)then term.setCursorBlink(false) scrollX=nbx-w+((wide and not right)and 1 or 0) for lineNr=1+scrollY,math.min(h+scrollY,#buffer)do drawLine(x,y,w,h,lineNr) end elseif ncx<1 or(ncx-1<1 and wide and right)then term.setCursorBlink(false) scrollX=nbx-1-((wide and right)and 1 or 0) for lineNr=1+scrollY,math.min(h+scrollY,#buffer)do drawLine(x,y,w,h,lineNr) end end term.setCursor(nbx-scrollX,nby-scrollY) nbx,nby=getCursor() local locstring=string.format("%d,%d",nby,nbx) if#cutBuffer>0 then locstring=string.format("(#%d) %s",#cutBuffer,locstring) end locstring=text.padLeft(locstring,10) gpu.set(x+w-#locstring,y+h,locstring) end local function highlight(bx,by,length,enabled) local x,y,w,h=getArea() local cx,cy=bx-scrollX,by-scrollY cx=math.max(1,math.min(w,cx)) cy=math.max(1,math.min(h,cy)) length=math.max(1,math.min(w-cx,length)) local fg,fgp=gpu.getForeground() local bg,bgp=gpu.getBackground() if enabled then gpu.setForeground(bg,bgp) gpu.setBackground(fg,fgp) end local indexFrom=lengthToChars(buffer[by],bx) local value=unicode.sub(buffer[by],indexFrom) if unicode.wlen(value)>length then value=unicode.wtrunc(value,length+1) end gpu.set(x-1+cx,y-1+cy,value) if enabled then gpu.setForeground(fg,fgp) gpu.setBackground(bg,bgp) end end local function home() local _,cby=getCursor() setCursor(1,cby) end local function ende() local _,cby=getCursor() setCursor(unicode.wlen(line())+1,cby) end local function left() local cbx,cby=getNormalizedCursor() if cbx>1 then local wideTarget,rightTarget=isWideAtPosition(line(),cbx-1) if wideTarget and rightTarget then setCursor(cbx-2,cby) else setCursor(cbx-1,cby) end return true elseif cby>1 then setCursor(cbx,cby-1) ende() return true end end local function right(n) n=n or 1 local cbx,cby=getNormalizedCursor() local be=unicode.wlen(line())+1 local wide,isRight=isWideAtPosition(line(),cbx+n) if wide and isRight then n=n+1 end if cbx+n<=be then setCursor(cbx+n,cby) elseif cby<#buffer then setCursor(1,cby+1) end end local function up(n) n=n or 1 local cbx,cby=getCursor() if cby>1 then setCursor(cbx,cby-n) end cutting=false end local function down(n) n=n or 1 local cbx,cby=getCursor() if cby<#buffer then setCursor(cbx,cby+n) end cutting=false end local function delete(fullRow) local _,cy=term.getCursor() local cbx,cby=getCursor() local x,y,w,h=getArea() local function deleteRow(row) local content=table.remove(buffer,row) local rcy=cy+(row-cby) if rcy<=h then gpu.copy(x,y+rcy,w,h-rcy,0,-1) drawLine(x,y,w,h,row+(h-rcy)) end return content end if fullRow then term.setCursorBlink(false) if#buffer>1 then deleteRow(cby) else buffer[cby]="" gpu.fill(x,y-1+cy,w,1," ") end setCursor(1,cby) elseif cbx<=unicode.wlen(line())then term.setCursorBlink(false) local index=lengthToChars(line(),cbx) buffer[cby]=unicode.sub(line(),1,index-1).. unicode.sub(line(),index+1) drawLine(x,y,w,h,cby) elseif cby<#buffer then term.setCursorBlink(false) local append=deleteRow(cby+1) buffer[cby]=buffer[cby]..append drawLine(x,y,w,h,cby) else return end setStatus(helpStatusText()) end local function insert(value) if not value or unicode.len(value)<1 then return end term.setCursorBlink(false) local cbx,cby=getCursor() local x,y,w,h=getArea() local index=lengthToChars(line(),cbx) buffer[cby]=unicode.sub(line(),1,index-1).. value.. unicode.sub(line(),index) drawLine(x,y,w,h,cby) right(unicode.wlen(value)) setStatus(helpStatusText()) end local function enter() term.setCursorBlink(false) local _,cy=term.getCursor() local cbx,cby=getCursor() local x,y,w,h=getArea() local index=lengthToChars(line(),cbx) table.insert(buffer,cby+1,unicode.sub(buffer[cby],index)) buffer[cby]=unicode.sub(buffer[cby],1,index-1) drawLine(x,y,w,h,cby) if cy0 then local sx,sy for syo=1,#buffer do sy=(iby+syo-1+#buffer-1)%#buffer+1 sx=string.find(buffer[sy],findText,syo==1 and ibx or 1,true) if sx and(sx>=ibx or syo>1)then break end end if not sx then sy=iby sx=string.find(buffer[sy],findText,nil,true) end if sx then sx=unicode.wlen(string.sub(buffer[sy],1,sx-1))+1 cbx,cby=sx,sy setCursor(cbx,cby) highlight(cbx,cby,unicode.wlen(findText),true) end end term.setCursor(7+unicode.wlen(findText),h+1) setStatus("Find: "..findText) local _,address,char,code=term.pull("key_down") if address==term.keyboard()then local handler,name=getKeyBindHandler(code) highlight(cbx,cby,unicode.wlen(findText),false) if name=="newline"then break elseif name=="close"then handler() elseif name=="backspace"then findText=unicode.sub(findText,1,-2) elseif name=="find"or name=="findnext"then ibx=cbx+1 iby=cby elseif not keyboard.isControl(char)then findText=findText..unicode.char(char) end end end setCursor(cbx,cby) setStatus(helpStatusText()) end local function cut() if not cutting then cutBuffer={} end local cbx,cby=getCursor() table.insert(cutBuffer,buffer[cby]) delete(true) cutting=true home() end local function uncut() home() for _,line in ipairs(cutBuffer)do insert(line) enter() end end local keyBindHandlers={ left=left, right=right, up=up, down=down, home=home, eol=ende, pageUp=function() local _,_,_,h=getArea() up(h-1) end, pageDown=function() local _,_,_,h=getArea() down(h-1) end, backspace=function() if not readonly and left()then delete() end end, delete=function() if not readonly then delete() end end, deleteLine=function() if not readonly then delete(true) end end, newline=function() if not readonly then enter() end end, save=function() if readonly then return end local new=not fs.exists(filename) local backup if not new then backup=filename.."~" for i=1,math.huge do if not fs.exists(backup)then break end backup=filename.."~"..i end fs.copy(filename,backup) end if not fs.exists(file_parentpath)then fs.makeDirectory(file_parentpath) end local f,reason=io.open(filename,"w") if f then local chars,firstLine=0,true for _,bline in ipairs(buffer)do if not firstLine then bline="\n"..bline end firstLine=false f:write(bline) chars=chars+unicode.len(bline) end f:close() local format if new then format=[["%s" [New] %dL,%dC written]] else format=[["%s" %dL,%dC written]] end setStatus(string.format(format,fs.name(filename),#buffer,chars)) else setStatus(reason) end if not new then fs.remove(backup) end end, close=function() running=false end, find=function() findText="" find() end, findnext=find, cut=cut, uncut=uncut } getKeyBindHandler=function(code) if type(config.keybinds)~="table"then return end local result,resultName,resultWeight=nil,nil,0 for command,keybinds in pairs(config.keybinds)do if type(keybinds)=="table"and keyBindHandlers[command]then for _,keybind in ipairs(keybinds)do if type(keybind)=="table"then local alt,control,shift,key=false,false,false for _,value in ipairs(keybind)do if value=="alt"then alt=true elseif value=="control"then control=true elseif value=="shift"then shift=true else key=value end end local keyboardAddress=term.keyboard() if(alt==not not keyboard.isAltDown(keyboardAddress))and (control==not not keyboard.isControlDown(keyboardAddress))and (shift==not not keyboard.isShiftDown(keyboardAddress))and code==keyboard.keys[key]and #keybind>resultWeight then resultWeight=#keybind resultName=command result=keyBindHandlers[command] end end end end end return result,resultName end local function onKeyDown(char,code) local handler=getKeyBindHandler(code) if handler then handler() elseif readonly and code==keyboard.keys.q then running=false elseif not readonly then if not keyboard.isControl(char)then insert(unicode.char(char)) elseif unicode.char(char)=="\t"then insert(" ") end end end local function onClipboard(value) value=value:gsub("\r\n","\n") local start=1 local l=value:find("\n",1,true) if l then repeat local next_line=string.sub(value,start,l-1) next_line=text.detab(next_line,2) insert(next_line) enter() start=l+1 l=value:find("\n",start,true) until not l end insert(string.sub(value,start)) end local function onClick(x,y) setCursor(x+scrollX,y+scrollY) end local function onScroll(direction) local cbx,cby=getCursor() setCursor(cbx,cby-direction*12) end do local f=io.open(filename) if f then local x,y,w,h=getArea() local chars=0 for fline in f:lines()do table.insert(buffer,fline) chars=chars+unicode.len(fline) if#buffer<=h then drawLine(x,y,w,h,#buffer) end end f:close() if#buffer==0 then table.insert(buffer,"") end local format if readonly then format=[["%s" [readonly] %dL,%dC]] else format=[["%s" %dL,%dC]] end setStatus(string.format(format,fs.name(filename),#buffer,chars)) else table.insert(buffer,"") setStatus(string.format([["%s" [New File] ]],fs.name(filename))) end setCursor(1,1) end while running do local event,address,arg1,arg2,arg3=term.pull() if address==term.keyboard()or address==term.screen()then local blink=true if event=="key_down"then onKeyDown(arg1,arg2) elseif event=="clipboard"and not readonly then onClipboard(arg1) elseif event=="touch"or event=="drag"then local x,y,w,h=getArea() arg1=arg1-x+1 arg2=arg2-y+1 if arg1>=1 and arg2>=1 and arg1<=w and arg2<=h then onClick(arg1,arg2) end elseif event=="scroll"then onScroll(arg3) else blink=false end if blink then term.setCursorBlink(true) end end end term.clear() term.setCursorBlink(true) F 2488 /bin/find.lua local shell=require("shell") local fs=require("filesystem") local text=require("text") local USAGE= [===[Usage: find [path] [--type=[dfs]] [--[i]name=EXPR] --path if not specified, path is assumed to be current working directory --type returns results of a given type, d:directory, f:file, and s:symlinks --name specify the file name pattern. Use quote to include *. iname is case insensitive --help display this help and exit]===] local args,options=shell.parse(...) if(not args or not options)or options.help then print(USAGE) if not options.help then return 1 else return end end if#args>1 then io.stderr:write(USAGE..'\n') return 1 end local path=#args==1 and args[1]or"." local bDirs=true local bFiles=true local bSyms=true local fileNamePattern="" local bCaseSensitive=true if options.iname and options.name then io.stderr:write("find cannot define both iname and name\n") return 1 end if options.type then bDirs=false bFiles=false bSyms=false if options.type=="f"then bFiles=true elseif options.type=="d"then bDirs=true elseif options.type=="s"then bSyms=true else io.stderr:write(string.format("find: Unknown argument to type: %s\n",options.type)) io.stderr:write(USAGE..'\n') return 1 end end if options.iname or options.name then bCaseSensitive=options.iname~=nil fileNamePattern=options.iname or options.name if type(fileNamePattern)~="string"then io.stderr:write('find: missing argument to `name\'\n') return 1 end if not bCaseSensitive then fileNamePattern=fileNamePattern:lower() end fileNamePattern=text.escapeMagic(fileNamePattern) fileNamePattern=fileNamePattern:gsub("%%%*",".*") end local function isValidType(spath) if not fs.exists(spath)then return false end if fileNamePattern:len()>0 then local fileName=spath:gsub('.*/','') if fileName:len()==0 then return false end local caseFileName=fileName if not bCaseSensitive then caseFileName=caseFileName:lower() end local s,e=caseFileName:find(fileNamePattern) if not s or not e then return false end if s~=1 or e~=caseFileName:len()then return false end end if fs.isDirectory(spath)then return bDirs elseif fs.isLink(spath)then return bSyms else return bFiles end end local function visit(rpath) local spath=shell.resolve(rpath) if isValidType(spath)then local result=rpath:gsub('/+$','') print(result) end if fs.isDirectory(spath)then local list_result=fs.list(spath) for list_item in list_result do visit(rpath:gsub('/+$','')..'/'..list_item) end end end visit(path) F 2439 /bin/flash.lua local component=require("component") local shell=require("shell") local fs=require("filesystem") local args,options=shell.parse(...) if#args<1 and not options.l then io.write("Usage: flash [-qlr] [] [label]\n") io.write(" q: quiet mode, don't ask questions.\n") io.write(" l: print current contents of installed EEPROM.\n") io.write(" r: save the current contents of installed EEPROM to file.\n") return end local function printRom() local eeprom=component.eeprom io.write(eeprom.get()) return nil end local function readRom() local eeprom=component.eeprom local fileName=shell.resolve(args[1]) if not options.q then if fs.exists(fileName)then io.write("Are you sure you want to overwrite "..fileName.."?\n") io.write("Type `y` to confirm.\n") repeat local response=io.read() until response and response:lower():sub(1,1)=="y" end io.write("Reading EEPROM "..eeprom.address..".\n") end local bios=eeprom.get() local file=assert(io.open(fileName,"wb")) file:write(bios) file:close() if not options.q then io.write("All done!\nThe label is '"..eeprom.getLabel().."'.\n") end return nil end local function writeRom() local file=assert(io.open(args[1],"rb")) local bios=file:read("*a") file:close() if not options.q then io.write("Insert the EEPROM you would like to flash.\n") io.write("When ready to write, type `y` to confirm.\n") repeat local response=io.read() until response and response:lower():sub(1,1)=="y" io.write("Beginning to flash EEPROM.\n") end local eeprom=component.eeprom if not options.q then io.write("Flashing EEPROM "..eeprom.address..".\n") io.write("Please do NOT power down or restart your computer during this operation!\n") end local result,reason=eeprom.set(bios) if reason then return nil,reason end local label=args[2] if not options.q and not label then io.write("Enter new label for this EEPROM. Leave input blank to leave the label unchanged.\n") label=io.read() end if label and#label>0 then local result,reason=eeprom.setLabel(label) if reason then return nil,reason end if not options.q then io.write("Set label to '"..eeprom.getLabel().."'.\n") end end if not options.q then io.write("All done! You can remove the EEPROM and re-insert the previous one now.\n") end return nil end local result,reason if options.l then result,reason=printRom() elseif options.r then result,reason=readRom() else result,reason=writeRom() end if reason then io.stderr:write(reason..'\n') return 1 endF 231 /bin/free.lua local computer=require("computer") local total=computer.totalMemory() local max=0 for _=1,40 do max=math.max(max,computer.freeMemory()) os.sleep(0) end io.write(string.format("Total%12d\nUsed%13d\nFree%13d\n",total,total-max,max)) F 6909 /bin/grep.lua local fs=require("filesystem") local shell=require("shell") local tty=require("tty") local computer=require("computer") local args,options=shell.parse(...) local gpu=tty.gpu() local function printUsage(ostream,msg) local s=ostream or io.stdout if msg then s:write(msg,'\n') end s:write([[Usage: grep [OPTION]... PATTERN [FILE]... Example: grep -i "hello world" menu.lua main.lua for more information, run: man grep ]]) end local PATTERNS={args[1]} local FILES={select(2,table.unpack(args))} local LABEL_COLOR=0xb000b0 local LINE_NUM_COLOR=0x00FF00 local MATCH_COLOR=0xFF0000 local COLON_COLOR=0x00FFFF local function pop(...) local result for _,key in ipairs({...})do result=options[key]or result options[key]=nil end return result end local plain=pop('F','fixed-strings') plain=not pop('e','--lua-regexp')and plain local pattern_file=pop('file') local match_whole_word=pop('w','word-regexp') local match_whole_line=pop('x','line-regexp') local ignore_case=pop('i','ignore-case') local stdin_label=pop('label')or'(standard input)' local stderr=pop('s','no-messages')and{write=function()end}or io.stderr local invert_match=not not pop('v','invert-match') if pop('V','version','help')then printUsage() return 0 end local max_matches=tonumber(pop('max-count'))or math.huge local print_line_num=pop('n','line-number') local search_recursively=pop('r','recursive') if pattern_file then local pattern_file_path=shell.resolve(pattern_file) if not fs.exists(pattern_file_path)then stderr:write('grep: ',pattern_file,': file not found') return 2 end table.insert(FILES,1,PATTERNS[1]) PATTERNS={} for line in io.lines(pattern_file_path)do PATTERNS[#PATTERNS+1]=line end end if#PATTERNS==0 then printUsage(stderr) return 2 end if#FILES==0 then FILES=search_recursively and{'.'}or{'-'} end if not options.h and search_recursively then options.H=true end if#FILES<2 then options.h=true end local f_only=pop('l','files-with-matches') local no_only=pop('L','files-without-match')and not f_only local include_filename=pop('H','with-filename') include_filename=not pop('h','no-filename')or include_filename local m_only=pop('o','only-matching') local quiet=pop('q','quiet','silent') local print_count=pop('c','count') local colorize=pop('color','colour')and io.output().tty and tty.isAvailable() local noop=function(...)return...;end local setc=colorize and gpu.setForeground or noop local getc=colorize and gpu.getForeground or noop local trim=pop('t','trim') local trim_front=trim and function(s)return s:gsub('^%s+','')end or noop local trim_back=trim and function(s)return s:gsub('%s+$','')end or noop if next(options)then if not quiet then printUsage(stderr,'unexpected option: '..next(options)) return 2 end return 0 end local function resolve(file) if file:sub(1,1)=='/'then return fs.canonical(file) else if file:sub(1,2)=='./'then file=file:sub(3,-1) end return fs.canonical(fs.concat(shell.getWorkingDirectory(),file)) end end if ignore_case then for i=1,#PATTERNS do PATTERNS[i]=PATTERNS[i]:gsub("(%%?)(.)",function(percent,letter) if percent~=""or not letter:match("%a")then return percent..letter else return string.format("[%s%s]",letter:lower(),letter:upper()) end end) end end local function getAllFiles(dir,file_list) for node in fs.list(shell.resolve(dir))do local rel_path=dir:gsub("/+$","")..'/'..node local resolved_path=shell.resolve(rel_path) if fs.isDirectory(resolved_path)then getAllFiles(rel_path,file_list) else file_list[#file_list+1]=rel_path end end end if search_recursively then local files={} for i,arg in ipairs(FILES)do if fs.isDirectory(arg)then getAllFiles(arg,files) else files[#files+1]=arg end end FILES=files end local function readLines() local curHand=nil local curFile=nil local meta=nil return function() if not curFile then local file=table.remove(FILES,1) if not file then return end meta={line_num=0,hits=0} if file=="-"then curFile=file meta.label=stdin_label curHand=io.input() else meta.label=file local file,reason=resolve(file) if fs.exists(file)then curHand,reason=io.open(file,'r') if not curHand then local msg=string.format("failed to read from %s: %s",meta.label,reason) stderr:write("grep: ",msg,"\n") return false,2 else curFile=meta.label end else stderr:write("grep: ",file,": file not found\n") return false,2 end end end meta.line=nil if not meta.close and curHand then meta.line_num=meta.line_num+1 meta.line=curHand:read("*l") end if not meta.line then curFile=nil if curHand then curHand:close() end return false,meta else return meta,curFile end end end local function write(part,color) local prev_color=color and getc() if color then setc(color)end io.write(part) if color then setc(prev_color)end end local flush=(f_only or no_only or print_count)and function(m) if no_only and m.hits==0 or f_only and m.hits~=0 then write(m.label,LABEL_COLOR) write('\n') elseif print_count then if include_filename then write(m.label,LABEL_COLOR) write(':',COLON_COLOR) end write(m.hits) write('\n') end end local ec=nil local any_hit_ec=1 local function test(m,p) local empty_line=true local last_index,slen=1,#m.line local needs_filename,needs_line_num=include_filename,print_line_num local hit_value=1 while last_index<=slen and not m.close do local i,j=m.line:find(p,last_index,plain) local word_fail,line_fail= match_whole_word and not(i and not(m.line:sub(i-1,i-1)..m.line:sub(j+1,j+1)):find("[%a_]")), match_whole_line and not(i==1 and j==slen) local matched=not((m_only or last_index==1)and not i) if(hit_value==1 and word_fail)or line_fail then matched,i,j=false end if invert_match==matched then break end if max_matches==0 then os.exit(1)end any_hit_ec=0 m.hits,hit_value=m.hits+hit_value,0 if f_only or no_only then m.close=true end if flush or quiet then return end if needs_filename then write(m.label,LABEL_COLOR) write(':',COLON_COLOR) needs_filename=nil end if needs_line_num then write(m.line_num,LINE_NUM_COLOR) write(':',COLON_COLOR) needs_line_num=nil end local s=m_only and''or m.line:sub(last_index,(i or 0)-1) local g=i and m.line:sub(i,j)or'' if i==1 then g=trim_front(g)elseif last_index==1 then s=trim_front(s)end if j==slen then g=trim_back(g)elseif not i then s=trim_back(s)end write(s) write(g,MATCH_COLOR) empty_line=false last_index=(j or slen)+1 if m_only or last_index>slen then write("\n") empty_line=true needs_filename,needs_line_num=include_filename,print_line_num elseif p:find("^^")and not plain then p="^$"end end if not empty_line then write("\n")end if max_matches~=math.huge and max_matches>=m.hits then m.close=true end end local uptime=computer.uptime local last_sleep=uptime() for meta,status in readLines()do if uptime()-last_sleep>1 then os.sleep(0) last_sleep=uptime() end if not meta then if type(status)=='table'then if flush then flush(status)end elseif status then ec=status or ec end else for _,p in ipairs(PATTERNS)do test(meta,p) end end end return ec or any_hit_ec F 2477 /bin/head.lua local shell=require("shell") local args,options=shell.parse(...) local error_code=0 local function pop(key,convert) local result=options[key] options[key]=nil if result and convert then local c=tonumber(result) if not c then io.stderr:write(string.format("use --%s=n where n is a number\n",key)) options.help=true error_code=1 end result=c end return result end local bytes=pop('bytes',true) local lines=pop('lines',true) local quiet={pop('q'),pop('quiet'),pop('silent')} quiet=quiet[1]or quiet[2]or quiet[3] local verbose={pop('v'),pop('verbose')} verbose=verbose[1]or verbose[2] local help=pop('help') if help or next(options)then local invalid_key=next(options) if invalid_key then invalid_key=string.format('invalid option: %s\n',invalid_key) error_code=1 else invalid_key='' end print(invalid_key..[[Usage: head [--lines=n] file Print the first 10 lines of each FILE to stdout. For more info run: man head]]) os.exit(error_code) end if#args==0 then args={'-'} end if quiet and verbose then quiet=false end local function new_stream() return { open=true, capacity=math.abs(lines or bytes or 10), bytes=bytes, buffer=(lines and lines<0 and{})or(bytes and bytes<0 and'') } end local function close(stream) if stream.buffer then if type(stream.buffer)=='table'then stream.buffer=table.concat(stream.buffer) end io.stdout:write(stream.buffer) stream.buffer=nil end stream.open=false end local function push(stream,line) if not line then return close(stream) end local cost=stream.bytes and line:len()or 1 stream.capacity=stream.capacity-cost if not stream.buffer then if stream.bytes and stream.capacity<0 then line=line:sub(1,stream.capacity-1) end io.write(line) if stream.capacity<=0 then return close(stream) end else if type(stream.buffer)=='table'then stream.buffer[#stream.buffer+1]=line if stream.capacity<0 then table.remove(stream.buffer,1) stream.capacity=0 end else stream.buffer=stream.buffer..line if stream.capacity<0 then stream.buffer=stream.buffer:sub(-stream.capacity+1) stream.capacity=0 end end end end for i=1,#args do local arg=args[i] local file,reason if arg=='-'then arg='standard input' file=io.stdin else file,reason=io.open(arg,'r') if not file then io.stderr:write(string.format([[head: cannot open '%s' for reading: %s]],arg,reason)) end end if file then if verbose or#args>1 then io.write(string.format('==> %s <==\n',arg)) end local stream=new_stream() while stream.open do push(stream,file:read('*L')) end file:close() end end F 600 /bin/hostname.lua local shell=require("shell") local args,ops=shell.parse(...) local hostname=args[1] if hostname then local file,reason=io.open("/etc/hostname","w") if not file then io.stderr:write("failed to open for writing: ",reason,"\n") return 1 end file:write(hostname) file:close() ops.update=true else local file=io.open("/etc/hostname") if file then hostname=file:read("*l") file:close() end end if ops.update then os.setenv("HOSTNAME_SEPARATOR",hostname and#hostname>0 and":"or"") os.setenv("HOSTNAME",hostname) elseif hostname then print(hostname) else io.stderr:write("Hostname not set\n") return 1 end F 1016 /bin/install.lua local computer=require("computer") local options do local basic,reason=loadfile("/lib/core/install_basics.lua","bt",_G) if not basic then io.stderr:write("failed to load install: "..tostring(reason).."\n") return 1 end options=basic(...) end if not options then return end if computer.freeMemory()<50000 then print("Low memory, collecting garbage") for i=1,20 do os.sleep(0) end end local transfer=require("tools/transfer") for _,inst in ipairs(options.cp_args)do local ec=transfer.batch(table.unpack(inst)) if ec~=nil and ec~=0 then return ec end end print("Installation complete!") if options.setlabel then pcall(options.target.dev.setLabel,options.label) end if options.setboot then local address=options.target.dev.address if computer.setBootAddress(address)then print("Boot address set to "..address) end end if options.reboot then io.write("Reboot now? [Y/n] ") if((io.read()or"n").."y"):match("^%s*[Yy]")then print("\nRebooting now!\n") computer.shutdown(true) end end print("Returning to shell.\n") F 893 /bin/label.lua local shell=require("shell") local devfs=require("devfs") local comp=require("component") local args,options=shell.parse(...) if#args<1 then io.write("Usage: label [-a] [