%KEYEDENTRY ON PROGRAM ttexts; { The following decalrations specify the manner in which time tables are represented. They MUST be INCLUDED in any time table program.} { C O N S T D E C L A R A T I O N S } CONST minsperday = 1440; {minutes in one day } numberofstations = 7; maxstringlength=12; {the length of the longest station string PETER....} maxwait = 240; {longest time between any connexions} { T Y P E D E C L A R A T I O N S } TYPE mintime = 0..minsperday; {internal representation of all times} hourtime = packed array[1..5] of char; {external representation HH.MM } station = (edin, peter, ely, camb, lkx, lls, roy); {internal representaion of stations} stationstring = packed array[1..maxstringlength] of char; {external representation of stations} changeinfoptr = ^changeinfo; changeinfo = record { record any changes involved in a list} place :station; {at which change occurrs orllx for lls} arrt :mintime; {arrival time } wait :0..maxwait; {interval before departure} next :changeinfoptr end; journeyptr= ^journey; journey = record { the basic time table entry } dept, arrt :mintime; {time of (complete) journey} change1 :changeinfoptr; { detail of change(s) or nil} marked :boolean; next :journeyptr end; ttableptr = ^ttable; ttable = record from, dest :station; { all journeys are between these 2 places} first :journeyptr { the first journey} { journeys are in ascending order of dept} end; { C O N V E R S I O N P R O C E D U R E S } { needed between internal and external representations } { of times and of stations } PROCEDURE mintohour(mt :mintime; var ht :hourtime); VAR hours :0..24; mins :0..59; FUNCTION decdigit (d :integer) :char; { 0..9 -> '0'..'9'} BEGIN decdigit:= chr(ord('0')+d); END; BEGIN hours:=mt div 60; mins := mt mod 60; ht[1] := decdigit(hours div 10); ht[2] := decdigit(hours mod 10); ht[3] := '.'; ht[4] := decdigit(mins div 10); ht[5] := decdigit(mins mod 10); END; FUNCTION hourtomin(ht :hourtime) :mintime; VAR hours, mins :integer; ok :boolean; FUNCTION dig2 (x :integer) :boolean; { true iff ht[x] & ht[x+1] are decimal digits} FUNCTION decdigit (ch :char) : boolean; { true if ch is dec digit} BEGIN decdigit := ('0'<=ch) and (ch<='9'); END; BEGIN dig2 := decdigit( ht[x]) and decdigit( ht[x+1]); END; FUNCTION val2 (x :integer) :integer; { integer represented by ht[x] & ht[x+1] } FUNCTION decval (ch :char) :integer; BEGIN decval := ord(ch) - ord('0'); END; BEGIN val2 := decval( ht[x]) * 10 + decval(ht[x+1]); END; BEGIN { of hour to min proper !!} ok := true; { checking valid HH & MM } hours:= 0; mins := 0; if dig2(1) then hours := val2(1) else ok := false; if ht[3] <> '.' then ok:=false; if dig2 (4) then mins:= val2(4) else ok := false; if (0<=hours) and (hours<=23) and (0<=mins) and (mins<=59) then hourtomin := 60*hours+mins else ok:= false; if not ok then begin halt(ht); end; END; PROCEDURE stationtostr(st :station; var s :stationstring); BEGIN case st of edin: s := 'EDINBURGH '; peter: s := 'PETERBOROUGH'; ely: s := 'ELY '; camb: s := 'CAMBRIDGE '; lkx: s := 'LONDON(KX) '; lls: s := 'LONDON(LS) '; roy: s := 'ROYSTON '; end; END; FUNCTION strtostation(s :stationstring) :station; {This is a crude comparison which looks only at key distinguishing characters!!} VAR ok :boolean; BEGIN ok := true; if s[1]='P' then strtostation := peter else if s[1]='C' then strtostation := camb else if s[1]='R' then strtostation := roy else if s[1]='E' then if s[2]='D' then strtostation := edin else if s[2]='L' then strtostation := ely else ok := false else if s[1] = 'L' then if s[8]='K' then strtostation := lkx else if s[8]='L' then strtostation := lls else ok := false else ok := false; if not ok then begin halt('**Unknown station**'); end; END; { of str to station } { I N P U T A N D O U T P U T P R O C E D U R E S } { i.e. they read or print one time table } PROCEDURE readtt(var inp :text; var tt :ttableptr); {Program halted if any input errors detected!} CONST terminator='*'; { at the left margin when journey expected} VAR last :journeyptr; { guides appending new journeys to partial list} PROCEDURE skipblanklines; BEGIN while eoln(inp) and not eof(inp) do readln(inp); if eof(inp) then halt('** file ended **'); END; PROCEDURE skipspaces; { only within a line } BEGIN while (inp^=' ') and not eoln(inp) do get(inp); END; PROCEDURE readstation( var st :station); VAR str :stationstring; n :0..maxstringlength; BEGIN skipspaces; n:=0; repeat n:=n+1; read(inp, str[n]); until (inp^=' ') or (n=maxstringlength); if inp^<>' ' then str[maxstringlength] :='?'; {force conversion error} while n< maxstringlength do begin { pad out with spaces} n:=n+1; str[n]:=' '; end; st := strtostation(str); END; FUNCTION getjourney :journeyptr; { reads a departure & arrival just} VAR jny :journeyptr; PROCEDURE readtime( var mt :mintime); VAR ht :hourtime; n :1..5; BEGIN skipspaces; for n:=1 to 5 do read(inp, ht[n]); mt := hourtomin(ht); { conversion error if bad input } END; BEGIN { getting a journey} new(jny); with jny^ do begin readtime(dept); readtime(arrt); marked := false; change1 := nil; next := nil; {not strictly necessary} end; readln(inp); { done with a dept & arrt} getjourney := jny; END; BEGIN { of read tt proper} new(tt); with tt^ do begin skipblanklines; readstation(from); readstation(dest); readln(inp); { done with that line} first := getjourney; last:=first; while inp^ <> terminator do begin last^.next := getjourney; last := last^.next; { newest one is latest} end; readln(inp); { get past terminating line} last^.next := nil; { mark the end of the list of journeys} end; {with tt} END; {of read tt!!!!} PROCEDURE writett(var out :text; tt :ttableptr); { fairly simple format, assumes max of 2 changes per journey} VAR froms, tos :stationstring; deps, arrs :hourtime; {values ready for writing} jny :journeyptr; PROCEDURE printchanges(change :changeinfoptr); VAR str :stationstring; ht :hourtime; BEGIN while change<>nil do begin with change^ do begin write(out, ' '); stationtostr(place,str); write(out, str); write(out, ' '); mintohour(arrt,ht); write(out, ht,':'); mintohour(wait,ht); write(out, ht); end; {with} change:=change^.next; end; { while} END; BEGIN with tt^ do begin writeln(out, ' TIME TABLE'); writeln(out, ' From To'); stationtostr(from,froms); stationtostr(dest,tos); writeln(out, froms, ' ':3, tos); writeln(out); writeln(out, 'Depart Arrive Changes(arrt:delay(mins))'); jny:=first; while jny <>nil do begin with jny^ do begin mintohour(dept,deps); mintohour(arrt,arrs); write(out, deps, ' ':4, arrs); if marked then write(out, '**** ') else write(out, ' '); printchanges(change1); writeln(out); end; {with jny^ } jny := jny^.next; end; writeln(out); writeln(out); writeln(out); end; {with tt^} END; { of printing a time table!!!!} BEGIN END.