cs-bos_app.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. local help_texts = {
  2. CLS = " Clears the screen.",
  3. CD = " Change disk. CD [HDD,FDD]",
  4. DATE = " Displays the current system date.",
  5. DIR = " Display directory of current disk. DIR [filename] brings up info for specified file or files if using wild card *.",
  6. DEL = " Delete a file. DEL [FILENAME]",
  7. HALT = " Shut down CS-BOS.",
  8. HELP = " Displays HELP menu. HELP [command] displays help on that command.",
  9. MEM = " Displays memory usage table.",
  10. EXIT = " Exit CS-BOS shell",
  11. REBOOT = " Perform a soft reboot.",
  12. TEXTCOLOR = " Change terminal text color. TEXTCOLOR [green, amber, or white]",
  13. SCROLLBACK = "Change terminal scrollback size. SCROLLBACK [##]",
  14. TIME = " Displays the current system time.",
  15. TIMEDATE = " Displays the current system time and date.",
  16. VER = " Displays CS-BOS version.",
  17. FORMAT = " View format information or Format Disk. FORMAT [/E] Erase disk, [/S] Create system (boot) disk, [/D] Create data disk",
  18. LABEL = " Show/Set floppy label. LABEL [new_label]",
  19. }
  20. local function get_initial_message(mtos, data)
  21. data.outlines = {
  22. "BASIC OPERATING SYSTEM v"..mtos.os_attr.version_string,
  23. "(C)COPYRIGHT "..mtos.os_attr.releaseyear.." CARDIFF-SOFT",
  24. "128K RAM SYSTEM 77822 BYTES FREE",
  25. }
  26. end
  27. local function add_outline(data, line)
  28. table.insert(data.outlines, line)
  29. if #data.outlines > data.scrollback_size then
  30. for i = data.scrollback_size, #data.outlines do
  31. table.remove(data.outlines,1)
  32. end
  33. end
  34. end
  35. local function is_executable_app(mtos, app)
  36. if not mtos.sysdata then -- cannot executed withoud sysdata
  37. return false
  38. elseif app and not app.view and -- app given
  39. app.name ~= 'cs-bos_launcher' and -- No recursive calls
  40. mtos:is_app_compatible(app.name) then
  41. return true
  42. else
  43. return false
  44. end
  45. end
  46. local function numWithCommas(n)
  47. return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,"):gsub(",(%-?)$","%1"):reverse()
  48. end
  49. --- Simple VFS for BOS Operations
  50. local simple_vfs_map = {}
  51. -- Hard disk
  52. simple_vfs_map.HDD = {
  53. id = 'HDD',
  54. dev = 'hdd',
  55. longname = 'DISK 0:HDD',
  56. check_inserted = function(disk, mtos)
  57. return mtos.bdev:is_hw_capability('hdd')
  58. end,
  59. get_full_name = function(disk, mtos)
  60. return disk.longname
  61. end,
  62. get_format = function(disk, mtos)
  63. return 'BOOT'
  64. end,
  65. }
  66. -- Floppy disk
  67. simple_vfs_map.FDD = {
  68. id = 'FDD',
  69. dev = 'removable',
  70. longname = 'DISK 0:FDD',
  71. check_inserted = function(disk, mtos)
  72. local idata = mtos.bdev:get_removable_disk()
  73. if idata.stack and ( idata.os_format == 'data' or idata.os_format == 'boot') then
  74. return true
  75. end
  76. end,
  77. get_full_name = function(disk, mtos)
  78. local idata = mtos.bdev:get_removable_disk()
  79. return disk.longname..": "..idata.label
  80. end,
  81. get_format = function(disk, mtos)
  82. local idata = mtos.bdev:get_removable_disk()
  83. return idata.os_format
  84. end,
  85. }
  86. simple_vfs_map.REMOVABLE = simple_vfs_map.FDD
  87. local simple_vfs = {}
  88. -- Get the VFS disk object
  89. function simple_vfs.get_disk(mtos, device)
  90. if not device then
  91. return
  92. end
  93. local disk = simple_vfs_map[device:upper()]
  94. local inserted
  95. if disk then
  96. inserted = disk:check_inserted(mtos)
  97. end
  98. return disk, inserted
  99. end
  100. function simple_vfs.parse_path(input_line)
  101. local filename = input_line:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
  102. local diskname
  103. if filename:sub(4,4) == ':' then
  104. diskname = filename:sub(1,3)
  105. filename = filename:sub(5)
  106. end
  107. return filename, diskname
  108. end
  109. --- End for Simple VFS for BOS Operations
  110. local function initialize_data(data, sdata, mtos, sysos)
  111. if mtos.os_attr.tty_monochrome then
  112. data.tty = mtos.os_attr.tty_style
  113. else
  114. data.tty = sdata.tty or data.tty or mtos.os_attr.tty_style
  115. if not laptop.supported_textcolors[data.tty] then --compat hack
  116. data.tty = mtos.os_attr.tty_style
  117. end
  118. end
  119. data.scrollback_size = sdata.scrollback_size or data.scrollback_size or mtos.os_attr.min_scrollback_size
  120. -- Set initial message on new session
  121. if not data.outlines then
  122. get_initial_message(mtos, data)
  123. end
  124. if not data.current_disk then
  125. if sysos.booted_from == 'removable' then
  126. data.current_disk = 'FDD'
  127. else
  128. data.current_disk = 'HDD'
  129. end
  130. end
  131. data.inputfield = data.inputfield or ""
  132. end
  133. laptop.register_app("cs-bos_launcher", {
  134. app_name = "CS-BOS Prompt",
  135. app_info = "Command Line Interface",
  136. fullscreen = true,
  137. app_icon = "laptop_cs_bos.png",
  138. formspec_func = function(cs_bos, mtos)
  139. local data = mtos.bdev:get_app_storage('ram', 'cs_bos')
  140. local sysos = mtos.bdev:get_app_storage('ram', 'os')
  141. local sdata = mtos.bdev:get_app_storage('system', 'cs_bos') or {} -- handle temporary if no sysdata given
  142. -- no system found. In case of booted from removable, continue in live mode
  143. if not mtos.sysdata and sysos.booted_from ~= "removable" then
  144. local formspec = "size[10,7]background[10,7;0,0;laptop_launcher_insert_floppy.png;true]"..
  145. "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"..
  146. "list[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main;2.5,3;1,1;]" ..
  147. "list[current_player;main;0,6.5;8,1;]" ..
  148. "listring[nodemeta:"..mtos.pos.x..','..mtos.pos.y..','..mtos.pos.z..";main]" ..
  149. "listring[current_player;main]"
  150. local idata = mtos.bdev:get_removable_disk()
  151. if idata.stack then
  152. if idata.os_format ~= "boot" then
  153. formspec = formspec .. "label[0,1.7;Disk found but not formatted to boot]"
  154. end
  155. end
  156. return formspec
  157. end
  158. initialize_data(data, sdata, mtos, sysos)
  159. local tty = laptop.supported_textcolors[data.tty]
  160. local formspec =
  161. "size[15,10]background[15,10;0,0;laptop_theme_desktop_icon_label_button_black.png;true]"..
  162. "label[-0.15,9.9;"..minetest.colorize(tty,data.current_disk..">").."]"..
  163. "field[1.020,9.93;15.6,1;inputfield;;"..minetest.formspec_escape(data.inputfield).."]"..
  164. "tablecolumns[text]tableoptions[background=#000000;border=false;highlight=#000000;"..
  165. "color="..tty..";highlight_text="..tty.."]"..
  166. "table[-0.35,-0.35;15.57, 10.12;outlines;"
  167. for idx,line in ipairs(data.outlines) do
  168. if idx > 1 then
  169. formspec = formspec..','
  170. end
  171. formspec = formspec..minetest.formspec_escape(line)
  172. end
  173. formspec = formspec..";"..#data.outlines.."]".."field_close_on_enter[inputfield;false]"
  174. return formspec
  175. end,
  176. receive_fields_func = function(cs_bos, mtos, sender, fields)
  177. local data = mtos.bdev:get_app_storage('ram', 'cs_bos')
  178. local sysos = mtos.bdev:get_app_storage('ram', 'os')
  179. local sdata = mtos.bdev:get_app_storage('system', 'cs_bos') or {} -- handle temporary if no sysdata given
  180. initialize_data(data, sdata, mtos, sysos)
  181. if fields.inputfield then -- move received data to the formspec input field
  182. data.inputfield = fields.inputfield
  183. end
  184. if fields.key_enter then
  185. -- run the command
  186. local exec_all = data.inputfield:split(" ")
  187. local input_line = data.inputfield
  188. local exec_command = exec_all[1] --further parameters are 2++
  189. add_outline(data, "> "..data.inputfield)
  190. data.inputfield = ""
  191. if exec_command then
  192. exec_command = exec_command:upper()
  193. end
  194. if exec_command == nil then --empty line
  195. elseif mtos.os_attr.blacklist_commands[exec_command] then
  196. add_outline(data, '?ERROR NOT IMPLEMENTED')
  197. elseif exec_command == "HALT" then
  198. -- same code as in node_fw on punch to disable the OS
  199. if mtos.hwdef.next_node then
  200. local hwdef_next = laptop.node_config[mtos.hwdef.next_node]
  201. if hwdef_next.hw_state then
  202. mtos[hwdef_next.hw_state](mtos, mtos.hwdef.next_node)
  203. else
  204. mtos:swap_node(hwdef.next_node)
  205. mtos:save()
  206. end
  207. end
  208. elseif exec_command == "DEL" then
  209. local filename, diskname = simple_vfs.parse_path(input_line:sub(5))
  210. if filename then
  211. local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
  212. if disk and inserted then
  213. local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
  214. if txtdata and txtdata[filename] then
  215. txtdata[filename] = nil
  216. add_outline(data, filename:upper()..' DELETED SUCCESSFULY')
  217. else
  218. add_outline(data, 'FILE NOT FOUND: '..filename)
  219. end
  220. end
  221. end
  222. elseif exec_command == "EXIT" then
  223. data.outlines = nil -- reset screen
  224. mtos:set_app() -- quit app (if in app mode)
  225. elseif exec_command == "REBOOT" then
  226. mtos:power_on() -- reboots computer
  227. elseif exec_command == "EJECT" then
  228. local idata = mtos.bdev:get_removable_disk()
  229. local success = idata:eject()
  230. if success then
  231. add_outline(data, 'DISK EJECTED')
  232. else
  233. add_outline(data, 'NO DISK FOUND')
  234. end
  235. elseif is_executable_app(mtos, laptop.apps[exec_command:lower()]) then
  236. add_outline(data, 'LAUNCHED '..exec_command)
  237. mtos:set_app(exec_command:lower())
  238. elseif exec_command == "CD" then
  239. local disk, inserted = simple_vfs.get_disk(mtos, exec_all[2])
  240. if disk and inserted then
  241. data.current_disk = disk.id
  242. add_outline(data, "CURRENT DISK = "..disk:get_full_name(mtos))
  243. elseif disk then
  244. add_outline(data, 'NO DISK PRESENT: '..disk.longname)
  245. else
  246. add_outline(data, "?SYNTAX ERROR")
  247. end
  248. elseif exec_command == "DIR" then
  249. local searchstring, diskname = simple_vfs.parse_path(input_line:sub(5))
  250. local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
  251. if disk and inserted then
  252. local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
  253. local message = "VIEWING CONTENTS OF "..disk:get_full_name(mtos)
  254. if searchstring and searchstring ~= '' then
  255. message = message .. ' FILTER STRING '..searchstring
  256. end
  257. add_outline(data, message)
  258. add_outline(data, "FORMAT: "..disk:get_format(mtos))
  259. add_outline(data, "")
  260. local file_found
  261. if sysos.booted_from == disk.dev then
  262. for k, v in pairs(laptop.apps) do
  263. if is_executable_app(mtos, v) then
  264. if not searchstring or searchstring == '' or k:upper():match('^'..searchstring:upper():gsub('*','.*')..'$' ) then
  265. add_outline(data, k:upper().."* "..(v.app_info or ""))
  266. file_found = true
  267. end
  268. end
  269. end
  270. end
  271. for k, v in pairs(txtdata) do
  272. if not searchstring or searchstring == '' or k:match('^'..searchstring:gsub('*','.*')..'$' ) then
  273. add_outline(data, k.." "..v.owner.." "..os.date("%I:%M:%S %p, %A %B %d, %Y", v.ctime))
  274. file_found = true
  275. end
  276. end
  277. if not file_found then
  278. add_outline(data, 'NO FILES ON THIS DISK')
  279. end
  280. elseif disk then
  281. add_outline(data, 'NO DISK PRESENT: '..disk.longname)
  282. else
  283. add_outline(data, "?SYNTAX ERROR")
  284. end
  285. elseif exec_command == "TYPE" then
  286. local filename, diskname = simple_vfs.parse_path(input_line:sub(6))
  287. if filename then
  288. local disk, inserted = simple_vfs.get_disk(mtos, diskname or data.current_disk)
  289. if disk and inserted then
  290. local txtdata = mtos.bdev:get_app_storage(disk.dev, 'stickynote:files')
  291. if txtdata then
  292. local file = txtdata[filename]
  293. if file and file.content then
  294. for s in file.content:gmatch("[^\n]+") do
  295. add_outline(data, s)
  296. end
  297. else
  298. add_outline(data, 'FILE NOT FOUND: '..filename)
  299. end
  300. end
  301. elseif disk then
  302. add_outline(data, 'NO DISK PRESENT: '..disk.longname)
  303. else
  304. add_outline(data, "?SYNTAX ERROR")
  305. end
  306. else
  307. add_outline(data, '?SYNATX ERROR')
  308. end
  309. elseif exec_command == "CLS" then
  310. data.outlines = {}
  311. elseif exec_command == "TIME" then
  312. add_outline(data, os.date("%I:%M:%S %p"))
  313. elseif exec_command == "DATE" then
  314. add_outline(data, os.date("%A %B %d, %Y"))
  315. elseif exec_command == "TIMEDATE" then
  316. add_outline(data, os.date("%I:%M:%S %p, %A %B %d, %Y"))
  317. elseif exec_command == "VER" then
  318. add_outline(data, 'CARDIFF-SOFT BASIC OPERATING SYSTEM v'..mtos.os_attr.version_string)
  319. elseif exec_command == "MEM" then
  320. local convent = math.random(30,99)
  321. local upper = math.random(10,99)
  322. local xms = math.random(20000,99999)
  323. add_outline(data, 'Memory Type Total = Used + Free')
  324. add_outline(data, '------------------------ ------------- ------------- -------------')
  325. add_outline(data, 'Conventional 640 '..convent..' '..(640-convent))
  326. add_outline(data, 'Upper 123 '..upper..' '..(123-upper))
  327. add_outline(data, 'Reserved 0 0 0')
  328. add_outline(data, 'Extended (XMS)* 130,309 '..numWithCommas(xms)..' '..numWithCommas(130309-xms))
  329. add_outline(data, '------------------------ ------------- ------------- -------------')
  330. add_outline(data, 'Total Memory 131,072 '..numWithCommas(convent+upper+xms)..' '..numWithCommas(131072-(convent+upper+xms)))
  331. elseif exec_command == "TEXTCOLOR" then
  332. local textcolor = exec_all[2]
  333. if textcolor and laptop.supported_textcolors[textcolor:upper()] then
  334. sdata.tty = textcolor:upper()
  335. add_outline(data, 'SET TEXTCOLOR TO: '..sdata.tty)
  336. elseif textcolor then
  337. add_outline(data, '?SYNATX ERROR')
  338. else
  339. add_outline(data, 'TEXTCOLOR: '..data.tty)
  340. end
  341. elseif exec_command == "SCROLLBACK" then
  342. if exec_all[2] then
  343. local newsize = tonumber(exec_all[2])
  344. if newsize then
  345. if newsize >= mtos.os_attr.min_scrollback_size and newsize <= mtos.os_attr.max_scrollback_size then
  346. sdata.scrollback_size = newsize
  347. add_outline(data, 'SET SCROLLBACK TO: '..newsize)
  348. else
  349. add_outline(data, "?OUT OF RANGE")
  350. end
  351. else
  352. add_outline(data, "?SYNTAX ERROR")
  353. end
  354. else
  355. add_outline(data, "SCROLLBACK: "..data.scrollback_size)
  356. add_outline(data, "SUPPORTED: "..mtos.os_attr.min_scrollback_size.."-"..mtos.os_attr.max_scrollback_size)
  357. end
  358. elseif exec_command == "FORMAT" then
  359. local idata = mtos.bdev:get_removable_disk()
  360. if not idata.stack then
  361. add_outline(data, '?DISK NOT FOUND')
  362. else
  363. local fparam
  364. if exec_all[2] then
  365. fparam = exec_all[2]:upper()
  366. end
  367. local ftype, newlabel
  368. if fparam == "/E" then
  369. ftype = ""
  370. newlabel = ""
  371. elseif fparam == "/S" then
  372. ftype = "boot"
  373. newlabel = "CS-BOS Boot Disk"
  374. elseif fparam == "/D" then
  375. ftype = "data"
  376. newlabel = "Data "..idata.def.description
  377. end
  378. if not ftype and fparam then
  379. add_outline(data, "?SYNTAX ERROR")
  380. else
  381. if ftype then
  382. add_outline(data, 'FORMATTING '..idata.def.description)
  383. idata:format_disk(ftype, newlabel)
  384. else
  385. add_outline(data, 'MEDIA INFORMATION: '..idata.def.description)
  386. end
  387. add_outline(data, "FORMAT: "..idata.os_format)
  388. add_outline(data, "LABEL: "..idata.label)
  389. end
  390. end
  391. elseif exec_command == "LABEL" then
  392. local idata = mtos.bdev:get_removable_disk()
  393. if not idata.stack then
  394. add_outline(data, '?DISK NOT FOUND')
  395. else
  396. if exec_all[2] then
  397. idata.label = input_line:sub(6):gsub("^%s*(.-)%s*$", "%1")
  398. end
  399. add_outline(data, "LABEL: "..idata.label)
  400. end
  401. elseif exec_command == "HELP" then
  402. local help_command = exec_all[2]
  403. if not help_command then -- no argument, print all
  404. add_outline(data, 'These shell commands are defined internally.')
  405. add_outline(data, '')
  406. local help_sorted = {}
  407. for k, v in pairs(help_texts) do
  408. if not mtos.os_attr.blacklist_commands[k] then
  409. table.insert(help_sorted, k.." "..v)
  410. end
  411. end
  412. table.sort(help_sorted)
  413. for _, kv in ipairs(help_sorted) do
  414. add_outline(data, kv)
  415. end
  416. else
  417. help_command = help_command:upper()
  418. local help_text
  419. if mtos.os_attr.blacklist_commands[help_command] then
  420. help_text = "?NOT IMPLEMENTED ERROR"
  421. else
  422. help_text = help_texts[help_command] or "? NO HELP IS AVAILABLE FOR THAT TOPIC"
  423. end
  424. add_outline(data, help_command:upper().. " "..help_text)
  425. end
  426. else
  427. add_outline(data, "?SYNTAX ERROR")
  428. end
  429. if data.outlines then
  430. add_outline(data, '')
  431. end
  432. end
  433. end,
  434. appwindow_formspec_func = function(...)
  435. --re-use the default launcher theming
  436. return laptop.apps["launcher"].appwindow_formspec_func(...)
  437. end,
  438. })