home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / CON_OUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-02  |  27.5 KB  |  1,044 lines

  1. #line 1 "CON_OUT.C"
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /**********************************************************************/
  6. /* Functions that pertain to console i/o - color, strings, chars etc. */
  7. /* Called from functions everywhere                                   */
  8. /**********************************************************************/
  9.  
  10. #include "sbbs.h"
  11.  
  12. extern char *mnestr;
  13.  
  14. /***************************************************/
  15. /* Seven bit table for EXASCII to ASCII conversion */
  16. /***************************************************/
  17. char *sbtbl="CUeaaaaceeeiiiAAEaAooouuyOUcLYRfaiounNao?--24!<>"
  18.             "###||||++||++++++--|-+||++--|-+----++++++++##[]#"
  19.             "abrpEout*ono%0ENE+><rj%=o..+n2* ";
  20.  
  21. char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  22. char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
  23.             ,"Jul","Aug","Sep","Oct","Nov","Dec"};
  24.  
  25. uchar outchar_esc=0;
  26.  
  27. #ifdef __WIN32__
  28.  
  29. int lclatr(int atr)
  30. {
  31.  
  32. textattr(atr);
  33. return(curatr);
  34. }
  35.  
  36. void lputc(ch)
  37. {
  38. switch(ch) {
  39.     case CLREOL:
  40.         clreol();
  41.         break;
  42.     case FF:
  43.         clrscr();
  44.         break;
  45.     case TAB:
  46.         if(!(wherex()%8))
  47.             putchar(SP);
  48.         while(wherex()%8)
  49.             putchar(SP);
  50.         break;
  51.     default:
  52.         putchar(ch);
  53.         break; }
  54. }
  55.  
  56. #endif
  57.  
  58. #ifdef __OS2__
  59.  
  60. HEV con_out_sem;                    /* Console command semaphore */
  61.  
  62. #define CON_OUT_BUFLEN        8192    /* Console output (ANSI) buffer */
  63. #define CON_BLK_BUFLEN        4096    /* Console block (all same atr) buffer */
  64.  
  65. uchar conoutbuf[CON_OUT_BUFLEN];
  66. uchar conblkbuf[CON_BLK_BUFLEN];
  67. volatile uint  conblkcnt=0;
  68. volatile uint  conoutbot=0;
  69. volatile uint  conouttop=0;
  70.  
  71. uchar lcl_curatr=LIGHTGRAY;
  72.  
  73. /****************************************************************************/
  74. /* Prints one block of text (all same attribute) at current cursor position */
  75. /****************************************************************************/
  76. void print_conblkbuf()
  77. {
  78. conblkbuf[conblkcnt]=0;
  79. cputs(conblkbuf);
  80. conblkcnt=0;
  81. }
  82.  
  83. void con_outch(int ch)
  84. {
  85.     static uchar ansi_esc;
  86.     static uchar ansi_curval;
  87.     static uchar ansi_val[3];
  88.     static uchar ansi_x;
  89.     static uchar ansi_y;
  90.     int x,y;
  91.  
  92. if(ch==ESC) {
  93.     ansi_esc=1;
  94.     ansi_val[0]=ansi_val[1]=ansi_val[2]=ansi_curval=0;
  95.     return; }
  96.  
  97. if(ansi_esc==1) {           /* Received ESC already */
  98.     if(ch=='[') {
  99.         ansi_esc++;
  100.         return; }
  101.     ansi_esc=ansi_val[0]=ansi_val[1]=ansi_val[2]=ansi_curval=0; }
  102.  
  103. if(ansi_esc==2) {           /* Received ESC[ already */
  104.  
  105.     if(isdigit(ch)) {
  106.         if(ansi_curval>2) ansi_curval=0;
  107.         ansi_val[ansi_curval]*=10;
  108.         ansi_val[ansi_curval]+=ch&0xf;
  109.         return; }
  110.  
  111.     if(ch==';') {
  112.         ansi_curval++;
  113.         return; }
  114.  
  115.     /* looks like valid ANSI, so purge the output block */
  116.     if(conblkcnt)
  117.         print_conblkbuf();
  118.     switch(ch) {
  119.         case 'A': // Move cursor up
  120.             y=wherey();
  121.             if(ansi_val[0])
  122.                 y-=ansi_val[0];
  123.             else
  124.                 y--;
  125.             if(y<1) y=1;
  126.             gotoxy(wherex(),y);
  127.             break;
  128.         case 'B': // Move cursor down
  129.             y=wherey();
  130.             if(ansi_val[0])
  131.                 y+=ansi_val[0];
  132.             else
  133.                 y++;
  134.             if(y>node_scrnlen) y=node_scrnlen;
  135.             gotoxy(wherex(),y);
  136.             break;
  137.         case 'C': // Move cursor right
  138.             x=wherex();
  139.             if(ansi_val[0])
  140.                 x+=ansi_val[0];
  141.             else
  142.                 x++;
  143.             if(x>80) x=80;
  144.             gotoxy(x,wherey());
  145.             break;
  146.         case 'D': // Move cursor left
  147.             x=wherex();
  148.             if(ansi_val[0])
  149.                 x-=ansi_val[0];
  150.             else
  151.                 x--;
  152.             if(x<1) x=1;
  153.             gotoxy(x,wherey());
  154.             break;
  155.         case 'J': // clear screen
  156.             if(ansi_val[0]==2)
  157.                 clrscr();
  158.             break;
  159.         case 'K': // clearn from cursor to end of line
  160.             clreol();
  161.             break;
  162.         case 'H': // Position cursor
  163.         case 'f':
  164.             y=ansi_val[0];
  165.             x=ansi_val[1];
  166.             if(x<1) x=1;
  167.             if(x>80) x=80;
  168.             if(y<1) y=1;
  169.             if(y>node_scrnlen) y=node_scrnlen;
  170.             gotoxy(x,y);
  171.             break;
  172.         case 's': // Save cursor position
  173.             ansi_x=wherex();
  174.             ansi_y=wherey();
  175.             break;
  176.         case 'u': // Restore cursor position
  177.             if(ansi_x)
  178.                 gotoxy(ansi_x,ansi_y);
  179.             break;
  180.         case 'm': // Select character attributes
  181.             for(x=0;x<=ansi_curval;x++)
  182.                 switch(ansi_val[x]) {
  183.                     case 0: // no special attributes
  184.                     case 8: // concealed text (no display)
  185.                         lcl_curatr=LIGHTGRAY;
  186.                         break;
  187.                     case 1: // high intensity
  188.                     case 3: // italic
  189.                     case 4: // underline
  190.                         lcl_curatr|=HIGH;
  191.                         break;
  192.                     case 2: // low intensity
  193.                         lcl_curatr&=~HIGH;
  194.                         break;
  195.                     case 5: // blink
  196.                     case 6: // rapid blink
  197.                     case 7: // reverse video
  198.                         lcl_curatr|=BLINK;
  199.                         break;
  200.                     case 30: // foreground black
  201.                         lcl_curatr&=0xf8;
  202.                         lcl_curatr|=BLACK;
  203.                         break;
  204.                     case 31: // foreground red
  205.                         lcl_curatr&=0xf8;
  206.                         lcl_curatr|=RED;
  207.                         break;
  208.                     case 32: // foreground green
  209.                         lcl_curatr&=0xf8;
  210.                         lcl_curatr|=GREEN;
  211.                         break;
  212.                     case 33: // foreground yellow
  213.                         lcl_curatr&=0xf8;
  214.                         lcl_curatr|=BROWN;
  215.                         break;
  216.                     case 34: // foreground blue
  217.                         lcl_curatr&=0xf8;
  218.                         lcl_curatr|=BLUE;
  219.                         break;
  220.                     case 35: // foreground magenta
  221.                         lcl_curatr&=0xf8;
  222.                         lcl_curatr|=MAGENTA;
  223.                         break;
  224.                     case 36: // foreground cyan
  225.                         lcl_curatr&=0xf8;
  226.                         lcl_curatr|=CYAN;
  227.                         break;
  228.                     case 37: // foreground white
  229.                         lcl_curatr&=0xf8;
  230.                         lcl_curatr|=LIGHTGRAY;
  231.                         break;
  232.                     case 40: // background black
  233.                         lcl_curatr&=0x8f;
  234.                         lcl_curatr|=(BLACK<<4);
  235.                         break;
  236.                     case 41: // background red
  237.                         lcl_curatr&=0x8f;
  238.                         lcl_curatr|=(RED<<4);
  239.                         break;
  240.                     case 42: // background green
  241.                         lcl_curatr&=0x8f;
  242.                         lcl_curatr|=(GREEN<<4);
  243.                         break;
  244.                     case 43: // background yellow
  245.                         lcl_curatr&=0x8f;
  246.                         lcl_curatr|=(BROWN<<4);
  247.                         break;
  248.                     case 44: // background blue
  249.                         lcl_curatr&=0x8f;
  250.                         lcl_curatr|=(BLUE<<4);
  251.                         break;
  252.                     case 45: // background magenta
  253.                         lcl_curatr&=0x8f;
  254.                         lcl_curatr|=(MAGENTA<<4);
  255.                         break;
  256.                     case 46: // background cyan
  257.                         lcl_curatr&=0x8f;
  258.                         lcl_curatr|=(CYAN<<4);
  259.                         break;
  260.                     case 47: // background white
  261.                         lcl_curatr&=0x8f;
  262.                         lcl_curatr|=(LIGHTGRAY<<4);
  263.                         break; }
  264.             textattr(lcl_curatr);
  265.             break; }
  266.  
  267.     ansi_esc=ansi_val[0]=ansi_val[1]=ansi_val[2]=ansi_curval=0;
  268.     return; }
  269.  
  270. if(conblkcnt+1>=CON_BLK_BUFLEN)
  271.     print_conblkbuf();
  272. switch(ch) {
  273.     case CLREOL:
  274.         if(conblkcnt) print_conblkbuf();
  275.         clreol();
  276.         break;
  277.     case FF:
  278.         if(conblkcnt) print_conblkbuf();
  279.         clrscr();
  280.         break;
  281.     case TAB:
  282.         if(conblkcnt) print_conblkbuf();
  283.         if(!(wherex()%8))
  284.             putch(SP);
  285.         while(wherex()%8)
  286.             putch(SP);
  287.         break;
  288.     default:
  289.         conblkbuf[conblkcnt++]=ch;
  290.         break; }
  291. }
  292.  
  293.  
  294. /****************************************************************************/
  295. /* Thread that services the console output buffer (conoutbuf) which         */
  296. /* contains ANSI escape sequences                                            */
  297. /* All output is for the text window (mirroring the remote console)         */
  298. /****************************************************************************/
  299. void con_out_thread(void *unused)
  300. {
  301.     int i,top,cnt;
  302.     ulong l;
  303.  
  304. while(1) {
  305.     mswait(1);
  306.     if(conoutbot==conouttop) {
  307.         DosWaitEventSem(con_out_sem,10000);  /* every 10 seconds */
  308.         DosResetEventSem(con_out_sem,&l);
  309.         continue; }
  310.     top=conouttop;
  311.     if(top<conoutbot)
  312.         cnt=CON_OUT_BUFLEN-conoutbot;
  313.     else
  314.         cnt=top-conoutbot;
  315.     for(i=conoutbot;i<conoutbot+cnt;i++)
  316.         con_outch(conoutbuf[i]);
  317.     conoutbot=i;
  318.     if(conblkcnt)
  319.         print_conblkbuf();
  320.     if(conoutbot==CON_OUT_BUFLEN)
  321.         conoutbot=0; }
  322. }
  323.  
  324.  
  325.  
  326. void outcon(char ch)
  327. {
  328.     int i=conouttop+1;
  329.  
  330. if(i==CON_OUT_BUFLEN)
  331.     i=0;
  332. while(conoutbot==i) // Wait for thread to service queue
  333.     mswait(1);
  334. conoutbuf[conouttop++]=ch;
  335. if(conouttop==CON_OUT_BUFLEN)
  336.     conouttop=0;
  337. DosPostEventSem(con_out_sem);     // Enable output
  338. }
  339.  
  340. int outcon_pending()
  341. {
  342. if(conoutbot!=conouttop)
  343.     return(1);
  344. if(conblkcnt) {
  345.     print_conblkbuf();
  346.     return(1); }
  347. return(0);
  348. }
  349.  
  350. int conaes()
  351. {
  352. return(outchar_esc==2);
  353. }
  354.  
  355. void lputc(int ch)
  356. {
  357.  
  358. while(outcon_pending())
  359.     mswait(1);
  360. switch(ch) {
  361.     case CLREOL:
  362.         clreol();
  363.         break;
  364.     case FF:
  365.         clrscr();
  366.         break;
  367.     case TAB:
  368.         if(!(wherex()%8))
  369.             putch(SP);
  370.         while(wherex()%8)
  371.             putch(SP);
  372.         break;
  373.     default:
  374.         putch(ch);
  375.         break; }
  376. }
  377.  
  378. long lputs(char *str)
  379. {
  380. while(outcon_pending())
  381.     mswait(1);
  382. return(cputs(str));
  383. }
  384.  
  385. int lclwx(void)
  386. {
  387. while(outcon_pending())
  388.     mswait(1);
  389. return(wherex());
  390. }
  391.  
  392. int lclwy(void)
  393. {
  394. while(outcon_pending())
  395.     mswait(1);
  396. return(wherey());
  397. }
  398.  
  399. void lclxy(int x, int y)
  400. {
  401. while(outcon_pending())
  402.     mswait(1);
  403. gotoxy(x,y);
  404. }
  405.  
  406. int lclatr(int x)
  407. {
  408.     int i;
  409.  
  410. while(conoutbot!=conouttop)     /* wait for output buf to empty */
  411.     mswait(1);
  412. if(x==-1)
  413.     return(lcl_curatr);
  414.  
  415. textattr(x);
  416. i=lcl_curatr;
  417. lcl_curatr=x;
  418. return(i);        /* Return previous attribute */
  419. }
  420.  
  421. #endif
  422.  
  423. /****************************************************************************/
  424. /* Outputs a NULL terminated string locally and remotely (if applicable)    */
  425. /* Handles ctrl-a characters                                                */
  426. /****************************************************************************/
  427. int bputs(char *str)
  428. {
  429.     int i;
  430.     ulong l=0;
  431.  
  432. while(str[l]) {
  433.     if(str[l]==1) {             /* ctrl-a */
  434.         ctrl_a(str[++l]);       /* skip the ctrl-a */
  435.         l++;                    /* skip the attribute code */
  436.         continue; }
  437.     if(str[l]=='@') {           /* '@' */
  438.         if(str==mnestr            /* Mnemonic string or */
  439.             || (str>=text[0]    /* Straight out of TEXT.DAT */
  440.                 && str<=text[TOTAL_TEXT-1])) {
  441.             i=atcodes(str+l);        /* return 0 if not valid @ code */
  442.             l+=i;                    /* i is length of code string */
  443.             if(i)                    /* if valid string, go to top */
  444.                 continue; }
  445.         for(i=0;i<TOTAL_TEXT;i++)
  446.             if(str==text[i])
  447.                 break;
  448.         if(i<TOTAL_TEXT) {        /* Replacement text */
  449.             //lputc(7);
  450.             i=atcodes(str+l);
  451.             l+=i;
  452.             if(i)
  453.                 continue; } }
  454.     outchar(str[l++]); }
  455. return(l);
  456. }
  457.  
  458. /****************************************************************************/
  459. /* Outputs a NULL terminated string locally and remotely (if applicable)    */
  460. /* Does not expand ctrl-a characters (raw)                                  */
  461. /* Max length of str is 64 kbytes                                           */
  462. /****************************************************************************/
  463. int rputs(char *str)
  464. {
  465.     ulong l=0;
  466.  
  467. while(str[l])
  468.     outchar(str[l++]);
  469. return(l);
  470. }
  471.  
  472. /****************************************************************************/
  473. /* Performs printf() through local assembly routines                        */
  474. /* Called from everywhere                                                   */
  475. /****************************************************************************/
  476. int lprintf(char *fmat, ...)
  477. {
  478.     va_list argptr;
  479.     char sbuf[256];
  480.     int chcount;
  481.  
  482. va_start(argptr,fmat);
  483. chcount=vsprintf(sbuf,fmat,argptr);
  484. va_end(argptr);
  485. lputs(sbuf);
  486. return(chcount);
  487. }
  488.  
  489. /****************************************************************************/
  490. /* Performs printf() using bbs bputs function                                */
  491. /****************************************************************************/
  492. int bprintf(char *fmt, ...)
  493. {
  494.     va_list argptr;
  495.     char sbuf[1024];
  496.  
  497. if(!strchr(fmt,'%'))
  498.     return(bputs(fmt));
  499. va_start(argptr,fmt);
  500. vsprintf(sbuf,fmt,argptr);
  501. va_end(argptr);
  502. return(bputs(sbuf));
  503. }
  504.  
  505. /****************************************************************************/
  506. /* Performs printf() using bbs rputs function                                */
  507. /****************************************************************************/
  508. int rprintf(char *fmt, ...)
  509. {
  510.     va_list argptr;
  511.     char sbuf[1024];
  512.  
  513. va_start(argptr,fmt);
  514. vsprintf(sbuf,fmt,argptr);
  515. va_end(argptr);
  516. return(rputs(sbuf));
  517. }
  518.  
  519. /****************************************************************************/
  520. /* Outputs character locally and remotely (if applicable), preforming echo  */
  521. /* translations (X's and r0dent emulation) if applicable.                    */
  522. /****************************************************************************/
  523. void outchar(char ch)
  524. {
  525.     char lch;
  526.     int i;
  527.  
  528. if(console&CON_ECHO_OFF)
  529.     return;
  530. if(ch==ESC)
  531.     outchar_esc=1;
  532. else if(outchar_esc==1) {
  533.     if(ch=='[')
  534.         outchar_esc++;
  535.     else
  536.         outchar_esc=0; }
  537. else
  538.     outchar_esc=0;
  539. if(useron.misc&NO_EXASCII && ch&0x80)
  540.     ch=sbtbl[(uchar)ch^0x80];  /* seven bit table */
  541. if(ch==FF && lncntr>1 && !tos) {
  542.     lncntr=0;
  543.     CRLF;
  544.     pause();
  545.     while(lncntr && online && !(sys_status&SS_ABORT))
  546.         pause(); }
  547. if(sys_status&SS_CAP    /* Writes to Capture File */
  548.     && (sys_status&SS_ANSCAP || (ch!=ESC && !lclaes())))
  549.     fwrite(&ch,1,1,capfile);
  550. if(console&CON_L_ECHO) {
  551.     if(console&CON_L_ECHOX && (uchar)ch>=SP)
  552.         outcon('X');
  553.     else if(node_misc&NM_NOBEEP && ch==7);     /* Do nothing if beep */
  554.     else if(ch==7) {
  555.             beep(2000,110);
  556.             nosound(); }
  557.     else outcon(ch); }
  558. if(online==ON_REMOTE && console&CON_R_ECHO) {
  559.     if(console&CON_R_ECHOX && (uchar)ch>=SP)
  560.         ch='X';
  561.     i=0;
  562.     while(outcom(ch)&TXBOF && i<1440) { /* 3 minute pause delay */
  563.  
  564.         if(lkbrd(1)) {
  565.             lch=lkbrd(0);    /* ctrl-c */
  566.             if(lch==3) {
  567.                 lputs("local abort (outchar)\r\n");
  568.                 i=1440;
  569.                 break; }
  570.             ungetkey(lch); }
  571.         if(!DCDHIGH)
  572.             break;
  573.         i++;
  574.         if(sys_status&SS_SYSPAGE)
  575.             beep(i,80);
  576.         else
  577.             mswait(80); }
  578.     if(i==1440) {                            /* timeout - beep flush outbuf */
  579.         i=rioctl(TXBC);
  580.         lprintf("timeout(outchar) %04X %04X\r\n",i,rioctl(IOFO));
  581.         outcom(7);
  582.         lputc(7);
  583.         rioctl(IOCS|PAUSE); } }
  584. if(ch==LF) {
  585.     lncntr++;
  586.     lbuflen=0;
  587.     tos=0; }
  588. else if(ch==FF) {
  589.     lncntr=0;
  590.     lbuflen=0;
  591.     tos=1; }
  592.  
  593. else {
  594.     if(!lbuflen)
  595.         latr=curatr;
  596.     if(lbuflen<LINE_BUFSIZE)
  597.         lbuf[lbuflen++]=ch; }
  598.  
  599. if(lncntr==rows-1 && ((useron.misc&UPAUSE && !(sys_status&SS_PAUSEOFF))
  600.     || sys_status&SS_PAUSEON)) {
  601.     lncntr=0;
  602.     pause(); }
  603.  
  604. }
  605.  
  606.  
  607. /****************************************************************************/
  608. /* performs the correct attribute modifications for the Ctrl-A code            */
  609. /****************************************************************************/
  610. void ctrl_a(char x)
  611. {
  612.     int i,j;
  613.     char tmp1[128],atr=curatr;
  614.  
  615. if(x && (uchar)x<ESC) {    /* Ctrl-A through Ctrl-Z for users with MF only */
  616.     if(!(useron.flags1&FLAG(x+64)))
  617.         console^=(CON_ECHO_OFF);
  618.     return; }
  619. if((uchar)x>=0x7f) {
  620.     if(useron.misc&ANSI)
  621.         bprintf("\x1b[%uC",(uchar)x-0x7f);
  622.     else
  623.         for(i=0;i<(uchar)x-0x7f;i++)
  624.             outchar(SP);
  625.     return; }
  626. switch(toupper(x)) {
  627.     case '!':   /* level 10 or higher */
  628.         if(useron.level<10)
  629.             console^=CON_ECHO_OFF;
  630.         break;
  631.     case '@':   /* level 20 or higher */
  632.         if(useron.level<20)
  633.             console^=CON_ECHO_OFF;
  634.         break;
  635.     case '#':   /* level 30 or higher */
  636.         if(useron.level<30)
  637.             console^=CON_ECHO_OFF;
  638.         break;
  639.     case '$':   /* level 40 or higher */
  640.         if(useron.level<40)
  641.             console^=CON_ECHO_OFF;
  642.         break;
  643.     case '%':   /* level 50 or higher */
  644.         if(useron.level<50)
  645.             console^=CON_ECHO_OFF;
  646.         break;
  647.     case '^':   /* level 60 or higher */
  648.         if(useron.level<60)
  649.             console^=CON_ECHO_OFF;
  650.         break;
  651.     case '&':   /* level 70 or higher */
  652.         if(useron.level<70)
  653.             console^=CON_ECHO_OFF;
  654.         break;
  655.     case '*':   /* level 80 or higher */
  656.         if(useron.level<80)
  657.             console^=CON_ECHO_OFF;
  658.         break;
  659.     case '(':   /* level 90 or higher */
  660.         if(useron.level<90)
  661.             console^=CON_ECHO_OFF;
  662.         break;
  663.     case ')':   /* turn echo back on */
  664.         console&=~CON_ECHO_OFF;
  665.         break;
  666.     case '-':                                /* turn off all attributes if */
  667.         if(atr&(HIGH|BLINK|(LIGHTGRAY<<4)))    /* high intensity, blink or */
  668.             attr(LIGHTGRAY);                /* background bits are set */
  669.         break;
  670.     case '_':                                /* turn off all attributes if */
  671.         if(atr&(BLINK|(LIGHTGRAY<<4)))        /* blink or background is set */
  672.             attr(LIGHTGRAY);
  673.         break;
  674.     case 'P':    /* Pause */
  675.         pause();
  676.         break;
  677.     case 'Q':   /* Pause reset */
  678.         lncntr=0;
  679.         break;
  680.     case 'T':   /* Time */
  681.         now=time(NULL);
  682.         unixtodos(now,&date,&curtime);
  683.         bprintf("%02d:%02d %s"
  684.             ,curtime.ti_hour==0 ? 12
  685.             : curtime.ti_hour>12 ? curtime.ti_hour-12
  686.             : curtime.ti_hour, curtime.ti_min, curtime.ti_hour>11 ? "pm":"am");
  687.         break;
  688.     case 'D':   /* Date */
  689.         now=time(NULL);
  690.         bputs(unixtodstr(now,tmp1));
  691.         break;
  692.     case ',':   /* Delay 1/10 sec */
  693.         mswait(100);
  694.         break;
  695.     case ';':   /* Delay 1/2 sec */
  696.         mswait(500);
  697.         break;
  698.     case '.':   /* Delay 2 secs */
  699.         mswait(2000);
  700.         break;
  701.     case 'S':   /* Synchronize */
  702.         ASYNC;
  703.         break;
  704.     case 'L':    /* CLS (form feed) */
  705.         CLS;
  706.         break;
  707.     case '>':   /* CLREOL */
  708.         if(useron.misc&ANSI)
  709.             bputs("\x1b[K");
  710.         else {
  711.             i=j=lclwx();
  712.             while(i++<79)
  713.                 outchar(SP);
  714.             while(j++<79)
  715.                 outchar(BS); }
  716.         break;
  717.     case '<':   /* Non-destructive backspace */
  718.         outchar(BS);
  719.         break;
  720.     case '[':   /* Carriage return */
  721.         outchar(CR);
  722.         break;
  723.     case ']':   /* Line feed */
  724.         outchar(LF);
  725.         break;
  726.     case 'A':   /* Ctrl-A */
  727.         outchar(1);
  728.         break;
  729.     case 'H':     /* High intensity */
  730.         atr|=HIGH;
  731.         attr(atr);
  732.         break;
  733.     case 'I':    /* Blink */
  734.         atr|=BLINK;
  735.         attr(atr);
  736.         break;
  737.     case 'N':     /* Normal */
  738.         attr(LIGHTGRAY);
  739.         break;
  740.     case 'R':
  741.         atr=(atr&0xf8)|RED;
  742.         attr(atr);
  743.         break;
  744.     case 'G':
  745.         atr=(atr&0xf8)|GREEN;
  746.         attr(atr);
  747.         break;
  748.     case 'B':
  749.         atr=(atr&0xf8)|BLUE;
  750.         attr(atr);
  751.         break;
  752.     case 'W':    /* White */
  753.         atr=(atr&0xf8)|LIGHTGRAY;
  754.         attr(atr);
  755.         break;
  756.     case 'C':
  757.         atr=(atr&0xf8)|CYAN;
  758.         attr(atr);
  759.         break;
  760.     case 'M':
  761.         atr=(atr&0xf8)|MAGENTA;
  762.         attr(atr);
  763.         break;
  764.     case 'Y':   /* Yellow */
  765.         atr=(atr&0xf8)|BROWN;
  766.         attr(atr);
  767.         break;
  768.     case 'K':    /* Black */
  769.         atr=(atr&0xf8)|BLACK;
  770.         attr(atr);
  771.         break;
  772.     case '0':    /* Black Background */
  773.         atr=(atr&0x8f)|(BLACK<<4);
  774.         attr(atr);
  775.         break;
  776.     case '1':    /* Red Background */
  777.         atr=(atr&0x8f)|(RED<<4);
  778.         attr(atr);
  779.         break;
  780.     case '2':    /* Green Background */
  781.         atr=(atr&0x8f)|(GREEN<<4);
  782.         attr(atr);
  783.         break;
  784.     case '3':    /* Yellow Background */
  785.         atr=(atr&0x8f)|(BROWN<<4);
  786.         attr(atr);
  787.         break;
  788.     case '4':    /* Blue Background */
  789.         atr=(atr&0x8f)|(BLUE<<4);
  790.         attr(atr);
  791.         break;
  792.     case '5':    /* Magenta Background */
  793.         atr=(atr&0x8f)|(MAGENTA<<4);
  794.         attr(atr);
  795.         break;
  796.     case '6':    /* Cyan Background */
  797.         atr=(atr&0x8f)|(CYAN<<4);
  798.         attr(atr);
  799.         break;
  800.     case '7':    /* White Background */
  801.         atr=(atr&0x8f)|(LIGHTGRAY<<4);
  802.         attr(atr);
  803.         break; }
  804. }
  805.  
  806. /***************************************************************************/
  807. /* Changes local and remote text attributes accounting for monochrome      */
  808. /***************************************************************************/
  809. /****************************************************************************/
  810. /* Sends ansi codes to change remote ansi terminal's colors                 */
  811. /* Only sends necessary codes - tracks remote terminal's current attributes */
  812. /* through the 'curatr' variable                                            */
  813. /****************************************************************************/
  814. void attr(int atr)
  815. {
  816.  
  817. if(!(useron.misc&ANSI))
  818.     return;
  819. if(!(useron.misc&COLOR)) {  /* eliminate colors if user doesn't have them */
  820.     if(atr&LIGHTGRAY)       /* if any foreground bits set, set all */
  821.         atr|=LIGHTGRAY;
  822.     if(atr&(LIGHTGRAY<<4))  /* if any background bits set, set all */
  823.         atr|=(LIGHTGRAY<<4);
  824.     if(atr&LIGHTGRAY && atr&(LIGHTGRAY<<4))
  825.         atr&=~LIGHTGRAY;    /* if background is solid, foreground is black */
  826.     if(!atr)
  827.         atr|=LIGHTGRAY; }   /* don't allow black on black */
  828. if(curatr==atr) /* text hasn't changed. don't send codes */
  829.     return;
  830.  
  831. if((!(atr&HIGH) && curatr&HIGH) || (!(atr&BLINK) && curatr&BLINK)
  832.     || atr==LIGHTGRAY) {
  833.     bputs("\x1b[0m");
  834.     curatr=LIGHTGRAY; }
  835.  
  836. if(atr==LIGHTGRAY)                  /* no attributes */
  837.     return;
  838.  
  839. if(atr&BLINK) {                     /* special attributes */
  840.     if(!(curatr&BLINK))
  841.         bputs(ansi(BLINK)); }
  842. if(atr&HIGH) {
  843.     if(!(curatr&HIGH))
  844.         bputs(ansi(HIGH)); }
  845.  
  846. if((atr&0x7)==BLACK) {              /* foreground colors */
  847.     if((curatr&0x7)!=BLACK)
  848.         bputs(ansi(BLACK)); }
  849. else if((atr&0x7)==RED) {
  850.     if((curatr&0x7)!=RED)
  851.         bputs(ansi(RED)); }
  852. else if((atr&0x7)==GREEN) {
  853.     if((curatr&0x7)!=GREEN)
  854.         bputs(ansi(GREEN)); }
  855. else if((atr&0x7)==BROWN) {
  856.     if((curatr&0x7)!=BROWN)
  857.         bputs(ansi(BROWN)); }
  858. else if((atr&0x7)==BLUE) {
  859.     if((curatr&0x7)!=BLUE)
  860.         bputs(ansi(BLUE)); }
  861. else if((atr&0x7)==MAGENTA) {
  862.     if((curatr&0x7)!=MAGENTA)
  863.         bputs(ansi(MAGENTA)); }
  864. else if((atr&0x7)==CYAN) {
  865.     if((curatr&0x7)!=CYAN)
  866.         bputs(ansi(CYAN)); }
  867. else if((atr&0x7)==LIGHTGRAY) {
  868.     if((curatr&0x7)!=LIGHTGRAY)
  869.         bputs(ansi(LIGHTGRAY)); }
  870.  
  871. if((atr&0x70)==(BLACK<<4)) {        /* background colors */
  872.     if((curatr&0x70)!=(BLACK<<4))
  873.         bputs("\x1b[40m"); }
  874. else if((atr&0x70)==(RED<<4)) {
  875.     if((curatr&0x70)!=(RED<<4))
  876.         bputs(ansi(RED<<4)); }
  877. else if((atr&0x70)==(GREEN<<4)) {
  878.     if((curatr&0x70)!=(GREEN<<4))
  879.         bputs(ansi(GREEN<<4)); }
  880. else if((atr&0x70)==(BROWN<<4)) {
  881.     if((curatr&0x70)!=(BROWN<<4))
  882.         bputs(ansi(BROWN<<4)); }
  883. else if((atr&0x70)==(BLUE<<4)) {
  884.     if((curatr&0x70)!=(BLUE<<4))
  885.         bputs(ansi(BLUE<<4)); }
  886. else if((atr&0x70)==(MAGENTA<<4)) {
  887.     if((curatr&0x70)!=(MAGENTA<<4))
  888.         bputs(ansi(MAGENTA<<4)); }
  889. else if((atr&0x70)==(CYAN<<4)) {
  890.     if((curatr&0x70)!=(CYAN<<4))
  891.         bputs(ansi(CYAN<<4)); }
  892. else if((atr&0x70)==(LIGHTGRAY<<4)) {
  893.     if((curatr&0x70)!=(LIGHTGRAY<<4))
  894.         bputs(ansi(LIGHTGRAY<<4)); }
  895.  
  896. curatr=atr;
  897. }
  898.  
  899. /****************************************************************************/
  900. /* Returns the ANSI code to obtain the value of atr. Mixed attributes        */
  901. /* high intensity colors, or background/forground cobinations don't work.   */
  902. /* A call to attr is more appropriate, being it is intelligent                */
  903. /****************************************************************************/
  904. char *ansi(char atr)
  905. {
  906.  
  907. switch(atr) {
  908.     case (char)BLINK:
  909.         return("\x1b[5m");
  910.     case HIGH:
  911.         return("\x1b[1m");
  912.     case BLACK:
  913.         return("\x1b[30m");
  914.     case RED:
  915.         return("\x1b[31m");
  916.     case GREEN:
  917.         return("\x1b[32m");
  918.     case BROWN:
  919.         return("\x1b[33m");
  920.     case BLUE:
  921.         return("\x1b[34m");
  922.     case MAGENTA:
  923.         return("\x1b[35m");
  924.     case CYAN:
  925.         return("\x1b[36m");
  926.     case LIGHTGRAY:
  927.         return("\x1b[37m");
  928.     case (RED<<4):
  929.         return("\x1b[41m");
  930.     case (GREEN<<4):
  931.         return("\x1b[42m");
  932.     case (BROWN<<4):
  933.         return("\x1b[43m");
  934.     case (BLUE<<4):
  935.         return("\x1b[44m");
  936.     case (MAGENTA<<4):
  937.         return("\x1b[45m");
  938.     case (CYAN<<4):
  939.         return("\x1b[46m");
  940.     case (LIGHTGRAY<<4):
  941.         return("\x1b[47m"); }
  942.  
  943. return("-Invalid use of ansi()-");
  944. }
  945.  
  946.  
  947. /****************************************************************************/
  948. /* Checks to see if user has hit Pause or Abort. Returns 1 if user aborted. */
  949. /* If the user hit Pause, waits for a key to be hit.                        */
  950. /* Emulates remote XON/XOFF flow control on local console                   */
  951. /* Preserves SS_ABORT flag state, if already set.                           */
  952. /* Called from various listing procedures that wish to check for abort      */
  953. /****************************************************************************/
  954. char msgabort()
  955. {
  956.     char ch;
  957.  
  958. if(sys_status&SS_SYSPAGE)
  959.     beep(random(800),1);
  960. if(lkbrd(1)) {
  961.     ch=inkey(0);
  962.     if(sys_status&SS_ABORT) {                   /* ^c */
  963.         keybufbot=keybuftop=0;
  964.         return(1); }
  965.     else if(ch==17 && online==ON_REMOTE)    /* ^q */
  966.         rioctl(IOCS|PAUSE);
  967.     else if(ch==19)                         /* ^s */
  968.         while(online) {
  969.             if((ch=inkey(0))!=0) {
  970.                 if(ch==17)  /* ^q */
  971.                     return(0);
  972.                 ungetkey(ch); }
  973.              if(sys_status&SS_ABORT) { /* ^c */
  974.                 keybufbot=keybuftop=0;
  975.                 return(1); }
  976.              checkline(); }
  977.     else if(ch)
  978.         ungetkey(ch); }
  979. checkline();
  980. if(sys_status&SS_ABORT)
  981.     return(1);
  982. if(online==ON_REMOTE && rioctl(IOSTATE)&ABORT) {
  983.     rioctl(IOCS|ABORT);
  984.     sys_status|=SS_ABORT;
  985.     return(1); }
  986. if(!online)
  987.     return(1);
  988. return(0);
  989. }
  990.  
  991.  
  992. /****************************************************************************/
  993. /* Takes the value 'sec' and makes a string the format HH:MM:SS             */
  994. /****************************************************************************/
  995. char *sectostr(uint sec,char *str)
  996. {
  997.     uchar hour,min,sec2;
  998.  
  999. hour=(sec/60)/60;
  1000. min=(sec/60)-(hour*60);
  1001. sec2=sec-((min+(hour*60))*60);
  1002. sprintf(str,"%2.2d:%2.2d:%2.2d",hour,min,sec2);
  1003. return(str);
  1004. }
  1005.  
  1006.  
  1007. /****************************************************************************/
  1008. /* Generates a 24 character ASCII string that represents the time_t pointer */
  1009. /* Used as a replacement for ctime()                                        */
  1010. /****************************************************************************/
  1011. char *timestr(time_t *intime)
  1012. {
  1013.     static char str[256];
  1014.     char mer[3],hour;
  1015.     struct tm *gm;
  1016.  
  1017. gm=localtime(intime);
  1018. if(gm==NULL) {
  1019.     strcpy(str,"Invalid Time");
  1020.     return(str); }
  1021. if(sys_misc&SM_MILITARY) {
  1022.     sprintf(str,"%s %s %02d %4d %02d:%02d:%02d"
  1023.         ,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
  1024.         ,gm->tm_hour,gm->tm_min,gm->tm_sec);
  1025.     return(str); }
  1026. if(gm->tm_hour>=12) {
  1027.     if(gm->tm_hour==12)
  1028.         hour=12;
  1029.     else
  1030.         hour=gm->tm_hour-12;
  1031.     strcpy(mer,"pm"); }
  1032. else {
  1033.     if(gm->tm_hour==0)
  1034.         hour=12;
  1035.     else
  1036.         hour=gm->tm_hour;
  1037.     strcpy(mer,"am"); }
  1038. sprintf(str,"%s %s %02d %4d %02d:%02d %s"
  1039.     ,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
  1040.     ,hour,gm->tm_min,mer);
  1041. return(str);
  1042. }
  1043.  
  1044.