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