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(×tamp, 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(×tamp, 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(×tamp); 196 regfree(&unixtimestamp); 197 regfree(&ignore); 198 regfree(&url); 199 200 return 0; 201 }