home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / PC.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  21KB  |  913 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: pc.c 1.5 93/07/16 11:48:17 ROOT_DOS Exp $
  7. *    04 Jun 92    1.2        GT    Bigger stack.                                    *
  8. *    15 Jul 93    1.5        GT    Fix warnings.                                    *
  9. ****************************************************************************/
  10.  
  11. #include <stdio.h>
  12. #include <conio.h>
  13. #include <dir.h>
  14. #include <dos.h>
  15. #include <io.h>
  16. #include <sys/stat.h>
  17. #include <string.h>
  18. #include <process.h>
  19. #include <fcntl.h>
  20. #include <alloc.h>
  21. #include <stdarg.h>
  22. #include <bios.h>
  23. #include "config.h"
  24. #include "global.h"
  25. #include "mbuf.h"
  26. #include "proc.h"
  27. #include "iface.h"
  28. #include "internet.h"
  29. #include "session.h"
  30. #include "socket.h"
  31. #include "cmdparse.h"
  32. #include "pc.h"
  33. #include "ip.h"
  34.  
  35. int start_back __ARGS((void));
  36. int stop_back __ARGS((void));
  37.  
  38. #define    CTLC    0x3
  39. #define    DEL    0x7f
  40.  
  41. static int kbchar __ARGS((void));
  42. extern int Curdisp;
  43. extern struct proc *Display;
  44. FILE *Rawterm;
  45. unsigned _stklen = 16384;
  46. int Tick;
  47. static int32 Starttime;    
  48. int32 Clock;
  49. extern int Escape;
  50.  
  51. #ifdef MULTITASK
  52. int Background = 0;
  53. int Nokeys = 0;
  54. extern unsigned Minheap;
  55. #endif
  56.  
  57. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  58.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  59.  * If this flag is set, the interrupt return code in pcgen.asm will
  60.  * send an End of Interrupt command to the second 8259 as well as the
  61.  * first.
  62.  */
  63. int Isat;
  64.  
  65. static char Ttbuf[BUFSIZ];
  66. static char Tsbuf[BUFSIZ];
  67. static int saved_break;
  68.  
  69. /* Keyboard input buffer */
  70. #define    KBSIZE    256
  71. static struct {
  72.     char buf[KBSIZE];
  73.     char *wp;
  74.     char *rp;
  75.     int cnt;
  76. } Keyboard;
  77.  
  78. int
  79. errhandler(errval,ax,bp,si)
  80. int errval,ax,bp,si;
  81. {
  82.     return 3;    /* Fail the system call */
  83. }
  84.  
  85. /* Called at startup time to set up console I/O, memory heap */
  86. void
  87. ioinit()
  88. {
  89.     /* Fail all I/O errors */
  90.     harderr(errhandler);
  91.  
  92.     /* Save these two file table entries for something more useful */
  93.     fclose(stdaux);
  94.     fclose(stdprn);
  95.     setbuf(stdout,Tsbuf);
  96.  
  97.     Rawterm = fopen("con","wb");
  98.     setbuf(Rawterm,Ttbuf);
  99.     /* this breaks tab expansion so you must use ANSI or NANSI */
  100.     ioctl(fileno(Rawterm), 1, (ioctl(fileno(Rawterm),0) & 0xff) | 0x20);
  101.     saved_break = getcbrk();
  102.     setcbrk(0);
  103.  
  104.     Starttime = bioscnt();
  105.     /* Link timer handler into timer interrupt chain */
  106.     chtimer(btick);
  107.  
  108.     /* Find out what multitasker we're running under, if any */
  109.     chktasker();
  110.  
  111.     /* Initialize keyboard queue */
  112.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  113.  
  114. }
  115. /* Called just before exiting to restore console state */
  116. void
  117. iostop()
  118. {
  119.     struct iface *ifp,*iftmp;
  120.     void (**fp)(void);
  121.  
  122.     setbuf(Rawterm,NULLCHAR);
  123.     ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm), 0) & 0xff & ~0x20);
  124.     setcbrk(saved_break);
  125.  
  126.     for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
  127.         iftmp = ifp->next;
  128.         if_detach(ifp);
  129.     }
  130.     /* Call list of shutdown functions */
  131.     for(fp = Shutdown;*fp != NULLVFP;fp++){
  132.         (**fp)();
  133.     }
  134. }
  135. /* Spawn subshell */
  136. int
  137. doshell(argc,argv,p)
  138. int argc;
  139. char *argv[];
  140. void *p;
  141. {
  142.     char *command;
  143.     int ret;
  144.  
  145. #ifdef MULTITASK
  146.     if(Background) {
  147.         if(!start_back())
  148.             return -1;
  149.         Nokeys++;
  150.     }
  151.     free(mallocw(Minheap)); /* Force heap/core break to reserve a heap */
  152. #endif
  153.  
  154.     if((command = getenv("COMSPEC")) == NULLCHAR)
  155.         command = "/COMMAND.COM";
  156.     ret = spawnv(P_WAIT,command,argv);
  157.  
  158. #ifdef MULTITASK
  159.     if(Background) {
  160.         Nokeys--;
  161.         stop_back();
  162.     }
  163. #endif
  164.  
  165.     return ret;
  166. }
  167.  
  168. #ifdef MULTITASK
  169. /* if multitask mode is set - allow NOS and shell/mail to share system time */
  170. dobackg(argc,argv,p)
  171. int argc;
  172. char *argv[];
  173. void *p;
  174. {
  175.     return setbool(&Background,"Multitasking DOS Shell ",argc,argv);
  176. }
  177. #endif
  178.  
  179. /* Keyboard interrupt handler */
  180. void
  181. kbint()
  182. {
  183.     int sig = 0;
  184.     int c;
  185. #ifdef MULTITASK
  186.     if(Background && Nokeys)
  187.         return;
  188. #endif
  189.     while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
  190.         sig = 1;
  191.         *Keyboard.wp++ = c;
  192.         if(Keyboard.wp == &Keyboard.buf[KBSIZE])
  193.             Keyboard.wp = Keyboard.buf;
  194.         Keyboard.cnt++;
  195.     }
  196.     if(sig){
  197.         psignal(&Keyboard,0);
  198.     }
  199. }
  200. static int
  201. kbchar()
  202. {
  203.     char i_state;
  204.     char c;
  205. #ifdef MULTITASK
  206.     if(Background && Nokeys)
  207.         return -1;
  208. #endif
  209.     i_state = dirps();
  210.     while(Keyboard.cnt == 0)
  211.         pwait(&Keyboard);
  212.     Keyboard.cnt--;
  213.     restore(i_state);
  214.     c = *Keyboard.rp++;
  215.     if(Keyboard.rp == &Keyboard.buf[KBSIZE])
  216.         Keyboard.rp = Keyboard.buf;
  217.     return uchar(c);
  218. }
  219. /* Flush the raw terminal output */
  220. void
  221. rflush()
  222. {
  223.     fflush(Rawterm);
  224. }
  225.  
  226. #ifdef MSDOS
  227. #ifdef ALLCMD
  228. struct funcstr {
  229.     char fkey;
  230.     char alloced;
  231.     char *fvalue;
  232.     int special;
  233. };
  234.  
  235. struct funcstr fkeys[] = {
  236.     { 15,0,NULLCHAR, 0 },    /* tab + shift */
  237.     { 59,1,NULLCHAR, 0 },  /* F1 */
  238.     { 60,1,NULLCHAR, 0 },  /* F2 */
  239.     { 61,1,NULLCHAR, 0 },  /* F3 */
  240.     { 62,1,NULLCHAR, 0 },  /* F4 */
  241.     { 63,0,NULLCHAR, 0 },    /* F5 */
  242.     { 64,0,NULLCHAR, 0 },    /* F6 */
  243.     { 65,0,NULLCHAR, 0 },    /* F7 */
  244.     { 66,0,NULLCHAR, 0 },    /* F8 */
  245.     { 67,0,NULLCHAR, 0 },    /* F9 */
  246.     { 68,0,NULLCHAR, 0 },    /* F10 */
  247.     { 71,1,NULLCHAR, 0 },    /* home*/
  248.     { 72,1,NULLCHAR, 0 },    /* up arrow*/
  249.     { 73,1,NULLCHAR, 0 },    /* pgup */
  250.     { 75,1,NULLCHAR, 0 },    /* left arrow */
  251.     { 77,1,NULLCHAR, 0 },    /* right arrow */
  252.     { 79,1,NULLCHAR, 0 },    /* end */
  253.     { 80,1,NULLCHAR, 0 },    /* down arrow */
  254.     { 81,1,NULLCHAR, 0 },    /* pgdn */
  255.     { 82,1,NULLCHAR, 0 },    /* ins */
  256.     { 83,1,NULLCHAR, 0 },    /* del */
  257.     { 84,0,NULLCHAR, 0 },    /* F1 + shift*/
  258.     { 85,0,NULLCHAR, 0 },    /* F2 + shift*/
  259.     { 86,0,NULLCHAR, 0 },    /* F3 + shift*/
  260.     { 87,0,NULLCHAR, 0 },    /* F4 + shift*/
  261.     { 88,0,NULLCHAR, 0 },    /* F5 + shift*/
  262.     { 89,0,NULLCHAR, 0 },    /* F6 + shift*/
  263.     { 90,0,NULLCHAR, 0 },    /* F7 + shift*/
  264.     { 91,0,NULLCHAR, 0 },    /* F8 + shift*/
  265.     { 92,0,NULLCHAR, 0 },    /* F9 + shift*/
  266.     { 93,0,NULLCHAR, 0 },    /* F10 + shift*/
  267.     { 94,0,NULLCHAR, 0 },    /* F1 + control*/
  268.     { 95,0,NULLCHAR, 0 },    /* F2 + control*/
  269.     { 96,0,NULLCHAR, 0 },    /* F3 + control*/
  270.     { 97,0,NULLCHAR, 0 },    /* F4 + control*/
  271.     { 98,0,NULLCHAR, 0 },    /* F5 + control*/
  272.     { 99,0,NULLCHAR, 0 },    /* F6 + control*/
  273.     { 100,0,NULLCHAR, 0 },    /* F7 + control*/
  274.     { 101,0,NULLCHAR, 0 },    /* F8 + control*/
  275.     { 102,0,NULLCHAR, 0 },    /* F9 + control*/
  276.     { 103,0,NULLCHAR, 0 },    /* F10 + control*/
  277.     { 104,0,NULLCHAR, 0 },    /* F1 + alt*/
  278.     { 105,0,NULLCHAR, 0 },    /* F2 + alt*/
  279.     { 106,0,NULLCHAR, 0 },    /* F3 + alt*/
  280.     { 107,0,NULLCHAR, 0 },    /* F4 + alt*/
  281.     { 108,0,NULLCHAR, 0 },    /* F5 + alt*/
  282.     { 109,0,NULLCHAR, 0 },    /* F6 + alt*/
  283.     { 110,0,NULLCHAR, 0 },    /* F7 + alt*/
  284.     { 111,0,NULLCHAR, 0 },    /* F8 + alt*/
  285.     { 112,0,NULLCHAR, 0 },    /* F9 + alt*/
  286.     { 113,0,NULLCHAR, 0 },    /* F10 + alt*/
  287.     { 114,0,NULLCHAR, 0 },    /* PrtSc + ctl*/
  288.     { 117,0,NULLCHAR, 0 },    /* end    + ctl */
  289.     { 118,0,NULLCHAR, 0 },    /* pgup + ctl */
  290.     { 119,0,NULLCHAR, 0 },    /* home + ctl */
  291.     { 132,0,NULLCHAR, 0 },    /* pgdn + ctl */
  292.     {   0,0,NULLCHAR,0 }
  293. };
  294.  
  295. char Leftover = 0;
  296. char *Nextkey;
  297. #endif /*ALLCMD*/
  298. #endif /*MSDOS*/
  299.  
  300. /* Read characters from the keyboard, translating them to "real" ASCII.
  301.  * If none are ready, block. The F-10 key is special; translate it to -2.
  302.  */
  303. #ifdef ALLCMD
  304. int
  305. kbread()
  306. {
  307. #ifndef    MSDOS
  308.     int c;
  309. #else
  310.     int c,i,j;
  311.  
  312.     if((c = Leftover) != 0)  {
  313.         Leftover = *Nextkey++;
  314.         return c;
  315.     }
  316. #endif    MSDOS
  317.     if((c = kbchar()) == 0){
  318.         /* Lead-in to a special char */
  319.         c = kbchar();
  320.         switch(c){
  321.         case 3:        /* NULL (bizzare!) */
  322.             c = 0;
  323.             break;
  324.         default:    /* Dunno what it is */
  325. #ifdef    MSDOS
  326.             if (c == Escape - 256)
  327.                 return -2;
  328.             for(i=0;(j = fkeys[i].fkey) != 0;i++)
  329.                 if(j == c) {
  330.                     Nextkey = fkeys[i].fvalue;
  331.                     if (fkeys[i].special == 1)
  332.                         {
  333.                         Leftover = *Nextkey++;
  334.                         return -2;
  335.                         }
  336.                     if(Nextkey == NULLCHAR) {
  337. /*                        c = -1; */
  338.                         return c + 255;
  339.                     }
  340.                     if((c = *Nextkey++) != 0)
  341.                         Leftover = *Nextkey++;
  342.                     else
  343.                         c = -1;
  344.                     return c;
  345.                 }
  346. #endif
  347.             c = -1;
  348.         }
  349.     }
  350.     if (c == Escape)
  351.         return -2;
  352.     return c;
  353. }
  354. #else /*ALLCMD*/
  355.  
  356. int
  357. kbread()
  358. {
  359.         int c;
  360.  
  361.         if((c = kbchar()) == 0){
  362.                 /* Lead-in to a special char */
  363.                 c = kbchar();
  364.                 switch(c){
  365.                 case 3:         /* NULL (bizzare!) */
  366.                         c = 0;
  367.                         break;
  368.                 case 68:        /* F-10 key (used as command-mode escape) */
  369.                         c = -2;
  370.                         break;
  371.                 case 83:        /* DEL key */
  372.                         c = 0x7f;
  373.                         break;
  374.                 default:        /* Dunno what it is */
  375.                     if(c > 58 && c < 68)    /* F1 to F9 */
  376.                         c = (c - 56) * -1;
  377.                     else
  378.                         c = -1;
  379.                 }
  380.         }
  381.         return c;
  382. }
  383.  
  384. #endif /*ALLCMD*/
  385.  
  386. #ifdef    MSDOS
  387. #ifdef ALLCMD
  388. int
  389. dofkey(argc,argv,p)
  390. int argc;
  391. char *argv[];
  392. void *p;
  393. {
  394.     int c,i,j;
  395.     char *q, *r, *special;
  396.     char str[100];
  397.  
  398.     if(argc == 1) {
  399.        tprintf("key num    key  num    key  num    key  num   key   num\n");
  400.        tprintf("f1   59    sf1   84    cf1   94    af1  104   pgup   73\n");
  401.        tprintf("f2   60    sf2   85    cf2   95    af2  105   pgdn   81\n");
  402.        tprintf("f3   61    sf3   86    cf3   96    af3  106   home   71\n");
  403.        tprintf("f4   62    sf4   87    cf4   97    af4  107   end    79\n");
  404.        tprintf("f5   63    sf5   88    cf5   98    af5  108   arup   72\n");
  405.        tprintf("f6   64    sf6   89    cf6   99    af6  109   ardn   80\n");
  406.        tprintf("f7   65    sf7   90    cf7  100    af7  110   ar l   75\n");
  407.        tprintf("f8   66    sf8   91    cf8  101    af8  111   ar r   77\n");
  408.        tprintf("f9   67    sf9   92    cf9  102    af9  112   ins    82\n");
  409.        tprintf("f10  68    sf10  93    cf10 103    af10 113   del    83\n");
  410.        tprintf("usage: fkey <key number> [<value> | \"string\"]\n");
  411.        return 0;
  412.     }
  413.  
  414.     c = atoi(argv[1]);
  415.     if(c == 0 || c > 255) {
  416.         tprintf("fkey number out of range.\n");
  417.         return 1;
  418.     }
  419.  
  420.     for(j = 0;(i = fkeys[j].fkey) != 0; j++)
  421.         if(i == c) 
  422.             break;
  423.  
  424.     if(i == 0){
  425.         tprintf("fkey number not found\n");
  426.         return 1;
  427.     }
  428.  
  429.     if(argc == 2) {
  430.         q = fkeys[j].fvalue;
  431.         r = str;
  432.         if(q == NULLCHAR)
  433.             tprintf("fkey %d has no assigned value.\n",c);
  434.         else {
  435.             while(*q)
  436.                 if(*q < ' ') { /* This is ASCII dependent !! */
  437.                     *r++ = '^';
  438.                     *r++ = *q++ + 0x40;
  439.                 } else
  440.                     *r++ = *q++;
  441.             *r = '\0';
  442.             switch (fkeys[j].special)
  443.                 {
  444.             case 1:
  445.                 special = "[command]";
  446.                 break;
  447.             default:
  448.                 special = "";
  449.                 break;
  450.                 }
  451.             tprintf("fkey = %s%s\n",special,str);
  452.         }
  453.         return 0;
  454.     }
  455.  
  456.     if(argc == 3) {
  457.         if(fkeys[j].alloced)
  458.             fkeys[j].alloced = 0;
  459.         else
  460.             if(fkeys[j].fvalue != NULLCHAR)
  461.                 free(fkeys[j].fvalue);
  462.         fkeys[j].special = 0;
  463.  
  464.         r = str;
  465.         q = argv[2];
  466.         if (strncmp(argv[2], "[command]", 9) == 0)
  467.             {
  468.             q += 9;
  469.             fkeys[j].special = 1;
  470.             }
  471.         while(*q){
  472.             if(*q == '^'){    /* ^ gives control char next */
  473.                 q++;
  474.                 if(*q == '^') {
  475.                     *r++ = *q++; /* No, he wants a ^ */
  476.                 } else {
  477.                     *r++ = *q++ & 0x1f;
  478.                 }
  479.             } else
  480.                 *r++ = *q++;
  481.         }
  482.         *r = '\0';
  483.         fkeys[j].fvalue = strdup(str);
  484.     }
  485.     return 0;
  486. }
  487. #endif /*ALLCMD*/
  488. #endif /*MSDOS*/
  489.  
  490. /* Install hardware interrupt handler.
  491.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  492.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  493.  */
  494. int
  495. setirq(irq,handler)
  496. unsigned irq;
  497. INTERRUPT (*handler)();
  498. {
  499.     /* Set interrupt vector */
  500.     if(irq < 8){
  501.         setvect(8+irq,handler);
  502.     } else if(irq < 16){
  503.         Isat = 1;
  504.         setvect(0x70 + irq - 8,handler);
  505.     } else {
  506.         return -1;
  507.     }
  508.     return 0;
  509. }
  510. /* Return pointer to hardware interrupt handler.
  511.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  512.  */
  513. INTERRUPT
  514. (*getirq(irq))()
  515. unsigned int irq;
  516. {
  517.     /* Set interrupt vector */
  518.     if(irq < 8){
  519.         return getvect(8+irq);
  520.     } else if(irq < 16){
  521.         return getvect(0x70 + irq - 8);
  522.     } else {
  523.         return NULLVIFP;
  524.     }
  525. }
  526. /* Disable hardware interrupt */
  527. int
  528. maskoff(irq)
  529. unsigned irq;
  530. {
  531.     if(irq < 8){
  532.         setbit(0x21,(char)(1<<irq));
  533.     } else if(irq < 16){
  534.         irq -= 8;
  535.         setbit(0xa1,(char)(1<<irq));
  536.     } else {
  537.         return -1;
  538.     }
  539.     return 0;
  540. }
  541. /* Enable hardware interrupt */
  542. int
  543. maskon(irq)
  544. unsigned irq;
  545.  {
  546.     if(irq < 8){
  547.         clrbit(0x21,(char)(1<<irq));
  548.     } else if(irq < 16){
  549.         irq -= 8;
  550.         clrbit(0xa1,(char)(1<<irq));
  551.     } else {
  552.         return -1;
  553.     }
  554.     return 0;
  555. }
  556. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  557. int
  558. getmask(irq)
  559. unsigned irq;
  560. {
  561.     if(irq < 8)
  562.         return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  563.     else if(irq < 16){
  564.         irq -= 8;
  565.         return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  566.     } else
  567.         return -1;
  568. }
  569. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  570.  * hardware clock tick. Signal a clock tick to the timer process.
  571.  */
  572. void
  573. ctick()
  574. {
  575.     Tick++;
  576.     psignal(&Tick,1);
  577. }
  578. /* Called from the timer process on every tick. NOTE! This function
  579.  * can NOT be called at interrupt time because it calls the BIOS
  580.  */
  581. void
  582. pctick()
  583. {
  584.     long t;
  585.     static long oldt;    /* Value of bioscnt() on last call */
  586.     static long days;    /* # of times bioscnt() has rolled over */
  587.  
  588.     /* Update the time-since-boot */
  589.     t = bioscnt();
  590.  
  591.     if(t < oldt)
  592.         days++;    /* bioscnt has rolled past midnight */
  593.     oldt = t;
  594.     Clock = (days * 0x1800b0L) + t - Starttime;
  595. }
  596.  
  597. /* Set bit(s) in I/O port */
  598. void
  599. setbit(port,bits)
  600. unsigned port;
  601. char bits;
  602. {
  603.     outportb(port,(char)inportb(port)|bits);
  604. }
  605. /* Clear bit(s) in I/O port */
  606. void
  607. clrbit(port,bits)
  608. unsigned port;
  609. char bits;
  610. {
  611.     outportb(port,(char)(inportb(port) & ~bits));
  612. }
  613. /* Set or clear selected bits(s) in I/O port */
  614. void
  615. writebit(port,mask,val)
  616. unsigned port;
  617. char mask;
  618. int val;
  619. {
  620.     register char x;
  621.  
  622.     x = inportb(port);
  623.     if(val)
  624.         x |= mask;
  625.     else
  626.         x &= ~mask;
  627.     outportb(port,x);
  628. }
  629. /* Convert a pointer to a long integer */
  630. long
  631. ptol(p)
  632. void *p;
  633. {
  634.     long x;
  635.  
  636.     x = FP_OFF(p);
  637. #ifdef    LARGEDATA
  638.     x |= (long)FP_SEG(p) << 16;
  639. #endif
  640.     return x;
  641. }
  642. void *
  643. ltop(l)
  644. long l;
  645. {
  646.     register unsigned seg,offset;
  647.  
  648.     seg = (unsigned int) (l >> 16);
  649.     offset = (unsigned int) l;
  650.     return MK_FP(seg,offset);
  651. }
  652. #ifdef    notdef    /* Assembler versions in pcgen.asm */
  653. /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
  654.  * Product is left in place of the multiplicand, and the carry is
  655.  * returned
  656.  */
  657. int16
  658. longmul(multiplier,n,multiplicand)
  659. int16 multiplier;
  660. int n;                /* Number of words in multiplicand[] */
  661. register int16 *multiplicand;    /* High word is in multiplicand[0] */
  662. {
  663.     register int i;
  664.     unsigned long pc;
  665.     int16 carry;
  666.  
  667.     carry = 0;
  668.     multiplicand += n;
  669.     for(i=n;i != 0;i--){
  670.         multiplicand--;
  671.         pc = carry + (unsigned long)multiplier * *multiplicand;
  672.         *multiplicand = pc;
  673.         carry = pc >> 16;
  674.     }
  675.     return carry;
  676. }
  677. /* Divide a 16-bit divisor into an arbitrary length dividend using
  678.  * long division. The quotient is returned in place of the dividend,
  679.  * and the function returns the remainder.
  680.  */
  681. int16
  682. longdiv(divisor,n,dividend)
  683. int16 divisor;
  684. int n;                /* Number of words in dividend[] */
  685. register int16 *dividend;    /* High word is in dividend[0] */
  686. {
  687.     /* Before each division, remquot contains the 32-bit dividend for this
  688.      * step, consisting of the 16-bit remainder from the previous division
  689.      * in the high word plus the current 16-bit dividend word in the low
  690.      * word.
  691.      *
  692.      * Immediately after the division, remquot contains the quotient
  693.      * in the low word and the remainder in the high word (which is
  694.      * exactly where we need it for the next division).
  695.      */
  696.     unsigned long remquot;
  697.     register int i;
  698.  
  699.     if(divisor == 0)
  700.         return 0;    /* Avoid divide-by-zero crash */
  701.     remquot = 0;
  702.     for(i=0;i<n;i++,dividend++){
  703.         remquot |= *dividend;
  704.         if(remquot == 0)
  705.             continue;    /* Avoid unnecessary division */
  706. #ifdef    __TURBOC__
  707.         /* Use assembly lang routine that returns both quotient
  708.          * and remainder, avoiding a second costly division
  709.          */
  710.         remquot = divrem(remquot,divisor);
  711.         *dividend = remquot;    /* Extract quotient in low word */
  712.         remquot &= ~0xffffL;    /* ... and mask it off */
  713. #else
  714.         *dividend = remquot / divisor;
  715.         remquot = (remquot % divisor) << 16;
  716. #endif
  717.     }
  718.     return remquot >> 16;
  719. }
  720. #endif
  721. void
  722. sysreset()
  723. {
  724.     void (*foo) __ARGS((void));
  725.  
  726.     foo = MK_FP(0xffff,0);    /* FFFF:0000 is hardware reset vector */
  727.     (*foo)();
  728. }
  729. void newscreen(struct session *sp)
  730. {
  731.     if(sp != NULLSESSION)
  732.         sp->screen = callocw(1,sizeof(struct screen));
  733. }
  734. void freescreen(struct session *sp)
  735. {
  736.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  737.         return;
  738.     if(sp->screen->save != NULLCHAR)
  739.         free(sp->screen->save);
  740.     free((char *)sp->screen);
  741. }
  742.  
  743. /* Save specified session screen and resume console screen */
  744. void
  745. swapscreen(old,new)
  746. struct session *old,*new;
  747. {
  748.     struct text_info tr;
  749.  
  750.     if(old == new)
  751.         return;    /* Nothing to do */
  752.  
  753.     fflush(Rawterm);
  754.     gettextinfo(&tr);
  755.     if(old != NULLSESSION){
  756.         /* Save old screen */
  757.         if(old->screen->save == NULLCHAR)
  758.             old->screen->save
  759.              = malloc(2*tr.screenheight*tr.screenwidth);
  760.         if(old->screen->save != NULLCHAR)
  761.             gettext(tr.winleft,tr.wintop,tr.winright,
  762.              tr.winbottom,old->screen->save);
  763.         old->screen->row = tr.cury;
  764.         old->screen->col = tr.curx;
  765.     }
  766.     if(new != NULLSESSION){
  767.         /* Load new screen */
  768.         if(new->screen->save != NULLCHAR){
  769.             puttext(tr.winleft,tr.wintop,tr.winright,
  770.              tr.winbottom,new->screen->save);
  771.             gotoxy(new->screen->col,new->screen->row);
  772.             /* Free the memory (saves 4K on a continuous basis) */
  773.             free(new->screen->save);
  774.             new->screen->save = NULLCHAR;
  775.         } else
  776.             clrscr();    /* Start with a fresh slate */
  777.     }
  778.     alert(Display,1);    /* Wake him up */
  779. }
  780. void
  781. display(i,v1,v2)
  782. int i;
  783. void *v1;
  784. void *v2;
  785. {
  786.     int c;
  787.     struct session *sp;
  788.  
  789.     /* This is very tricky code. Because the value of "Current" can
  790.      * change any time we do a pwait, we have to be careful to detect
  791.      * any change and go back and start again.
  792.      */
  793.     for(;;){
  794.         sp = Current;
  795.  
  796.         if(sp->morewait){
  797.             pwait(&sp->row);
  798.             if(sp != Current || sp->row <= 0){
  799.                 /* Current changed value, or the user
  800.                  * hasn't really hit a key
  801.                  */
  802.                 continue;
  803.             }
  804.             /* Erase the prompt */
  805.             fprintf(Rawterm,"\r        \r");
  806.         }
  807.         sp->morewait = 0;
  808.         if((c = rrecvchar(sp->output)) == -1){
  809.             /* the alert() in swapscreen will cause this to
  810.              * return -1 when current changes
  811.              */
  812.             pwait(NULL);    /* Prevent a nasty loop */
  813.             continue;
  814.         }
  815. #ifdef ANSI
  816.         ansi_putc(sp->screen, c);
  817. #else
  818.         putc(c,Rawterm);
  819. #endif
  820.         if(sp->record != NULLFILE)
  821.             putc(c,sp->record);
  822.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  823.             fprintf(Rawterm,"--More--");
  824.             sp->morewait = 1;
  825.         }
  826.     }
  827. }
  828. /* Return time since startup in milliseconds. If the system has an
  829.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  830.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  831.  * value of the counter and combining it with the global clock tick counter.
  832.  * Otherwise 55 ms resolution is provided.
  833.  *
  834.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  835.  * between the two reads. The tick counter is examined before and after the
  836.  * hardware counter is read. If the tick counter changes, try again.
  837.  * Note: the hardware counter counts down from 65536.
  838.  */
  839. int32
  840. msclock()
  841. {
  842.     int32 hi;
  843.     int16 lo;
  844.     int16 count[4];    /* extended (48-bit) counter of timer clocks */
  845.  
  846.     if(!Isat)
  847.         return Clock * MSPTICK;
  848.  
  849.     do {
  850.         hi = Clock + Tick;
  851.         lo = clockbits();
  852.     } while(hi != Clock + Tick);
  853.  
  854.     count[0] = 0;
  855.     count[1] = hi >> 16;
  856.     count[2] = hi;
  857.     count[3] = -lo;
  858.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  859.     longdiv(13125,4,count);
  860.     return ((long)count[2] << 16) + count[3];
  861. }
  862. /* Return clock in seconds */
  863. int32
  864. secclock()
  865. {
  866.     int32 hi;
  867.     int16 lo;
  868.     int16 count[4];    /* extended (48-bit) counter of timer clocks */
  869.  
  870.     if(!Isat)
  871.         return (Clock * MSPTICK) / 1000L;
  872.  
  873.     do {
  874.         hi = Clock + Tick;
  875.         lo = clockbits();
  876.     } while(hi != Clock + Tick);
  877.  
  878.     count[0] = 0;
  879.     count[1] = hi >> 16;
  880.     count[2] = hi;
  881.     count[3] = -lo;
  882.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  883.     longdiv(13125,4,count);
  884.     longdiv(1000,4,count);    /* Convert to seconds */
  885.     return ((long)count[2] << 16) + count[3];
  886. }
  887.  
  888.  
  889. int
  890. doisat(argc,argv,p)
  891. int argc;
  892. char *argv[];
  893. void *p;
  894. {
  895.     return setbool(&Isat,"AT/386 mode",argc,argv);
  896. }
  897.  
  898. /* Directly read BIOS count of time ticks. This is used instead of
  899.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  900.  * which resets the midnight overflow flag, losing days on the clock.
  901.  */
  902. long
  903. bioscnt()
  904. {
  905.     int i_state;
  906.     long rval;
  907.  
  908.     i_state = dirps();
  909.     rval = * (long far *)MK_FP(0x40,0x6c);
  910.     restore(i_state);
  911.     return rval;
  912. }
  913.