UMBC CMSC 211

UMBC | CSEE


Random Access

When we work with disk files, we do not have to process things in sequential order. We can get to any byte in the file to start our processing. Remember that when you open the file, you must open it with the correct access method. It is very common to want up update random files, so you must open it for ReadWrite. Actually, the hardest part of this is to make sure you change to the current position pointer to the correct spot in the file.

If the file has a fix-length format, that every record is the same size, then it is very easy to locate the proper position. It is simply:

newPosition = ( desiredRecordNumber - 1) * recordLength Subtract one from the desired record number, because record numbers are zero-based. If you want the 8th record of 80 characters, 7 * 80 = 560. Move to the 560th byte in the file and there you are.

Variable length records are more difficult and require a more advanced technique to get to the correct location, such as indexing or hashing. Again, though, once you know where to go, it is only one step to get there.

For our purposes, that one step is a macro, _LSeek. (All four general registers are used, so I recommend that you use sLSeek instead).

;;
;;	_LSeek	Handle, Handle, SeekType, LoDistance[, HiDistance]
;;              SeekType is the actual numerical value of 
;;              the seek type, 0, 1, 2, or one of the corresponding
;;              symbolic values FromStart, FromCur, or FromEnd
;;              Seek distance is a double-word integer
;;              HiDistanceLoDistance.
;;              If disktance is single precision,positive or 
;;              negative, HiDistancecan be omitted
;;              If success, returns Carry Flag clear and new 
;;              current position is in DX/AX
;;
  
Note the following cases for seek type:
SeekType distance locates to
FromStart 0 the beginning of the file (a 'rewind')
FromStart n absolute byte n in the file
FromCur n > 0 n bytes forward from the current location
FromCur -n, n > 0 n bytes backward from the current location
FromEnd 0 the end of the file and (AX, DX becomes the file length)
FromEnd -n, n < 0 n bytes back from the end of the file
FromCur 0 File position (unchanged) to AX, DX

If we look at the underlying DOS command be have:

Input Parameters

AH 42H
AL
0 seek relative to start of file
1 seek relative to current file pointer
2 seek relative to end of file
BX file handle of opened disk file
CX most significant part of offset
DX least significant part of offset

Output Parameters

An Example

;; LOG.ASM--Program looks for a file LOGFILE in current directory
;;  and if it doesn't exist, creates one.  It then appends to
;;  this file current date and time (form mm/dd/yy hh:mm:ss), then
;;  on the following line, indented four spaces, writes the 
;;  rest of the command that invoked it.
;;
;;  LOG makes use of a procedure TwoDigs defined here which takes
;;   number from 0 to 99 in al and converts it to two consecutive
;;   ASCII digits at si.  Si is then updated to point to the 
;;   character after the second digit, + 1.
;;
;;  Program text from "Assembly Language for the IBM PC Family" by
;;   William B. Jones, (c) Copyright 1992, 1997, 2001, Scott/Jones Inc.
;;
INCLUDE PCMAC.INC
    
        .MODEL  SMALL
        .586
    
        .STACK  100h
    
IFDEF   ??version
PSP     SEGMENT AT 0 USE16
ELSE
PSP     SEGMENT AT 0
ENDIF
        ORG     128
CmdLen  DB      ?
Command DB      127 DUP (?)
PSP     ENDS

        .DATA
FileName DB     'LOGFILE', 0
AccessMsg DB    'Cannot access LOGFILE$'
NoCreate DB     'Cannot create LOGFILE$'
WErrMsg DB      'LOGFILE write error$'
Stamp   DB      'mm/dd/yy hh:mm:ss'
CRLF    DB      13, 10 ;    Used both for Stamp and by itself
STAMPLEN EQU    $ - Stamp ; Number of bytes to write for Stamp
INDENT  EQU     4
LogIndent DB     INDENT DUP (' ')

Do2     MACRO   whence
        mov     al, &whence&
        call    TwoDigs
        ENDM

        .CODE
        EXTRN   CCheck : NEAR, WCheck : NEAR
Logger  PROC
        _Begin
        ASSUME  es:PSP
    

        _Open   FileName, Write ;   Get Log File
        jnc     GotLogFile
        _Creat  FileName ;   File doesn't exist (or is read-only)

        call    CCheck ;          Try to make it

GotLogFile:
        mov     di, ax ;        Save handle in di

        _LSeek  di, FromEnd, 0 ; Seek to end of file

        call    CCheck

;  Write date and time stamp

        _GetDate
        mov     si, OFFSET Stamp
        Do2     dh ;        Month
        Do2     dl ;        Day
        mov     ax, cx ;        Reduce year to 2 digits
        mov     bl, 100 ;        avoiding Y2K-type problems
        div     bl
        Do2     ah ;        Year % 100
        _GetTime
        Do2     ch ;        Hour
        Do2     cl ;        Minute
        Do2     dh ;        Second
        _Write  di, Stamp, STAMPLEN
        call    WCheck

;  Write log message

        _Write  di, LogIndent, INDENT
        call    WCheck
        push    ds ;    must have ds --> PSP for next _Write
        mov     al, CmdLen
        sub     ah, ah ;        Convert CmdLen to word
        _Write  di, Command, ax, es
        pop     ds
        call    WCheck
        _Write  di, CRLF, 2
        call    WCheck
    
        _Close  di
        _Exit   0

Logger  ENDP

TwoDigs PROC

        aam     ; Standard trick to convert # <= 99 to
        add     ax, '00' ;  two ASCII digits; store at [si]
        xchg    ah, al

        mov     [si], ax
        add     si, 3 ; skip si over digits and punctuation

        ret

TwoDigs ENDP

        END     Logger


  


UMBC | CSEE