radio

radio.ircforever.org
git clone git://git.ircforever.org/radio
Log | Files | Refs | Submodules | README | LICENSE

thread.c (5468B)


      1 #include "thread.h"
      2 
      3 #include "util.h"
      4 
      5 #include <fcntl.h>
      6 #include <limits.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <time.h>
     10 
     11 #define MAX_COLUMN_LEN	78
     12 
     13 enum read_state
     14 {
     15 	HEADER,
     16 	MESSAGE
     17 };
     18 
     19 /*
     20 static void
     21 fprint_tabs(FILE *stream, int n)
     22 {
     23 	int i;
     24 	for (i = 0; i < n; i++)
     25 		fputc('\t', stream);
     26 }
     27 */
     28 
     29 static int
     30 msg_push(struct thread *t, char c)
     31 {
     32 	int	 newcap;
     33 	char	*newmsg;
     34 
     35 	if (t->msglen == t->msgcap) {
     36 		newcap = t->msgcap * 2;
     37 		if ((newmsg = realloc(t->msg, newcap)) == NULL)
     38 			return -1;
     39 		t->msgcap = newcap;
     40 		t->msg = newmsg;
     41 	}
     42 	t->msg[t->msglen++] = c;
     43 	return 0;
     44 }
     45 
     46 int
     47 thread_open(struct thread *t, char *path)
     48 {
     49 	if ((t->stream = fopen(path, "r")) == NULL)
     50 		fatal("%s:", path);
     51 	t->msgcap = 1024;
     52 	t->msg = emalloc(t->msgcap);
     53 	thread_reset(t);
     54 	return 0;
     55 }
     56 
     57 void
     58 thread_reset(struct thread *t)
     59 {
     60 	t->msglen = 0;
     61 	t->depth = -1;
     62 	if (fseek(t->stream, 0, SEEK_SET) == -1)
     63 		fatal("fseek:");
     64 	fscanf(t->stream, "%9d\n", &t->lastid);
     65 	t->lineno = 1;
     66 }
     67 
     68 int
     69 thread_close(struct thread *t)
     70 {
     71 	fclose(t->stream);
     72 	free(t->msg);
     73 	return 0;
     74 }
     75 
     76 int
     77 thread_next(struct thread *t)
     78 {
     79 	char c, lc;	/* current char, last char */
     80 	enum read_state state;
     81 	char *str;
     82 	int depth;
     83 
     84 	state = HEADER;
     85 	t->msglen = 0;
     86 	lc = '\0';
     87 	depth = -1;
     88 
     89 	while ((c = fgetc(t->stream))) {
     90 		if (c == EOF && lc == '\0')
     91 			return EOF;
     92 		if (c == '\n') {
     93 			t->lineno++;
     94 		}
     95 		if (c == '\n' && state == HEADER) {
     96 			t->msg[t->msglen] = '\0';
     97 			for(str = t->msg; *str == '#'; str++)
     98 				depth++;
     99 			if (depth == -1 || depth > t->depth+1)
    100 				goto err;
    101 			if (depth == 0)
    102 				t->pid = 0;
    103 			else
    104 				t->pid = t->depth_array[depth-1];
    105 			t->depth = depth;
    106 			if (sscanf(str,
    107 			    "%9d %31s %4d-%2d-%2d %2d:%2d:%2d %c",
    108 			    &t->id, t->user,
    109 			    &t->time[0], &t->time[1], &t->time[2],
    110 			    &t->time[3], &t->time[4], &t->time[5],
    111 			    &c) != 8)	/* make sure c don't get assigned */
    112 				goto err;
    113 			t->depth_array[t->depth] = t->id;
    114 			t->msglen = 0;
    115 			state = MESSAGE;
    116 			lc = c;
    117 		} else if (c == EOF || (lc == '\n' && c == '#')) {
    118 			if (state != MESSAGE || t->msglen == 0)
    119 				goto err;
    120 			if (c == '#')
    121 				ungetc(c, t->stream);
    122 			t->msg[t->msglen-1] = '\0';
    123 			return 0;
    124 		} else {
    125 			msg_push(t, c);
    126 			lc = c;
    127 		}
    128 	}
    129 err:
    130 	fatal("%d: syntax error", t->lineno);
    131 	return EOF;
    132 }
    133 
    134 static void
    135 thread_print(FILE *stream,
    136     int depth, int id, char *user,
    137     int year, int mon, int day,
    138     int hour, int min, int sec,
    139     char *msg)
    140 {
    141 	int i;
    142 	for (i = 0; i <= depth; i++)
    143 		fputc('#', stream);
    144 	fprintf(stream, "%d %s %04d-%02d-%02d %02d:%02d:%02d\n",
    145 	    id, user,
    146 	    year, mon, day,
    147 	    hour, min, sec);
    148 	fprintf(stream, "%s\n", msg);
    149 }
    150 
    151 int
    152 thread_add(struct thread *t, int pid, char *msg)
    153 {
    154 	FILE		*tmp;
    155 	time_t		 clock;
    156 	struct tm	*tm;
    157 	int		 pdepth = -1;		/* parent depth */
    158 	int		 res, added = 0;
    159 
    160 	if ((tmp = fopen("tmp/tmp.db", "w")) == NULL)
    161 		fatal("%s:", "tmp.db");
    162 	fprintf(tmp, "%d\n", t->lastid+1);
    163 
    164 	time(&clock);
    165 	tm = gmtime(&clock);
    166 	while (1) {
    167 		res = thread_next(t);
    168 		if ((pdepth != -1 && !added &&
    169 		    (res == EOF || t->depth <= pdepth)) ||
    170 		    (res == EOF && pid == 0)) {
    171 			thread_print(tmp, pdepth+1, t->lastid+1, "Anonymous",
    172 			    tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
    173 			    tm->tm_hour,      tm->tm_min,   tm->tm_sec,
    174 			    msg);
    175 			added = 1;
    176 		}
    177 		if (res == EOF)
    178 			break;
    179 		if (pdepth == -1 && t->id == pid)
    180 			pdepth = t->depth;
    181 
    182 		thread_print(tmp, t->depth, t->id, t->user,
    183 		    t->time[0], t->time[1], t->time[2],
    184 		    t->time[3], t->time[4], t->time[5],
    185 		    t->msg);
    186 	}
    187 	fclose(tmp);
    188 	if (pid != 0 && pdepth == -1)
    189 		fatal("failed to find parent id: %d", pid);
    190 
    191 	if (renameat(AT_FDCWD, "./tmp/tmp.db", AT_FDCWD, "./threads/thread.db") == -1)
    192 		fatal("renameat:");
    193 	return 0;
    194 }
    195 
    196 /* int
    197 thread_write_plain(struct thread *t, FILE *stream)
    198 {
    199 	char *s, *last_word;
    200 	int column;
    201 
    202 	fprint_tabs(stream, t->depth);
    203 	fprintf(stream, "* %s %d-%02d-%02d %02d:%02d:%02d\n",
    204 			t->user,
    205 			t->time[0], t->time[1], t->time[2],
    206 			t->time[3], t->time[4], t->time[5]);
    207 
    208 	fprint_tabs(stream, t->depth);
    209 	fputs("| ", stream);
    210 	column = 0;
    211 	last_word = t->msg;
    212 	for (s = t->msg;; s++) {
    213 		if (*s == ' ' || *s == '\n' || *s == '\0') {
    214 			if ((column + s - last_word) > MAX_COLUMN_LEN
    215 			|| (*last_word == '\n')) {
    216 				last_word++;
    217 				fputc('\n', stream);
    218 				fprint_tabs(stream, t->depth);
    219 				fputs("| ", stream);
    220 				column = 0;
    221 			}
    222 			fprintf(stream, "%.*s", (int)(s - last_word), last_word);
    223 			column += s - last_word;
    224 			last_word = s;
    225 
    226 			if (*s == '\0')
    227 				break;
    228 		}
    229 	}
    230 	fputs("\n\n", stream);
    231 	return 0;
    232 } */
    233 
    234 int
    235 thread_write_html(struct thread *t, FILE *stream, int depth)
    236 {
    237 	char *s;
    238 
    239 	fprintf(stream, "<div id=\"%d\" class=\"thread\" style=\"margin-left:%d%%;\">\n",
    240 			t->id, depth * 2);
    241 
    242 	fprintf(stream, "<p class=\"thread_header\">");
    243 	fprintf(stream, "%s %d-%02d-%02d %02d:%02d:%02d | ", t->user,
    244 	    t->time[0], t->time[1], t->time[2],
    245 	    t->time[3], t->time[4], t->time[5]);
    246 	if (t->pid != 0) {
    247 		if (depth == 0)
    248 			fprintf(stream, "<a href=\"%d\">parent</a> | ", t->pid);
    249 		else
    250 			fprintf(stream, "<a href=\"#%d\">parent</a> | ", t->pid);
    251 	}
    252 	fprintf(stream, "<a href=\"#%d\">link</a> | ", t->id);
    253 	fprintf(stream, "<a href=\"%d\">reply</a>", t->id);
    254 	fprintf(stream, "</p>\n");
    255 
    256 	fputs("<p>", stream);
    257 	for (s = t->msg; *s != '\0'; s++) {
    258 		if (*s == '\n') {
    259 			fputs("<br>", stream);
    260 		}
    261 		fputc(*s, stream);
    262 	}
    263 	fputs("</p>\n", stream);
    264 	fputs("</div>\n", stream);
    265 	return 0;
    266 }