home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / utility / tr.zoo / tr.c < prev    next >
C/C++ Source or Header  |  1991-03-07  |  8KB  |  395 lines

  1. /****************************************************************/
  2. /*    Translate characters in a file                */
  3. /*                                */
  4. /*    By David Megginson, 1991                */
  5. /*    Released into the public domain.            */
  6. /*                                */
  7. /*    Command line options:                    */
  8. /*        -c    use the complement of the characters    */
  9. /*        -d    delete the given characters        */
  10. /*        -s    squeeze repeated instances        */
  11. /*    (count everything by default)                */
  12. /*                                */
  13. /*    Makefile options:                    */
  14. /*        -DBUFFER_SIZE=n        Read n bytes at a time    */
  15. /*        -DCHARSET_SIZE=n    Character set size    */
  16. /*        -DSKIP_CR        Ignore carriage returns    */
  17. /****************************************************************/
  18.  
  19.  
  20. /* $Id: tr.c,v 1.2 1991/03/05 09:01:38 david Exp david $ */
  21.  
  22. /*
  23.  * $Log: tr.c,v $
  24.  * Revision 1.2  1991/03/05  09:01:38  david
  25.  * Changed `static version' to `static char * version' (duh!)
  26.  *
  27.  * Revision 1.1  1991/03/05  08:58:44  david
  28.  * Initial revision
  29.  *
  30.  */
  31.  
  32. static char * version = "$Id: tr.c,v 1.2 1991/03/05 09:01:38 david Exp david $";
  33.  
  34.  
  35. #include <stdio.h>
  36. #include <stddef.h>
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <fcntl.h>
  40. #include <errno.h>
  41.  
  42. /* The string of legal options for getopt            */
  43.  
  44. #define    OPTSTRING    "cds"
  45.  
  46. /* The size of the character set in use. Allow the Makefile    */
  47. /* to override this, if desired.                */
  48.  
  49. #ifndef    CHARSET_SIZE
  50. #define    CHARSET_SIZE    256
  51. #endif
  52.  
  53. /* The translation table                    */
  54.  
  55. char table[CHARSET_SIZE];
  56.  
  57. /* The combined size of the buffers. Allow the user to define    */
  58. /* this in the Makefile if desired.                */
  59.  
  60. #ifndef    BUFFER_SIZE
  61. #define    BUFFER_SIZE    50000L
  62. #endif
  63.  
  64. /* Use these buffers to do the translation            */
  65.  
  66. static char buffer1[BUFFER_SIZE/2];
  67. static char buffer2[BUFFER_SIZE/2];
  68.  
  69. /* Command line options                        */
  70.  
  71. #define    OPTSTRING    "cds"
  72.  
  73. /* Command line flags                        */
  74.  
  75. static int c_flag = 0;
  76. static int d_flag = 0;
  77. static int s_flag = 0;
  78.  
  79. /* getopt() stuff                        */
  80.  
  81. extern int optind;
  82.  
  83. /* Local functions */
  84.  
  85. static void parse_string( const char * string );
  86. static void parse_strings( const char * string1,const char * string2 );
  87. static void expand_string( const char * string,char * buffer );
  88. static void do_delete( void );
  89. static fpos_t delete_between_buffers( fpos_t count );
  90. static void do_translate( void );
  91. static fpos_t translate_between_buffers( fpos_t count );
  92. static void usage( void );
  93.  
  94.  
  95. main( int ac,const char ** av )
  96. {
  97.     int opt;
  98.  
  99.     /* Register the options                */
  100.     
  101.     opt = getopt(ac,av,OPTSTRING);
  102.     while( opt != EOF ) {
  103.         switch( opt ) {
  104.  
  105.         case 'c':    /* complement    */
  106.             c_flag = 1;
  107.             break;
  108.         case 'd':    /* delete    */
  109.             d_flag = 1;
  110.             if( s_flag ) {
  111.                 fprintf(stderr,"%s: -d and -s conflict\n",
  112.                         av[0]);
  113.                 exit(2);
  114.             }
  115.             break;
  116.         case 's':    /* squeeze    */
  117.             s_flag = 1;
  118.             if( d_flag ) {
  119.                 fprintf(stderr,"%s: -d and -s conflict\n",
  120.                         av[0]);
  121.                 exit(2);
  122.             }
  123.             break;
  124.         }
  125.  
  126.         opt = getopt(ac,av,OPTSTRING);
  127.     }
  128.  
  129.     /* If the -d option is given, we need only    */
  130.     /* one string; otherwise, we need two.        */
  131.     
  132.     if( d_flag ) {
  133.         if( optind != ac - 1 ) {
  134.             usage();
  135.             exit(2);
  136.         }
  137.         parse_string(av[optind]);
  138.         do_delete();
  139.     } else {
  140.         if( optind != ac - 2 ) {
  141.             usage();
  142.             exit(2);
  143.         }
  144.         parse_strings(av[optind],av[optind+1]);
  145.         do_translate();
  146.     }
  147.  
  148.     return 0;
  149. }
  150.  
  151.  
  152. /*******
  153.     Parse a single command-line string.
  154.  
  155.     Arguments:    const char * string
  156.     Return value:    none
  157. *******/
  158.  
  159. static void
  160. parse_string( const char * string )
  161. {
  162.     int x,def,special;
  163.     char * ptr;
  164.  
  165.     /* If the complement flag is set, flag everything    */
  166.     /* in the table except the contents of the string;    */
  167.     /* otherwise, flag only the contents of the string.    */
  168.     
  169.     if( c_flag ) {
  170.         def = 1;
  171.         special = 0;
  172.     } else {
  173.         def = 0;
  174.         special = 1;
  175.     }
  176.  
  177.     /* Set the whole table to the default setting.        */
  178.     
  179.     for( x = 0; x < CHARSET_SIZE; x++ )
  180.         table[x] = def;
  181.  
  182.     /* Expand the string.                    */
  183.     
  184.     expand_string(string,buffer1);
  185.  
  186.     /* Read the string into the table            */
  187.     
  188.     for( ptr = buffer1; *ptr; ptr++ )
  189.         table[*ptr] = special;
  190. }
  191.  
  192.  
  193. /*******
  194.     Parse two command-line strings for translation.
  195.  
  196.     Arguments:    const char * string1
  197.             const char * string2
  198.     Return value:    none
  199. *******/
  200.  
  201. static void
  202. parse_strings( const char * string1,const char * string2 )
  203. {
  204.     int x;
  205.     char * ptr1,* ptr2;
  206.  
  207.     /* expand both strings, borrowing the i/o buffers    */
  208.     
  209.     expand_string(string1,buffer1);
  210.     expand_string(string2,buffer2);
  211.     ptr1 = buffer1;
  212.     ptr2 = buffer2;
  213.  
  214.     /* if the complement flag is set, use everything but    */
  215.     /* the characters in string1                */
  216.     
  217.     if( c_flag ) {
  218.  
  219.         /* flag the entire table        */
  220.         
  221.         for( x = 0; x < CHARSET_SIZE; x++ )
  222.             table[x] = 1;
  223.  
  224.         /* unflag the characters given        */
  225.         
  226.         for( ; *ptr1; ptr1++ )
  227.             table[*ptr1] = 0;
  228.  
  229.         /* translate all flagged characters    */
  230.         for( x = 0; x < CHARSET_SIZE; x++ ) {
  231.             if( table[x] ) {
  232.                 table[x] = *ptr2;
  233.                 if( *(ptr2+1) )
  234.                     ptr2++;
  235.             }
  236.         }
  237.  
  238.     /* set up the translation table                */
  239.     
  240.     } else {
  241.         for( ; *ptr1; ptr1++ ) {
  242.             table[*ptr1] = *ptr2;
  243.             if( *(ptr2+1) )
  244.                 ptr2++;
  245.         }
  246.     }
  247. }
  248.     
  249. /*******
  250.     Expand a command-line string into a full string.
  251.  
  252.     Arguments:    const char * string
  253.             char * buffer    the output buffer
  254.     Return value:    none
  255. *******/
  256.  
  257. static void
  258. expand_string( const char * string,char * buffer )
  259. {
  260.     int c;
  261.     
  262.     while( *string ) {
  263.         if( *(string+1) == '-' && *(string+2) ) {
  264.             for( c = *string; c <= *(string+2); c++ )
  265.                 *(buffer++) = c;
  266.             string += 3;
  267.         } else if( *string == '\\' ) {
  268.             if( *(string+1) >= '0'
  269.                     && *(string+1) <= '7' ) {
  270.                 c = *(++string) - '0';
  271.             }
  272.             if( *(string+1) >= '0'
  273.                     && *(string+1) <= '7' ) {
  274.                 c = c * 8 + *(++string) - '0';
  275.             }
  276.             if( *(string+1) >= '0'
  277.                     && *(string+1) <= '7' ) {
  278.                 c = c * 8 + *(++string) - '0';
  279.             }
  280.             *(buffer++) = c;
  281.             string++;
  282.         } else {
  283.             *(buffer++) = *(string++);
  284.         }
  285.     }
  286.     *buffer = '\0';
  287. }
  288.  
  289.  
  290. /*******
  291.     Copy from stdin to stdout, deleting characters.
  292. *******/
  293.  
  294. static void
  295. do_delete()
  296. {
  297.     fpos_t total_read,total_write;
  298.  
  299.     do {
  300.         total_read = read(0,buffer1,BUFFER_SIZE/2);
  301.         if( total_read > 0 )
  302.             total_write = delete_between_buffers(total_read);
  303.         write(1,buffer2,total_write);
  304.     } while( total_read > 0 );
  305. }
  306.  
  307. /*******
  308.     Filter delete between buffers.
  309. *******/
  310.  
  311. static fpos_t
  312. delete_between_buffers( fpos_t count )
  313. {
  314.     fpos_t x,outpos = 0;
  315.  
  316.     for( x = 0; x < count; x++ ) {
  317. #ifdef SKIP_CR
  318.         /* Make sure that we delete the \r as well as    */
  319.         /* the \n in an \r\n combination        */
  320.         
  321.         if( buffer1[x] == '\r' && buffer1[x+1] == '\n'
  322.                 && !table['\n'] )
  323.             continue;
  324. #endif SKIP_CR
  325.         if( !table[buffer1[x]] )
  326.             buffer2[outpos++] = buffer1[x];
  327.     }
  328.     return outpos;
  329. }
  330.  
  331. /*******
  332.     Copy from stdin to stdout, translating characters.
  333. *******/
  334.  
  335. static void
  336. do_translate()
  337. {
  338.     fpos_t total_read,total_write;
  339.  
  340.     do {
  341.         total_read = read(0,buffer1,BUFFER_SIZE/2);
  342.         if( total_read > 0 )
  343.             total_write = translate_between_buffers(total_read);
  344.         write(1,buffer2,total_write);
  345.     } while( total_read > 0 );
  346. }
  347.  
  348.  
  349. /*******
  350.     Filter translate between buffers.
  351. *******/
  352.  
  353. static fpos_t
  354. translate_between_buffers( fpos_t count )
  355. {
  356.     fpos_t x,outpos = 0;
  357.     int lastchar = 0;
  358.  
  359.     for( x = 0; x < count; x++ ) {
  360. #ifdef SKIP_CR
  361.         /* If the \n is going to become something else,    */
  362.         /* we should not copy the \r            */
  363.         
  364.         if( buffer1[x] == '\r' && buffer1[x+1] == '\n'
  365.                 && table['\n'] )
  366.             x++;
  367. #endif
  368.         if( !table[buffer1[x]] ) {
  369.             lastchar = buffer1[x];
  370.             buffer2[outpos++] = lastchar;
  371.         } else if( s_flag && table[buffer1[x]] == lastchar ) {
  372.             continue;
  373.         } else {
  374. #ifdef SKIP_CR
  375.         /* If we are translating into \n, do not add    */
  376.         /* \r for now (buffer overflow)            */
  377. #endif SKIP_CR
  378.             lastchar = table[buffer1[x]];
  379.             buffer2[outpos++] = lastchar;
  380.         }
  381.     }
  382.     return outpos;
  383. }
  384.  
  385.  
  386. /*******
  387.     Print a usage message.
  388. *******/
  389.  
  390. static void
  391. usage()
  392. {
  393.     fprintf(stderr,"usage: tr [-cds [string1 [string2]]]\n");
  394. }
  395.