{ 22/7/87 16:46 persons} %include "sm:consts.inc" %include "sm:formats.inc" %include "sm:utils.inc" ! This file contains the procedures for handling a file of names and ! addresses and other details. %constreal linewidth=3.341 ;! Labelwidth-2*leftmargin. %recordformat sourcef(%record(sourcef)%name next,prev, %record(personf)%name atid) %recordformat sourcelistf(%record(sourcef)%name head,tail) %ownrecord(line80listf) departmentlist=0 %externalrecord(personlistf) dests1 %constinteger hhmax=55 %conststring(255)%array hh(0:hhmax)= %c "This requires an address, line by line, ending with an asterisk(*) on a line by itself.", { 0} "This requires the name of the addressee, complete with style, initials, degrees and honours. File-names may be included in the form @File. They will be expanded when the list has been ended with '*' on a line by itself.", { 1} "This wants a copy-list of IDs or names, separated by semi-colons (spilling over several lines), ending with an asterisk(*) on a line by itself. This list will be printed in the letters.", { 2} "This requires the name of a file containing control data to run the program for testing.", { 3} "This requires the form of name to be used after ""Dear"".", { 4} "This requires the degrees and honours of the person, in the usual form to follow the name.", { 5} "This requires the name of the Department. If the name given is CS then the Department is filled in as Computer Science, the KB address and phone- number are supplied and so is the University's telex number.", { 6} "This requires the senders extension on from 667-1081.", { 7} "This requires any comments or other unspecified information.", { 8} "This requires the forenames.", { 9} "This requires the name and any other information about the sender. It may spill over several lines. It must end with an asterisk (*) on a line by itself.", {10} "This requires an address in the usual form, ending with an asterisk(*) on a line by itself.", {11} "This requires the home telephone number.", {12} "This requires an identifier, such as the Vax user-name e.g. KBD.", {13} "This requires the interests of the person, one to a line. The sequence must be ended with an asterisk(*) on a line by itself.", {14} "This requires a file-name for the body of the letter. If no file of the name already exists a new file will be created, otherwise a new version will be made. The new version can be put into a new file by presenting the form:- "" oldfile/newfile.""", {15} "This requires the sender's reference for this letter.", {16} "This requires the name of a file containing details of addressees, as though they were being presented at the console.", {17} "This requires the persons office address in the usual form, terminated by an asterisk(*) on a line by itself.", {18} "This requires the telephone number of the person's office.", {19} "This requires the room-number of the person's office in the building in which his Department is situated.", {20} "This requires the style that precedes the person's name.", {21} "This requires the person's surname.", {22} "This requires the person's telex number.", {23} "This requires a list identifying the people who are to receive copies of the memorandum. The list must consist of IDs or names, separated by semi-colons. The list may spill over several lines. It must end with an asterisk(*) on a line by itself.", {24} "This requires the reference of the letter to which this is a reply.", {25} "This requires the dedication to follow ""Yours"" at the end of the letter.", {26} "This requires a file-name for the body of the memorandum. If no file of the name already exists a new file will be created, otherwise a new version will be made. The new version can be put into a new file by presenting the form:- "" oldfile/newfile.""", {27} "This requires yes/no. Yes signifies that copies are to be sent to only those people whose IDs or names have been found in name-file.", {28} "You may change any item other than the permanent heading by answering ""yes"" to the next prompt and ""yes"" to the prompts for those items you wish to change and ""no"" to the others.", {29} "You may decide not to send the documents to the laser-printer at this late stage. If you answer ""yes"" they will be sent.", {30} "This requires the name or the ID of the originator of the memorandum.", {31} " The names, addresses, IDs etc that have just been typed will now be sorted into the name-list. If the answer to this prompt is no, the list will be closed, if the answer is yes, you will be promped for more information about people.", {32} "This skips until it finds ""@"" on a line by itself." {33}, "This prints whatever you put on this line (apart from ""*"").", {34} "This will produce a file copy of the letter.", {35} "This requires the intials of the person.", {36} "This expects a list of recipients, each with the name to be used for the label, the address, the name to be used after 'Dear' and the form to be used after 'Yours'. The list may be ended by typing '.end' instead of any item.", {37} "This expects yes, no or .end as the answer.", {38} "This expects the name of a file which contains the letter head ended by an asterisk(*) on a line by itself. The default is [sm.head]department.lay (b::office:department on APM)", {39} "This expects the heading for the top of the letter, with Layout directives, ending at the first asterisk(*).", {40} "This expects the name of a file of names and addresses.", {41} "Do you wish to delete all the output so far created?", {42} "This requires the name of an input file of records. The result will be put into the same file unless an output file is named.", {43} "This wants a copy-list of IDs or names, separated by semi-colons (spilling over several lines), ending with an asterisk(*) on a line by itself. This list will not be printed in the letters.", {44} "This requires the name of the firm with which this person is associated.",{45} "This requires an answer yes, no or .end, the latter stopping the program.",{46} "This is for your electronic mail address in the UK form, e.g. sm@uk.ac.edinburgh.ecsvax", {47} "This wants an answer yes or no. Yes will lead to the file of names and addresses for labels being sent to the laser printer and deleted.", {48} "This wants an answer yes or no. Yes will lead to the file of names and addresses for labels being sent to the laser printer and deleted.", {49} "This wants the name of the sender and his description, to be printed beneath his signature.", {50} "This wants an answer yes or no. Yes wil lead to a file copy being printed.", {51} "This wants an answer yes or no. Yes will lead to a file of labels being created.", {52} "Type the number or name of the item you want to change, or 0 to create letters.Type .end to abandon the program.", {53} ""(*) %ownrecord(line40listf) line40list=0 %ownrecord(line80listf) namelist=0 %externalstring(15)%array prt(0:hhmax)= %c "Address: ", { 0} "Addressee: ", { 1} "Cc: ", { 2} "Datafile: ", { 3} "Dear ", { 4} "Degrees: ", { 5} "Department: ", { 6} "Extension: ", { 7} "Extra: ", { 8} "Forenames: ", { 9} "From: ", {10} {For letters} "Home address: ", {11} "Home phone: ", {12} "Id: ", {13} "Interests: ", {14} "Letter-file: ", {15} "My reference: ", {16} "Addressee-file:", {17} "Office address:", {18} "Office phone: ", {19} "Room: ", {20} "Style: ", {21} "Surname: ", {22} "Telex: ", {23} "To: ", {24} "Your reference:", {25} "Yours ", {26} "Memo-file: ", {27} "Selective? ", {28} "Changes? ", {29} "Print letters? ", {30} "From: ", {31} {For memo} "More people? ", {32} "Skip to @: ", {33} "Enclosure: ", {34} "File copy? ", {35} "Initials: ", {36} "Recipients: ", {37} "More recipients", {38} "Heading-file: ", {39} "Heading: ", {40} "Address-file: ", {41} "Delete all? ", {42} "Input/output: ", {43} "Bcc: ", {44} "Firm: ", {45} "Delete? ", {46} "Emailaddr: ", {47} "Print labels? ", {48} "Print memos? ", {49} "Sent by: ", {50} "File copy? ", {51} "Create labels? ", {52} "Item: ", {53} "Printer: ", {54} ""(*) %routine trace(%string(255) s) %owninteger first=yes %integer oldout %if first=yes %thenstart open output(2,"trace") first=no %finish oldout=outstream select output(2) print string(s) newline select output(oldout) %end %routine trace record(%record(*)%name a,%string(255) s) %integer i,j,k,l %conststring(1)%array hex(0:15)= "0","1","2","3","4","5","6","7","8","9", "A","B","C","D","E","F" s=s.ssp.ssp.itoh(addr(a)) %for i=0,1,3 %cycle s=s.ssp %for j=0,1,1 %cycle s=s.ssp %for k=0,1,1 %cycle l=byteinteger(addr(a)+4*i+2*j+k) s=s.hex((l>>4)&16_f).hex(l&16_f) %repeat %repeat %repeat trace(s) %end %routine praddr(%name a,%string(255) s) %integer i print string(s) i=addr(a) print string(itoh(i)) newline %end %externalrecord(interestf)%map newinterest %record(interestf) pattern %record(interestf)%name p p==new(pattern) p_next==nil; p_prev==nil p_line==nil %result==p %end %externalrecord(interestlistf)%map newinterestlist %record(interestlistf) pattern %record(interestlistf)%name p p==new(pattern) p_head==nil; p_tail==nil %result==p %end %externalrecord(line40f)%map newline40 %record(line40f) pattern %record(line40f)%name p p==new(pattern) p_next==nil; p_prev==nil p_line="" %result==p %end %externalrecord(line40listf)%map newline40list %record(line40listf) pattern %record(line40listf)%name p p==new(pattern) p_head==nil; p_tail==nil %result==p %end %externalrecord(line80f)%map newline80 %record(line80f) pattern %record(line80f)%name p p==new(pattern) p_next==nil; p_prev==nil p_line="" %result==p %end %externalrecord(line80listf)%map newline80list %record(line80listf) pattern %record(line80listf)%name p p==new(pattern) p_head==nil; p_tail==nil %result==p %end %externalroutine clear person(%record(personf)%name a) a=0 a_homeaddr_head==nil; a_homeaddr_tail==nil a_initials="" a_interests==newinterestlist a_id=end a_next==nil a_officeaddr_head==nil; a_officeaddr_tail==nil a_prev==nil a_extra_head==nil; a_extra_tail==nil %end %externalrecord(personf)%map newperson %record(personf) personpattern %record(personf)%name p p==new(personpattern) clear person(p) %result==p %end %externalrecord(personlistf)%map newpersonlist %record(personlistf) personlistpattern %record(personlistf)%name p p==new(personlistpattern) p_head==nil; p_tail==nil %result==p %end %externalrecord(sourcef)%map newsource %record(sourcef) sourcepattern %record(sourcef)%name p p==new(sourcepattern) p=0 p_next==nil; p_prev==nil %result==p %end %externalrecord(sourcelistf)%map newsourcelist %record(sourcelistf) sourcelistpattern %record(sourcelistf)%name p p==new(sourcelistpattern) p_head==nil; p_tail==nil %result==p %end %routine out(%string(255) s) print string(s.snl) %end %externalroutine prec(%record(personf)%name p) out(p_id) out(p_style) out(p_initials) out(p_forenames) out(p_surname) %end %externalroutine preclist(%record(personlistf)%name l,%string(255) s) %record(personf)%name p %integer oldout message(s,"") oldout=outstream select output(1) out(s.snl) %if l_head==nil %then out("L_head points at nil.") %elsestart p==l_head %while p##nil %cycle prec(p) newline p==p_next %repeat %finish out("L_tail points at nil.") %if l_tail==nil out("End of list.".snl) select output(oldout) %end %externalrecord(interestf)%map insert interest(%record(interestf)%name a, %record(interestlistf)%name l) %record(interestf)%name p message("Null interest","mon") %if a==nil message("Null interest list","mon") %if l==nil p==l_head p==p_next %while p##nil %and p_line_line0 %and charno(a,length(a))=sp %end %routine trim trailing commas(%string(*)%name a) length(a)=length(a)-1 %while length(a)>0 %and charno(a,length(a))=',' %end %routine trim trailing commas and spaces(%string(*)%name a) length(a)=length(a)-1 %while length(a)>0 %c %and (charno(a,length(a))=',' %or charno(a,length(a))=sp) %end %routine tidy line(%string(*)%name a) trim leading spaces(a) trim trailing commas and spaces(a) %end ! This discards leading spaces. ! It trims trailing spaces and commas. ! It trims trailing full stops from the last line. %routine trim address(%record(line80listf)%name address) %record(line80f)%name p,q p==address_head %while p##nil %cycle trim trailing commas and spaces(p_line) q==p p==p_next excise cell(q,address) %and dispose(q) %if q_line="" %repeat %if address_tail##nil %thenstart p==address_tail length(p_line)=length(p_line)-1 %while length(p_line)>0 %c %and charno(p_line,length(p_line))='.' %finish %end %externalroutine prune and lower(%string(*)%name a) %integer i,j,k %constinteger conv='A'-'a' %return %if a="" j=0 %for i=1,1,length(a) %cycle k=charno(a,i) %if k#' ' %thenstart j=j+1 k=k-conv %if 'A'<=k<='Z' charno(a,j)=k %finish %repeat length(a)=j %end %externalroutine copy address(%record(line80listf)%name a,b) ! This copies list a to list b. %record(line80f)%name p,q b_head==nil; b_tail==nil p==a_head %while p##nil %cycle q==newline80 q_line=p_line %if b_tail==nil %thenstart b_head==q b_tail==q %finishelsestart q_prev==b_tail b_tail_next==q b_tail==q %finish p==p_next %repeat %end %string(255)%fn initials(%string(255) x) %string(255) y,z %integer i,j z="" %while x#"" %cycle i=1 i=i+1 %while i<=length(x) %and letterd(charno(x,i))=no %exit %if i>length(x) charno(x,j-i+1)=charno(x,j) %for j=i,1,length(x) length(x)=length(x)-i+1 y=x %and x="" %unless x->y.(",").x z=z.tostring(charno(y,1))."." %repeat %result=z %end %externalroutine sort persons(%record(personf)%array(1)%name X,%integer n) %record(personf) temp %integer i %routine adjust heap(%integer father,end) %integer son son=2*father %return %if son>end son=son+1 %if sonX(son)_id %or %c (X(son+1)_id=X(son)_id %and (X(son+1)_surname>X(son)_surname %or %c (X(son+1)_surname=X(son)_surname %and X(son+1)_forenames>X(son)_forenames)))) %if X(father)_id0 %and (charno(a,length(a))=',' %c %or charno(a,length(a))='.' %or charno(a,length(a))=sp) %end %externalroutine prune lines(%record(line80listf)%name a) %record(line80f)%name p,q %return %if a_head==nil p==a_head %while p##nil %cycle prune(p_line) %if p==nil %thenstart q==p p==p_prev excise cell(q,a) %finish %if p==nil %then p==a_head %else p==p_next %repeat %end %string(255)%fn despace(%string(255) a) %integer i,j prune and lower(a) j=0 %for i=1,1,length(a) %cycle j=j+1 %and charno(a,j)=charno(a,i) %unless charno(a,i)=sp %repeat length(a)=j %result=a %end %routine h(%integer n) %if 0 <=n<= hhmax %thenstart newline print string(hh(n).snl) print string( %c "This item can be omitted from the letter by replying to the prompt". %c " with an asterisk(*).".snl) %unless n=1 %or n=15 %or n=24 %or n=27 %c %or n=28 %or n=29 %or n=30 %or n=31 %finishelse print string("There is no help available for this item.".snl) %end %routine read word(%string(*)%name a) %integer j skip symbol %while next symbol=sp %or next symbol=nl a="" read symbol(j) %and a=a.tostring(j) %while sp#next symbol#nl %end %externalintegerfn panswer(%integer n) %string(255) a %on %event 9,15 %start message("Input ended while answering ".prt(n),"mon") %if event_event=9 message(a." found while answering ".prt(n),"stop") %c %if event_sub=1 %signal %event 15,2 %unless event_sub=0 h(n) %finish %cycle prompt("yes or no: ") read word(a) lower(a) %signal %event 15,1 %unless ".end"#a#"@" %signal %event 15,0 %if a="?" %result=no %if charno(a,1)=no %result=yes %if charno(a,1)=yes %repeat %end %routine collect(%string(*)%name a,%integer n,skipnl) %string(255) x %integer j %on %event 15 %start %signal %event 15,1 %unless event_sub=0 h(n) %finish prompt(prt(n)) a="" skip symbol %while next symbol=sp %or (skipnl=yes %and next symbol=nl) %cycle read symbol(j) %exit %if j=nl a=a.tostring(j) %repeat x=a prune and lower(x) prune(x) %signal %event 15,0 %if x="?" a=end %and %signal %event 15,1 %if x=end %end ! This deletes leading spaces. ! It returns "*" if it reads a blank line. %externalroutine get(%string(*)%name a,%integer n) collect(a,n,no) a="*" %if a="" %end ! This discards leading spaces and leading blank lines. ! It returns ".end" if it reads ".end" on a line by itself in any ! combination of cases. %externalroutine input(%string(*)%name a,%integer n) collect(a,n,yes) %end %routine outline(%string(7) prefix,%string(80) x,%string(7) postfix, %string(15) use) x="*" %if x="" %and use="file" print string(prefix) %if use="layout" print string(x) print string(postfix) %if use=":tt" %or use="layout" newline %end ! This looks for a nil link to end an address and then prints a blank line. ! It prints '*' if the argument record is nil or points at nil. %externalroutine print address(%record(line80listf)%name address, %string(15) use) %record(line80f)%name p %string(80) x %string(7) b,c,d %if address==nil %or address_head==nil %or address_head_line="" %thenstart %if use="file" %then x="*" %else x="" outline("",x.snl,"",use) %return %finish %if use="layout" %or use="centre" %then b="$B0 " %else b="" %if use="centre" %then use="layout" %and c="$B^0" %else c="" p==address_head %while p##nil %and p_line#"*"%cycle d="" %if use="layout" %or use=":tt" %thenstart ! To end last line of address with full stop. %if ','#charno(p_line,length(p_line))#'.' %thenstart %if p_next==nil %or p_next_line="*" %then d="." %else d="," %finish %finish outline(b,p_line,d.c,use) %if "*"#p_line#"" p==p_next %repeat %if use="file" %then outline("","*","",use) %else newline %end ! This prints the non-null and non-asterisk (* alone) lines. It looks ! for a nil pointer to terminate printing. %externalroutine print lines(%record(line80listf)%name l) %record(line80f)%name p p==l_head %while p##nil %cycle print string(p_line.snl) p==p_next %repeat %end %externalroutine print label style %integer i %constreal labeldepth=1.575 ;! Depth of a label in inches. %constreal labelwidth=3.741 ;! Width of a label in inches. %constreal left=0.342 ;! Margin at left of page of labels. %constreal leftmargin=0.2 ;! Margin at left of a label. %constreal linewidth=3.341 ;! Labelwidth-2*leftmargin %constreal top=0.342 ;! Margin at top of page. %constreal topmargin=0.2 ;! Margin at top of label. %constinteger vertlabels=7 ;! Maximum number of labels down the page. print string("$D.var loc".snl) print string("$J0".snl) print string("$D.FORMAT Labelpage".snl) %for i=0,1,vertlabels-1 %cycle print string("=$O".rtod(leftmargin,1,3).""",". %c rtod(topmargin+i*labeldepth,1,3).""",3.341"",1.175""[]".snl) print string("=$O".rtod(leftmargin+labelwidth,1,3).""",". %c rtod(topmargin+i*labeldepth,1,3).""",3.341"",1.175""[]".snl) %repeat print string("=$C".snl) print string("=$Labelpage".snl) print string( %c "$M".rtod(left,1,3).""",".rtod(top,1,3).""",". %c rtod(8.2-2*left,1,3).""",".rtod(11.5-2*top,1,3)."""".snl) print string("$Labelpage".snl) %end %externalrealfn printlength(%string(255) s,%string(31) font) %constinteger fontno=1 %conststring(31)%array fontname(1:fontno)="hershey" %constbyteintegerarray scalable(1:fontno)=yes %realarrayname h %constrealarray hersheywidth(0:255)= %c 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 866,600,866,1000,1066,1133,1200,533, 733,733,733,1266,600,1266,600,1066, 933,933,933,933,933,933,933,933, 933,933,600,600,1133,1266,1133,933, 1200,1000,1133,1000,1133,1066,1000,1133, 1200,666,866,1133,933,1333,1133,1066, 1066,1066,1133,1066,1066,1200,1000,1266, 1066,933,933,733,1066,733,1133,866, 533,1000,1066,866,1066,866,800,933, 1200,666,666,1133,666,1733,1200,933, 1066,1000,933,933,800,1200,1000,1266, 1000,1000,866,733,466,733,1133,0, 0(*) %string(31) y %real x %integer i,flag,n lower(font) flag=no %for i=1,1,fontno %cycle flag=yes %and %exit %if font->(fontname(i)).y %repeat %if flag=no %thenstart font="hershey" n=10 h==hersheywidth %finishelsestart %if scalable(i)=yes %thenstart n=dtoi(y) h==hersheywidth %finishelsestart ! A fudge until IMP V3 is available. n=10 h==hersheywidth %finish %finish x=0 %for i=1,1,length(s) %cycle x=x+Hersheywidth(charno(s,i)) %repeat x=x*n/100000 %result=x %end %externalroutine print label(%record(line80listf)%name b) %record(line80listf) a,aa %real c,d %ownstring(31) font %owninteger horizlabels=2 ;! Maximum number of labels across the page. %integer i,j,k,l %owninteger labelno=1 ;! Number of label across the page. %integer m %constinteger maxpts=14 ;! Largest type size for labels. %constinteger minpts=6 ;! Smallest type size for labels. %record(line80f)%name p %ownreal pagewidth=7.48 ;! Width of the page in inches. %ownreal pagedepth=11.7 ;! Depth of the page in inches. %constreal printdepth=1.175 ;! Labeldepth-2*topmargin %record(line80f)%name q %owninteger rowno=1 ;! Number of label down the page. %ownreal slope=0.00 ;! Indentation per line of address. %string(255) u %routine set max(%record(line80listf)%name b,%realname chars, %integername lines,%integer points) %real x %record(line80f)%name p,q p==b_tail %while p##nil %cycle %if p_line="" %thenstart q==p p==p_prev excise cell(q,b) dispose(q) %finishelse p==p_prev %repeat chars=0 p==b_head lines=0 %while p##nil %cycle x=printlength(p_line,"hershey".itod(points)) chars=x %if charslinewidth %cycle breaks=yes ! Fix alignment point for rest of line. { r_line="$loc=X"} r_line="" ! Locate break-point in line. m=length(p_line) q==newline80 q_line=p_line %cycle m=m-1 %until m=0 %or charno(q_line,m)=sp length(q_line)=m xx=printlength(q_line,"Hershey".itod(s)) %repeat %until m=0 %or xx(q_line).p_line ! Trim first part of line and insert. length(q_line)=length(q_line)-1 %while charno(q_line,length(q_line))=sp insert cell before(q,p,b) ! Align last fragment to fix-point from previous line. r==newline80 { r_line="$X>loc"} r_line="$B>0" append cell(r,aa) %repeat p==p_next %repeat %result=breaks %end %integerfn scale(%record(line80listf)%name b,aa) %record(line80listf) a %record(line80f)%name p %integer breaks,i,j,s %for s=maxpts,-1,minpts-1 %cycle copy address(b,a) breaks=split lines(a,aa,s) i=0; p==a_head %while p##nil %cycle i=i+1 p==p_next %repeat ! Hershey(10) has a line-depth of 0.14". %exit %if i*s<=printdepth*70 %and (breaks=0 %or s<=10) delete list(a) delete list(aa) %repeat %if s0" %else u="" ! Punctuate lines. p==b_head %while p##nil %cycle %if '.'#charno(p_line,length(p_line))#',' %thenstart %if p_next==nil %then p_line=p_line."." %else p_line=p_line."," %finish p==p_next %repeat ! Replace 'D/-'. p==b_head p_line=u %unless u="" ! Plant font and size. aa_head==nil; aa_tail==nil font="$Hershey(".itod(scale(b,aa)).")" print string(font.snl) p==b_head; q==aa_head %while p##nil %cycle %if p==b_head %then u="" %else u="$B0 " u=u.p_line.q_line.snl print string(u) p==p_next; q==q_next %repeat print string("$C".snl) %end ! This looks for an asterisk(*) to end an address. It replaces it with a ! nil pointer 'next' on the last line stored. ! If the whole address is "*", it is replaced by nil in both the head and tail ! of the head-cell. ! It skips leading spaces in each line. %externalroutine get lines(%record(line80listf)%name lines,%integer n) %record(line80f)%name p %string(80) a,x lines_head==nil; lines_tail==nil %cycle get(a,n) message("Stopped while getting ".prt(n),"stop") %if a=end a="*" %if a="" %or a="@" %exit %if a="*" p==newline80 p_line=a append cell(p,lines) %repeat %end %externalroutine input lines(%record(line80listf)%name lines,%integer n) %record(line80f)%name p %string(80) a lines_head==nil; lines_tail==nil input(a,n) %cycle message("Stopped while inputting ".prt(n),"stop") %if a=end a="*" %if a="" %or a="@" %exit %if a="*" p==newline80 p_line=a append cell(p,lines) get(a,n) %repeat %end %externalroutine get address(%record(line80listf)%name address,%integer n) %record(line80f)%name p get lines(address,n) trim address(address) %end %externalroutine input address(%record(line80listf)%name address,%integer n) input lines(address,n) trim address(address) %end %externalroutine print person(%record(personf)%name a,%string(15) use) %record(interestf)%name b %string(255) x %return %if a_id=end %if use=":tt" %thenstart print string(a_style." ") %if ""#a_style#"*" %if ""#a_forenames#"*" %then x=a_forenames." " %else x=a_initials print string(x) %if ""#x#"*" print string(a_surname) print string(",".a_degrees) %if ""#a_degrees#"*" newline %finishelsestart ! Surname. outline("",a_surname,"",use) ! Style. outline("",a_style,"",use) ! Forenames. outline("",a_forenames,"",use) ! Initials. outline("",a_initials,"",use) ! Degrees. outline("",a_degrees,"",use) %finish ! Home address. print address(a_homeaddr,use) ! Home Telephone number. outline("",a_homephone,"",use) ! ID. outline("",a_id,"",use) ! Firm. outline("",a_firm_line,"",use) ! Department. outline("",a_department_line,"",use) ! Room. outline("",a_room,"",use) ! Office address. print address(a_officeaddr,use) ! Office Telephone number. outline("",a_officephone,"",use) ! Extension. outline("",a_ext,"",use) ! Mail address. outline("",a_emailaddr,"",use) ! Telex number. outline("",a_telex,"",use) ! Interests. %if a_interests##nil %thenstart b==a_interests_head %while b##nil %cycle %exit %unless ""#b_line_line#"*" outline("",b_line_line,"",use) b==b_next %repeat %finish print string("*") %if use="file" newline ! Extra. print lines(a_extra) ! Terminate record. outline("",snl."@".snl.snl,"",use) %end ! This returns a cleared record if '.end' is the only word on a line. ! It assumes that each address ends with an asterisk(*) on a line by itself. ! It assumes that each record is followed by '@'. %externalroutine read person(%record(personf)%name a) %record(interestf)%name b %record(line40f)%name c %record(line80f)%name d %string(80) x %integer i %on %event 9,15 %start clear person(a) %return %finish clear person(a) ! Surname. input(a_surname,22) prune(a_surname) a_surname="*" %if a_surname="" clear person(a) %and %return %if a_surname="@" ! Style. get(a_style,21) a_style="*" %if a_style="" ! Forenames. get(a_forenames,9) a_forenames="*" %if a_forenames="" ! Initials. get(a_initials,36) a_initials="*" %if a_initials="" ! Degrees. get(a_degrees,5) a_degrees="*" %if a_degrees="" ! Home address. get address(a_homeaddr,11) ! Home Telephone number. get(a_homephone,12) a_homephone="*" %if a_homephone="" ! ID. get(a_id,13) a_id="*" %if a_id="" ! Firm. get(a_firm_line,45) a_firm_line="*" %if a_firm_line="" ! Department. get(a_department_line,6) a_department_line="*" %if a_department_line="" ! Room. get(a_room,20) a_room="*" %if a_room="" ! Office address. x=a_department_line; prune and lower(x) %if x="cs" %thenstart %for i=1,1,6 %cycle d==newline80 d_line=univaddr(i) append cell(d,a_officeaddr) %repeat a_officephone="(031) 667 1081" %finishelsestart get address(a_officeaddr,18) ! Office Telephone number. get(a_officephone,19) a_officephone="*" %if a_officephone="" %finish ! Extension. get(a_ext,7) a_ext="*" %if a_ext="" ! Mail address. get(a_emailaddr,47) a_emailaddr="*" %if a_emailaddr="" ! Telex number. %if x="cs" %then a_telex="727442 (UNIVED G)" %and %c a_department_line="Computer Science" %else get(a_telex,23) a_telex="*" %if a_telex="" ! Interests, up to an asterisk(*). a_interests==newinterestlist %cycle b==newinterest c==newline40 get(c_line,14) c_line="*" %if c_line="" %or c_line="@" %exit %if c_line="*" b_line==insert line40(c,line40list) b==insert interest(b,a_interests) %repeat ! Extra. This must end with an asterisk(*) on a line by itself. get lines(a_extra,8) ! Skip to "@". input(x,33) %until x="@" %end ! This appends b to a and sets b to nil. %externalroutine concatpersonlists(%record(personlistf)%name a,b) b==nil %and %return %if b==nil %or b_head==nil a==b %and b==nil %and %return %if a==nil %or a_head==nil a_tail_next==b_head b_head_prev==a_tail a_tail==b_tail b==nil %end %externalroutine concatsourcelists(%record(sourcelistf)%name a,b) b==nil %and %return %if b==nil %or b_head==nil a==b %and b==nil %and %return %if a==nil %or a_head==nil a_tail_next==b_head b_head_prev==a_tail a_tail==b_tail b==nil %end %externalroutine exciseinterest(%record(interestf)%name p, %record(interestlistf)%name l) %return %if p==nil %or l==nil %or l_head==nil %if l_head==p %thenstart l_head==l_head_next %if l_head==nil %then l_tail==nil %else l_head_prev==nil p_next==nil; p_prev==nil %return %finish %if l_tail==p %thenstart l_tail==l_tail_prev %if l_tail==nil %then l_head==nil %else l_tail_next==nil p_next==nil; p_prev==nil %return %finish p_prev_next==p_next p_next_prev==p_prev p_next==nil; p_prev==nil %end %externalroutine exciseline40(%record(line40f)%name p, %record(line40listf)%name l) %return %if p==nil %or l==nil %or l_head==nil %if l_head==p %thenstart l_head==l_head_next %if l_head==nil %then l_tail==nil %else l_head_prev==nil p_next==nil; p_prev==nil %return %finish %if l_tail==p %thenstart l_tail==l_tail_prev %if l_tail==nil %then l_head==nil %else l_tail_next==nil p_next==nil; p_prev==nil %return %finish p_prev_next==p_next p_next_prev==p_prev p_next==nil; p_prev==nil %end %externalroutine exciseline80(%record(line80f)%name p, %record(line80listf)%name l) %return %if p==nil %or l==nil %or l_head==nil %if l_head==p %thenstart l_head==l_head_next %if l_head==nil %then l_tail==nil %else l_head_prev==nil p_next==nil; p_prev==nil %return %finish %if l_tail==p %thenstart l_tail==l_tail_prev %if l_tail==nil %then l_head==nil %else l_tail_next==nil p_next==nil; p_prev==nil %return %finish p_prev_next==p_next p_next_prev==p_prev p_next==nil; p_prev==nil %end %externalroutine exciseperson(%record(personf)%name p, %record(personlistf)%name l) %return %if p==nil %or l==nil %or l_head==nil %if l_head==p %thenstart l_head==l_head_next %if l_head==nil %then l_tail==nil %else l_head_prev==nil p_next==nil; p_prev==nil %return %finish %if l_tail==p %thenstart l_tail==l_tail_prev %if l_tail==nil %then l_head==nil %else l_tail_next==nil p_next==nil; p_prev==nil %return %finish p_prev_next==p_next p_next_prev==p_prev p_next==nil; p_prev==nil %end %externalroutine excisesource(%record(sourcef)%name p, %record(sourcelistf)%name l) %return %if p==nil %or l==nil %or l_head==nil %if l_head==p %thenstart l_head==l_head_next l_head_prev==nil %unless l_head==nil p_next==nil; p_prev==nil %return %finish %if l_tail==p %thenstart l_tail==l_tail_prev l_tail_next==nil p_next==nil; p_prev==nil %return %finish p_prev_next==p_next p_next_prev==p_prev p_next==nil; p_prev==nil %end ! This inserts list a before item p in b. %externalroutine insertpersonlistbefore(%record(personlistf)%name a,b, %record(personf)%name p) %return %if a==nil %or a_head==nil %if b==nil %thenstart b==newpersonlist b=a %return %finish %if b_head==nil %then b=a %and %return %if p==nil %or p_prev==nil %thenstart a_tail_next==b_head b_head_prev==a_tail b_head==a_head %return %finish a_head_prev==p_prev a_tail_next==p p_prev_next==a_head p_prev==a_tail %end ! This inserts list a before item p in b. %externalroutine insertsourcelistbefore(%record(sourcelistf)%name a,b, %record(sourcef)%name p) %return %if a==nil %or a_head==nil %if b==nil %thenstart b==newsourcelist b=a %return %finish %if b_head==nil %then b=a %and %return %if p==nil %or p_prev==nil %thenstart a_tail_next==b_head b_head_prev==a_tail b_head==a_head %return %finish a_head_prev==p_prev a_tail_next==p p_prev_next==a_head p_prev==a_tail %end %externalroutine insert line80list before(%record(line80listf)%name a,b, %record(line80f)%name p) %return %if a==nil %or a_head==nil message("Cannot insert in an unassigned list.","mon") %if b==nil %if b_head==nil %then b=a %and %return %if p==nil %or p_prev==nil %thenstart a_tail_next==b_head b_head_prev==a_tail b_head==a_head a_head==nil; a_tail==nil %return %finish a_head_prev==p_prev a_tail_next==p p_prev_next==a_head p_prev==a_tail a_head==nil; a_tail==nil %end %externalroutine print personlist(%record(personlistf) a,%string(80) s) %record(personf)%name p %integer oldout oldout=outstream select output(0) print string(s.snl) print string("Personlist empty".snl) %and %return %if %c a==nil %or a_head==nil p==a_head %while p##nil %cycle print person(p," ") p==p_next %repeat print string(snl."End of list of persons.".snl) select output(oldout) %end %externalroutine reedit person(%record(personf)%name a) %record(line80f)%name p,q %record(interestf)%name b %record(line40f)%name c %integer n %on %event 15 %start message("Stopped from input while Changing ".prt(n),"stop") %finish message( %c "For each item that may be changed you will be shown the prompt and".snl.%c "the current value. Respond with yes if you wish to change its value,".snl. %c "respond with no otherwise.","") ! Style. n=21 print string(prt(21).a_style.snl) get(a_style,21) %if panswer(21)=yes ! Forenames. n=9 %if a_forenames="" %then print string("No forename.".snl) %c %else print string(prt(9).a_forenames.snl) get(a_forenames,9) %if panswer(9)=yes ! Initials. %if a_initials="" %then print string("No initials".snl) %c %else print string(prt(36).a_initials.snl) get(a_initials,36) %if panswer(36)=yes ! Surname. n=22 print string(prt(22).a_surname.snl) input(a_surname,22) %if panswer(22)=yes prune(a_surname) ! Degrees. n=5 print string(prt(5).a_degrees.snl) get(a_degrees,5) %if panswer(5)=yes ! Home address. n=11 print string(prt(11).snl) print address(a_homeaddr,":tt") %if panswer(11)=yes %thenstart p==a_homeaddr_head %while p##nil %cycle q==p_next dispose(p) p==q %repeat get address(a_homeaddr,11) %finish ! Home Telephone number. n=12 print string(prt(12).a_homephone.snl) get(a_homephone,12) %if panswer(12)=yes ! ID. n=13 print string(prt(13).a_id.snl) get(a_id,13) %if panswer(13)=yes ! Department. n=6 print string(prt(6).a_department_line.snl) get(a_department_line,6) %if panswer(6)=yes ! Room. n=20 print string(prt(20).a_room.snl) get(a_room,20) %if panswer(20)=yes ! Office address. n=18 print string(prt(18).snl) print address(a_officeaddr,":tt") %if panswer(18)=yes %thenstart p==a_officeaddr_head %and exciseline80(p,a_officeaddr) %and dispose(p) %c %while a_officeaddr_head##nil get address(a_officeaddr,18) %finish ! Office Telephone number. n=19 print string(prt(19).a_officephone.snl) get(a_officephone,19) %if panswer(19)=yes ! Extension. n=7 print string(prt(7).a_ext.snl) get(a_ext,7) %if panswer(7)=yes ! Telex number. n=23 print string(prt(23).a_telex.snl) get(a_telex,23) %if panswer(23)=yes ! Interests, up to asterisk (*). n=14 print string(prt(14).snl) b==a_interests_head %while b##nil %cycle %exit %if b_line_line="" outline("",b_line_line,"",":tt") b==b_next %repeat %if panswer(14)=yes %thenstart b==a_interests_head %and exciseinterest(b,a_interests) %and dispose(b) %c %while a_interests_head##nil %cycle b==newinterest c==newline40 get(c_line,14) c_line="" %if c_line="@" %exit %if c_line="" b_line==insert line40(c,line40list) b==insert interest(b,a_interests) %repeat %finish ! Extra. This must end with an asterisk(*) on a line by itself. n=8 print string(prt(8).snl) print lines(a_extra) get lines(a_extra,8) %if panswer(8)=yes %end %externalroutine identify(%record(personlistf)%name noname, %string(255) namelist,%integer control) %record(personf)%name p %record(personf) person %string(255) u,v,w,x,y,z %integer ct %return %if noname_head==nil %or namelist="" open input(3,namelist) select input(3) ct=0 p==noname_head %while p##nil %cycle ct=ct+1 p==p_next %repeat %while ct>0 %cycle read person(person) z=despace(person_id) %exit %if z=end x=despace(person_surname) y=despace(person_initials).x w=despace(person_style).y ! Match person id and name against IDs and names in noname. p==noname_head %while p##nil %cycle u=despace(p_surname) v=despace(p_id) %if (u#"" %and ( u=z %or u=y %or u=x %or u=w)) %c %or (v#"" %and ( v=z %or v=y %or v=x %or v=w)) %thenstart ! Noname record recognised. Fill details into record in 'noname'. p_id=person_id; p_surname=person_surname p_style=person_style; p_forenames=person_forenames p_initials=person_initials; p_degrees=person_degrees p_department=person_department; p_room=person_room p_officeaddr=person_officeaddr ct=ct-1 %exit %finish p==p_next %repeat %repeat close input select input(control) %end ! The values of n are: 2 for Cc with letters, 24 for To with memoranda. %externalroutine isolate ids(%record(line80listf)%name l) %record(line80f)%name p,q %string(80) s p==l_head %while p##nil %cycle s=p_line %while s#"" %cycle q==newline80 q_line=s %and s="" %unless s->q_line.(";").s insert cell before(q,p,l) %repeat q==p; p==p_next excise cell(q,l) dispose(q) %repeat %end %integerfn pick up files(%record(line80listf)%name l,%integer n,control) %record(line80listf) x %record(line80f)%name p,q %string(80) s %integer flag flag=no p==l_head %while p##nil %cycle %if p_line->("@").s %thenstart %cycle %exit %if exists(s) message( %c s." does not exist. Do you want to replace it?","") %if panswer(41)=yes %then get(s,41) %else s="" %exit %if s="" %repeat %if s="" %then p==p_next %elsestart flag=yes q==p_prev open input(3,s) select input(3) get lines(x,n) close input select input(control) %if x_head##nil %thenstart isolate ids(x) insert line80list before(x,l,p) excise cell(p,l) dispose(p) %finish %if q==nil %then p==l_head %else p==q_next %finish %finishelse p==p_next %repeat %result=flag %end %externalroutine get recipients( %c %record(personlistf)%name noname,%integer n,control) %record(line80listf) x %record(line80f)%name p,q %record(personf)%name r %integer flag ! Get top level of names of recipients. select input(control) get lines(x,n) isolate ids(x) flag=pick up files(x,n,control) %until flag=no ! Copy to Dests1 for use in file-copies. dests1_head==nil; dests1_tail==nil p==x_head %while p##nil %cycle r==newperson r_id=p_line q==newline80 q_line=p_line append cell(q,r_extra) append cell(r,dests1) p==p_next %repeat ! Copy to Noname. noname_head==nil; noname_tail==nil p==x_head %while p##nil %cycle r==newperson r_id=p_line q==newline80 q_line=p_line append cell(q,r_extra) append cell(r,noname) p==p_next %repeat delete list(x) %end %endoffile