MULE 0.0.1
Multi-Use Library Essentials
Loading...
Searching...
No Matches
main.c

A word counter built on the single header, dist/mule.h. The file lives in a Str inside an Arena, and every line and word is a StrView into it.

/* A small word counter that shows MULE in use.
*
* build/debug/main [file] reads stdin when no file is given
*
* The file is read into a Str that lives in an arena. Lines and words are
* StrViews into that one buffer, so counting allocates nothing more, and one
* arena_free releases it all.
*
* It uses the single-header distribution, dist/mule.h, the way any project
* would. */
#define MULE_IMPLEMENTATION
#include "mule.h"
#include <stdio.h>
#include <stdlib.h>
static void print_count(bool color, const char *label, size_t n) {
if (color)
printf(LOG_GREEN "%-8s" LOG_RESET " %zu\n", label, n);
else
printf("%-8s %zu\n", label, n);
}
int main(int argc, char **argv) {
if (argc > 2) {
fprintf(stderr, "usage: %s [file]\n", argv[0]);
return EXIT_FAILURE;
}
const char *name = argc == 2 ? argv[1] : "stdin";
FILE *f = argc == 2 ? fopen(name, "rb") : stdin;
if (f == NULL) {
perror(name);
return EXIT_FAILURE;
}
Arena arena = { 0 };
Str text = { .alloc = arena_allocator(&arena) };
bool ok = str_append_file(&text, f);
bool read_error = ferror(f);
if (f != stdin) fclose(f);
if (!ok) {
fprintf(stderr, "%s: %s\n", name,
read_error ? "read error" : "out of memory");
arena_free(&arena);
return EXIT_FAILURE;
}
size_t lines = 0, words = 0, longest = 0;
StrView rest = str_view(&text), line, word;
while (sv_split_next(&rest, SV("\n"), &line)) {
lines++;
if (sv_ends_with(line, SV("\r")))
line = sv_slice(line, 0, line.len - 1);
if (line.len > longest) longest = line.len;
while (sv_token_next(&line, SV(" \t\v\f\r"), &word)) words++;
}
bool color = log_color_enabled(stdout);
print_count(color, "lines", lines);
print_count(color, "words", words);
print_count(color, "bytes", text.len);
print_count(color, "longest", longest);
arena_free(&arena);
return EXIT_SUCCESS;
}
#define LOG_GREEN
Green text.
Definition log.h:98
#define LOG_RESET
Back to the terminal's default style.
Definition log.h:100
bool log_color_enabled(FILE *f)
True when colour escapes written to f will render as colour.
Definition log.c:37
const Allocator * arena_allocator(Arena *a)
An Allocator that draws from a.
Definition mem.c:95
void arena_free(Arena *a)
Release every block.
Definition mem.c:112
Bump allocator over a chain of blocks.
Definition mem.h:86
size_t len
Bytes of content, excluding the terminator.
Definition str.h:66
#define SV(lit)
View of a string literal, with its length computed at compile time.
Definition str.h:80
StrView str_view(const Str *s)
Borrow the whole of s.
Definition str.c:212
bool sv_token_next(StrView *rest, StrView delims, StrView *token)
strtok without the mutation: skip delims, then cut the next run of other bytes.
Definition str.c:306
bool str_append_file(Str *s, FILE *f)
Append everything left to read from f.
Definition str.c:156
bool sv_ends_with(StrView v, StrView suffix)
True when v ends with suffix.
Definition str.c:263
bool sv_split_next(StrView *rest, StrView sep, StrView *piece)
Cut the piece before sep off rest.
Definition str.c:286
StrView sv_slice(StrView v, size_t from, size_t to)
Bytes from up to but not including to.
Definition str.c:268
Owned, growable byte string.
Definition str.h:64
Non-owning view of bytes; handy for passing slices and literals around.
Definition str.h:72