master xplshn/aruu / cmd / posix / wc.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <string.h>
  4
  5#include "utf.h"
  6#include "util.h"
  7
  8static int    lflag = 0;
  9static int    wflag = 0;
 10static char   cmode = 0;
 11static size_t tc = 0, tl = 0, tw = 0;
 12
 13static void
 14output(const char *str, size_t nc, size_t nl, size_t nw)
 15{
 16  int first = 1;
 17
 18  if (lflag) {
 19    first = 0;
 20    printf("%zu", nl);
 21  }
 22  if (wflag) {
 23    if (!first)
 24      putchar(' ');
 25    first = 0;
 26    printf("%zu", nw);
 27  }
 28  if (cmode) {
 29    if (!first)
 30      putchar(' ');
 31    printf("%zu", nc);
 32  }
 33  if (str)
 34    printf(" %s", str);
 35  putchar('\n');
 36}
 37
 38static void
 39wc(FILE *fp, const char *str)
 40{
 41  int    word = 0, rlen;
 42  Rune   c;
 43  size_t nc = 0, nl = 0, nw = 0;
 44
 45  while ((rlen = efgetrune(&c, fp, str))) {
 46    nc += (cmode == 'c') ? rlen : (c != Runeerror);
 47    if (c == '\n')
 48      nl++;
 49    if (!isspacerune(c))
 50      word = 1;
 51    else if (word) {
 52      word = 0;
 53      nw++;
 54    }
 55  }
 56  if (word)
 57    nw++;
 58  tc += nc;
 59  tl += nl;
 60  tw += nw;
 61  output(str, nc, nl, nw);
 62}
 63
 64static void
 65usage(void)
 66{
 67  eprintf("usage: %s [-c | -m] [-lw] [file ...]\n", argv0);
 68}
 69
 70// ?man wc: count lines, words, and bytes
 71// ?man arguments: file ...
 72// ?man display the number of lines, words, and bytes in files
 73int
 74main(int argc, char *argv[])
 75{
 76  FILE *fp;
 77  int   many;
 78  int   ret = 0;
 79
 80  ARGBEGIN
 81  {
 82    // ?man -c: print count or perform stdout action
 83    case 'c':
 84      cmode = 'c';
 85      break;
 86    // ?man -m: specify mode or limit
 87    case 'm':
 88      cmode = 'm';
 89      break;
 90    // ?man -l: list in long format
 91    case 'l':
 92      lflag = 1;
 93      break;
 94    // ?man -w: wait for completion
 95    case 'w':
 96      wflag = 1;
 97      break;
 98    default:
 99      usage();
100  }
101  ARGEND
102
103  if (!lflag && !wflag && !cmode) {
104    cmode = 'c';
105    lflag = 1;
106    wflag = 1;
107  }
108
109  if (!argc) {
110    wc(stdin, NULL);
111  } else {
112    for (many = (argc > 1); *argv; argc--, argv++) {
113      if (!strcmp(*argv, "-")) {
114        *argv = "<stdin>";
115        fp    = stdin;
116      } else if (!(fp = fopen(*argv, "r"))) {
117        weprintf("fopen %s:", *argv);
118        ret = 1;
119        continue;
120      }
121      wc(fp, *argv);
122      if (fp != stdin && fshut(fp, *argv))
123        ret = 1;
124    }
125    if (many)
126      output("total", tc, tl, tw);
127  }
128
129  ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
130
131  return ret;
132}