home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1996 September
/
Simtel-MSDOS-Sep1996-CD2.iso
/
disc2
/
c
/
unixclib.asm
< prev
next >
Wrap
Assembly Source File
|
1985-10-13
|
10KB
|
330 lines
title UNIXCLIB - UNIX/C FUNCTIONS FOR PC/MS-DOS
page 55,131
; UNIXCLIB - Routines for providing UNIX-like functions for PC/MS-DOS
;
; Date of last update: 10/9/85
;
; This is a package of routines that
;
; (1) emulate routines found in the standard C function libraries on
; UNIX systems, and/or
; (2) help bridge the gap between MS-DOS and Unix.
;
;
; Author credit summary:
;
; Function Author Organization
;
; sleep Lawrence B. Afrin Clemson University
; file_exists " "
; set_jmp " "
; long_jmp " "
;
;
; This package was conceived by Lawrence B. Afrin of Clemson University.
; Please send all questions, comments, suggestions, and new routines to
; LBAFRIN@CLEMSON (CSNet) or LBAFRIN.CLEMSON@CSNET-RELAY (ARPANet). These
; routines were principally written for support of DeSmet C, although
; they can probably be easily interfaced to any C compiler if you know
; the compiler's mechanism(s) or protocol(s) for calling assembler
; routines.
;
; The current catalog of routines in UNIXCLIB.ASM follows:
;
; sleep(x) functionally equivalent to UNIX sleep(3) -
; int x pauses execution for x seconds
;
; file_exists(s) determines whether the named PC/MS-DOS file
; char *s exists - helps in building support for the
; UNIX System V O_CREAT feature (create/open
; file only if it doesn't already exist)
;
; long_jmp(j) major enhancement to DeSmet longjmp() -
; jmp_buf j; provides functionality identical to the
; standard UNIX longjmp() (which DeSmet doesn't)
;
; set_jmp(j) major enhancement to DeSmet setjmp() -
; jmp_buf j; provides functionality identical to the
; standard UNIX setjmp() (which DeSmet doesn't)
;
;
; Remember, send your contributions to this library to LBAFRIN@CLEMSON.
; I'm happy to receive DeSmet-related and non-DeSmet-related routines for
; review. I can usually respond to submissions within a day or two, but
; please don't complain if you see my response time lagging. As a
; medical student I have to put my academic and patient responsibilities
; at a higher priority than the public service of supervising this library.
;
; -- Larry Afrin
; Dept. of Computer Science
; Clemson University
; Implementation notes for the following 4 routines: All were tested under
; MASM v1.00, DeSmet C 2.41, and PC-DOS 3.10. Most versions of MASM and
; DeSmet C should work. I expect that PC/MS-DOS 2.x and 3.0 work fine,
; too, but I don't think 1.10 will hack it.
;
; DeSmet puts all code segments in the `pgroup' group and all data segments
; in the `dgroup' group.
;
pgroup group prog
dgroup group data
prog segment para public 'prog'
assume cs:prog,ds:data,es:nothing
public sleep
public file_exists
public set_jmp
public long_jmp
;
; sleep - written by Lawrence B. Afrin of Clemson University
; (lbafrin@clemson). Provides UNIX-like sleep(3) functionality.
;
; calling mechanism is: push <number of seconds to sleep>
; call sleep
;
; note that this limits the maximum sleep time to 65535 seconds
sleep proc near
push bp ; enter in a DeSmet-approved (more or
mov bp,sp ; less) manner
sub sp,10
push ax ; save regs
push bx
push cx
push dx
cmp ax,0 ; test for sleep(x) where x <= 0
jg sleep8
jmp sleep7 ; ignore call if such is the case
sleep8: mov ah,2ch ; get the current time from DOS
int 21h
mov [bp-2],cx ; [bp-4:bp-2] hold the original time
mov [bp-4],dx
mov [bp-6],cx ; [bp-8:bp-6] will hold the target
mov [bp-8],dx ; time (when we end our sleep)
mov word ptr [bp-10],60
mov ax,[bp+4]
xor dx,dx
div word ptr [bp-10]
add dl,[bp-7] ; add num of secs (mod 60) to orig secs
cmp dl,60
jl sleep0
sub dl,60 ; overflow of targ secs, so take mod 60
inc byte ptr [bp-6] ; and increment target minutes
sleep0: mov [bp-7],dl
cmp ax,0
je sleep3
xor dx,dx
div word ptr [bp-10]
add dl,[bp-6] ; add num of mins (mod 60) to targ mins
cmp dl,60
jl sleep1
sub dl,60 ; overflow of targ mins, so take mod 60
inc byte ptr [bp-5] ; and increment target hours
sleep1: mov [bp-6],dl
cmp ax,0
je sleep3
add al,[bp-5]
cmp al,24
jl sleep2
sub al,24
sleep2: mov [bp-5],al ; by now we know our target time
; now let's start looping until we hit
; the target time
sleep3: mov ah,2ch ; top of loop: get current time
int 21h
mov ax,[bp-6]
mov bx,[bp-8]
cmp cx,[bp-2] ; if current time >= original time (don't have
jg sleep4 ; to worry about 24 hour wraparound because
jl sleep6 ; max number of sleep secs = 65535, which
cmp dx,[bp-4] ; is < 24 hours (= 86400))
jl sleep6
sleep4: cmp ax,[bp-2] ; then if target time <= original time
jg sleep5
jl sleep3
cmp bx,[bp-4]
jle sleep3 ; then loop again
sleep5: cmp cx,ax ; else if current time >= target time
jg sleep7 ; then exit
jl sleep3 ; else loop again
cmp dx,bx
jl sleep3
jmp sleep7
sleep6: cmp ax,[bp-2] ; else if target time > original time
jg sleep7
cmp bx,[bp-4]
jg sleep7 ; then exit
cmp cx,ax ; else if current time >= target time
jg sleep7 ; then exit
jl sleep3 ; else loop again
cmp dx,bx
jl sleep3
sleep7: pop dx ; exit
pop cx
pop bx
pop ax
mov sp,bp
pop bp
ret
sleep endp
;
; file_exists - written by Lawrence B. Afrin of Clemson University
; (lbafrin@clemson). Tells caller whether specified PC/MS-DOS file
; already exists. Helpful in building higher level file system support
; such as for the O_CREAT flag in the UNIX System V open(2) call.
;
; calling mechanism is: push <address (in data seg) of filename string>
; call file_exists
;
; returns AX = 0 if file does not exist
; AX = 1 if file does exist
;
; Note that file_exists temporarily establishes a new Disk Transfer Address.
;
data segment para public 'data'
file_exists_dta db 128 dup (?)
old_dta_seg dw ?
old_dta_off dw ?
data ends
file_exists proc near
push bp ; play DeSmet games
mov bp,sp
push bx
push cx
push dx
push es
mov ah,2fh ; get old dta
int 21h
mov old_dta_seg,es ; save old dta
mov old_dta_off,bx
mov dx,offset dgroup:file_exists_dta
mov ah,1ah
int 21h ; set up temp dta
mov dx,[bp+4]
mov ah,4eh
mov cx,0
int 21h ; ask DOS if file exists
mov cx,1 ; assume it does
cmp ax,0 ; does it?
je file_exists_x ; yup
mov cx,0 ; whoops, no it doesn't
file_exists_x:
push cx ; save return code
push ds
mov dx,old_dta_off
mov ax,old_dta_seg
mov ds,ax
mov ah,1ah
int 21h ; restore old dta
pop ds
pop ax ; restore return code
pop es
pop dx
pop cx
pop bx
mov sp,bp
pop bp
ret
file_exists endp
; set_jmp and long_jmp - written by Lawrence B. Afrin of Clemson University
; (lbafrin@clemson). Provides UNIX-like setjmp(3) and longjmp(3) function-
; ality, significantly extends functionality of DeSmet counterparts.
;
; Note that the type of the "jmp_buf"-type variable in this implementation
; is a three-element one-dimensional integer array. (The C statement would be
; "typedef int jmp_buf[3];".
;
; set_jmp:
; calling mechanism is: push <address (in data seg) of jmp_buf var>
; call set_jmp
;
; returns AX = 0
;
; long_jmp:
; calling mechanism is: push <value to be faked as set_jmp return val>
; push <address (in data seg) of jmp_buf var>
; call long_jmp
;
; causes a return with AX = "fake return val" to the instruction follow-
; ing the call to set_jmp that was made specifying the same jmp_buf
; variable
;
; IMPORTANT NOTES!!!
;
; (1) These routines are specific for DeSmet C and probably no other C
; compilers. They depend heavily on the DeSmet protocol used
; to manage stack frames.
; (2) The same warnings as in the DeSmet manual apply here. A long_jmp
; into a routine containing the corresponding set_jmp, when the
; target routine is no longer "active" (i.e., on the stack), has
; a totally unguaranteed result.
; (3) The performance of these routines under the DeSmet debugger has
; not been tested. Use at your own risk!
;
;
; How It Works
;
; The DeSmet "environment" that needs to be saved and restored by
; set_jmp/long_jmp consists of an address to jump/return to, the
; current frame pointer (found in BP), and the current stack
; pointer (you guessed it, SP). set_jmp saves these values into
; the jmp_buf, and long_jmp restores SP and BP and then plays a
; trick so that when it returns, it actually is as if the
; corresponding set_jmp were returning (except that the return value
; is as specified in the call to long_jmp).
;
set_jmp proc near
push bp ; we're going to do this without disturbing
push bx ; regs except the return value reg, AX
mov bp,sp ; let's get some addressability here
mov bx,[bp+6] ; load the jmp_buf address into BX
mov ax,[bp+4] ; load the target jump address into AX
mov [bx],ax ; tuck this address away in (int) jmp_buf[0]
lea ax,[bp+6] ; load into AX the value that we're going to
; want to give SP in the long_jmp
mov [bx+2],ax ; tuck that away in (int) jmp_buf[1]
mov ax,[bp+2] ; load into AX the BP (frame ptr) we saved above
mov [bx+4],ax ; save that, too, in (int) jmp_buf[2]
pop bx ; that's it! now restore regs,
pop bp
mov ax,0 ; set the return code
ret ; and get out of here
set_jmp endp
long_jmp proc near ; notice that we get away with this without
; having to play with any registers not
; intimately involved in the concept of
; a long_jmp; neat, huh?
mov bp,sp ; use bp for work variable
mov ax,[bp+4] ; load long_jmp's 2nd argument as the return val
mov bp,[bp+2] ; now point bp at the jmp_buf
mov sp,ds:[bp+2] ; load SP
push ds:[bp+0] ; push the target address onto the `new' stack
mov bp,ds:[bp+4] ; load BP
; (The stack should now be looking *exactly*
; as if it's ready for a NEAR-type return
; from the corresponding set_jmp call, except
; that AX has the return value specified in
; the long_jmp call.)
ret ; let's get back to work
long_jmp endp
prog ends
end