insomnia

A frontend for the hii IRC client

git clone https://git.8pit.net/insomnia.git

  1#include <err.h>
  2#include <regex.h>
  3#include <string.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <unistd.h>
  7
  8#include <sys/types.h>
  9
 10#define REGEXPR "^([0-9]+) \\(([^)]+)\\) (.*)$"
 11#define REGSUBS 4 /* 3 subexpressions +1 for entire expression */
 12
 13#define LEN(X) (sizeof(X) / sizeof(X[0]))
 14#define MATCHLEN(X) ((int)(X->rm_eo - X->rm_so))
 15
 16enum {
 17	CECHO = 37, /* white */
 18	CHIGH = 31, /* red */
 19
 20	FBOLD = 1,  /* bold font */
 21	FNORM = 10, /* normal font */
 22};
 23
 24/* See https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit */
 25static int colors[] = {
 26	31, 32, 33, 34, 35, 36,
 27	91, 92, 93, 94, 95, 96,
 28};
 29
 30static short eflag; /* use custom format for own nick */
 31static short mflag; /* highlight mentions */
 32
 33static int
 34gencolor(char *str, size_t len)
 35{
 36	size_t i;
 37	int code;
 38
 39	for (code = 0, i = 0; i < len; i++)
 40		code += str[i];
 41
 42	return colors[code % LEN(colors)];
 43}
 44
 45static void
 46printline(char *line, regmatch_t *time, regmatch_t *nick, regmatch_t *text)
 47{
 48	int color, attribute;
 49	char *suffix, *timestr, *nickstr, *textstr;
 50
 51	/* in bounds due to regex */
 52	suffix = &line[strlen(line) - 2];
 53
 54	timestr = &line[time->rm_so];
 55	nickstr = &line[nick->rm_so];
 56	textstr = &line[text->rm_so];
 57
 58	if (eflag && *suffix == '\006') { /* send by own client */
 59		color = CECHO;
 60		attribute = FBOLD;
 61	} else {
 62		color = gencolor(nickstr, MATCHLEN(nick));
 63		attribute = FNORM;
 64	}
 65
 66	printf("%.*s (\033[%d;%dm%.*s\033[0m) ",
 67	       MATCHLEN(time), timestr,
 68	       color, attribute,
 69	       MATCHLEN(nick), nickstr);
 70
 71	if (mflag && *suffix == '\007') /* text contains mention */
 72		printf("\033[%dm%.*s\033[0m%s", CHIGH,
 73		       (int)(suffix - textstr), textstr, suffix);
 74	else
 75		printf("%s", textstr);
 76}
 77
 78int
 79main(int argc, char **argv)
 80{
 81	int opt;
 82	regex_t reg;
 83	regmatch_t matches[REGSUBS];
 84	static char *line;
 85	static size_t len;
 86
 87#ifdef __OpenBSD__
 88	if (pledge("stdio", NULL) == -1)
 89		err(EXIT_FAILURE, "pledge failed");
 90#endif
 91
 92	while ((opt = getopt(argc, argv, "em")) != -1) {
 93		switch (opt) {
 94		case 'e':
 95			eflag = 1;
 96			break;
 97		case 'm':
 98			mflag = 1;
 99			break;
100		}
101	}
102
103	if (regcomp(&reg, REGEXPR, REG_EXTENDED))
104		errx(EXIT_FAILURE, "regcomp failed");
105
106	while (getline(&line, &len, stdin) != -1) {
107		if (regexec(&reg, line, REGSUBS, matches, 0))
108			printf("%s", line);
109		else
110			printline(line, &matches[1], &matches[2], &matches[3]);
111
112		fflush(stdout);
113	}
114	if (ferror(stdin))
115		errx(EXIT_FAILURE, "ferror failed");
116
117	return EXIT_SUCCESS;
118}