add: dev workflow shenanigans
some shit
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
# fastwc style, codified. 4 spaces, Allman braces, 80 columns.
|
||||||
|
# The style guide is the law; clang-format is the enforcement.
|
||||||
|
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
ColumnLimit: 80
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
PointerAlignment: Right
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
IncludeBlocks: Regroup
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
# fastwc clang-tidy configuration.
|
||||||
|
# The project compiles with zero warnings; clang-tidy keeps the
|
||||||
|
# static analysis honest. clang-analyzer-* runs in-editor via clangd.
|
||||||
|
#
|
||||||
|
# Disabled noise:
|
||||||
|
# - DeprecatedOrUnsafeBufferHandling: demands Annex K *_s functions,
|
||||||
|
# which are not portable POSIX (WG14 deprecated Annex K itself).
|
||||||
|
# - bugprone-reserved-identifier: flags _POSIX_C_SOURCE, the required
|
||||||
|
# feature-test macro idiom for POSIX programs.
|
||||||
|
|
||||||
|
Checks: '-*,clang-analyzer-*,bugprone-*,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-bugprone-reserved-identifier,-bugprone-easily-swappable-parameters'
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
FormatStyle: file
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# clangd configuration for fastwc.
|
||||||
|
# The style guide is the law; clangd is the enforcement.
|
||||||
|
|
||||||
|
CompileFlags:
|
||||||
|
Compiler: clang
|
||||||
|
Add:
|
||||||
|
- -Wall
|
||||||
|
- -Wextra
|
||||||
|
|
||||||
|
Diagnostics:
|
||||||
|
ClangTidy: true
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# fastwc editor configuration — one file, one opinion, one indentation.
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[Makefile.am]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# fastwc repository hygiene.
|
||||||
|
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.c text
|
||||||
|
*.h text
|
||||||
|
*.md text
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.ac text
|
||||||
|
*.am text
|
||||||
|
*.json text
|
||||||
|
|
||||||
|
*.c diff=cpp
|
||||||
|
*.h diff=cpp
|
||||||
|
*.sh diff=bash
|
||||||
@@ -60,6 +60,8 @@ benchmarks/FAILED-benchmark.txt
|
|||||||
# ---> fastwc build artifacts
|
# ---> fastwc build artifacts
|
||||||
bin/
|
bin/
|
||||||
fastwc
|
fastwc
|
||||||
|
compile_commands.json
|
||||||
|
.cache/
|
||||||
|
|
||||||
# ---> autotools generated
|
# ---> autotools generated
|
||||||
Makefile
|
Makefile
|
||||||
|
|||||||
+19
-1
@@ -12,7 +12,25 @@ release: all
|
|||||||
bench: release
|
bench: release
|
||||||
./benchmarks/test-all.sh
|
./benchmarks/test-all.sh
|
||||||
|
|
||||||
|
# --- developer conveniences ---
|
||||||
|
# compile_commands.json for clangd (bear if present, else Makefile-derived).
|
||||||
|
compile-commands:
|
||||||
|
./scripts/gen-compile-commands.sh
|
||||||
|
|
||||||
|
# Make the code confess to the style guide.
|
||||||
|
format:
|
||||||
|
clang-format -i $(fastwc_SOURCES)
|
||||||
|
|
||||||
|
# Verify the code already confesses, without touching it.
|
||||||
|
format-check:
|
||||||
|
clang-format --dry-run --Werror $(fastwc_SOURCES)
|
||||||
|
|
||||||
|
# Static analysis via clang-tidy (needs compile_commands.json).
|
||||||
|
# Warnings are errors: the style guide is the law.
|
||||||
|
lint: compile-commands
|
||||||
|
clang-tidy -p . --warnings-as-errors='*' $(fastwc_SOURCES)
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
rm -rf bin
|
rm -rf bin
|
||||||
|
|
||||||
.PHONY: release bench
|
.PHONY: release bench compile-commands format format-check lint
|
||||||
|
|||||||
@@ -75,6 +75,26 @@ keep the minimum, and fail the moment fastwc loses a single case. GNU
|
|||||||
`wc` is used as an oracle the same way you'd use a broken clock:
|
`wc` is used as an oracle the same way you'd use a broken clock:
|
||||||
occasionally it's right, and it's the only one around.
|
occasionally it's right, and it's the only one around.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
The editor setup is one command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make compile-commands # compile_commands.json for clangd
|
||||||
|
```
|
||||||
|
|
||||||
|
clangd reads `.clangd`, `.clang-tidy`, and `.clang-format` — the style
|
||||||
|
guide, enforced by robots. We use `bear` when it's installed; the
|
||||||
|
fallback hand-rolls the single entry from the Makefile, because one
|
||||||
|
source file doesn't need a database.
|
||||||
|
|
||||||
|
- `make format` — make the code confess to the style guide
|
||||||
|
- `make format-check` — verify without touching
|
||||||
|
- `make lint` — clang-tidy, static analysis included
|
||||||
|
|
||||||
|
`.editorconfig` and `.gitattributes` keep every editor honest. Your
|
||||||
|
editor has opinions. So do we. Ours are in the repo.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT. Do whatever you want. We're not GNU, we won't sue you — we'll just
|
MIT. Do whatever you want. We're not GNU, we won't sue you — we'll just
|
||||||
|
|||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# Generate compile_commands.json for clangd.
|
||||||
|
#
|
||||||
|
# Uses bear when available so every real compile command is captured
|
||||||
|
# (future-proof as the project grows). Otherwise hand-rolls the single
|
||||||
|
# entry from the flags in the generated Makefile — one source file, one
|
||||||
|
# entry, no mysteries.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
if [ ! -f Makefile ]; then
|
||||||
|
echo "gen-compile-commands: no Makefile found - run ./autogen.sh first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v bear >/dev/null 2>&1; then
|
||||||
|
bear -- make -B >/dev/null
|
||||||
|
# Drop the configure probes (conftest.c); clangd only wants real files.
|
||||||
|
jq 'map(select(.file | endswith("conftest.c") | not))' compile_commands.json \
|
||||||
|
> compile_commands.json.tmp && mv compile_commands.json.tmp compile_commands.json
|
||||||
|
echo "compile_commands.json generated via bear"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CC=$(sed -n 's/^CC = //p' Makefile | head -n1)
|
||||||
|
[ -z "$CC" ] && CC=cc
|
||||||
|
DEFS=$(sed -n 's/^DEFS = //p' Makefile | head -n1)
|
||||||
|
AM_CFLAGS=$(sed -n 's/^AM_CFLAGS = //p' Makefile | head -n1)
|
||||||
|
CFLAGS=$(sed -n 's/^CFLAGS = //p' Makefile | head -n1)
|
||||||
|
|
||||||
|
# Drop defines carrying embedded quotes (PACKAGE_* metadata): they would
|
||||||
|
# break JSON and clangd does not need them.
|
||||||
|
SAFE_DEFS=''
|
||||||
|
for d in $DEFS; do
|
||||||
|
case "$d" in
|
||||||
|
*\"*) ;;
|
||||||
|
*) SAFE_DEFS="$SAFE_DEFS $d" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
CMD="$CC$SAFE_DEFS -I. $AM_CFLAGS $CFLAGS -c src/main.c -o src/main.o"
|
||||||
|
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
jq -n --arg d "$ROOT" --arg c "$CMD" --arg f "$ROOT/src/main.c" \
|
||||||
|
'[{directory: $d, command: $c, file: $f}]' > compile_commands.json
|
||||||
|
else
|
||||||
|
printf '[{"directory":"%s","command":"%s","file":"%s"}]\n' \
|
||||||
|
"$ROOT" "$CMD" "$ROOT/src/main.c" > compile_commands.json
|
||||||
|
fi
|
||||||
|
echo "compile_commands.json generated (fallback)"
|
||||||
+153
-87
@@ -19,24 +19,26 @@
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
F_LINES = 1 << 0, /* -l: count '\n' */
|
{
|
||||||
F_WORDS = 1 << 1, /* -w: whitespace-separated tokens */
|
F_LINES = 1 << 0, /* -l: count '\n' */
|
||||||
F_CHARS = 1 << 2, /* -m: multibyte characters */
|
F_WORDS = 1 << 1, /* -w: whitespace-separated tokens */
|
||||||
F_BYTES = 1 << 3, /* -c: bytes */
|
F_CHARS = 1 << 2, /* -m: multibyte characters */
|
||||||
|
F_BYTES = 1 << 3, /* -c: bytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int flags = 0;
|
static int flags = 0;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
long long lines;
|
long long lines;
|
||||||
long long words;
|
long long words;
|
||||||
long long chars;
|
long long chars;
|
||||||
long long bytes;
|
long long bytes;
|
||||||
int ok; /* read succeeded */
|
int ok; /* read succeeded */
|
||||||
} counts_t;
|
} counts_t;
|
||||||
|
|
||||||
static unsigned char ws_tab[256]; /* ws_tab[c] = 1 if c is whitespace */
|
static unsigned char ws_tab[256]; /* ws_tab[c] = 1 if c is whitespace */
|
||||||
|
|
||||||
static void init_ws_tab(void)
|
static void init_ws_tab(void)
|
||||||
{
|
{
|
||||||
@@ -46,18 +48,17 @@ static void init_ws_tab(void)
|
|||||||
|
|
||||||
static void usage(FILE *out)
|
static void usage(FILE *out)
|
||||||
{
|
{
|
||||||
fprintf(out,
|
fprintf(out, "usage: fastwc [-lwc] [-m] [file...]\n"
|
||||||
"usage: fastwc [-lwc] [-m] [file...]\n"
|
"\n"
|
||||||
"\n"
|
"Count lines, words, and bytes (default) or selected counts.\n"
|
||||||
"Count lines, words, and bytes (default) or selected counts.\n"
|
"With no file, or when file is -, read standard input.\n"
|
||||||
"With no file, or when file is -, read standard input.\n"
|
"\n"
|
||||||
"\n"
|
" -l count lines\n"
|
||||||
" -l count lines\n"
|
" -w count words\n"
|
||||||
" -w count words\n"
|
" -c count bytes\n"
|
||||||
" -c count bytes\n"
|
" -m count characters\n"
|
||||||
" -m count characters\n"
|
" --help display this help and exit\n"
|
||||||
" --help display this help and exit\n"
|
" --version output version information and exit\n");
|
||||||
" --version output version information and exit\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -75,7 +76,8 @@ static long long count_newlines(const unsigned char *s, size_t n)
|
|||||||
long long k = 0;
|
long long k = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (; i + 8 <= n; i += 8) {
|
for (; i + 8 <= n; i += 8)
|
||||||
|
{
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
memcpy(&x, s + i, 8);
|
memcpy(&x, s + i, 8);
|
||||||
x = (x ^ nl) & cl;
|
x = (x ^ nl) & cl;
|
||||||
@@ -99,7 +101,8 @@ static long long count_words(const unsigned char *s, size_t n, int *prev_ws)
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
int prev = *prev_ws;
|
int prev = *prev_ws;
|
||||||
|
|
||||||
for (; i + 8 <= n; i += 8) {
|
for (; i + 8 <= n; i += 8)
|
||||||
|
{
|
||||||
uint8_t m = 0;
|
uint8_t m = 0;
|
||||||
m |= (uint8_t)ws_tab[s[i + 0]] << 0;
|
m |= (uint8_t)ws_tab[s[i + 0]] << 0;
|
||||||
m |= (uint8_t)ws_tab[s[i + 1]] << 1;
|
m |= (uint8_t)ws_tab[s[i + 1]] << 1;
|
||||||
@@ -117,7 +120,8 @@ static long long count_words(const unsigned char *s, size_t n, int *prev_ws)
|
|||||||
prev = (m >> 7) & 1;
|
prev = (m >> 7) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i < n; i++) {
|
for (; i < n; i++)
|
||||||
|
{
|
||||||
int ws = ws_tab[s[i]];
|
int ws = ws_tab[s[i]];
|
||||||
if (prev && !ws)
|
if (prev && !ws)
|
||||||
w++;
|
w++;
|
||||||
@@ -142,27 +146,34 @@ static void count_stream_mb(FILE *fp, counts_t *c)
|
|||||||
|
|
||||||
memset(&st, 0, sizeof st);
|
memset(&st, 0, sizeof st);
|
||||||
|
|
||||||
while ((nread = fread(buf + pend, 1, sizeof buf - pend, fp)) > 0) {
|
while ((nread = fread(buf + pend, 1, sizeof buf - pend, fp)) > 0)
|
||||||
|
{
|
||||||
size_t n = nread + pend;
|
size_t n = nread + pend;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
c->bytes += (long long)nread;
|
c->bytes += (long long)nread;
|
||||||
|
|
||||||
while (i < n) {
|
while (i < n)
|
||||||
|
{
|
||||||
wchar_t wc;
|
wchar_t wc;
|
||||||
size_t r;
|
size_t r;
|
||||||
|
|
||||||
if (buf[i] < 0x80) {
|
if (buf[i] < 0x80)
|
||||||
|
{
|
||||||
wc = buf[i];
|
wc = buf[i];
|
||||||
r = 1;
|
r = 1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
r = mbrtowc(&wc, (const char *)buf + i, n - i, &st);
|
r = mbrtowc(&wc, (const char *)buf + i, n - i, &st);
|
||||||
if (r == (size_t)-2) { /* incomplete: carry over */
|
if (r == (size_t)-2)
|
||||||
|
{ /* incomplete: carry over */
|
||||||
pend = n - i;
|
pend = n - i;
|
||||||
memmove(buf, buf + i, pend);
|
memmove(buf, buf + i, pend);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (r == (size_t)-1) { /* invalid sequence */
|
if (r == (size_t)-1)
|
||||||
|
{ /* invalid sequence */
|
||||||
memset(&st, 0, sizeof st);
|
memset(&st, 0, sizeof st);
|
||||||
wc = L'\xfffd';
|
wc = L'\xfffd';
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -171,9 +182,12 @@ static void count_stream_mb(FILE *fp, counts_t *c)
|
|||||||
|
|
||||||
if (wc == L'\n')
|
if (wc == L'\n')
|
||||||
c->lines++;
|
c->lines++;
|
||||||
if (iswspace(wc)) {
|
if (iswspace(wc))
|
||||||
|
{
|
||||||
prev_ws = 1;
|
prev_ws = 1;
|
||||||
} else if (prev_ws) {
|
}
|
||||||
|
else if (prev_ws)
|
||||||
|
{
|
||||||
c->words++;
|
c->words++;
|
||||||
prev_ws = 0;
|
prev_ws = 0;
|
||||||
}
|
}
|
||||||
@@ -192,16 +206,21 @@ static void count_stream_mb(FILE *fp, counts_t *c)
|
|||||||
/* Fast path (-l/-w/-c): one pass, per-chunk memchr + table counting. */
|
/* Fast path (-l/-w/-c): one pass, per-chunk memchr + table counting. */
|
||||||
static void count_stream(FILE *fp, counts_t *c)
|
static void count_stream(FILE *fp, counts_t *c)
|
||||||
{
|
{
|
||||||
static unsigned char buf[1 << 17]; /* 128 KiB */
|
static unsigned char buf[1 << 17]; /* 128 KiB */
|
||||||
size_t nread;
|
size_t nread;
|
||||||
int prev_ws = 1; /* start of file: as if preceded by whitespace */
|
int prev_ws = 1; /* start of file: as if preceded by whitespace */
|
||||||
|
|
||||||
if (flags & F_CHARS) {
|
if (flags & F_CHARS)
|
||||||
|
{
|
||||||
count_stream_mb(fp, c);
|
count_stream_mb(fp, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((nread = fread(buf, 1, sizeof buf, fp)) > 0) {
|
for (;;)
|
||||||
|
{
|
||||||
|
nread = fread(buf, 1, sizeof buf, fp); /* NOLINT: EOF-state FP */
|
||||||
|
if (nread == 0)
|
||||||
|
break;
|
||||||
c->bytes += (long long)nread;
|
c->bytes += (long long)nread;
|
||||||
if (flags & F_LINES)
|
if (flags & F_LINES)
|
||||||
c->lines += count_newlines(buf, nread);
|
c->lines += count_newlines(buf, nread);
|
||||||
@@ -217,38 +236,53 @@ static void count_file(const char *path, counts_t *c)
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
if (strcmp(path, "-") == 0) {
|
if (strcmp(path, "-") == 0)
|
||||||
fp = stdin;
|
{
|
||||||
} else {
|
count_stream(stdin, c);
|
||||||
fp = fopen(path, "rb");
|
if (ferror(stdin))
|
||||||
if (fp == NULL) {
|
fprintf(stderr, "fastwc: standard input: read error: %s\n",
|
||||||
fprintf(stderr, "fastwc: %s: %s\n", path, strerror(errno));
|
strerror(errno));
|
||||||
c->ok = 0;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
fp = fopen(path, "rb");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fastwc: %s: %s\n", path, strerror(errno));
|
||||||
|
c->ok = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
count_stream(fp, c);
|
count_stream(fp, c);
|
||||||
|
|
||||||
if (ferror(fp))
|
if (ferror(fp))
|
||||||
fprintf(stderr, "fastwc: %s: read error: %s\n",
|
fprintf(stderr, "fastwc: %s: read error: %s\n", path, strerror(errno));
|
||||||
strcmp(path, "-") == 0 ? "standard input" : path,
|
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
if (fp != stdin)
|
fclose(fp);
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int col_width(long long v)
|
static int col_width(long long v)
|
||||||
{
|
{
|
||||||
int w = 1;
|
int w = 1;
|
||||||
while (v >= 10) {
|
while (v >= 10)
|
||||||
|
{
|
||||||
v /= 10;
|
v /= 10;
|
||||||
w++;
|
w++;
|
||||||
}
|
}
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void widen(int *width, long long v, int enabled)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
w = col_width(v);
|
||||||
|
if (w > *width)
|
||||||
|
*width = w;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
counts_t *rows;
|
counts_t *rows;
|
||||||
@@ -258,29 +292,43 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
init_ws_tab();
|
init_ws_tab();
|
||||||
|
|
||||||
for (a = 1; a < argc; a++) {
|
for (a = 1; a < argc; a++)
|
||||||
|
{
|
||||||
const char *arg = argv[a];
|
const char *arg = argv[a];
|
||||||
|
|
||||||
if (arg[0] != '-' || arg[1] == '\0')
|
if (arg[0] != '-' || arg[1] == '\0')
|
||||||
break; /* first file argument */
|
break; /* first file argument */
|
||||||
if (strcmp(arg, "--") == 0) {
|
if (strcmp(arg, "--") == 0)
|
||||||
|
{
|
||||||
a++;
|
a++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (strcmp(arg, "--help") == 0) {
|
if (strcmp(arg, "--help") == 0)
|
||||||
|
{
|
||||||
usage(stdout);
|
usage(stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (strcmp(arg, "--version") == 0) {
|
if (strcmp(arg, "--version") == 0)
|
||||||
|
{
|
||||||
printf("fastwc 0.1.0\n");
|
printf("fastwc 0.1.0\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (const char *p = arg + 1; *p; p++) {
|
for (const char *p = arg + 1; *p; p++)
|
||||||
switch (*p) {
|
{
|
||||||
case 'l': flags |= F_LINES; break;
|
switch (*p)
|
||||||
case 'w': flags |= F_WORDS; break;
|
{
|
||||||
case 'c': flags |= F_BYTES; break;
|
case 'l':
|
||||||
case 'm': flags |= F_CHARS; break;
|
flags |= F_LINES;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
flags |= F_WORDS;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
flags |= F_BYTES;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
flags |= F_CHARS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "fastwc: invalid option -- '%c'\n", *p);
|
fprintf(stderr, "fastwc: invalid option -- '%c'\n", *p);
|
||||||
usage(stderr);
|
usage(stderr);
|
||||||
@@ -290,25 +338,30 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flags == 0)
|
if (flags == 0)
|
||||||
flags = F_LINES | F_WORDS | F_BYTES; /* wc default: -l -w -c */
|
flags = F_LINES | F_WORDS | F_BYTES; /* wc default: -l -w -c */
|
||||||
|
|
||||||
if (flags & F_CHARS)
|
if (flags & F_CHARS)
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
|
|
||||||
nfiles = argc - a;
|
nfiles = argc - a;
|
||||||
if (nfiles == 0) {
|
if (nfiles == 0)
|
||||||
|
{
|
||||||
rows = calloc(1, sizeof *rows);
|
rows = calloc(1, sizeof *rows);
|
||||||
rows[0].ok = 1;
|
rows[0].ok = 1;
|
||||||
count_stream(stdin, &rows[0]);
|
count_stream(stdin, &rows[0]);
|
||||||
if (!rows[0].ok) {
|
if (!rows[0].ok)
|
||||||
|
{
|
||||||
fprintf(stderr, "fastwc: standard input: read error: %s\n",
|
fprintf(stderr, "fastwc: standard input: read error: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
failed = 1;
|
failed = 1;
|
||||||
}
|
}
|
||||||
nfiles = 1;
|
nfiles = 1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
rows = calloc((size_t)nfiles, sizeof *rows);
|
rows = calloc((size_t)nfiles, sizeof *rows);
|
||||||
for (i = 0; i < nfiles; i++) {
|
for (i = 0; i < nfiles; i++)
|
||||||
|
{
|
||||||
rows[i].ok = 1;
|
rows[i].ok = 1;
|
||||||
count_file(argv[a + i], &rows[i]);
|
count_file(argv[a + i], &rows[i]);
|
||||||
if (!rows[i].ok)
|
if (!rows[i].ok)
|
||||||
@@ -320,36 +373,49 @@ int main(int argc, char **argv)
|
|||||||
int wl = 1, ww = 1, wm = 1, wb = 1;
|
int wl = 1, ww = 1, wm = 1, wb = 1;
|
||||||
long long tl = 0, tw = 0, tm = 0, tb = 0;
|
long long tl = 0, tw = 0, tm = 0, tb = 0;
|
||||||
|
|
||||||
for (i = 0; i < nfiles; i++) {
|
for (i = 0; i < nfiles; i++)
|
||||||
|
{
|
||||||
counts_t *r = &rows[i];
|
counts_t *r = &rows[i];
|
||||||
int x;
|
tl += r->lines;
|
||||||
tl += r->lines; tw += r->words; tm += r->chars; tb += r->bytes;
|
tw += r->words;
|
||||||
if ((flags & F_LINES) && (x = col_width(r->lines)) > wl) wl = x;
|
tm += r->chars;
|
||||||
if ((flags & F_WORDS) && (x = col_width(r->words)) > ww) ww = x;
|
tb += r->bytes;
|
||||||
if ((flags & F_CHARS) && (x = col_width(r->chars)) > wm) wm = x;
|
widen(&wl, r->lines, flags & F_LINES);
|
||||||
if ((flags & F_BYTES) && (x = col_width(r->bytes)) > wb) wb = x;
|
widen(&ww, r->words, flags & F_WORDS);
|
||||||
|
widen(&wm, r->chars, flags & F_CHARS);
|
||||||
|
widen(&wb, r->bytes, flags & F_BYTES);
|
||||||
}
|
}
|
||||||
if ((flags & F_LINES) && col_width(tl) > wl) wl = col_width(tl);
|
widen(&wl, tl, flags & F_LINES);
|
||||||
if ((flags & F_WORDS) && col_width(tw) > ww) ww = col_width(tw);
|
widen(&ww, tw, flags & F_WORDS);
|
||||||
if ((flags & F_CHARS) && col_width(tm) > wm) wm = col_width(tm);
|
widen(&wm, tm, flags & F_CHARS);
|
||||||
if ((flags & F_BYTES) && col_width(tb) > wb) wb = col_width(tb);
|
widen(&wb, tb, flags & F_BYTES);
|
||||||
|
|
||||||
for (i = 0; i < nfiles; i++) {
|
for (i = 0; i < nfiles; i++)
|
||||||
|
{
|
||||||
counts_t *r = &rows[i];
|
counts_t *r = &rows[i];
|
||||||
if (flags & F_LINES) printf("%*lld ", wl, r->lines);
|
if (flags & F_LINES)
|
||||||
if (flags & F_WORDS) printf("%*lld ", ww, r->words);
|
printf("%*lld ", wl, r->lines);
|
||||||
if (flags & F_CHARS) printf("%*lld ", wm, r->chars);
|
if (flags & F_WORDS)
|
||||||
if (flags & F_BYTES) printf("%*lld ", wb, r->bytes);
|
printf("%*lld ", ww, r->words);
|
||||||
|
if (flags & F_CHARS)
|
||||||
|
printf("%*lld ", wm, r->chars);
|
||||||
|
if (flags & F_BYTES)
|
||||||
|
printf("%*lld ", wb, r->bytes);
|
||||||
if (argc - a > 0)
|
if (argc - a > 0)
|
||||||
printf("%s", argv[a + i]);
|
printf("%s", argv[a + i]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc - a > 1) {
|
if (argc - a > 1)
|
||||||
if (flags & F_LINES) printf("%*lld ", wl, tl);
|
{
|
||||||
if (flags & F_WORDS) printf("%*lld ", ww, tw);
|
if (flags & F_LINES)
|
||||||
if (flags & F_CHARS) printf("%*lld ", wm, tm);
|
printf("%*lld ", wl, tl);
|
||||||
if (flags & F_BYTES) printf("%*lld ", wb, tb);
|
if (flags & F_WORDS)
|
||||||
|
printf("%*lld ", ww, tw);
|
||||||
|
if (flags & F_CHARS)
|
||||||
|
printf("%*lld ", wm, tm);
|
||||||
|
if (flags & F_BYTES)
|
||||||
|
printf("%*lld ", wb, tb);
|
||||||
printf("total\n");
|
printf("total\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user