This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
KnightMiner's profile picture

Extensions: a simple program that adds support for file extensions

Started by KnightMiner, 28 August 2015 - 07:06 PM
KnightMiner #1
Posted 28 August 2015 - 09:06 PM
So, if you are like me, you don't like the fact that running a paint program or a non-lua text file (such as for printing) causes a script error. You would rather be redirected to the program that can properly read the file.
Well, your struggles are over. Just use "extensions" once upon startup of your computer, and you can tell a program to run based on its extension!

Usage

To use, simply run the program. It will replace the shell.run function with the new extension supporting program, while preserving the old function under the name of shell.runRaw.
The first time you run the program, it will additionally prompt you to create a file call extensions.cfg, which is a table of all available extensions, and the program which should run the file. Any number of custom extensions may be added, but note that files with custom extensions may behave oddly if you attempt to open them outside of ComputerCraft. Each entry in the table is simply a string value, or be the first key of a table value. If using a table value, you can also set the key noExt to true to trim the extension from the file name before passing it onto the program.
Additionally, the program will support two parameters to skip prompts (in case you are running it inside another program).
  • The first one can be set to "create" to force creation of the extensions.cfg file and open the editing screen, "create-default" to create the default file without loading the editor, or "skip" to cancel if the file does not exist.
  • Either of the two parameters can also be set to "load" to cancel running if the program has already run, or "reload" to rerun the program anyways (such as if you changed the extensions list and wish to reload it.)
After running, any files with valid extensions that you run will boot with the specified program. Additionally, the file will pass on any parameters, which will be added to the parameters for the program the filename. The program will also add an API called extensions containing two items:
  • extensions.list - a table of all extensions, cached to the last time the extensions were loaded (meaning it will not reflect edits to extensions.cfg until reload, keeping it consistent with shell.run)
  • extensions.program( string program ) - returns prog, file, noExt
    • prog is the program used to run the program name given, or nil if no program is set for that extension. Useful to check if a program is actually a file, or to know how to read a file within another program.
    • file is the name of the file, removing any args after the extension
    • noExt is the input parameter without the extension on the file name, used internally by shell.run for the sake of certain programs which always add an extension (and expect none on the input args). Will be nil if the program does not set noExt to true
Download

To install or update Extensions v2.1, simply use the following command to run the installer. It will automatically download the program and add it to your startup routine.
pastebin run QsNh3x2S

If you would download Extensions v2.1 manually (say you have a complicated startup routine, or a custom OS), simply use the following command to download just the program.
pastebin get 7Nq6R70n extensions
Edited on 12 December 2015 - 12:52 AM
cyanisaac #2
Posted 28 August 2015 - 09:18 PM
I must try that, it's an insanely good concept :D/>
KnightMiner #3
Posted 20 September 2015 - 12:22 AM
The program is now version 1.1, with two changes:
  • shell.run now properly returns its success
  • the global table extensions was added, containing a couple of functions to get extension information in other programs
FUNCTION MAN! #4
Posted 20 September 2015 - 12:55 AM
This is a nice program, but I must rant.

Determining file type based on extension is bad. Files should have a header, a footer, or some other easily identifiable criteria.

