home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / ARTFIX09.ZIP / TIMED / DOS-OLD / TIMED.ASM < prev    next >
Assembly Source File  |  1999-10-29  |  15KB  |  496 lines

  1. ; Timed.Asm written 1998 by Tobias Ernst.
  2. ;
  3. ; This file installs interrupt service handlers that are needed by the
  4. ; patched TimEd executable and then spawns the patched TimEd executable,
  5. ; and afterwards deinstalls the interrupt service handlers. The patched
  6. ; TimEd executable is expected to have the name "timed.ovl" and reside
  7. ; in the same directory as the timed.com file that is assembled from
  8. ; timed.asm.
  9. ;
  10. ; This file is written for Borland TASM, but should also work with
  11. ; microsoft MASM and compatible assemblers, though I didn't test it.
  12. ; Assemble as follows:
  13. ;
  14. ; tasm timed.asm
  15. ; tlink timed /t
  16. ;
  17. ; If you use another linker, assure that a .COM file is generated, or
  18. ; convert the EXE file with EXE2BIN. It is important that the file is
  19. ; a .COM file!
  20.  
  21. DGROUP group  _TEXT, _DATA
  22.  
  23. _TEXT        SEGMENT BYTE PUBLIC 'CODE'
  24.         ASSUME CS: DGROUP, DS:DGROUP, SS:DGROUP
  25.  
  26. org             0100h
  27. start:          jmp main
  28.  
  29.  
  30. ; Symbolic contants for the interrupt vectors to use
  31.  
  32.  
  33. vector1         equ 04Dh
  34. vector2         equ 04Eh
  35. vector3         equ 04Fh
  36. vector4         equ 04Bh
  37. vector5         equ 04Ch
  38.  
  39.  
  40. ;  Interrupt Service Routine #1
  41. ;  Function:  Get a year number in tm.tm_year format from [bx+0a],
  42. ;             and push the modulo of the division of this number by 100
  43. ;             to the stack.
  44. ;  Notes:     As an interrupt normally does not leave anything on the
  45. ;             stack, this code looks a bit unconventional
  46. ;  Purpose:   This routine is called when writing a FTSC date stamp
  47. ;             into a *.squish or *.msg base, and when writing a hudson
  48. ;             time stamp. It prevents the 2 digit date field from spilling
  49. ;             (without the modulo 100 operation, "100" would be written
  50. ;             there in the year 2000 instead of 00).
  51.  
  52. service1:       mov cs:[tmpax],ax      ;save AX
  53.  
  54.                 pop ax                 ;get the return address from stack
  55.                 mov cs:[retadd1],ax
  56.                 pop ax
  57.                 mov cs:[retadd2],ax
  58.                 pop ax
  59.                 mov cs:[retadd3],ax
  60.  
  61.                 mov ax, word ptr[bx+0ah]
  62.                 push cx
  63.                 mov cl, 064h          ; only pass the modulo 100 value
  64.                 idiv cl               ; to sprintf
  65.                 pop cx
  66.                 mov al,ah
  67.                 xor ah,ah
  68.                 push ax
  69.  
  70.                 push cs:[retadd3]      ;Now jump back
  71.                 push cs:[retadd2]
  72.                 push cs:[retadd1]
  73.                 mov ax,cs:[tmpax]
  74.                 iret
  75.  
  76. tmpax           dw 0
  77. retadd1         dw 0
  78. retadd2         dw 0
  79. retadd3         dw 0
  80.  
  81.  
  82.  
  83. ;  Interrupt Service Routine #2
  84. ;  Function:  Get a year number in tm.tm_year format from [bx+0a],
  85. ;             add 1900 to it (which will yield a correct four digit number
  86. ;             in all cases, and push it to the stack.
  87. ;  Notes:     As an interrupt normally does not leave anything on the
  88. ;             stack, this code looks a bit unconventional
  89. ;  Purpose:   This routine is called when writing the day number for a
  90. ;             %year variable in a message template. We have patched the
  91. ;             executable to use %4.4d instead of 19%2.2d, so we have to
  92. ;             push a four digit year number now instead of a two digit one.
  93.  
  94. service2:       mov cs:[tmpax_2],ax    ;save AX
  95.  
  96.                 pop ax                 ;get return address from stack
  97.                 mov cs:[retadd1_2],ax
  98.                 pop ax
  99.                 mov cs:[retadd2_2],ax
  100.                 pop ax
  101.                 mov cs:[retadd3_2],ax
  102.  
  103.                 mov ax, word ptr[bx+0ah]
  104.                 add ax, 1900d
  105.                 push ax                ;push the 4 digit year number
  106.  
  107.                 push cs:[retadd3_2]    ;jump back
  108.                 push cs:[retadd2_2]
  109.                 push cs:[retadd1_2]
  110.                 mov ax,cs:[tmpax_2]
  111.                 iret
  112.  
  113. tmpax_2         dw 0
  114. retadd1_2       dw 0
  115. retadd2_2       dw 0
  116. retadd3_2       dw 0
  117.  
  118.  
  119.  
  120. ;  Interrupt Service Routine 3
  121. ;  Function: Convert a two digit year number that has is stored in AX
  122. ;            into a DOS time compliant year number (which gives the
  123. ;            number of years that have been passed since 1980).
  124. ;            The method we use is save until 2080.
  125. ;  Purpose:  Prevent wrong binary timestamps (TimEd derives them from the
  126. ;            two digit FTSC date) in Squish and MSG areas.
  127.  
  128. service3:
  129.                 cmp ax, 80d    ; is ax >= 80
  130.                 jae twc        ; if so ->   19xx
  131.                 add ax, 20d    ; otherwise: 20xx
  132.                 iret
  133. twc:            sub ax, 80d
  134.                 iret
  135.  
  136.  
  137.  
  138.  
  139. ;  Interrupt Service Routine #4
  140. ;  Function:  Get a year number in tm.tm_year format from [si+0a],
  141. ;             and push the modulo of the division of this number by 100
  142. ;             to the stack.
  143. ;  Notes:     As an interrupt normally does not leave anything on the
  144. ;             stack, this code looks a bit unconventional
  145. ;  Purpose:   This routine is called when writing the message info screen.
  146. ;             The modulo operation prevents wrong output like "'110" instead
  147. ;             of "'10" in the year of 2010.
  148.  
  149. service4:       mov cs:[tmpax_4],ax      ;save AX
  150.  
  151.                 pop ax                   ;get the return address from stack
  152.                 mov cs:[retadd1_4],ax
  153.                 pop ax
  154.                 mov cs:[retadd2_4],ax
  155.                 pop ax
  156.                 mov cs:[retadd3_4],ax
  157.  
  158.                 mov ax, word ptr[si+0ah]
  159.                 push cx
  160.                 mov cl, 064h          ; only pass the modulo 100 value
  161.                 idiv cl               ; to sprintf
  162.                 pop cx
  163.                 mov al,ah
  164.                 xor ah,ah
  165.                 push ax
  166.  
  167.                 push cs:[retadd3_4]      ;Now jump back
  168.                 push cs:[retadd2_4]
  169.                 push cs:[retadd1_4]
  170.                 mov ax,cs:[tmpax_4]
  171.                 iret
  172.  
  173. tmpax_4         dw 0
  174. retadd1_4       dw 0
  175. retadd2_4       dw 0
  176. retadd3_4       dw 0
  177.  
  178.  
  179. ;  Interrupt Service Routine #5
  180. ;  Function: - Get a two digit year number from [bp-0eh] to AX
  181. ;            - Convert AX to a "tm.tm_year" compatible year number, that
  182. ;              is, the number of years that have passed since 1900.
  183. ;  Purpose:  This routine is called when reading in a message from the
  184. ;            Hudson Message Base. HMB only has a two digit year field,
  185. ;            so we have to interpret a two digit year number somehow.
  186. ;            Here, we assume that a year number of 00..79 is in 20xx,
  187. ;            while a year number of 80..99 is in 19xx. This makes HMB
  188. ;            save until 12/31/2079.
  189.  
  190. service5:       mov ax, word ptr[bp-0eh]
  191.                 cmp ax, 80d    ; is ax >= 80
  192.                 jae twc2       ; if so ->   19xx
  193.                 add ax, 100d   ; otherwise: 20xx, add 100 dec
  194. twc2:           iret
  195.  
  196.  
  197. ; The main program. These routines install the correct interrupt handlers,
  198. ; execute timed.ovl, and restore the original interrupt handlers. This code
  199. ; is fairly uninteresting.
  200.  
  201. main:
  202.                 mov ax, cs         ; set up the segment registers and stack
  203.                 mov ds, ax
  204.                 mov ss, ax
  205.                 mov es, ax
  206.                 mov ax, offset DGROUP:stack_high
  207.                 mov sp, ax
  208.  
  209.                                    ; free unneeded memory
  210.                 mov bx, offset DGROUP:highwater
  211.                 shr bx, 4
  212.                 inc bx
  213.                 mov ah, 4Ah
  214.                 int 21h
  215.  
  216.                                    ; store the old interrupt vectors
  217.                 mov ah, 35h
  218.                 mov al, vector1
  219.                 int 21h
  220.                 mov [oldofs1],bx
  221.                 mov [oldseg1],es
  222.                 mov al, vector2
  223.                 int 21h
  224.                 mov [oldofs2],bx
  225.                 mov [oldseg2],es
  226.                 mov al, vector3
  227.                 int 21h
  228.                 mov [oldofs3],bx
  229.                 mov [oldseg3],es
  230.                 int 21h
  231.                 mov al, vector4
  232.                 int 21h
  233.                 mov [oldofs4],bx
  234.                 mov [oldseg4],es
  235.                 mov al, vector5
  236.                 int 21h
  237.                 mov [oldofs5],bx
  238.                 mov [oldseg5],es
  239.  
  240.  
  241.  
  242.                                   ; set the new interrupt vectors
  243.                 mov ah,25h
  244.                 mov al, vector1
  245.                 mov dx, offset DGROUP:service1
  246.                 int 21h
  247.                 mov al, vector2
  248.                 mov dx, offset DGROUP:service2
  249.                 int 21h
  250.                 mov al, vector3
  251.                 mov dx, offset DGROUP:service3
  252.                 int 21h
  253.                 mov al, vector4
  254.                 mov dx, offset DGROUP:service4
  255.                 int 21h
  256.                 mov al, vector5
  257.                 mov dx, offset DGROUP:service5
  258.                 int 21h
  259.  
  260.  
  261.  
  262.                                    ; prepare the call to stringops
  263.                 push ds
  264.                 mov ax, offset DGROUP:paramoff
  265.                 push ax
  266.                 push ds
  267.                 mov ax, offset DGROUP:paramseg
  268.                 push ax
  269.                 push ds
  270.                 mov ax, offset DGROUP:prognameoff
  271.                 push ax
  272.                 push ds
  273.                 mov ax, offset DGROUP:prognameseg
  274.                 push ax
  275.  
  276.                 mov ah,062h        ; get PSP
  277.                 int 21h
  278.                 push bx
  279.                 xor  ax,ax
  280.                 push ax
  281.  
  282.                 call _stringops    ; fill in the various structures
  283.                 add sp, 014h
  284.  
  285.  
  286.                 mov ax, [paramseg] ; call the DOS EXEC function
  287.                 mov es, ax
  288.                 mov bx, [paramoff]
  289.                 mov dx, [prognameoff]
  290.                 mov ax, [prognameseg]
  291.                 mov ds, ax
  292.                 mov ax, 04B00h
  293.                 int 21h
  294.  
  295.                 mov ax, cs         ; restore the registers
  296.                 mov ds, ax
  297.                 mov ss, ax
  298.                 mov ax, offset DGROUP:stack_high
  299.                 mov sp, ax
  300.  
  301.  
  302.                 mov bx, ds         ; restore the interrupt vectors
  303.                 mov ah, 25h
  304.  
  305.                 mov al, vector1
  306.                 mov dx, [oldofs1]
  307.                 mov cx, [oldseg1]
  308.                 mov ds, cx
  309.                 int 21h
  310.                 mov ds, bx
  311.  
  312.                 mov al, vector2
  313.                 mov dx, [oldofs2]
  314.                 mov cx, [oldseg2]
  315.                 mov ds, cx
  316.                 int 21h
  317.                 mov ds, bx
  318.  
  319.                 mov al, vector3
  320.                 mov dx, [oldofs3]
  321.                 mov cx, [oldseg3]
  322.                 mov ds, cx
  323.                 int 21h
  324.                 mov ds, bx
  325.  
  326.                 mov al, vector4
  327.                 mov dx, [oldofs4]
  328.                 mov cx, [oldseg4]
  329.                 mov ds, cx
  330.                 int 21h
  331.                 mov ds, bx
  332.  
  333.                 mov al, vector5
  334.                 mov dx, [oldofs5]
  335.                 mov cx, [oldseg5]
  336.                 mov ds, cx
  337.                 int 21h
  338.                 mov ds, bx
  339.  
  340.                 mov ah, 04dh     ; query return code of the .OVL module
  341.                 int 21h
  342.                 mov ah, 04ch     ; terminate program
  343.                 int 21h
  344.  
  345. ; _stringops
  346. ; This function fills in the huge bunch of tables that is required for the
  347. ; DOS exec function. It looks a bit weired, because it has originally been
  348. ; created by a C compiler.
  349.  
  350. _stringops    proc    near
  351.     push    bp
  352.     mov    bp,sp
  353.     sub    sp,12
  354.     push    si
  355.     push    di
  356.  
  357.  
  358.    ;        /* pass the command line on as is */
  359.     les    bx,dword ptr [bp+4]
  360.     mov    al,byte ptr es:[bx+128]
  361.     mov    byte ptr DGROUP:_cmdlin,al
  362.     cmp    byte ptr DGROUP:_cmdlin,126
  363.     jle    short @1@534
  364.     mov    byte ptr DGROUP:_cmdlin,126
  365. @1@534:
  366.     xor    si,si
  367.     jmp    short @1@618
  368. @1@562:
  369.     les    bx,dword ptr [bp+4]
  370.     add    bx,si
  371.     mov    al,byte ptr es:[bx+129]
  372.     mov    byte ptr DGROUP:_cmdlin[si+1],al
  373.     inc    si
  374. @1@618:
  375.     mov    al,byte ptr DGROUP:_cmdlin
  376.     cbw
  377.     cmp    ax,si
  378.     jg    short @1@562
  379.     mov    byte ptr DGROUP:_cmdlin[si+1],13
  380.  
  381.    ;        /* adjust the name of the file to be spawned in the env_block */
  382.     les    bx,dword ptr [bp+4]
  383.     mov    ax,word ptr es:[bx+44]
  384.     mov    word ptr [bp-2],ax
  385.     mov    word ptr [bp-4],0
  386.     mov    ax,word ptr [bp-2]
  387.     mov    dx,word ptr [bp-4]
  388.     mov    word ptr [bp-6],ax
  389.     mov    word ptr [bp-8],dx
  390.     jmp    short @1@702
  391. @1@674:
  392.     inc    word ptr [bp-8]
  393. @1@702:
  394.     les    bx,dword ptr [bp-8]
  395.     cmp    byte ptr es:[bx],1
  396.     jne    short @1@674
  397.     les    bx,dword ptr [bp-8]
  398.     cmp    byte ptr es:[bx+1],0
  399.     jne    short @1@674
  400.  
  401.     mov    ax,word ptr [bp-6]
  402.     mov    dx,word ptr [bp-8]
  403.     add    dx,2
  404.     mov    word ptr [bp-10],ax
  405.     mov    word ptr [bp-12],dx
  406.     mov    word ptr [bp-6],ax
  407.     mov    word ptr [bp-8],dx
  408.     jmp    short @1@814
  409. @1@786:
  410.     inc    word ptr [bp-8]
  411. @1@814:
  412.     les    bx,dword ptr [bp-8]
  413.     cmp    byte ptr es:[bx],0
  414.     jne    short @1@786
  415.     les    bx,dword ptr [bp-8]
  416.     mov    byte ptr es:[bx-3],79
  417.     les    bx,dword ptr [bp-8]
  418.     mov    byte ptr es:[bx-2],86
  419.     les    bx,dword ptr [bp-8]
  420.     mov    byte ptr es:[bx-1],76
  421.    ;        /* fill in the parameter block */
  422.     mov    ax,word ptr [bp-2]
  423.     mov    word ptr DGROUP:_paramblock,ax
  424.     mov    word ptr DGROUP:_paramblock+2,offset DGROUP:_cmdlin
  425.     mov    word ptr DGROUP:_paramblock+4,ds
  426.     mov    word ptr DGROUP:_paramblock+6,offset DGROUP:_fcb2
  427.     mov    word ptr DGROUP:_paramblock+8,ds
  428.     mov    word ptr DGROUP:_paramblock+10,offset DGROUP:_fcb2
  429.          mov    word ptr DGROUP:_paramblock+12,ds
  430.     les    bx,dword ptr [bp+16]
  431.     mov    word ptr es:[bx],ds
  432.     les    bx,dword ptr [bp+20]
  433.     mov    word ptr es:[bx],offset DGROUP:_paramblock
  434.     les    bx,dword ptr [bp+8]
  435.     mov    ax,word ptr [bp-10]
  436.     mov    word ptr es:[bx],ax
  437.     les    bx,dword ptr [bp+12]
  438.     mov    ax,word ptr [bp-12]
  439.     mov    word ptr es:[bx],ax
  440.     pop    di
  441.     pop    si
  442.     mov    sp,bp
  443.     pop    bp
  444.     ret
  445. _stringops    endp
  446.  
  447.  
  448. _TEXT ENDS
  449.  
  450. _DATA        SEGMENT WORD PUBLIC 'DATA'
  451.  
  452.  
  453. ; These variables store the old interrupt vectors
  454. oldseg1      dw ?
  455. oldseg2      dw ?
  456. oldseg3      dw ?
  457. oldseg4      dw ?
  458. oldseg5      dw ?
  459. oldofs1      dw ?
  460. oldofs2      dw ?
  461. oldofs3      dw ?
  462. oldofs4      dw ?
  463. oldofs5      dw ?
  464.  
  465.  
  466. ; These variables are used to exchange data between the main program
  467. ; and the _stringops subroutine
  468. paramoff    dw 1
  469. paramseg    dw 2
  470. prognameoff dw 3
  471. prognameseg dw 4
  472.  
  473. ; We do need a little bit of stack for our own ...
  474. stack_low       dw 128 dup (10)
  475. stack_high      dw 0
  476.  
  477.  
  478. ; These structures are filled in and passed to the DOS EXEC function
  479. _cmdlin    label    byte
  480.     db    128 dup (0)
  481. _paramblock    label    word
  482.     db    16 dup (0)
  483. _fcb2    label    word
  484.     db    35 dup (0)
  485. _fcb1    label    word
  486.     db    35 dup (0)
  487.  
  488. ; This variable marks the last address in the file, so that the rest
  489. ; of the memory can be freed.
  490. highwater db 0
  491.  
  492. _DATA ENDS
  493.  
  494. END start
  495.  
  496.