(* ** PROGRAM TITLE: AUTHOR ** ** WRITTEN BY: Raymond E. Penley ** DATE WRITTEN: 24 June 1980 ** ** WRITTEN FOR: Pascal/Z Users Group ** ** Original program ** A General Purpose Keyword In Context Program ** by: Randy Reitz ** 26 Maple St ** Chatham Township, N.J. 07928 ** June 1980 ** ** DONATED TO PASCAL/Z USERS GROUP, July 1980 *) Program AUTHOR; label 9999; { abort } const Program_title = 'AUTHOR'; Sort_message = 'Sort by 1) TITLE, 2) AUTHOR, or 3) DATE? '; default = 80 ; dflt_str_len = default; { default length for a string } fid_length = 14; {max file name length} line_len = default; n = 10; title$field$width = 56; author$field$width = 14; date$field$width = 8; Pdelim = '^'; { the "P" delimeter } Sdelim = '/'; { the "S" delimeter } space = ' '; screen_lines = 24; {# of viewing lines on consle device } StrMax = 255; type dfltstr = STRING dflt_str_len; fid = STRING FID_LENGTH; INDEXES = array[1..n] of integer; str0 = STRING 0 ; str1 = STRING 1; str255 = STRING Strmax ; Mstring = STRING Strmax; links = ^entry; {}stuffing = record title, author, date : dfltstr end; entry = record {} stuff: stuffing; Rlink, Llink: links end; var bad_lines : integer; { count of # of bad lines } bell : char; cix : char; error : boolean; High, LINE, Low : dfltstr; i : integer; { global index } in_file : fid; num : integer; { occurrences of "P"/"S" delimeters } root : links; Ploc, { location of "P" delimeters } Sloc : INDEXES; { location of "S" delimeters } sort : 0..n; size, { size of current file } this_line : integer; { current line counter } termination : boolean; { Program termination flag } wrk1 : text; { the input file } (*********************************************) (*---This is how we get string functions in Pascal/Z---*) Function length(x: str255): integer; external; Function index(x,y: str255): integer; external; Procedure setlength(var x: str0; y: integer); external; Procedure KEYIN(VAR cix: char); external; (*---Direct Keyboard onput of a single char---*) Procedure COPY( { TO } VAR dest : dfltstr; { FROM } THIS : MSTRING ; {STARTING AT} POSN : INTEGER ; {# OF CHARS } LEN : INTEGER ) ; { COPY(NEW_NAME, NBUF, NAME_ADDR, NAME_LEN); } { COPY(A_STRING, A_STRING, 5, 5); } { GLOBAL default = default line length; dfltstr = STRING default; StrMax = 255; MSTRING = STRING StrMax; } LABEL 9; VAR ix : 1..StrMax; begin SETLENGTH(dest,0); {length returned string=0} If (len + posn) > default then{EXIT}goto 9; IF ((len+posn-1) <= LENGTH(this)) and (len > 0) and (posn > 0) then FOR ix:=1 to len do APPEND(dest, this[posn+ix-1]); 9: {Any error returns dest with a length of ZERO.} End{of COPY}; PROCEDURE CONCAT({New_String} VAR C : dfltstr ; {Arg1_str } A : Mstring ; {Arg2_str } B : Mstring ); { CONCAT(New_string, Arg1, Arg2); } { An error returns length of new_string=0 } { GLOBAL default = default line length; dfltstr = STRING default; StrMax = 255; Mstring = STRING StrMax; } var ix : 1..StrMax; begin SETLENGTH(C,0); If (LENGTH(A) + LENGTH(B)) <= default then begin APPEND(C,A); APPEND(C,B); end; End{of CONCAT}; Function UCASE(ch: char): char; begin If ch IN ['a'..'z'] then UCASE := chr(ord(ch) - 32) Else UCASE := ch end; Procedure FINDR( PAT : str1; VAR S : dfltstr; VAR where : INDEXES; VAR cnt : integer ); var ix, cum : integer; temp : dfltstr; begin cum := 0; cnt := 0; where[1] := 0; Repeat COPY(temp, S, cum+1, length(S)-cum); ix := INDEX(temp, pat); cum := cum + ix; If (ix>0) then begin S[cum] := space; cnt := cnt + 1; where[cnt] := cum; where[cnt+1] := 0; end; Until (ix=0) OR (cum=length(S)); end{of FINDR}; Procedure ENTER(newx: links); var this, next: links; Newkey, Thiskey: dfltstr; begin If (root=nil) then root := newx Else begin next := root; Repeat this := next; CASE sort of 1: begin Newkey := newx^.stuff.title; Thiskey := this^.stuff.title; end; 2: begin Newkey := newx^.stuff.author; Thiskey := this^.stuff.author; end; 3: begin Newkey := newx^.stuff.date; Thiskey := this^.stuff.date; end End{case}; If Newkey <= Thiskey then next := this^.Llink Else next := this^.Rlink; Until next=nil; If Newkey <= Thiskey then this^.Llink := newx Else this^.Rlink := newx; end End{of Enter}; Procedure PAUSE; var dummy: char; begin this_line := 0; write('Press return to continue'); readln(dummy); End{of Pause}; Procedure TRAVERSE(ptr: links); var thiskey: dfltstr; begin CASE sort of 1: Thiskey := ptr^.stuff.title; 2: Thiskey := ptr^.stuff.author; 3: Thiskey := ptr^.stuff.date End{case}; If (ptr^.Llink<>nil) AND (Thiskey>=low) then TRAVERSE(ptr^.Llink); {}If (thiskey >= low) AND (thiskey <= high) then begin{ Write a line } With ptr^.stuff do begin CASE sort of 1: begin { TITLE || AUTHOR || DATE } write( title : title$field$width ); write( author : author$field$width ); writeln( date : date$field$width ); end; 2: begin { AUTHOR || TITLE || DATE } write( author : author$field$width ); write( title : title$field$width ); writeln( date : date$field$width ); end; 3: begin { DATE || TITLE || AUTHOR } write( date : date$field$width ); write( title : title$field$width ); writeln( author : author$field$width ); end End{case}; end{with}; this_line := this_line + 1; If (this_line*6+1 > screen_lines) then PAUSE; end{ Write a line }; {}If (ptr^.Rlink<>nil) AND (Thiskey <= high) then TRAVERSE(ptr^.Rlink); End{of TRAVERSE}; Procedure CREATIT; { GLOBAL I : integer; } var p: links; temp1, newtitle, newauthor, newdate : dfltstr; begin NEW(p); CASE sort of 1: begin {} COPY(newtitle, LINE, ploc[I]+1, sloc[ 1 ]-ploc[I] ); COPY(temp1, LINE, 1, ploc[I] ); APPEND(newtitle,temp1); end; 2,3:If (LINE[1]=space) then {} COPY(newtitle, LINE, 2, sloc[1]-1) Else {} COPY(newtitle, LINE, 1, sloc[1]) End{case}; {} COPY(newauthor, LINE, sloc[1]+1, (sloc[2]-sloc[1])-1); If (length(newauthor) > author$field$width) then setlength(newauthor,author$field$width); newdate := '19'; COPY(temp1, LINE, sloc[2]+1, length(LINE)-sloc[2] ); APPEND(newdate, temp1); {} newtitle[1] := Ucase(newtitle[1]); {} newauthor[1] := Ucase(newauthor[1]); {} newdate[1] := Ucase(newdate[1]); With p^.stuff do begin title := newtitle; author := newauthor; date := newdate end{with}; p^.Llink := nil; p^.Rlink := nil; ENTER(p); end{of CREATIT}; Procedure Read_Data_File; begin Readln(wrk1,LINE); while not EOF(wrk1) do begin FINDR(Sdelim, LINE, sloc, num); error := (num<>2); FINDR(Pdelim, LINE, ploc, num); error := (error OR (num=0)); If sort IN [2,3] then num := 1; If not error then For i:=1 to num do begin CREATIT; size := SUCC(size) end Else begin writeln(bell,'***BAD LINE***',bell); bad_lines := bad_lines + 1; writeln(LINE) end; READLN(wrk1,LINE) end{while}; End{of Read_Data_File}; Procedure GETID( MESSAGE : dfltstr; VAR ID: FID ); { GLOBAL FID_LENGTH = 14; dfltstr = STRING dflt_str_len; fid = STRING FID_LENGTH; } const space = ' '; begin setlength(ID,0); writeln; write(message); READLN(ID); while length(ID)', in_file); RESET(in_file,wrk1); end{of initialize}; Begin{ of Program KeyWordInContext } Initialize; If EOF(wrk1) then begin writeln('File ', in_file, 'not found'); {EXIT}goto 9999; end; REPEAT writeln; write(Sort_messge); KEYIN(cix);Writeln(cix); sort := ORD(cix) - ORD('0'); UNTIL sort IN [1,2,3]; Read_Data_File; writeln('Sort complete with ', size:3, ' records entered.'); If bad_lines > 0 then writeln('There are ', bad_lines:3, ' bad lines in the data file.'); writeln; writeln('Enter range for output.'); Termination := false; REPEAT setlength(low,0); setlength(high,0); {} writeln; write('Low string ( to quit) ->'); readln(low); If not termination then begin{ low string } low[1] := UCASE(low[1]); write('High string ->'); readln(high); If not termination then begin{ high string } high[1] := UCASE(high[1]); this_line := 0; CLEAR; TRAVERSE(root) end{ high string } end{ low string } UNTIL Termination; 9999:{ file not found } End{ of Program AUTHOR }. .