hysteria

ii wrapper script
git clone git://git.2f30.org/hysteria
Log | Files | Refs | README | LICENSE

hysteria-highlight.c (4720B)


      1 /*
      2  * highlight chat for ii similar in style to irssi.
      3  *
      4  * supports:
      5  * - highlight own nick, words + beep (can set urgent hint).
      6  * - highlight own messages.
      7  * - highlight urls.
      8  * - highlight server messages.
      9  * - align nicknames.
     10  * - ignore words.
     11  * - don't print date-prefix (YYYY-mm-dd).
     12  * - convert unix timestamp prefix to localtime.
     13  */
     14 
     15 #include <errno.h>
     16 #include <regex.h>
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <sys/types.h>
     21 #include <time.h>
     22 
     23 #include "config.h"
     24 #include "arg.h"
     25 char *argv0;
     26 #include "util.h"
     27 
     28 static char    timebuf[TIMEFORMAT_BUFSIZ] = "";
     29 static regex_t nick, nickalign, server, timestamp, ignore, url, word;
     30 static regex_t unixtimestamp;
     31 
     32 static void
     33 printalign(const char *s, size_t len, size_t maxlen)
     34 {
     35 	size_t i;
     36 
     37 	if(len < maxlen) {
     38 		for(i = 0; i < maxlen - len; i++)
     39 			putchar(' ');
     40 	}
     41 	for(i = 0; i < len && i < maxlen; i++)
     42 		putchar(*s++);
     43 }
     44 
     45 static int
     46 eregcomp(regex_t *preg, const char *regex, int cflags)
     47 {
     48 	char errbuf[BUFSIZ] = "";
     49 	int r;
     50 
     51 	if((r = regcomp(preg, regex, cflags)) == 0)
     52 		return r;
     53 
     54 	regerror(r, preg, errbuf, sizeof(errbuf));
     55 	fprintf(stderr, "%s: invalid regex: %s\n", argv0, errbuf);
     56 	exit(1);
     57 	return r;
     58 }
     59 
     60 static void
     61 usage(void)
     62 {
     63 	fprintf(stderr, "usage: %s [-n nick] [-w word ] [-i ignore]\n", argv0);
     64 	exit(1);
     65 }
     66 
     67 int
     68 main(int argc, char *argv[])
     69 {
     70 	/* buffer: should be atleast 512 bytes (IRC RFC) + datetime prefix,
     71 	 * assumes line length is lower than sizeof(buffer). */
     72 	char buffer[1024];
     73 	regmatch_t match, matches[3];
     74 	regoff_t len;
     75 	const char *p;
     76 	struct tm tm;
     77 	time_t t;
     78 	int hasmatch, ret;
     79 
     80 	ARGBEGIN {
     81 	case 'i':
     82 		regexignore = EARGF(usage());
     83 		break;
     84 	case 'n':
     85 		regexnick = EARGF(usage());
     86 		break;
     87 	case 'w':
     88 		regexword = EARGF(usage());
     89 		break;
     90 	default:
     91 		usage();
     92 	} ARGEND;
     93 
     94 	if(argc > 0)
     95 		usage();
     96 
     97 	/* compile regex */
     98 	eregcomp(&nick, regexnick, REG_EXTENDED | REG_ICASE);
     99 	eregcomp(&nickalign, regexnickalign, REG_EXTENDED);
    100 	eregcomp(&server, regexserver, REG_EXTENDED);
    101 	eregcomp(&timestamp, regextimestamp, REG_EXTENDED);
    102 	eregcomp(&unixtimestamp, regexunixtimestamp, REG_EXTENDED);
    103 	eregcomp(&ignore, regexignore, REG_EXTENDED | REG_ICASE);
    104 	eregcomp(&url, regexurl, REG_EXTENDED | REG_ICASE);
    105 	eregcomp(&word, regexword, REG_EXTENDED | REG_ICASE);
    106 
    107 	while(fgets(buffer, sizeof(buffer), stdin)) {
    108 		p = buffer;
    109 
    110 		/* convert unix timestamp to localtime */
    111 		if((ret = regexec(&unixtimestamp, p, 1, &match, 0)) == 0) {
    112 			errno = 0;
    113 			t = (time_t)strtol(p, NULL, 10);
    114 			if(errno != 0)
    115 				t = 0;
    116 			memset(&tm, 0, sizeof(tm));
    117 			if(localtime_r(&t, &tm) != NULL &&
    118 			   (strftime(timebuf, sizeof(timebuf), timeformat, &tm) > 0))
    119 				fputs(timebuf, stdout);
    120 			p += match.rm_eo - match.rm_so;
    121 		} else if((ret = regexec(&timestamp, p, 1, &match, 0)) == 0) {
    122 			/* skip date part (YYY-mm-dd) of timestamp */
    123 			p += match.rm_eo - match.rm_so;
    124 		}
    125 
    126 		/* highlight / color server messages */
    127 		if((ret = regexec(&server, p, 1, &match, 0)) == 0) {
    128 			fputs(servercolor, stdout);
    129 			fputs(p, stdout);
    130 			fputs(reset, stdout);
    131 			fflush(stdout);
    132 			continue;
    133 		}
    134 
    135 		/* ignore on match */
    136 		if((ret = regexec(&ignore, p, 1, &match, 0)) == 0)
    137 			continue;
    138 
    139 		/* align nicknames */
    140 		if((ret = regexec(&nickalign, p, 2, matches, 0)) == 0)
    141 		{
    142 			fwrite(p, 1, matches[1].rm_so, stdout);
    143 			putchar('@');
    144 			p += matches[1].rm_so;
    145 			len = matches[1].rm_eo - matches[1].rm_so;
    146 			/* own nick ?: color nickname part white */
    147 			if((ret = regexec(&nick, p, 1, &match, 0)) == 0 &&
    148 				match.rm_so == 0 && match.rm_eo == len)
    149 			{
    150 				fputs(nickcolor, stdout);
    151 				printalign(p, len, 10);
    152 				fputs(reset, stdout);
    153 			} else {
    154 				printalign(p, len, 10);
    155 			}
    156 			if(len > 0)
    157 				p += len;
    158 		}
    159 
    160 		hasmatch = 1;
    161 		while(hasmatch) {
    162 			hasmatch = 0;
    163 			/* highlight word */
    164 			if((ret = regexec(&word, p, 1, &match, 0)) == 0) {
    165 				fwrite(p, 1, match.rm_so, stdout);
    166 				fputs(wordcolor, stdout);
    167 				p += match.rm_so;
    168 				fwrite(p, 1, match.rm_eo - match.rm_so, stdout);
    169 				fputs(reset, stdout);
    170 				p += match.rm_eo - match.rm_so;
    171 				/* beep, can be set in your terminal to set urgent hint */
    172 				putchar('\a');
    173 				hasmatch = 1;
    174 			}
    175 			/* highlight url */
    176 			if((ret = regexec(&url, p, 1, &match, 0)) == 0) {
    177 				fwrite(p, 1, match.rm_so, stdout);
    178 				fputs(urlcolor, stdout);
    179 				p += match.rm_so;
    180 				fwrite(p, 1, match.rm_eo - match.rm_so, stdout);
    181 				fputs(reset, stdout);
    182 				p += match.rm_eo - match.rm_so;
    183 				hasmatch = 1;
    184 			}
    185 		}
    186 		fputs(p, stdout); /* rest */
    187 		fflush(stdout);
    188 	}
    189 
    190 	/* free regex */
    191 	regfree(&word);
    192 	regfree(&nick);
    193 	regfree(&nickalign);
    194 	regfree(&server);
    195 	regfree(&timestamp);
    196 	regfree(&unixtimestamp);
    197 	regfree(&ignore);
    198 	regfree(&url);
    199 
    200 	return 0;
    201 }