home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / chop / chop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-25  |  5.6 KB  |  296 lines

  1. /*
  2.  *    chop - chop selected fields out of text.
  3.  *    G. L. Sicherman.  August 7, 1990.  February 10, 1991.
  4.  *
  5.  *    chop -cLIST [file ...]
  6.  *    chop -fLIST [-dchar] [-b] [file ...]
  7.  *
  8.  *    Chop writes the specified fields (-f) or columns (-c)
  9.  *        to the standard output.
  10.  *    Default output field separator is horizontal tab.
  11.  *    Default field separator is white space;
  12.  *    -dx... specifies characters x... as input field separators
  13.  *    and the first x as output field separator.
  14.  *    If the input separator is white space, leading white space
  15.  *    is ignored unless you specify -b.
  16.  *
  17.  *    Unlike cut(1), chop processes *all* input lines as specified,
  18.  *    and a line can be as long as you like.
  19.  *
  20.  *    Carriage returns, line feeds, and form feeds all act as
  21.  *    line separators.  Other control characters (other than
  22.  *    separators) are treated as ordinary characters in fields.
  23.  *    In columns, BS is -1 column, HT jumps to a standard
  24.  *    8-column tab stop.
  25.  *
  26.  *    EXIT CODES:    0 on success;
  27.  *            1 on syntax errors;
  28.  *            2 on file access failures.
  29.  */
  30.  
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34.  
  35. char    *calloc();
  36.  
  37. #define    INFINITY    (-1)
  38. #define    DEFOUTSEP    '\t'
  39.  
  40. struct rangetype {
  41.     int    first;
  42.     int    last;
  43. };
  44.  
  45. static    int    bflag = 0;
  46. static    char    *cflag = (char *)NULL;
  47. static    char    *dflag = (char *)NULL;
  48. static    char    *fflag = (char *)NULL;
  49. static    FILE    *Input;
  50. static    int    nranges;
  51. static    char    *progn;
  52. static    struct    rangetype    *range;
  53. static    int    (*process)();
  54. static    int    cprocess(), fprocess();
  55.  
  56. usage()
  57. {
  58.     fprintf(stderr, "usage: %s -cLIST [file ...]\n", progn);
  59.     fprintf(stderr, "       %s -fLIST [-dCHARS] [-b] [file ...]\n", progn);
  60.     exit(1);
  61. }
  62.  
  63. main(argc, argv)
  64. int    argc;
  65. char    **argv;
  66. {
  67.     progn = *argv;
  68.     while (--argc) {
  69.         if ('-'!=**++argv) break;
  70.         switch(*++*argv) {
  71.         case 'b':
  72.             bflag = 1;
  73.             break;
  74.         case 'c':
  75.             if (!*(cflag = ++*argv)) {
  76.                 fprintf(stderr,
  77.                 "%s: column list required after -c\n", progn);
  78.                 exit(1);
  79.             }
  80.             break;
  81.         case 'd':
  82.             if (!*(dflag = ++*argv)) {
  83.                 fprintf(stderr,
  84.                 "%s: character required after -d\n", progn);
  85.                 exit(1);
  86.             }
  87.             break;
  88.         case 'f':
  89.             if (!*(fflag = ++*argv)) {
  90.                 fprintf(stderr,
  91.                 "%s: field list required after -f\n", progn);
  92.                 exit(1);
  93.             }
  94.             break;
  95.         default:
  96.             usage();
  97.         }
  98.     }
  99.     if (!fflag == !cflag) usage();
  100.     if (cflag) {
  101.         process = cprocess;
  102.         setupranges(cflag);
  103.     }
  104.     else {
  105.         process = fprocess;
  106.         setupranges(fflag);
  107.     }
  108.     if (cflag && dflag) fprintf(stderr, "%s: -d option ignored with -c\n",
  109.         progn);
  110.     if (cflag && bflag) fprintf(stderr, "%s: -b option ignored with -c\n",
  111.         progn);
  112.     if (fflag && dflag && bflag) {
  113.         fprintf(stderr, "%s: -b option ignored with -d\n", progn);
  114.         bflag = 0;
  115.     }
  116.     if (argc) while (argc--) {
  117.         Input = fopen(*argv++, "r");
  118.         if (!Input) {
  119.             fprintf(stderr, "%s: cannot read %s\n",
  120.                 progn, *--argv);
  121.             exit(2);
  122.         }
  123.         (*process)(Input);
  124.         fclose(Input);
  125.     }
  126.     else (*process)(stdin);
  127. }
  128.  
  129. /*
  130.  *    chop -c
  131.  */
  132. static    int    incol, outcol;
  133.  
  134. static int
  135. cprocess(stream)
  136. FILE    *stream;
  137. {
  138.     int    k;
  139.  
  140.     incol = outcol = 0;
  141.     for (;;) {
  142.         switch(k = getc(stream)) {
  143.         case EOF:    return;
  144.         case '\b':    if (!incol--) incol = 0;
  145.                 break;
  146.         case '\t':    incol = (incol+8)&~7;
  147.                 break;
  148.         case '\n':
  149.         case '\r':
  150.         case '\f':    catchup();
  151.                 putchar(k);
  152.                 incol = outcol = 0;
  153.                 break;
  154.         default:
  155.                 catchup();
  156.                 if (wantit(++outcol)) putchar(k);
  157.                 incol++;
  158.         }
  159.     }
  160. }
  161.  
  162. catchup()
  163. {
  164.     while (incol > outcol) if (wantit(++outcol)) putchar(' ');
  165.     while (incol < outcol) if (wantit(outcol--)) putchar('\b');
  166. }
  167.  
  168. /*
  169.  *    chop -f
  170.  */
  171.  
  172. static int
  173. fprocess(stream)
  174. FILE    *stream;
  175. {
  176.     int    field, go;
  177.     int    k;
  178.     int    later;
  179.     char    *seps;
  180.     int    want;
  181.  
  182.     field = later = 0;
  183.     seps = dflag? dflag: "\t ";
  184.     for (;;) {
  185. newfield:
  186.         field++;
  187.         go = 0;
  188.         want = wantit(field);
  189.         if (want && later++) putchar(*seps);
  190.         for (;;) {            /* process one field */
  191.             k = getc(stream);
  192.             if (EOF==k) return;
  193.             if (strchr(seps, k)) {
  194.                 if (field==1 && !go
  195.                 && !dflag && !bflag) continue;
  196.                 else break;
  197.             }
  198.             if (strchr("\n\r\f", k)) {
  199.                 putchar(k);
  200.                 field = later = 0;
  201.                 goto newfield;    /* i.e., break 2 */
  202.             }
  203.             go = 1;
  204.             if (want) putchar(k);
  205.         }
  206. /*
  207.  *        If white space, skip it.
  208.  */
  209.         if (!dflag) for (;;) {
  210.             k = getc(stream);
  211.             if (EOF==k) {
  212.                 putchar(*seps);
  213.                 return;
  214.             }
  215.             if (strchr(seps, k)) continue;
  216.             ungetc(k, stream);
  217.             break;
  218.         }
  219.     }
  220. }
  221.  
  222. int
  223. wantit(f)
  224. int    f;
  225. {
  226.     int    r;
  227.  
  228.     for (r=0; r<nranges; r++) {
  229.         if (range[r].last != INFINITY && range[r].last < f) continue;
  230.         if (range[r].first <= f) return 1;
  231.     }
  232.     return 0;
  233. }
  234.  
  235. setupranges(list)
  236. char    *list;
  237. {
  238.     char    *cursor;
  239. /*
  240.  *    How many commas?
  241.  */
  242.     nranges = 1;
  243.     for (cursor = list; *cursor; cursor++)
  244.         if (',' == *cursor) nranges++;
  245.     range = (struct rangetype *)calloc(nranges, sizeof(struct rangetype));
  246.     nranges = 0;
  247.     for (cursor = list; cursor; ) {
  248.         onerange(cursor);
  249.         if (cursor = strchr(cursor,',')) cursor++;
  250.     }
  251. }
  252.  
  253. onerange(r)
  254. char    *r;
  255. {
  256.     if (isdigit(*r)) {
  257.         range[nranges].first = atoi(r);
  258.         while (isdigit(*r)) r++;
  259.         if (','==*r || !*r) {
  260.             range[nranges].last = range[nranges].first;
  261.             nranges++;
  262.             return;
  263.         }
  264.         if ('-'!=*r++) {
  265.             fprintf(stderr,
  266.                 "%s: bad character '%c' in field list\n",
  267.                 progn, *--r);
  268.             exit(1);
  269.         }
  270.     }
  271.     else if ('-'==*r++) {
  272.         range[nranges].first = 1;
  273.     }
  274.     else {
  275.         fprintf(stderr, "%s: bad character '%c' in field list\n",
  276.             progn, *--r);
  277.         exit(1);
  278.     }
  279.     if (','==*r || !*r) {
  280.         range[nranges++].last = INFINITY;
  281.         return;
  282.     }
  283.     if (!isdigit(*r)) {
  284.         fprintf(stderr, "%s: bad character '%c' in field list\n",
  285.             progn, *r);
  286.         exit(1);
  287.     }
  288.     range[nranges++].last = atoi(r);
  289.     while (isdigit(*r)) r++;
  290.     if (*r && ','!=*r) {
  291.         fprintf(stderr, "%s: bad character '%c' in field list\n",
  292.             progn, *r);
  293.         exit(1);
  294.     }
  295. }
  296.