Category : Miscellaneous Language Source Code
Archive   : ADATUT12.ZIP
Filename : LEDIT.ANS

 
Output of file : LEDIT.ANS contained in archive : ADATUT12.ZIP

-- Our solution to Outside Assignment 5:
with TEXT_IO; use TEXT_IO;
procedure LEDIT is

MAX_LENGTH : constant := 80;
MAX_LINE_NUMBER : constant := 29_999;
type TEXT is
record
LEN : INTEGER range 0 .. MAX_LENGTH := 0;
VAL : STRING(1 .. MAX_LENGTH);
end record;
type LINK;
type P is access LINK;
type LINK is
record
NUM : POSITIVE;
LINE : TEXT;
NEXT : P;
end record;
HEAD : P := new LINK;
TEMP : P;
INPUT_FILE, OUTPUT_FILE : FILE_TYPE;
INPUT : TEXT;
FINISHED : BOOLEAN := FALSE;
LINE_NUM : NATURAL := 10;

function STR(T : in TEXT) return STRING is separate;
procedure READ_INPUT_FILE is separate;
procedure DO_COMMAND is separate;
begin
PUT("Input file: "); GET_LINE(INPUT.VAL, INPUT.LEN);
READ_INPUT_FILE;
PUT("Output file: "); GET_LINE(INPUT.VAL, INPUT.LEN);
CREATE(OUTPUT_FILE, NAME => STR(INPUT));

-- Get and process commands.
while not FINISHED loop
PUT("> "); GET_LINE(INPUT.VAL, INPUT.LEN);
DO_COMMAND;
end loop;

-- Write the output file.
TEMP := HEAD.NEXT; -- Skip unused link at start of linked list.
while TEMP /= null loop
PUT_LINE(OUTPUT_FILE, STR(TEMP.LINE)); -- Write line of text.
TEMP := TEMP.NEXT; -- Get next link.
end loop;
CLOSE(OUTPUT_FILE);
end LEDIT;

separate(LEDIT)
function STR(T : in TEXT) return STRING is
begin
return T.VAL(1 .. T.LEN);
end STR;

separate (LEDIT)
procedure READ_INPUT_FILE is
begin -- If the input file exists, print a message and read it in.
OPEN(INPUT_FILE, IN_FILE, STR(INPUT));
PUT_LINE("File found.");
TEMP := HEAD;
while not END_OF_FILE(INPUT_FILE) loop
GET_LINE(INPUT_FILE, INPUT.VAL, INPUT.LEN); -- Read a line.
TEMP.NEXT := new LINK'(LINE_NUM, INPUT, null); -- Add to list.
TEMP := TEMP.NEXT; -- Advance pointer to next link.
LINE_NUM := LINE_NUM + 10;
end loop;
CLOSE(INPUT_FILE);
exception -- If the input file doesn't exist, just print a message.
when NAME_ERROR => PUT_LINE("File not found.");
end READ_INPUT_FILE;

separate(LEDIT)
procedure DO_COMMAND is
procedure DELETE_FIRST_CHARACTER(T : in out TEXT) is separate;
procedure GET_LEADING_INTEGER(N : out NATURAL) is separate;
procedure STRIP_LEADING_SPACES_FROM_INPUT is separate;
procedure ADD_DELETE_REPLACE_LINE is separate;
procedure LIST is separate;
begin
STRIP_LEADING_SPACES_FROM_INPUT;
if STR(INPUT) = "exit" or STR(INPUT) = "EXIT" then
FINISHED := TRUE;
elsif INPUT.LEN >= 4 and (INPUT.VAL(1 .. 4) = "list" or
INPUT.VAL(1 .. 4) = "LIST") then
LIST;
elsif INPUT.LEN > 0 and INPUT.VAL(1) not in '0' .. '9' then
PUT_LINE("Unrecognized command.");
elsif INPUT.LEN > 0 then
GET_LEADING_INTEGER(LINE_NUM);
if LINE_NUM not in 1 .. MAX_LINE_NUMBER then
PUT_LINE("Illegal line number.");
else
ADD_DELETE_REPLACE_LINE;
end if;
end if;
exception
when NUMERIC_ERROR | CONSTRAINT_ERROR =>
PUT_LINE("Line number too large.");
end DO_COMMAND;

