💾 Archived View for thrig.me › blog › 2023 › 08 › 01 › repcharcount.c captured on 2023-11-14 at 09:11:38.

View Raw

More Information

⬅️ Previous capture (2023-09-08)

-=-=-=-=-=-=-

// repcharcount - counts repeats of the same character

#include <sys/types.h>

#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <getopt.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#define BUFSIZE 8192

void emit_help(void);
void report(unsigned long count, int c);

int
main(int argc, char *argv[])
{
	char buf[BUFSIZE], *fname;
	int ch, fd, previous;
	ssize_t amount;
	unsigned long count = 1;

#ifdef __OpenBSD__
	if (pledge("rpath stdio", NULL) == -1) err(1, "pledge failed");
#endif

	setlocale(LC_ALL, "C");

	while ((ch = getopt(argc, argv, "h?")) != -1) {
		switch (ch) {
		case 'h':
		case '?':
		default:
			emit_help();
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0 || (argc == 1 && strncmp(*argv, "-", (size_t) 2) == 0)) {
		fd    = STDIN_FILENO;
		fname = "-";
	} else {
		if ((fd = open(*argv, O_RDONLY)) == -1)
			err(EX_IOERR, "could not open '%s'", *argv);
		fname = *argv;
	}

#ifdef __OpenBSD__
	if (pledge("stdio", NULL) == -1) err(1, "pledge failed");
#endif

	if ((amount = read(fd, buf, 1)) != 1)
		err(EX_IOERR, "read() on %s failed", fname);
	previous = buf[0];

	while (1) {
		amount = read(fd, buf, BUFSIZE);
		if (amount > 0) {
			for (ssize_t i = 0; i < amount; i++) {
				if (buf[i] != previous) {
					report(count, previous);
					previous = buf[i];
					count    = 0;
				}
				count++;
			}
		} else if (amount == 0) { // EOF
			break;
		} else if (amount == -1) {
			err(EX_IOERR, "read() on %s failed", fname);
		} else {
			errx(EX_IOERR, "unexpected read() on %s: %ld", fname,
			     amount);
		}
	}
	if (count > 0) report(count, previous);

	exit(EXIT_SUCCESS);
}

inline void
emit_help(void)
{
	fputs("Usage: repcharcount [file|-]\n", stderr);
	exit(EX_USAGE);
}

inline void
report(unsigned long count, int c)
{
	if (isprint(c) && !isspace(c)) {
		printf("%lu %c\n", count, c);
	} else {
		printf("%lu 0x%02X\n", count, c);
	}
}