home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1996 September / Simtel-MSDOS-Sep1996-CD2.iso / disc2 / c / unixclib.asm < prev    next >
Assembly Source File  |  1985-10-13  |  10KB  |  330 lines

  1.     title    UNIXCLIB - UNIX/C FUNCTIONS FOR PC/MS-DOS
  2.     page    55,131
  3.  
  4. ; UNIXCLIB - Routines for providing UNIX-like functions for PC/MS-DOS
  5. ;
  6. ; Date of last update: 10/9/85
  7. ;
  8. ; This is a package of routines that 
  9. ;
  10. ;    (1) emulate routines found in the standard C function libraries on
  11. ;        UNIX systems, and/or
  12. ;    (2) help bridge the gap between MS-DOS and Unix.
  13. ;
  14. ;
  15. ; Author credit summary:
  16. ;
  17. ;    Function        Author            Organization
  18. ;
  19. ;    sleep            Lawrence B. Afrin    Clemson University
  20. ;    file_exists            "            "
  21. ;    set_jmp                "            "
  22. ;    long_jmp            "            "
  23. ;
  24. ;
  25. ; This package was conceived by Lawrence B. Afrin of Clemson University.
  26. ; Please send all questions, comments, suggestions, and new routines to
  27. ; LBAFRIN@CLEMSON (CSNet) or LBAFRIN.CLEMSON@CSNET-RELAY (ARPANet).  These
  28. ; routines were principally written for support of DeSmet C, although
  29. ; they can probably be easily interfaced to any C compiler if you know
  30. ; the compiler's mechanism(s) or protocol(s) for calling assembler
  31. ; routines.
  32. ;
  33. ; The current catalog of routines in UNIXCLIB.ASM follows:
  34. ;
  35. ;    sleep(x)        functionally equivalent to UNIX sleep(3) -
  36. ;        int x        pauses execution for x seconds
  37. ;
  38. ;    file_exists(s)        determines whether the named PC/MS-DOS file
  39. ;        char *s        exists - helps in building support for the
  40. ;                UNIX System V O_CREAT feature (create/open
  41. ;                file only if it doesn't already exist)
  42. ;
  43. ;    long_jmp(j)        major enhancement to DeSmet longjmp() -
  44. ;        jmp_buf j;    provides functionality identical to the
  45. ;                standard UNIX longjmp() (which DeSmet doesn't)
  46. ;
  47. ;    set_jmp(j)        major enhancement to DeSmet setjmp() -
  48. ;        jmp_buf j;    provides functionality identical to the
  49. ;                standard UNIX setjmp() (which DeSmet doesn't)
  50. ;
  51. ;
  52. ; Remember, send your contributions to this library to LBAFRIN@CLEMSON.
  53. ; I'm happy to receive DeSmet-related and non-DeSmet-related routines for
  54. ; review.  I can usually respond to submissions within a day or two, but
  55. ; please don't complain if you see my response time lagging.  As a
  56. ; medical student I have to put my academic and patient responsibilities
  57. ; at a higher priority than the public service of supervising this library.
  58. ;
  59. ;                        -- Larry Afrin
  60. ;                           Dept. of Computer Science
  61. ;                           Clemson University
  62.  
  63.  
  64.  
  65. ; Implementation notes for the following 4 routines:  All were tested under
  66. ; MASM v1.00, DeSmet C 2.41, and PC-DOS 3.10.  Most versions of MASM and
  67. ; DeSmet C should work.  I expect that PC/MS-DOS 2.x and 3.0 work fine,
  68. ; too, but I don't think 1.10 will hack it.
  69.  
  70. ;
  71. ; DeSmet puts all code segments in the `pgroup' group and all data segments
  72. ; in the `dgroup' group.
  73. ;
  74. pgroup    group    prog
  75. dgroup    group    data
  76.  
  77. prog    segment    para public 'prog'
  78.     assume    cs:prog,ds:data,es:nothing
  79.  
  80.     public    sleep
  81.     public    file_exists
  82.     public    set_jmp
  83.     public    long_jmp
  84.  
  85. ;
  86. ; sleep - written by Lawrence B. Afrin of Clemson University
  87. ; (lbafrin@clemson).  Provides UNIX-like sleep(3) functionality.
  88. ;
  89. ;    calling mechanism is:    push    <number of seconds to sleep>
  90. ;                call    sleep
  91. ;
  92. ;    note that this limits the maximum sleep time to 65535 seconds
  93. sleep    proc    near
  94.     push    bp            ; enter in a DeSmet-approved (more or
  95.     mov    bp,sp            ;   less) manner
  96.     sub    sp,10
  97.     push    ax            ; save regs
  98.     push    bx
  99.     push    cx
  100.     push    dx
  101.     cmp    ax,0            ; test for sleep(x) where x <= 0
  102.     jg    sleep8
  103.     jmp    sleep7            ; ignore call if such is the case
  104. sleep8:    mov    ah,2ch            ; get the current time from DOS
  105.     int    21h
  106.     mov    [bp-2],cx        ; [bp-4:bp-2] hold the original time
  107.     mov    [bp-4],dx
  108.     mov    [bp-6],cx        ; [bp-8:bp-6] will hold the target
  109.     mov    [bp-8],dx        ;   time (when we end our sleep)
  110.     mov    word ptr [bp-10],60
  111.     mov    ax,[bp+4]
  112.     xor    dx,dx
  113.     div    word ptr [bp-10]
  114.     add    dl,[bp-7]        ; add num of secs (mod 60) to orig secs
  115.     cmp    dl,60
  116.     jl    sleep0
  117.     sub    dl,60            ; overflow of targ secs, so take mod 60
  118.     inc    byte ptr [bp-6]        ;   and increment target minutes
  119. sleep0:    mov    [bp-7],dl
  120.     cmp    ax,0
  121.     je    sleep3
  122.     xor    dx,dx
  123.     div    word ptr [bp-10]
  124.     add    dl,[bp-6]        ; add num of mins (mod 60) to targ mins
  125.     cmp    dl,60
  126.     jl    sleep1
  127.     sub    dl,60            ; overflow of targ mins, so take mod 60
  128.     inc    byte ptr [bp-5]        ;   and increment target hours
  129. sleep1:    mov    [bp-6],dl
  130.     cmp    ax,0
  131.     je    sleep3
  132.     add    al,[bp-5]
  133.     cmp    al,24
  134.     jl    sleep2
  135.     sub    al,24
  136. sleep2:    mov    [bp-5],al        ; by now we know our target time
  137.                     ; now let's start looping until we hit
  138.                     ;   the target time
  139. sleep3:    mov    ah,2ch            ; top of loop: get current time
  140.     int    21h
  141.     mov    ax,[bp-6]
  142.     mov    bx,[bp-8]
  143.     cmp    cx,[bp-2]    ; if current time >= original time (don't have
  144.     jg    sleep4        ;   to worry about 24 hour wraparound because
  145.     jl    sleep6        ;   max number of sleep secs = 65535, which
  146.     cmp    dx,[bp-4]    ;   is < 24 hours (= 86400))
  147.     jl    sleep6
  148. sleep4:    cmp    ax,[bp-2]    ;   then if target time <= original time
  149.     jg    sleep5
  150.     jl    sleep3
  151.     cmp    bx,[bp-4]
  152.     jle    sleep3        ;          then loop again
  153. sleep5:    cmp    cx,ax        ;          else if current time >= target time
  154.     jg    sleep7        ;                 then exit
  155.     jl    sleep3        ;                 else loop again
  156.     cmp    dx,bx
  157.     jl    sleep3
  158.     jmp    sleep7
  159. sleep6:    cmp    ax,[bp-2]    ;   else if target time > original time
  160.     jg    sleep7
  161.     cmp    bx,[bp-4]
  162.     jg    sleep7        ;          then exit
  163.     cmp    cx,ax        ;          else if current time >= target time
  164.     jg    sleep7        ;                 then exit
  165.     jl    sleep3        ;                 else loop again
  166.     cmp    dx,bx
  167.     jl    sleep3
  168. sleep7:    pop    dx        ; exit
  169.     pop    cx
  170.     pop    bx
  171.     pop    ax
  172.     mov    sp,bp
  173.     pop    bp
  174.     ret
  175. sleep    endp
  176.  
  177.  
  178. ;
  179. ; file_exists - written by Lawrence B. Afrin of Clemson University
  180. ; (lbafrin@clemson).  Tells caller whether specified PC/MS-DOS file
  181. ; already exists.  Helpful in building higher level file system support
  182. ; such as for the O_CREAT flag in the UNIX System V open(2) call.
  183. ;
  184. ;    calling mechanism is:    push    <address (in data seg) of filename string>
  185. ;                call    file_exists
  186. ;
  187. ;    returns AX = 0 if file does not exist
  188. ;        AX = 1 if file does exist
  189. ;
  190. ; Note that file_exists temporarily establishes a new Disk Transfer Address.
  191. ;
  192.  
  193. data    segment    para public 'data'
  194.  
  195. file_exists_dta    db    128 dup (?)
  196. old_dta_seg    dw    ?
  197. old_dta_off    dw    ?
  198.  
  199. data    ends
  200.  
  201. file_exists    proc    near
  202.     push    bp            ; play DeSmet games
  203.     mov    bp,sp
  204.     push    bx
  205.     push    cx
  206.     push    dx
  207.     push    es
  208.     mov    ah,2fh            ; get old dta
  209.     int    21h
  210.     mov    old_dta_seg,es        ; save old dta
  211.     mov    old_dta_off,bx
  212.     mov    dx,offset dgroup:file_exists_dta
  213.     mov    ah,1ah
  214.     int    21h            ; set up temp dta
  215.     mov    dx,[bp+4]
  216.     mov    ah,4eh
  217.     mov    cx,0
  218.     int    21h            ; ask DOS if file exists
  219.     mov    cx,1            ; assume it does
  220.     cmp    ax,0            ; does it?
  221.     je    file_exists_x        ; yup
  222.     mov    cx,0            ; whoops, no it doesn't
  223. file_exists_x:
  224.     push    cx            ; save return code
  225.     push    ds
  226.     mov    dx,old_dta_off
  227.     mov    ax,old_dta_seg
  228.     mov    ds,ax
  229.     mov    ah,1ah
  230.     int    21h            ; restore old dta
  231.     pop    ds
  232.     pop    ax            ; restore return code
  233.     pop    es
  234.     pop    dx
  235.     pop    cx
  236.     pop    bx
  237.     mov    sp,bp
  238.     pop    bp
  239.     ret
  240. file_exists    endp
  241.  
  242.  
  243. ; set_jmp and long_jmp - written by Lawrence B. Afrin of Clemson University
  244. ; (lbafrin@clemson).  Provides UNIX-like setjmp(3) and longjmp(3) function-
  245. ; ality, significantly extends functionality of DeSmet counterparts.
  246. ;
  247. ; Note that the type of the "jmp_buf"-type variable in this implementation
  248. ; is a three-element one-dimensional integer array.  (The C statement would be
  249. ; "typedef int jmp_buf[3];".
  250. ;
  251. ; set_jmp:
  252. ;    calling mechanism is:    push    <address (in data seg) of jmp_buf var>
  253. ;                call    set_jmp
  254. ;
  255. ;    returns AX = 0
  256. ;
  257. ; long_jmp:
  258. ;    calling mechanism is:    push    <value to be faked as set_jmp return val>
  259. ;                push    <address (in data seg) of jmp_buf var>
  260. ;                call    long_jmp
  261. ;
  262. ;    causes a return with AX = "fake return val" to the instruction follow-
  263. ;    ing the call to set_jmp that was made specifying the same jmp_buf
  264. ;    variable
  265. ;
  266. ; IMPORTANT NOTES!!!
  267. ;
  268. ;    (1) These routines are specific for DeSmet C and probably no other C
  269. ;        compilers.  They depend heavily on the DeSmet protocol used
  270. ;        to manage stack frames.
  271. ;    (2) The same warnings as in the DeSmet manual apply here.  A long_jmp
  272. ;        into a routine containing the corresponding set_jmp, when the
  273. ;        target routine is no longer "active" (i.e., on the stack), has
  274. ;        a totally unguaranteed result.
  275. ;    (3) The performance of these routines under the DeSmet debugger has
  276. ;        not been tested.  Use at your own risk!
  277. ;
  278. ;
  279. ; How It Works
  280. ;
  281. ;    The DeSmet "environment" that needs to be saved and restored by
  282. ;    set_jmp/long_jmp consists of an address to jump/return to, the
  283. ;    current frame pointer (found in BP), and the current stack
  284. ;    pointer (you guessed it, SP).  set_jmp saves these values into
  285. ;    the jmp_buf, and long_jmp restores SP and BP and then plays a
  286. ;    trick so that when it returns, it actually is as if the
  287. ;    corresponding set_jmp were returning (except that the return value
  288. ;    is as specified in the call to long_jmp).
  289. ;
  290.  
  291. set_jmp    proc    near
  292.     push    bp        ; we're going to do this without disturbing
  293.     push    bx        ;   regs except the return value reg, AX
  294.     mov    bp,sp        ; let's get some addressability here
  295.     mov    bx,[bp+6]    ; load the jmp_buf address into BX
  296.     mov    ax,[bp+4]    ; load the target jump address into AX
  297.     mov    [bx],ax        ; tuck this address away in (int) jmp_buf[0]
  298.     lea    ax,[bp+6]    ; load into AX the value that we're going to
  299.                 ;   want to give SP in the long_jmp
  300.     mov    [bx+2],ax    ; tuck that away in (int) jmp_buf[1]
  301.     mov    ax,[bp+2]    ; load into AX the BP (frame ptr) we saved above
  302.     mov    [bx+4],ax    ; save that, too, in (int) jmp_buf[2]
  303.     pop    bx        ; that's it!  now restore regs,
  304.     pop    bp
  305.     mov    ax,0        ; set the return code
  306.     ret            ; and get out of here
  307. set_jmp    endp
  308.  
  309. long_jmp    proc    near    ; notice that we get away with this without
  310.                 ;   having to play with any registers not
  311.                 ;   intimately involved in the concept of
  312.                 ;   a long_jmp; neat, huh?
  313.     mov    bp,sp        ; use bp for work variable
  314.     mov    ax,[bp+4]    ; load long_jmp's 2nd argument as the return val
  315.     mov    bp,[bp+2]    ; now point bp at the jmp_buf
  316.     mov    sp,ds:[bp+2]    ; load SP
  317.     push    ds:[bp+0]    ; push the target address onto the `new' stack
  318.     mov    bp,ds:[bp+4]    ; load BP
  319.                 ; (The stack should now be looking *exactly*
  320.                 ; as if it's ready for a NEAR-type return
  321.                 ; from the corresponding set_jmp call, except
  322.                 ; that AX has the return value specified in
  323.                 ; the long_jmp call.)
  324.     ret            ; let's get back to work
  325. long_jmp    endp
  326.  
  327. prog    ends
  328.  
  329.     end
  330.