separate(LEDIT.DO_COMMAND)
procedure ADD_DELETE_REPLACE_LINE is
INP : TEXT := INPUT;
begin
if INP.LEN > 0 and INP.VAL(1) = ' ' then -- Treat "9x" like "9 x".
DELETE_FIRST_CHARACTER(INP);
end if;
TEMP := HEAD; -- Find where this number belongs in linked list.
while TEMP /= null and then TEMP.NEXT /= null and then
TEMP.NEXT.NUM <= LINE_NUM loop
if TEMP.NEXT.NUM = LINE_NUM then
TEMP.NEXT := TEMP.NEXT.NEXT; -- Delete line.
else
TEMP := TEMP.NEXT; -- Advance to next link in list.
end if;
end loop;
if INPUT.LEN > 0 then -- Add line.
TEMP.NEXT := new LINK'(LINE_NUM, INP, TEMP.NEXT);
end if;
end ADD_DELETE_REPLACE_LINE;

separate(LEDIT.DO_COMMAND)
procedure DELETE_FIRST_CHARACTER(T : in out TEXT) is
begin
T.VAL(1 .. T.LEN - 1) := T.VAL(2 .. T.LEN);
T.LEN := T.LEN - 1;
end DELETE_FIRST_CHARACTER;

separate(LEDIT.DO_COMMAND)
procedure GET_LEADING_INTEGER(N : out NATURAL) is
ANS: INTEGER := 0;
begin
while INPUT.LEN > 0 and INPUT.VAL(1) in '0' .. '9' loop
ANS := ANS*10 + CHARACTER'POS(INPUT.VAL(1)) -CHARACTER'POS('0');
DELETE_FIRST_CHARACTER(INPUT);
end loop;
N := ANS;
end GET_LEADING_INTEGER;

separate(LEDIT.DO_COMMAND)
procedure STRIP_LEADING_SPACES_FROM_INPUT is
begin
while INPUT.LEN > 0 and INPUT.VAL(1) = ' ' loop
DELETE_FIRST_CHARACTER(INPUT);
end loop;
end STRIP_LEADING_SPACES_FROM_INPUT;

separate(LEDIT.DO_COMMAND)
procedure LIST is
package IIO is new INTEGER_IO(INTEGER); use IIO;
START, FINISH : NATURAL;
VALID : BOOLEAN := TRUE;
begin

INPUT.LEN := INPUT.LEN - 4; -- Delete the name of the command.
INPUT.VAL(1 .. INPUT.LEN) := INPUT.VAL(5 .. INPUT.LEN + 4);
STRIP_LEADING_SPACES_FROM_INPUT;
if INPUT.LEN = 0 then -- For "LIST" alone, list all lines.
START := 0;
FINISH := MAX_LINE_NUMBER + 1;
else
GET_LEADING_INTEGER(START); -- Get number after "LIST".
STRIP_LEADING_SPACES_FROM_INPUT;
if INPUT.LEN = 0 then -- For "LIST n", list only line n.
FINISH := START;
elsif INPUT.VAL(1) /= '-' then -- Else "-" must follow n.
VALID := FALSE;
else
DELETE_FIRST_CHARACTER(INPUT); -- Delete the "-".
STRIP_LEADING_SPACES_FROM_INPUT;
GET_LEADING_INTEGER(FINISH); -- Get number after "-".
STRIP_LEADING_SPACES_FROM_INPUT;
if FINISH = 0 and START = 0 then -- "LIST -" isn't valid.
VALID := FALSE;
elsif FINISH = 0 then -- For "LIST n -", list n through end.
FINISH := MAX_LINE_NUMBER + 1;
end if;
VALID := VALID and INPUT.LEN = 0; -- No trailing garbage.
end if;
end if;
if not VALID then
PUT_LINE("Illegal syntax for LIST.");
else
TEMP := HEAD.NEXT; -- Skip unused link at start of linked list.
while TEMP /= null and then TEMP.NUM <= FINISH loop
if TEMP.NUM >= START then
PUT(TEMP.NUM, WIDTH => 5); -- Print line number, width 5.
PUT_LINE(' ' & STR(TEMP.LINE)); -- Print text of line.
end if;
TEMP := TEMP.NEXT; -- Get next link.
end loop;
end if;
exception
when NUMERIC_ERROR | CONSTRAINT_ERROR =>
PUT_LINE("Line number too large in LIST.");
end LIST;