home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / TEXT / UTILITY / TDS_V10.ZIP / TDS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-26  |  15.0 KB  |  566 lines

  1. /* TDS v1.0 - Transliteration, Deletion, and Squeeze filter
  2.  * Copyright 1990 by Edward Lee 
  3.  * edlee@chinet.chi.il.us
  4.  *
  5.  * TDS is a fast superset of the UNIX Sys V(tm) TR program.
  6.  *
  7.  * Suggested compilation:
  8.  *     MSDOS Turbo C v2.0:  tcc -K -O -f- -mt -lt tds.c
  9.  *                  Sys V:  cc -O -s tds.c -o tds
  10.  * Sys V with shared libs:  cc -O -s tds.c -o tds -lc_s
  11.  *
  12.  * This program uses a prefix string length indicator to allow ALL characters
  13.  * to be handled.  Examine the MYSTR type definition if you do not know what 
  14.  * is meant by a prefix string length indicator.  This idea is borrowed from
  15.  * Texas Instruments by the author of this program, and it is implemented
  16.  * here in a more general way.  As far as I know, the concept previously had
  17.  * no name.  The advantage of using a prefix string length indicator is that
  18.  * it requires no special character to terminate a string.
  19.  */
  20.  
  21. /*
  22. * PROGRAM HISTORY
  23. *~01:00-04:20 08Jun1990, Program performs multiple char translation
  24. * 16:15-18:33 ", Added option switch processing
  25. * 10:00-11:11 09Jun, Added -c)omplement operation in setup_t()
  26. * 12:20-12:33 ", Added -s)queeze operation in main()
  27. * 12:33-13:33 ", Moved -c)omplement operation to its own routine
  28. * 23:00-23:30 ", Added -d)elete operation in main()
  29. * 23:30-23:52 ", Tied the various options together
  30. * 21:31-22:46 10Jun, Changed prefixed string type into a structure
  31. * 16:50-17:19 11Jun, Parenthesized conditional, corrected off-by-one error
  32. * 17:19-18:56 ", Induced and incorporated undocumented length rules
  33. * 18:56-17:42 ", Cleaned up unneeded variables, tested program
  34. * 01:05-01:20 14Jun, Added code for -ds option combination
  35. * 02:30-02:42 Optimized -ds code
  36. *       01:55 17Jun, Added #ifndef ushort, compiled under Turbo C v2.0
  37. * 15:30-16:56 23Aug, Began to incorporate esch() and range() routines which
  38. *                    were developed and tested separately over four days 
  39. * 01:15-01:39 24Aug, Modified range() for variable parameters
  40. * 01:00-03:06 27Aug, Revised comments, checked code consistency & compromised
  41. * 15:34-18:32 29Aug, Modifed range() and range2() for MYSTR, added error msgs,
  42. *                    compiled, tested, corrected off-by-one error in range2(),
  43. * 03:17-03:25 01Sep, Corrected a change in getopts() which introduced an
  44. *                    indefinite pointer condition.
  45. *       02:40 25Nov, Corrected the update of s2->i[] in setup_t()
  46. *       20:34 25Nov, Cleaned up unused variables, unneeded brackets
  47. *       11:25 21Dec, Test
  48. *~23:30-23:47 21Dec, Deleted unused function, minor loop optimization, test
  49. *~12:00-12:45 22Dec, Deleted unnecessary complications in setup_t, test,
  50. *                    optimized (delete && squeeze) section, test
  51. *~21:45-22:07 22Dec, Optimized setup_t(), test
  52. *~      11:20 23Dec, Cleanup, test
  53. *       11:20 26Dec, Replaced char with unchar to prevent crashes on *nix
  54. *                    systems; spent two days tracking this down
  55. *                    Deleted range() and replaced function with range2()
  56. *       14:15 26Dec, Final test before release
  57.  */
  58.  
  59. #include <stdio.h>
  60.  
  61. #ifndef __TURBOC__
  62. #include <sys/types.h>
  63. #endif
  64.  
  65. #ifndef unchar
  66. #define unchar unsigned char
  67. #endif
  68.  
  69. #ifndef ushort
  70. #define ushort short unsigned int
  71. #endif
  72.  
  73. #define SIZE (32768)
  74. #define TRUE (1)
  75. #define FALSE (0)
  76.  
  77. #define MAXMYSLEN (256)
  78. typedef struct {
  79.           int    len;
  80.           unchar s [MAXMYSLEN];
  81.           ushort i [256];         /* Map of unique characters in {string}, */
  82.                                   /* a.k.a the i)ntersection of {string}   */
  83.                                   /* with the character set {0...255} */
  84.         } MYSTR;
  85.  
  86. unchar a[SIZE];                   /* Input/Output character buffer */
  87.  
  88. unchar t[] = {   /* Translation table for character codes 0-255 */
  89.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
  90.  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
  91.  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
  92.  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,
  93.  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,
  94.  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
  95.  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
  96.  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  97.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
  98.  90,  91,  92,  93,  94,  95,  96,  97,  98,  99,
  99. 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
  100. 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  101. 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
  102. 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
  103. 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
  104. 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  105. 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
  106. 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
  107. 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
  108. 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
  109. 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
  110. 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
  111. 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
  112. 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  113. 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
  114. 250, 251, 252, 253, 254, 255
  115. };  /* Translation table for character codes 0-255 */
  116.  
  117. int delete, invert, squeeze=FALSE;      /* Boolean variables */
  118.  
  119.  
  120. void error(s)
  121.  unchar *s;
  122. {
  123.   (void)fputs(s, stderr);
  124.   (void)fputs("\n", stderr);
  125.   exit(1);
  126. } /* error */
  127.  
  128.  
  129. /* Routine to decode backslash escape codes at run-time */
  130. int esch(p)
  131.  unchar **p;
  132. {
  133. int n;
  134.  
  135.   if (**p != '\\') {              /* Backslash escape code? */
  136.      n=(int)**p;                  /* No */
  137.  
  138.      if (**p=='\000')             /* Real end-of-string? */
  139.         return(-1);               /* Yes */
  140.  
  141.      ++(*p);                      /* Some other character */
  142.      return(n);
  143.   }
  144.  
  145.   ++(*p);                         /* Skip over '\'      */
  146.  
  147.   /* Octal escape character */
  148.   if (**p >= '0' && **p <= '7') {
  149.      n = (**p-48);
  150.  
  151.      ++(*p);
  152.  
  153.      if (**p >= '0' && **p <= '7') {
  154.         n = (n<<3) + (**p-48);       /* (n<<3) = (n*8) */
  155.  
  156.         ++(*p);
  157.  
  158.         if (**p >= '0' && **p <= '7') {
  159.            n = (n<<3) + (**p-48);
  160.            ++(*p);
  161.         }
  162.      }
  163.  
  164.      if (n>255)
  165.         error ("tds: the maximum octal escape code is \\377");
  166.  
  167.      return(n);
  168.   }  /* Octal */
  169.  
  170.   /* Decimal escape character */
  171.   if (**p == 'd' || **p == 'D') {
  172.      ++(*p);
  173.  
  174.      if (**p >= '0' && **p <= '9') {
  175.         n = (**p-48);
  176.  
  177.         ++(*p);
  178.  
  179.         if (**p >= '0' && **p <= '9') {
  180.            n = n*10 + (**p-48);
  181.  
  182.            ++(*p);
  183.  
  184.            if (**p >= '0' && **p <= '9') {
  185.               n = n*10 + (**p-48);
  186.               ++(*p);
  187.            }
  188.         }
  189.  
  190.         if (n>255)
  191.            error ("tds: the maximum decimal escape code is \\d255");
  192.  
  193.         return(n);
  194.      }
  195.   }  /* Decimal */
  196.  
  197.   /* Hexadecimal escape character */
  198.   if (**p=='h' || **p=='H' || **p=='x' || **p=='X') {
  199.      ++(*p);
  200.  
  201.      if((**p >= '0' && **p <= '9') ||
  202.         (**p >= 'A' && **p <= 'F') || (**p >= 'a' && **p <= 'f')) {
  203.  
  204.         if (**p <= '9')              /* Make ASCII hex digit into an integer */
  205.            n = (**p-48);             /* 48 = ((int)'0') */
  206.         else
  207.         if (**p <= 'F')
  208.            n = (**p-55);             /* 55 = ((int)'A' - 10) */
  209.         else
  210.            n = (**p-87);             /* 87 = ((int)'a' - 10) */
  211.  
  212.         ++(*p);
  213.  
  214.         if((**p >= '0' && **p <= '9') ||
  215.            (**p >= 'A' && **p <= 'F') || (**p >= 'a' && **p <= 'f')) {
  216.  
  217.            if (**p <= '9')
  218.               n = (n<<4) + (**p-48);   /* (n<<4) = (n*16) */
  219.            else
  220.            if (**p <= 'F')
  221.               n = (n<<4) + (**p-55);
  222.            else
  223.               n = (n<<4) + (**p-87);
  224.  
  225.            ++(*p);
  226.         }
  227.  
  228.         return(n);
  229.      }
  230.   }  /* Hexadecimal */
  231.  
  232.   /* Miscellaneous escape codes */
  233.   if (**p=='a' || **p=='A') {    /* A)udible bell      */
  234.      ++(*p);
  235.      return(7);
  236.   }
  237.  
  238.   if (**p=='b' || **p=='B') {    /* B)ackspace         */
  239.      ++(*p);
  240.      return(8);
  241.   }
  242.  
  243.   if (**p=='t' || **p=='T') {    /* T)ab               */
  244.      ++(*p);
  245.      return(9);
  246.   }
  247.  
  248.   if (**p=='n' || **p=='N') {   /* N)ewline, linefeed */
  249.      ++(*p);
  250.      return(10);
  251.   }
  252.  
  253.   if (**p=='v' || **p=='V') {   /* V)ertical tab      */
  254.      ++(*p);
  255.      return(11);
  256.   }
  257.  
  258.   if (**p=='f' || **p=='F') {   /* F)ormfeed          */
  259.      ++(*p);
  260.      return(12);
  261.   }
  262.  
  263.   if (**p=='r' || **p=='R') {   /* carriage R)eturn   */
  264.      ++(*p);
  265.      return(13);
  266.   }
  267.  
  268.   if (**p=='s' || **p=='S') {  /* S)pace             */
  269.      ++(*p);
  270.      return(32);
  271.   }
  272.  
  273.   if (**p=='\\') {             /* backslash          */
  274.      ++(*p);
  275.      return(92);
  276.   }
  277.  
  278.   if (**p=='\000')             /* real end-of-string */
  279.      return(-1);
  280.  
  281.   n=(int)**p;                  /* non-escape code    */
  282.   ++(*p);
  283.   return(n);
  284. }  /* esch */
  285.  
  286.  
  287. /* Append a character to a prefix string */
  288. void pcappend(c, s)
  289.  unchar c;
  290.  MYSTR *s;
  291. {
  292.   if (s->len >= MAXMYSLEN)
  293.      error ("tds: maximum string length exceeded");
  294.  
  295.   s -> s[s->len] = c;
  296.   s -> len += 1;               /* Update length indicator */
  297.   s -> i[(int)c] = TRUE;       /* Update intersection map */
  298. }  /* pcappend */
  299.  
  300.  
  301. void range2(s, d)
  302.  unchar **s;
  303.  MYSTR *d;
  304. {
  305. int c1, c2, n;
  306.  
  307.   if (**s=='[')
  308.      ++(*s);
  309.  
  310.   while (**s != ']') {
  311.         c1 = esch (s);                  /* Get the 1st character */
  312.  
  313.         if (c1 < 0)
  314.            error ("tds: was expecting a character map in string2, e.g. [a-zr*5]");
  315.  
  316.         if (**s=='-') {
  317.            ++(*s);
  318.  
  319.            c2 = esch (s);               /* Get the 2nd character */
  320.            if (c2 < 0)
  321.               error ("tds: was expecting end of character range after '-', e.g. [a-zZ-A], in string2");
  322.  
  323.            if (c1 < c2)                 /* Does the range ascend or descend? */
  324.               while (c1 <= c2)          /* It ascends */
  325.                     pcappend (c1++, d); /* Fill up the destination buffer */
  326.            else
  327.               while (c1 >= c2)          /* It descends */
  328.                     pcappend (c1--, d); /* Fill up the destination buffer */
  329.         } else
  330.         if (**s=='*') {
  331.            ++(*s);
  332.  
  333.            n=(-1);
  334.  
  335.            if (**s >= '0' && **s <= '9') {
  336.               n = (**s-48);
  337.  
  338.               ++(*s);
  339.  
  340.               if (**s >= '0' && **s <= '9') {
  341.                  n = n*10 + (**s-48);
  342.  
  343.                  ++(*s);
  344.  
  345.                  if (**s >= '0' && **s <= '9') {
  346.                     n = n*10 + (**s-48);
  347.  
  348.                     ++(*s);
  349.                  }
  350.               }
  351.            }
  352.  
  353.            if (n>256)
  354.               error ("tds: character multiplier may not exceed 256, e.g. [a*256], in string2");
  355.  
  356.            if (n<0)
  357.               n= 256 - (d -> len);
  358.  
  359.            while (n--)
  360.                  (void)pcappend(c1, d);
  361.  
  362.         } else
  363.         error ("tds: was expecting a '-' or '*' in character range, e.g. [a-zr*5], in string2");
  364.   }  /* while */
  365.  
  366.   ++(*s);  /* Skip over closing ']' */
  367. }  /* range2 */
  368.  
  369.  
  370. void clr_mystr(s)
  371.  MYSTR *s;
  372. {
  373. int i;
  374.  
  375.   s -> len = 0;
  376.  
  377.   i=256;
  378.   do {
  379.        --i;
  380.        s -> i[i] = FALSE;
  381.   } while (i);
  382.  
  383. }  /* clr_mystr */
  384.  
  385.  
  386. void getopts(argc, argv, as1, as2)
  387.  int argc;
  388.  unchar *argv[];
  389.  MYSTR *as1, *as2;
  390. {
  391. unchar *c;
  392. int flag, i;
  393.  
  394.   flag = 0;
  395.  
  396.   for (i=1; i<argc; i++) {
  397.       c=argv[i];
  398.  
  399.       if (*c == '-') 
  400.          while (*c++) {
  401.                if (*c == 'c')
  402.                   invert=TRUE;
  403.                else
  404.                if (*c == 'd')
  405.                   delete=TRUE;
  406.                else
  407.                if (*c == 's')
  408.                   squeeze=TRUE;
  409.           }  /* while */
  410.       else
  411.           if (flag==0) {
  412.              while (*c)
  413.                    if (*c == '[')
  414.                       (void)range2 (&c, as1);
  415.                    else
  416.                       (void)pcappend(esch (&c), as1);
  417.  
  418.              ++flag;
  419.           } else
  420.              while (*c)
  421.                    if (*c == '[')
  422.                       (void)range2 (&c, as2);
  423.                    else
  424.                       (void)pcappend(esch (&c), as2);
  425.  
  426.   }  /* for */
  427. }  /* getopts */
  428.  
  429.  
  430. /* Complement prefixed string:  s = {0...255 character set} - {s.i[]} */
  431. void complement(s)
  432.  MYSTR *s;
  433. {
  434. int i=256;
  435. int j=0;
  436.  
  437.   do {                            /* Invert the intersection map */
  438.       --i;
  439.       s -> i[i] = 1 - (s -> i[i]);
  440.   } while (i);
  441.  
  442.   s -> len = 256 - (s -> len);    /* Update the length */
  443.  
  444.   for (i=0; i<256; i++)
  445.       if (s -> i[i] == TRUE)
  446.          s -> s[j++] = (char)i;   /* Make string reflect new map and length */
  447. }  /* complement */
  448.  
  449.  
  450. /* Set up translation table */
  451. void setup_t(s1, s2)
  452.  MYSTR *s1, *s2;
  453. {
  454. int i;
  455. int len = s1->len;
  456.  
  457.    if (s2->len == 0)        /* Added for compatibility with tr */
  458.       *s2 = *s1;
  459.    else
  460.    if (s1->len > s2->len)   /* Length of s1 > length of s2 ?   */
  461.       len = s2->len;
  462.  
  463.    for (i=0; i<len; i++)    /* Make {t} = s/{s1}/{s2}/ */
  464.        t[ (int)(s1->s[i]) ] = s2->s[i];
  465. }  /* setup_t */
  466.  
  467.  
  468. int main (argc, argv)
  469.  int argc;
  470.  unchar *argv[];
  471. {
  472. int ch, i, j, n;
  473. int lastch=(-1);   /* Initialize to a number outside the 0-255 character set */
  474. unchar tch;
  475. MYSTR s1, s2;
  476.  
  477.   (void)clr_mystr(&s1);
  478.   (void)clr_mystr(&s2);
  479.  
  480.   (void)getopts(argc, argv, &s1, &s2);
  481.  
  482.  
  483.   if (invert)
  484.      (void)complement(&s1);
  485.  
  486.  
  487.   (void)setup_t(&s1, &s2);
  488.  
  489.  
  490.   if (delete && squeeze) {
  491.      do {
  492.           n=fread(a, 1, SIZE, stdin);
  493.  
  494.           j=0;
  495.           for (i=0; i<n; i++) {
  496.               if (s1.i[ (int)a[i] ] == FALSE) {
  497.                  ch=(int)a[i];    /* Present, untranslated input character */
  498.  
  499.                  if ( (ch != lastch) ||
  500.                       (s2.i[ch] == FALSE) ) {
  501.                     a[j++] = ch;
  502.                     lastch = ch;
  503.                  }  /* if */
  504.  
  505.              }  /* if */
  506.  
  507.           }
  508.  
  509.           (void)fwrite(a, 1, j, stdout);
  510.      } while (n!=0);
  511.  
  512.      return(0);
  513.   }  /* if (delete && squeeze) */
  514.  
  515.  
  516.   if (delete) {
  517.      do {
  518.           n=fread(a, 1, SIZE, stdin);
  519.  
  520.           j=0;
  521.           for (i=0; i<n; i++)
  522.               if (s1.i[ (int)a[i] ] == FALSE)
  523.                  a[j++] = a[i];
  524.  
  525.           (void)fwrite(a, 1, j, stdout);
  526.      } while (n!=0);
  527.  
  528.      return(0);
  529.   }  /* if (delete) */
  530.  
  531.  
  532.   if (squeeze) {
  533.      do {
  534.           n=fread(a, 1, SIZE, stdin);
  535.  
  536.           j=0;
  537.           for (i=0; i<n; i++) {
  538.               ch=(int)a[i];       /* Present, untranslated input character */
  539.               tch=t[ch];          /* Present, translated input character */
  540.  
  541.               if ( (tch != lastch) ||
  542.                  (s2.i[tch] == FALSE) ) {
  543.                  a[j++] = tch;
  544.                  lastch = tch;
  545.               }
  546.           }  /* for */
  547.  
  548.           (void)fwrite(a, 1, j, stdout);
  549.      } while (n!=0);
  550.  
  551.      return(0);
  552.   }  /* if (squeeze) */
  553.  
  554.  
  555. /* A straight-forward translation filter when there are no option flags: */
  556.   do {
  557.        n=fread(a, 1, SIZE, stdin);
  558.  
  559.        for (i=0; i<n; i++)
  560.            a[i] = t[ (int)a[i] ];
  561.  
  562.        (void)fwrite(a, 1, n, stdout);
  563.   } while (n!=0);
  564.   return(0);
  565. }  /* main */
  566.