include "keybd.s7i";
const type: editLineFile is sub null_file struct
var file: inFile is STD_NULL;
var file: outFile is STD_NULL;
var boolean: allowUnicode is TRUE;
var string: line is "";
var boolean: lineFinished is TRUE;
var array string: history is 0 times "";
end struct;
const func file: openEditLine (in file: inFile, in file: outFile) is func
result
var file: newFile is STD_NULL;
local
var editLineFile: new_editLineFile is editLineFile.value;
begin
new_editLineFile.inFile := inFile;
new_editLineFile.outFile := outFile;
newFile := toInterface(new_editLineFile);
end func;
const func file: openEditLineLatin1 (in file: inFile, in file: outFile) is func
result
var file: newFile is STD_NULL;
local
var editLineFile: new_editLineFile is editLineFile.value;
begin
new_editLineFile.inFile := inFile;
new_editLineFile.outFile := outFile;
new_editLineFile.allowUnicode := FALSE;
newFile := toInterface(new_editLineFile);
end func;
const func string: getln (inout editLineFile: inEditLine) is func
result
var string: line is "";
local
var char: ch is ' ';
var char: response is ' ';
var integer: pos is 1;
var array string: history is 0 times "";
var integer: historyPos is 0;
begin
if inEditLine.line = "" then
history := inEditLine.history & [] ("");
historyPos := length(history);
repeat
if pos <= length(line) then
cursorOn(inEditLine.outFile, line[pos]);
else
cursorOn(inEditLine.outFile, ' ');
end if;
flush(inEditLine.outFile);
ch := getc(inEditLine.inFile);
if pos <= length(line) then
cursorOff(inEditLine.outFile, line[pos]);
else
cursorOff(inEditLine.outFile, ' ');
end if;
case ch of
when {KEY_BS}:
if pos > 1 then
decr(pos);
moveLeft(inEditLine.outFile, line[pos len 1]);
erase(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
line := line[.. pred(pos)] & line[succ(pos) ..];
write(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
end if;
when {KEY_DEL}:
if pos <= length(line) then
erase(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
line := line[.. pred(pos)] & line[succ(pos) ..];
write(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
end if;
when {KEY_HOME}:
moveLeft(inEditLine.outFile, line[.. pred(pos)]);
pos := 1;
when {KEY_END}:
write(inEditLine.outFile, line[pos ..]);
pos := succ(length(line));
when {KEY_LEFT}:
if pos > 1 then
decr(pos);
moveLeft(inEditLine.outFile, line[pos len 1]);
end if;
when {KEY_RIGHT}:
if pos <= length(line) then
write(inEditLine.outFile, line[pos]);
incr(pos);
end if;
when {KEY_UP}:
if historyPos > 1 then
moveLeft(inEditLine.outFile, line[.. pred(pos)]);
erase(inEditLine.outFile, line);
moveLeft(inEditLine.outFile, line);
history[historyPos] := line;
decr(historyPos);
line := history[historyPos];
write(inEditLine.outFile, line);
pos := succ(length(line));
end if;
when {KEY_DOWN}:
if historyPos < length(history) then
moveLeft(inEditLine.outFile, line[.. pred(pos)]);
erase(inEditLine.outFile, line);
moveLeft(inEditLine.outFile, line);
history[historyPos] := line;
incr(historyPos);
line := history[historyPos];
write(inEditLine.outFile, line);
pos := succ(length(line));
end if;
when {KEY_CTL_C, KEY_CTL_T}:
write(inEditLine.outFile, " terminate (y/n)? ");
moveLeft(inEditLine.outFile, " ");
cursorOn(inEditLine.outFile, ' ');
flush(inEditLine.outFile);
response := getc(inEditLine.inFile);
cursorOff(inEditLine.outFile, ' ');
if lower(response) = 'y' then
writeln(inEditLine.outFile, "yes ");
writeln(inEditLine.outFile);
writeln(inEditLine.outFile, "*** PROGRAM TERMINATED BY USER");
exit(PROGRAM);
else
backSpace(inEditLine.outFile, " terminate (y/n)? ");
write(inEditLine.outFile, line[pos len 20]);
moveLeft(inEditLine.outFile, line[pos len 20]);
end if;
when {KEY_NL, KEY_CLOSE, EOF}:
noop;
otherwise:
if ch >= ' ' and ch <= '~' or ch >= '\160;' and ch <= '\255;' or
ch >= '\256;' and ch <= '\16#10ffff;' and inEditLine.allowUnicode then
line := line[.. pred(pos)] & str(ch) & line[pos ..];
write(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[succ(pos) ..]);
incr(pos);
end if;
end case;
until ch = KEY_NL or ch = EOF or ch = KEY_CLOSE;
writeln(inEditLine.outFile);
inEditLine.bufferChar := ch;
if length(inEditLine.history) = 0 or
inEditLine.history[length(inEditLine.history)] <> line then
inEditLine.history &:= line;
end if;
else
line := inEditLine.line;
inEditLine.line := "";
end if;
inEditLine.lineFinished := FALSE;
end func;
const func char: getc (inout editLineFile: inEditLine) is func
result
var char: ch is ' ';
local
var integer: number is 0;
begin
if inEditLine.lineFinished then
inEditLine.line := getln(inEditLine);
end if;
if inEditLine.line = "" then
ch := inEditLine.bufferChar;
inEditLine.lineFinished := TRUE;
else
ch := inEditLine.line[1];
inEditLine.line := inEditLine.line[2 ..];
end if;
end func;
const func string: gets (inout editLineFile: inEditLine, in integer: maxLength) is func
result
var string: striRead is "";
begin
if maxLength <= 0 then
if maxLength <> 0 then
raise RANGE_ERROR;
end if;
else
if inEditLine.lineFinished then
inEditLine.line := getln(inEditLine);
end if;
striRead := inEditLine.line[.. maxLength];
inEditLine.line := inEditLine.line[succ(maxLength) ..];
while length(striRead) < maxLength do
striRead &:= inEditLine.bufferChar;
inEditLine.lineFinished := TRUE;
if length(striRead) < maxLength then
inEditLine.line := getln(inEditLine);
striRead &:= inEditLine.line[.. maxLength - length(striRead)];
inEditLine.line := inEditLine.line[succ(maxLength - length(striRead)) ..];
end if;
end while;
end if;
end func;
const func boolean: eof (in editLineFile: inEditLine) is
return inEditLine.lineFinished and inEditLine.bufferChar = EOF;
const func boolean: hasNext (in editLineFile: inEditLine) is
return inEditLine.bufferChar = EOF;
const func string: readPassword (inout file: aFile) is DYNAMIC;
const func string: readPassword (inout editLineFile: inEditLine) is func
result
var string: line is "";
local
var char: ch is ' ';
var integer: pos is 1;
begin
repeat
if pos <= length(line) then
cursorOn(inEditLine.outFile, '*');
else
cursorOn(inEditLine.outFile, ' ');
end if;
flush(inEditLine.outFile);
ch := getc(inEditLine.inFile);
if pos <= length(line) then
cursorOff(inEditLine.outFile, '*');
else
cursorOff(inEditLine.outFile, ' ');
end if;
if ch = KEY_BS then
if pos > 1 then
decr(pos);
moveLeft(inEditLine.outFile, line[pos len 1]);
erase(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
line := line[.. pred(pos)] & line[succ(pos) ..];
write(inEditLine.outFile, "*" mult length(line[pos ..]));
moveLeft(inEditLine.outFile, line[pos ..]);
end if;
elsif ch = KEY_DEL then
if pos <= length(line) then
erase(inEditLine.outFile, line[pos ..]);
moveLeft(inEditLine.outFile, line[pos ..]);
line := line[.. pred(pos)] & line[succ(pos) ..];
write(inEditLine.outFile, "*" mult length(line[pos ..]));
moveLeft(inEditLine.outFile, line[pos ..]);
end if;
elsif ch = KEY_HOME then
moveLeft(inEditLine.outFile, line[.. pred(pos)]);
pos := 1;
elsif ch = KEY_END then
write(inEditLine.outFile, line[pos ..]);
pos := succ(length(line));
elsif ch = KEY_LEFT then
if pos > 1 then
decr(pos);
moveLeft(inEditLine.outFile, line[pos len 1]);
end if;
elsif ch = KEY_RIGHT then
if pos <= length(line) then
write(inEditLine.outFile, "*");
incr(pos);
end if;
elsif ch >= ' ' and ch <= '~' or ch >= '\160;' and ch <= '\255;' or
ch >= '\256;' and ch <= '\16#10ffff;' and inEditLine.allowUnicode then
line := line[.. pred(pos)] & str(ch) & line[pos ..];
write(inEditLine.outFile, "*" mult length(line[pos ..]));
moveLeft(inEditLine.outFile, line[succ(pos) ..]);
incr(pos);
end if;
until ch = KEY_NL or ch = EOF;
writeln(inEditLine.outFile);
inEditLine.bufferChar := ch;
inEditLine.line := "";
inEditLine.lineFinished := FALSE;
end func;