home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / utils.zip / rmescseq.c < prev    next >
C/C++ Source or Header  |  2001-08-31  |  8KB  |  240 lines

  1. /*
  2.   rmescseq.c  --  Removes ANSI X3.64 escape sequences from input stream.
  3.  
  4.   To build: [g]cc -o rmescseq rmescseq.c
  5.   To use:   rmescseq < infile > outfile
  6.  
  7.   Authors: F. da Cruz, J. Altman, Columbia University.
  8.   (Adapted by J. Altman from C-Kermit ckucns.c.)
  9.  
  10.   Copyright (C) 2001,
  11.   Trustees of Columbia University in the City of New York,
  12.   All rights reserved.  Terms of use and redistribution as for C-Kermit 7.0:
  13.   ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
  14. */
  15.  
  16. /* Escape-sequence parser state definitions. */
  17.  
  18. #define ES_NORMAL 0                     /* Normal, not in escape sequence */
  19. #define ES_GOTESC 1                     /* Current character is ESC */
  20. #define ES_ESCSEQ 2                     /* Inside an escape sequence */
  21. #define ES_GOTCSI 3                     /* Inside a control sequence */
  22. #define ES_STRING 4                     /* Inside DCS,OSC,PM, or APC string */
  23. #define ES_TERMIN 5                     /* 1st char of string terminator */
  24.  
  25. /* Important buffer lengths */
  26.  
  27. #define ESCBUFLEN 128
  28. #define STRBUFLEN 256
  29.  
  30. /* Important Control Characters */
  31.  
  32. #define NUL 0
  33. #define BS  8
  34. #define CAN 24
  35. #define SUB 26
  36. #define ESC 27
  37. #define SP  32
  38. #define CSI 155
  39. #define ST  156
  40.  
  41. /* The usual boolean values */
  42.  
  43. #define FALSE 0
  44. #define TRUE  1
  45.  
  46. /* Some state */
  47.  
  48. static int escstate = ES_NORMAL;
  49. static int escnext = 1;
  50. static int esclast = 0;
  51. static int strrecv = 0;
  52. static unsigned char escbuffer[ESCBUFLEN];
  53. static unsigned char strbuf[STRBUFLEN];
  54. static int strlength = 0;
  55.  
  56. /* This function parses an incoming data stream and extracts the ANSI x3.64 */
  57. /* commands and places them into escbuffer[].  Characters which are part of */
  58. /* the data stream but not part of a x3.64 command sequence are returned.   */
  59. /* When a character is not returned the function returns either -1 to       */
  60. /* indicate that a complete sequence has yet to be received or -2 to signal */
  61. /* that a complete sequence is in the escbuffer[].                          */
  62.  
  63. int
  64. ansi_x3_64(ch) unsigned char ch; {
  65.  
  66.     if (escstate == ES_NORMAL) {    /* Not in an escape sequence */
  67.     if (ch == ESC) {        /* This character is an Escape */
  68.         escstate = ES_GOTESC;    /* Change state to GOTESC */
  69.         esclast = 0;        /* Reset buffer pointer */
  70.             escbuffer[0] = ESC;
  71.         }
  72.         else if ( ch == CSI) {
  73.             escstate = ES_GOTCSI;    /* Escape sequence was restarted */
  74.             escbuffer[0] = CSI;         /* Save in case we have to replay it */
  75.             esclast = 1;        /* Reset buffer pointer, but */
  76.             escbuffer[1] = '[';         /* But translate to 7-bit */
  77.     } else {            /* Not an ESC, stay in NORMAL state */
  78.             return(ch);
  79.     }
  80.     return(-1);                    /* Return in either case. */
  81.     }
  82.  
  83. /* We are in an escape sequence... */
  84.  
  85.     if (ch < SP || (ch == CSI)) {    /* Control character? */
  86.         if (ch == CAN || ch == SUB) {   /* These cancel an escape sequence  */
  87.         escstate = ES_NORMAL;       /* Go back to normal. */
  88.         strlength = 0;
  89.         strbuf[0] = 0 ;
  90.         strrecv = FALSE ;
  91.     } else if (ch == BS) {     /* Erases previous */
  92.         if ( escstate == ES_GOTCSI && esclast == 1 ) {
  93.         escstate = ES_GOTESC ;
  94.         esclast = 0 ;
  95.         }
  96.         else if ( escstate == ES_ESCSEQ && esclast == 1 ) {
  97.         escstate = ES_GOTESC ;
  98.         esclast = 0 ;
  99.         }
  100.         else if ( escstate == ES_GOTESC && esclast == 0 ) {
  101.         escstate = ES_NORMAL ;
  102.         }
  103.         else if ( escstate == ES_TERMIN ) {
  104.         escstate = ES_STRING ;
  105.         }
  106.         else if ( escstate == ES_STRING ) {
  107.         if ( strlength > 0 )
  108.             strlength-- ;
  109.         else {
  110.             escstate = ES_GOTESC ;
  111.         }
  112.         }
  113.         else if ( esclast > 0 ) {
  114.         esclast--;        /* Escape sequence char (really?) */
  115.         }
  116.     } else if (ch == ESC) {
  117.         if ( escstate == ES_STRING )
  118.         escstate = ES_TERMIN ;
  119.         else {
  120.         escstate = ES_GOTESC;    /* Escape sequence was restarted */
  121.         esclast = 0;        /* Reset buffer pointer */
  122.                 escbuffer[0] = ESC;     /* Save in case we have to replay it */
  123.         }
  124.         } else if (ch == CSI) {
  125.             escstate = ES_GOTCSI;    /* Escape sequence was restarted */
  126.             escbuffer[0] = CSI;         /* Save in case we have to replay it */
  127.             esclast = 1;        /* Reset buffer pointer, but */
  128.             escbuffer[1] = '[';         /* But translate for vtescape() */
  129.     } else if (ch != NUL) {
  130.         return(ch);
  131.     }
  132.     return(-1);
  133.     }
  134. /*
  135.   Put this character in the escape sequence buffer.
  136.   But we don't put "strings" in this buffer;
  137.   Note that indexing starts at 1, not 0.
  138. */
  139.     if (escstate != ES_STRING && escstate != ES_TERMIN)
  140.     if (esclast < ESCBUFLEN)
  141.         escbuffer[++esclast] = ch;
  142.  
  143.     switch (escstate) {            /* Enter esc sequence state switcher */
  144.       case ES_GOTESC:            /* GOTESC state, prev char was Esc */
  145.     switch ( ch ) {
  146.       case '[':            /* Left bracket after ESC is CSI */
  147.         escstate = ES_GOTCSI;    /* Change to GOTCSI state */
  148.         break;
  149.       case '_':            /* Application Program Command (APC) */
  150.       case 'P':            /* Device Control String (DCS) Intro */
  151.       case 'Q':            /* Private Use One (PU1) Introducer */
  152.       case 'R':            /* Private Use Two (PU2) Introducer */
  153.       case 'X':            /* Start of String (SOS) Introducer */
  154.       case '^':                /* Privacy Message (PM) */
  155.       case ']':                /* Operating System Command (OSC) */
  156.             escstate = ES_STRING;    /* Enter STRING-absorption state */
  157.             strrecv = TRUE;        /* We are receiving a string */
  158.             strlength = 0;        /* and reset string buffer index */
  159.             break;
  160.       default:
  161.         if ((ch > 057) && (ch < 0177)){/* Or final char, '0' thru '~' */
  162.                 escstate = ES_NORMAL;      /* Go back to normal. */
  163.                 return(-2);           /* Go act on it. */
  164.             } else
  165.           escstate = ES_ESCSEQ;
  166.     }
  167.     break;
  168.  
  169.       case ES_ESCSEQ:            /* ESCSEQ -- in an escape sequence */
  170.     if (ch > 057 && ch < 0177) {    /* Final character is '0' thru '~' */
  171.         escstate = ES_NORMAL;       /* Go back to normal. */
  172.             return(-2);            /* Go handle it */
  173.         }
  174.       case ES_GOTCSI:            /* GOTCSI -- In a control sequence */
  175.     if (ch > 077 && ch < 0177) {    /* Final character is '@' thru '~' */
  176.         escstate = ES_NORMAL;       /* Go back to normal. */
  177.             return(-2);            /* Go act on it. */
  178.         }
  179.       case ES_STRING:            /* Inside a string */
  180.     if (ch == ESC) {        /* ESC may be 1st char of terminator */
  181.         escstate = ES_TERMIN;    /* Change state to find out. */
  182.         } else if (ch == ST) {        /* C1 String Terminator */
  183.         escstate = ES_NORMAL;    /* If so, back to NORMAL */
  184.         strrecv = FALSE ;
  185.         } else if (strrecv) {
  186.             if (strlength < STRBUFLEN) { /* If in string, */
  187.         strbuf[strlength++] = ch; /* deposit this character */
  188.             } else {            /* Buffer overrun */
  189.         strrecv = FALSE ;       /* Discard what we got */
  190.         strlength = 0;            /* and go back to normal */
  191.         escstate = ES_NORMAL ;
  192.             }
  193.     }
  194.     break;                /* Absorb all other characters. */
  195.  
  196.     case ES_TERMIN:            /* May have a string terminator */
  197.     if (ch == '\\') {        /* which must be backslash */
  198.         escstate = ES_NORMAL;    /* If so, back to NORMAL */
  199.         strrecv = FALSE ;
  200.     } else {
  201.             if (ch >= SP)        /* Just a stray Esc character. */
  202.           escstate = ES_STRING;    /* Return to string absorption. */
  203.             if (strrecv) {
  204.                 if (strlength+1 < STRBUFLEN) {   /* In string, */
  205.                     strbuf[strlength++] = ESC;   /* deposit Esc character */
  206.                     strbuf[strlength++] = ch;    /* and this character too */
  207.                 }
  208.             }
  209.         }
  210.     }
  211.     return(-1);
  212. }
  213.  
  214. int
  215. main(argc, argv) int argc; char ** argv; {
  216.     unsigned char ch;
  217.     int n;
  218.  
  219.     while (1) {
  220.         n = read(0, &ch, 1);
  221.         if (n <= 0)
  222.       return;
  223.  
  224.         if ((ch > 127) && (ch < 160) &&    /* It's a C1 character */
  225.         ch != CSI) {        /* But not CSI         */
  226.             n = ansi_x3_64(ESC);    /* Convert to C0 form  */
  227.             if (n >= 0) {
  228.                 ch = (n & 0xFF);
  229.                 write(1, &ch, 1);
  230.             }
  231.             ch = (ch & 0x7F) | 0x40;
  232.         }
  233.         n = ansi_x3_64(ch);
  234.         if (n >= 0) {
  235.             ch = (n & 0xFF);
  236.             write(1, &ch, 1);
  237.         }
  238.     }
  239. }
  240.