home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / CLFEB88.ZIP / TSRI.LTG < prev   
Encoding:
Text File  |  1988-02-04  |  12.9 KB  |  501 lines

  1. Terminate and Stay Resident Programs by Al Stevens
  2.  
  3. /* -------- Listing 1 - tsr.h --------- */
  4.  
  5. void resinit(void);
  6. void resident_psp(void);
  7. void interrupted_psp(void);
  8. unsigned resident(char *,void interrupt (*)());
  9. void terminate(void);
  10. void restart(void);
  11. void suspend(void);
  12. int get_char(void);
  13. void popup(void);
  14. void openfiles(void);
  15. void closefiles(void);
  16.  
  17. /* ---------- Listing 2 - tsr.c ---------- */
  18.  
  19. #include <dos.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <dir.h>
  23. #include "tsr.h"
  24.  
  25. static union REGS rg;
  26.  
  27. /* -------- modify for the specific TSR ------------ */
  28. unsigned sizeprogram = 9000/16;   /* TSR SIZE (PARAGRAPHS) */
  29. unsigned scancode = 52;              /* HOT KEY SCAN CODE     */
  30. unsigned keymask = 8;              /* HOT KEY STATUS MASK   */
  31. char signature [] = "CLOCK";      /* TSR SIGNATURE           */
  32.  
  33. static void interrupt ifunc();
  34.  
  35. /* --------- main function for the TSR program ------- */
  36. main(argc, argv)
  37. char *argv[];
  38. {
  39.     int ivec;
  40.  
  41.     if ((ivec = resident(signature, ifunc)) != 0)    {
  42.         /* ----- TSR is resident ------- */
  43.         if (argc > 1)    {
  44.             /* ---- there is a command line parameter --- */
  45.             rg.x.ax = 0;
  46.             if (strcmp(argv[1], "quit") == 0)
  47.                 rg.x.ax = 1;
  48.             else if (strcmp(argv[1], "restart") == 0)
  49.                 rg.x.ax = 2;
  50.             else if (strcmp(argv[1], "wait") == 0)
  51.                 rg.x.ax = 3;
  52.             if (rg.x.ax)    {
  53.                 /* -- call the communications interrupt -- */
  54.                 int86(ivec, &rg, &rg);
  55.                 return;
  56. è            }
  57.         }
  58.         printf("\nClock is already resident");
  59.     }
  60.     else    {
  61.         /* ------ initial load of TSR program ------ */
  62.         printf("\nResident clock is loaded");
  63.         openfiles();
  64.         resinit();
  65.     }
  66. }
  67.  
  68. /* -------- TSR communications ISR ---------- */
  69. void interrupt ifunc(bp,di,si,ds,es,dx,cx,bx,ax)
  70. {
  71.     if (ax == 1)            /* "quit" */
  72.         terminate();
  73.     else if (ax == 2)        /* "restart" */
  74.         restart();
  75.     else if (ax == 3)        /* "wait" */
  76.         suspend();
  77. }
  78.  
  79. /* -------- Listing 3 - resident.c --------- */
  80.  
  81. #include <dos.h>
  82. #include <stdio.h>
  83. #include "tsr.h"
  84.  
  85. /* --- vectors ---- */
  86. #define KEYBD   9
  87. #define TIMER   0x1c
  88. #define DISK    0x13
  89. #define VIDEO   0x10
  90. #define ZERODIV 0
  91. #define INT28   0x28
  92. #define CRIT    0x24
  93.  
  94. /* ------ interrupt vector chains ------ */
  95. static void interrupt (*oldtimer)();
  96. static void interrupt (*old28)();
  97. static void interrupt (*oldkb)();
  98. static void interrupt (*olddisk)();
  99. static void interrupt (*oldvideo)();
  100. static void interrupt (*oldcrit)();
  101. extern void interrupt (*ZeroDivVector)();
  102. /* ------ ISRs for the TSR ------- */
  103. static void interrupt newtimer();
  104. static void interrupt new28();
  105. static void interrupt newkb();
  106. static void interrupt newdisk();
  107. static void interrupt newvideo();
  108. static void interrupt newcrit();
  109. /* ------ registers for int86 & dos86 ------- */
  110. static union REGS rg;
  111. èstatic struct SREGS seg;
  112.  
  113. static unsigned dosseg;        /* DOS segment address             */
  114. static unsigned dosbusy;    /* offset to InDOS flag         */
  115. static char far *mydta;        /* TSR's DTA                     */
  116. static unsigned myss;        /* TSR's stack segment             */
  117. static unsigned stack;        /* TSR's stack pointer             */
  118. static unsigned mypsp;        /* TSR's PSP address             */
  119. static unsigned intpsp;        /* Interrupted PSP address         */
  120. static unsigned psps[2];    /* Table of DOS PSP addresses     */
  121. static int pspctr;            /* # of DOS PSP addresses         */
  122. static int resoff;            /* suspend/resume flag             */
  123. static int running;            /* TSR running indicator         */
  124. static int popflg;            /* Hot key pressed flag         */
  125. static int diskflag;        /* Disk BIOS busy flag             */
  126. static int videoflag;        /* Video BIOS busy flag         */
  127. static int cflag;            /* staging area for flags          */
  128.  
  129. /* ------- local prototypes -------- */
  130. static void resterm(void);
  131. static void pspaddr(void);
  132. static void dores(void);
  133.  
  134. /* -------- establish & declare residency --------- */
  135. void resinit()
  136. {
  137.     extern unsigned sizeprogram;    /* defined in popup.c */
  138.  
  139.     segread(&seg);
  140.     myss = seg.ss;
  141.     /* ------ get address of DOS busy flag ---- */
  142.     rg.h.ah = 0x34;
  143.     intdos(&rg, &rg);
  144.     dosseg = _ES;
  145.     dosbusy = rg.x.bx;
  146.     /* ----- get address of resident program's dta ----- */
  147.     mydta = getdta();
  148.     /* -------- get addresses of PID in DOS ------- */
  149.     pspaddr();
  150.     /* ----- get original interrupt vectors ----- */
  151.     oldtimer = getvect(TIMER);
  152.     old28 = getvect(INT28);
  153.     oldkb = getvect(KEYBD);
  154.     olddisk = getvect(DISK);
  155.     oldvideo = getvect(VIDEO);
  156.     /* ----- attach vectors to resident program ----- */
  157.     setvect(TIMER, newtimer);
  158.     setvect(KEYBD, newkb);
  159.     setvect(INT28, new28);
  160.     setvect(DISK, newdisk);
  161.     setvect(VIDEO, newvideo);
  162.     /* ------ compute stack pointer ------- */
  163.     stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300;
  164.     /* ---- restore zero divide interrupt vector --- */
  165.     setvect(ZERODIV, ZeroDivVector);
  166. è    /* ----- terminate and stay resident ------- */
  167.     keep(0, sizeprogram);
  168. }
  169.  
  170. /* ------ BIOS disk functions ISR ------- */
  171. void interrupt newvideo(bp,di,si,ds,es,dx,cx,bx,ax)
  172. {
  173.     videoflag++;
  174.     (*oldvideo)();
  175.     ax = _AX;        /* for the register returns */
  176.     bx = _BX;
  177.     cx = _CX;
  178.     dx = _DX;
  179.     es = _ES;
  180.     di = _DI;
  181.     --videoflag;
  182. }
  183.  
  184. /* -------- critical error ISR ---------- */
  185. void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
  186. {
  187.     ax = 0;            /* ignore critical errors */
  188.     cflag = flgs;    /* for newdisk */
  189. }
  190.  
  191. /* ------ BIOS disk functions ISR ------- */
  192. void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
  193. {
  194.     diskflag++;
  195.     (*olddisk)();
  196.     ax = _AX;        /* for the ax return */
  197.     newcrit();        /* to get current flags register */
  198.     flgs = cflag;   /* newdisk will return oldisk's flags */
  199.     --diskflag;
  200. }
  201.  
  202. /* ----- keyboard ISR ------ */
  203. void interrupt newkb()
  204. {
  205.     extern unsigned scancode;    /* defined in ... */
  206.     extern unsigned keymask;    /* ... popup.c    */
  207.     static int kbval;
  208.  
  209.     if (inportb(0x60) == scancode)    {
  210.         kbval = peekb(0, 0x417);
  211.         if (!resoff && ((kbval & keymask) ^ keymask) == 0)    {
  212.             /* --- reset the keyboard ---- */
  213.             kbval = inportb(0x61);
  214.             outportb(0x61, kbval | 0x80);
  215.             outportb(0x61, kbval);
  216.             disable();
  217.             outportb(0x20, 0x20);
  218.             enable();
  219.             /* ---- set hotkey indicator ---- */
  220.             if (!running)
  221. è                popflg = 1;
  222.             return;
  223.         }
  224.     }
  225.     (*oldkb)();
  226. }
  227.  
  228. /* ----- timer ISR ------- */
  229. void interrupt newtimer()
  230. {
  231.     (*oldtimer)();
  232.     if (popflg && peekb(dosseg, dosbusy) == 0)
  233.         if (diskflag == 0 && videoflag == 0)    {
  234.             outportb(0x20, 0x20);
  235.             popflg = 0;
  236.             dores();
  237.         }
  238. }
  239.  
  240. /* ----- 0x28 ISR -------- */
  241. void interrupt new28()
  242. {
  243.     (*old28)();
  244.     if (popflg && peekb(dosseg, dosbusy) != 0)    {
  245.         popflg = 0;
  246.         dores();
  247.     }
  248. }
  249.  
  250. /* ------ switch psp context from interrupted to TSR ----- */
  251. void resident_psp()
  252. {
  253.     int pp;
  254.  
  255.     /* ------ save interrupted program's psp ----- */
  256.     intpsp = peek(dosseg, *psps);
  257.     /* ----- set resident program's psp ----- */
  258.     for (pp = 0; pp < pspctr; pp++)
  259.         poke(dosseg, psps [pp], mypsp);
  260. }
  261.  
  262. /* ---- switch psp context from TSR to interrupted ---- */
  263. void interrupted_psp()
  264. {
  265.     int pp;
  266.  
  267.     /* ----- reset interrupted program's psp ----- */
  268.     for (pp = 0; pp < pspctr; pp++)
  269.         poke(dosseg, psps [pp], intpsp);
  270. }
  271.  
  272. /* ------ execute the resident program ------- */
  273. static void dores()
  274. {
  275.     static char far *intdta;    /* interrupted DTA             */
  276. è    static unsigned intsp;        /*     "       stack pointer */
  277.     static unsigned intss;        /*     "       stack segment */
  278.     static unsigned ctrl_break; /* Ctrl-Break setting         */
  279.  
  280.     running = 1;
  281.     disable();
  282.     intsp = _SP;
  283.     intss = _SS;
  284.     _SP = stack;
  285.     _SS = myss;
  286.     enable();
  287.     oldcrit = getvect(CRIT);/* redirect critical error     */
  288.     setvect(CRIT, newcrit);
  289.     rg.x.ax = 0x3300;        /* get ctrl break setting      */
  290.     intdos(&rg, &rg);
  291.     ctrl_break = rg.h.dl;
  292.     rg.x.ax = 0x3301;        /* turn off ctrl break logic   */
  293.     rg.h.dl = 0;
  294.     intdos(&rg, &rg);
  295.     intdta = getdta();        /* get interrupted dta         */
  296.     setdta(mydta);            /* set resident dta            */
  297.     resident_psp();            /* swap psps                   */
  298.     popup();                /* execute resident program    */
  299.     interrupted_psp();        /* reset interrupted psp       */
  300.     setdta(intdta);            /* reset interrupted dta       */
  301.     setvect(CRIT, oldcrit);    /* reset critical error        */
  302.     rg.x.ax = 0x3301;        /* reset ctrl break            */
  303.     rg.h.dl = ctrl_break;
  304.     intdos(&rg, &rg);
  305.     disable();                /* reset interrupted stack     */
  306.     _SP = intsp;
  307.     _SS = intss;
  308.     enable();
  309.     running = 0;
  310. }
  311.  
  312. static int avec = 0;
  313.  
  314. /* ------- test to see if the program is already resident
  315.       if not, attach to an available interrupt ---------- */
  316. unsigned resident(signature, ifunc)
  317. char *signature;
  318. void interrupt (*ifunc)();
  319. {
  320.     char *sg;
  321.     unsigned df;
  322.     int vec;
  323.  
  324.     segread(&seg);
  325.     df = seg.ds-seg.cs;
  326.     for (vec = 0x60; vec < 0x68; vec++)    {
  327.         if (getvect(vec) == NULL)    {
  328.             if (!avec)
  329.                 avec = vec;
  330.             continue;
  331. è        }
  332.         for (sg = signature; *sg; sg++)
  333.             if (*sg!=peekb(peek(0,2+vec*4)+df,(unsigned)sg))
  334.                 break;
  335.         if (!*sg)
  336.             return vec;
  337.     }
  338.     if (avec)
  339.         setvect(avec, ifunc);
  340.     return 0;
  341. }
  342.  
  343. /* -------- find address of PID ---------- */
  344. static void pspaddr()
  345. {
  346.     unsigned adr = 0;
  347.     unsigned enddos;    /* offset to the end of DOS */
  348.  
  349.     /* ------- get the current psp --------- */
  350.     rg.h.ah = 0x51;
  351.     intdos(&rg, &rg);
  352.     mypsp = rg.x.bx;
  353.     /* ----- find the end of the DOS segment ------- */
  354.     rg.h.ah = 0x52;
  355.     intdos(&rg, &rg);
  356.     enddos = _ES;
  357.     enddos = peek(enddos, rg.x.bx-2);
  358.     /* ---- search for matches on the psp in dos ---- */
  359.     while (pspctr < 2 &&
  360.             (unsigned)((dosseg<<4) + adr) < (enddos<<4))    {
  361.         if (peek(dosseg, adr) == mypsp)    {
  362.             rg.h.ah = 0x50;
  363.             rg.x.bx = mypsp + 1;
  364.             intdos(&rg, &rg);
  365.             if (peek(dosseg, adr) == mypsp+1)
  366.                 psps[pspctr++] = adr;
  367.             /* ---- reset the original psp ------ */
  368.             rg.h.ah = 0x50;
  369.             rg.x.bx = mypsp;
  370.             intdos(&rg, &rg);
  371.         }
  372.         adr++;
  373.     }
  374. }
  375.  
  376. /* ------- terminate function ----------- */
  377. static void resterm()
  378. {
  379.     static unsigned mcbseg;
  380.  
  381.     closefiles();    /*  close TSR files */
  382.     /* ----- restore the interrupt vectors ----- */
  383.     setvect(TIMER, oldtimer);
  384.     setvect(KEYBD, oldkb);
  385.     setvect(INT28, old28);
  386. è    setvect(DISK, olddisk);
  387.     setvect(VIDEO, oldvideo);
  388.     setvect(avec, (void interrupt (*)()) 0);
  389.     /* ---- get the seg addr of 1st DOS MCB ---- */
  390.     rg.h.ah = 0x52;
  391.     intdos(&rg, &rg);
  392.     mcbseg = _ES;
  393.     mcbseg = peek(mcbseg, rg.x.bx-2);
  394.     /* ---- walk thru mcb chain & release memory ----- */
  395.     segread(&seg);
  396.     while (peekb(mcbseg, 0) == 0x4d)    {
  397.         if (peek(mcbseg, 1) == mypsp)    {
  398.             rg.h.ah = 0x49;
  399.             seg.es = mcbseg+1;
  400.             intdosx(&rg, &rg, &seg);
  401.         }
  402.         mcbseg += peek(mcbseg, 3) + 1;
  403.     }
  404. }
  405.  
  406. /* --------- terminate the resident program --------- */
  407. void terminate()
  408. {
  409.     if (getvect(VIDEO) == (void interrupt (*)()) newvideo)
  410.         if (getvect(DISK) == (void interrupt (*)()) newdisk)
  411.             if (getvect(KEYBD) == newkb)
  412.                 if (getvect(INT28) == new28)
  413.                     if (getvect(TIMER) == newtimer)    {
  414.                         resterm();
  415.                         return;
  416.                     }
  417.     resoff = 1;    /* another TSR is above us, merely suspend */
  418. }
  419.  
  420. /* ------------- restart the resident program --------- */
  421. void restart()
  422. {
  423.     resoff = 0;
  424. }
  425.  
  426. /* ------- put the program on hold -------- */
  427. void suspend()
  428. {
  429.     resoff = 1;
  430. }
  431.  
  432. /* ------------- get a keyboard character ---------------- */
  433. int get_char()
  434. {
  435.      int c;
  436.  
  437.     while (1)    {
  438.         rg.h.ah = 1;
  439.         int86(0x16, &rg, &rg);        /* char ready? */
  440.         if (rg.x.flags & 0x40)    {
  441. è            int86(0x28, &rg, &rg);    /* 0x28 interrupt */
  442.             continue;
  443.         }
  444.         rg.h.ah = 0;
  445.         int86(0x16, &rg, &rg);        /* read the char */
  446.         if (rg.h.al == 0)            /* function key? */
  447.             c = rg.h.ah | 128;        /* adjust scan code */
  448.         else
  449.             c = rg.h.al;
  450.         break;
  451.     }
  452.     return c;
  453. }
  454.  
  455. /* ---------- Listing 4 - clock.c ------------ */
  456.  
  457. /*
  458.  * A sample TSR that is connected with the TSR Library
  459.  * functions. This program will display the current date
  460.  * and time on the screen when the hot key is pressed.
  461.  * The display remains and the TSR stays popped up until
  462.  * another key is pressed.
  463.  */
  464.  
  465. #include <stdio.h>
  466. #include <dos.h>
  467. #include "tsr.h"
  468.  
  469. #define VSEG 0xb800        /* change to 0xb000 for MDA */
  470. #define ROW 10            /* where the clock displays */
  471. #define COL 30
  472.  
  473. void popup()
  474. {
  475.     struct date dat;
  476.     struct time tim;
  477.     int sv[20];
  478.     char bf[20];
  479.     unsigned v;
  480.     static char tmsk [] = " %2d-%02d-%02d %02d:%02d:%02d ";
  481.  
  482.     /* ---- get the current date and time ------ */
  483.     gettime(&tim);
  484.     getdate(&dat);
  485.     /* ----- save the video memory ----- */
  486.     for (v = 0; v < 19; v++)
  487.         sv[v] = peek(VSEG, ((ROW*80+COL) + v) * 2);
  488.     /* ----- build the date/time display ------- */
  489.     sprintf(bf,tmsk,dat.da_day,dat.da_mon,dat.da_year
  490.         % 100,tim.ti_hour, tim.ti_min, tim.ti_sec);
  491.     /* ----- display the date and time -------- */
  492.     for (v = 0; v < 19; v++)
  493.         poke(VSEG, ((ROW*80+COL) + v) * 2, 0x7000 + bf[v]);
  494.     get_char();
  495.     /* -------- restore the video memory ---- */
  496. è    for (v = 0; v < 19; v++)
  497.         poke(VSEG, ((ROW*80+COL) + v) * 2, sv[v]);
  498. }
  499.  
  500. /* ----- startup function, to be used in TSR application ---- */
  501. void openfiles()
  502. {
  503. }
  504.  
  505. /* ----- shutdown function, to be used in TSR application ---- */
  506. void closefiles()
  507. {
  508. }
  509.  
  510.