'===========================================================================
' Subject: TRUNCATE FILE                      Date: Unknown Date           
'  Author: Unknown Author(s)                  Code: QB, PDS                
'  Origin: FidoNet QUIK_BAS Echo            Packet: DOS.ABC
'===========================================================================
' > Is there an easy way in QB to truncate a file to a certain length
' > without copying it? 
 
'Sure .. Not directly via QB, but through an interrupt call. As long as
'the file is opened for RANDOM, BINARY or OUTPUT, this should work fine.
'I wrote it for QBX, but it'll work fine for other version by changing
'the $INCLUDE to QB.BI for VBDOS.BI.
 
    DECLARE FUNCTION TruncateFile% (Handle%, NewLength&)
    DEFINT A-Z
    REM $INCLUDE: 'qbx.bi'
    OPEN "TEST.DAT" FOR BINARY AS #1        'Create a file to test
    A$ = " "
    PUT #1, 10240, A$                       'Make it 10K long
    PRINT "File length:"; LOF(1)            'Make sure
    Handle% = FILEATTR(1, 2)                'Get DOS file handle
    NewLength& = 5000                       'New length for this file
    Status% = TruncateFile%(Handle%, NewLength&)    'Do it
    IF Status% THEN
        PRINT "DOS Error";Status%;" occurred."
    ELSE
        PRINT "New file length:"; LOF(1)
    END IF
    CLOSE
 
FUNCTION TruncateFile% (Handle%, NewLength&)
 
    DIM Reg AS RegTypeX
 
    'First, position the file read/write pointer to the place where the
    'truncation should take place. We can't trust BASIC's SEEK statement
    'because the movement is sometimes held until the next read/write.
 
    Reg.AX = &H4200             'DOS "Set file pointer" function
    Reg.BX = Handle%
 
    'We go through these steps to prevent "overflow" errors when
    'NewLength& > 32767. The high word of the file position goes in CX
    'and the low word goes in DX. Since BASIC treats integers and longs
    '"signed" variables, we need to take to extra steps to prevent
    'an overflow error as we break the long integer down.
 
    DEF SEG
    Addr% = VARPTR(NewLength&)
    Reg.CX = CVI(CHR$(PEEK(Addr% + 2)) + CHR$(PEEK(Addr% + 3)))
    Reg.DX = CVI(CHR$(PEEK(Addr%)) + CHR$(PEEK(Addr% + 1)))
    CALL InterruptX(&H21, Reg, Reg)
    IF Reg.Flags AND 1 THEN
        Status% = Reg.AX
        GOTO TruncateExit
    END IF
 
    'Now, write 0 bytes.
    Reg.AX = &H4000                 'Dos "Write file or device"
    Reg.BX = Handle%
    Reg.CX = 0                      'Write 0 bytes
    Reg.DX = 0                      'These are not needed, but make
    Reg.DS = 0                      ' sure they're zero, just in case
    CALL InterruptX(&H21, Reg, Reg)
    IF Reg.Flags AND 1 THEN
        Status% = Reg.AX
    END IF
 
TruncateExit:
    TruncateFile% = Status%
 
END FUNCTION
