home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / msdos / c / tsrc.arc / TSR2.LTG next >
Encoding:
Text File  |  1988-02-26  |  18.1 KB  |  556 lines

  1. /* -------- Listing 1 - tsr.h --------- */
  2. void resinit(void);
  3. void resident_psp(void);
  4. void interrupted_psp(void);
  5. int resident(char *);
  6. void terminate(void);
  7. void restart(void);
  8. void suspend(void);
  9. int get_char(void);
  10. void popup(void);
  11. void openfiles(void);
  12. void closefiles(void);
  13. void vpoke(unsigned, unsigned, unsigned);
  14. unsigned vpeek(unsigned, unsigned);
  15. int keyrdy(void);
  16. unsigned getsp(void);
  17. unsigned peek(unsigned, unsigned);
  18. char peekb(unsigned, unsigned);
  19. void poke(unsigned, unsigned, unsigned);
  20. int keyhit(void);
  21.  
  22.  
  23.  
  24. /* ---------- Listing 2 - tsr.c ---------- */
  25. #include <dos.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <bios.h>
  29. #include "tsr.h"
  30. static union REGS rg;
  31. static struct SREGS sg;
  32. /* -------- modify this for each TSR ------------ */
  33. unsigned heaplen = 128;      /* heap length                  */
  34. unsigned scancode = 52;      /* (Period) HOT KEY SCAN CODE   */
  35. unsigned keymask = 8;        /* (Alt)    HOT KEY STATUS MASK */
  36. char signature [] = "CLOCK"; /* TSR SIGNATURE                */
  37. void main(void);
  38. /* --------- main function for the TSR program ------- */
  39. void main()
  40. {
  41.     int r;
  42.     if ((r = resident(signature)) == 0)    {
  43.         printf("\nResident clock is loaded");
  44.         openfiles();
  45.         resinit();
  46.     }
  47.     printf("\nClock is %s", (r == 1 ? "already resident" : "restarted"));
  48. }
  49. /* ------------- get a keyboard character ---------------- */
  50. int get_char()
  51. {
  52.     int c;
  53.     while (keyhit() == 0)
  54.         ;
  55.     c = _bios_keybrd(_KEYBRD_READ);
  56. è    return ((c&0xff)==0) ? (((c>>8)&0xff)|128) : (c&0xff);
  57. }
  58. /* ------- set the Disk Transfer Address ---------- */
  59. void setdta(char far *dta)
  60. {
  61.     rg.h.ah = 0x1a;
  62.     rg.x.dx = FP_OFF(dta);
  63.     sg.ds = FP_SEG(dta);
  64.     int86x(0x21, &rg, &rg, &sg);
  65. }
  66. /* ------- get the Disk Transfer Address ---------- */
  67. char far *getdta(void)
  68. {
  69.     static char far *dta;
  70.     rg.h.ah = 0x2f;
  71.     int86x(0x21, &rg, &rg, &sg);
  72.     FP_SEG(dta) = sg.es;
  73.     FP_OFF(dta) = rg.x.bx;
  74.     return dta;
  75. }
  76. /* ----- peek, peekb, poke --------- */
  77. unsigned peek(unsigned s, unsigned o)
  78. {
  79.     static unsigned far *ip;
  80.     FP_SEG(ip) = s;
  81.     FP_OFF(ip) = o;
  82.     return *ip;
  83. }
  84. char peekb(unsigned s, unsigned o)
  85. {
  86.     static char far *ip;
  87.     FP_SEG(ip) = s;
  88.     FP_OFF(ip) = o;
  89.     return *ip;
  90. }
  91. void poke(unsigned s, unsigned o, unsigned c)
  92. {
  93.     static unsigned far *ip;
  94.     FP_SEG(ip) = s;
  95.     FP_OFF(ip) = o;
  96.     *ip = c;
  97. }
  98.  
  99. /* -------- Listing 3 - resident.c --------- */
  100. #include <dos.h>
  101. #include <conio.h>
  102. #include <stdio.h>
  103. #include <stdlib.h>
  104. #include <malloc.h>
  105. #include "tsr.h"
  106. #pragma intrinsic (inp, outp)
  107. char far *getdta(void);
  108. void setdta(char far *);
  109. static union REGS rg;
  110. static struct SREGS seg;
  111. è/* --- vectors ---- */
  112. #define KEYBD   9
  113. #define VIDEO   0x10
  114. #define TIMER   0x1c
  115. #define DISK    0x13
  116. #define ZERODIV 0
  117. #define INT28   0x28
  118. #define CRIT    0x24
  119. #define CTRLC    0x23
  120. #define CTRLBRK    0x1b
  121. /* ------ interrupt vector chains ------ */
  122. static void (interrupt far *oldbreak)(void);
  123. static void (interrupt far *oldctrlc)(void);
  124. static void (interrupt far *oldtimer)(void);
  125. static void (interrupt far *old28)(void);
  126. static void (interrupt far *oldkb)(void);
  127. static void (interrupt far *oldcrit)(void);
  128. void (interrupt far *olddisk)(void);
  129. void (interrupt far *oldvideo)(void);
  130. /* ------ ISRs for the TSR ------- */
  131. static void interrupt far newtimer(void);
  132. static void interrupt far new28(void);
  133. static void interrupt far newkb(void);
  134. static void interrupt far newcrit(int,int,int,int,int,int,int,int,int,int);
  135. static void interrupt far newbreak(void);
  136. extern void interrupt far newdisk(void);
  137. extern void interrupt far newvideo(void);
  138.  
  139. extern unsigned heaplen;      /* TSR's heap size            */
  140. static unsigned sizeprogram;  /* TSR's program size         */
  141. static unsigned dosseg;       /* DOS segment address        */
  142. static char far *dosbusy;     /* points to InDOS flag       */
  143. static char far *mydta;       /* TSR's DTA                  */
  144. static unsigned intpsp;       /* Interrupted PSP address    */
  145. static unsigned far *psps[2]; /* Table of DOS PSP addresses */
  146. static int pspctr;            /* # of DOS PSP addresses     */
  147. static int popflg;            /* Hot key pressed flag       */
  148. unsigned myss;                /* TSR's stack segment        */
  149. unsigned stack;               /* TSR's stack pointer        */
  150. int suspending;               /* suspend/resume flag        */
  151. int terminating;              /* terminate flag             */
  152. int diskflag;                 /* Disk BIOS busy flag        */
  153. int videoflag;                /* Video BIOS busy flag       */
  154. /* ------- local prototypes -------- */
  155. static void resterm(void);
  156. static void pspaddr(void);
  157. void dores(void);
  158. void _ctermsub(void);
  159. void popup_tsr(void);
  160. /* -------- establish & declare residency --------- */
  161. void resinit()
  162. {
  163.     /* ------ save TSR stack pointer ------- */
  164.     stack = getsp();
  165.     segread(&seg);
  166. è    myss = seg.ss;
  167.     /* ------ get address of DOS busy flag ---- */
  168.     rg.h.ah = 0x34;
  169.     int86x(0x21, &rg, &rg, &seg);
  170.     dosseg = seg.es;
  171.     FP_SEG(dosbusy) = seg.es;
  172.     FP_OFF(dosbusy) = rg.x.bx;
  173.     /* ----- get address of resident program's dta ----- */
  174.     mydta = getdta();
  175.     /* -------- get addresses of PSP in DOS ------- */
  176.     pspaddr();
  177.     /* ----- get original interrupt vectors ----- */
  178.     oldtimer = _dos_getvect(TIMER);
  179.     old28 = _dos_getvect(INT28);
  180.     oldkb = _dos_getvect(KEYBD);
  181.     olddisk = _dos_getvect(DISK);
  182.     oldvideo = _dos_getvect(VIDEO);
  183.     /* ----- attach vectors to resident program ----- */
  184.     _dos_setvect(TIMER, newtimer);
  185.     _dos_setvect(INT28, new28);
  186.     _dos_setvect(KEYBD, newkb);
  187.     _dos_setvect(DISK, newdisk);
  188.     _dos_setvect(VIDEO, newvideo);
  189.     /* ------ compute program size ------- */
  190.     sizeprogram = heaplen/16 + ((myss + (stack+50) / 16) - _psp);
  191.     /* ---- restore zero divide interrupt vector --- */
  192.     _ctermsub();
  193.     /* ----- terminate and stay resident ------- */
  194.     _dos_keep(0, sizeprogram);
  195. }
  196. /* ---------- break handler ------------ */
  197. static void interrupt far newbreak()
  198. {    return;   }
  199. /* -------- critical error ISR ---------- */
  200. static void interrupt far newcrit(es,ds,di,si,bp,sp,bx,dx,cx,ax)
  201. {    ax = 0;   }
  202. static int kbval;
  203. static char far *kmask = (char far *) 0x417;
  204. /* ----- keyboard ISR ------ */
  205. static void interrupt far newkb()
  206. {
  207.     extern unsigned scancode, keymask, running;
  208.     if (scancode && inp(0x60) == scancode)    {
  209.         kbval = *kmask & keymask;
  210.         if (!suspending && kbval == keymask) {
  211.             /* --- reset the keyboard ---- */
  212.             kbval = inp(0x61);
  213.             outp(0x61, kbval | 0x80);
  214.             outp(0x61, kbval);
  215.             outp(0x20, 0x20);
  216.             /* ---- set hotkey indicator ---- */
  217.             if (!running)
  218.                 popflg = 1;
  219.             return;
  220.         }
  221. è    }
  222.     (*oldkb)();
  223. }
  224. /* ----- timer ISR ------- */
  225. static void interrupt far newtimer()
  226. {
  227.     extern unsigned scancode, keymask, running;
  228.     (*oldtimer)();
  229.     if (!scancode)    {
  230.         kbval = *kmask & keymask;
  231.         if (!suspending && kbval == keymask)
  232.             if (!running)
  233.                 popflg = 1;
  234.     }
  235.     if (popflg && *dosbusy == 0)
  236.         if (diskflag == 0 && videoflag == 0)    {
  237.             outp(0x20, 0x20);
  238.             popflg = 0;
  239.             dores();
  240.         }
  241. }
  242. /* ----- INT28 ISR -------- */
  243. static void interrupt far new28()
  244. {
  245.     (*old28)();
  246.     if (popflg && *dosbusy != 0)    {
  247.         popflg = 0;
  248.         dores();
  249.     }
  250. }
  251. /* ------ switch psp context from interrupted to TSR ----- */
  252. void resident_psp()
  253. {
  254.     int pp;
  255.     intpsp = *psps[0];              /* save interrupted program's psp */
  256.     for (pp = 0; pp < pspctr; pp++) /* set resident program's psp */
  257.         *psps [pp] = _psp;
  258. }
  259. /* ---- switch psp context from TSR to interrupted ---- */
  260. void interrupted_psp()
  261. {
  262.     int pp;
  263.     for (pp = 0; pp < pspctr; pp++)  /* reset interrupted program's psp */
  264.         *psps [pp] = intpsp;
  265. }
  266. void popup_tsr()
  267. {
  268.     static char far *intdta;         /* interrupted DTA     */
  269.     static unsigned intsp, intss;    /*     "       stack   */
  270.     static unsigned char ctrl_break; /* Ctrl-Break setting  */
  271.     oldcrit = _dos_getvect(CRIT);/* redirect critical error */
  272.     oldbreak = _dos_getvect(CTRLBRK);
  273.     oldctrlc = _dos_getvect(CTRLC);
  274.     _dos_setvect(CRIT, newcrit);
  275.     _dos_setvect(CTRLBRK, newbreak);
  276. è    _dos_setvect(CTRLC, newbreak);
  277.     rg.x.ax = 0x3300;            /* get ctrl break setting      */
  278.     int86(0x21, &rg, &rg);
  279.     ctrl_break = rg.h.dl;
  280.     rg.x.ax = 0x3301;            /* turn off ctrl break logic   */
  281.     rg.h.dl = 0;
  282.     int86(0x21, &rg, &rg);
  283.     intdta = getdta();           /* get interrupted dta         */
  284.     setdta(mydta);               /* set resident dta            */
  285.     resident_psp();              /* swap psps                   */
  286.     popup();                     /* execute resident program    */
  287.     interrupted_psp();           /* reset interrupted psp       */
  288.     setdta(intdta);              /* reset interrupted dta       */
  289.     _dos_setvect(CRIT, oldcrit); /* reset critical error*/
  290.     _dos_setvect(CTRLBRK, oldbreak);
  291.     _dos_setvect(CTRLC, oldctrlc);
  292.     rg.x.ax = 0x3301;            /* reset ctrl break            */
  293.     rg.h.dl = ctrl_break;
  294.     int86(0x21, &rg, &rg);
  295.     if (terminating)
  296.         terminate();
  297. }
  298. /* ------- test to see if the TSR is already resident ------- */
  299. int resident(signature)
  300. char *signature;
  301. {
  302.     char *sg;
  303.     unsigned df, mcbseg, blkseg;
  304.     segread(&seg);
  305.     df = seg.ds - _psp;
  306.     rg.h.ah = 0x52;    /*  get the seg addr of 1st DOS MCB */
  307.     intdosx(&rg, &rg, &seg);
  308.     mcbseg = peek(seg.es, rg.x.bx-2);
  309.     while (peekb(mcbseg, 0) == 0x4d)  {  /* walk thru chain, srch for TSR */
  310.         blkseg = peek(mcbseg, 1);
  311.         if (peek(blkseg, 0) == 0x20cd)    {
  312.             if (blkseg == _psp)   /* this is a psp */
  313.                 break;            /* if the transient copy */
  314.             for (sg = signature; *sg; sg++)
  315.                 if (*sg!=peekb(blkseg+df,(unsigned)sg))
  316.                     break;
  317.             if (!*sg)    {    /* if TSR is already resident */
  318.                 if (peek(blkseg+df, (unsigned) &suspending))    {
  319.                     poke(blkseg+df, (unsigned) &suspending, 0);
  320.                     return 2;  /* unsuspend a suspended TSR */
  321.                 }
  322.                 return 1;
  323.             }
  324.         }
  325.         mcbseg += peek(mcbseg, 3) + 1;
  326.     }
  327.     return 0;
  328. }
  329. /* -------- find address of PSP ---------- */
  330. static void pspaddr()
  331. è{
  332.     unsigned adr = 0;
  333.     unsigned enddos;    /* offset to the end of DOS */
  334.     static unsigned far *ed, far *ps;
  335.     rg.h.ah = 0x52;     /* find the end of the DOS segment */
  336.     int86x(0x21, &rg, &rg, &seg);
  337.     FP_SEG(ed) = seg.es;
  338.     FP_OFF(ed) = rg.x.bx-2;
  339.     enddos = *ed;
  340.     while (pspctr < 2 &&    /* search for matches on the psp in dos */
  341.             (unsigned)((dosseg<<4) + adr) < (enddos<<4))    {
  342.         FP_SEG(ps) = dosseg;
  343.         FP_OFF(ps) = adr;
  344.         if (*ps == _psp)    {
  345.             rg.h.ah = 0x50;
  346.             rg.x.bx = _psp + 1;
  347.             int86(0x21, &rg, &rg);
  348.             if (*ps == _psp+1)
  349.                 psps[pspctr++] = ps;
  350.             rg.h.ah = 0x50;    /* reset the original psp */
  351.             rg.x.bx = _psp;
  352.             int86(0x21, &rg, &rg);
  353.         }
  354.         adr++;
  355.     }
  356. }
  357. /* ------- terminate function ----------- */
  358. static void resterm()
  359. {
  360.     static unsigned far *env;
  361.     closefiles();    /*  close TSR files */
  362.     _dos_setvect(TIMER, oldtimer);    /*  restore the interrupt vectors */
  363.     _dos_setvect(INT28, old28);
  364.     _dos_setvect(KEYBD, oldkb);
  365.     _dos_setvect(DISK, olddisk);
  366.     _dos_setvect(VIDEO, oldvideo);
  367.     FP_SEG(env) = _psp;    /* release memory owned by the TSR */
  368.     FP_OFF(env) = 0x2c;
  369.     _dos_freemem(*env);
  370.     _dos_freemem(_psp);
  371. }
  372. /* --------- terminate the resident program --------- */
  373. void terminate()
  374. {
  375.     if (_dos_getvect(VIDEO) == (void (interrupt far *)()) newvideo)
  376.         if (_dos_getvect(DISK) == (void (interrupt far *)()) newdisk)
  377.             if (_dos_getvect(KEYBD) == newkb)
  378.                 if (_dos_getvect(INT28) == new28)
  379.                     if (_dos_getvect(TIMER) == newtimer)    {
  380.                         resterm();
  381.                         return;
  382.                     }
  383.     terminating = 0;    /* another TSR is above, suspend */
  384.     suspending = 1;
  385. }
  386. è
  387. ;------------------- Listing 4 - tsrasm.asm ------------------------
  388.         dosseg
  389.         .model small
  390.         .data
  391.         public  _running
  392.         extrn   _myss       : word
  393.         extrn   _stack      : word
  394.         extrn   _suspending : word
  395.         extrn   _olddisk    : dword
  396.         extrn   _oldvideo   : dword
  397.         extrn   _diskflag   : word
  398.         extrn   _videoflag  : word
  399. intss   dw      ?
  400. intsp   dw      ?
  401. _running db     0
  402.         .code
  403. extrn   _popup_tsr : near
  404. public  _getsp
  405. ; -------- return the stack pointer
  406. ;       stackpointer = getsp()
  407. ; ------------------------------------------
  408. _getsp  proc    near
  409.         mov     ax,sp
  410.         ret
  411. _getsp  endp
  412. public  _keyhit
  413. ; ------- test for a keystroke, return 1 if key ready, 0 if not
  414. ;         k = keyhit();
  415. ;--------------------------------------
  416. _keyhit proc    near
  417.         mov     ah,1      ; BIOS read key status
  418.         int     16h
  419.         mov     ah,1      ; in case of ctrl-break
  420.         jnz     keyret    ; if a key is ready
  421.         int     28h       ; else, call int 28 to allow other TSRs in
  422.         mov     ax,0      ; and return false
  423. keyret: ret
  424. _keyhit endp
  425. public  _dores
  426. ; -------- swap the stack and call the popup function
  427. _dores  proc    near
  428.         cmp     _suspending,0
  429.         jne     resret      ; don't pop up if the TSR is suspended
  430.         mov     _running,1  ; prevent reentrant TSRs
  431.         cli
  432.         mov     intss,ss    ; save the interrupted stack
  433.         mov     intsp,sp
  434.         mov     ss,_myss    ; set the TSR's stack
  435.         mov     sp,_stack
  436.         sti
  437.         call    _popup_tsr  ; pop up the TSR utility
  438.         cli
  439.         mov     ss,intss    ; restore the interrupted stack
  440.         mov     sp,intsp
  441. è        sti        
  442.         mov     _running,0
  443. resret: ret
  444. _dores  endp
  445. public  _newdisk
  446. ;--------- 0x13 (disk) BIOS Interrupt Service Routine
  447. _newdisk proc   far
  448.         push    ds
  449.         push    bp
  450.         mov     bp,dgroup   ; set ds to TSR's data segment
  451.         mov     ds,bp
  452.         inc     _diskflag   ; set disk in process flag
  453.         pushf
  454.         call    _olddisk    ; chain to old disk interrupt
  455.         dec     _diskflag   ; reset disk in process flag
  456.         pop     bp
  457.         pop     ds
  458.         ret     2           ; ret 2 passes on the flags
  459. _newdisk endp
  460. public  _newvideo
  461. ;--------- 0x10 (video) BIOS Interrupt Service Routine
  462. _newvideo proc  far
  463.         push    ds
  464.         push    bp
  465.         mov     bp,dgroup   ; set ds to TSR's data segment
  466.         mov     ds,bp
  467.         inc     _videoflag  ; set video in process flag
  468.         pop     bp          ; some EGA functions use bp in
  469.         pushf
  470.         call    _oldvideo   ; chain to old video interrupt
  471.         dec     _videoflag  ; reset video in process flag
  472.         pop     ds
  473.         iret
  474. _newvideo endp
  475. public  _vpoke
  476. ; -------- insert a word into video memory
  477. ;       vpoke(unsigned vseg, unsigned adr, unsigned ch);
  478. ; ------------------------------------------
  479. _vpoke  proc    near
  480.         push    bp
  481.         mov     bp,sp
  482.         push    di
  483.         push    es
  484.         mov     cx,4[bp]  ; video board base address
  485.         mov     es,cx
  486.         mov     di,6[bp]  ; offset address from caller
  487.         cmp     cx,45056  ;mono?
  488.         jz      mono1
  489.         mov     dx,986    ; video status port address
  490. loop1:  in      al,dx     ; wait for retrace to quit
  491.         test    al,1
  492.         jnz     loop1
  493. loop2:  in      al,dx     ; wait for retrace to start
  494.         test    al,1
  495.         jz      loop2
  496. èmono1:  mov     ax,8[bp]  ; word to insert
  497.         stosw             ; insert it
  498.         pop     es
  499.         pop     di
  500.         pop     bp
  501.         ret
  502. _vpoke  endp
  503. public _vpeek
  504. ; -------- retrieve a word from video memory
  505. ;       unsigned vpeek(unsigned vseg, unsigned adr);
  506. ; ------------------------------------------
  507. _vpeek  proc    near
  508.         push    bp
  509.         mov     bp,sp
  510.         push    si
  511.         push    ds
  512.         mov     si,6[bp]  ; offset address
  513.         mov     cx,4[bp]  ; video board base address
  514.         mov     ds,cx                
  515.         cmp     cx,45056  ;mono?
  516.         jz      mono2
  517.         mov     dx,986    ; video status port address
  518. loop3:  in      al,dx     ; wait for retrace to stop
  519.         test    al,1
  520.         jnz     loop3
  521. loop4:  in      al,dx     ; wait for retrace to start
  522.         test    al,1
  523.         jz      loop4
  524. mono2:  lodsw             ; get the word
  525.         pop     ds
  526.         pop     si
  527.         pop     bp
  528.         ret
  529. _vpeek  endp
  530. end
  531.  
  532. /* ---------- Listing 5 - clock.c ------------ */
  533. #include <dos.h>
  534. #include <time.h>
  535. #include "tsr.h"
  536. #define VSG 0xb800    /* video memory segment (MDA=0xb000) */
  537. #define ROW 10        /* where the clock displays */
  538. #define COL 30
  539. #define vad(x,y) ((y)*160+(x)*2)
  540. extern int terminating, suspending;
  541. /* --- function called when TSR is popped up ----- */
  542. void popup()
  543. {
  544.     int c, v;
  545.     unsigned sv[24];
  546.     char *tm;
  547.     long tim;
  548.     for (v = 0; v < 24; v++)    /* save the video memory */
  549.         sv[v] = vpeek(VSG, vad(COL+v, ROW));
  550.     while (!keyhit())    { /* run until a key is pressed    */
  551. è        time(&tim);        /* get the current date and time */
  552.         tm = ctime(&tim);  /* display the date and time     */
  553.         for (v = 0; v < 24; v++)
  554.             vpoke(VSG, vad(COL+v, ROW), *(tm + v) | 0x7000);
  555.     }
  556.     terminating = ((c = get_char()) == 'u');
  557.     suspending = (c == 's');
  558.     /* -------- restore the video memory ---- */
  559.     for (v = 0; v < 24; v++)
  560.         vpoke(VSG, vad(COL+v, ROW), sv[v]);
  561. }
  562. /* --- null startup & shutdown functions --- */
  563. void openfiles() {}
  564. void closefiles() {}
  565.  
  566.