home *** CD-ROM | disk | FTP | other *** search
- {$U-,C-,I-}
- PROGRAM convert;
-
-
- {------------------------------------------------------------------------------
-
- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-
- This program has been tested on many different forms of procedures
- and functions, but may not work on the particular one you have created. If
- your procedure does not work make sure that there are no nested procedures
- and that there is enough memory to load the full procedure in.
-
- Specifically for version 2.00B of the generic MS-DOS or IBM PC-DOS
- implementations Turbo Pascal. It would be easy to convert this for other
- versions of those same implementations. See Consideration #4 below. If
- anyone wants to convert this for the CP/M 86 implementation, you are welcome
- to do so and UPLoad it here.
-
- ------------------------------------------------------------------------------
-
-
- Convert is used to change precompiled chain files into a format that is
- callable by a Turbo program as an external .COM file. There is a loader
- ( LOADER.INC ) that must be included ie. $I LOADER.INC by the program that
- is to use the .COM files created by Convert.
-
-
- There are just a few considerations and precautions that must be taken
- for the external created by Convert to work properly :
-
- 1 : The files to be converted must be chain files.
- 2 : The procedure should have a dummy BEGIN END. to be compiled. Do
- NOT put anything inside the BEGIN END. of the external procedure.
- 3 : Each procedure or function cannot have nested procedures or functions
- inside of it.
- 013D
- 4 : The program Convert must have the CONST LibrarySize set to the ending
- of the Turbo RUN-TIME library ( $2828 for the PC 2.00B, $2565 for
- the generic MS-DOS implementation of Turbo Pascal version 2.00B ).
- 5 : Each program that uses the loader and an external procedure cannot
- be run twice within Turbo, unless a recompilation occurs.
-
- For an example of an external and a calling program read the file CONVRT.DOC.
-
- Written by
- Jim McCarthy
- Technical Support
- Borland International
-
- ------------------------------------------------------------------------------}
-
- CONST
- LibrarySize = $2954; { Size of RUN-TIME library }
- ProcStart = $296A; { LibrarySize + $16 }
-
- TYPE
- str3 = string[ 3 ];
- str80 = string[ 80 ];
- chararr15 = array [ 0..15 ] of char;
- ptr = ^proc;
- proc = record
- byte_val : byte;
- setaddr : boolean;
- next : ptr;
- end;
-
- CONST
- HexStr : CharArr15 = '0123456789ABCDEF';
-
- VAR
- proc_top, proc_current, proc_temp,
- head_top, head_current, head_temp : ptr;
- cmdline : str80 absolute cseg:$0080;
- filename, outfile, base : str80;
- extension : str3;
- element, byte_buff : byte;
- inp, out : file of byte;
- i, j, size, address, table_size,
- table_addr, current_addr, num_calls,
- prog_size, size_file : integer;
-
- PROCEDURE init;
-
- VAR
- i : integer;
-
- BEGIN
- For i := 1 to 5 Do writeln;
- head_top := nil;
- proc_top := nil;
- num_calls := 0;
- i := $100;
- prog_size := 0;
- table_addr := 1;
- current_addr := 0;
- END;
-
-
- PROCEDURE Report( filename : str80; error : integer );
-
- BEGIN
- Case ( error ) of
- 1 : writeln( 'Disk Full.' );
- 2 : writeln( 'File must not be a .COM file.' );
- 3 : writeln( 'Cannot open file : ''', filename, '''.' );
- 4 : writeln( 'Read error on file : ''',filename,'''.' );
- 5 : writeln( 'Write error on file : ''',filename,'''.' );
- End;
- writeln( 'Program ending.' );
- close( inp );
- close( out );
- Halt;
- END;
-
- PROCEDURE TruncForSp( var buffer : str80 );
-
- VAR
- i, j, len : integer;
-
- BEGIN
- i := 1;
- len := length( buffer );
- While ( buffer[ i ] = ' ' ) and ( i <= len ) Do
- i := i + 1;
- For j := 1 to len - i + 1 Do
- buffer[ j ] := buffer[ i + j - 1 ];
- buffer[ 0 ] := chr(len - i + 1);
- END;
-
- FUNCTION HexAddr( address : integer ) : str80;
-
- VAR
- buffer : str80;
- low1nib, low2nib, high1nib, high2nib : byte;
-
- BEGIN
- low1nib := address and $F;
- high1nib := ( address and $F0 ) shr 4;
- low2nib := ( address and $F00 ) shr 8;
- high2nib := ( address and $F000 ) shr 12;
- HexAddr := HexStr[ high2nib ] + HexStr[ low2nib ] +
- HexStr[ high1nib ] + HexStr[ low1nib ];
- END;
-
- PROCEDURE GetFileBase( var filename : str80; var base : str80;
- var extension : str3 );
-
- VAR
- i, j : integer;
-
- BEGIN
- i := 1;
- While ( not ( filename[ i ] in [ '.', ' ' ] )) and
- ( i <= length( filename )) Do
- Begin
- filename[ i ] := Upcase( filename[ i ] );
- base[ i ] := filename[ i ];
- base[ 0 ] := chr( i );
- i := i + 1;
- End;
- If ( filename[ i ] = '.' ) then
- Begin
- i := i + 1;
- j := 1;
- While ( not ( filename[ i ] in [ ' ', '.' ] )) and
- ( i <= length( filename )) and ( j <= 3 ) Do
- Begin
- filename[ i ] := UpCase( filename[ i ] );
- extension[ j ] := filename[ i ];
- extension[ 0 ] := chr( j );
- j := j + 1;
- i := i + 1;
- End;
- End;
- END;
-
- PROCEDURE SetUpFiles( filename : str80 );
-
- BEGIN
- assign( inp, filename );
- reset( inp );
- If ( IOResult <> 0 ) then Report( filename, 3 );
- GetFileBase( filename, base, extension );
- If ( extension <> 'COM' ) then
- outfile := base + '.COM'
- else Report( '', 2 );
- assign( out, outfile );
- rewrite( out );
- If ( IOResult <> 0 ) then Report( '', 1 );
- END;
-
- PROCEDURE AddHeadPtr( value : byte; setcall : boolean );
-
- BEGIN
- New( head_temp );
- head_temp^.byte_val := value;
- head_temp^.setaddr := setcall;
- If ( head_top <> nil ) then
- head_current^.next := head_temp
- else
- head_top := head_temp;
- head_current := head_temp;
- head_current^.next := nil;
- END;
-
- PROCEDURE AddProcPtr( value : byte; setcall : boolean );
-
- BEGIN
- New( proc_temp );
- proc_temp^.byte_val := value;
- proc_temp^.setaddr := setcall;
- If ( proc_top <> nil ) then
- proc_current^.next := proc_temp
- else
- proc_top := proc_temp;
- proc_current := proc_temp;
- proc_current^.next := nil;
- END;
-
- PROCEDURE DumpPtr( top : ptr );
-
- VAR
- current, temp : ptr;
- value : byte;
- i : integer;
-
- BEGIN
- i := 0;
- current := top;
- While ( current <> nil ) Do
- Begin
- temp := current;
- value := current^.byte_val;
- write( out, value );
- If ( IOResult <> 0 ) then Report( outfile, 5 );
- current := current^.next;
- i := i + 1;
- End;
- END;
-
- PROCEDURE CreatHeader( var header_size : integer; numcalls : integer );
-
- VAR
- temp, temp1, temp2 : ptr;
- i, current_addr : integer;
-
- BEGIN
- current_addr := 0;
- header_size := 0;
- temp := proc_top;
- i := 0;
- While ( temp <> nil ) and ( i <= numcalls ) Do
- Begin
- If ( temp^.byte_val = $E8 ) or ( temp^.byte_val = $E9 ) then
- Begin
- temp1 := temp^.next;
- temp2 := temp1^.next;
- address := ( temp2^.byte_val shl 8 ) + temp1^.byte_val;
- address := ( ProcStart + current_addr + 2 ) - ( address xor $FFFF );
- If ( temp^.byte_val = $E9 ) then
- write( 'JMP made to : ', HexAddr( address ))
- else
- write( 'CALL made to : ', HexAddr( address ));
- If ( address < LibrarySize ) and ( address > $100 ) then
- Begin
- writeln( ' Address to be changed.' );
- temp^.setaddr := true;
- AddHeadPtr( $E9, false );
- AddHeadPtr( address and $FF, false );
- AddHeadPtr(( address and $FF00 ) shr 8, false );
- header_size := header_size + 3;
- i := i + 1;
- End
- else
- writeln( ' Address not changed.' );
- current_addr := current_addr + 2;
- temp := temp2^.next;
- End
- else temp := temp^.next;
- current_addr := current_addr + 1;
- End;
- writeln;
- END;
-
- PROCEDURE SetProcCalls( header_size, numcalls : integer );
-
- VAR
- address, current_addr, curr_proc_addr,
- curr_head_addr, i, line : integer;
- temp, temp1, temp2 : ptr;
-
- BEGIN
- temp := proc_top;
- curr_head_addr := 3;
- curr_proc_addr := header_size + 3;
- current_addr := 0;
- line := 1;
- i := 0;
- While ( temp <> nil ) and ( i <= numcalls ) Do
- Begin
- If (( temp^.byte_val = $E8 ) or ( temp^.byte_val = $E9 )) and
- ( temp^.setaddr = true ) then
- Begin
- temp1 := temp^.next;
- temp2 := temp1^.next;
- temp := temp2^.next;
- address := ( curr_proc_addr - curr_head_addr + 2 ) xor $FFFF;
- temp1^.byte_val := ( address and $FF );
- temp2^.byte_val := ( address and $FF00 ) shr 8;
- current_addr := current_addr + 2;
- curr_head_addr := curr_head_addr + 3;
- curr_proc_addr := curr_proc_addr + 2;
- i := i + 1;
- End
- else
- temp := temp^.next;
- curr_proc_addr := curr_proc_addr + 1;
- current_addr := current_addr + 1;
- line := line + 1;
- End;
- END;
-
- PROCEDURE PointToStart;
-
- VAR
- i : integer;
- byte_val : byte;
-
- BEGIN
- For i := 0 to $15 Do
- Begin
- read( inp, byte_val );
- If ( IOResult <> 0 ) then Report( filename, 4 );
- End;
- END;
-
- PROCEDURE SetHeaderSize( table_size : integer );
-
- VAR
- element : byte;
-
- BEGIN
- element := $E9;
- write( out, element );
- element := table_size and $FF;
- write( out, element );
- element := ( table_size and $FF00 ) shr 8;
- write( out, element );
- END;
-
- BEGIN
- LowVideo;
- filename := cmdline;
- If ( length( filename ) = 0 ) then
- Begin
- write( 'Chain file name to convert to .COM file : ' );
- HighVideo;
- readln( filename );
- LowVideo;
- writeln;
- End;
- TruncForSp( filename );
- If ( length( filename ) > 0 ) then
- Begin
- Init;
- SetUpFiles( filename );
- PointToStart;
- size_file := filesize( inp );
- While ( not eof( inp )) and ( memavail > 10 ) and
- ( prog_size < size_file - $1C ) Do
- Begin
- read( inp, byte_buff );
- AddProcPtr( byte_buff, false );
- If ( byte_buff = $E8 ) or ( byte_buff = $E9 ) then
- num_calls := num_calls + 1;
- prog_size := prog_size + 1;
- End;
- writeln( 'Bytes of program read : ', HexAddr( prog_size ));
- writeln( 'Calls or Jumps made : ', HexAddr( num_calls ));
- writeln;
- CreatHeader( table_size, num_calls );
- writeln( 'Header size : ', HexAddr( table_size ));
- SetProcCalls( table_size, num_calls );
- SetHeaderSize( table_size );
- DumpPtr( head_top );
- DumpPtr( proc_top );
- close( inp );
- close( out );
- End;
- END.