(************************************************ ** PROGRAM TITLE: Name and Address ** Version 3.0 ** ** WRITTEN BY: Raymond E. Penley ** DATE WRITTEN: 26 June 1980 ** ** ORIGINAL PROGRAM: ** A General Purpose Permuted Keyword Index Program ** Written by: Randy Reitz ** 26 Maple St ** Chatham Township, N.J. 07928 ** ** Date written: June 1980 ** ** WRITTEN FOR-S100 Microsystems Magazine ** ** Donated to PASCAL/Z USERS GROUP, july 1980 ** ***********************************************) Program NameAndAddress; label 9999; { abort } const Program_title = 'NAME AND ADDRESS'; Sort_message = 'Sort by 1) Name, 2) Address, or 3) Zip Code? '; default = 80 ; dflt_str_len = default; { default length for a string } dflt_margin = 1; { Left margin default } fid_length = 14; {max file name length} line_len = default; n = 10; {Maximun # of delimeters} name$field$width = 20; { Name line width } address$field$width = 40; { Address line width } Zip$field$width = 5; { ZIP Code line width} 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 name, { Name line } address, { Address line } Zip : dfltstr { ZIP Code line } 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; { CP/M File Identifier } margin, { left margin } num : integer; { occurrences of "P"/"S" delimeters } root : links; Ploc, { location of "P" delimeters } Sloc : INDEXES; { location of "S" delimeters } sort : 0..255; 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 { NAME Key } Newkey := newx^.stuff.name; Thiskey := this^.stuff.name; end; 2: begin { ADDRESS Key } Newkey := newx^.stuff.address; Thiskey := this^.stuff.address; end; 3: begin { ZIP Code Key } Newkey := newx^.stuff.Zip; Thiskey := this^.stuff.Zip; 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); { ---Address format--- Name line 1 Address line 2 Zip Code line 3 line 4 } var thiskey: dfltstr; begin CASE sort of 1: Thiskey := ptr^.stuff.name; { Name } 2: Thiskey := ptr^.stuff.address; { Address } 3: Thiskey := ptr^.stuff.Zip { Zip Code } End{case}; If (ptr^.Llink<>nil) AND (Thiskey>=low) then TRAVERSE(ptr^.Llink); If (thiskey >= low) AND (thiskey <= high) then begin{ Write an address } With ptr^.stuff do begin writeln(' ':margin, name : name$field$width ); writeln(' ':margin, address : address$field$width ); writeln(' ':margin, Zip : Zip$field$width ); writeln; end{with}; this_line := this_line + 1; If (this_line*6)+1 > screen_lines then PAUSE; end{ Write an address }; If (ptr^.Rlink<>nil) AND (Thiskey <= high) then TRAVERSE(ptr^.Rlink); End{of TRAVERSE}; Procedure CREATIT; { GLOBAL I : integer; } var p: links; temp1, newname, newaddress, newZip : dfltstr; begin NEW(p); CASE sort of 1: begin COPY(newname, LINE, ploc[I]+1, sloc[ 1 ]-ploc[I] ); COPY(temp1, LINE, 1, ploc[I] ); APPEND(newname,temp1); end; 2,3: If (LINE[1]=space) then COPY(newname, LINE, 2, sloc[1]-1) Else COPY(newname, LINE, 1, sloc[1]) End{case}; COPY(newaddress, LINE, sloc[1]+1, (sloc[2]-sloc[1])-1); If (length(newaddress) > address$field$width) then setlength(newaddress,address$field$width); COPY(newZip, LINE, sloc[2]+1, length(LINE)-sloc[2] ); newname[1] := Ucase(newname[1]); newaddress[1] := Ucase(newaddress[1]); newZip[1] := Ucase(newZip[1]); With p^.stuff do begin name := newname; { Name line } address := newaddress; { Address line } Zip := newZip { ZIP Code } end{with}; p^.Llink := nil; p^.Rlink := nil; ENTER(p); end{of CREATIT}; 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 In the Data File---} 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}; {--- Read is complete ---} {---Announce no of records found---} 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; write('Enter left margin? '); READLN(margin); 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 Name and Address }. .