/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include #include "arg.h" struct result { ssize_t n; int width; }; char *argv0; static void usage(void) { fprintf(stderr, "usage: %s [-s] [file] ...\n", argv0); exit(1); } static ssize_t count(int fd, const char *fname) { char buf[BUFSIZ], c; ssize_t i, n, ret = 0; char quote = 0; char comment = 0; signed char escape = 0; signed char slash = 0; signed char asterisk = 0; for (;;) { n = read(fd, buf, sizeof(buf)); if (n <= 0) { if (!n) break; if (errno == EINTR) continue; fprintf(stderr, "%s: %s :%s\n", argv0, fname, strerror(errno)); return -1; } for (i = 0; i < n; i++) { c = buf[i]; again: if (slash) { slash = 0; if (c == '*' || c == '/') comment = c; else goto again; } else if (comment == '/') { if (c == '\n') comment = 0; } else if (comment == '*') { if (c == '*') { asterisk = 1; } else if (asterisk) { asterisk = 0; if (c == '/') comment = 0; } } else if (escape) { escape = 0; } else if (quote) { if (c == '\\') escape = 1; else if (c == quote) quote = 0; } else if (c == '/') { slash = 1; } else if (c == '"' || c == '\'') { quote = c; } else if (c == '{') { ret += 1; } } } return ret; } static ssize_t open_and_count(const char *path) { ssize_t r; int fd; if (!path || !strcmp(path, "-")) { r = count(STDIN_FILENO, ""); } else { fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, "%s: %s: %s\n", argv0, path, strerror(errno)); return -1; } r = count(fd, path); close(fd); } return r; } static int strwidth(const char *s) { size_t wn, n = strlen(s) + 1u; wchar_t *ws = calloc(n, sizeof(*ws)); int r = -1; if (!ws) { fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); exit(1); } wn = mbstowcs(ws, s, n); if (wn != (size_t)-1) r = wcswidth(ws, wn); free(ws); return r < 0 ? (int)n - 1 : r; } int main(int argc, char *argv[]) { struct result *results; int sum_only = 0; int ret = 0; ssize_t r; size_t total = 0u; int i, left, right; int maxwidth = 0; ARGBEGIN { case 's': sum_only = 1; break; default: usage(); } ARGEND; setlocale(LC_ALL, ""); if (argc < 2) { r = open_and_count(argv[0]); if (r < 0) return 1; printf("%zi\n", r); } else { results = calloc((size_t)argc, sizeof(*results)); if (!results) { fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); exit(1); } for (i = 0; i < argc; i++) { results[i].n = open_and_count(argv[0]); if (results[i].n < 0) { ret = 1; continue; } left = strwidth(argv[i]); right = snprintf(NULL, 0u, "%zi", results[i].n); results[i].width = left + right; if (maxwidth < results[i].width) maxwidth = results[i].width; } for (i = 0; i < argc; i++) { if (results[i].n < 0) continue; total += (size_t)results[i].n; if (sum_only) continue; printf("%s:%*s %zi\n", argv[i], maxwidth - results[i].width, "", results[i].n); } free(results); printf("%zu\n", total); } if (fflush(stdout) || ferror(stdout) || fclose(stdout)) { fprintf(stderr, "%s: : %s\n", argv0, strerror(errno)); exit(1); } return ret; }