memebuilder/mods/laptop/apps/cs-bos_app.lua
2022-08-16 16:12:37 -04:00

465 lines
16 KiB
Lua

local help_texts = {
CLS = " Clears the screen.",
CD = " Change disk. CD [HDD,FDD]",
DATE = " Displays the current system date.",
DIR = " Display directory of current disk. DIR [filename] brings up info for specified file or files if using wild card *.",
DEL = " Delete a file. DEL [FILENAME]",
HALT = " Shut down CS-BOS.",
HELP = " Displays HELP menu. HELP [command] displays help on that command.",
MEM = " Displays memory usage table.",
EXIT = " Exit CS-BOS shell",
REBOOT = " Perform a soft reboot.",
TEXTCOLOR = " Change terminal text color. TEXTCOLOR [green, amber, or white]",
SCROLLBACK = "Change terminal scrollback size. SCROLLBACK [##]",
TIME = " Displays the current system time.",
TIMEDATE = " Displays the current system time and date.",
VER = " Displays CS-BOS version.",
FORMAT = " View format information or Format Disk. FORMAT [/E] Erase disk, [/S] Create system (boot) disk, [/D] Create data disk",
LABEL = " Show/Set floppy label. LABEL [new_label]",
}
local function get_initial_message(mtos, data)
data.outlines = {
"BASIC OPERATING SYSTEM v"..mtos.os_attr.version_string,
"(C)COPYRIGHT "..mtos.os_attr.releaseyear.." CARDIFF-SOFT",
"128K RAM SYSTEM 77822 BYTES FREE",
}
end
local function add_outline(data, line)
table.insert(data.outlines, line)
if #data.outlines > data.scrollback_size then
for i = data.scrollback_size, #data.outlines do
table.remove(data.outlines,1)
end
end
end
local function is_executable_app(mtos, app)
if not mtos.sysdata then -- cannot executed withoud sysdata
return false
elseif app and not app.view and -- app given
app.name ~= 'cs-bos_launcher' and -- No recursive calls
mtos:is_app_compatible(app.name) then
return true
else
return false
end
end
local function numWithCommas(n)
return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,"):gsub(",(%-?)$","%1"):reverse()
end
--- Simple VFS for BOS Operations
local simple_vfs_map = {}
-- Hard disk
simple_vfs_map.HDD = {
id = 'HDD',
dev = 'hdd',
longname = 'DISK 0:HDD',
check_inserted = function(disk, mtos)
return mtos.bdev:is_hw_capability('hdd')
end,
get_full_name = function(disk, mtos)
return disk.longname
end,
get_format = function(disk, mtos)
return 'BOOT'
end,
}
-- Floppy disk
simple_vfs_map.FDD = {
id = 'FDD',
dev = 'removable',
longname = 'DISK 0:FDD',
check_inserted = function(disk, mtos)
local idata = mtos.bdev:get_removable_disk()
if idata.stack and ( idata.os_format == 'data' or idata.os_format == 'boot') then
return true
end
end,
get_full_name = function(disk, mtos)
local idata = mtos.bdev:get_removable_disk()
return disk.longname..": "..idata.label
end,
get_format = function(disk, mtos)
local idata = mtos.bdev:get_removable_disk()
return idata.os_format
end,
}
simple_vfs_map.REMOVABLE = simple_vfs_map.FDD
local simple_vfs = {}
-- Get the VFS disk object
function simple_vfs.get_disk(mtos, device)
if not device then
return
end
local disk = simple_vfs_map[device:upper()]
local inserted
if disk then
inserted = disk:check_inserted(mtos)
end
return disk, inserted
end
function simple_vfs.parse_path(input_line)
local filename = input_line:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
local diskname
if filename:sub(4,4) == ':' then
diskname = filename:sub(1,3)
filename = filename:sub(5)
end
return filename, diskname
end
--- End for Simple VFS for BOS Operations
local function initialize_data(data, sdata, mtos, sysos)
if mtos.os_attr.tty_monochrome then
data.tty = mtos.os_attr.tty_style
else
data.tty = sdata.tty or data.tty or mtos.os_attr.tty_style
if not laptop.supported_textcolors[data.tty] then --compat hack
data.tty = mtos.os_attr.tty_style
end
end
data.scrollback_size = sdata.scrollback_size or data.scrollback_size or mtos.os_attr.min_scrollback_size
-- Set initial message on new session
if not data.outlines then
get_initial_message(mtos, data)
end
if not data.current_disk then
if sysos.booted_from == 'removable' then
data.current_disk = 'FDD'
else
data.current_disk = 'HDD'
end
end
data.inputfield = data.inputfield or ""
end
laptop.register_app("cs-bos_launcher", {
app_name = "CS-BOS Prompt",
app_info = "Command Line Interface",
fullscreen = true,
app_icon = "laptop_cs_bos.png",
formspec_func = function(cs_bos, mtos)
local data = mtos.bdev:get_app_storage('ram', 'cs_bos')
local sysos = mtos.bdev:get_app_storage('ram', 'os')
local sdata = mtos.bdev:get_app_storage('system', 'cs_bos') or {} -- handle temporary if no sysdata given
-- no system found. In case of booted from removable, continue in live mode
if not mtos.sysdata and sysos.booted_from ~= "removable" then
local formspec = "size[10,7]background[10,7;0,0;laptop_launcher_insert_floppy.png;true]"..
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"..
"list[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main;2.5,3;1,1;]" ..
"list[current_player;main;0,6.5;8,1;]" ..
"listring[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main]" ..
"listring[current_player;main]"
local idata = mtos.bdev:get_removable_disk()
if idata.stack then
if idata.os_format ~= "boot" then
formspec = formspec .. "label[0,1.7;Disk found but not formatted to boot]"
end
end
return formspec
end
initialize_data(data, sdata, mtos, sysos)
local tty = laptop.supported_textcolors[data.tty]
local formspec =
"size[15,10]background[15,10;0,0;laptop_theme_desktop_icon_label_button_black.png;true]"..
"label[-0.15,9.9;"..minetest.colorize(tty,data.current_disk..">").."]"..
"field[1.020,9.93;15.6,1;inputfield;;"..minetest.formspec_escape(data.inputfield).."]"..
"tablecolumns[text]tableoptions[background=#000000;border=false;highlight=#000000;"..
"color="..tty..";highlight_text="..tty.."]"..
"table[-0.35,-0.35;15.57, 10.12;outlines;"
for idx,line in ipairs(data.outlines) do
if idx > 1 then
formspec = formspec..','
end
formspec = formspec..minetest.formspec_escape(line)
end
formspec = formspec..";"..#data.outlines.."]".."field_close_on_enter[inputfield;false]"
return formspec
end,
receive_fields_func = function(cs_bos, mtos, sender, fields)
local data = mtos.bdev:get_app_storage('ram', 'cs_bos')
local sysos = mtos.bdev:get_app_storage('ram', 'os')
local sdata = mtos.bdev:get_app_storage('system', 'cs_bos') or {} -- handle temporary if no sysdata given
initialize_data(data, sdata, mtos, sysos)
if fields.inputfield then -- move received data to the formspec input field
data.inputfield = fields.inputfield
end
if fields.key_enter then
-- run the command
local exec_all = data.inputfield:split(" ")
local input_line = data.inputfield
local exec_command = exec_all[1] --further parameters are 2++
add_outline(data, "> "..data.inputfield)
data.inputfield = ""
if exec_command then
exec_command = exec_command:upper()
end
if exec_command == nil then --empty line
elseif mtos.os_attr.blacklist_commands[exec_command] then
add_outline(data, '?ERROR NOT IMPLEMENTED')
elseif exec_command == "HALT" then
-- same code as in node_fw on punch to disable the OS
if mtos.hwdef.next_node then
local hwdef_next = laptop.node_config[mtos.hwdef.next_node]
if hwdef_next.hw_state then
mtos[hwdef_next.hw_state](mtos, mtos.hwdef.next_node)
else
mtos:swap_node(hwdef.next_node)
mtos:save()
end
end
elseif exec_command == "DEL" then
local filename, diskname = simple_vfs.parse_path(input_line:sub(5))
if filename then
local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
if disk and inserted then
local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
if txtdata and txtdata[filename] then
txtdata[filename] = nil
add_outline(data, filename:upper()..' DELETED SUCCESSFULY')
else
add_outline(data, 'FILE NOT FOUND: '..filename)
end
end
end
elseif exec_command == "EXIT" then
data.outlines = nil -- reset screen
mtos:set_app() -- quit app (if in app mode)
elseif exec_command == "REBOOT" then
mtos:power_on() -- reboots computer
elseif exec_command == "EJECT" then
local idata = mtos.bdev:get_removable_disk()
local success = idata:eject()
if success then
add_outline(data, 'DISK EJECTED')
else
add_outline(data, 'NO DISK FOUND')
end
elseif is_executable_app(mtos, laptop.apps[exec_command:lower()]) then
add_outline(data, 'LAUNCHED '..exec_command)
mtos:set_app(exec_command:lower())
elseif exec_command == "CD" then
local disk, inserted = simple_vfs.get_disk(mtos, exec_all[2])
if disk and inserted then
data.current_disk = disk.id
add_outline(data, "CURRENT DISK = "..disk:get_full_name(mtos))
elseif disk then
add_outline(data, 'NO DISK PRESENT: '..disk.longname)
else
add_outline(data, "?SYNTAX ERROR")
end
elseif exec_command == "DIR" then
local searchstring, diskname = simple_vfs.parse_path(input_line:sub(5))
local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
if disk and inserted then
local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
local message = "VIEWING CONTENTS OF "..disk:get_full_name(mtos)
if searchstring and searchstring ~= '' then
message = message .. ' FILTER STRING '..searchstring
end
add_outline(data, message)
add_outline(data, "FORMAT: "..disk:get_format(mtos))
add_outline(data, "")
local file_found
if sysos.booted_from == disk.dev then
for k, v in pairs(laptop.apps) do
if is_executable_app(mtos, v) then
if not searchstring or searchstring == '' or k:upper():match('^'..searchstring:upper():gsub('*','.*')..'$' ) then
add_outline(data, k:upper().."* "..(v.app_info or ""))
file_found = true
end
end
end
end
for k, v in pairs(txtdata) do
if not searchstring or searchstring == '' or k:match('^'..searchstring:gsub('*','.*')..'$' ) then
add_outline(data, k.." "..v.owner.." "..os.date("%I:%M:%S %p, %A %B %d, %Y", v.ctime))
file_found = true
end
end
if not file_found then
add_outline(data, 'NO FILES ON THIS DISK')
end
elseif disk then
add_outline(data, 'NO DISK PRESENT: '..disk.longname)
else
add_outline(data, "?SYNTAX ERROR")
end
elseif exec_command == "TYPE" then
local filename, diskname = simple_vfs.parse_path(input_line:sub(6))
if filename then
local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
if disk and inserted then
local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
if txtdata then
local file = txtdata[filename]
if file and file.content then
for s in file.content:gmatch("[^\n]+") do
add_outline(data, s)
end
else
add_outline(data, 'FILE NOT FOUND: '..filename)
end
end
elseif disk then
add_outline(data, 'NO DISK PRESENT: '..disk.longname)
else
add_outline(data, "?SYNTAX ERROR")
end
else
add_outline(data, '?SYNATX ERROR')
end
elseif exec_command == "CLS" then
data.outlines = {}
elseif exec_command == "TIME" then
add_outline(data, os.date("%I:%M:%S %p"))
elseif exec_command == "DATE" then
add_outline(data, os.date("%A %B %d, %Y"))
elseif exec_command == "TIMEDATE" then
add_outline(data, os.date("%I:%M:%S %p, %A %B %d, %Y"))
elseif exec_command == "VER" then
add_outline(data, 'CARDIFF-SOFT BASIC OPERATING SYSTEM v'..mtos.os_attr.version_string)
elseif exec_command == "MEM" then
local convent = math.random(30,99)
local upper = math.random(10,99)
local xms = math.random(20000,99999)
add_outline(data, 'Memory Type Total = Used + Free')
add_outline(data, '------------------------ ------------- ------------- -------------')
add_outline(data, 'Conventional 640 '..convent..' '..(640-convent))
add_outline(data, 'Upper 123 '..upper..' '..(123-upper))
add_outline(data, 'Reserved 0 0 0')
add_outline(data, 'Extended (XMS)* 130,309 '..numWithCommas(xms)..' '..numWithCommas(130309-xms))
add_outline(data, '------------------------ ------------- ------------- -------------')
add_outline(data, 'Total Memory 131,072 '..numWithCommas(convent+upper+xms)..' '..numWithCommas(131072-(convent+upper+xms)))
elseif exec_command == "TEXTCOLOR" then
local textcolor = exec_all[2]
if textcolor and laptop.supported_textcolors[textcolor:upper()] then
sdata.tty = textcolor:upper()
add_outline(data, 'SET TEXTCOLOR TO: '..sdata.tty)
elseif textcolor then
add_outline(data, '?SYNATX ERROR')
else
add_outline(data, 'TEXTCOLOR: '..data.tty)
end
elseif exec_command == "SCROLLBACK" then
if exec_all[2] then
local newsize = tonumber(exec_all[2])
if newsize then
if newsize >= mtos.os_attr.min_scrollback_size and newsize <= mtos.os_attr.max_scrollback_size then
sdata.scrollback_size = newsize
add_outline(data, 'SET SCROLLBACK TO: '..newsize)
else
add_outline(data, "?OUT OF RANGE")
end
else
add_outline(data, "?SYNTAX ERROR")
end
else
add_outline(data, "SCROLLBACK: "..data.scrollback_size)
add_outline(data, "SUPPORTED: "..mtos.os_attr.min_scrollback_size.."-"..mtos.os_attr.max_scrollback_size)
end
elseif exec_command == "FORMAT" then
local idata = mtos.bdev:get_removable_disk()
if not idata.stack then
add_outline(data, '?DISK NOT FOUND')
else
local fparam
if exec_all[2] then
fparam = exec_all[2]:upper()
end
local ftype, newlabel
if fparam == "/E" then
ftype = ""
newlabel = ""
elseif fparam == "/S" then
ftype = "boot"
newlabel = "CS-BOS Boot Disk"
elseif fparam == "/D" then
ftype = "data"
newlabel = "Data "..idata.def.description
end
if not ftype and fparam then
add_outline(data, "?SYNTAX ERROR")
else
if ftype then
add_outline(data, 'FORMATTING '..idata.def.description)
idata:format_disk(ftype, newlabel)
else
add_outline(data, 'MEDIA INFORMATION: '..idata.def.description)
end
add_outline(data, "FORMAT: "..idata.os_format)
add_outline(data, "LABEL: "..idata.label)
end
end
elseif exec_command == "LABEL" then
local idata = mtos.bdev:get_removable_disk()
if not idata.stack then
add_outline(data, '?DISK NOT FOUND')
else
if exec_all[2] then
idata.label = input_line:sub(6):gsub("^%s*(.-)%s*$", "%1")
end
add_outline(data, "LABEL: "..idata.label)
end
elseif exec_command == "HELP" then
local help_command = exec_all[2]
if not help_command then -- no argument, print all
add_outline(data, 'These shell commands are defined internally.')
add_outline(data, '')
local help_sorted = {}
for k, v in pairs(help_texts) do
if not mtos.os_attr.blacklist_commands[k] then
table.insert(help_sorted, k.." "..v)
end
end
table.sort(help_sorted)
for _, kv in ipairs(help_sorted) do
add_outline(data, kv)
end
else
help_command = help_command:upper()
local help_text
if mtos.os_attr.blacklist_commands[help_command] then
help_text = "?NOT IMPLEMENTED ERROR"
else
help_text = help_texts[help_command] or "? NO HELP IS AVAILABLE FOR THAT TOPIC"
end
add_outline(data, help_command:upper().. " "..help_text)
end
else
add_outline(data, "?SYNTAX ERROR")
end
if data.outlines then
add_outline(data, '')
end
end
end,
appwindow_formspec_func = function(...)
--re-use the default launcher theming
return laptop.apps["launcher"].appwindow_formspec_func(...)
end,
})