$pascal '92071-1X336 REV.2041 800611'$ $heap 0$ PROGRAM BUILD; { *NAME: BUILD *SOURCE: 92071-18336 *RELOC: 92071-16336 *PGMR: DAVE NEFF **************************************************************** * (C) COPYRIGHT HEWLETT-PACKARD COMPANY, 1980. 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. * ****************************************************************} {BUILD is a utility for the RTE-L/20 which configures a memory image file is a bootable memory only (non disk) system. Read in global constants, types, and variables.} $include 'BUGBL'$ {External procedure definitions. Calls to FMP.} PROCEDURE readf(VAR idcb:dcb; VAR ierr:integer; VAR ibuff:buffer; ilen:integer; VAR len,num:integer);external; PROCEDURE writf(VAR idcb:dcb; VAR ierr:integer; VAR ibuff:buffer; ilen,rec_num:integer);external; {Although open is not used in the main, it is used by all of the segments. Declare it here to make the segments smaller, and cut down on segment load time, at no cost of total program size.} PROCEDURE open(VAR idcb:dcb; VAR ierr:integer; VAR file_name:string6); external; {Similarly, all segments use namr, so declare it here.} PROCEDURE namr(VAR buffer:namr_parse_buffer; VAR inline:input_line; length:integer; VAR istrc:integer);external; {Declare calls to system resources.} FUNCTION ifbrk:integer;external; {The remaining external procedures are in the segments.} {See the segment source listings for documentation on the calling and return sequences.} PROCEDURE handle_error(err_type: error_type; {Set of error cases} err_number,err_line: integer; VAR err_file: input_line; err_flen:integer); external; PROCEDURE file_init;$direct$ external; PROCEDURE def_partitions;$direct$ external; PROCEDURE get_command$direct$;external; PROCEDURE cleanup_files;$direct$ external; PROCEDURE ss_process;$direct$ external; PROCEDURE question_process;$direct$ external; PROCEDURE pt_process;$direct$ external; PROCEDURE sz_process;$direct$ external; PROCEDURE st_process;$direct$ external; PROCEDURE pa_process;$direct$ external; PROCEDURE rp_process;$direct$ external; PROCEDURE pr_process;$direct$ external; {This procedure handles the segment loads.} {@SGLD is a PASCAL library routine.} PROCEDURE segload $ALIAS '@SGLD'$ (segment:fname);external; {segment_load uses segload and information about the segment structure contained in set types to ease the segmentation process.} { called_routine: Enumerated type which indicates the name of the routine which is to be called immediately after segment_load.} PROCEDURE segment_load(called_routine:all_routines); $direct$ BEGIN {Changing the various case conditions, and possibly the all_routines type (when adding or deleting routines), is all that is required when changing the segmentation structure.} CASE called_routine OF fileinit: IF segnum<>1 THEN BEGIN segload('BUS1 '); segnum:=1; END; rpprocess,szprocess: IF segnum<>2 THEN BEGIN segload('BUS2 '); segnum:=2; END; paprocess,ssprocess,questionprocess,ptprocess, stprocess,handleerror,cleanupfiles,prprocess: IF segnum<>3 THEN BEGIN segload('BUS3 '); segnum:=3; END; getcommand,defpartitions: IF segnum<>4 THEN BEGIN segload('BUS4 '); segnum:=4; END; END; {CASE} END; {segment_load} {break_program is a boolean function which is mapped onto the system library routine ifbrk. The routine merely calls ifbrk, and sets break_program true or false accordingly. It also sets abort true should the break flag be set.} FUNCTION break_program:boolean; $direct$ BEGIN IF ifbrk=0 THEN break_program:=false ELSE BEGIN break_program:=true; abort:=true; END; END; {set_error_path defines the appropriate error path when an error is detected, and input is from a command file.} PROCEDURE set_error_path; $direct$ BEGIN CASE error_path OF uncond_abort: abort:=true; uncond_end: build_ended:=true; OTHERWISE END; END; {set_error_path} {fmp_error is called whenever FMP returns an error code in ierr.} { ierr: FMP error code, passed by value, name: Name of file which had an associated error.} PROCEDURE fmp_error(ierr:integer;VAR name:string6); $direct$ CONST fmp='FMP '; on_file=' ON FILE: '; BEGIN writeln(ofile,star_error,fmp,ierr:5,on_file, name.file_name); IF echo_write THEN writeln(ifile,star_error,fmp,ierr:5,on_file, name.file_name); IF NOT interactive THEN set_error_path; END; {fmp_err} {pascl_errors catches all pascal runtime system generated errors. It is in a segment since the actual error handling routine (handle_error) aborts the program. The PASCAL runtime call uses .ENTR convention.} PROCEDURE pascl_error $ALIAS '@PREP'$ (err_type: error_type; err_number,err_line: integer; VAR err_file:input_line; err_flen:integer); BEGIN {Overlay any other segment. This is the last segload.} segment_load(handleerror); {Call actual error handler.} handle_error(err_type,err_number,err_line,err_file,err_flen); END;{pascl_error} {cnvrt_addr accepts an integer address and returns the record number (recnum) and its offset (starting at 1 for address 0) assuming the file concerned is a memory image, with no header.} { addr: integer address, passed by value, recnum: integer record numeer associated with address, returned, so passed by name, offset: integer offset within the record associated with the address, returned, so passed by name. } PROCEDURE cnvrt_addr(addr:integer; VAR recnum,offset:integer); $direct$ BEGIN recnum:=(addr DIV recd_len)+1; offset:=(addr MOD recd_len)+1; END; {cnvrt_addr} {getword is a function which is passed an address, and some parameters about the memory image file (no header),and returns the value stored at the passed address. The parameter curr_rec is used to prevent needless disk reads (when the current buffer contains the needed word).} { address: Address of word to be retrieved, passed by value, idcb: dcb of the memory image file the word is in, passed by name to achieve efficient parameter passing, ibuff: buffer associated with the above dcb. Type 1 file access bypasses the idcb. Passed by name for efficiency, name: file name where information exists. Used to pass fmp_error the name when errors occur. Passed by name, curr_rec: The current record number which had the information currently in ibuff, used to prevent needless disk reads. Passed by name since it may be modified.} FUNCTION getword(address:integer;VAR idcb:dcb; VAR ibuff:buffer; VAR name:string6;VAR curr_rec:integer):integer; VAR {integer type declarations.} ierr, {FMP error code identifier.} len, {Number of characters actually read by a readf.} offset, {Buffer offset of the desired word in the record.} recd:integer; {Record number which contains the desired word.} BEGIN cnvrt_addr(address,recd,offset); IF recd<>curr_rec THEN BEGIN {Its a miss. Get the correct record.} readf(idcb,ierr,ibuff,recd_len,len,recd); IF ierr<0 THEN fmp_error(ierr,name) ELSE curr_rec:=recd; END; IF ierr>=0 THEN getword:=ibuff[offset]; END; {getword} {putword stores the word at the passed address into the appropriate memory image file (no header). The word is actually stored onto the disk when the boolean ship is true, or when a record boundary is reached.} { word: Integer to be stored at the specified address, passed by value, address: Integer address where word is to be stored, passed by value, idcb: dcb of the memory image file the word is in,passed by name, ibuff: buffer associated with the above dcb. name: File name where the information is to be stored. Used to pass fmp_error the name when errors occur. Passed by name, curr_rec: The current record number which had the information currently in ibuff, used to prevent needless disk reads. ship: A boolean passed by value, when true, ibuff is written to the disk, when false, ibuff is only written to the disk if the offset is a record boundary.} PROCEDURE putword(word,address:integer; VAR idcb:dcb; VAR ibuff:buffer; VAR name:string6; VAR curr_rec:integer; ship:boolean); VAR {integer type declarations.} ierr, {FMP error code returned here.} len, {Actual number of characters read by a readf call.} offset, {Buffer offset of word to store.} recd:integer; {Record number associated with address.} BEGIN cnvrt_addr(address,recd,offset); IF recd<>curr_rec THEN BEGIN {Its a miss. Get the correct record.} readf(idcb,ierr,ibuff,recd_len,len,recd); IF ierr<0 THEN fmp_error(ierr,name) ELSE curr_rec:=recd; END; IF ierr>=0 THEN BEGIN ibuff[offset]:=word; IF ship OR (offset=recd_len) THEN BEGIN writf(idcb,ierr,ibuff,recd_len,recd); IF ierr<0 THEN fmp_error(ierr,name); END; END; END; {putword} {writline writes certain strings to the files.} { inline: The input line to be written. Passed by name for sake of efficiency.} PROCEDURE writline(VAR inline:input_line); $direct$ BEGIN writeln(ofile,inline); IF echo_write THEN writeln(ifile,inline); END; {writline} {error is the routine which prints out most of the error messages. message: The passed message. bool: A boolean which is set true if BUILD is not runing interactively.} PROCEDURE error(message:input_line); $direct$ BEGIN {Output the error. The entire message string is not output to prevent possible overflows. The entire message should be seen, however, since all errors have under 63 characters.} writeln(ofile,star_error,message:63); IF echo_write THEN writeln(ifile,star_error,message:63); IF NOT interactive THEN set_error_path; END; {error} {The main program now begins.} BEGIN {Load the segment containing the file initialization routine.} segment_load(fileinit); {Define the PASCAL file variables IFILE and OFILE, depending upon the run string. Prompt for any files not given in run string. Open the files, and check for error conditions concerning the snap and system files.} IF NOT break_program THEN file_init; {Define the partitions. The restart (/R command) returns the flow to a different point.} segment_load(defpartitions); {The loop is in case a /R is typed while defining partitions.} restart_partitioning:=true; WHILE restart_partitioning AND NOT (abort OR build_ended OR break_program) DO def_partitions; first_rp_process:=true; {Loop here until aborted or ended.} WHILE NOT (abort OR build_ended OR break_program) DO BEGIN {Call get_command. The routine merely outputs the build prompt, and calls line_read to get the string. The string will be in the global inline, and its parsed representation will be in namr_buffer. This is a routine so many library routines are in the segment, not in the main.} segment_load(getcommand); get_command; {Save the command for use by best_part.} user_command.chars:=namr_buffer.param1.command; WITH namr_buffer DO IF types.param1<>ascii THEN error(bad_type) ELSE {Handle the command cases.} IF param1.command='SS' THEN BEGIN segment_load(ssprocess); ss_process; END ELSE IF param1.command='/R' THEN BEGIN segment_load(defpartitions); restart_partitioning:=true; {The while loop is in case the user types /R during the partition definition phase.} WHILE restart_partitioning DO def_partitions; END ELSE IF param1.command='??' THEN BEGIN segment_load(questionprocess); question_process; END ELSE IF param1.command='PT' THEN BEGIN segment_load(ptprocess); pt_process; END ELSE IF param1.command='RP' THEN BEGIN segment_load(rpprocess); rp_process; END ELSE IF param1.command='PR' THEN BEGIN segment_load(prprocess); pr_process; END ELSE IF param1.command='SZ' THEN BEGIN segment_load(szprocess); sz_process; END ELSE IF param1.command='ST' THEN BEGIN segment_load(stprocess); st_process; END ELSE IF param1.command='PA' THEN BEGIN segment_load(paprocess); pa_process; END ELSE IF NOT (abort OR build_ended) THEN error(bad_command); END; IF build_ended THEN BEGIN {Call rp_process to take care of the last RP command (when specified.} segment_load(rpprocess); rp_process; END; {Close files, purge the BUILD image if aborted, and output the completion messages.} segment_load(cleanupfiles); cleanup_files; END. {BUILD}