Asuro/src/terminal.pas

397 lines
10 KiB
ObjectPascal

{ ************************************************
* Asuro
* Unit: Terminal
* Description: Interactive shell for the user
************************************************
* Author: K Morris
* Contributors:
************************************************ }
unit terminal;
interface
uses
bios_data_area,
console,
keyboard,
util,
lmemorymanager,
strings,
tracer,
asuro;
const
TERMINAL_HWND = 1;
type
PParamList = ^TParamList;
TParamList = record
Param : pchar;
Next : PParamList;
end;
PHistory = ^THistory;
THistory = record
Command : pchar;
Next : PHistory;
end;
TCommandBuffer = array[0..1023] of byte;
TCommandMethod = procedure(params : PParamList);
TCommand = record
registered : boolean;
command : pchar;
method : TCommandMethod;
description : pchar;
end;
var
buffer : TCommandBuffer;
History : PHistory;
bIndex : uint32 = 0;
Commands : array[0..65534] of TCommand;
Working_Directory : PChar = '/';
procedure run;
procedure init;
procedure registerCommand(command : pchar; method : TCommandMethod; description : pchar);
function getParams(buf : TCommandBuffer) : PParamList;
function paramCount(params : PParamList) : uint32;
function getParam(index : uint32; params : PParamList) : pchar;
procedure setWorkingDirectory(str : pchar);
function getWorkingDirectory : pchar;
function getTerminalHWND : uint32;
implementation
uses
RTC;
function getTerminalHWND : uint32;
begin
getTerminalHWND:= TERMINAL_HWND;
end;
function getWorkingDirectory : pchar;
begin
getWorkingDirectory:= Working_Directory;
end;
procedure setWorkingDirectory(str : pchar);
begin
if str <> nil then begin
Working_Directory:= stringCopy(str);
end;
end;
function paramCount(params : PParamList) : uint32;
var
current : PParamList;
i : uint32;
begin
push_trace('terminal.paramCount');
current:= params;
i:= 0;
while current^.param <> nil do begin
inc(i);
current:= current^.next;
end;
paramCount:= i-1;
pop_trace;
end;
function getParams(buf : TCommandBuffer) : PParamList;
var
start, finish : uint32;
size : uint32;
ptr : uint32;
root : PParamList;
current : PParamList;
begin
push_trace('terminal.getParams');
root:= PParamList(kalloc(sizeof(TParamList)));
current:= root;
current^.next:= nil;
current^.Param:= nil;
start:= 0;
finish:= 0;
while buf[start] <> 0 do begin
while (char(buf[finish]) <> ' ') and (buf[finish] <> 0) do begin
inc(finish);
end;
size:= finish - start;
if size > 0 then begin
ptr:= uint32(@buf[start]);
current^.Param:= pchar(kalloc(size+2));
memset(uint32(current^.Param), 0, size+2);
memcpy(uint32(ptr), uint32(current^.Param), size);
current^.next:= PParamList(kalloc(sizeof(TParamList)));
current:= current^.next;
current^.next:= nil;
current^.Param:= nil;
end;
start:=finish+1;
inc(finish);
end;
getParams:= root;
pop_trace;
end;
function getParam(index : uint32; params : PParamList) : pchar;
var
result : pchar;
search : PParamList;
i : uint32;
begin
push_trace('terminal.getParam');
result:= nil;
search:= params;
for i:=0 to index do begin
search:= search^.next;
end;
result:= search^.param;
getParam:= result;
pop_trace;
end;
procedure freeParams(params : PParamList);
var
p : PParamList;
next : PParamList;
begin
push_trace('terminal.freeParams');
p:= params;
next:= p^.next;
while p^.next <> nil do begin
if p^.param <> nil then kfree(void(p^.param));
kfree(void(p));
p:= next;
next:= p^.next;
end;
pop_trace;
end;
procedure testParams(params : PParamList);
begin
while params^.Param <> nil do begin
writestringlnWND(params^.Param, TERMINAL_HWND);
params:= params^.next;
end;
end;
procedure echo(params : PParamList);
var
current : PParamList;
begin
current:= params^.next;
while current^.param <> nil do begin
console.writestringWND(current^.param, TERMINAL_HWND);
console.writestringWND(' ', TERMINAL_HWND);
current:= current^.next;
end;
console.writestringlnWND('', TERMINAL_HWND);
end;
procedure clear(params : PParamList);
begin
console.clearWND(TERMINAL_HWND);
end;
procedure version(params : PParamList);
begin
console.writestringlnWND(asuro.VERSION, TERMINAL_HWND);
end;
procedure help(params : PParamList);
var
i : uint32;
begin
console.writestringlnWND('Registered Commands: ', TERMINAL_HWND);
for i:=0 to 65534 do begin
if Commands[i].Registered then begin
console.writestringWND(' ', TERMINAL_HWND);
console.writestringWND(Commands[i].command, TERMINAL_HWND);
console.writestringWND(' - ', TERMINAL_HWND);
console.writestringlnWND(Commands[i].description, TERMINAL_HWND);
end;
end;
end;
procedure cockwomble(params : PParamList);
var
x, y : uint8;
o : uint16;
i : uint32;
begin
i:= 1;
while true do begin
for y:=0 to 63 do begin
for x:=0 to 159 do begin
o:= uint16(y * i + x * i + i + (BDA^.Ticks SHR 3));
outputChar(' ', x, y, $FFFF, o);
end;
end;
i:= uint32(i) + 1;
end;
end;
procedure test(params : PParamList);
begin
if paramCount(params) > 0 then begin
console.writeintlnWND(stringToInt(getParam(0, params)), TERMINAL_HWND);
end else begin
console.writestringlnWND('Invalid number of params', TERMINAL_HWND);
end;
end;
procedure printTime(Params : PParamList);
begin
writeIntWND(DateTime.Day, TERMINAL_HWND);
writeStringWND('/', TERMINAL_HWND);
writeIntWND(DateTime.Month, TERMINAL_HWND);
writeStringWND('/', TERMINAL_HWND);
writeIntWND(DateTime.Century, TERMINAL_HWND);
writeIntWND(DateTime.Year, TERMINAL_HWND);
writeStringWND(' ', TERMINAL_HWND);
writeIntWND(DateTime.Hours, TERMINAL_HWND);
writeStringWND(':', TERMINAL_HWND);
writeIntWND(DateTime.Minutes, TERMINAL_HWND);
writeStringWND(':', TERMINAL_HWND);
writeIntlnWND(DateTime.Seconds, TERMINAL_HWND);
//writeStringWND('Weekday: ', TERMINAL_HWND);
//writeIntlnWND(DateTime.Weekday, TERMINAL_HWND);
end;
procedure registerCommand(command : pchar; method : TCommandMethod; description : pchar);
var
index : uint32;
begin
index:= 0;
while Commands[index].registered = true do inc(index);
Commands[index].registered:= true;
Commands[index].Command:= command;
Commands[index].method:= method;
Commands[index].description:= description;
end;
procedure process_command;
var
fallthrough : boolean;
params : PParamList;
i : uint32;
next : PParamList;
uppera, upperb : pchar;
begin
push_trace('terminal.process_command');
{ Start a new line. }
console.writecharlnWND(' ', TERMINAL_HWND);
{ Enable fallthrough/Unrecognized command }
fallthrough:= true;
{ Get all params and check params[0] (the command) to see if it's registered }
params:= getParams(buffer);
if params^.param <> nil then begin
uppera:= stringToUpper(params^.param);
for i:=0 to 65534 do begin
if Commands[i].registered then begin
upperb:= stringToUpper(Commands[i].command);
if stringEquals(uppera, upperb) then begin
Commands[i].method(params);
fallthrough:= false;
end;
kfree(void(upperb));
end;
end;
kfree(void(uppera));
end;
{ Free the params }
freeParams(params);
{ Display message if command is unknown AKA fallthrough is active }
if fallthrough then begin
console.writestringlnWND('Unknown Command.', TERMINAL_HWND);
end;
{ Reset the terminal ready for the next command }
console.writestringWND('Asuro#', TERMINAL_HWND);
console.writestringWND(Working_Directory, TERMINAL_HWND);
console.writestringWND('> ', TERMINAL_HWND);
bIndex:= 0;
memset(uint32(@buffer[0]), 0, 1024);
pop_trace;
end;
procedure key_event(info : TKeyInfo);
begin
if (info.key_code >= 32) and (info.key_code <= 126) then begin
if bIndex < 1024 then begin
buffer[bIndex]:= info.key_code;
inc(bIndex);
console.writecharWND(char(info.key_code), TERMINAL_HWND);
end;
end;
if info.key_code = 8 then begin //backspace
if bIndex > 0 then begin
console.backspaceWND(TERMINAL_HWND);
dec(bIndex);
buffer[bIndex]:= 0;
end;
end;
if info.key_code = 13 then begin //return
process_command;
end;
end;
procedure change_dir(Params : PParamList);
begin
if paramCount(Params) > 0 then begin
setWorkingDirectory(getParam(0, Params));
end;
end;
procedure ToggleWND1(Params : PParamList);
begin
console.toggleWNDVisible(1);
end;
procedure init;
begin
console.writestringln('TERMINAL: INIT BEGIN.');
memset(uint32(@Commands[0]), 0, 65535*sizeof(TCommand));
memset(uint32(@buffer[0]), 0, 1024);
registerCommand('VERSION', @version, 'Display the running version of Asuro.');
registerCommand('CLEAR', @clear, 'Clear the Screen.');
registerCommand('HELP', @help, 'Lists all registered commands and their description.');
registerCommand('ECHO', @echo, 'Echo''s text to the terminal.');
registerCommand('TESTPARAMS', @testParams, 'Tests param parsing.');
registerCommand('TEST', @test, 'Command for testing.');
registerCommand('CD', @change_dir, 'Change Directory test.');
registerCommand('PATTERN', @cockwomble, 'Print an animated pattern to the screen.');
registerCommand('TOGGLEWND1', @ToggleWND1, 'Toggle WND 1 Visibility.');
registerCommand('TIME', @printTime, 'PRINT TIME!');
console.writestringln('TERMINAL: INIT END.');
end;
procedure run;
begin
keyboard.hook(@key_event);
console.clearWND(TERMINAL_HWND);
console.writestringWND('Asuro#', TERMINAL_HWND);
console.writestringWND(Working_Directory, TERMINAL_HWND);
console.writestringWND('> ', TERMINAL_HWND);
console.setWNDVisible(TERMINAL_HWND, true);
end;
end.