$pascal '92070-1X291 REV.2001 800606'$ $heap 0$ $segment$ PROGRAM PFS3; { *NAME: PFS3 *SOURCE: 92070-18291 *RELOC: 92070-16291 *PGMR: DAVE NEFF * **************************************************************** * (C) COPYRIGHT HEWLETT-PACKARD COMPANY, 1979. ALL RIGHTS * * RESERVED. NO PART OF THIS PROGRAM MAY BE PHOTOCOPIED, * * REPRODUCED OR TRANSLATED TO ANOTHER PROGRAM LANGUAGE WITHOUT * * THE PRIOR WRITTEN CONSENT OF HEWLETT-PACKARD COMPANY. * **************************************************************** } {PFS3 contains the procedures used for part 3 of the formatting process. It is in memory most of the time PFORM is running.} {Read in global constants,types, and variables.} $include 'PFGBL'$ {External procedure definitions. Calls to FMP.} PROCEDURE readf(VAR idcb:dcb; VAR ierr:integer; VAR ibuff:buffer; ilen,len,num:integer);external; PROCEDURE close(VAR idcb:dcb);external; PROCEDURE locf(VAR idcb:dcb; VAR ierr,irec,irb,ioff,jsec,jlu,jty:integer); external; PROCEDURE writf(VAR idcb:dcb; VAR ierr:integer; VAR ibuff:buffer; ilen,rec_num:integer);external; PROCEDURE purge(VAR idcb:dcb; VAR ierr:integer; VAR name:fname; VAR isecu,icr:integer);external; PROCEDURE open(VAR idcb:dcb; VAR ierr:integer; VAR name:fname; iopin,isecu,icr:integer);external; {Declaration of external assembly language routines.} FUNCTION andi(i1,i2:integer):integer;external; FUNCTION ori(i1,i2:integer):integer;external; {rshift shifts an integer right 1 bit, and puts 0 in the high bit.} PROCEDURE rshift(int:integer);external; PROCEDURE split_namr(VAR iline:input_line; VAR len:integer; VAR name:fname; VAR security,cartridge,start_char, namr_type:integer);external; {External procedures used by PFS3,but in the main program.} FUNCTION getword(addr:integer; VAR idcb:dcb; VAR ibuff:buffer; VAR name:fname; VAR curr_rec:integer):integer;external; PROCEDURE putword(word,address:integer;VAR idcb:dcb; VAR ibuff:buffer; VAR name:fname; VAR curr_rec:integer; ship:boolean); external; PROCEDURE writline(line:input_line);external; PROCEDURE readline(line:input_line; len:integer);external; PROCEDURE fmp_error(ierr:integer; VAR file_name:fname);external; {The routines in this segment are next.} {make_word is a FUNCTION which accepts two characters, and returns the value of the the 16 bit integer which corresponds to the first character in the upper byte and the second character in the lower byte.} { upper_byte: The first character passed. lower_byte: The second character passed.} FUNCTION make_word(upper_byte,lower_byte:char):integer; BEGIN make_word:=ori(ord(upper_byte)*256,ord(lower_byte)); END; {make_word} {right_shift is a function which rotates an integer right the passed number of bits. This function is used to adjust for fields rather than through the use of the DIV operator to prevent problems due to a possibly set bit 15 (DIV preserves sign).} { num: The integer to be rotated. bits: The number of bits to rotate.} FUNCTION right_shift(num,bits:integer):integer; VAR i, {A loop index.} tnum:integer; {The temporary and running rotation result.} BEGIN {right_shift} IF bits<=0 THEN right_shift:=num ELSE IF bits>=16 THEN right_shift:=0 ELSE BEGIN tnum:=num; FOR i:=1 to bits DO rshift(tnum); right_shift:=tnum; END; END; {right_shift} {getidseg uses getword to retrieve an entire idsegment from the system memory image file.} { start_addr: The starting address of the id segment to be retrieved from the system image file. idcb: The dcb of the current system image. ibuff: The buffer associated with the dcb. name: The name of the system image file. curr_rec: The record number of the system image which corresponds to the current contents of ibuff. segment: The array which contains the returned id segment.} PROCEDURE getidseg(start_addr:integer;VAR idcb:dcb; VAR ibuff:buffer; VAR name:fname; VAR curr_rec:integer; VAR segment:idseg); VAR addr, {The address of the current word being retrieved from the system image.} i:integer; {Counts through the id segment to retrieve 30 words.} BEGIN io_error:=false; i:=0; {Loop using getword until the entire id segment has been retrieved or until an FMP error occurs.} WHILE (irecd_len THEN BEGIN {Must get a new record.} offset:=1; cur_fde_rec:=cur_fde_rec+1; {Check to see if the new current record is off the current track. If so, adjust the pointers accordingly.} IF ((cur_fde_rec-first_track_rec)=recs_per_track) THEN BEGIN {Must move to the next file directory track.} first_track_rec:=first_track_rec-recs_per_track; cur_fde_rec:=first_track_rec; END; {Get the next record.} readf(idcb,ierr,ibuff,recd_len,len,cur_fde_rec); END; END; END; fl_conflict:=conflict; END; {fl_conflict} {rt_conflict is a function which is true if the passed skel_ids specifies base page, main, or segment addresses which conflict with a current id segment in the system image. The function is false if the skel_ids would be rp'd into the background partition,or there are no conflicts.} { start_addr: The starting address in the system image file which points to the beginning of the array of 30 word id segments. idcb: The dcb of the system image file. ibuff: The buffer associated with the system dcb. Type 1 access is used. name: The name of the system image file. curr_rec: The record number which the current contents of ibuff correspond to. skel_ids: The first 34 words of the header of the type 6 file being checked for conflicts. free_addr: The address of the first free id segment availiable. It is zero if all id segments are used, and it is -1 if the name in the skeleton id segment is the same as a name already RP'd.} FUNCTION rt_conflict(start_addr:integer; VAR idcb:dcb; VAR ibuff :buffer;VAR name:fname; VAR curr_rec:integer; VAR skel_ids:lo_idseg; VAR free_addr:integer) :boolean; VAR {boolean TYPE declarations.} first_free_found, {true when an availiable id segment has been found in the system image, false otherwise.} real_time, {true when the skeleton id segment passed to the routine corresponds to the real time partition of the system, false if the skeleton id segment corresponds to the background partition.} temp_rt_con:boolean; {true when a conflict has been found with currently RP'd real time programs, false as long as no conflicts are found. Upon return, rt_conflict is assigned this value.} {idseg type declaration.} curr_ids:idseg; {The current id segment of the system image which is being tested.} {integer types are declared next.} curr_bpl, {The low base page address of the id segment from the system image currently being checked.} curr_bph, {The high base page address of the id segment from the system image currently being checked.} curr_high, {The high main address of the id segment from the system image currently being checked.} curr_low, {The low main address of the idsegment from the system image currently being checked.} curr_num_segs, {The number of segments of the id segment from the system image being searched.} i, {Counts the number of id segments from the system image which have been checked out.} new_bpl, {The low base page address from the skeleton id segment passed to the routine.} new_bph, {The high base page address from the skeleton id segment.} new_high, {The high main address from the skeleton id segment.} new_low, {The low main address from the skeleton id segment.} new_num_segs:integer; {The number of segments the skeleton id segment specifies.} BEGIN {Get the address information from the passed skeleton id segment.} new_low:=skel_ids[21]; new_num_segs:=right_shift(skel_ids[24],10); IF new_num_segs>0 THEN BEGIN {Program to be checked is segmented.} new_high:=skel_ids[33]-1; {This includes maximum segment extent} new_bph:=skel_ids[34]-1; new_bpl:=andi(skel_ids[24],1023); END ELSE BEGIN {Current program is unsegmented.} new_high:=skel_ids[22]-1; new_bph:=skel_ids[25]-1; new_bpl:=skel_ids[24]; END; free_addr:=0; i:=0; first_free_found:=false; temp_rt_con:=false; WHILE (I=fwbg THEN real_time:=false ELSE real_time:=true; IF real_time AND (curr_num_segs>0) THEN BEGIN {Only one real time can be segmented. By definition, it must be the last real time in the partition, and its highest segment address is therefore the last word of the real time partition.} curr_high:=fwbg-1; curr_bph:=bgbp-1; curr_bpl:=andi(curr_ids[24],1023); END ELSE IF real_time THEN BEGIN {Current idseg from system image is an unsegmented real time.} curr_high:=curr_ids[23]-1; curr_bph:=(andi(curr_ids[25],1023)-1); curr_bpl:=curr_ids[24]; END; {Check for conflict due to same name already RP'd.} IF (curr_ids[13]=skel_ids[13]) AND (curr_ids[14]=skel_ids[14]) AND (curr_ids[15]=skel_ids[15]) THEN BEGIN temp_rt_con:=true; free_addr:=-1; END ELSE {Real time programs may have address conflicts. Check bounds.} IF real_time THEN BEGIN IF (((new_low<=curr_high) AND (new_low>=curr_low)) OR ((new_high<=curr_high) AND (new_high>=curr_low))) THEN temp_rt_con:=true; IF (((new_bpl<=curr_bph) AND (new_bpl>=curr_bpl)) OR ((new_bph<=curr_bph) AND (new_bph>=curr_bpl))) THEN temp_rt_con:=true; END; END; rt_conflict:=temp_rt_con; END; {rt_conflict} {convrt_seg accepts a short id segment number (starting at 1) and returns its record number and offset of the ibuff. For example, if segnum is 2, convrt_seg will return recnum=2 and offset=9.} { segnum: The number of the short id segment of which information is desired. recnum: The returned record number which contains the segment number specified by segnum. offset: The offset (starting at 1) of the above segnum in the above recnum.} PROCEDURE convrt_seg(segnum:integer;VAR recnum,offset:integer); BEGIN recnum:=((segnum*short_idseg_length-1) DIV recd_len)+2; offset:=((segnum-1) MOD (recd_len DIV short_idseg_length)) *short_idseg_length; offset:=offset+1; END; {convrt_seg} {getshort_ids gets a short id segment from the specified file, and returns the segment in sids (passed by name).} { segnum: The number of the segment to be retrieved. idcb: The dcb of the memory image file which contains the short id segment desired. ibuff: The buffer associated with the above idcb. name: The name of the file which contains the short id segment desired. curr_rec: The record number which the current contents of ibuff corresponds to. sids: The short id segment returned by the routine.} PROCEDURE getshort_ids(segnum:integer; VAR idcb:dcb; VAR ibuff:buffer; VAR name:fname; VAR curr_rec:integer; VAR sids:sh_idseg); VAR {integer declarations.} i, {Counter used for moving the contents of ibuff into a short idsegment structure.} ierr, {The ierr code returned by FMP calls.} len, {The actual length of a record, read, required for calls to readf.} offset, {The offset passed to convrt_seg.} recnum:integer; {The record number passed to convrt_seg.} BEGIN convrt_seg(segnum,recnum,offset); IF recnum<>curr_rec THEN BEGIN {Its a miss. Get the correct record,update curr_rec.} readf(idcb,ierr,ibuff,recd_len,len,recnum); IF ierr<0 THEN fmp_error(ierr,name) ELSE curr_rec:=recnum; END; IF ierr>=0 THEN FOR i:=1 TO short_idseg_length DO sids[i]:=ibuff[i+offset-1]; END; {getshort_ids} {calc_checksum calculates and stores the checksum of a short idseg} { sids: The short id segment to compute the checksum for.} PROCEDURE calc_checksum(VAR sids:sh_idseg); VAR {integer type declarations.} csw, {Variable which counts to the checksum word.} i:integer; {Index into the short id segment, which counts through the sids.} BEGIN csw:=0; FOR i:=1 TO (short_idseg_length-1) DO csw:=csw+sids[i]; sids[short_idseg_length]:=csw; END; {calc_checksum} {rec_to_ts converts the record number passed by value in rec into the appropriate values of track and sector.} { rec: The number of the record in the output (PROM image) file, which is to be converted into track, sector information. track: The track corresponding to the record. sector: The sector corresponding to the record.} PROCEDURE rec_to_ts(rec:integer;VAR track,sector:integer); BEGIN sector:=((rec-1)*2) MOD sect_per_track; track:=(rec-1) DIV recs_per_track; END;{rec_to_ts} {recd_to_tb converts the passed record number into its track and logical block number on the PROM disk. A block is like a record (2 sectors) but is device, not file, relative.} { rec: The number of the PROM image record which is to be converted. track: The record's corresponding track. block: The record's corresponding block.} PROCEDURE recd_to_tb(rec:integer; VAR track,block:integer); BEGIN block:=(rec-1) MOD recs_per_track; track:=(rec-1) DIV recs_per_track; END;{recd_to_tb} {rec_extent is a function which accepts a low address and a high address plus one, and calculates the number of file records such address would extend. The function is used for rp-ing a file.} { lo_addr: The low address of the extent. hi_addrp1: The high address plus one of the extent.} FUNCTION rec_extent(lo_addr,hi_addrp1:integer):integer; VAR {integer declarations.} num_recs, {The number of records which the addresses extend.} num_words, {The number of words which the addresses extend.} remainder:integer; {The number of words in the last record of the extent.} BEGIN num_words:=hi_addrp1-lo_addr; num_recs:=num_words DIV recd_len; {Find out if there are any remaining words the above calculations did not take into account.} remainder:=num_words MOD recd_len; IF remainder>0 THEN {There is one record which the extent partially encompasses.} num_recs:=num_recs+1; rec_extent:=num_recs; END; {rec_extent} {putfde writes a file directory entry into the output file.} { entry_num: The entry number of the file directory. Numbering starts with 1. idcb: The dcb of the PROM image file. ibuff: The buffer associated with idcb. name: The PROM image file name. start_rec: The starting record number of the file directory track the entry is to be stored on. fde: The 16 word file directory entry itself.} PROCEDURE putfde(entry_num:integer; VAR idcb:dcb; ibuff:buffer; VAR name:fname; start_rec:integer; VAR fde:file_directory); VAR {integer type declarations.} i, {The index which is used to transfer fde into ibuff.} ierr, {The error code returned by FMP calls.} len, {The actual length of the record read, required for readf calls.} offset, {The offset of the fde in ibuff.} recnum:integer; {The record number which contains the space for the fde.} BEGIN {Compute the record number using the following simple formula.} recnum:=start_rec+((entry_num*fdir_length-1) DIV recd_len); readf(idcb,ierr,ibuff,recd_len,len,recnum); IF ierr<0 THEN fmp_error(ierr,name) ELSE BEGIN {Put the directory entry at the correct place in the outfile.}