ELF files on Linux/*BSD or Mach-O files on OS X, heck, even a.out files on research UNIX do not need an extension. Sure, it's easier for an user to identify a file based on extension, but for computers, it's way easier for files to have a tag of sorts on them. Java can open JAR files without an extension, tar(1) can unpack files without an extension, and most important, UNIX-like (that is to say, non-shitty) kernels can open files without any extension at all. This is because of the so-called magic numbers (they should be called magic strings) that files have.

Ever saw a python script with #!/usr/bin/env python on top of it? Or maybe, a shell script with #!/bin/sh on top? This inscructs the executable loader to pipe the contents of the file into the path specified after #!.

We don't need file extension support in CC. We need formats with identifier sequences on them.

TL;DR: 5/10, extensions are bad.

EDIT: I read your code, and do you really load your config file with dofile? Do you know how dangerous that is?
For example, a config file might be a while loop, and the system will hang. Dofile loads the file as a lua script, and since CC doesn't have permissions, you could wipe the FS from that config file.
Edited on 19 September 2015 - 11:31 PM
KnightMiner #5
Posted 21 September 2015 - 04:06 AM
This is a nice program, but I must rant.

Determining file type based on extension is bad. Files should have a header, a footer, or some other easily identifiable criteria.

ELF files on Linux/*BSD or Mach-O files on OS X, heck, even a.out files on research UNIX do not need an extension. Sure, it's easier for an user to identify a file based on extension, but for computers, it's way easier for files to have a tag of sorts on them. Java can open JAR files without an extension, tar(1) can unpack files without an extension, and most important, UNIX-like (that is to say, non-shitty) kernels can open files without any extension at all. This is because of the so-called magic numbers (they should be called magic strings) that files have.

Ever saw a python script with #!/usr/bin/env python on top of it? Or maybe, a shell script with #!/bin/sh on top? This inscructs the executable loader to pipe the contents of the file into the path specified after #!.

We don't need file extension support in CC. We need formats with identifier sequences on them.

TL;DR: 5/10, extensions are bad.
Maybe in real life computers that would be more relevant, but in ComputerCraft we only ever have one type of script, and the rest of the file types are convenient data storage (where the author really shouldn't need to make it fully function as a lua script when it is designed to be read by the program). Two good examples are paint files and text files
  • Paint files are read by the paint program by simply reading the characters, and thus there is no way to add information to the file about how to run it without changing that core program, which while I though about doing, it overall made more sense to just teach the computer how to read the file.
  • A text file is for printing. Adding any additional text will cause it to improperly print when using the edit program, which leads to the requirement of making a whole new program just to print a simple text file, and in the end you have made something that is already done.
In the end, it is a lot easier to tag the file someplace other than where it stores data, so naturally the title makes sense, leading to file extensions. It also makes it easier to change what program opens the file, such as if someone makes a better paint program or a dedicated text editor (for the sake of additional features that is, rather than re-implementing existing behavior)

Also, there is no removal of functionality with such tags. Trying to open a file with the wrong program just pukes as you would expect on any computer, just like if you tell the computer that .txt should be opened in an image editor.

So overall, rather than re-implement current functionality for the sake of ideals, I would rather work with what already exists (files containing just data), which is a much simpler task and does not require the user changing their methods. This program is meant as a convenience for people like me who work with already existing file types. I would say feel free to write a program like that to handle files, but I find this system to work well enough myself (Said program would either require storing all files in lua format, or making a new program to read all programs before loading them to check what program it specified, including basic lua files.)

EDIT: I read your code, and do you really load your config file with dofile? Do you know how dangerous that is?
For example, a config file might be a while loop, and the system will hang. Dofile loads the file as a lua script, and since CC doesn't have permissions, you could wipe the FS from that config file.

Assuming the user is using it on a private computer or a server among trusted people: not at all. The file should only contain said table, and it would only be different if the owner edits it to include such malicious stuff. Assuming they are using it on a public server with possibly untrustworthy people: no more dangerous than a startup file normally is, as adding a virus in the config file would be no different that adding a virus in the extensions program file or startup file, they all would get run at startup. The only exception is if you implement some form of protection for startup programs, but want to leave the config file publicly editable, in which case I agree it is less secure.

Do you have a suggestion for a better way to load configuration files that does not require the user installing additional apis? Or maybe an easy/fast way to validate the file before loading it?
Edited on 21 September 2015 - 02:11 AM
negamartin #6
Posted 21 September 2015 - 11:59 AM
I totally agree on you about extensions. Why overcomplicate stuff? This should exist in "vanilla" computercraft.
And I think you can do textutils.unserialize(handle.readAll())?
I havent actually tested or read your code, as I am on my phone, so that might just run the file :P/>
KnightMiner #7
Posted 21 September 2015 - 05:20 PM
I totally agree on you about extensions. Why overcomplicate stuff? This should exist in "vanilla" computercraft. And I think you can do textutils.unserialize(handle.readAll())? I havent actually tested or read your code, as I am on my phone, so that might just run the file :P/>/>
That actually works quite well. It requires the data to be something you can assign to a variable (which means it is not run upon loading) and the program will break if a value is set to a function rather than running it.

I just updated the program to version 2, containing that and actually loading the extensions stuff as an API rather than a global variable. If you have downloaded the program before, run the installer again and it will automatically fix the configuration file (assuming you had a valid one before).
KnightMiner #8
Posted 12 December 2015 - 12:54 AM
Extensions is now in version 2.1, with the following changes:
  • The program now supports spaces in file names (like when you normally surround a program's name with quotation marks, not that it's advised)
  • It will now pass on parameters from the file to the program opening the file (useful in cases like my other program Stratego to set a host name when booting the game from a save game file).
  • Entries now will use the first key of a table if the value from the list is a table
  • Programs support having their extension trimmed, by defining the key "noExt" in a table entry.
  • extensions.program() now has three returns instead of just one.
  • Errors are now added using the printError() function, and some typos have been fixed
Edited on 12 December 2015 - 12:55 AM
Piorjade #9
Posted 16 December 2015 - 08:09 PM
My question is: If I want to add an extension (let's say .app) and i wrote my own program, which can execute that extension..

What do I have to write In the .cfg? I tried : app = "/nameofthatprogram" ; but that didn't work.
Do I really need to move the program into /rom/programs?
KnightMiner #10
Posted 17 December 2015 - 02:35 AM
My question is: If I want to add an extension (let's say .app) and i wrote my own program, which can execute that extension..

What do I have to write In the .cfg? I tried : app = "/nameofthatprogram" ; but that didn't work.
Do I really need to move the program into /rom/programs?
Simply the path to the program, as if you were to try running the program directly from the command line. I assume the issue was the /, so try app = "nameofthatprogram"

As for the program path, it currently has to either be in the current directory or in any available path, though I have plans on making it properly support an absolute path (starting from the root directory that is).
Piorjade #11
Posted 17 December 2015 - 12:06 PM
Oh that worked, thanks.
I tried to move the program to another folder (e.g. /this/is/the/program)
and wrote into the .cfg :

app = "this/is/the/program"

And it worked too. This tool is really useful :)/>