Test MS-DOS file truncate, worry with 'lds si,[bp].n'
Aubrey McIntosh
aubrey at rpp386.cactus.org
Mon Oct 2 03:35:27 AEST 1989
I wrote the attached model program to answer questions for myself. It is
not well commented, but possibly worth posting anyway. At another time,
I might wear my editor hat, and clean up (someone elses) code so that it
reads better. If anyone wants to edit this code (in the publishing sense)
please do so. Naturally, you woud still attribute me as author.
Two threads of thought are explored and affirmatively answered in the program:
1) Can I truncate an existing file to an arbitrary length?
1.a) Can I force MS-DOS to relinquish the disk space while the
file is still open.
2) Can I construct any supporting environment for the
LDS SI, DWORD PTR label
instruction.
There are comments on the enter/leave macro. If you have a NEC V20,
or '186, '286..., they produce correct code for those opcodes. I was
arguing with MASM and found an opcode map before I found the MASM docs.
The familiar push bp/sub sp,<size>/mov bp,sp sequence given as comments
in the macro is code suitable on an 8088 machine, in this one program.
They do not reconcile with the db statements in the macro.
I used Symdeb when exploring, and traced through the program. At various
times, I would do a t=<other label> and, in effect, have a menu driven
interface through Symdeb. Some of the comments [ only | can't otherwise
possibly ] make sense unless you keep that in mind. That is also why there
are Publics in a self-contained main level program.
CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT
CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT CUT
name Truncate
title The File Truncate test program. Verified w/ Symdeb.
subttl A style ancillary to LDS dx,mem.
page 132,75
.radix 16
; .286
; --------------------------------------------------------
; Aubrey McIntosh
; Verify a method of truncating a file in MS-DOS.
; September 19, 1989. For use with Lilith emulator.
; Modify or comment upon freely. Leave my credits.
;
; MD-DOS functions:
; dos 3d02, <Open named file>
; dos 4200, <Move file pointer.>
; dos 4000, <Write to end of file.>
; dos 4000, <Write zero length record.>
; dos 4500, <Duplicate file handle.>
; dos 3e00, <Close duplicate file>
; dos 3f00, <Read a byte past implied clip point. Should fail.>
;
; I had needed a way to 'clip' a file at some point, so
; that I could emulate the way a mag tape works, i.e.
; when you write on it, and then 'rewind' it, there is
; a file mark immediately past the last data, and earlier
; files are irrelevant (erased). Simply using create on
; a new file was not useful to the third party application.
;
; Misinformation has been on the net that this is not
; possible, and I had tedious work arounds for years.
; Here is how I did it.
;
; Also, I digress into a shallow '86 hack.
; --------------------------------------------------------
data group vars, stack ;no initialized values.
text group const, code ;can be in rom.
public stklimit, stk, filenm, handle, buffer
public start, open, position0, trunc,
public position1, dupHandle, close0, read, close, stop
; --------------------------------------------------------
const segment public para 'rom'
; ------ Various string and pointer constants.
filenm db 'scratch.tmp',0
nameptr dd filenm
bufptr dd buffer
stklimit dd stk
const ends
vars segment public para 'ram'
handle dw ?
buffer db 100 dup ( ? )
vars ends
stack segment stack page 'ram'
db 40 dup ('stack ')
stk label word
stack ends
; --------------------------------------------------------
; The dos macro is just playing. I was miffed about having to put all
; the message addresses, lengths, and such somewhere before giving
; each error message. I thought LDS dx,xx would be a part of the solution,
; but the setup seemed unusually expensive. I worried with it a while,
; and came up with this. I sometimes still try to write tight code, just
; to keep up an anachronistic skill. Not a deep hack, but still an
; unorthodox way of using the instruction set to get to the goal, and
; an afternoon's pleasure.
;
; The routine messageToAux uses the return address on the stack as
; a pointer to a data packet immediately following the client's call.
; This lets me use an LDS dx,[bp].2 instruction without
; hardcoding pointers.
;
; The string length, the correct return address, and the string
; address are all implied by the packet, and are free with the
; (far) return value on the stack!
;
; This usage of [bp].n, IMHO, nicely compliments the LDS <reg>,<ref>
; instruction. After much searching, it is the only method I know
; to set up for the LDS without eating up memory with
; ptr dd <label> constructs. Although the return address is modified
; on the stack, this is pure code and not self modifying.
;
; I think this saves space. Audit calculations for both ways
; of handling the 'write to aux' task are included.
;
; Two other concerns are not addressed:
; a. Can I muck with the stack in '286 protected mode?
; b. Can I make the code position independent?
; --------------------------------------------------------
call macro proc
; --------------------------------------------------------
; I can't get mixed far/near call/returns to work out. Since
; I'm determined to save a byte in the call, here goes.
; I get position independent code out of it anyway.
; --------------------------------------------------------
db 0E, 0e8 ;emulate far call to same segment.
dw proc-($+2) ;offset.
endm
; --------------------------------------------------------
callPacket macro message
local nextCode
callcount = callcount + 1 ;an audit artifact.
call messageToAux
dw text : nextCode
db 'Error while '
db '&message'
db 0DH, 0A, 0
nextCode label near
endm
; --------------------------------------------------------
dos macro callid, message
local no_error
mov ax, callid
int 21
jnc no_error
callPacket <message>
nop ;No corrective action taken.
no_error:
endm
; --------------------------------------------------------
enter macro size,levels
db 0c8 ;push bp
dw size ;mov bp, sp
db levels ;nop -- other features not used today.
endm
leave macro
db 0c9 ;pop bp
endm
; --------------------------------------------------------
code segment public para 'rom'
assume cs:text, ds:nothing
test:
string label byte ;no extent: zero length string.
adr dd string
lds dx, adr
mov cx, string-adr
mov ax, 4000
int 21
endtest:
temp = endtest - test
test2:
call messageToAux ;push cs; call near is better.
dw text : morecode
string2 label byte ;no extent: zero length string.
morecode:
endtest2:
temp2 = endtest2-test2
advantage = temp-temp2
overhead = messageToAuxEnd - messageToAux
increment = callcount * advantage
total = increment - overhead
callcount = 1
code ends
; --------------------------------------------------------
; --------------------------------------------------------
code segment public para 'rom'
assume cs:text, ds:nothing
public messageToAux
messageToAux proc far
enter 0,0 ;NEC v-20 & .286 -- manage bp, sp.
lds si, [bp].2 ;load ptr to word following call.
cld
lodsw ;load return address, inc si,2.
mov [bp].2, ax ;replace return address on stack.
sub ax, si ;form string size in bytes to ax.
mov cx, ax
mov dx, si
mov ax, 4000
mov bx,2 ;handle for std error
int 21
leave
ret ;jmp stop
messageToAuxEnd:
messageToAux endp
start:
mov ax, seg data
mov es, ax
assume es: data
open: ;This opens your existing long, scratch file.
lds dx, nameptr
dos 3d02, <Open named file>
mov handle, ax
position0: ;Then the file is positioned midway through.
mov bx, handle
mov cx,0
mov dx,1000
dos 4200, <Move file pointer>
trunc: ;A zero length record is written.
mov bx, handle
mov cx,0
lds dx,bufptr
dos 4000, <Write zero length record.>
; --------------------------------------------------------
; This is the deal:
; A read beyond the clip point returns no bytes read. i.e.
; the file has been logically truncated. However, no disk
; activity has occured.
;
; If the file is closed now, the size is diminished, and the
; FAT is adjusted.
;
; If I do a dup handle, the close on the duped handle, this
; happens:
; There is disk activity, and the relinquished space is recovered.
; The original handle is still valid, open, and clipped. I can
; read data from it just fine.
; --------------------------------------------------------
dupHandle:
mov bx, handle
dos 4500, <Duplicate file handle.>
close0:
mov bx, ax ;use new handle.
dos 3e00, <Close duplicate file>
position1:
mov bx, handle
mov cx,0
mov dx,1010
dos 4200, <Move file pointer>
read:
; This will report 0 bytes read, but carry is clear.
mov bx, handle
mov cx, 1 ;bytes to read.
lds dx,bufptr
dos 3f00, <Read a byte past implied clip point. Should fail.>
close:
mov bx, handle
dos 3e00, <Close file>
stop:
mov ax, 4c00
int 21
code ends
end start
--
Aubrey McIntosh Freelance using Modula-2
Real time, embedded, instruments.
Austin, TX 78723 Enquiries welcome
1-(512)-452-1540 aubrey%rpp386.Cactus.org at cs.utexas.edu
More information about the Alt.sources
mailing list