PROGRAM RECIPE;
(*
** PROGRAM TITLE THE RECIPE SYSTEM
** Version PAS-1.2 translated from
** the BASIC version into Pascal.
**
** WRITTEN BY: Ray Penley
** DATE WRITTEN: 23 FEB 1980 / last modified: 28 FEB 80
** WRITTEN FOR: Computer hobbyists
**
** PROGRAM SUMMARY:
**
** The recipe system stores recipes and retrives them
** by means of a numeric key that represents the foods
** used in the meal. Foods are divided into four
** categories according to their nutritional value.
**
** INPUT AND OUTPUT FILES:
** RCPDAT.XXX and RCPDAT.YYY
** - the DATA and the backup files
** RECIPE.MST - the statistics file
** DUMMY.$$$ - see Procedure InputRecipe for use.
**
** ORIGINAL PROGRAM:
** T.G.LEWIS, 'THE MIND APPLIANCE'
** HAYDEN BOOK COMPANY
**)
CONST
str_len = 73; (* max length of all strings + one *)
EOS = '|'; (* End of String marker *)
Master = 'RECIPE.MST';
Tab20 = 20 ;
Tab15 = 15 ;
on = true;
off = false;
TYPE
string = packed array[1..str_len] of char;
string2 = packed array[1..2] of char;
string14 = packed array[1..14] of char;
datatype = record
MR, (* MaxRecords *)
CR : integer; (* Curr_Rcds *)
F1, (* current_ID *)
F2, (* backup_ID *)
date : string14(* last_update *)
end;
VAR
a_RAY : packed array[1..5] of string;
data :datatype;
Bell,
command :char;
Last_update :string14;
Curr_Rcds, (* No. of current active records *)
Hash, (* Computed Index value of Recipe *)
Last,
MaxRecords, (* Maximum records allowed *)
TTY (* width of terminal/CRT *)
:integer;
End_of_File, (* End of File flag *)
End_of_Text, (* End of Text flag *)
adding_recipies, (* flag = true when adding recipies *)
switch, error,
done, yflag : boolean;
(* FID. File Identifier *)
current_ID, (* Current file ID *)
backup_ID :string14; (* Back up file ID *)
(*----------------------------------------------*)
(* DISK I/O *)
(*----------------------------------------------*)
Procedure OPEN_MASTER;
begin
(* OPEN file RECIPE.MST for READ assign stats *)
RESET(master, stats);
READ(stats, data );
with data do begin
MaxRecords := MR;
Curr_Rcds := CR;
current_ID := F1;
backup_ID := F2;
last_update := date
end(* with *)
end;
Procedure UPDATE_MASTER;
begin
(* OPEN file RECIPE.MST for WRITE assign stats *)
REWRITE(master, stats);
with data do begin
MR := MaxRecords;
CR := Curr_Rcds;
F1 := current_ID ;
F2 := backup_ID ;
date := last_update
end(* with *);
WRITE(stats, data )
end;
Procedure GETLINE((* VAR fx : TEXT; *)
VAR INBUFF : string );
(**
Returns:
End_of_Text = true if attempt is made to exceed
the input buffer length.
End_of_File = true if EOF
INBUFF = input string
***)
VAR
CH : CHAR;
ix, length : integer;
begin
length := 0;
End_of_Text := FALSE;
WHILE NOT EOF(fa) AND (CH <> EOS) DO
begin
If length < str_len then
begin
READ(fa, CH );
length := length +1;
INBUFF [length] := CH
end(* If *)
ELSE (*** error ***)
begin
error := true;
End_of_Text := TRUE
end(* else *)
end(* WHILE *);
If length >= last then
last:=length
Else
REPEAT
INBUFF[ last ] := EOS;
last := last -1
UNTIL last=length;
(*** !!! SET FLAG !!! ***)
End_of_File := EOF(fa);
end(*---of GetLine---*);
Procedure PUTLINE((* VAR fx : TEXT; *)
VAR this :string );
VAR
CH : char;
pos : integer;
begin
pos := 0;
REPEAT
pos := pos +1;
CH := this[ pos ];
If CH <> EOS then Write(fb, CH)
UNTIL (CH = EOS) OR (pos = str_len);
Write(fb, EOS ) (* Mark the End of String *)
end(*---of PUTLINE---*);
Procedure PUT_RECORD((* VAR fx : TEXT; *)
VAR Index : integer );
VAR
jx : integer;
begin
Writeln(fb, Index:5);
For jx:=1 to 5 do
PUTLINE((* fb, *) a_RAY[jx] );
end(*---of PUT_RECORD---*);
Procedure GET_RECORD((* VAR fx : TEXT; *)
VAR Index : integer );
VAR
JJ : integer;
begin
READLN (fa, Index);
FOR JJ := 1 to 5 DO
GETLINE((* fa, *) a_RAY[JJ] );
end(*---of GET_RECORD---*);
Procedure PRINT((* VAR fx : TEXT; *)
VAR this : string );
(* Print the string 'this' until EOS *)
VAR
CH : CHAR;
pos : integer;
begin
pos := 0;
REPEAT
pos := pos +1;
CH := this[ pos ];
If CH <> EOS then Write(CH)
UNTIL (CH = EOS) OR (pos = str_len);
Writeln
end(*---of PRINT---*);
Procedure SCAN((* VAR fx : TEXT; *)
VAR INBUFF : String ;
count : integer );
(* SCAN Version 1.1 *
Enter with:
count = maximum # chars allowed.
Returns:
INBUFF = input string
EOS = End of string marker
Flags:
error = false - good input
= true if buffer length exceeded
If invalid ASCII char detected.
Valid Alphanumeric chars are:
between the space - CHR(32) to the tilde - CHR(126)
GLOBAL
str_len = << default for string length >>
EOS = '|';
error : boolean
string : packed array[1..str_len] of char
*)
VAR
InChar : char;
length : integer;
begin
error := false;
For length:=1 to str_len do INBUFF[ length ]:= EOS;
length := 0;
REPEAT
If length < count then(* get valid inputs *)
begin
READ( InChar );
If InChar IN [' ' .. '~'] then
begin (* Increment length and store InChar *)
length := length +1;
INBUFF[length] := InChar
end(* if *)
ELSE
begin
Writeln(' Alphanumerics only -');
error:=TRUE
end(* else *)
end(* If *)
ELSE (* ERROR *)
begin (* RESET EndOfLine (EOLN) *)
READLN(INBUFF[count]);
Writeln('Maximum of', count:4, ' characters please!');
error:=TRUE
end(* ELSE *)
UNTIL EOLN(INPUT) OR error;
end(*---of SCAN11---*);
Procedure QUIRY;
(* YES/NO INPUT MODULE
Returns:
yflag =TRUE FOR ''Y' or 'y' INPUT
=FALSE FOR 'N' or 'n' INPUT
GLOBAL
yflag : boolean;
*)
VAR
Ans : char;
error : boolean;
begin
error := true;
yflag := false;
REPEAT
error := false;
READ(Ans);
If (Ans = 'Y') OR (Ans = 'y') then
yflag := true
Else
If (Ans <> 'N') AND (Ans <> 'n') then
begin
Writeln(BELL, 'Please answer ''Y'' or ''N'' ');
error := true
end
Until NOT error
end(*---of QUIRY---*);
Procedure SKIP(L1 : integer);
VAR ix : integer;
begin
FOR ix:=1 to L1 do Writeln;
end;
Procedure PAUSE;
VAR dummy : char;
begin
skip(4);
Write('Type return to continue:');
READ(dummy);
end;
Procedure BREAK;
begin
CLEAR;
SKIP(5);
end;
Procedure Pstring(picture : string2; count : integer );
VAR ix : integer;
begin
FOR ix:=1 to count DO Write( picture );
Writeln;
end(*---of Pstring---*);
Procedure ShowRecipe;
VAR JJ : integer;
begin
FOR JJ := 1 to 5 DO
PRINT(a_RAY[JJ]) ;
Writeln
end(*--of ShowRecipe--*);
Procedure InputFeatures(VAR I : integer);
(******************************************
* Input Features of Recipe *
*******************************************)
(*
RETURNS:
Hash value computed for various choices
**)
CONST
Msg1 = 'None of these' ;
VAR
F, D, V, P :integer;
(******************************************
* Compute the index value by assigning *
* a weight to each digit in the set. *
*******************************************)
I := 252*F + 36*P + 6*D + V -295
end;
Procedure InputRecipe;
LABEL 2399; (*---EXIT---*)
VAR
state : (absent, done, adding) ;
ix, jx : integer;
temp : string14;
Line : string;
Procedure Correct;
begin
REPEAT
BREAK;
Write(bell);
Writeln(' ':(TTY DIV 2) -10, 'HERE IS YOUR RECIPE');
Writeln;
ShowRecipe;
Writeln;
Writeln('Are there any corrections to be made ');
QUIRY;
If yflag then
begin
BREAK;
Writeln('Enter <cr> return if correct or Reenter the line');
Writeln;
For ix:=1 to 5 do
begin
PRINT(a_RAY[ix]);
SCAN(Line, str_len -1);
If Line[1] <> ' ' then a_RAY[ix] := Line
end
end(* If *)
Until yflag=false;
end(*---of Correct---*);
Procedure QUEST;
begin
Pause;
BREAK;
Write('Do you want to ADD recipies? ' );
QUIRY;
CLEAR;
end;
begin(*---InputRecipe---*)
QUEST;
If yflag=false then (* EXIT *) goto 2399;
adding_recipies := true ;
state := adding ;
(* OPEN file backup_ID for WRITE assign fb *)
REWRITE(backup_ID, fb);
(* OPEN file current_ID for READ assign fa *)
RESET(current_ID, fa);
If NOT EOF(fa) then
begin(* COPY current to back_up *)
ix := 0 ;
While ix < Curr_Rcds do
begin
ix := ix +1;
GET_RECORD((* fa, *) HASH);
PUT_RECORD((* fb, *) HASH);
end(* while *)
end(* IF *);
REPEAT
If Curr_Rcds > MaxRecords then
state := done
Else(* we can add more date *)
begin
Writeln( 'Identify Recipe with features. First ');
InputFeatures(HASH);
BREAK;
Writeln( 'Now Enter 5 lines of the recipe');
Writeln;
For jx := 1 to 5 DO
begin
Write('>');
SCAN( a_RAY[jx], str_len -1 );
end;(* For *)
Correct(* if required *);
Curr_Rcds := Curr_Rcds +1;
PUT_RECORD((* fb, *) HASH);
QUEST;
If yflag=false then state := done;
end;(* else *)
UNTIL state<>adding;
(*---------------------------------------*
* *** trick *** *
* close previous file ID assigned *
* FCB fb and fix CP/M directory entry *
*---------------------------------------*)
REWRITE('DUMMY.$$$', fb);
(* SWAP file ID`s *)
(* Back Up file is now the Current file *)
temp := backup_ID;
backup_ID := current_ID;
current_ID := temp;
Procedure File_Scan ;
(*
GLOBAL
MaxRecords = maximum allowed records
Curr_Rcds = # of recipes in file
*)
VAR
state : (absent, found, searching) ;
ix, index : integer;
Procedure DUMP;
(*********************************
* OUTPUT all Recipes from file *
**********************************)
begin
REPEAT
If ix > Curr_Rcds then
state := absent
Else
begin
ix := ix +1;
GET_RECORD((* fa, *) HASH);
Display_One(HASH);
Pause
end(* else *)
UNTIL state<>searching;
end(*--of DUMP--*);
Procedure FIND;
(*************************************
* Lookup recipes from file *
**************************************)
VAR
Index : integer;
begin
CLEAR;
InputFeatures(Index);
REPEAT
If ix > Curr_Rcds then
state := absent
Else
begin
GET_RECORD((* fa, *) HASH);
If HASH=Index then
state := found
Else
ix := ix +1
end(* else *);
Until state<>searching;
If state=found then
begin
CLEAR;
Display_One(HASH);
end;
end(*--of Lookup--*);
begin(*---File_Scan---*)
Pause;
state := absent;
If adding_recipies then
(* read new stats *) OPEN_MASTER;
(* OPEN file current_ID for READ assign fa *)
RESET(current_ID, fa);
If NOT EOF(fa) then
begin
state := searching ;
ix := 1 ;
If Curr_rcds=0 then
state := absent
Else
begin
CASE command of
'O', 'o': DUMP;
'F', 'f': FIND
end(* case *)
end(* else *)
end(* IF *);
If state=absent then
begin
BREAK;
Writeln('That''s all the Recipes on File');
end;
Pause;
end(*---of File_Scan---*);
Procedure INIT1;
(* byte count/record = (chars/line + overhead/line) times No. of lines *)
begin
BELL := CHR(7) ;
TTY := 72 ;
last := str_len ;
MaxRecords := 50 ;(* 360 times 50 = 18000 bytes *)
Curr_Rcds := 0 ;
Last_Update := 'YY/MM/DD ';
current_ID := 'RCPDAT.XXX ';
backup_ID := 'RCPDAT.YYY ';
adding_recipies := false
end;
Procedure INIT2;
begin
(* OPEN file `RECIPE.MST` for READ assign stats *)
RESET(master, stats);
If EOF(stats) then(* not found *)
(* OPEN file `RECIPE.MST` for WRITE assign stats *)
UPDATE_MASTER
Else begin(* READ in data record *)
READ(stats, data );
with data do begin
MaxRecords := MR;
Curr_Rcds := CR;
current_ID := F1;
backup_ID := F2;
last_update := date
end(* with *)
end;
SKIP(5);
Writeln('Last update of Recipe data file was ', last_update);
Writeln('File currently consists of ', Curr_Rcds:4, ' Recipies');
Writeln;
Write('Please enter todays date <YY/MM/DD> ');
READLN(last_update)
end;
(*----------------------------------------------*
* MAIN PROGRAM *
*----------------------------------------------*)
BEGIN
INIT1;
CLEAR;
Pstring( '**', (TTY DIV 2));
Writeln;
Writeln( ' ':22, 'The Recipe System');
Writeln;
Pstring( '**', (TTY DIV 2));
INIT2;
done := false;
WHILE NOT(done) DO
begin
CLEAR;
Pstring( '**', (TTY DIV 2));
skip(3);
Writeln( ' ':Tab15, 'Select One of the following:');
Writeln;
Writeln( ' ':Tab20, 'I(nput Recipes');
Writeln( ' ':Tab20, 'O(utput all Recipes');
Writeln( ' ':Tab20, 'F(ind a Recipe');
Writeln( ' ':Tab20, 'S(top');
switch := on;
WHILE switch(* is on *
) do
begin
switch := off;
Writeln;
Write(' ':(Tab15), 'Enter choice ' );
READ( command );
CASE command of
'I', 'i': InputRecipe;
'O', 'o',
'F', 'f': File_Scan;
'S', 's': done := true;
ELSE: begin
Write(BELL);
switch := on
end
end(* case *)
end(* while switch is on *)
end(* while not done *)
end(*---of Program Recipe---*).