home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 329_01 / tr.c < prev    next >
C/C++ Source or Header  |  1988-12-16  |  6KB  |  325 lines

  1. /*-
  2.  * tr - transliterate characters
  3.  *
  4.  * Usage: tr [-bcds] [inset [outset]]
  5.  *
  6.  * Use as a filter. Outset is padded to the length of
  7.  * inset by repeating its last character, if necessary.
  8.  * Inset and outset may contain ranges of the form a-b, where a and/or b
  9.  * may be omitted, and octal numbers of the form \ooo, where ooo is 1-3
  10.  * octal digits.  Combining the two (\1-\5) is allowed.
  11.  * Nulls are acceptable both in the input stream and in the arguments
  12.  * (in the form of an octal escape).
  13.  *
  14.  * Options:
  15.  * -b   operate in binary mode (default is text)
  16.  * -c   complement inset with respect to 1-0377 octal (in ASCII order)
  17.  * -d   delete inset
  18.  * -s   squeeze repeated characters in outset into one on output
  19.  *
  20.  * David MacKenzie
  21.  * Latest revision: 05/19/88
  22. **
  23. **    Roberto Artigas Jr
  24. **    P.O. Box 281415
  25. **    Memphis, TN 38168-1415
  26. **    home: 901-762-6092
  27. **    work: 901-373-4738
  28. **
  29. **    1988.12.09 - Get to run under OS/2.
  30. **        Used C/2 version 1.10 under OS/2 E 1.1
  31. **        cl -c -AL tr.c
  32. **        link tr,/noi,tr,llibce+os2, ;
  33. **+
  34. */
  35. #define AZTEC    0
  36.  
  37. #define    CMP    0
  38. #define    DOS    0
  39. #define    OS2    1
  40. #include    <stdio.h>
  41.  
  42. #if    DOS || OS2
  43. #include    <stdlib.h>
  44. #include    <string.h>
  45. #include    <io.h>
  46. #define    agetc    getc
  47. #define    aputc    putc
  48. #endif
  49.  
  50. /*
  51.  * Function prototypes 
  52.  */
  53. void parse();
  54. void simpoct();
  55. void simprange();
  56. int indexo();
  57. void complement();
  58. void pad();
  59. void tr();
  60. void outchar();
  61. void usage();
  62.  
  63.  
  64. #define NCHARS 256
  65.  
  66.  
  67. #define isoct(d) ((d) >= '0' && (d) <= '7')
  68.  
  69. /* Counted strings, to allow nulls in the arguments (via octal escapes). */
  70. typedef struct
  71. {
  72.     int len;
  73.     char buf[NCHARS];
  74. } SET;
  75. #if AZTEC
  76. #undef getchar
  77. #define getchar() (bflag ? getc(stdin) : agetc(stdin))
  78. int bflag = 0;
  79. #endif
  80.  
  81. int cflag = 0,
  82.  dflag = 0,
  83.  sflag = 0;
  84.  
  85. int 
  86. main(argc, argv)
  87. int argc;
  88. char **argv;
  89. {
  90.     int optind;
  91.     SET inset,
  92.      outset,
  93.      inset2,
  94.     *insetp;
  95.  
  96.     for (optind = 1; optind < argc && argv[optind][0] == '-'; ++optind)
  97.     {
  98.     while (*++argv[optind])
  99.         switch (*argv[optind])
  100.         {
  101. #if AZTEC
  102.         case 'b':
  103.         bflag = 1;
  104.         break;
  105. #endif
  106.         case 'c':
  107.         cflag = 1;
  108.         break;
  109.         case 'd':
  110.         dflag = 1;
  111.         break;
  112.         case 's':
  113.         sflag = 1;
  114.         break;
  115.         default:
  116.         usage();
  117.         break;
  118.         }
  119.     }
  120.     if (optind == argc - 2)
  121.     {
  122.     parse(argv[optind], &inset);
  123.     parse(argv[optind + 1], &outset);
  124.     } else
  125.     if (optind == argc - 1)
  126.     parse(argv[optind], &inset);
  127.     else
  128.     if (optind != argc)
  129.     usage();
  130.  
  131.     if (cflag)
  132.     {
  133.     complement(&inset, &inset2);
  134.     insetp = &inset2;
  135.     } else
  136.     insetp = &inset;
  137.  
  138.     pad(insetp, &outset);
  139.  
  140.     tr(insetp, &outset);
  141.  
  142.     return (0);
  143.     exit(0);
  144. }
  145.  
  146. void 
  147. parse(in, out)
  148. char *in;                   /* Null-terminated string. */
  149. SET *out;
  150. {
  151.     SET tempset;
  152.  
  153.     simpoct(in, &tempset);
  154.     simprange(&tempset, out);
  155. }
  156. /*
  157.  * Copy string in to string out, with octal escapes simplified to their
  158.  * actual value. 
  159.  */
  160.  
  161. void 
  162. simpoct(in, out)
  163. char *in;                   /* Null-terminated string. */
  164. SET *out;
  165. {
  166.     int i;                   /* Digit counter for octal escapes. */
  167.     char *outp;
  168.  
  169.     outp = out->buf;
  170.     while (*in)
  171.     if (*in == '\\')
  172.     {
  173.         *outp = 0;
  174.         for (i = 0, ++in; i < 3 && isoct(*in); ++i, ++in)
  175.         *outp = *outp * 8 + *in - '0';
  176.         if (i == 0)
  177.         *outp = *in++;           /* \d, where !isoct(d), = d */
  178.         ++outp;
  179.     } else
  180.         *outp++ = *in++;
  181.  
  182.     out->len = outp - out->buf;
  183. }
  184. /*
  185.  * Copy string in to string out, with character ranges simplified to the
  186.  * actual range of values. 
  187.  */
  188.  
  189. void 
  190. simprange(in, out)
  191. SET *in,
  192. *out;
  193. {
  194.     char first,
  195.      last;                   /* First, last chars in range. */
  196.     char *inp,
  197.     *outp;
  198.  
  199.     inp = in->buf;
  200.     outp = out->buf;
  201.     while (inp < in->buf + in->len)
  202.     if (*inp == '-')
  203.     {
  204.         if (outp == out->buf)
  205.         /* "-..." = "\1-..." */
  206.         *outp++ = 1;
  207.         first = outp[-1];
  208.         ++inp;
  209.         if (inp == in->buf + in->len)
  210.         /* "...-" = "...-\377" */
  211.         last = 0377;
  212.         else
  213.         last = *inp++;
  214.         for (++first; first <= last; ++first)
  215.         *outp++ = first;
  216.     } else
  217.         *outp++ = *inp++;
  218.     out->len = outp - out->buf;
  219. }
  220. /*
  221.  * Put the complement of in with respect to 1-0377 octal into out, in ASCII
  222.  * order. 
  223.  */
  224.  
  225. void 
  226. complement(in, out)
  227. SET *in,
  228. *out;
  229. {
  230.     char *outp;
  231.     int i;
  232.  
  233.     outp = out->buf;
  234.     for (i = 1; i <= 0377; ++i)
  235.     if (indexo(in, i) == -1)
  236.         *outp++ = i;
  237.     out->len = outp - out->buf;
  238. }
  239. /*
  240.  * If necessary, pad outset to the length of inset with outset's last
  241.  * character. 
  242.  */
  243.  
  244. void 
  245. pad(inset, outset)
  246. SET *inset,
  247. *outset;
  248. {
  249.     char last;
  250.  
  251.     last = outset->buf[outset->len - 1];
  252.     while (outset->len < inset->len)
  253.     outset->buf[outset->len++] = last;
  254. }
  255. /*
  256.  * Copy standard input to standard output; if a character is a member of
  257.  * inset, transliterate it to the corresponding member of outset. 
  258.  */
  259.  
  260. void 
  261. tr(inset, outset)
  262. SET *inset,
  263. *outset;
  264. {
  265.     int c;                   /* One character of input. */
  266.     int i;                   /* Index into in and out bufs. */
  267.  
  268.     while ((c = getchar()) != EOF)
  269.     if ((i = indexo(inset, c)) != -1)
  270.     {
  271.         if (!dflag)
  272.         outchar(outset->buf[i], outset);
  273.     } else
  274.         outchar(c, outset);
  275. }
  276. /*
  277.  * Send c to standard output, removing duplicate consecutive characters that
  278.  * are members of outset if the -s flag was given. 
  279.  */
  280. void 
  281. outchar(c, outset)
  282. int c;
  283. SET *outset;
  284. {
  285.     static int prevc = -1;
  286.  
  287.     if (!sflag || c != prevc || indexo(outset, c) == -1)
  288.     {
  289. #if AZTEC
  290.     if (!bflag)
  291.         aputc(c, stdout);
  292.     else
  293. #endif
  294.         putc(c, stdout);
  295.     }
  296.     prevc = c;
  297. }
  298. /*
  299.  * Return the offset (0 through s->len - 1) of the first occurrence of
  300.  * character c in s, or -1 if not found. 
  301.  */
  302.  
  303. int 
  304. indexo(s, c)
  305. SET *s;
  306. char c;
  307. {
  308.     int i;
  309.  
  310.     for (i = 0; i < s->len && s->buf[i] != c; ++i)
  311.      /* Do nothing. */ ;
  312.     return i < s->len ? i : -1;
  313. }
  314.  
  315. void 
  316. usage()
  317. {
  318. #if AZTEC
  319.     fprintf(stderr, "Usage: tr [-bcds] [inset [outset]]\n");
  320. #else
  321.     fprintf(stderr, "Usage: tr [-cds] [inset [outset]]\n");
  322. #endif
  323.     exit(1);
  324. }
  325.