$pascal '92071-1X339 REV.2041 800808'$ $heap 0$ $segment$ PROGRAM BUS3; { * *NAME: BUS3 *SOURCE: 92071-18339 *RELOC: 92071-16339 *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. * **************************************************************** } {BUS3 is loaded into memory after any phase 3 command but RP is detected. These commands include SZ,PT,PA, etc.} {Read in the global constants, variables and types.} $include '&BUGBL'$ {FMP call declarations.} PROCEDURE purge(VAR idcb:dcb; VAR ierr:integer; VAR name:string6; VAR isecu,icrn:integer);external; PROCEDURE fmp_close $ALIAS 'CLOSE'$(VAR idcb:dcb);external; PROCEDURE eclos(VAR idcb:dcb; VAR ierr:integer; itrun:doubint);external; {System resources declarations.} PROCEDURE cnumd(VAR int:integer; string:string6);external; {Non FMP externals contained in the main program are next.} PROCEDURE namr(VAR buffer:namr_parse_buffer; VAR inline:input_line; length:integer; VAR istrc:integer);external; FUNCTION getword(address:integer; VAR idcb:dcb; VAR ibuff:buffer; VAR name:string6; VAR curr_rec:integer):integer; external; PROCEDURE putword(word,address:integer; VAR idcb:dcb; VAR ibuff:buffer; VAR name:string6; VAR curr_rec:integer;post:boolean); external; PROCEDURE fmp_error(VAR ierr:integer; VAR name:string6); $direct$ external; PROCEDURE error(message:input_line)$direct$;external; PROCEDURE writline(line:input_line); $direct$ external; {Calls to system, or system resources.} PROCEDURE exec(ecode,place_holder:integer);external; PROCEDURE prtn(prams:prtn_prams);external; {warning is called to output a message when a warning is detected. All warnings are nonfatal of course, so no boolean need be set.} { message: String which describes the warning.} PROCEDURE warning(message:input_line);$direct$ CONST star_warning='*WARNING - '; BEGIN {The message string may be truncated to 60 characters for the same reason as in routine error.} writeln(ofile,star_warning,message:60); IF echo_write THEN writeln(ifile,star_warning,message:60); END; {warning} {handle_error handles certain forms of PASCAL errors, such as an FMP -6 on a command file. This is the only case which should, in theory, actually ever be trapped.} { err_type: Describes the class of the error condition. err_number: Some classes of errors have an associated number, passed in this paramater. err_line: Some classes of errors occur at a specific source line, and the line number is passed here. err_file: Some errors pass the PASCAL file name identifier as a paramater (i.e. fmp). Note that this paramater contains the internal (i.e. variable name) representation of the file name, not its actual external representation (i.e. namr). err_flen: Number of significant characters associated with err_file.} PROCEDURE handle_error (err_type: error_type; err_number, err_line: integer; VAR err_file: input_line; err_flen:integer); CONST runtime='PASCAL RUNTIME SYSTEM CODE # '; at_line=' AT LINE '; segl='SEGMENT LOAD FAILURE IN '; io_error='PASCAL IO SYSTEM CODE # '; VAR error_file:string6; {The name of the file in error.} ises, {Dummy param for loglu call.} i:integer; BEGIN {The file name is not always good. Try to detect this case and prevent garbage from being displayed.} IF err_flen=0 THEN error_file.file_name:=' ' ELSE FOR i:= 1 TO 6 DO error_file.file_name[i]:=err_file[i]; {Convert the file name from the internal representation (ifile or ofile) to its external name the user sees.} IF error_file.file_name='IFILE ' THEN error_file:=input_file ELSE IF error_file.file_name='OFILE ' THEN error_file:=output_file; {The error might be related to ifile or ofile. In this case, the attempt to write the error message could in turn result in another call to handle_error, which would then yield an infinite loop of errors. These next few lines do a pretty good job of preventing this problem, but the result is that these errors will only show up on the scheduling terminal.} {Ignore any warnings.} IF err_type<>warn THEN BEGIN echo_write:=false; close(ifile); close(ofile); rewrite(ofile,login_lu.file_name); CASE err_type OF fmp: fmp_error(err_number,error_file); seg: BEGIN {Output segment load error.} writeln(ofile,star_error,segl,error_file.file_name); END; io: BEGIN {These errors have their own code.} {Output the general case error message.} writeln(ofile,star_error,io_error,err_number:3); END; run: BEGIN {Runtime errors also have their own code.} write(ofile,star_error,runtime,err_number:3); writeln(ofile,at_line,err_line:5); END; END; {Case Statement.} {Abort the program with exec call. First give the abortion message.} writeln(ofile,build_prompt.five_char,aborted); {Cleanup stray files.} IF made_sys_file THEN purge(sys_dcb,ierr,sys_file,sys_secu,sys_crn); {Close the snap.} fmp_close(snap_dcb); {Return abort with prtn (recoverable by scheduling program via rmpar).} prtn('ABORTED '); {Exit with an exec call.} exec(6,0); END; {Fatal runtime error checks.} END;{handle_error} {cleanup_files is the last routine called by BUILD. It closes the BUILD system and snap file, and purges the BUILD file if the run was aborted (/A).} PROCEDURE cleanup_files; $direct$ BEGIN IF abort AND made_sys_file THEN purge(sys_dcb,ierr,sys_file,sys_secu,sys_crn); IF abort THEN BEGIN {Output message.} writeln(ofile,build_prompt.five_char,aborted); IF echo_write THEN writeln(ifile,build_prompt.five_char,aborted); {Set up abort return.} prtn('ABORTED '); END ELSE BEGIN {Set up the end return.} prtn('ENDED '); {Close the BUILD output file.} eclos(sys_dcb,ierr,((max_mem_size-mem_size)*recds_per_k) + roundoff_blocks); {Output the messages.} IF made_sys_file THEN BEGIN writeln(ofile,build_prompt.five_char,cmpleted); IF echo_write THEN writeln(ifile,build_prompt.five_char, cmpleted); writeln(ofile,bootable_sys_image,sys_file.file_name,'.'); IF echo_write THEN writeln(ifile,bootable_sys_image, sys_file.file_name,'.'); END; END; {Close the snapshot.} fmp_close(snap_dcb); {Close pascal opened files.} close(ifile); close(ofile); END; {cleanup_files} {ss_process changes the system security code into a new value.} PROCEDURE ss_process; $direct$ BEGIN namr(namr_buffer,inline,line_length,istrc); WITH namr_buffer DO IF NOT ((types.param1=numeric) OR (types.param1=ascii)) THEN error(bad_type) ELSE {Put the new code into the system.} putword(param1.int1,sec_addr,sys_dcb,sys_dcb.buff, sys_file,cur_sys_rec,true); END; {ss_process} {st_process defines the last rp'ed program as the startup program, and places its rmpar params into its id. Any previously defined startup program is processed by zeroing its rmpar paramater field.} PROCEDURE st_process; $direct$ VAR post:boolean; {Tells putword to post to disk.} i, {Loop index for changing rampar params.} cur_id_addr:integer; {Address of the current ID segment.} BEGIN IF first_rp_process OR rp_error THEN error(bad_command) ELSE BEGIN {Calculate the address of the next free id.} cur_id_addr:=id_addr+(cur_id_number-1)*idseg_length; {Put the address at $BOOT.} putword(cur_id_addr,start_addr,sys_dcb,sys_dcb.buff, sys_file,cur_sys_rec,true); post:=false; IF start_specified THEN {Zero out previous RMPAR paramaters.} FOR i:=1 TO 5 DO BEGIN IF i=5 THEN post:=true; putword(0,last_start_id_addr+i,sys_dcb,sys_dcb.buff, sys_file,cur_sys_rec,post); END; start_specified:=true; last_start_id_addr:=cur_id_addr; {Now fill in the correct, new, RMPAR paramaters.} FOR i:=1 TO 5 DO BEGIN namr(namr_buffer,inline,line_length,istrc); {Shove in ID regardless of type.} cur_idseg.ints[1+i]:=namr_buffer.param1.int1; END; END; END; {st_process} {question_process outputs the help facility in response to a ??.} PROCEDURE question_process; $direct$ CONST msg1= ' Commands which are valid in the present context are as follows:'; msg2= ' SS,newcode Change the system security code to newcode.'; msg3= ' PT Display a partition table which describes the'; msg4= ' size, location, and occupant of all partitions.'; msg5= ' RP,prog,[newname] Construct an id segment for the program (using'; msg6= ' newname if specified), relink the program if'; msg7= ' necessary, and load the program into memory.'; msg8= ' /R Restart BUILD at the partition definition phase.'; msg9= ' All partition and ID tables are zeroed.'; msg10= ' /E End the BUILD process.'; msg11= ' /A Abort the BUILD process. The output file made'; msg12= ' by BUILD is purged.'; msg13= ' The remaining commands modify the last RPed program (if any).'; msg14= ' PR[IORITY],n The program is to be of priority n.'; msg15= ' PA[RTITION],n Load the program into partition n.'; msg16= ' ST[ART][,p1]..[,p5] The program is to be the startup program'; msg17= ' with the specified optional RMPAR paramaters.'; msg18= ' SZ,nn Size of the program including system common (if'; msg19= ' used) in K words. When specified, this overrides'; msg20= ' the size as defined to the loader.'; BEGIN {Output the instructions, conditional upon the context.} writline(msg1); writline(msg2); writline(msg3); writline(msg4); writline(msg5); writline(msg6); writline(msg7); writline(msg8); writline(msg9); writline(msg10); writline(msg11); writline(msg12); {Skip a space for cosmetic reasons.} writeln(ofile); IF echo_write THEN writeln(ifile); {Output information about the RP modifiers.} writline(msg13); writline(msg14); IF NOT auto_partitioning THEN writline(msg15); writline(msg16); writline(msg17); writline(msg18); writline(msg19); writline(msg20); END; {pt_process outputs the occupants and sizes of all partitions defined so far in the BUILD process.} PROCEDURE pt_process;$direct$ CONST header= 'PRTN NUM LOW PAGE LENGTH OCCUPANT'; no_parts_defined='No partitions have been defined so far.'; none=''; VAR cur_id_addr, {Address of current id pointed to by the current MAT.} cur_mat_addr, {Address of current MAT being scanned.} last_mat_number, {Last sequential mat to scan.} length, {Length of current partition.} low_page, {Starting page number of current partition.} mat_number:integer; {Current mat number being scanned.} occupant:string6; {Name of occupant of partition.} BEGIN IF (auto_partitioning AND (first_rp_process OR (rp_error AND (num_matvs=0)))) THEN BEGIN {Automatic partitioning was selected, but no partitions have been defined. Output an indication of this fact to the user.} writeln(ofile,no_parts_defined); IF echo_write THEN writeln(ifile,no_parts_defined); END ELSE BEGIN {Output the header.} writeln(ofile,header); IF echo_write THEN writeln(ifile,header); {Initialize the loop starting and ending values.} IF auto_partitioning AND NOT rp_error THEN last_mat_number:=num_matvs+1 ELSE last_mat_number:=num_matvs; mat_number:=0; WHILE (mat_numbercur_mat_number) OR (NOT auto_partitioning) THEN BEGIN {Must look at the MAT on disk to get the information.} cur_id_addr:=getword(cur_mat_addr,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); length:=getword(cur_mat_addr+1,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec) + 1; low_page:=getword(cur_mat_addr+2,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); END; IF (mat_number=cur_mat_number) AND NOT rp_error THEN BEGIN {The needed information is mostly in memory. Handle this case specially since the next disk update occurs on the next rp_process call.} IF auto_partitioning THEN BEGIN {Get the MAT information from in memory information.} cur_id_addr:=0; length:=cur_idseg.id.size_less_1+1; low_page:=mem_size-rem_memory; END; {The program name is in the in memory id.} occupant.five_char:=cur_idseg.id.name; occupant.file_name[6]:=space1; END ELSE {Must go to disk to get the info since mat_number<>cur_mat_number.} BEGIN cur_id_addr:=getword(cur_mat_addr,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); length:=getword(cur_mat_addr+1,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec) + 1; low_page:=getword(cur_mat_addr+2,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); IF cur_id_addr=0 THEN occupant.file_name:=none ELSE WITH occupant DO BEGIN int1:=getword(cur_id_addr+12,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); int2:=getword(cur_id_addr+13,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); int3:=getword(cur_id_addr+14,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); file_name[6]:=space1; END; END; {Output information about this partition.} writeln(ofile,mat_number:8,low_page:10,length:8,space2, occupant.file_name); IF echo_write THEN writeln(ifile,mat_number:8,low_page:10,length:8,space2, occupant.file_name); END; END; END; {pt_process} {pa_process inserts a program into a specified partition as indicated by a PA command. The PA command is only acceptable if automatic partition construction was not requested.} PROCEDURE pa_process; $direct$ CONST in_use='PARTITION IN USE'; too_small='PARTITION IS TOO SMALL'; VAR cur_mat_addr, {The mat address of the specified partition.} cur_id_addr, {The id address field for the specified partition.} part_size_minus1: {The partition size less 1 from the MAT.} integer; BEGIN IF auto_partitioning OR first_rp_process OR rp_error THEN error(bad_command) ELSE BEGIN {Pick up the specified partition.} namr(namr_buffer,inline,line_length,istrc); IF namr_buffer.types.param1<>numeric THEN error(bad_type) ELSE IF (namr_buffer.param1.int1<1) OR (namr_buffer.param1.int1>num_matvs) THEN error(bad_range) ELSE WITH namr_buffer DO BEGIN {No errors so far. Pick up a few words from the MAT associated with the partition number.} cur_mat_addr:=mat_addr + mat_length*(param1.int1-1); cur_id_addr:=getword(cur_mat_addr,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); IF (cur_id_addr<>0) AND (param1.int1<>cur_mat_number) THEN {The partition is in use.} error(in_use) ELSE IF param1.int1<>cur_mat_number THEN BEGIN part_size_minus1:=getword(cur_mat_addr+1,sys_dcb, sys_dcb.buff,sys_file,cur_sys_rec); IF part_size_minus1numeric THEN error(bad_type) ELSE IF namr_buffer.param1.int1<1 THEN error(bad_range) ELSE cur_idseg.id.priority:=namr_buffer.param1.int1; END; END;.{pr_process,BUS3}