home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
catalog
/
pibcat17.arc
/
PIBCATS1.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1989-03-31
|
36KB
|
700 lines
(*--------------------------------------------------------------------------*)
(* Trim --- Trim trailing blanks from a string *)
(*--------------------------------------------------------------------------*)
FUNCTION Trim( S : AnyStr ) : AnyStr;
(*--------------------------------------------------------------------------*)
(* *)
(* Function: Trim *)
(* *)
(* Purpose: Trims trailing blanks from a string *)
(* *)
(* Calling sequence: *)
(* *)
(* Trimmed_S := TRIM( S ); *)
(* *)
(* S --- the string to be trimmed *)
(* Trimmed_S --- the trimmed version of S *)
(* *)
(* Calls: None *)
(* *)
(* Remarks: *)
(* *)
(* Note that the original string itself is left untrimmed. *)
(* *)
(* Pascal version might be written as: *)
(* *)
(* VAR *)
(* I: INTEGER; *)
(* *)
(* BEGIN *)
(* *)
(* I := ORD( S[0] ); *)
(* *)
(* WHILE ( I > 0 ) AND ( S[I] = ' ' ) DO *)
(* I := PRED( I ); *)
(* *)
(* S[0] := CHR( I ); *)
(* Trim := S; *)
(* *)
(* END; *)
(* *)
(*--------------------------------------------------------------------------*)
BEGIN (* Trim *)
INLINE(
$1E/ { PUSH DS ; Save DS}
{;}
$C5/$76/$06/ { LDS SI,[BP+6] ; Get address of S}
$FC/ { CLD ; Forward search}
$AC/ { LODSB ; Get length of S}
$3C/$00/ { CMP AL,0 ; See if length 0}
$74/$21/ { JE Trim2 ; If so, no trimming required}
{;}
$30/$ED/ { XOR CH,CH}
$88/$C1/ { MOV CL,AL ; Remember length for search loop}
{;}
$B0/$20/ { MOV AL,' ' ; Blank to AL}
{;}
$C4/$7E/$06/ { LES DI,[BP+6] ; Get address of S}
$01/$CF/ { ADD DI,CX ; Point to end of source string}
{;}
$FD/ { STD ; Backwards search}
$F3/$AE/ { REPE SCASB ; Scan over blanks}
$74/$01/ { JE Trim1 ; If CX=0, entire string is blank.}
$41/ { INC CX}
{;}
$88/$C8/ {Trim1: MOV AL,CL ; Length to copy}
$C5/$76/$06/ { LDS SI,[BP+6] ; Source string address}
$46/ { INC SI ; Skip length}
$C4/$7E/$0A/ { LES DI,[BP+10] ; Result string address}
$FC/ { CLD ; Forward move}
$AA/ { STOSB ; Set length in result}
$F2/$A4/ { REP MOVSB ; Move trimmed result}
$E9/$04/$00/ { JMP Exit}
{;}
$C4/$7E/$0A/ {Trim2: LES DI,[BP+10] ; Result string address}
$AA/ { STOSB ; Set length=0 in result}
{;}
$1F); {Exit: POP DS ; Restore DS}
END (* Trim *);
(*--------------------------------------------------------------------------*)
(* Dupl -- Duplicate a character n times *)
(*--------------------------------------------------------------------------*)
FUNCTION Dupl( Dup_char : Char; Dup_Count: INTEGER ) : AnyStr;
(*--------------------------------------------------------------------------*)
(* *)
(* Function: Dupl *)
(* *)
(* Purpose: Duplicate a character n times *)
(* *)
(* Calling Sequence: *)
(* *)
(* Dup_String := Dupl( Dup_Char: Char; Dup_Count: INTEGER ): AnyStr; *)
(* *)
(* Dup_Char --- Character to be duplicated *)
(* Dup_Count --- Number of times to duplicate character *)
(* Dup_String --- Resultant duplicated string *)
(* *)
(* Calls: None *)
(* *)
(* Remarks: *)
(* *)
(* This routine could be programmed directly in Turbo as: *)
(* *)
(* VAR *)
(* S : AnyStr; *)
(* *)
(* BEGIN *)
(* *)
(* FillChar( S[1], Dup_Count, Dup_Char ); *)
(* S[0] := CHR( Dup_Count ); *)
(* *)
(* Dupl := S; *)
(* *)
(* END; *)
(* *)
(*--------------------------------------------------------------------------*)
BEGIN (* Dupl *)
INLINE(
$8A/$4E/$06/ { MOV CL,[BP+6] ; Pick up dup count (0..255)}
$30/$ED/ { XOR CH,CH ; Clear upper byte of count}
$C4/$7E/$0A/ { LES DI,[BP+10] ; Result address}
$FC/ { CLD ; Set direction flag}
$88/$C8/ { MOV AL,CL ; Get result length}
$AA/ { STOSB ; Store result length}
$8B/$46/$08/ { MOV AX,[BP+8] ; Get char to duplicate}
$F2/$AA); { REP STOSB ; Perform duplication}
END (* Dupl *);
(*----------------------------------------------------------------------*)
(* Min --- Find minimum of two integers *)
(*----------------------------------------------------------------------*)
FUNCTION Min( A, B: INTEGER ) : INTEGER;
(*----------------------------------------------------------------------*)
(* *)
(* Function: Min *)
(* *)
(* Purpose: Returns smaller of two numbers *)
(* *)
(* Calling sequence: *)
(* *)
(* Smaller := MIN( A , B ) : INTEGER; *)
(* *)
(* A --- 1st input integer number *)
(* B --- 2nd input integer number *)
(* Smaller --- smaller of A, B returned *)
(* *)
(* *)
(* Calls: None *)
(* *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Min *)
IF A < B Then
Min := A
Else
Min := B;
END (* Min *);
(*----------------------------------------------------------------------*)
(* Max --- Find maximum of two integers *)
(*----------------------------------------------------------------------*)
FUNCTION Max( A, B: INTEGER ) : INTEGER;
(*----------------------------------------------------------------------*)
(* *)
(* Function: Max *)
(* *)
(* Purpose: Returns larger of two numbers *)
(* *)
(* Calling sequence: *)
(* *)
(* Larger := MAX( A , B ) : INTEGER; *)
(* *)
(* A --- 1st input integer number *)
(* B --- 2nd input integer number *)
(* Larger --- Larger of A, B returned *)
(* *)
(* *)
(* Calls: None *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Max *)
IF A > B Then
Max := A
Else
Max := B;
END (* Max *);
(*--------------------------------------------------------------------------*)
(* UpperCase --- Convert string to upper case *)
(*--------------------------------------------------------------------------*)
FUNCTION UpperCase( S: AnyStr ): AnyStr;
(*--------------------------------------------------------------------------*)
(* *)
(* Function: UpperCase *)
(* *)
(* Purpose: Convert string to upper case *)
(* *)
(* Calling Sequence: *)
(* *)
(* Upper_String := UpperCase( S : AnyStr ): AnyStr; *)
(* *)
(* S --- String to be converted to upper case *)
(* Upper_String --- Resultant uppercase string *)
(* *)
(* Calls: UpCase *)
(* *)
(* Remarks: *)
(* *)
(* This routine could be coded directly in Turbo as: *)
(* *)
(* VAR *)
(* I : INTEGER; *)
(* L : INTEGER; *)
(* T : AnyStr; *)
(* *)
(* BEGIN *)
(* *)
(* L := ORD( S[0] ); *)
(* *)
(* FOR I := 1 TO L DO *)
(* T[I] := UpCase( S[I] ); *)
(* *)
(* T[0] := CHR( L ); *)
(* UpperCase := T; *)
(* *)
(* END; *)
(* *)
(*--------------------------------------------------------------------------*)
BEGIN (* UpperCase *)
INLINE(
$1E/ { PUSH DS ; Save DS}
$C5/$76/$06/ { LDS SI,[BP+6] ; Get source string address}
$C4/$7E/$0A/ { LES DI,[BP+10] ; Get result string address}
$FC/ { CLD ; Forward direction for strings}
$AC/ { LODSB ; Get length of source string}
$AA/ { STOSB ; Copy to result string}
$30/$ED/ { XOR CH,CH}
$88/$C1/ { MOV CL,AL ; Move string length to CL}
$E3/$0E/ { JCXZ Exit ; Skip if null string}
{;}
$AC/ {UpCase1: LODSB ; Get next source character}
$3C/$61/ { CMP AL,'a' ; Check if lower-case letter}
$72/$06/ { JB UpCase2}
$3C/$7A/ { CMP AL,'z'}
$77/$02/ { JA UpCase2}
$2C/$20/ { SUB AL,'a'-'A' ; Convert to uppercase}
{;}
$AA/ {UpCase2: STOSB ; Store in result}
$E2/$F2/ { LOOP UpCase1}
{;}
$1F); {Exit: POP DS ; Restore DS}
END (* UpperCase *);
(*--------------------------------------------------------------------------*)
(* Adjust_Hour --- Convert 24 hour time to 12 hour am/pm *)
(*--------------------------------------------------------------------------*)
PROCEDURE Adjust_Hour( VAR Hour : WORD;
VAR AmPm : STRING2 );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Adjust_Hour *)
(* *)
(* Purpose: Converts 24 hour time to 12 hour am/pm time *)
(* *)
(* Calling sequence: *)
(* *)
(* Adjust_Hour( VAR Hour : WORD; AmPm : String2 ); *)
(* *)
(* Hour --- Input = Hours in 24 hour form; *)
(* Output = Hours in 12 hour form. *)
(* AmPm --- Output 'am' or 'pm' indicator *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Adjust_Hour *)
IF ( Hour < 12 ) THEN
BEGIN
AmPm := 'am';
IF ( Hour = 0 ) THEN
Hour := 12;
END
ELSE
BEGIN
AmPm := 'pm';
IF ( Hour <> 12 ) THEN
Hour := Hour - 12;
END;
END (* Adjust_Hour *);
(*----------------------------------------------------------------------*)
(* Dir_Convert_Date_And_Time --- Convert directory creation date/time *)
(*----------------------------------------------------------------------*)
PROCEDURE Dir_Convert_Date_And_Time( Time : LONGINT;
VAR S_Date : AnyStr;
VAR S_Time : AnyStr );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Dir_Convert_Date_And_Time *)
(* *)
(* Purpose: Convert creation date/time from DOS directory entry. *)
(* *)
(* Calling Sequence: *)
(* *)
(* Dir_Convert_Date_And_Time( Time : LONGINT; *)
(* VAR S_Date : AnyStr; *)
(* VAR S_Time : AnyStr ); *)
(* *)
(* Time --- Packed time/date as read from DOS directory *)
(* S_Date --- converted date in dd-mon-yy format *)
(* S_Time --- converted time in hh:mm ampm format *)
(* *)
(* Calls: *)
(* *)
(* UnPackTime *)
(* *)
(*----------------------------------------------------------------------*)
VAR
DT : DateTime;
YY : String[2];
HH : String[2];
MM : String[3];
DD : String[2];
AmPm : STRING[2];
BEGIN (* Dir_Convert_Date_And_Time *)
(* If time stamp is 0, don't bother *)
(* to unpack it. *)
IF ( Time = 0 ) THEN
BEGIN
S_Date := ' ';
S_Time := ' ';
END
ELSE
BEGIN
(* Get date/time values *)
UnpackTime( Time , DT );
WITH DT DO
BEGIN
STR( ( Year - 1900 ): 2 , YY );
MM := Month_Names[ Month ];
STR( Day:2 , DD );
S_Date := DD + '-' + MM + '-' + YY;
IF ( ( Hour + Min + Sec ) = 0 ) THEN
S_Time := ' '
ELSE
BEGIN
Adjust_Hour( WORD( Hour ) , AmPm );
STR( Hour:2 , HH );
STR( Min: 2 , MM );
IF ( MM[1] = ' ' ) THEN MM[1] := '0';
S_Time := HH + ':' + MM + ' ' + AmPm;
END;
END;
END;
END (* Dir_Convert_Date_And_Time *);
(*----------------------------------------------------------------------*)
(* Dir_Convert_Date_And_Time --- Convert directory creation date/time *)
(*----------------------------------------------------------------------*)
PROCEDURE Dir_Convert_Date_And_Time_2( Time : LONGINT;
VAR S_Date : AnyStr;
VAR S_Time : AnyStr );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Dir_Convert_Date_And_Time_2 *)
(* *)
(* Purpose: Convert creation date/time from DOS directory entry. *)
(* *)
(* Calling Sequence: *)
(* *)
(* Dir_Convert_Date_And_Time_2( Time : LONGINT; *)
(* VAR S_Date : AnyStr; *)
(* VAR S_Time : AnyStr ); *)
(* *)
(* Time --- Packed time/date as read from DOS directory *)
(* S_Date --- converted date in yy/mm/dd format *)
(* S_Time --- converted time in hh:mm 24 hour format *)
(* *)
(* Calls: *)
(* *)
(* UnPackTime *)
(* *)
(*----------------------------------------------------------------------*)
VAR
DT : DateTime;
YY : String[2];
HH : String[2];
MM : String[2];
DD : String[2];
BEGIN (* Dir_Convert_Date_And_Time_2 *)
(* If time stamp is 0, don't bother *)
(* to unpack it. *)
IF ( Time = 0 ) THEN
BEGIN
S_Date := ' ';
S_Time := ' ';
END
ELSE
BEGIN
(* Get date/time values *)
UnpackTime( Time , DT );
WITH DT DO
BEGIN
STR( ( Year - 1900 ): 2 , YY );
STR( Month:2 , MM );
IF ( MM[ 1 ] = ' ' ) THEN MM[ 1 ] := '0';
STR( Day:2 , DD );
IF ( DD[ 1 ] = ' ' ) THEN DD[ 1 ] := '0';
S_Date := YY + '/' + MM + '/' + DD;
IF ( ( Hour + Min + Sec ) = 0 ) THEN
S_Time := ' '
ELSE
BEGIN
STR( Hour:2 , HH );
STR( Min: 2 , MM );
IF ( HH[ 1 ] = ' ' ) THEN HH[ 1 ] := '0';
IF ( MM[ 1 ] = ' ' ) THEN MM[ 1 ] := '0';
S_Time := HH + ':' + MM;
END;
END;
END;
END (* Dir_Convert_Date_And_Time_2 *);
(*----------------------------------------------------------------------*)
(* Convert_String_To_AsciiZ -- Convert Turbo string to Ascii Z String *)
(*----------------------------------------------------------------------*)
PROCEDURE Convert_String_To_AsciiZ( VAR S: AnyStr );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Convert_String_To_AsciiZ *)
(* *)
(* Purpose: Convert Turbo string to ascii Z string *)
(* *)
(* Calling Sequence: *)
(* *)
(* Convert_String_To_AsciiZ( VAR S: AnyStr ); *)
(* *)
(* S --- Turbo string to be turned into Ascii Z string *)
(* *)
(* Calls: *)
(* *)
(* None *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Convert_String_To_AsciiZ *)
S := S + CHR( 0 );
END (* Convert_String_To_AsciiZ *);
(*----------------------------------------------------------------------*)
(* Dir_Set_Disk_Transfer_Address --- Set DMA address for disk I/O *)
(*----------------------------------------------------------------------*)
PROCEDURE Dir_Set_Disk_Transfer_Address( VAR DMA_Buffer );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Dir_Set_Disk_Transfer_Address *)
(* *)
(* Purpose: Sets DMA address for disk transfers *)
(* *)
(* Calling Sequence: *)
(* *)
(* Dir_Set_Disk_Transfer_Address( VAR DMA_Buffer ); *)
(* *)
(* DMA_Buffer --- direct memory access buffer *)
(* *)
(* Calls: *)
(* *)
(* MsDos *)
(* *)
(*----------------------------------------------------------------------*)
VAR
Dir_Reg: Registers;
BEGIN (* Dir_Set_Disk_Transfer_Address *)
Dir_Reg.Ax := $1A00;
Dir_Reg.Ds := SEG( DMA_Buffer );
Dir_Reg.Dx := OFS( DMA_Buffer );
MsDos( Dir_Reg );
END (* Dir_Set_Disk_Transfer_Address *);
(*----------------------------------------------------------------------*)
(* Dir_Get_Volume_Label --- Get volume label of a disk *)
(*----------------------------------------------------------------------*)
PROCEDURE Dir_Get_Volume_Label( Volume : CHAR;
VAR Volume_Label : AnyStr;
VAR Time : LONGINT );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Dir_Get_Volume_Label *)
(* *)
(* Purpose: Gets volume label for specified disk *)
(* *)
(* Calling sequence: *)
(* *)
(* Dir_Get_Volume_Label( Volume : CHAR; *)
(* VAR Volume_Label : AnyStr; *)
(* VAR Time : LONGINT ); *)
(* *)
(* Volume --- Disk letter for which to get label *)
(* Volume_Label --- Actual label itself *)
(* Time --- Packed creation date/time of volume label *)
(* *)
(* Remarks: *)
(* *)
(* Because of various bugs in the MS DOS 2.x file searching *)
(* facilities, this routine will not return a volume date or time *)
(* for DOS 2.x. *)
(* *)
(*----------------------------------------------------------------------*)
TYPE
Directory_Record = RECORD
Filler : ARRAY[1..21] Of BYTE;
File_Attr : BYTE (* File attributes *);
File_Time : LONGINT (* Creation time *);
File_Size : LONGINT (* Size in bytes *);
File_Name : ARRAY[1..80] Of CHAR (* Name *);
END;
Extended_FCB = RECORD
Fcb_Flag : BYTE (* $FF = extended FCB *);
Filler1 : ARRAY[1..5] OF BYTE;
FCB_Attr : BYTE (* File attribute *);
FCB_Drive : BYTE (* Drive *) ;
FCB_FileName: ARRAY[1..11] OF CHAR (* File name *);
FCB_BlockNo : INTEGER (* Block # *);
FCB_RecSize : INTEGER (* Record size *);
FCB_FileSize: Longint (* File size *);
FCB_Date : INTEGER (* File date *);
FCB_Time : INTEGER (* File time *);
Filler2 : ARRAY[1..33] OF BYTE (* Make 64 bytes *);
END;
VAR
Volume_Data : Directory_Record;
Regs : Registers;
Volume_Pat : STRING[15];
OVolume_Data : Extended_FCB;
Volume_FCB : Extended_FCB;
BEGIN (* Dir_Get_Volume_Label *)
(* Use FCB code for DOS 2.x *)
IF ( LO( DosVersion ) = 2 ) THEN
WITH Regs DO
BEGIN (* Dos 2.x *)
(* Clear out FCBs *)
FillChar( Volume_FCB , 64, 0 );
FillChar( OVolume_Data, 64, 0 );
(* Set up extended FCB for volume *)
(* label search. *)
Volume_FCB.FCB_Flag := $FF;
Volume_FCB.FCB_Attr := VolumeID;
Volume_FCB.FCB_Drive := ORD( Volume ) - ORD('A') + 1;
FillChar( Volume_FCB.FCB_FileName, 11, '?' );
(* Set address to receive volume label *)
Dir_Set_Disk_Transfer_Address( OVolume_Data );
(* Call DOS to search for volume label *)
Regs.Ds := SEG( Volume_FCB );
Regs.Dx := OFS( Volume_FCB );
Regs.Ax := $1100;
MsDos( Regs );
(* Check if we got label. If so, *)
(* get it. Date and time will most *)
(* likely be garbage, so set them to *)
(* zero so they won't be listed later. *)
IF ( Regs.Al = $FF ) THEN
Volume_Label := ''
ELSE
Volume_Label := OVolume_Data.FCB_FileName;
Time := 0;
END (* Dos 2.x *)
ELSE
WITH Regs DO
BEGIN (* Dos 3.x and higher *)
(* Set up DMA address for volume info *)
Dir_Set_Disk_Transfer_Address( Volume_Data );
(* Search root directory for label *)
Volume_Pat := Volume + ':*.*';
Convert_String_To_AsciiZ( Volume_Pat );
Regs.Ds := SEG( Volume_Pat[1] );
Regs.Dx := OFS( Volume_Pat[1] );
Regs.Ax := $4E00;
Regs.Cx := VolumeID;
(* Find volume label *)
MsDos( Regs );
IF ( FCarry AND Regs.Flags ) <> 0 THEN
BEGIN (* No volume label found *)
Volume_Label := '';
Time := 0;
END
ELSE
WITH Volume_Data DO
BEGIN (* Extract volume label *)
Volume_Label := TRIM( COPY( File_Name, 1, POS( #0 , File_Name ) - 1 ) );
Time := File_Time;
END;
END (* Dos 3.x and higher *);
END (* Dir_Get_Volume_Label *);