mirror of
https://codeberg.org/TicklishHoneyBee/CLIte.git
synced 2026-03-11 09:04:37 +00:00
update documents and bump version
This commit is contained in:
parent
1f2c8d85f3
commit
dc048f20cc
6 changed files with 558 additions and 444 deletions
|
|
@ -1,6 +1,6 @@
|
|||
var clite = {
|
||||
state:{
|
||||
version:'0.2-2',
|
||||
version:'0.2-3',
|
||||
isinit:false
|
||||
},
|
||||
core:{
|
||||
|
|
@ -1318,6 +1318,7 @@ clite.vfs = {
|
|||
vfsdata.api.mkDir('/usr/clite/web');
|
||||
vfsdata.api.mkDir('/usr/home');
|
||||
vfsdata.api.mkDir('/usr/share');
|
||||
vfsdata.api.mkDir('/usr/share/docs');
|
||||
vfsdata.api.mkDir('/usr/share/site');
|
||||
vfsdata.api.mkDir('/usr/src');
|
||||
vfsdata.api.mkDir('/usr/src/libs');
|
||||
|
|
|
|||
|
|
@ -14,4 +14,7 @@ clite/core.css:/usr/clite/web/core.css:0:0:-rw-r-----
|
|||
data/intro.txt:/usr/share/introduction:0:0:-rw-rw-r--
|
||||
data/about.txt:/usr/share/site/about:0:0:-rw-rw-r--
|
||||
data/lipsum.txt:/usr/share/site/lipsum:0:0:-rw-rw-r--
|
||||
readme.txt:/usr/clite/readme.txt:0:0:-rw-r--r--
|
||||
readme.txt:/usr/share/docs/readme.txt:0:0:-rw-r--r--
|
||||
readme-libs.txt:/usr/share/docs/readme-libs.txt:0:0:-rw-r--r--
|
||||
readme-programs.txt:/usr/share/docs/readme-programs.txt:0:0:-rw-r--r--
|
||||
readme-internals.txt:/usr/share/docs/readme-internals.txt:0:0:-rw-r--r--
|
||||
|
|
|
|||
103
readme-internals.txt
Normal file
103
readme-internals.txt
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
CLIte Internals:
|
||||
|
||||
CLite's aim is not just to create a functional unix-like terminal in a
|
||||
web page, but also to have that built on top of a unix-like operating
|
||||
system written in javascript and which runs in a web page.
|
||||
|
||||
CLIte follows the common programming methodology of creating in three
|
||||
steps:
|
||||
|
||||
First, make it work.
|
||||
Second, make it work right.
|
||||
Third, make it work well.
|
||||
|
||||
This means that some areas are still very much a work in progress, but
|
||||
are gradually being improved.
|
||||
|
||||
At its core, CLIte is made up of the follow parts:
|
||||
|
||||
The Core:
|
||||
Effectively CLIte's 'kernel', this consists of functions needed to do
|
||||
basic tasks, such as loading files, loading scripts, safely running
|
||||
code, downloading files, rebooting the system, and system initialisation.
|
||||
Most of this is either abstracted away to higher level functions, or
|
||||
otherwise need never be used by user-level programs.
|
||||
|
||||
The Terminal:
|
||||
The terminal handles user input, and displays program output. Most of
|
||||
which is abstracted away to standard io calls on /dev/tty, and even
|
||||
further abstracted to standard io calls on the standard input, output,
|
||||
and error filedescriptors that every program has. Additionally the
|
||||
term library offers some advanced functionality which is subject to
|
||||
change.
|
||||
|
||||
The VFS: (Virtual File Sytem)
|
||||
CLIte's virtual file system bares no relation to the file system of the
|
||||
server it is run on (thus /etc/passwd is not the server's /etc/passwd
|
||||
file!).
|
||||
During system initialisation, the root filesystem is mounted by creating
|
||||
the VFS, with physical server-side files then mapped into the VFS using
|
||||
a plain-text config file which is stored in /dev/wfs (web file system,
|
||||
for lack of a better name). The content of files are then loaded in as
|
||||
needed when the VFS file is accessed.
|
||||
However other files in the VFS are created dynamically as needed during
|
||||
system initialisation. For instance, commands are loaded in directly
|
||||
from javascript functions, which creates both the executable file in
|
||||
/bin/<name> as well as the source file in /usr/src/<name>.js. Thus two
|
||||
VFS files are created from each command, with many commands being held
|
||||
in a single server-side file. Libraries are loaded in similarly, to
|
||||
both /lib/<name>.so and /usr/src/libs/<name>.js
|
||||
Additionally, configuration files in /etc, and various default devices
|
||||
in /dev are also created programatically. As is the system log file
|
||||
in /var/logs.
|
||||
Most VFS functions are abstracted away to stdio functions.
|
||||
|
||||
The Process Manager:
|
||||
CLIte's process manager keeps track of running programs as processes and
|
||||
process groups, in a typical unix-like manner. It also wraps each
|
||||
process in its own try/catch block to ensure errors are handled
|
||||
correctly, and that failed processes aren't left 'hanging'.
|
||||
It also manages callbacks for functions such as wait() so that processes
|
||||
can monitor and act upon each other as needed.
|
||||
|
||||
The User Manager:
|
||||
The user manager controls the user logins, and dynamically generates a
|
||||
guest session as needed.
|
||||
|
||||
The Logger:
|
||||
The Logger manages the system logs, printing them to the terminal during
|
||||
system initialisation and shutdown, as well as writing them to the
|
||||
system log at /var/logs
|
||||
|
||||
The Lifecycle of a Process:
|
||||
|
||||
1. fork() is called with the environment and io data passed to it.
|
||||
This adds a new process to the process manager, which assigns it
|
||||
a process id (pid) and also creates a file in /proc/<pid> for
|
||||
storing data about the process.
|
||||
Both the environment and io data are then cloned, and the new
|
||||
process is called asynchronously, forking it from the current
|
||||
process.
|
||||
The process id of the new process is returned to the parent.
|
||||
2. exec() is called, again the environment and io data is passed to it,
|
||||
along with the file path and arguments for a new program.
|
||||
This checks the file both exists and is executable by the current
|
||||
user.
|
||||
Then updated details of the program are sent to the process manager.
|
||||
The current program is then overwritten with a call to the new
|
||||
program.
|
||||
3. The program then runs as intended, and exits normally, or fails and
|
||||
is caught by a try/catch which exits the program.
|
||||
4. exit() is called with an integer 'exit state':
|
||||
zero for no error.
|
||||
less than zero for internal error
|
||||
greater than zero for the program's own use
|
||||
This ends the program, and notifies the process manager that the
|
||||
process has exit.
|
||||
The process manager will then remove the process from the process
|
||||
list, delete the process' data file in /proc/<pid>, then handle
|
||||
any wait() calls that have been queued for the process exit.
|
||||
|
||||
Typically, this is when the shell's waitpid() on the process causes the
|
||||
shell to once again show a prompt, awaiting the user's next command
|
||||
input.
|
||||
323
readme-libs.txt
Normal file
323
readme-libs.txt
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
CLIte libraries:
|
||||
|
||||
System libraries may be loaded into a program for use of their API using the
|
||||
io.include() function:
|
||||
|
||||
var stdio = io.include('stdio');
|
||||
|
||||
This returns a reference to the library which can be stored in a variable as
|
||||
seen above. Calls to library functions can then be made using that reference:
|
||||
|
||||
stdio.open('/path/to/file');
|
||||
|
||||
There is no need to name the variable the same as the library name, however
|
||||
this is considered good practice.
|
||||
A library's 'header' name, as used in include() is not the same as its
|
||||
file name /lib/lib*.so. For instance for the standard io library, you
|
||||
would include 'stdio' but the filename is libio.so
|
||||
|
||||
The libraries, and their API functions are listed below:
|
||||
|
||||
stdlib (libstd.so): io.include('stdlib')
|
||||
Provides a growing standard unix-like library.
|
||||
|
||||
basename('path')
|
||||
returns the base name of a file path:
|
||||
'/usr/home/guest/file.txt' -> 'file.txt'
|
||||
|
||||
dirname('path')
|
||||
returns the directory name of a file path:
|
||||
'/usr/home/guest/file.txt' -> '/usr/home/guest'
|
||||
|
||||
uname()
|
||||
returns an object containing system information:
|
||||
{
|
||||
sysname:'CLIte', // system name, always 'CLIte'
|
||||
nodename:'localhost', // network hostname
|
||||
release:'0.1...', // contains the current CLIte version as stored in clite.state.version
|
||||
version:'0.1...', // same as release
|
||||
machine:navigator.userAgent // contains the browser user agent string
|
||||
}
|
||||
|
||||
nodename is either the website domain, or 'localhost' if loaded
|
||||
without a webserver. This allows programs to test if the system
|
||||
is running locally or not (example is `cat -l' which does not
|
||||
print unloaded files if running without a webserver).
|
||||
|
||||
fork(env,io,call)
|
||||
Creates a new process, with environment and io data passed to it.
|
||||
Returns the pid of the new process, or 0 on failure.
|
||||
call should be a function that accepts the env and io as
|
||||
arguments, this is where the new process begins.
|
||||
|
||||
function newProc(env,io) {
|
||||
io.write('this is a new process!');
|
||||
io.exit(0);
|
||||
}
|
||||
var pid = fork(env,io,newProc);
|
||||
|
||||
exec(path,args,env,io)
|
||||
Executes a new program, replacing the current one.
|
||||
Returns 0 on success, non-zero on failure.
|
||||
Unlike typical unix exec(), this always returns. On success the
|
||||
original program should do nothing more, including not exiting.
|
||||
|
||||
path is the fully resolved file path of the program to be
|
||||
executed, such as '/bin/ls'.
|
||||
args is the argument array created by passing a command line to
|
||||
strToArgs, see above.
|
||||
env and io, are the current environment and io data.
|
||||
|
||||
var command = "ls -l";
|
||||
var args = stdlib.strToArgs(command);
|
||||
var path = stdlib.resolvePath(args[0],'/bin');
|
||||
var r = stdlib.exec(path,args,env,io);
|
||||
if (r == 0)
|
||||
return;
|
||||
|
||||
wait(cb)
|
||||
Calls cb(pid) once any child of the current process has exited.
|
||||
Calls immediately if the are no child processes.
|
||||
Returns false on error.
|
||||
|
||||
waitpid(pid,cb)
|
||||
Calls cb(pid) when the process with id pid has exited. Calls
|
||||
immediately if the process does not exist.
|
||||
If pid is less than 0, functions like wait(cb)
|
||||
Returns false on error.
|
||||
|
||||
waitall(cb)
|
||||
Calls cb(pid) once all child processes of the current process
|
||||
group have exited. Calls immediately if the are no child processes.
|
||||
Returns false on error.
|
||||
|
||||
getuid()
|
||||
Returns the numeric user id of the current user.
|
||||
|
||||
getgid()
|
||||
Returns teh numeric group id of the current user.
|
||||
|
||||
clite (libclite.so): io.include('clite')
|
||||
Provides provides special functions used in CLIte.
|
||||
|
||||
resolvePath('path','base')
|
||||
Resolves a relative path to a full path, using the present
|
||||
working directory or 'base':
|
||||
|
||||
clite.resolvePath('file.txt') -> '/usr/home/guest/file.txt'
|
||||
clite.resolvePath('file.txt','/etc') -> '/etc/file.txt'
|
||||
clite.resolvePath('~/../file.txt') -> '/usr/home/file.txt'
|
||||
|
||||
strToArgs('string')
|
||||
Splits a string into an array of arguments for passing to
|
||||
exec(), supports quotes and so on:
|
||||
|
||||
clite.strToArgs('ls -l /var') -> ['ls','-l','var']
|
||||
|
||||
|
||||
stdio (libio.so): io.include('stdio')
|
||||
Provides access to io functions and types for file access
|
||||
|
||||
stdio.types:
|
||||
object for mapping values of stat.type:
|
||||
FT_UNKOWN: 0 Unknown file type
|
||||
FT_TEXT: 1 Plain text file
|
||||
FT_BINARY: 2 Binary file, likely a javascript function
|
||||
FT_DIR: 3 Directory
|
||||
FT_LINK: 4 Symbolic link
|
||||
FT_DEV: 5 Device
|
||||
FT_REMOTE: 6 Unloaded remote data (will change after loading)
|
||||
FT_SCRIPT: 7 Plain text file beginning with #!
|
||||
FT_IMAGE: 8 Image file, specifically a javascript Image object
|
||||
|
||||
creat('path','-')
|
||||
creates a new file at path
|
||||
returns true on success
|
||||
|
||||
open('path',callback,open_link)
|
||||
Open the file at path, returns a file descriptor.
|
||||
On error returns null, and calls callback(null) if set.
|
||||
If callback is set, will call the function at callback with the
|
||||
file descriptor, this allows remote data to be loaded for the
|
||||
file before beginning read or write operations.
|
||||
If callback is false, open will return directly, without loading
|
||||
remote data.
|
||||
If open_link is set and true, and 'path' is a symbolic link, the
|
||||
returned file descriptor is for the link, not the file pointed to.
|
||||
|
||||
var fd = stdio.open('path',false); // opens the file without loading data
|
||||
var fd = stdio.open('path',callback); // calls callback(fd) when data is loaded
|
||||
var fd = stdio.open('path',callback,true); // as above, but will not follow a link
|
||||
var fd = stdio.open('path'); // as a general rule, don't do this
|
||||
|
||||
close(fd)
|
||||
Closes a file opened with open()
|
||||
|
||||
stdio.close(fd);
|
||||
|
||||
read(fd,callback)
|
||||
Reads a single character or keystroke from a file.
|
||||
callback is an optional callback function, used soley for
|
||||
asynchronously reading from a tty.
|
||||
Returns null if there is no data to read.
|
||||
|
||||
When reading from a regular file, will return a single character.
|
||||
When reading from a tty:
|
||||
Returns true on success or false on failure.
|
||||
Calls callback() and passes as an argument either:
|
||||
A full line of text as entered by the user.
|
||||
\1 (start of header) followed by a special key
|
||||
name (such as ArrowUp).
|
||||
null if the tty cannot be read from.
|
||||
|
||||
var c = stdio.read(fd);
|
||||
|
||||
readLine(fd,callback)
|
||||
Reads a line from a file, up to the next newline, or end of file.
|
||||
Returns null if there is no data to read.
|
||||
|
||||
When reading from a tty, functions the same as read().
|
||||
|
||||
var line = stdio.readLine(fd);
|
||||
|
||||
readAll(fd)
|
||||
Returns the entire content of a file.
|
||||
Returns null if there is no data to read.
|
||||
Works only on regular files (and some non-tty devices).
|
||||
|
||||
var data = stdio.readAll(fd);
|
||||
|
||||
write(fd,data)
|
||||
Write data to a file.
|
||||
Returns true on success.
|
||||
|
||||
if (stdio.write(fd,'string')) {
|
||||
// it worked
|
||||
}else{
|
||||
// it failed
|
||||
}
|
||||
|
||||
ftruncate(fd,length)
|
||||
truncate('path',length)
|
||||
Truncates a file's size to no more than length.
|
||||
Does not increase a file's size to length.
|
||||
Returns true on success.
|
||||
|
||||
var result = stdio.ftruncate(fd,10);
|
||||
var result = stdio.truncate('/usr/home/guest/file.txt',10);
|
||||
|
||||
seek(fd,pos)
|
||||
Moves the read/write position of an open file to pos.
|
||||
If pos is less than 0, then returns the current position without
|
||||
changing, otherwise returns the new position.
|
||||
pos is always relative to the start of the file. When a file is
|
||||
first opened, pos will be set to the start of the file.
|
||||
To set the position to the end of a file, first get the file size
|
||||
using stat() or fstat().
|
||||
|
||||
var p = stdio.seek(fd,10);
|
||||
|
||||
remove('path')
|
||||
Deletes a file or directory.
|
||||
Returns true on success.
|
||||
To delete a directory, the directory must be empty.
|
||||
|
||||
if (stdio.remove('/usr/home/guest/file.txt'))
|
||||
// success!
|
||||
|
||||
link('path','target')
|
||||
Creates a new symbolic link at 'path' which points to 'target'.
|
||||
'target' must exist.
|
||||
If 'path' exists, and is already a link, will update the link.
|
||||
Returns true on success.
|
||||
|
||||
if (stdio.link('/usr/home/guest/logfile','/vr/logs'))
|
||||
// success!
|
||||
|
||||
stat('path')
|
||||
fstat(fd)
|
||||
Returns a stat object with infomation about a file.
|
||||
Returns null on error.
|
||||
Editing the returned object does not change anything for the
|
||||
actual file, it just means your stat object is now wrong.
|
||||
|
||||
var st = stdio.stat('/usr/home/guest/file.txt');
|
||||
var st = stdio.fstat(fd);
|
||||
|
||||
Stat object contents:
|
||||
st.name: string containing the file name
|
||||
st.type: file type identifier, see stdio.types above for more info
|
||||
st.uid: numeric id of the file owner
|
||||
st.gid: numeric id of the file group
|
||||
st.size: file size, or 0 for non text files
|
||||
st.perms: the permissions string for the file, see chmod below.
|
||||
|
||||
chmod('path','mode')
|
||||
fchmod(fd,'mode')
|
||||
Change a file's mode (permissions).
|
||||
Returns true on success.
|
||||
|
||||
The mode string is a 9 or 10 character string describing the
|
||||
file permissions. The optional first character describes the
|
||||
file type, and cannot be changed. Attempting to change the first
|
||||
character will not cause the function to fail, but only the
|
||||
permissions will be changed.
|
||||
|
||||
10 character string: -rwxrwxrwx
|
||||
9 character string: rwxrwxrwx
|
||||
|
||||
After the option first character, the mode string is comprised of
|
||||
3 sets of permissions for Read, Write, and eXecute, one each for
|
||||
the user, group, and others.
|
||||
|
||||
rwx permissions for the file's owner
|
||||
rwx permissions for users in the file's group
|
||||
rwx permissions for other users
|
||||
|
||||
Replacing any of the permissions with a dash '-' will remove that
|
||||
permission from that set:
|
||||
|
||||
rwxr-xr--
|
||||
The user has all permissions, the group has read and execute
|
||||
permissions, others have only read permissions.
|
||||
|
||||
isattty(fd)
|
||||
returns true if fd refers to a tty.
|
||||
|
||||
fprintf(fd,format,args)
|
||||
Print formatted text to the file at fd.
|
||||
Actually formatting is a work in progress, ignore the args.
|
||||
Returns true on success.
|
||||
|
||||
printf(fmt,args)
|
||||
Equivalent to fprintf(io.stdout,fmt,args);
|
||||
|
||||
term (libterm.so): io.include('term')
|
||||
Provides access to raw terminal and tty functions.
|
||||
|
||||
clear()
|
||||
Clears the current terminal, equivalent to running `clear' from
|
||||
the shell.
|
||||
|
||||
opentty()
|
||||
Creates a new blank terminal (tty) with raw key events, for
|
||||
custom displays and interactions. (The less command uses this).
|
||||
Returns a reference object for interacting with the new tty.
|
||||
Returns null on error.
|
||||
|
||||
var tty = term.opentty();
|
||||
|
||||
closetty(tty)
|
||||
Closes a tty created with opentty().
|
||||
|
||||
ttyctrl(func,v)
|
||||
Special function for setting and accessing CLIte-specific tty
|
||||
data. Specifically for interacting directly with the form used
|
||||
for user data input.
|
||||
func is a string containing the intended function.
|
||||
v is the value to set.
|
||||
Returns either the requested data, or false on error.
|
||||
|
||||
term.ttyctrl('iset',string); // sets the current input value
|
||||
var txt = term.ttyctrl('iget'); // gets the current input value
|
||||
term.ttyctrl('prompt',string); // sets the current prompt text
|
||||
123
readme-programs.txt
Normal file
123
readme-programs.txt
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
CLIte command details and API:
|
||||
|
||||
Commands are mostly contained in clite/commands.js and are loaded in
|
||||
at runtime. Each command looks something like:
|
||||
|
||||
clite.commands.load('name',function(args,env,io) {
|
||||
io.write("Hello World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
The load function is only available during boot time, and will:
|
||||
1. load the program into the vfs at /bin/name
|
||||
2. load the source of the program into the vfs at /usr/src/name.js
|
||||
|
||||
The function in the second argument is roughly equivalent to main() in C.
|
||||
This function takes 3 arguments:
|
||||
'args' is equivalent to argv in C, being an array of strings containing
|
||||
the command line arguments, args[0] is the command itself, args.length
|
||||
is equivalent to argc in C.
|
||||
'env' contains the current environment variables: env.PWD contains the
|
||||
present working directory, and so on.
|
||||
'io' contains file descriptors for accessing standard input, output,
|
||||
and error, as well as a method for loading in libraries:
|
||||
|
||||
io.stdout
|
||||
file descriptor for standard output
|
||||
|
||||
io.stderr
|
||||
file descriptor for standard error
|
||||
|
||||
io.stdin
|
||||
file descriptor for standard input
|
||||
|
||||
Note that writing to stdout or stderr, when it is a tty, will
|
||||
currently always print that output as a line, with a newline
|
||||
appended. This may change in the future.
|
||||
|
||||
io.exit(value) exits the program, equivalent to the C exit() function.
|
||||
A program can also be exited by returning a non-null value from the 'main'
|
||||
function.
|
||||
|
||||
io.include('name') loads a library into the current scope for use. See
|
||||
the libs readme file for more details.
|
||||
|
||||
|
||||
Example Programs:
|
||||
Due to the nature of javascript, it is not possible to simply stop half
|
||||
way through a function to wait for user input or for some remote data
|
||||
to load. Instead we have to use a callback function, which complicates
|
||||
things a little, and means there are two kinds of programs: Synchronous,
|
||||
and Asynchronous.
|
||||
|
||||
Synchronous Program:
|
||||
A Synchronous program runs and then exits, with no waiting for callbacks.
|
||||
As such, it looks much like a regular unix program might, and simply
|
||||
returns with an exit code.
|
||||
Here's a "Hello World" as an example:
|
||||
|
||||
clite.commands.load('hello',function(args,env,io) {
|
||||
io.write("Hello World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Asynchronous Program:
|
||||
An Asynchronous program typically uses io calls to interact with data
|
||||
that may not be immediately available; such as remotely loading file
|
||||
data or reading input from a user. As such callbacks are needed to
|
||||
handle that data once it is available.
|
||||
Therefore a return null is used, which lets the system know it is an
|
||||
asyncronous program that will exit later using the io.exit() function.
|
||||
Here's a simple program that reads in a file, and prints it to stdout:
|
||||
|
||||
clite.commands.load('show',function(args,env,io) {
|
||||
var stdlib = io.include('stdlib');
|
||||
var stdio = io.include('stdio');
|
||||
|
||||
// check there's a file to read from
|
||||
if (args.length != 2) {
|
||||
io.error('Specify a file to read');
|
||||
return 1; // not asyncronous yet, so just return
|
||||
}
|
||||
|
||||
// take the argument, and get it's full path
|
||||
var file = stdlib.resolvePath(args[1]);
|
||||
|
||||
// file callback function that will receive the file descriptor
|
||||
// once the file has data in it
|
||||
function fcb(fd) {
|
||||
if (!fd) {
|
||||
// print an error, exit the program, then end
|
||||
io.error('could not open file');
|
||||
io.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// read in the whole file in one go
|
||||
var data = stdio.readAll(fd);
|
||||
// close the file
|
||||
stdio.close(fd);
|
||||
|
||||
// check there's something there
|
||||
if (!data) {
|
||||
// print an error, exit the program, then end
|
||||
io.error('could not read file');
|
||||
io.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// write to stdout
|
||||
io.write(data);
|
||||
|
||||
// and exit successfully
|
||||
io.exit(0);
|
||||
}
|
||||
|
||||
// open the file, and set the callback
|
||||
var fd = stdio.open(file,fcb);
|
||||
|
||||
// we don't want to exit the program yet,
|
||||
// so return null to let the system know that the
|
||||
// program is asyncronous (reads user data, or loads remote data)
|
||||
return null;
|
||||
}
|
||||
445
readme.txt
445
readme.txt
|
|
@ -71,445 +71,6 @@ export - without arguments: will print all environment variables and their
|
|||
- with argument: allows an environment variable to be changed or
|
||||
created. `export FOO=bar'
|
||||
|
||||
|
||||
Command details and API:
|
||||
|
||||
Commands are currently all contained in clite/commands.js and are loaded in
|
||||
at runtime. Each command looks something like:
|
||||
|
||||
|
||||
clite.commands.load('name',function(args,env,io) {
|
||||
io.write("Hello World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
The load function is only available during boot time, and will:
|
||||
1. load the program into the vfs at /bin/name
|
||||
2. load the source of the program into the vfs at /usr/src/name.js
|
||||
|
||||
The function in the second argument is roughly equivalent to main() in C.
|
||||
This function takes 3 arguments:
|
||||
'args' is equivalent to argv in C, being an array of strings containing
|
||||
the command line arguments, args[0] is the command itself, args.length
|
||||
is equivalent to argc in C.
|
||||
'env' contains the current environment variables: env.PWD contains the
|
||||
present working directory, and so on.
|
||||
'io' contains file descriptors for accessing standard input, output,
|
||||
and error, as well as a method for loading in libraries:
|
||||
|
||||
io.stdout
|
||||
file descriptor for standard output
|
||||
|
||||
io.stderr
|
||||
file descriptor for standard error
|
||||
|
||||
io.stdin
|
||||
file descriptor for standard input
|
||||
|
||||
Note that writting to stdout or stderr, when it is a tty, will
|
||||
currently always print that output as a line, with a newline
|
||||
appended. This may change in the future.
|
||||
|
||||
io.exit(value) exits the program, equivalent to the C exit() function.
|
||||
A program can also be exited by returning a non-null value from the 'main'
|
||||
function.
|
||||
|
||||
io.include('name') loads a library into the current scope for use. See
|
||||
below for more details.
|
||||
|
||||
|
||||
Libraries:
|
||||
|
||||
System libraries may be loaded into a program for use of their API using the
|
||||
io.include() function:
|
||||
|
||||
var stdio = io.include('stdio');
|
||||
|
||||
This returns a reference to the library which can be stored in a variable as
|
||||
seen above. Calls to library functions can then be made using that reference:
|
||||
|
||||
stdio.open('/path/to/file');
|
||||
|
||||
There is no need to name the variable the same as the library name, however
|
||||
this is considered good practice.
|
||||
|
||||
The libraries, and their API functions are listed below:
|
||||
|
||||
stdlib: io.include('stdlib')
|
||||
Provides a growing standard unix-like library.
|
||||
|
||||
basename('path')
|
||||
returns the base name of a file path:
|
||||
'/usr/home/guest/file.txt' -> 'file.txt'
|
||||
|
||||
dirname('path')
|
||||
returns the directory name of a file path:
|
||||
'/usr/home/guest/file.txt' -> '/usr/home/guest'
|
||||
|
||||
resolvePath('path','base')
|
||||
special function that resolves a relative path to a full path,
|
||||
using the present working directory or 'base':
|
||||
resolvePath('file.txt') -> '/usr/home/guest/file.txt'
|
||||
resolvePath('file.txt','/etc') -> '/etc/file.txt'
|
||||
resolvePath('~/../file.txt') -> '/usr/home/file.txt'
|
||||
|
||||
strToArgs('string')
|
||||
special function that splits a string into an array of arguments
|
||||
for passing to exec(), supports quotes and so on:
|
||||
'ls -l /var' -> ['ls','-l','var']
|
||||
|
||||
uname()
|
||||
returns an object containing system information:
|
||||
{
|
||||
sysname:'CLIte', // system name, always 'CLIte'
|
||||
nodename:'localhost', // network hostname
|
||||
release:'0.1...', // contains the current CLIte version as stored in clite.state.version
|
||||
version:'0.1...', // same as release
|
||||
machine:navigator.userAgent // contains the browser user agent string
|
||||
}
|
||||
|
||||
nodename is either the website domain, or 'localhost' if loaded
|
||||
without a webserver. This allows programs to test if the system
|
||||
is running locally or not (example is `cat -l' which does not
|
||||
print unloaded files if running without a webserver).
|
||||
|
||||
fork(env,io,call)
|
||||
Creates a new process, with environment and io data passed to it.
|
||||
Returns the pid of the new process, or 0 on failure.
|
||||
call should be a function that accepts the env and io as
|
||||
arguments, this is where the new process begins.
|
||||
|
||||
function newProc(env,io) {
|
||||
io.write('this is a new process!');
|
||||
io.exit(0);
|
||||
}
|
||||
var pid = fork(env,io,newProc);
|
||||
|
||||
exec(path,args,env,io)
|
||||
Executes a new program, replacing the current one.
|
||||
Returns 0 on success, non-zero on failure.
|
||||
Unlike typical unix exec(), this always returns. On success the
|
||||
original program should do nothing more, including not exiting.
|
||||
|
||||
path is the fully resolved file path of the program to be
|
||||
executed, such as '/bin/ls'.
|
||||
args is the argument array created by passing a command line to
|
||||
strToArgs, see above.
|
||||
env and io, are the current environment and io data.
|
||||
|
||||
var command = "ls -l";
|
||||
var args = stdlib.strToArgs(command);
|
||||
var path = stdlib.resolvePath(args[0],'/bin');
|
||||
var r = stdlib.exec(path,args,env,io);
|
||||
if (r == 0)
|
||||
return;
|
||||
|
||||
wait(cb)
|
||||
Calls cb(pid) once any child of the current process has exited.
|
||||
Calls immediately if the are no child processes.
|
||||
Returns false on error.
|
||||
|
||||
waitpid(pid,cb)
|
||||
Calls cb(pid) when the process with id pid has exited. Calls
|
||||
immediately if the process does not exist.
|
||||
If pid is less than 0, functions like wait(cb)
|
||||
Returns false on error.
|
||||
|
||||
waitall(cb)
|
||||
Calls cb(pid) once all child processes of the current process
|
||||
group have exited. Calls immediately if the are no child processes.
|
||||
Returns false on error.
|
||||
|
||||
getuid()
|
||||
Returns the numeric user id of the current user.
|
||||
|
||||
getgid()
|
||||
Returns teh numeric group id of the current user.
|
||||
|
||||
|
||||
stdio: io.include('stdio')
|
||||
Provides access to io functions and types for file access
|
||||
|
||||
stdio.types:
|
||||
object for mapping values of stat.type:
|
||||
FT_UNKOWN: 0 Unknown file type
|
||||
FT_TEXT: 1 Plain text file
|
||||
FT_BINARY: 2 Binary file, likely a javascript function
|
||||
FT_DIR: 3 Directory
|
||||
FT_LINK: 4 Symbolic link
|
||||
FT_DEV: 5 Device
|
||||
FT_REMOTE: 6 Unloaded remote data (will change after loading)
|
||||
FT_SCRIPT: 7 Plain text file beginning with #!
|
||||
FT_IMAGE: 8 Image file, specifically a javascript Image object
|
||||
|
||||
creat('path','-')
|
||||
creates a new file at path
|
||||
returns true on success
|
||||
|
||||
open('path',callback,open_link)
|
||||
Open the file at path, returns a file descriptor.
|
||||
On error returns null, and calls callback(null) if set.
|
||||
If callback is set, will call the function at callback with the
|
||||
file descriptor, this allows remote data to be loaded for the
|
||||
file before beginning read or write operations.
|
||||
If callback is false, open will return directly, without loading
|
||||
remote data.
|
||||
If open_link is set and true, and 'path' is a symbolic link, the
|
||||
returned file descriptor is for the link, not the file pointed to.
|
||||
|
||||
var fd = stdio.open('path',false); // opens the file without loading data
|
||||
var fd = stdio.open('path',callback); // calls callback(fd) when data is loaded
|
||||
var fd = stdio.open('path',callback,true); // as above, but will not follow a link
|
||||
var fd = stdio.open('path'); // as a general rule, don't do this
|
||||
|
||||
close(fd)
|
||||
Closes a file opened with open()
|
||||
|
||||
stdio.close(fd);
|
||||
|
||||
read(fd,callback)
|
||||
Reads a single character or keystroke from a file.
|
||||
callback is an optional callback function, used soley for
|
||||
asynchronously reading from a tty.
|
||||
Returns null if there is no data to read.
|
||||
|
||||
When reading from a regular file, will return a single character.
|
||||
When reading from a tty:
|
||||
Returns true on success or false on failure.
|
||||
Calls callback() and passes as an argument either:
|
||||
A full line of text as entered by the user.
|
||||
\1 (start of header) followed by a special key
|
||||
name (such as ArrowUp).
|
||||
null if the tty cannot be read from.
|
||||
|
||||
var c = stdio.read(fd);
|
||||
|
||||
readLine(fd,callback)
|
||||
Reads a line from a file, up to the next newline, or end of file.
|
||||
Returns null if there is no data to read.
|
||||
|
||||
When reading from a tty, functions the same as read().
|
||||
|
||||
var line = stdio.readLine(fd);
|
||||
|
||||
readAll(fd)
|
||||
Returns the entire content of a file.
|
||||
Returns null if there is no data to read.
|
||||
Works only on regular files (and some non-tty devices).
|
||||
|
||||
var data = stdio.readAll(fd);
|
||||
|
||||
write(fd,data)
|
||||
Write data to a file.
|
||||
Returns true on success.
|
||||
|
||||
if (stdio.write(fd,'string')) {
|
||||
// it worked
|
||||
}else{
|
||||
// it failed
|
||||
}
|
||||
|
||||
ftruncate(fd,length)
|
||||
truncate('path',length)
|
||||
Truncates a file's size to no more than length.
|
||||
Does not increase a file's size to length.
|
||||
Returns true on success.
|
||||
|
||||
var result = stdio.ftruncate(fd,10);
|
||||
var result = stdio.truncate('/usr/home/guest/file.txt',10);
|
||||
|
||||
seek(fd,pos)
|
||||
Moves the read/write position of an open file to pos.
|
||||
If pos is less than 0, then returns the current position without
|
||||
changing, otherwise returns the new position.
|
||||
pos is always relative to the start of the file. When a file is
|
||||
first opened, pos will be set to the start of the file.
|
||||
To set the position to the end of a file, first get the file size
|
||||
using stat() or fstat().
|
||||
|
||||
var p = stdio.seek(fd,10);
|
||||
|
||||
remove('path')
|
||||
Deletes a file or directory.
|
||||
Returns true on success.
|
||||
To delete a directory, the directory must be empty.
|
||||
|
||||
if (stdio.remove('/usr/home/guest/file.txt'))
|
||||
// success!
|
||||
|
||||
link('path','target')
|
||||
Creates a new symbolic link at 'path' which points to 'target'.
|
||||
'target' must exist.
|
||||
If 'path' exists, and is already a link, will update the link.
|
||||
Returns true on success.
|
||||
|
||||
if (stdio.link('/usr/home/guest/logfile','/vr/logs'))
|
||||
// success!
|
||||
|
||||
stat('path')
|
||||
fstat(fd)
|
||||
Returns a stat object with infomation about a file.
|
||||
Returns null on error.
|
||||
Editing the returned object does not change anything for the
|
||||
actual file, it just means your stat object is now wrong.
|
||||
|
||||
var st = stdio.stat('/usr/home/guest/file.txt');
|
||||
var st = stdio.fstat(fd);
|
||||
|
||||
Stat object contents:
|
||||
st.name: string containing the file name
|
||||
st.type: file type identifier, see stdio.types above for more info
|
||||
st.uid: numeric id of the file owner
|
||||
st.gid: numeric id of the file group
|
||||
st.size: file size, or 0 for non text files
|
||||
st.perms: the permissions string for the file, see chmod below.
|
||||
|
||||
chmod('path','mode')
|
||||
fchmod(fd,'mode')
|
||||
Change a file's mode (permissions).
|
||||
Returns true on success.
|
||||
|
||||
The mode string is a 9 or 10 character string describing the
|
||||
file permissions. The optional first character describes the
|
||||
file type, and cannot be changed. Attempting to change the first
|
||||
character will not cause the function to fail, but only the
|
||||
permissions will be changed.
|
||||
|
||||
10 character string: -rwxrwxrwx
|
||||
9 character string: rwxrwxrwx
|
||||
|
||||
After the option first character, the mode string is comprised of
|
||||
3 sets of permissions for Read, Write, and eXecute, one each for
|
||||
the user, group, and others.
|
||||
|
||||
rwx permissions for the file's owner
|
||||
rwx permissions for users in the file's group
|
||||
rwx permissions for other users
|
||||
|
||||
Replacing any of the permissions with a dash '-' will remove that
|
||||
permission from that set:
|
||||
|
||||
rwxr-xr--
|
||||
The user has all permissions, the group has read and execute
|
||||
permissions, others have only read permissions.
|
||||
|
||||
isattty(fd)
|
||||
returns true if fd refers to a tty.
|
||||
|
||||
fprintf(fd,format,args)
|
||||
Print formatted text to the file at fd.
|
||||
Actually formatting is a work in progress, ignore the args.
|
||||
Returns true on success.
|
||||
|
||||
printf(fmt,args)
|
||||
Equivalent to fprintf(io.stdout,fmt,args);
|
||||
|
||||
term: io.include('term')
|
||||
Provides access to raw terminal and tty functions.
|
||||
|
||||
clear()
|
||||
Clears the current terminal, equivalent to running `clear' from
|
||||
the shell.
|
||||
|
||||
opentty()
|
||||
Creates a new blank terminal (tty) with raw key events, for
|
||||
custom displays and interactions. (The less command uses this).
|
||||
Returns a reference object for interacting with the new tty.
|
||||
Returns null on error.
|
||||
|
||||
var tty = term.opentty();
|
||||
|
||||
closetty(tty)
|
||||
Closes a tty created with opentty().
|
||||
|
||||
ttyctrl(func,v)
|
||||
Special function for setting and accessing CLIte-specific tty
|
||||
data. Specifically for interacting directly with the form used
|
||||
for user data input.
|
||||
func is a string containing the intended function.
|
||||
v is the value to set.
|
||||
Returns either the requested data, or false on error.
|
||||
|
||||
term.ttyctrl('iset',string); // sets the current input value
|
||||
var txt = term.ttyctrl('iget'); // gets the current input value
|
||||
term.ttyctrl('prompt',string); // sets the current prompt text
|
||||
|
||||
|
||||
Example Programs:
|
||||
Due to the nature of javascript, it is not possible to simply stop half
|
||||
way through a function to wait for user input or for some remote data
|
||||
to load. Instead we have to use a callback function, which complicates
|
||||
things a little, and means there are two kinds of programs: Syncronous,
|
||||
and Asyncronous.
|
||||
|
||||
Syncronous Program:
|
||||
A Syncronous program runs and then exits, with no waiting for callbacks.
|
||||
As such, it looks much like a regular unix program might, and simply
|
||||
returns with an exit code.
|
||||
Here's a "Hello World" as an example:
|
||||
|
||||
clite.commands.load('hello',function(args,env,io) {
|
||||
io.write("Hello World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Asyncronous Program:
|
||||
An Asycronous program typically uses io calls to interact with data
|
||||
that may not be immediately available; such as remotely loading file
|
||||
data or reading input from a user. As such callbacks are needed to
|
||||
handle that data once it is available.
|
||||
Therefore a return null is used, which lets the system know it is an
|
||||
asyncronous program that will exit later using the io.exit() function.
|
||||
Here's a simple program that reads in a file, and prints it to stdout:
|
||||
|
||||
clite.commands.load('show',function(args,env,io) {
|
||||
var stdlib = io.include('stdlib');
|
||||
var stdio = io.include('stdio');
|
||||
|
||||
// check there's a file to read from
|
||||
if (args.length != 2) {
|
||||
io.error('Specify a file to read');
|
||||
return 1; // not asyncronous yet, so just return
|
||||
}
|
||||
|
||||
// take the argument, and get it's full path
|
||||
var file = stdlib.resolvePath(args[1]);
|
||||
|
||||
// file callback function that will receive the file descriptor
|
||||
// once the file has data in it
|
||||
function fcb(fd) {
|
||||
if (!fd) {
|
||||
// print an error, exit the program, then end
|
||||
io.error('could not open file');
|
||||
io.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// read in the whole file in one go
|
||||
var data = stdio.readAll(fd);
|
||||
// close the file
|
||||
stdio.close(fd);
|
||||
|
||||
// check there's something there
|
||||
if (!data) {
|
||||
// print an error, exit the program, then end
|
||||
io.error('could not read file');
|
||||
io.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// write to stdout
|
||||
io.write(data);
|
||||
|
||||
// and exit successfully
|
||||
io.exit(0);
|
||||
}
|
||||
|
||||
// open the file, and set the callback
|
||||
var fd = stdio.open(file,fcb);
|
||||
|
||||
// we don't want to exit the program yet,
|
||||
// so return null to let the system know that the
|
||||
// program is asyncronous (reads user data, or loads remote data)
|
||||
return null;
|
||||
}
|
||||
For more information, check the other readme files for info on CLIte internals.
|
||||
Also, consider buying the developer a coffee:
|
||||
https://ko-fi.com/ticklishhoneybee
|
||||
|
|
|
|||
Loading…
Reference in a new issue