IMD 1.16: 1/06/2007 10:05:51 FOGCPM.173 --FOGCPM173JRTMAN 006 JRTMAN 006V-04-00 87 JRTMAN 007 !"#$%&'()*+,-JRTMAN 007./0123456789:;<=JRTMAN 007>?@ABCDEFGHIJKLMJRTMAN 007NOPQRSTUVWXYZ[\]JRTMAN 007j^_`abcdefghijk-CPM173 DOC JRTMAN 009lmnJRTMAN 100opqrstuvwxyz{|}~JRTMAN 100 JRTMAN 101LJRTMAN 103JRTMAN 103FThis is the disk name.  JRT Pascal User's Guide version 3.0 NOT FOR SALE -55- 6. Builtin procedures Several builtin procedures are provided in Pascal. Most of these relate to input/output processing and are dicussed in the input/output section of this manual. The remaining procedures are covered in this section. A list of them and their purpose follows. JRT Pascal extensions are marked with an asterisk. procedure purpose --------- --------- * CALL direct access to CP/M and BIOS * DELETE delete portion of dynamic string DISPOSE de-allocate dynamic variables * FILLCHAR initialize a string * INSERT insert string into dynamic string * MAP access main storage NEW alloccate dynamic variables * PORTOUT hardware port output * SYSTEM EXEC services Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -56- 6.1 CALL Format CALL( address, parameter_regs, returned_regs ); The CALL builtin procedure allows the user to make direct calls to the CP/M operating system, to your own Basic Input/Output System (BIOS), and to any machine language code present in main storage. The 8080 data registers can be directly setup for passing parameters to the module called. The 8080 data registers which are returned from the module may contain return values which can be used directly from Pascal programs. Note that this assembly language interface complements the external procedure assembler. User subroutines which must be written in assembler will usually be written as external procedures and assembled. That gives the advantage of fully automatic loading and relocation. CALL is intended primarily for direct access to the operating system services. The address field is an integer expression. This field is regarded as an unsigned 16-bit integer. When CALL is executed, control is transferred to the machine code at the address. The module there MUST return control to Pascal with a RET instruction. The 8080 stack MUST NOT be modified on return to Pascal. The 8080, 8085 and Z80 microcomputers have 7 one-byte data registers and a one-byte flag register. The Z80 has additional registers but these are not used in a CP/M environment. Six of the data registers can be grouped as two-byte registers for some uses.  8080 Register Map --------------------- ! A ! FLAGS ! --------------------- ! B ! C ! --------------------- ! D ! E ! --------------------- ! H ! L ! --------------------- Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -57- The parameter_regs and returned_regs fields have a particular format which must be declared in your program. The parameter_regs field is directly loaded into the microprocessor data registers before control is transferred to the called module. When control is returned to Pascal, the current data registers are stored into the field identified by returned regs. Both of these fields should be declared like this: TYPE DATA_REGISTERS = RECORD CASE INTEGER OF 1 : ( FLAG,A,C,B,E,D,L,H : CHAR ); 2 : ( PSW,BC,DE,HL : INTEGER ); END; This is a variant record which defines the data registers for access in one or two bytes at a time. For example, sometimes it may be necessary to regard the register pair DE as an integer, other times it may be necessary to treat register E alone as a single byte. Both definitions total 8 bytes. NOTE that in definition 1 above that the register names are in an unusual sequence. This is necessary because the 8080/Z80 microprocessors store 16 bit data in "byte-reverse" format. Examples: VAR PARM_REGS, RETURNED_REGS : DATA_REGISTERS;  CALL( 5, PARM_REGS, RETURNED_REGS ); 6.1.1 Calling the CP/M operating system An operating system is a program which provides services to application programs running under it. Some of these services are "create file", "write string to printer", "reinitialize system", and so on. Using the CALL builtin procedure the user can directly access these services from his Pascal programs. Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -58- The CP/M and MP/M User's Guides describe in detail the services provided and parameters required for each. Each service is identified by a one- byte function code. This code is stored in register C before control is transferred to CP/M. Many services also require an integer parameter such as an address in register pair DE. The entry point address for all CP/M compatible systems is location 5. At address 5 is stored a jump instruction to the actual CP/M module. The address of the BIOS (warm-start entry point) is stored at address 0001 in main storage and may be accessed with the MAP builtin procedure. The MAP and CALL procedures allow direct access to all of the services provided by the BIOS. Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -59- The service codes for CP/M 2.2 and MP/M are: code service ---- -------- 0 system reset 1 console input 2 console output 3 reader input 4 punch output 5 printer output 6 direct console input/output 7 get I/O byte 8 set I/O byte 9 print string 10 read console buffer 11 get console status 12 return version number 13 reset disk system 14 select disk 15 open existing file 16 close file 17 search for first file control block 18 search for next file control block 19 delete file 20 read sequential 21 write sequential 22 create file 23 rename file 24 return login vector 25 return current disk 26 set DMA address 27 get addr (alloc) 28 write protect disk 29 get read/only vector 30 set file attributes 31 get addr (disk parms) 32 set/get user code 33 read random record 34 write random record 35 compute file size 36 set random record 37 reset drive 40 write random with zero fill Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -60- The following services are available in MP/M only: code service  ---- -------- 128 absolute memory request 129 relocatable memory request 130 memory free 131 poll 132 flag wait 133 flag set 134 create queue 135 open queue 136 delete queue 137 read queue 138 conditional read queue 139 write queue 140 conditional write queue 141 delay 142 dispatch 143 terminate process 144 create process 145 set priority 146 attach console 147 detach console 148 set console 149 assign console  150 send CLI command 151 call resident system process 152 parse filename 153 get console number 154 system data address 155 get date and time Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -61- Examples: 1. (* GET THE VERSION NUMBER FROM CP/M *) PROCEDURE GET_VERSION; VAR PARM_REGS, RETURN_REGS : DATA_REGISTERS; BEGIN (* SET FUNCTION CODE := 12 *) PARM_REGS.C := CHR(12); CALL( 5, PARM_REGS, RETURN_REGS ); (* THE CP/M VERSION NUMBER IS RETURNED IN REGISTER L. IF REGISTER H IS 01 THEN THE OPERATING SYSTEM IS MP/M *) CASE ORD( RETURNED_REGS.H ) OF 0 : WRITE('CP/M '); 1 : WRITE('MP/M '); ELSE : WRITE('????'); END; WRITE(' VERSION '); CASE HEX$( RETURNED_REGS.L ) OF '00' : WRITELN('1.X'); '20' : WRITELN('2.0'); '22' : WRITELN('2.2'); ELSE : WRITELN( HEX$( RETURNED_REGS.L )); END; END; (* GET_VERSION *) 2. PROCEDURE WRITE_PROTECT_CURRENT_DISK; VAR PARM_REGS, RETURNED_REGS : DATA_REGISTERS; BEGIN PARM_REGS.C := CHR(28); CALL( 5, PARM_REGS, RETURNED_REGS ); END; Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -62- 3. PROCEDURE GET_USER_CODE; VAR PARM_REGS, RETURNED_REGS : DATA_REGISTERS;  BEGIN PARM_REGS.C := CHR(32); CALL( 5, PARM_REGS, RETURNED_REGS ); WRITELN('USER CODE = ',ORD( RETURNED_REGS.A )); END; 4. PROCEDURE SEARCH_FOR_FIRST ( NAME, TYPE : STRING[8] ); TYPE FILE_CONTROL_BLOCK = RECORD DISK : CHAR; FILENAME : ARRAY [1..8] OF CHAR; FILETYPE : ARRAY [1..3] OF CHAR; EXTENT : CHAR; S1, S2 : CHAR; RECORD_COUNT : CHAR; BLOCKS : ARRAY [1..16] OF CHAR; CURRENT_RECORD : CHAR; R0, R1, R2 : CHAR; END; VAR FCB : FILE_CONTROL_BLOCK; PARM_REGS, RETURNED_REGS : DATA_REGISTERS; BEGIN (* SET UP FCB *) FCB.DISK := CHR(0); FCB.FILENAME := NAME; FCB.FILETYPE := TYPE;  (* SET UP PARM_REGS *) PARM_REGS.C := CHR(17); PARM_REGS.DE := ADDR(FCB); CALL( 5, PARM_REGS, RETURNED_REGS ); (* TEST RETURN CODE *) IF RETURNED_REGS.A = CHR(255) THEN WRITELN('FILE NOT FOUND'); END; Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -63- 6.2 DELETE Format DELETE( string_variable, position, length ); The DELETE builtin procedure is used to delete a number of characters from a dynamic string variable. The first parameter refers to the string variable, NOT a string expression. The second parameter is an integer expression which indicates the first character to be deleted (characters in dynamic strings are numbered from 1). The third parameter is an integer expression which indicates the number of characters to be deleted. The hidden length field of the dynamic string variable is updated. If the position and length parameters refer to an area beyond the current length of the string, a run-time error occurs. Examples: DELETE( TARGET_STR, 25, 3 ); DELETE( STR1, POS( 'END', STR1), 3 ); DELETE( STR3, 9, X + 3 ); Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -64- 6.3 DISPOSE Format DISPOSE( pointer_variable ); The DISPOSE builtin procedure is used to de-allocate dynamic variables. The pointer-variable addresses a dynamic variable in dynamic storage. After execution of the procedure the space released is available for other uses. JRT Pascal supports true dynamic storage with auto-compression. When blocks are freed up, storage fragmentation tends to occur, i.e., small unused blocks tend to accumulate. Because many blocks tend to be small, they cannot be immediately reused for another purpose. When storage becomes short, an auto-compression is initiated by the Pascal system. In this process, all freed blocks are gathered into the center area of storage and all needed blocks are moved to the top of storage. In this way, storage fragmentation is totally eliminated. The DISPOSE procedure can be used to de-allocate ghost variables created by the MAP builtin procedure. Although ghost variables use no real storage, they do require a small amount of space in the pointer tables. Example: PROCEDURE DISPOSE_DEMO; TYPE  DYN_VAR = ARRAY [1..200] OF CHAR; VAR POINTER : ^DYN_VAR; BEGIN NEW( POINTER ); (* ALLOCATE A DYNAMIC VARIABLE *) (* DO SOME PROCESSING WITH THE DYNAMIC VARIABLE *) DISPOSE( POINTER ); (* FREE UP THE 200 BYTES *) END; Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -65- 6.4 FILLCHAR Format FILLCHAR( structured_variable, length, character ); The FILLCHAR builtin procedure is a very fast and simple way to initialize a structured variable (array or record) to a character. The length parameter is an integer expression which indicates the number of bytes to be initialized. The entire variable from its first byte up to the length specified is set to the character expression value. CAUTION - This is a hazardous procedure since the run-time system cannot verify that the initialization by character has not run past the end of the variable and perhaps overlayed other variables or program code. Examples: FILLCHAR( VECTOR, 160, CHR(0) ); FILLCHAR( PRODUCT_ARRAY, 2500, '*' ); Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -66- 6.5 INSERT Format INSERT( source_string, target_string_variable, position ); The INSERT builtin procedure inserts the source string expression into the target string variable at the indicated position. The source string may be a literal string or other string expression.  The target string must be an actual variable. The source string is inserted into the target variable beginning at the character indicated by the integer expression position. If the combination of parameters would cause the target string to overflow its maximum length or if position is less than 1, a run-time error occurs. Examples: INSERT( 'ABCD', STR1, 15 ); INSERT( FILENAME, MASK, 1 ); STR1 := 'MERE FACTICITY.'; INSERT( 'TRUTH IS NOT ', STR1, 1 ); Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -67- 6.6 MAP Format MAP( pointer_variable, address ); The MAP procedure allows the user to access any part of the computer's storage. It uses the facilities of the dynamic storage system and pointer variable to, in effect, overlay a map on any area of storage. This is sometimes called a "dsect" or "ghost variable". Unlike its close relative, the NEW procedure, MAP does not actually allocate a dynamic storage block. Instead of obtaining a storage block and setting the pointer variable to point at it, it lets the user specify the address. The address can be anywhere from 0 to 0FFFFH. Like the NEW procedure, MAP does require five bytes of pointer table space. When the ghost variable is no longer needed, it can be removed from the table with the DISPOSE procedure. Examples: 1. (* ACCESS A 24 X 80 VIDEO TERMINAL *) (* IT IS A MEMORY-MAPPED MODEL WITH ITS *) (* VIDEO SCREEN BEGINNING AT 0F000H *) TYPE SCREEN = ARRAY [1..24, 1..80] OF CHAR;  VAR CRT : ^SCREEN; BEGIN MAP(CRT, 0F000H ); (* CLEAR THE SCREEN *) CRT^ := ' '; (* WRITE MESSAGE ON TOP LINE OF CRT *) CRT^[1] := 'MEMORY MAPPED CRT EXAMPLE'; ... END; Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -68- 2. (* OBTAIN THE ADDRESS OF THE USER BIOS. *) (* JMP INSTRUCTION AT ADDR 0 ADDRESSES *) (* THE WARM-START ENTRY POINT IN BIOS *) FUNCTION BIOS : INTEGER; VAR PTR : ^INTEGER; BEGIN MAP( PTR, 1 ); BIOS := (PTR^ -3); (* START OF BIOS *) END; 3. (* SET THE IOBYTE AT ADDR 3 TO NEW VALUE *) PROCEDURE SET_IOBYTE ( X : CHAR ); VAR PTR : ^CHAR; BEGIN MAP( PTR, 3 ); PTR^ := X; DISPOSE( PTR ); END; Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -69- 6.7 NEW Format 1 NEW( pointer_variable ); Format 2 NEW( pointer_variable, tag1,...,tagn ); The NEW procedure allocates new dynamic variables. A block of dynamic storage of the required size is obtained. The block's virtual address (not its actual address) is stored in the pointer table. Virtual addressing and dynamic storage are fully explained in the section on storage management in this manual. After NEW has been executed, the dynamic variable may be accessed. Dynamic variables remain allocated until specifically de-allocated by the DISPOSE procedure. If a procedure uses NEW to allocate a dynamic variables, that variable remains allocated after the procedure ends. Format 2 contains 1 to n tag fields. These are the fields specified in the CASE clause of variant records. Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -70- Example: (* PROGRAM FRAGMENT TO ALLOCATE A *) (* LINKED LIST OF VARIABLE LENGTH. *) (* THE ROOT OF THE LIST IS A GLOBAL *) (* VARIABLE. NODES AFTER THE FIRST *) (* ARE INSERTED BETWEEN THE ROOT AND *) (* THE FIRST NODE. *) TYPE NODE = RECORD  NEXT : INTEGER; DATA : STRING[300]; END; VAR ROOT : ^NODE; PROCEDURE LINKED_LIST ( COUNT : INTEGER ); VAR I : INTEGER; TEMP : ^NODE; BEGIN (* ALLOCATE FIRST NODE *) NEW( ROOT ); (*SET END_OF_LIST INDICATOR *) ROOT^.NEXT := NIL; (* ALLOCATE LINKED LIST *) FOR I := 1 TO COUNT DO BEGIN NEW( TEMP ); TEMP^.NEXT := ROOT; ROOT := TEMP; END; END; (* LINKED_LIST *) Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE  -71- 6.8 PORTOUT Format PORTOUT( port_number, byte ); The PORTOUT procedure writes a byte directly to one of the hardware output ports. The port_number is an integer expression. The byte is a string or char expression. Examplels: PORTOUT( MODEM, START_CHAR ); PORTOUT( VOICE_SYNTHESIZER, 'A' ); PORTOUT( FIRE_ALARM, RESET ); PORTOUT( TELETYPE, CHR(7) ); PORTOUT( 15H, CHR( 3 + X )); Copy compliments of Merle Schnick SECTION 6: Builtin Procedures JRT Pascal User's Guide version 3.0 NOT FOR SALE -72- 6.9 SYSTEM Format SYSTEM( option ); The SYSTEM procedure allows the user to control the trace facililties, the routing of console output, dynamic storage compression and warning messagges. The options for SYSTEM are listed below. The default states of the JRT Pascal system are indicated with an asterisk: option purpose ------- -------- * CONS route output to console NOCONS no output to console LIST route output to printer * NOLIST no output to printer * WARNING display warning messages NOWARNING suppress warning messages LTRACE activate line trace * NOLTRACE disable line trace LRANGE,l,u set line range for line trace PTRACE activate procedure trace * NOPTRACE disable procedure trace INITIALIZE re-initialize disk system  after disk switch COMPRESS compress dynamic storage The LRANGE option requires two additional parameters. The lower and upper line numbers are integer expressions. Examples: SYSTEM( LIST ); SYSTEM( NOWARNING ); SYSTEM( LRANGE, 250, 300 ); SYSTEM( COMPRESS ); Copy compliments of Merle Schnick SECTION 6: Builtin Procedures M( LIST ); SYSTEM( NOWARNING ); SYSTEM( LRANGE, 250, 300 ); SYSTEM( COMPRESS ); Copy compliments of Merle Schnick LRANGE,l,u set line range for line trace PTRACE activate procedure trace * NOPTRACE disable procedure trace INITIALIZE re-initialize disk system   JRT Pascal User's Guide version 3.0 NOT FOR SALE -73- 7. Input/output JRT Pascal includes a powerful input/output subsystem which can be used to meet virtually any processing requirement. Three modes of input/output - console, sequential disk, random disk - are provided. Disk files can be processed in either TEXT mode or in BINARY mode. TEXT mode is most commonly used by BASIC languages. Data is stored in ASCII text readable format. BINARY mode is found on larger mini and mainframe computers. The data is input/output in the binary format used internally by the language. Not only is the data more compact in some cases but it is also of fixed length. For example, an integer in text format could occupy from two bytes to six bytes, depending on its value. But in binary format an integer is always exactly two bytes. TEXT mode is sometimes called "stream I/O". BINARY mode is sometimes called "record I/O". Another advantage of binary format is that the user can process data files or COM files containing special control characters. All files in JRT Pascal are "untyped". That is, the user can read and write data of any format to any file. The user can write records of entirely different formats and sizes on the same file. JRT Pascal also supports direct access to the hardware input/output ports without having to write an assembly language subroutine. The builtin function PORTIN and builtin procedure PORTOUT are described in the sections on builtin functions and builtin procedures. JRT Pascal version 3 now supports Pascal file variables. Files may now be passed as parameters to procedures, allocated locally in procedures, be used in records or arrays, be used in assignment statements. The Pascal builtin procedures GET and PUT are now supported. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -74- 7.1 Console input/output Console input/output is the usual means for a program to interact with the user. Data values can be displayed at a video terminal or teletype and data can be keyed in. Console input/output always occurs in text rather than binary format. Integers, real numbers, strings, characters and Booleans will be displayed in text format. Set variables have no meaningful text format and cannot be written to the console. IMPORTANT - Since the console is regarded as a text device, data items are delimited by commas, spaces, tabs and semicolons. To read one character at a time, use this function: FUNCTION GET_CHAR : CHAR; VAR R : RECORD FLAG,A,C,D,E,D,L,H : CHAR; END; BEGIN R.C := CHR(1); CALL( 5,R,R ); GET_CHAR := R.A END; Using the HEX$ builtin function, any variable can be converted to hex format for direct display. On console input for integers, data may be keyed in using standard decimal format or in hex format. An 'H' character suffix indicates hex format. On input to the console, data items may be separated by spaces, tabs, commas or semicolons. Character or structured variable inputs which contain special characters may be entered in single quotes. The quote character itself may be entered by doubling it. Sample input lines: 3.14159,77 03ch,'JRT Systems' 'don''t say you can''t' 6.70234e-25,0.0000003 Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -75- Reading from the console into a dynamic string variable is treated differently. An entire line of text is obtained from the console and moved directly into the string variable. Separator characters and single quotes are ignored. The system will not allow more characters to be keyed in than can fit into the variable in the READ's parameter list. Console output can also be routed to the printer or list device. The SYSTEM procedure is fully described in the section on builtin procedures. Some of its options are: SYSTEM( LIST ); route output to printer SYSTEM( NOLIST ); do not route to printer SYST EM( CONS ); route to console device SYSTEM( NOCONS ); do not route to console The builtin procedures/functions used in console input/output are: READ, READLN read data into storage WRITE, WRITELN write data to console/printer EOLN end of line function Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -76- 7.2 Sequential file processing Disk files are not inherently sequential or random. Those terms apply to the means of access which may be applied to any disk file. Sequential file processing is generally faster than random access because input/output can be buffered and because the disk positioning mechanism only needs to move short distances. JRT Pascal lets the user obtain maximum processing speed by defining the buffer size for sequential files. The buffer is the holding area where disk data is loaded and written. This area is filled or emptied in one burst - one disk access with one head load operation. A very small buffer may cause disk "chattering" during processing because of frequent accesses. A large buffer will result in less frequent but longer disk accesses. The buffer size is specified as an integer expression in the RESET or REWRITE procedure. It will be rounded up to a multiple of 128. If storage is plentiful, buffers of 4096 or 8192 bytes will improve processing. The builtin procedures/functions used in sequential disk file processing are RESET open file for input REWRITE open file for output CLOSE terminate file processing READ, READLN read data into storage WRITE, WRITELN write data to disk EOF end of file function EOLN end of line function ERASE delete a file RENAME rename a file Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -77- This sample program reads in a file and dumps it in hex format to the console: PROGRAM DUMP; TYPE BLOCK = ARRAY [1..16] OF CHAR; NAME = ARRAY [1..14] OF CHAR; VAR B : BLOCK; DUMP_FILE : FILE OF BLOCK; FILENAME : NAME; BEGIN WHILE TRUE DO (* INFINITE LOOP *) BEGIN WRITE('enter filename : '); READLN( FILENAME ); RESET( DUMP_FILE, FILENAME, BINARY, 4096); WHILE NOT EOF( DUMP_FILE ) DO BEGIN READ( DUMP_FILE; B); WRITELN( HEX$(B) ); END; CLOSE( DUMP_FILE ); WRITELN; END; END. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -78- 7.3 Random file processing CP/M version 2.2 or higher is required to use JRT Pascal random file processing.  For many types of processing it is not known in advance in which sequence the records of a file will be needed. A spelling dictionary or online inquiry customer database obviously must use random access files. In JRT Pascal, random access is fully supported. Data can be read and updated by providing the relative record number (RRN) within the file for fixed length records. The first record is at RRN=0. For variable length records, the data can be read or updated by providing the relative byte address (RBA). The RBA is the location of the data item within the file. The first byte is at RBA=0. The RBA mode of processing gives much greater flexibility than RRN. If all records had to be the same size, then all would have to be the size of the largest, resulting in much wasted space and slower access. Beginning with JRT Pascal version 2.1, random files up to the   CP/M maximum of 8 megabytes are supported. The RBA or RRN value may be an integer or a real expression. Programs written under earlier versions are source code compatible but must be recompiled using the version 2.1 or later compiler. The procedures used in random file processing are: OPEN open or create random file CLOSE terminate file processing READ read data into storage WRITE transfer data to disk ERASE delete a file RENAME rename a file A sample program shows random access to a file containing sales information for the various departments of a retail store. The records are located by department number. Copy compliments of Merle Schnick SECTION 7: Input/output  JRT Pascal User's Guide version 3.0 NOT FOR SALE -79- Sample program: PROGRAM INQUIRY; LABEL 10; TYPE DEPT_RECORD = RECORD INVENTORY : REAL; MTD_SALES : REAL; YTD_SALES : REAL; DISCOUNT : REAL; END; VAR INPUT_AREA : DEPT_RECORD; DEPT_FILE : FILE OF DEPT_RECORD; DEPT : INTEGER; BEGIN (* INQUIRY *) OPEN( DEPT_FILE, 'C:DEPTDATA.RND', BINARY ); REPEAT WRITE('Enter dept number : '); READLN( DEPT ); IF DEPT = 999 THEN GOTO 10; (* EXIT *) READ( DEPT_FILE, RRN, DEPT; INPUT_AREA ); WRITELN; WRITELN('dept ',DEPT,  ' inv ',INPUT_AREA.INVENTORY:9:2, ' disc ',INPUT_AREA.DISCOUNT:9:2); WRITELN(' MTD sales',MTD_SALES:9:2, ' YTD sales',YTD_SALES:9:2); WRITELN; 10: (* EXIT LABEL *) UNTIL DEPT = 999; CLOSE( DEPT_FILE ); END (* INQUIRY *). Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -80- 7.4 Indexed file processing CP/M version 2.2 or higher is required to use JRT Pascal indexed file processing. Beginning with version 3.0, JRT Pascal provides full support for indexed files. The index file system is implemented as 2 external procedures so that it occupies no main storage when it is not being used. Indexed files consist of two separate disk files: the main data file with a filetype of DAT and an index file with the filetype of IX0. The indexed file system has 3 components. INDEX0 external procedure performs most of the functions. INDEX1 external procedure compresses the data files and rebalances the indexes. The INDEX2 program is executed by itself and reorganizes the files for more efficient access. The external procedure INDEX0 performs these operations: A add a new record B read first record (beginning) C close file D delete a record F flush buffers, close and reopen files N new file allocation O open file Q query whether indexes should be balanced R read a record S read next record in sequence U update a record  W issue a warning Z turn off warning message INDEX1 performs these operations: J rebalance the indexes K compress data file and balance indexes Records must all be the same size - from 16 to 2048 bytes. They need not be a multiple of 128 bytes. The maximum number of records depends on the key size: Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -81- (1024 DIV (KEY_SIZE +3)) * 256 key size max records ________ ___________ 4 32767 <--- Not more than 32767 6 28928 records ever allowed 8 23808 15 14336 The maximum number of records should be s et to somewhat less than the maximum theoretical number of records, to prevent the loss of a record when adding to an unbalanced file. Note also that the file of indexes will be 257k when the maximum number of records are entered, so a reasonable (high) estimate should be used for the maximum number of records. IMPORTANT - No key should contain all zeroes, since a zero key is used to indicate deleted keys and records. The key must be the first field in each record. The key size may be from 2 to 32 bytes. A utility program INDEX2 is provided to reorganize the data file and generate new index files. 7.4.1 Index file format The index file is divided into one primary index and up to 256 secondary indexes. Each index block is 1024 bytes. The primary index contains 256 4-byte fields. Each of these is the first 4 bytes of the lowest key in a secondary index. The secondary indexes contain actual key values and 3-byte record loacator fields. The number of keys per secondary index is: 1024 DIV (KEY_SIZE +3) Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -82- 7.4.2 Data file format The data file consists of a 1024 byte control record followed by the data records. The control record contains the filename, maximum record count, current record count, key size, record size, delete count, and deleted record list. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -83-  Index file format !-------------------------------! ! ! 1 K blocks ! primary index ! !-------------------------------! ! ! ! ! !----- up to 256 --------! ! ! ! secondary indexes ! !----- --------! ! ! ! ! !-------------------------------! Data file format !-------------------------------!  ! ! ! control record 1 K ! !-------------------------------! ! ! ! ! ! ! ! ! ! data records ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  ! ! ! ! ! ! !-------------------------------! Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -84- 7.4.3 Using INDEX0 The indexed file system is implemented in an external procedure named INDEX0. To access it, these declarations are required in your main program: TYPE KEY_TYPE = -------------- { your key type declarations } RECORD_TYPE = ----------- { your record type declarations } INDEX_RECORD = RECORD DISK : CHAR; FILENAME : ARRAY [1..8] OF CHAR; RETURN_CODE : INTEGER; R ESERVED : ARRAY [1..200] OF CHAR; END; PROCEDURE INDEX0 ( COMMAND : CHAR; VAR KEY : KEY_TYPE; VAR DATA : RECORD_TYPE; VAR IR : INDEX_RECORD ); EXTERN; To use INDEX0 the index_record must be initialized with the filename and disk on which the file is located. The return code is set by INDEX0 and indicates if each operation was successfully completed. Warning messages may optionally be issued, see command 'W'. An indexed file must be allocated before it can be opened or used in any way. Each time INDEX0 is called, a valid command code must be passed. The key, data, and ir parameters are also required, although key and data will not be used by every command. It is allowed to have multiple indexed files open at the same time. Each one is indentified by a different index_record. The index record (IR) should be set to blanks before individual fields are initialized. For a given index file, the first call to INDEX0 in a program should be to open ('O') or create ('N') the index and data files. (INDEX0 can be called with the 'W' first, so that error messages will be printed.) Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -85- 7.4.4 INDEX commands Commands J and K are processed by INDEX1. All others are processed by INDEX0. A add a new record - insert a new key into index, if duplicate key exists, abort operation - write new data record to data file B read first record (begin) - read the first record (in sorted order) - returns key and record C close indexed files - this MUST be done on completion of processing or newly written data may be lost D delete a record - nullify key entry for record - add record locator to delete list F flush buffers, close and reopen files - flush buffers that have changed - close files to preserve changes J rebalance indexes (INDEX1) - uses temporary file - deletes old index file - renames new index file K rebalance indexes and compact data file (INDEX1) - uses temporary files - deletes old index and data files - renames new index and data files - reopen files for further processing N new file allocation - program will inquire at the console the parameters of the new indexed file 1. record size in bytes 2. key size in bytes 3. maximum number of records to be allowed; the index file will be allocated based on this number Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -86- - index files are left open for further processing - files must be closed (or flushed) to preserve the new contents O open indexed files - open the index and data files - load the primary index into dynamic  storage Q query data base status - return 'Y' in key[1] if the data base should be reorganized ('J') - else return 'N' in key[1] R read a record - search the indexes for the key - read the data record into the user's record variable S read next record in sequence - will read next record after a previous 'B', 'R', 'S', or 'U' U update a record - the update operation MUST ALWAYS be preceded by a read operation with the same key - write modified record to data file W warning messages - turn on the warning message feature - caused non-zero return codes to print verbal error messages Z turn off warning messages Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -87- 7.4.5 INDEX return codes 0 successful completion 1 duplicate key 2 maximum number of records exceeded 3 key not found 4 update key does not match read key or previous read was not successful 5 key value does not match key in record 6 second open or new without closing previous file 7 invalid command (eg. 'M' or an 'S' without a preceeding 'B', 'R', 'S', or 'U') 8 file not open 9 serious error ( no specific message ) 7.4.6 Balanced indexes Searching for records is usually very efficient, both in random and sequential modes. Adding to a data base is usually efficient until one or more of the secondary indexes gets full. (If records are added in sorted order, then the addition process will be very efficient.) INDEX0 will not automatically "balance" keys in the index files, so that additions fill up the secondary indexes. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -88- Your program can "Query" the status of an indexed file by using 'Q' in a call to the index. The first letter of the key will be set to 'Y' if the indexes should be balanced, and 'N' if that is not necessary yet. (INDEX0 decides that the indexes should be balanced when an add ('A') must move a secondary index from one block to another). Reorganizing indexes To reorganize an indexed file so that adding new records will be efficient, set the record argument to all blanks and call INDEX1 with command 'J' (for adJust or Justify). INDEX1 will create a new balanced index file on the same disk as the current index file. There must be space for the new index file, which will be called name.$$I. INDEX1 will then delete the old .IX0 file and rename the new file to name.IX0. Reorganization takes 2500 to 3200 bytes of space in main memory as well as space on the disk, so it is never done automatically. INDEX1 must be declared as an external procedure (just as INDEX0 was declared) if your program is going to balance indexes "on the fly". PROCEDURE INDEX1 ( COMMAND : CHAR; VAR KEY : KEY_TYPE; VAR DATA : RECORD_TYPE; VAR IR : INDEX_RECORD ); EXTERN; INDEX1 supports the J and K operations which are described in section 7.4.4. In general, the record variable should be set to all blanks before INDEX1 is called. 7.4.7 INDEX2 utility Type EXEC INDEX2 to rebalance the indexes in the file and to compact the data after many deletions. INDEX2 will ask for the name of the disk drive containing the indexed files (A to P), the name of index files (which you would enter without any '.' or '.DAT' or '.IX0'), and the name of the compacted files. You can have the new files put on the same or another disk drive as the original files. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -89- INDEX2 will also ask for a new number of maximum records. If you enter 0, the previous maximum will be used.  Compressing data from within a program INDEX2 uses INDEX0 and INDEX1 to perform the actual indexed file accesses. Highly sophisticated programs can also use INDEX1 to compact the data file as well as balance the indexes. Call INDEX1 with the command 'K' (kompress) to do a complete reorganization. If the record argument is set to all blanks, then the same disk drive and same maximum record count will be used in creating the new data base copies. If the record argument is given the following structure, then alternate disk drives or a different maximum number of records can be set. VAR new_param : RECORD new_disk_flag : CHAR; new_disk : CHAR; max_nr_flag : CHAR; max_nr_rec : INTEGER; old_leave : CHAR; END; Set new_param.new_disk_flag to 'Y' if new_param.new_disk contains another disk drive letter (such as 'C'). Set new_param.max_nr_flag to 'Y' if new_param.max_nr_rec contains a new maximum number of records, such as 2000. The new_disk_flag only works with the 'K' option. The old_leave flag only works with the 'K' option when a new_disk is specified. When the 'K' option is used, the record passed must be big enough to hold records read from the disk. You might want to assign rec to contain new_param, and then call INDEX1, for example Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -90- rec := new_param; INDEX1 ('K',key, rec, ir); Most programs will not need to use the 'K' option, since the equivalent can be done as needed by having the user issue the CP/M command EXEC INDEX2, preferably after the data bases have been copied to backup disks. 7.4.8 Efficiency notes Reading records from the data base is only slow when very many keys have the same first four characters. If the indexes in more than one secondary index block have the same first four characters, INDEX0 may have to search more than one secondary index block to find a given record. Generally, this will not occur. Random output in general under CP/M is inefficient due to buffering requirements. Random output will be most efficient with double density disks with 1K blocks or with single density disks with 128 blocks. Maximum number of records The maximum number of records should be set to somewhat (50 to 200) less than the theoretical maximum. If, for example, 8-byte keys are declared with up to 23808 records, 256 records are entered, the indexes are balanced (with 'J'). There will now be 256 secondary indexes blocks with one key each. Then, if 92 records are added with key greater than the 256th record, the last secondary index will be full. Since one secondary index block can hold 93 8-byte keys, adding a 93rd key larger than the 256th will "overflow" the top secondary index block. A serious error. Currently, the maximum number of records is 32767 for index files with 2-, 3-, and 4-byte keys. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -91- 7.4.9 Sample indexed file program The following simple program will let you create, add to, query, close, and search any data base. It assumes that the record and the key are  alphanumeric (printable) information. You can enter individual commands to the program, which will call INDEX0 (or INDEX1) to perform the equivalent command. The runtime example that follows the listing of TSTINDEX shows the creation of a simple address file, with 16 character search keys and (one line) addresses up to 80 characters long. The resulting records are then 96 bytes long. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -92- PROGRAM tstindex; TYPE key_t = ARRAY[1..256] of CHAR; rec_t = ARRAY[1..2048] of CHAR; ctrl_rec = RECORD c_1 : ARRAY[1..4] of INTEGER; rec_size : INTEGER; c_2 : INTEGER; key_size : INTEGER; end; index_record = RECORD disk : CHAR; filename : ARRAY[1..8] of CHAR; return_code : INTEGER; res_1 : INTEGER; ctrl : ^ctrl_rec; reserved : ARRAY[1..196] of CHAR; END; VAR key : key_t; rec : rec_t; cmd : CHAR; ir : index_record; tem_d : ARRAY[1..2048] of CHAR; PROCEDURE INDEX0 ( command : CHAR; var key : key_t; var rec : rec_t; var ir : index_record ); extern; PROCEDURE INDEX1 ( command : CHAR; var key : key_t; var rec : rec_t; var ir : index_record ); extern; Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0  NOT FOR SALE -93- BEGIN (* tstindex *) ir := ' '; write('Disk: '); readln(ir.disk); write('File: '); readln(ir.filename); REPEAT write('cmd: '); readln(cmd); cmd := upcase(cmd); key := ' '; rec := ' '; IF (cmd in ['A', 'D', 'R', 'U']) THEN BEGIN write('key: '); readln(key); IF (cmd in ['A', 'U'] THEN BEGIN write('data: '); readln(tem_d); rec := copy(key, 1, ir.ctl^.key_size) + copy(tem_d, 1, ir.ctl^.rec_size - ir.ctl^.key_size); END; END; (* justify or kompress must call INDEX1 *) IF (cmd in ['J', 'K'] THEN BEGIN rec := ' '; INDEX1(cmd, key, rec, ir); END ELSE INDEX0(cmd, key, rec, ir); IF (ir.return_code <> 0) THEN BEGIN writeln('Error:', ir.return_code); END; IF (cmd = 'Q') THEN writeln('query result: ',key[1]); IF (cmd in ['B', 'R', 'S']) THEN BEGIN writeln('key: ', copy(rec, 1, ir.ctl^.key_size)); writeln('data: ', copy(rec, ir.ctl^.key_size + 1, ir.ctl^.rec_size - ir.ctl^.key_size)); END; UNTIL (cmd = '?'); END. (* tstindex *) Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -94- Execution of TSTINDEX is shown for a simple data base with 16 character names and up to 96 characters of information (which happens to be addresses). Note that the key length and record length are entered from the terminal in the N command. A>EXEC B:TSTINDEX Exec ver 3.0 Disk: B File: ADDRESS cmd: W cmd: N Record size in bytes: 96 Key size in bytes: 16 Maximum number of records: 500 cmd: A key: JRT data: 'JRT Systems/45 Camino Alto/Mill Valley, CA 94941' cmd: A key: OLD data: 'Old JRT Office/550 Irving St/SF, CA 94122' cmd: B key: JRT data: JRT Systems/45 camino Alto/Mill Valley, CA 94941 cmd: S key: OLD data: Old JRT Office/550 Irving St/SF, CA 94122 cmd: S %INDEX error: Key not found Error: 3 cmd: a key: LITTLE data: 'Little Italy/4109 24th St/SF, CA 94114' cmd: a key: SZECHWAN data: 'Szechwan Court/1668 Haight St/SF, CA 94117' cmd: f cmd: r key: JRT key: JRT data: JRT Systems/45 Camino Alto/Mill Valley, CA 94941 cmd: r key: OTHER %INDEX error: Key not found return code 3 cmd: z Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -95- cmd: ? Error: 7 Program termination Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -96- 7.5 CLOSE Format CLOSE ( file_variable ); The CLOSE builtin procedure terminates processing against a sequential or random disk file. If a sequential output file is not properly closed, the data written out will be lost because CLOSE updates the disk directory. This procedure also releases storage reserved for input/output buffers of sequential files. Examples: CLOSE ( F1 ); CLOSE ( DATA_FILE ); CLOSE ( MASTER_CUSTOMER_REPORT ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -97- 7.5.1 EOF Format EOF ( file_variable ); The end of file function indicates when the end of a file is reached during input processing. It returns a Boolean value of true immediately after end of file detection, otherwise it returns false. The EOF function has no meaning in console or random disk processing. When processing a file in text mode, end of file is detected when all data up to the first CTRL-Z (1AH) has been read. This is the standard character to indicate the end of data. When processing a file in binary mode, end of file is detected when all the data in the last allocated sector of the file has been read. Examples: 1. (* COMPUTE THE AVERAGE OF A FILE OF NUMBERS *) RESET( F1, 'DAILY.SAL', TEXT, 4096); TOTAL := 0; COUNT := 0; WHILE NOT EOF(F1) DO BEGIN READ(F1; DAILY_SALES); TOTAL := TOTAL + DAILY_SALES; COUNT := COUNT + 1; END; AVERAGE := TOTAL / COUNT; CLOSE( F1 ); 2. (* WRITE A FILE TO THE PRINTER *) SYSTEM( LIST ); RESET( F1, 'TEST.PAS', BINARY, 2048 ); READ(F1; CH); (* INSTEAD OF USING EOF, WE DIRECTLY TEST FOR A CHARACTER 1AH, SINCE THIS IS BINARY FILE *) WHILE CH <> CHR(1AH) DO BEGIN WRITE( CH ); READ(F1; CH); END; CLOSE( F1 ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -98- 7.6 EOLN Format 1 EOLN ( file_variable ); Format 2 EOLN; The end of line function returns a Boolean value true if the end of line is reached, otherwise it returns false. This function applies only to console and text files, not to binary files. Format 1 is used to sense end of line while reading disk files. Format 2 is used to sense end of line in console input. This function is used primarily to read in an unknown number of data items from a line of text. Executing a READLN, with or without any parameters, always resets EOLN to false and positions the file at the start of the next line of text. Examples: 1. (* READ NUMBERS FROM CONSOLE, COMPUTE AVG *) TOTAL := 0; COUNT := 0; WHILE NOT EOLN DO BEGIN READ( NUMBER ); TOTAL := TOTAL + NUMBER; COUNT := COUNT + 1; END; READLN; AVERAGE := TOTAL DIV COUNT; 2. (* READ DATA FROM FILE, COUNT LINES OF TEXT *) LINE_COUNT := 0; WHILE NOT EOF(F1) DO BEGIN READ(F1; DATA_ITEM); PROCESS_DATA( DATA_ITEM ); IF EOLN(F1) THEN BEGIN LINE_COUNT := LINE_COUNT + 1; READLN(F1) END;  END; Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -99- 7.7 ERASE Format ERASE ( filename ); The ERASE procedure deletes files from the disk. It can be used to delete files from any available disk by including the disk identifier in the filename. ERASE is implemented as an external procedure. Any program referencing it must include it declaration: PROCEDURE ERASE ( NAME : STRING[20] ); EXTERN; Examples: ERASE( 'TESTPGM.PAS' ); ERASE( CONCAT( 'B:', FILENAME, FILETYPE ) ); ERASE( 'A:' + NAME + '.HEX' ); ERASE( BACKUP_FILE ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -100- 7.8 GET Format GET ( file_variable ); This standard Pascal procedure moves the next data item from the sequential file into the file's buffer variable. If there is not another data item in the file then the EOF function becomes true. The READ procedure allows reading directly from a file into any variable. READ ( F; X ); is equivalent to: X := F^; GET ( F ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -101- 7.9 OPEN Format 1 OPEN ( file_variable, filename, BINARY ); Format 2 OPEN ( file_variable, filename, TEXT );  The OPEN builtin procedure is used to open files for random access. Format 1 is used to open files in binary mode. Format 2 is used to open files in text mode. The file_variable refers to a file variable declared in the VAR declaration section. The filename is a string or structured expression which may include disk identifier letter. The file specified by the filename is opened for use if present. If not present, a new file is created. Both formats may be used with both RRN and RBA accessing. Examples: OPEN ( INVENTORY, 'INVENTRY.DAT', BINARY ); OPEN ( F1, RANGE + '.DAT', TEXT ); OPEN ( CASE_HISTORY, 'D:TORTS.LIB', BINARY ); OPEN ( DICTIONARY, 'B:SPELLING.LIB', BINARY ); Copy compliments of Merle Schnick SECTION 7: Input/output  JRT Pascal User's Guide version 3.0 NOT FOR SALE -102- 7.10 PICTURE The external function PICTURE allows you to format (real) numbers in powerful ways. Check printing is easy, as are commas within a number and exponential notation. Floating (or fixed) dollar signa are easy to specify. Credit and debit indications can be included. Literal characters such as currency signs can also be put in the formatted string. COBOL and PL/I programmers will find familiar features such as with trailing signs. PICTURE takes a format string and a real number as arguments. It returns a formated string, which can be printed on the console, the line printer, written to a file, concatenated with other strings, or saved for further processing. For example, RES$ := PICTURE("*$##,###.##", 1456.20); WRITELN ("Sum: ", PICTURE("###,###.### ###", 6583.1234567)); will set RES$ (which should be declared as a string or array of characters) to the eleven characters **$1,456.20 and next write a line consisting of the twenty characters Sum: 6,583.123 456. PICTURE is supplied as a compiled function (the file PICTURE.INT). PICTURE must be declared in any program that uses it as FUNCTION PICTURE (FMT : STRING; R : REAL) : STRING; EXTERN; The format string is not hard to create. PICTURE generally puts one character in the result string for every character in the format string, the exceptions marked with a *. The format characters are summarized below. Note that you will usually need only pound signs, commas, and periods in your formats. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -103- Format Replaced with 0 Literal zero (used only with exponential notation 9 A decimal digit (always) B Space (or fill character) CR CR if the number is positive, else spaces DB DB if the number is negative, else spaces E Exponent (consisting of E, sign, and two digits) (*) E+## Exponent (sign and digit indications are ignored) (*) L Literal L (as a currency sign) S Minus or plus sign V Implied decimal point (*) Z Digit or fill character - Minus sign if negative, else space + Plus sign if positive, else minus sign # Digit or fill character % Digit or fill character * Asterisk fill ** Asterisk fill and one digit *$ Asterisk fill and floating dollar sign **$ Asterisk fill, floating dollar sign, and one digit , Comma if digit has already been formated, else space / Literal / (or fill character) : Literal : (or fill character) space Literal space (or fill character) ^ Exponent (E, sign, and two digits) (*) ^^^^ Exponent (*) _ Next character is included literally (*) _* or * A single asterisk (*) _$ or $ A single dollar sign (*) Examples (our favorite formats) -#.### ###^^^^ Large and small numbers $##.## Price of JRT Pascal ###,### Number of happy customers *$###,###.## Checks (especially pay checks) -##,###,###,###,###.## Change in the national debt Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -104- In general, PICTURE can use any format with legal characters. It is possible to create ridiculous formats, such as "-+". An appropriate matching string will be returned (either space, plus, or minus in this case). If the format contains and invalid format character, PICTURE will complain and will return a two character string ?? Upper case and lower case letters are equivalent in the format, so E or e can be used for the exponent. Simple number formating Pound signs (#) are usually used to indicate where digits should be placed. A decimal point indicates where the decimal point should go. PICTURE does NO rounding, but just truncates insignificant digits. (The vertical bar just indicates the start of the result in the following examples, and will not be included in the actual result). Format Number Result Length | ##### 15000 15000 5 | -2.6 -2 5 | -17.98 -17 5 | ###.## 29.95 29.95 6 | -10.756 -10.75 6 Punctuation Commas can be inserted in the formated number. A comma in the format will cause a comma AT THE CORRESPONDING POSITION if a digit has already been put into the result in a position to the comma position. If no significant digit has been seen, then a space or asterisk is substituted. Note that PICTURE DOES NOT automatically put commas every third position. You can place commas in any meaningful (or meaningless) position in your number. Format Number Result Length | ###,### 2470 2,470 7 | #,### -999 -999 5 | #,###### 2743562 2,743562 8 COUNT YOUR COMMAS AND DIGITS. Commas can be used after the decimal point if desired. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -105- A space (or B) works exactly the same as commas for those of you who want to punctuate numbers with spaces instead of commas. Note that this is different from the PRINT USING statement in Basics, which treat blanks as delimiters. Exponential Notation Exponential notation is indicated either with an uparrow (^) or the letter E. Following uparrows, signs, and digit indicators are ignored, so you can use ^^^^ or E+##. The formated exponent ALWAYS takes four characters: the letter E, the sign of the exponent, and two digits. If you want PICTURE to create numbers in exponential notation with a leading 0 before the decimal point, you can use the digit 0 in a format before the decimal. Format Number Result Length | #.###^ 15000 1.500E+04 9  | -2.5 -.250E+01 9 | ###.####^ 15000 150.0000E+01 12 | -2.5 -25.0000E-01 12 | ###.####E+## -2.5 -25.0000E-01 12 | 0.### ###^^^^ 15000 0.150 000E+05 13 Signs Normally, PICTURE will put a minus sign before the first significant digit in a number if that number is negative. This is called a floating sign, and will take up one digit position. You can have PICTURE handle the sign in many other ways. To put the minus sign (or blank) in a fixed position, use a - in the format. The minus sign can be before the first significant digit or at the end of the number. To put a negative or positive sign in a fixed position, use a plus sign (+) or an S instead of the minus sign. Format Number Result Length | -#### -12 - 12 5 | 134 134 5 | ####+ -12 12- 5 | 134 134+ 5 Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -106- With exponential notation, you will generally want to specify the location of the sign, since a floating sign will cause one less digit before the decimal to be printed WITH NEGATIVE NUMBERS than with POSITIVE NUMBERS. Format Number Result Length | -0.### ###^^^^ 15000 0.150 000E+05 14 | -15000 -0.150 000E+05 14 | -#.######^^^^ 15000 1.500000E+04 13 | -.###^ 15001 .150E+04 9 | +.###^ 15001 +.150E+04 9 | -2.506 -.250E+01 9 | .###-^ 15001 .150 E+04 9  | -2.506 .250-E+01 9 Note that you can put the sign in a number of inappropriate places and can even have the sign appear more that once. Dollar signs and check printing Floating dollar signs and asterisks fill work in a straightforward manner, and will produce the sort of results you would want for printing dollar sign amounts or checks. To enter a $ or * at a fixed position, use one of the "literal next" characters, the underline (_) or backslash () before the $ or *. Format Number Result Length | _$##,###.## 2745.23 $ 2,745.23 10 | $##,###.## 2645.23 $2,745.23 10 Note that the **, $$, and **$ formats are optional in JRT Pascal's PICTURE function. They are equivalent to *#, $#, and *$#, respectively The only exceptions to the "one format character, one result character" rule are 1) the two "literal next" characters (_ and ) which do not appear in the result 2) the V, which is not printed 3) the two exponent characters (^ and E) which always take four characters (and which cause following ^, +, -, #, and 9 specifications to be ignored in the format). Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -107- Overflow Overflow occurs when the number to be formated cannot fit in the format provided, as when 1000 is to be formated in a three digit field (###). When that happens, PICTURE puts a % in place of ALL digits. In exponential notation, the only cause of overflow is with negative numbers when no sign is indicated and no digits are allowed before the decimal point. Format Number Result Length | -## 200005 %% 3 | ###### -40000102 -%%%%% 6 | *$#,### 400102 *$%,%%% 7 | .###^ -207 .%%%E+03 8 Testing formats for PICTURE Here is a routine you can use to test your own PICTURE specifications. (We use an extension of this program that allows file input and output to test ours.) The program reads the number of real digits to be formated and the numbers to be formated. It then reads one format specification at a time an prints each of the numbers in that format. PROGRAM TESTPICT CONST MAX_REAL = 100; VAR I : INTEGER; NR_REALS : INTEGER; PIC : STRING; REAL_ARR : ARRAY[1..MAX_REAL] OF REAL; EXTERN PICTURE ( FMT : STRING; R : REAL) : STRING; EXTERN; BEGIN REPEAT WRITE('Number of real numbers to format: '); READLN(NR_REALS); UNTIL (NR_REALS < MAX_REAL); FOR I := 1 TO NR_REALS DO READ(REAL_ARR[I]); READLN; Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -108- REPEAT WRITE('Format: '); READLN(PIC); IF(PIC <> '*') THEN FOR I := 1 TO NR_REALS DO BEGIN WRITELN(I:3, ' ', | REAL$(REAL_ARR[I], ' ', PICTURE(PIC, REAL_ARR[I]), | ' '); END; UNTIL (PIC = '*'); END. Note that currently, JRT Pascal requires that real numbers entered in exponential form must have a exponent sign and two exponent decimal digits. This restriction will be relaxed in the future. Formats for ex-COBOL and PL/I programmers The format character V can be used to set an implied decimal point without printing one. (V. and .V can also be used. The . will always be included in the result. Z can be used in place of #, and 9 can be used to force printing of a digit. The "literal" / and : can be used. They will be replaced by the fill character (space or *) if appropriate. Multiple + and - signs can be used in place of # to cause floating signs. Subtle differences between JRT Pascal's PICTURE and other languages will be found. Use the TESTPICT routine to experiment as needed. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -109- 7.11 PUT Format PUT ( file_variable ); This standard Pascal procedure appends the current value of the buffer variable to the sequential file.  The WRITE procedure allows writing directly to a file from any variable. WRITE ( F; X ); is equivalent to: F^ := X; PUT ( F ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -110- 7.12 READ, READLN Format 1 (console) READ/LN (variable1, variable2,... ); Format 2 (sequential disk) READ/LN ( file_variable ; variable1, variable2,... ); Format 3 (random disk) READ/LN ( file_variable, RRN, integer_or_real_expr ; variable1, variable2,... ); Format 4 (random disk) READ/LN ( file_variable, RBA, integer_or_real_expr ; variable1, variable2,... ); The READ standard procedure is used to bring data from console  or disk into main storage. Format 1 is used for reading data from the console keyboard. When it is executed it will obtain data from the console buffer, convert it to the proper format, and store the data in the specified variables. If sufficient data is not available, the system will wait for more data to be keyed in. If data is keyed in with unacceptable format, a warning message is issued. Dynamic string variables may only be used in READ format 1 - in console input - and not in disk file input. To read character data from disk files, arrays of characters or records may be used. Reading from the console into a dynamic string variable is treated differently. An entire line of text is obtained from the console and moved directly into the string variable. Separator characters and single quotes are ignored. The system will not allow more characters to be keyed in than can fit into the variable. The string variable must be the only variable in the READ's parameter list. When all data on a given input line has been read in, the EOLN function becomes true. The READLN procedure has the additional purpose of resetting EOLN to false. READLN always clears out the current input line. For example, if 5 numbers were keyed in on one line and a READLN were issued with 3 variables in its parameter list, the last 2 numbers on that line would be lost. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -111- Format 2 is used to read in data from a sequential disk file. Whether the file is processed as text or binary data is specified when the file is opened (RESET). The file_variable must refer to a file which has been successfully opened or a run-time error will occur. Note that JRT Pascal uses a semicolon after the file_variable rather than a comma. Format 3 is used to read in data from a random file by giving the relative record number (RRN) of the record required. The first record number is at RRN=0. The file must have been successfully opened with the OPEN procedure. Sequential and random file accesses cannot be mixed unless the file is first closed and then re-opened in the other mode. The size of records on the file for RRN processing is determined when the file is declared. For example, a FILE OF REAL has a record size of 8 bytes. Format 4 is used to read data from a random file by giving the relative byte address (RBA) of the data item required. The first byte of the file is at RBA=0. The file must have been successfully opened with the OPEN procedure. Random processing cannot be mixed with sequential processing but RRN and RBA processing can be mixed without re-opening the file. Examples: READLN( A, B ); READ( DATA_FILE; X_DATA, Y_DATA ); READ( HISTORY_FILE, RRN, YEAR; MAJOR_EVENT ); READ( INQUIRY_FILE, RBA, 0; INDEX ); READLN; (* RESET EOLN *) Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -112- 7.13 RENAME Format RENAME ( old_name, new_name ); The RENAME procedure is used to rename disk files on any disk. The old_name and new_name are string expressions. RENAME is implemented as an external procedure. Any program referencing it must include it declarations:  PROCEDURE RENAME ( OLD, NEW1 : STRING[20] ); EXTERN; Examples: RENAME( 'C:TEST.PAS', 'TEST2.PAS' ); RENAME( OLD_FILE_NAME, NEW_FILE_NAME ); RENAME( DISK + OLD_NAME, NEW_NAME ); RENAME( 'SORT.BAK', 'SORT.PAS' ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -113- 7.14 RESET Format 1 RESET ( file_variable, filename, BINARY, bufr_size ); Format 2 RESET ( file_variable, filename, TEXT, bufr_size ); The RESET standard procedure is used to open already existing files for sequential input. IMPORTANT CHANGE from version 2.2 to version 3.0 of JRT Pascal: RESET now sets the EOF function to true and issues a warning message if the file does not exist on disk. It used to cause the old program to terminate with an error. NOTE: All programs should now test EOF immediately after RESET. Format 1 is used to open files in binary mode. Format 2 opens files in text mode. The file_variable refers to a file variable declared in the VAR declaration section. The filename is a string or structured expression which may include disk identifier letter. The bufr_size is an integer expression which indicates the size of the input buffer to be allocated in dynamic storage. When storarage is available, larger buffers are preferred because they result in fewer disk accesses and thus faster processing. The buffer size is rounded up to a multiple of 128. Values like 1024, 2048 and 4096 are recommended for bufr_size. Examples: RESET( INPUT_FILE, 'SOURCE.PAS', BINARY, 1024 ); RESET( LOG, 'B:LOG.DAT', TEXT, 2048 ); RESET( DAILY_SALES, 'C:DAILY.DAT', TEXT, 256 ); RESET( STATISTICS, 'STAT.DAT', BINARY, 1024 ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -114- 7.15 REWRITE Format 1 REWRITE( file_variable, filename, BINARY, bufr_size ); Format 2 REWRITE( file_variable, filename, TEXT, bufr_size ); The REWRITE standard procedure is used to open all files for sequential disk output. A new file with the given filename is allocated. If a file with that name already exists, it is deleted to free the space allocated to it. Format 1 is used to open files in binary mode. Format 2 opens files in text mode. The file_variable refers to a file variable declared in the VAR declaration section. The filename is a string or structured expression which may include disk identifier letter. The bufr_size is an integer expression which indicates the size of the input buffer to be allocated in dynamic storage. When storage is available, larger buffers are preferred because they result in fewer disk accesses and thus faster processing. The buffer size is rounded up to a multiple of 128. Values like 1024, 2048 and 4096 are recommended for bufr_size. Examples: REWRITE( LOG_FILE, 'F:LOG.DAT', TEXT, 512 ); REWRITE( REPORT, MONTH + '.RPT', TEXT, 1024 ); REWRITE( SYMBOL, PGM + '.SYM', BINARY, 256 ); REWRITE( STATISTICS, 'B:STATS.DAT', TEXT, 768 ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -115- 7.16 WRITE, WRITELN Format 1 (console) WRITE/LN ( variable1, variable2,... ); Format 2 (sequential disk) WRITE/LN ( file_variable ; variable1, variable2,... ); Format 3 (random disk) WRITE/LN ( file_variable, RRN, integer_or_real_expr ; variable1, variable2,... ); Format 4 (random disk) WRITE/LN ( file_variable, RBA, integer_or_real_expr ; variable1, variable2,... ); The WRITE standard procedure is used to transfer data from main storage to the console for display or to disk for storage. Format 1 is used to write data to the console or printer. The console is always considered to be a text device, i.e., data is always converted to readable text format before output. Standard ASCII control characters are supported: decimal hex purpose  ------- --- -------- 9 09h horizontal tab 10 0ah line feed 12 0ch form feed, clear screen 13 0dh carriage return, end line For example, executing the Pascal statement WRITE( CHR(12) ); will clear the screen of most types of CRT terminals. The WRITELN statement is identical to the WRITE except that it also writes a carriage return character after the data, i.e., it ends the current output line. A WRITELN may be used by itself, without any variables, to write a blank line to the output device. Format 2 is used to write data to squential disk files. The file must have been successfully opened with a REWRITE procedure. This format may be used in either binary or text mode processing. Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -116- Note that JRT Pascal uses a semicolon after the file_variable rather than a comma. Format 3 is used to write data to a random file by giving the relative record number (RRN) of the record being updated or created. The first record is at RRN=0. The file must have been successfully opened with the OPEN procedure. Sequential and random file processing cannot be mixed unless the file is first closed then re-opened in the other mode. The size of records on the file for RRN processing is determined when the file is declared. For example, a FILE OF REAL has a record size of 8 bytes, the size of real variables. Format 4 is used to write data to a random file by giving the relative byte address (RBA) at which the data is to be stored. The first byte of the file is at RBA=0. The data will be stored beginning at the specified RBA and continuing until it is all written out. The file must have been successfully opened with the OPEN procedure. Random processing cannot be mixed with sequential processing but RRN and RBA processing can be mixed without re-opening the file. When processing in text mode, a convenient formatting option is available. Any of the variables in the WRITE parameter list may be suffixed with a colon and an integer expression. This specifies the field width of the data value being written. IF the data item is shorter than this then spaces will be inserted on the left of the item. This option is used when columns of figures must be aligned. A second option is available for real numbers. After the field width integer expression, a second colon and integer expression may be used to indicate the number of digits right of the  decimal place to be displayed. Examples: WRITELN( 'THE TIME IS ',GET_TIME ); WRITE( DATA_FILE; X[1], X[2], X[3] ); FOR I:=1 TO 100 DO WRITE( DATA_FILE; X[1] ); IF DATA < 0 THEN WRITE( NEGATIVE_DATA; DATA ) ELSE WRITE( POSITIVE_DATA; DATA ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -117- WRITELN( REPORT; TOTAL_SALES:12:2 ); WRITE( CUSTOMER_FILE, RRN, CUST_NUM; NEW_CUSTOMER_RECORD ); WRITE( INQUIRY, RBA, 0; INDEX ); WRITELN; (* WRITE BLANK LINE *) WRITE( CHR(0CH) ); (* CLEAR SCREEN *)  Copy compliments of Merle Schnick SECTION 7: Input/output LANK LINE *) WRITE( CHR(0CH) ); (* CLEAR SCREEN *) ; X[1] ); IF DATA < 0 THEN WRITE( NEGATIVE_DATA; DATA ) ELSE WRITE( POSITIVE_DATA; DATA ); Copy compliments of Merle Schnick SECTION 7: Input/output JRT Pascal User's Guide version 3.0 NOT FOR SALE -117- WRITELN( REPORT; TOTAL_SALES:12:2 ); WRITE( CUSTOMER_FILE, RRN, CUST_NUM; NEW_CUSTOMER_RECORD ); WRITE( INQUIRY, RBA, 0; INDEX ); WRITELN; (* WRITE BLANK LINE *) WRITE( CHR(0CH) ); (* CLEAR SCREEN *)  JRT Pascal User's Guide version 3.0 NOT FOR SALE -119- 9. Customiz External procedures and functions are compiled separately from the main program. They can be linked together with the main program using the Linker (section 8 of this manual). If this is not done, they will be automatically loaded from disk into the computer's main storage when they are first referenced. If a short-on-storage condition arises, they may be purged from storage if they are not currently active. Procedures which are rarely used, like initialization or error handling, would not occupy main storage except when needed. Also, very large programs might be divided into several phases, each corresponding to an external procedure. The EXEC loads the external procedures from disk. There is no need to inform EXEC on which disk each procedure resides - it will search for them. This means that you do NOT have to put all the program sections onto the A: disk. EXEC and the compiler, JRTPAS3, contain 'disk search lists' which specify which disks are available on the system. The default lists are set to 'AB', i.e., drives A: and B:. The seach lists should be modified to reflect the hardware configuration. The Customiz program is provided to modify the lists in both EXEC and JRTPAS2 simultaneously. Before running Customiz, be sure that both EXEC and JRTPAS3 are not write protected files or on a write proctected disk or drive. To run Customiz, enter: EXEC CUSTOMIZ A new disk search list, with up to four disk letters, may be specified. The letters must be contiguous. NOTE that this list also determines the SEQUENCE in which the disks are searched for the external procedures and functions. ABC (note no spaces between letters) Copy compliments of Merle Schnick SECTION 9: Customiz  are searched for the external procedures anhe system. The default lists are set to 'AB', i.e., drives A: and B:. The seach lists should be modified to reflect the hardware configuration. The Customiz program is provided to modify the lists in both EXEC and JRTPAS2 simultaneously. Before running Customiz, be sure that both EXEC and JRTPAS3 are not write protected files or on a write proctected disk or drive. To run Customiz, enter: EXEC CUSTOMIZ A new disk search list, with up to four disk letters, may be specified. The letters must be contiguous. NOTE that this list also determines the SEQUENCE in which the disks are searched for the external procedures an JRT Pascal User's Guide version 3.0 NOT FOR SALE -120- 10. Assembler The JRT Pascal system provides two methods of preparing external procedures and functions written in assembly language. A special purpose assembler is provided which generates modules in the correct format. The second method may be used if a Microsoft format assembler is available, such as RMAC or MACRO-80. The CONVERTM utility converts the '.REL' files produced by these two assemblers into '.INT' format files which may be accessed as external procedures (see section 10.7 of this manual). The JRT assembler translates 8080 assembly language into JRT relocatable format modules. These modules can be called from a Pascal program as if they were Pascal external procedures. Parameters may be passed to them and function return values may be received.  The JRT assembler is compatible with the standard ASM.COM program distributed with CP/M. Input files must have a file type of '.ASM'. The assembler output is a file of type '.INT', which may be linked with the main program or automatically loaded at run-time. 10.1 Entry codes After an external procedure is loaded into main storage, EXEC transfers control to it. A five byte code (95,6,0,92,0) is placed at the start of the procedure to inform EXEC that this is an assembler procedure rather than Pascal. The procedure must end with a return (RET) instruction. Any registers EXCEPT the 8080 stack pointer may be modified. Example of entry codes: ;procedure entry db 95,6,0,92,0 ;required entry codes ; ;send a message to console mvi c,9 ;print buffer code  lxi d,msg ;address of message call 5 ;bdos entry point ; ret ;end of procedure ; msg db 'JRTASM sample procedure' db 0dh,0ah,'$' ;carriage return/line feed ; end Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -121- If this procedure were named SAMPLE.ASM then the declaration in the Pascal program referencing it would be: PROCEDURE SAMPLE; EXTERN; 10.2 Operating JRTASM To assemble an external procedure, enter: EXEC JRTASM You will be prompted at the console for the input filename and options. The options are: 1 - produce a listing on the console during pass 1 of the assembly process, useful for debugging. C - produce an output file of type '.COM' rather than '.INT'. This is not an external procedure but a directly executable command file in standard CP/M format. An ORG 100H directive should be included since the default origin is 0. 10.3 Directives These assembler directives are supported: directive purpose --------- --------- ORG set location counter, not used in external procedures SET assign a value to a variable EQU assign a value to a fixed symbol IF/ELSE/ENDIF conditional assembly of code, may be nested to 16 levels DB define byte, multiple operands  DW define word DS define storage READ used to assign a new value to a variable, like SET except that value is obtained from console WRITE display strings or expressions on console Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -122- Examples of directives: 1. a set 9 if a = 9 write 'a is equal to nine' else write 'a is not equal to nine' endif 2. x read ;msg at console will ask for x write 'x squared is ',(x * x) 3. a set a + 1 ;increment a db 'string',a,255 Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -123- 10.4 Expressions Integer expressions can be used in assembler instructions. Expressions are either fixed or relocatable. A symbol is relocatable if it refers to an address, otherwise it is fixed. If any symbol in an expression is relocatable then the entire expression is relocatable. Parenthesis may be nested to any level. These operators are supported: * / + - NOT AND OR XOR MOD HIGH LOW EQ NE LT LE GT GE  Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -124- 10.5 Parameters and function return values Parameters of any data type may be passed to assembler external procedures and functions. The EXEC maintains a data stack which contains all static variables, parameters, function return values and procedure linkage blocks. Three address pointers are used to access the data stack. These are available to external procedures in the 8080 register pairs on entry to the procedure. BASE (HL) - address of the data stack CUR (DE) - address of the linkage block for currently active procedure TOS (BC) - top of stack, points past last allocated byte I I I I TOS-->I I I-----------------I I I I 6 bytes I linkage block for I I current procedure CUR-->I I I-----------------I I 2 bytes I parameter length fld I-----------------I I I I x bytes I parameters of I I current procedure I I I-----------------I I I I I I I I I global variables  I I of main program I-----------------I I I I 6 bytes I linkage block for I I main program I I BASE-->I-----------------I Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -125- With the three data stack pointers, the parameters passed to the procedure can be accessed. If it is a function, the return value can be stored. Also, the global variables of the main program can be accessed. For example, if the first global variable declared in the main Pascal program which calls the external procedure is an integer named INT1, then just add 6 to the BASE pointer to get the address of INT1. The BASE pointer is in register pair HL on entry to the procedure. Data stack after procedure call DEMO( 'A',7 ); 'A' 7 length linkage block 41 0700 0300 xx xx xx xx xx xx yy I I CUR TOS The two byte integer fields are in 8080 byte-reverse format. The parameter length field is equal to three. The linkage block is six bytes of unspecified data Parameters are accessed by decrementing the CUR pointer. Pascal value parameters are actually present in the data stack. For reference parameters, the address of the variable is present in the data stack. If the procedure has no parameters, the parameter length field is zero. Function return values must be stored just before the function's first parameter in the data stack.  Data stack after function call X := TEST( 3,8 ); (The return value is of the type integer) 3 8 length linkage block rrrr 0300 0800 0400 xx xx xx xx xx xx yy I I I return value CUR TOS If the return value is of type CHAR, a string, or a structured variable (entire array, entire record) then there is a two byte length field between the return value and the first parameter. This field is set by EXEC and MUST NOT be modified. If the return value is a dynamic string, the current length field is a two byte field at the beginning of the string. This must be set to the desired length of the field. Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -126- Data stack after function call NAME := LOOKUP( 'X',1); (The return value is of type ARRAY [1..4] OF CHAR;) return value rv len 'X' 1 length linkage block rr rr rr rr 0400 58 0100 0300 xx xx xx xx xx xx yy I I CUR TOS 10.6 Debugging assembler procedures One effective way to debug external procedures written in assembler uses the CP/M Dynamic Debugging Tool (DDT). If a user is running a Pascal program under DDT, then a RST 7 instruction will be seen as a breakpoint and allow the user to access all the DDT facilities. To run under DDT, enter: DDT EXEC.COM Iprogram_name G100 When the RST 7 instruction is encountered, DDT will gain control. The display, modify, disassemble facilities then can be used to examine the procedure data areas. To resume execution, use the XP command to set the instruction address ahead by 1, to get past the RST 7 instruction. Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -127- 10.7 Convertm program The Convertm program translates Microsoft format '.REL' files into JRT format '.INT' files. Only '.REL' files may be input - '.HEX' files do not contain information about relocation addresses. To run the Convertm program, enter: EXEC CONVERTM The program will inquire at the console for the name of the module to be translated. A file type of '.REL' is assumed. The output module '.INT' file is placed on the same disk. 10.8 Sample assembly programs Three sample assembly programs are included here. Two external procedures (setbit, resetbit) and one external function (testbit) can be called from any Pascal program or external function. These small modules provide fast and simple bit manipulation facilities. They also illustrate the passing and returning of parameters for assembly language external procedures. Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -128- Listing of setbit.asm: ;setbit.asm ;external procedure which sets a bit on in a byte ; ; procedure setbit ( var x : char; bit : integer ); ; extern; ; bit# in range 0..7 ; ;entry code db 95,6,0 ;int vmcode db 92 ;lpn vmcode db 0 ;mode vmcode ;on entry bc=wtos de=wb hl=wbase ; ;get bit# in b_reg, addr(x) in hl, x into c_reg setbit xchg ;hl=wb dcx h! dcx h! dcx h! dcx h mov b,m ;bit# dcx h! mov d,m! dcx h! mov e,m ;addr(x) xchg ;hl=addr(x) mov c,m ;c=x ;create mask inr b ;incr loop count mvi a,1 loop rrc dcr b jnz loop ;a=mask c=byte ora c mov m,a ;store byte ret ; end Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -129- Listing of resetbit.asm ;resetbit.asm ;external procedure which reset bit in a byte ; ; procedure resetbit ( var x : char; bit : integer ); ; extern; ; bit# in range 0..7 ; ;entry code db 95,6,0 ;int vmcode db 92 ;lpn vmcode db 0 ;mode vmcode ;on entry bc=wtos de=wb hl=wbase ; ;get bit# in b_reg, addr(x) in hl, x into c_reg resetbit xchg ;hl=wb dcx h! dcx h! dcx h! dcx h mov b,m ;bit# dcx h! mov d,m! dcx h! mov e,m ;addr(x) xchg ;hl=addr(x) mov c,m ;c=x ;create mask inr b ;incr loop count mvi a,0feh loop rrc dcr b jnz loop ;a=mask c=byte ana c mov m,a ;store byte ret ; end  Copy compliments of Merle Schnick SECTION 10: Assembler JRT Pascal User's Guide version 3.0 NOT FOR SALE -130- Listing of testbit.asm ;testbit.asm ;external function which returns bit value of a byte ; ; function testbit ( x : char; bit : integer ): ; boolean; extern; ; ; bit number is in range 0..7 ; ;entry code db 95,6,0 ;int vmcode db 92 ;lpn vmcode db 0 ;mode vmcode ;on entry bc=wtos de=wb hl=wbase ; ;get bit# into b_reg and x into a_reg testbit xchg ;hl=wb dcx h! dcx h! dcx h! dcx h ;point to bit lownib mov b,m ;low byte of bit dcx h! mov a,m ;x inr b ;shift loop loop rlc dcr b jnz loop jc true ;bit is set ;false : bit is zero dcx h! mvi m,0! dcx h! mvi m,0 ret ;true : bit is one true dcx h! mvi m,0! dcx h! mvi m,1 ret ; end Copy compliments of Merle Schnick SECTION 10: Assembler  ret ;true : bit is one true dcx h! mvi m,0! dcx h! mvi m,1 ret ; end nt vmcode db 92 ;lpn vmcode db 0 ;mode vmcode ;on entry bc=wtos de=wb hl=wbase ; ;get bit# into b_reg and x into a_reg testbit xchg ;hl=wb dcx h! dcx h! dcx h! dcx h ;point to bit lownib mov b,m ;low byte of bit dcx h! mov a,m ;x inr b ;shift loop loop rlc dcr b jnz loop jc true  JRT Pascal User's Guide version 3.0 NOT FOR SALE -131- 11. Storage management This section discusses the initialization and structure of main storage in the JRT Pascal system during execution of Pascal programs. 11.1 Main storage When a Pascal program is started by entering the command "EXEC prog_name", the EXEC.COM file is loaded into main storage at address 100H by the CP/M operating system. After EXEC receives control from CP/M, it determines how much storage is available and formats this area. EXEC then loads the Pascal program module from disk. Processing of the Pascal program then begins. During program execution, there are four main regions of main storage. Starting from the lowest address, these are: 1. EXEC - The run-time environment. This region is fixed in size and contains the primary run-time support system.  2. Pascal program module - This region is fixed in size and contains the compiled Pascal program from an '.INT' file. 3. Data stack - This region is variable in size. It begins at the end of the Pascal program and grows toward higher addresses (and toward the dynamic storage region, discussed next). This region contains all static variables (those created by VAR declarations), parameters passed to procedures and procedure activation blocks. 4. Dynamic storage - This region is variable in size. It begins at the top of available storage and grows down toward lower addresses (and towards the data stack, previously discussed). This region contains dynamic variables (those created by the NEW procedure), input/output buffers, file control blocks, external procedures and EXEC control tables. Since the data stack and the dynamic storage regions grow toward each other, a collision between these areas is possible when storage is nearly full. To prevent this condition, the run-time system maintains a 64 byte cushion between the two areas. When the cushion becomes less than 64 bytes, the run-time system takes several actions to restore the cushion. Copy compliments of Merle Schnick SECTION 11: Storage management JRT Pascal User's Guide version 3.0 NOT FOR SALE -132- If there is less than 64 bytes of free space in main storage, the least-recently-used procedure will be deleted. Dynamic storage is then compressed (see section 11.2 of this manual). Processing will continue even if the cushion cannot be restored, although performance will gradually decrease. Only if there is actually a colllision between the data stack and the dynamic storage regions will the run-time system recognize an  error condition and terminate processing. Copy compliments of Merle Schnick SECTION 11: Storage management JRT Pascal User's Guide version 3.0 NOT FOR SALE -133- Map of main storage use in JRT Pascal system: high ------------------------------- address I DYNAMIC STORAGE I I I I variable in size I I I I direction ! I I of growth ! I I V I I-----------------------------I I unused area (CUSHION) I 64 bytes  I-----------------------------I I DATA STACK I I I I variable in size I I I I direction ^ I I of growth ! I I ! I I-----------------------------I I PASCAL PROGRAM I I INT module I I I I fixed in size I I-----------------------------I I EXEC.COM I I run-time system I I  I I fixed in size I low I I address ------------------------------- 100H Copy compliments of Merle Schnick SECTION 11: Storage management JRT Pascal User's Guide version 3.0 NOT FOR SALE -134- 11.2 Dynamic storage The JRT Pascal run-time system provides TRUE dynamic storage with auto-compression. Virtual storage is supported for external procedures. The JRT Pascal Dynamic Storage Management System is designed to provide complete support for advanced features such as dynamic data structures (linked lists, trees, rings,...) and completely automatic virtual storage for external procedure and function code. Dynamic storage may contain these items:  1. external procedures/functions 2. dynamic variables created by the NEW procedure 3. input/output buffers 4. file control blocks 5. EXEC control blocks and pointer tables 6. a free list of de-allocated storage blocks All of these items are allocated as blocks of dynamic storage. Dynamic storage blocks are addressed indirectly in JRT Pascal in order to allow the blocks to be moved during compression by updating a pointer table. The value stored in a pointer variable by the execution of the NEW procedure is a "virtual address" rather than the real address of the block allocated. The virtual address is used to locate an entry in an internal table called a pointer table, which contains the size and real address of each storage block. There may be up to 32 pointer tables and each one contains up to 52 entries for storage blocks. During dynamic storage compression, the real address of a storage block may change, but the virtual address does not change. The dynamic storage manager performs these services: 1. Format dynamic storage and initialize pointer tables. 2. Maintain the free list. This is a linked list which contains blocks of storage which have been de-allocated (by the DISPOSE procedure, by closing a file, or by purging of an external procedure). 3. Allocate a storage block. When a storage block is requested (by the NEW procedure, opening a file, or loading an external procedure), the storage manager attempts to satisfy this request by searching the free list or extending the dynamic storage region. When scanning the free list for a block, the first block which is large enough is selected. If this block is much too large, it is split and the remainder returned to the free list. After a block has been found, its real address, size, and a flag field are entered in a pointer table. 4. Release a block of storage. This adds a de-allocated block to the free list and deletes the corresponding pointer table entries. Copy compliments of Merle Schnick SECTION 11: Storage management JRT Pascal User's Guide version 3.0 NOT FOR SALE -135- 5. Determine the amount of free space. The free space is the sum of the sizes of all blocks on the free list and the size of the gap between the data stack region and the dynamic storage region. 6. Compress dynamic storage. All of the allocated storage blocks are moved into the top of storage to eliminate free space. The free list is set to a null pointer. The pointer table entries of all blocks are updated. If external procedures were moved then their relocatable addresses are adjusted. If active external procedures were moved then the Pascal program counter and the procedure return addresses are adjusted. 7. Convert the virtual address of a block to a real address. Copy compliments of Merle Schnick SECTION 11: Storage management re adjusted. 7. Convert the virtual address of a block to a real address. e sum of the sizes of all blocks on the free list and the size of the gap between the data stack region and the dynamic storage region. 6. Compress dynamic storage. All of the allocated storage blocks are moved into the top of storage to eliminate free space. The free list is set to a null pointer. The pointer table entries of all blocks are updated. If external procedures were moved then their relocatable addresses are adjusted.  JRT Pascal User's Guide version 3.0 NOT FOR SALE -140- 13. Debugging Pascal programs Debugging computer programs is the process of correcting "bugs" in a program so that it will perform as desired. There are two phases of debugging: correcting syntax errors in a program in order to obtain an error-free compile, and correcting errors which occur during the running of the program after a clean compile. Referencing an undeclared variable is an example of the first kind of error. Dividing by zero is an example of the second kind. This section is primarily concerned with the second kind of error - those that occur during program testing. JRT Pascal provides several facilities to simplify the location and the correction of run-time errors. The debugging philosophy is to provide the programmer with as much relevant information as possible in a clearly formatted display. The run-time system detects errors at two levels of severity - errors and warnings. When warnings occur, a message is issued and processing continues. When an error occurs, processing must terminate. Error and warning messages are all presented in verbal format - there are no number or letter codes to look up. These messages are stored on a disk file so that main storage is not wasted. 13.1 Trace options JRT Pascal allows a trace of the program line numbers while a program is running. This trace may be turned on or off by the program itself. The range of line numbers to be traced may also be set by the program. A trace of procedure names can also be produced. On entry to each procedure, the name and activation count is displayed. On exit, the name of the procedure is displayed. This feature can also be turned on or off under program control. The Exec interrupt mode can be entered by a control-n command while a program is running. In this mode, the traces and line number range can be modified. Other system status information can also be displayed. When in interrupt mode, entering a space character will cause a list of valid commands to be displayed. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -141- Exec interrupt allows asynchronous control of the trace facility. Programmed control is also supported with the SYSTEM builtin procedure. An interactive external procedure to control these trace facilities at run-time is provided. The DEBUG procedure is described in section 13.2 of this manual. To use these traces, the %LTRACE and %PTRACE compiler directives must be inserted in the program. It is recommended that the first line of a program being tested contains both directives, so that the entire program will be subject to tracing. An additional advantage is that when these options are present, if an error or warning occurs, the line number and the latest procedure name will be displayed with the error message. The coding of these directives and use of the SYSTEM builtin procedure to control the traces are described in the section on compiler directives (section 3 of this manual). 13.2 DEBUG procedure The DEBUG external procedure allows the control of the dynamic trace facilities while a program is being tested. The procedure and line traces can be turned on or off and the line range can be set by commands entered from the console. The file DEBUG.INT on the distribution disk is the compiled external procedure module. To reference an external procedure from a Pascal program, it is necessary to declare it: PROCEDURE DEBUG; EXTERN; The procedure can be called from an number of places in the test program by inserting a procedure call statement: DEBUG; Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -142- When it is activated, DEBUG will interact with the programmer to modify the current trace operations. Listing of DEBUG.PAS: extern procedure debug; var reply : char; lower, upper : integer; begin (* debug *) writeln; write('Activate line trace? y/n : '); readln(reply); if upcase(reply) = 'Y' then begin write('Range of lines? lower,upper : '); readln(lower,upper); system( ltrace ); system( lrange,lower,upper ); end else system( noltrace ); write('Activate procedure trace? y/n : '); readln(reply); if upcase(reply) = 'Y' then system( ptrace ) else system( noptrace ); writeln; end; (* debug *). Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -143- 13.3 System status display When an error is detected, an error message is displayed on the console. The current line number and last entered procedure name may also be displayed (see section 13.1). A system status display is also created. This display contains useful information about the current state of the run-time system. The s ystem status display shows nine fields of information. If external procedures are present, the external procedure table is also formatted and displayed. System status display addr :54F5 prog :3BA7 size :4815 base :83BC cur :89AC tos :8A33 low :A8B9 compr:0002 purge:0000 Most of these values indicate the use of storage in the run-time system. Storage management is discussed fully in section 11 of this manual. A simplified map of storage is presented here: ------------------------- I CP/M I I-----------------------I I DYNAMIC STORAGE I I I low---> I-----------------------I I I I unused I I I  tos---> I-----------------------I I I cur---> I DATA STACK I I I base--> I-----------------------I I I I PASCAL CODE I <--addr (of error) I I prog--> I-----------------------I I I I EXEC run-time I I system I 100h--> I-----------------------I I reserved area I ------------------------- Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -144- 1. addr - the address at which the error occurred. This may be in the Pascal code area or in the dynamic storage area if the error was in an external procedure. 2. prog - the starting address of the main Pascal program. 3. size - the size of the main program module. 4. base - the base or bottom of the data stack. 5. cur - the address of the current procedure activation block. 6. tos - top of stack. This is the address just past the end of the data stack. 7. low - the lowest address occupied by any dynamic storage block. 8. compr - a count of the number of times storage has been auto-compressed. 9. purge - a count of the number of external procedures that have been purged from dynamic storage due to short-on-storage condition. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0  NOT FOR SALE -145- The system status display may contain one additional line of input/output information. The name of the most recently referenced file, a status byte and the current default disk will be displayed if files have been used by the program. @:SAMPLE PAS 88 A If the file was opened without specifying a disk letter then @ is shown, otherwise the disk letter. The status byte contains several flag bits: bit meaning --- --------- 80 file is open 40 random mode - not sequential 20 text mode - not binary 10 EOLN flag set 08 input - not output or random 04 EOF flag set Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -146- Formatted external procedure table exproc name addr use cnt time stat ACCTPAY1 C2AE 0000 0004 30 ACCTPAY2 3E22 0000 0165 74 GENLEDG1 0001 0000 0000 00 ACCTREC1 3F55 0001 014E F4 ACCTREC2 440C 0001 015A F4 SORT 0001 0000 0000 00 +INVENTRY 503A 0001 020D F4 CHECKS 5052 0000 0103 30 1. exproc name - the name of the external procedure or function. A plus sign indicates the external procedure which was most currently entered or exited. This is not necessarily the currently active procedure. 2. addr - the address in main storage of the external procedure module. If this valu!e is 0001 then the module is not currently in main storage. 3. use cnt - a count of the number of times the procedure is CURRENTLY active. Usually this will be 0000 (not active) or 0001 (active). It will be greater that 0001 only if the procedure is called recursively. 4. time - in order to determine which procedure was least-recently-used, the run-time system maintains a pseudo-timer which is incremented once on each entry to or exit from an external procedure. The field contains the value of the pseudo-timer the last time the procedure was entered or exited. 5. stat - a status indicator with several flag bits: bit meaning --- -------- 80 procedure is currently active 40 procedure was linked with main program 20 procedure is currently in storage 10 procedure file control block is open 04 procedure address is real, not virtual Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -147- 13.4 Run-time messages The run-time system provides several messages to aid in the correction of error or exceptional conditions. In addition to these general messages, about 75 more specific messages of 1 to 4 lines to text are provided to describe particular error conditions. The general run-time messages are all prefixed with a % character. These messages are listed here: %Entry - indicated entry to a procedure when procedure trace is active. Procedure name and activation count are listed. External procedures are indicated by an asterisk before the name. %Error - fatal error detected by run-time system. Program terminates. %Exit - indicates exit from procedure when procedure trace is active. Procedure name is listed. External procedures are indicated by an asterisk before the name. %Extern - indicates that error occurred while attempting to load an external procedure module. The procedure name is listed. %Input error - indicates a format error when reading console input, such as entering a character string when an integer was expected. %Line - indicates line number where error occurred. The module must have been compiled with %LTRACE option. %Main - error occurred in main program BEGIN-END block, not in procedure. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -148- %Proc - error occurred in procedure, not in main program  BEGIN-END block. %Trace - line number trace indicator. %Warning - non-fatal error condition. Processing continues. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -149- 13.5 Common Problems A. General difficulties 1. The master disks accidently got erased by a program... MAKE BACKUP COPIES OF JRT PASCAL when you first get it. May we suggest: Remember the Master Disk, to keep it wholly. As a read-only disk, please. 2. The disks will not boot up when on is put in drive A: and the system is reset... After you copy JRT Pascal to your own working disks, put a copy of your operating system (using SYSGEN or whatever YOUR operating system calls it) on the working disks. We cannot put your operating system on disks we distribute. 3. With CP/M 1.4, CDOS or the equivalents, CUSTOMIZ, LINKER and random I/O in general will not work.... Sorry about that, but to get random I/O on 8 megabyte files, CP/M 2.2 would be required. LINKER is never required for JRT Pascal. The function of CUSTOMIZ can be performed by two simple patches in DDT. This involves patching the disk search list in EXEC.COM and JRTPAS3.COM. Both of these list are at 0155h and consist of up to four upper case letters followed by a Z. A>DDT EXEC.COM -S155 0155 41 41 0156 42 42 0157 4A 5A (an upper case Z) 0158 00 . -G0 A>SAVE 93 EXEC.COM For JRTPAS3.COM, the SAVE command line is A>SAVE 85 JRTPAS3.COM 4. The diagnostic "JRTPAS3?" or "SOURCE FILE NOT FOUND" comes up... CP/"M needs to know the drive on which the file JRTPAS3.COM is located, if it is not on the current default drive. JRTPAS3 needs to know the drive on which the source file to be compiled is located. Further, that source file must have a '.PAS' suffix on the name. So, for example, you may need to type B:JRTPAS3 B:PGM if the default drive is A: and both JRTPAS3.COM and PGM.PAS are on the B: drive. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -150- 5. The compiler and everything else does not fit on one disk... There are many possible ways to set JRT Pascal up when you have a system with small drive capabilities. One is: On disk A: On disk B: -EXEC.COM -JRTPAS3.COM -your editor -PASCAL0.INT  (ED, WordStar, etc.) -PASCAL1.INT -the PASCAL SOURCE program -PASCAL2.INT being developed -PASCAL3.INT -perhaps PASCAL.LIB -PASCAL4.INT -PASCAL.LIB You Osborne owners may have to do some shuffling until you find the arrangement that works best for you. For example, the compiler disk could be on drive A:, which would alternate with the WordStar disk as necessary (with appropriate Control-C's after disk changes). The source and object programs could then stay on B:, perhaps with EXEC.COM and another copy of PASCAL.LIB. Be sure there is a copy of your operating system on each disk you put in drive A:. 6. The compiler (or run-time) USED to work, but now it doesn't... Use EXEC VERIFY to check the compiler and/or run time files again. Even if the sums agree, a file or files may have gotten shuffled by a malfunctioning program, hardware errors, or bad diskette handling. If necessary, go back to the original master disks (write-protect labels, right?) and copy the needed files to a NEW diskette. If necessary, act as if you had just gotten JRT Pascal (square-1). 7. EXEC VERIFY does not even work... Make sure that EXEC.COM, VERIFY.INT, and PASCAL.LIB are MOUNTED on your disk system, and that you told CP/M the right drive for EXEC.COM and that you gave EXEC the right location for VERIFY.INT. You may need to use B:EXEC B:VERIFY if the files are on B:. Remember when you run EXEC.COM that PASCAL.LIB must be present on one of the drives in the "disk search list" (usually A: or B:). 8. BDOS errors show up when a DIR is requested of a master disk... Make sure that your system is expecting a disk in the format provided. For example, single density 8" disks: Some operating systems cannot sense a density change once they have determined "the format for that drive". A system reset may be needed. Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -151- B. Compiler Errors 1. String literal too long... Somewhere in the program, a literal string does not have a closing or opening single quote. This error is caught by the lexical scanner before the program is listed. (Most editors make it easy to search for all lines with single quotes.) 2. Block structure invalid (and other strange diagnostics)... Perhaps the program is attempting to declare or use a reserved word. The list of reserved words in JRT Pascal is somewhat longer than standard. For example, LENGTH and POS are reserved. 3. Compiler acts like something is not there... Many versions of WordStar set the high-order bit of the 'current' character when a file is closed, even when editing in non-document form. ALWAYS end a WordStar edit with (^QC) before (^KD). Also, use PIP newfile.PAS=oldfile.PAS[Z] to clear off parity bits. 4. Compiler "goes away"... Hit system reset, then look for undeclared variables, types, or constants in the next line listed. Also check for ; or , used inappropriately. Look for unbalanced parenthesis. 5. Out of memory... Split the program into a main program and external procedures so that each portion is 600 to 1200 lines long. (Maximum length depends on the program and the available memory.) 6. Array out of bounds at end of compilation... External procedure names can be 8 characters long and should not contain $ or _ characters, since the exproc name is turned into a CP/M file name. # Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -152- C. Run-time Errors 1. Object file not found... Make sure that the source program is compiled successfully, and that the appropriate drive is indicated on the file name, as EXEC B:PGM. 2. Library not present... PASCAL.LIB must be present on one of the drives in the "disk search list" (usually A: or B:). 3. Files never get written to... CLOSE(file_variable) is required after files have been written, so that CP/M performs a proper close on the file. Otherwise, the file size will be the next lower multiple of 16K in size, usually zero. 4. Reading characters from a file, most of the characters in a word get skipped... The difference between binary and text modes are significant. If you  want every character in a file, use binary in the reset of open statement. 5. Reading from a file in binary mode, end of file is hard to determine... Control-Z (1ah) marks the end of a text file (unless the real end of file on a 128 byte boundary occurs). Test for both character =CHR(26) and EOF. For binary records, a special record consisting of all 255 (0ffh) or all EOF's (1ah) may be needed to mark the end of the file, since CP/M only keeps track of 128-byte sectors. 6. External procedures get all mixed up... Declare external procedures properly. When external procedures refer to other external procedures, the declaration order count must match those in the main program: If your main has FUNCTION COS(R : REAL): REAL; EXTERN; FUNCTION SIN(R : REAL): REAL; EXTERN; and your exproc has declared only  FUNCTION SIN(R : REAL): REAL; EXTERN; lo and behold, the exproc will get a value of 1.0 if it passes 0.0 to what it thinks is SIN. The exproc will have actually called COS. Internally, external procedures refer to other external procedures by number. 'Dummy' declarations such as PROCEDURE X1; EXTERN; can be used as place holders, as long as the names are unique. The name used in the MAIN program will be used to find the external procedure on the disk. 7. Values are not returned correctly from external functions (or arguments are not passed correctly to external procedures)... Make sure the declaration of arguments in the calling program match those in the external procedure. If a VAR is missing in one and Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -153- present in another, you could have trouble. 8. Control-C does not stop a program (or control-N does not stop it either)... Use control-N to cause an execution interrupt (you can either exit the program with Z or continue with R, as appropriate). Use %LTRACE or $L when compiling the program to allow execution interrupts and also error diagnostics with line numbers. Copy compliments of Merle Schnick SECTION 13: Debugging cution interrupts and also error diagnostics with line numbers. ose in the external procedure. If a VAR is missing in one and Copy compliments of Merle Schnick SECTION 13: Debugging JRT Pascal User's Guide version 3.0 NOT FOR SALE -153- present in  This is the release date of the disk. $ Fog Library Disk FOG-CPM.173 Copyright (1987) by Fog International Computer Users Group to the extent not copyrighted by the original author for the exclusive use and enjoyment of its members. Any reproduction or distribution for profit or personal gain is strictly forbidden. For information, contact FOG, P. O. Box 3474, Daly City, CA. 94015-0474. as part of the description of a file indicates that the program is distributed on a "try first, pay if you like it" basis. If you find the program(s) meet your need, please refer to the author's documentation for information on becoming a registered user. Only by registering and paying for the programs you like and use will the authors of such programs continue development. Often, more complete documentation, additional modules, and new releases are available only to registered users. Disk 3 of 4. JRT Pascal. Filename Description -04-00 .87 This is the release date of the disk. -CPM173 .DOC This is the description of the disk contents. JRTMAN .006 DD9E 27K ver. 4.0 [JRT Pascal 51 of 78] JRTMAN .007 5726 78K ver. 4.0 [JRT Pascal 52 of 78] JRTMAN .009 1ED5 3K ver. 4.0 [JRT Pascal 53 of 78] JRTMAN .100 6D4A 18K ver. 4.0 [JRT Pascal 54 of 78] JRTMAN .101 0790 10K ver. 4.0 [JRT Pascal 55 of 78] JRTMAN .103 D5B0 25K ver. 4.0 [JRT Pascal 56 of 78] E diskno="&mdiskno".AND. .NOT. EOF() IF diskno="000" IF dfile="FOG-DOS" ? " %&'