So, this is one of my more, uh, interesting adventures.
Basically, my laptop at work (edit: spelling; thanks Lord of the Dance!) died, and our fear-less admin (and resident Lord of the Dance) requested that I try Western Digital’s hard disk analyzer. Well, interestingly enough, that utility requires a FreeDOS install, which I put on a spare 1GiB USB stick. Well, that got me thinking: what else can I do with a spare FreeDOS install? Well, I can put FreePascal on it! That would make it super useful!
So, thus armed, I set out to write some neat stuff for FreeDOS… and promptly hit a wall: the FreePascal IDE wouldn’t load! I don’t recall what the error was, but naturally my next step was to check if the compiler would work, which it did. “Well, that should be enough…”
My First step was a simple “hello world!” type of program:
program foo;
begin
writeln("Hello, world");
end.
Can you spot the bug? Suffice it to say that I haven’t written Pascal in some time, & forgot that Strings are ' '
delimited rather than " "
delimited; the above was quickly followed by:
program bar;
begin
writeln('Hello, world!');
end.
The fun part about this is that I wrote them line-by-line using GECHO
; the built in DOS-echo didn’t handle strings properly.
(Although, thinking about it, I wonder if I could have used something like TYPE CON
… Have to try that later). Basically I wrote way too many lines of:
C:\\WORK>\\fpc\\bin\\go32v2\\gecho "program foo;" > foo.pas
C:\\WORK>\\fpc\\bin\\go32v2\\gecho "begin" >> foo.pas
...
As you may imagine, that was slow going :D
Having written a “Hello, world” that I could compile, my next thought was to write something akin to cat
, where it would read from STDIN
(or Input
in Pascal) and write to STDOUT
. I don’t know if I screwed something up, but EOF
was not working for me (I would hit ^Z
and it would keep going; I probably mistyped something), so my cat
replacement reads until it hits .
byitself on a line, like ed
does:
program dog(input, output);
var s: string;
begin
readln(s);
while s <> '.' do
begin
writeln(s);
readln(s);
end;
end.
The code is simple, and I hand formatted it, but mostly so that I could attempt to read it later. Personally, I like the idea of Pascal/Algol, but I do find the lack of symbols a bit disorienting at times, so I do like to have it nicely formatted.
Armed with that code, I set out to write a simple prompt test:
program prompttest(input, output);
var
s : string;
begin
write('> ');
readln(s);
while s <> 'q' do
begin
writeln('s is ', s);
write('> ');
readln(s);
end;
end.
Having written that, I finally set out to write a very basic editor, which I dubbed “ZDLIN”. I can’t tell you how many times I had to type this in; after getting the p
and i
commands to work, it was a devil of a time to retype the whole thing in order to add commands. I was thinking about adding a handful of other small utilities, like head
and tail
, to help with the process, but eventually I just soldiered on & wrote it out:
program zdlin(input, output);
uses
Classes, SysUtils;
var
buffer : TStringList;
line, src : string;
idx, tmp0, tmp1, tmp2 : integer;
begin
buffer := TStringList.create;
src := ParamStr(1);
buffer.LoadFromFile(src);
idx := buffer.count - 1;
write('> ');
readln(line);
while line <> 'q' do
begin
if line = 'p' then
begin
if idx > 0 then
begin
for tmp0 := 0 to idx do
begin
writeln(buffer[tmp0]);
end;
end;
end
else if line = 'P' then // should prompt for a range
begin
if idx > 0 then
begin
for tmp0 := 0 to idx do
begin
writeln(inttostr(tmp0),': ', buffer[tmp0]);
end;
end;
end
else if line = 'd' then
begin
write('at: ');
readln(line);
Val(line, tmp0, tmp1);
buffer.delete(tmp0);
Dec(idx);
end
else if line = 'D' then
begin
write('start: ');
readln(line);
Val(line, tmp0, tmp1);
write('end: ');
readln(line);
Val(line, tmp1, tmp2);
for tmp2 := tmp0 to tmp1 do
begin
buffer.delete(tmp0); // buffer shrinks each time
end;
idx := buffer.count - 1;
end
else if line = 'I' then
begin
write('at: ');
readln(line);
Val(line, tmp0, tmp1);
readln(line);
tmp1 := tmp0;
while line <> '.' do
begin
buffer.insert(tmp0, line);
Inc(tmp0);
readln(line);
end;
Inc(idx, tmp0 - tmp1);
end
else if line = 'i' then
begin
readln(line);
while line <> '.' do
begin
idx := buffer.add(line);
readln(line);
end;
end
else
writeln('Unknown command: ', line);
write('> ');
readln(line);
end;
buffer.SaveToFile(src);
buffer.Free;
end.
As you can see, there is no command parsing what so ever; commands are simply p
or P
, and the user is then prompted for any other parameters as necessay. Though basic, it should be enough to implement [https://twitter.com/bigthingist/status/454454027418230784 Bigthingist’s] idea, and make something more visual. Of course, as I replied, I would be interested in trying to make something [http://en.wikipedia.org/wiki/Sam_(text_editor) Sam-like] as a test. And, of course, I’d like to make a Digamma Runtime; Retargetting Enyalios for FreePascal shouldn’t be too difficult; I’d be more concerned about it being too large for memory though :D
The files mentioned above can be downloaded below: