int main(int argc, char **argv) { bool gen_i2s, gen_i2s_transtab, gen_s2i, uppercase, lowercase; char *prefix; size_t i; /* This is required by gen_tables.h */ assert(NUM_VALUES <= (SSIZE_MAX / 2 + 1)); /* To make sure GT_ISUPPER and GT_ISLOWER work. */ assert('Z' == 'A' + 25 && 'z' == 'a' + 25); gen_i2s = false; gen_i2s_transtab = false; gen_s2i = false; uppercase = false; lowercase = false; prefix = NULL; assert (argc > 1); for (i = 1; i < (size_t)argc; i++) { if (strcmp(argv[i], "--i2s") == 0) gen_i2s = true; else if (strcmp(argv[i], "--i2s-transtab") == 0) gen_i2s_transtab = true; else if (strcmp(argv[i], "--s2i") == 0) gen_s2i = true; else if (strcmp(argv[i], "--uppercase") == 0) uppercase = true; else if (strcmp(argv[i], "--lowercase") == 0) lowercase = true; else if (strcmp(argv[i], "--duplicate-ints") == 0) allow_duplicate_ints = true; else { assert(*argv[i] != '-'); assert(prefix == NULL); prefix = argv[i]; } } assert(prefix != NULL); assert(!(uppercase && lowercase)); printf("/* This is a generated file, see Makefile.am for its " "inputs. */\n"); for (i = 0; i < NUM_VALUES; i++) values[i].orig_index = i; qsort(values, NUM_VALUES, sizeof(*values), cmp_value_strings); /* FIXME? if (gen_s2i), sort the strings in some other order (e.g. "first 4 nodes in BFS of the bsearch tree first") to use the cache better. */ /* FIXME? If the only thing generated is a transtab, keep the strings in the original order to use the cache better. */ output_strings(prefix); if (gen_s2i) output_s2i(prefix, uppercase, lowercase); if (gen_i2s) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_vals); output_i2s(prefix); } if (gen_i2s_transtab) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_orig_index); output_i2s_transtab(prefix); } return EXIT_SUCCESS; }
int html_day_index(const char *list, unsigned int y, unsigned int m, unsigned int d) { unsigned int aday; off_t idx_offset; off_t size, size_n; int fd, error, got; idx_msgnum_t mx[2]; /* today, next day */ struct buffer dst; struct idx_message *mp; int prev; /* have prev message = 1 */ int count; /* how many messages in this month */ int next; /* flag & index to next message */ if (y < MIN_YEAR || y > MAX_YEAR || m < 1 || m > 12 || d < 1 || d > 31) return html_error("Invalid date"); aday = YMD2ADAY(y - MIN_YEAR, m, d); fd = idx_open(list); if (fd < 0) return html_error(errno == ENOENT ? "No such mailing list" : NULL); /* read two consecutive aday entries * will need them to determine message count for this day */ error = !idx_read_aday_ok(fd, aday, &mx, sizeof(mx)); if (error || mx[0] < 1 || mx[0] >= MAX_MAILBOX_MESSAGES) { idx_close(fd); return html_error((error || mx[0] > 0) ? NULL : "No messages" " for this day"); } if (mx[1] > 0) count = mx[1] - mx[0]; else count = -mx[1]; size = count * sizeof(struct idx_message); idx_offset = IDX2MSG(mx[0] - 1); if (mx[0] > 1) { /* read one more entry for Prev day quick link */ size += sizeof(struct idx_message); idx_offset -= sizeof(struct idx_message); prev = 1; } else { prev = 0; } /* read one more entry for Next day quick link */ size_n = size + sizeof(struct idx_message); if (!(mp = malloc(size_n)) || (got = idx_read(fd, idx_offset, mp, size_n)) == -1 || (got != size && got != size_n)) { idx_close(fd); free(mp); return html_error("Index error"); } next = (got == size_n) ? count + prev : 0; if (idx_close(fd) || error || buffer_init(&dst, 0)) { free(mp); return html_error(NULL); } buffer_appends(&dst, "\n"); if (html_flags & HTML_HEADER) { buffer_appends(&dst, "<title>"); buffer_appends_html(&dst, list); buffer_appendf(&dst, " mailing list - %u/%02u/%02u</title>\n", y, m, d); } if (html_flags & HTML_BODY) { int i; if (prev) { buffer_appends(&dst, "<a href=\""); buffer_appendf(&dst, "../../../%u/%02u/%02u/\">[<prev day]</a> ", MIN_YEAR + mp[0].y, mp[0].m, mp[0].d); } if (next) { buffer_appends(&dst, "<a href=\""); buffer_appendf(&dst, "../../../%u/%02u/%02u/\">[next day>]</a> ", MIN_YEAR + mp[next].y, mp[next].m, mp[next].d); } buffer_appends(&dst, "<a href=\"..\">[month]</a>" " <a href=\"../..\">[year]</a>" " <a href=\"../../..\">[list]</a>\n"); buffer_appends(&dst, "<p><h2>"); buffer_appends_html(&dst, list); buffer_appendf(&dst, " mailing list - %u/%02u/%02u</h2>\n", y, m, d); if (count) buffer_appends(&dst, "<ul>\n"); for (i = 0; i < count; i++) { struct idx_message *msg = mp + i + prev; buffer_appendf(&dst, "<li><a href=\"%u\">", i + 1); output_strings(&dst, msg, 1); buffer_appends(&dst, "\n"); } if (count) buffer_appends(&dst, "</ul>\n"); buffer_appendf(&dst, "<p>%u message%s\n", count, count == 1 ? "" : "s"); } free(mp); return html_send(&dst); }
int html_month_index(const char *list, unsigned int y, unsigned int m) { unsigned int d, n, aday, dp; int fd; idx_msgnum_t mn[32], mp, count, total; struct buffer dst; int first; /* first message of this month */ off_t size, size_n; struct idx_message *msgp = NULL, *msg = NULL; int prev = 0, next = 0; if (y < MIN_YEAR || y > MAX_YEAR || m < 1 || m > 12) return html_error("Invalid date"); aday = ((y - MIN_YEAR) * 12 + (m - 1)) * 31; fd = idx_open(list); if (fd < 0) return html_error(errno == ENOENT ? "No such mailing list" : NULL); if (!idx_read_aday_ok(fd, aday, mn, sizeof(mn))) { idx_close(fd); return html_error("Index error"); } /* quickly calculate how many messages we have in this month */ total = 0; first = 0; mp = mn[0]; for (d = 1; d <= 31; d++) { if (!mn[d]) continue; if (mp > 0) { /* Remember index of first message */ if (first == 0) first = mp; count = (mn[d] > 0) ? mn[d] - mp : -mn[d]; if (count <= 0) { buffer_free(&dst); idx_close(fd); return html_error(NULL); } total += count; } mp = mn[d]; } /* have messages, allocate and read them */ if (total && first) { off_t got; off_t idx_offset; first--; size = total * sizeof(struct idx_message); idx_offset = IDX2MSG(first); /* we need to read prev and next messages too */ if (first) { size += sizeof(struct idx_message); idx_offset -= sizeof(struct idx_message); prev = 1; } size_n = size + sizeof(struct idx_message); if (!(msgp = malloc(size_n)) || (got = idx_read(fd, idx_offset, msgp, size_n)) == -1 || (got != size && got != size_n)) { idx_close(fd); free(msgp); return html_error("Index error"); } msg = msgp + prev; next = (got == size_n) ? total + prev : 0; } if (idx_close(fd) || buffer_init(&dst, 0)) { free(msgp); return html_error(NULL); } buffer_appends(&dst, "\n"); if (html_flags & HTML_HEADER) { buffer_appends(&dst, "<title>"); buffer_appends_html(&dst, list); buffer_appendf(&dst, " mailing list - %u/%02u</title>\n", y, m); } if (html_flags & HTML_BODY) { if (prev) { buffer_appends(&dst, "<a href=\""); buffer_appendf(&dst, "../../%u/%02u/\">[<prev month]</a> ", MIN_YEAR + msgp[0].y, msgp[0].m); } if (next) { buffer_appends(&dst, "<a href=\""); buffer_appendf(&dst, "../../%u/%02u/\">[next month>]</a> ", MIN_YEAR + msgp[next].y, msgp[next].m); } buffer_appends(&dst, "<a href=\"..\">[year]</a>" " <a href=\"../..\">[list]</a>\n"); buffer_appends(&dst, "<p><h2>"); buffer_appends_html(&dst, list); buffer_appendf(&dst, " mailing list - %u/%02u</h2>\n", y, m); if (!total || !msg) { buffer_free(&dst); free(msgp); return html_error("No messages for this month"); } html_output_month_cal(&dst, mn, y, m, L_DAILY); total = 0; dp = 0; mp = mn[0]; for (d = 1; d <= 31; d++) { if (!mn[d]) continue; if (mp > 0) { if (mn[d] > 0) count = mn[d] - mp; else count = -mn[d]; if (count <= 0) { buffer_free(&dst); free(msgp); return html_error(NULL); } if (!total) buffer_appends(&dst, "<p>Messages by day:\n<p>\n"); total += count; buffer_appendf(&dst, "<b>%s %u</b> " "(<a href=\"%02u/\">%u message%s</a>)<br>\n" "<ul>\n", month_name[m - 1], dp + 1, dp + 1, count, count == 1 ? "" : "s"); int maxn = count; if (count >= MAX_SHORT_MSG_LIST) maxn = MAX_SHORT_MSG_LIST; if (count > MAX_SHORT_MSG_LIST) maxn--; for (n = 1; n <= maxn; n++) { buffer_appendf(&dst, "<li><a href=\"%02u/%u\">", dp + 1, n); output_strings(&dst, msg++, 1); buffer_appends(&dst, "\n"); } msg += count - maxn; if (count > MAX_SHORT_MSG_LIST) buffer_appendf(&dst, "<li><a href=\"%02u/\">%u more messages</a>\n", d, count - maxn); buffer_appends(&dst, "</ul>\n"); } mp = mn[d]; dp = d; } if (total) buffer_appendf(&dst, "<p>%u message%s\n", total, total == 1 ? "" : "s"); else buffer_appends(&dst, "<p>No messages\n"); } free(msgp); return html_send(&dst); }
int html_year_index(const char *list, unsigned int y) { unsigned int min_y, max_y, m, d, aday, rday; int fd; idx_msgnum_t *mn, count; size_t mn_size; struct buffer dst; aday = 0; mn_size = (N_ADAY + 1) * sizeof(idx_msgnum_t); min_y = MIN_YEAR; max_y = MAX_YEAR; if (y) { if (y < min_y || y > max_y) return html_error("Invalid date"); aday = (y - min_y) * (12 * 31); mn_size = (12 * 31 + 1) * sizeof(idx_msgnum_t); min_y = max_y = y; } fd = idx_open(list); if (fd < 0) return html_error(errno == ENOENT ? "No such mailing list" : NULL); if (!(mn = malloc(mn_size)) || !idx_read_aday_ok(fd, aday, mn, mn_size)) { idx_close(fd); free(mn); return html_error(NULL); } /* find first and next index for Prev and Next year links */ int first = 0; int lastn = 0; rday = YMD2ADAY(min_y - MIN_YEAR, 1, 1) - aday; unsigned int eday = YMD2ADAY(max_y - MIN_YEAR + 1, 1, 1) - aday; int sanity = 0; for (; rday < eday; rday++) { if (mn[rday] > 0) { if (!first) first = mn[rday]; if (mn[rday + 1] <= 0) lastn = mn[rday] + -mn[rday + 1]; else lastn = mn[rday + 1]; /* sanity check of index */ if (lastn <= mn[rday] || ((mn[rday] != sanity) && sanity)) { buffer_free(&dst); free(mn); return html_error("Index corrupt"); } sanity = lastn; } } int prev = 0; int next = 0; if (first || lastn) { struct idx_message msg; off_t size = sizeof(struct idx_message); if (first > 1) { if (!idx_read_msg_ok(fd, first - 2, &msg, size)) { free(mn); return html_error("Index error"); } prev = MIN_YEAR + msg.y; } if (lastn > 1) { if (idx_read_msg_ok(fd, lastn, &msg, size)) next = MIN_YEAR + msg.y; } } /* read Recent messages */ struct idx_message *msg = NULL; int recent_count = 0; int i; if (min_y != max_y && lastn > 1) { int recent_offset = 0; recent_count = MAX_RECENT_MSG_LIST; if ((lastn - 1) < recent_count) recent_count = lastn - 1; size_t size = recent_count * sizeof(struct idx_message); recent_offset = lastn - recent_count; if (!(msg = malloc(size)) || !idx_read_msg_ok(fd, recent_offset - 1, msg, size)) recent_count = 0; /* resolve to message number in the day and cache in offset field */ rday = YMD2ADAY(min_y - MIN_YEAR, 1, 1) - aday; i = 0; for (; rday < eday; rday++) { if (mn[rday] > 0 && recent_offset >= mn[rday]) { count = aday_count(&mn[rday]); while (recent_offset < (mn[rday] + count)) { msg[i].offset = recent_offset - mn[rday] + 1; recent_offset++; i++; if (i > recent_count) break; } } } } if (idx_close(fd) || buffer_init(&dst, 0)) { free(msg); free(mn); return html_error(NULL); } buffer_appends(&dst, "\n"); if (html_flags & HTML_HEADER) { buffer_appends(&dst, "<title>"); buffer_appends_html(&dst, list); buffer_appends(&dst, " mailing list"); if (min_y == max_y) buffer_appendf(&dst, " - %u", y); buffer_appends(&dst, "</title>\n"); } if (html_flags & HTML_BODY) { if (prev) buffer_appendf(&dst, "<a href=\"../%u/\">[prev year]</a>\n", prev); if (next) buffer_appendf(&dst, "<a href=\"../%u/\">[next year]</a>\n", next); if (min_y == max_y) buffer_appends(&dst, "<a href=\"..\">[list]</a>\n"); buffer_appends(&dst, "<p><h2>"); buffer_appends_html(&dst, list); buffer_appends(&dst, " mailing list"); if (min_y == max_y) buffer_appendf(&dst, " - %u", y); buffer_appends(&dst, "</h2>\n"); idx_msgnum_t total = 0, monthly_total[12]; /* output short year-o-month index */ int o_header = 0; int o_year = 0; int o_month = -1; for (y = max_y; y >= min_y; y--) { rday = YMD2ADAY(y - MIN_YEAR, 1, 1) - aday; for (m = 1; m <= 12; m++) { monthly_total[m - 1] = 0; for (d = 1; d <= 31; d++, rday++) { if (mn[rday] <= 0) continue; if (mn[rday + 1] > 0) count = mn[rday + 1] - mn[rday]; else count = -mn[rday + 1]; monthly_total[m - 1] += count; } if (!monthly_total[m - 1]) continue; if (!o_header) { buffer_appends(&dst, "\n<table border=0 " "class=cal_brief><tr><th>" "<th>Jan<th>Feb<th>Mar" "<th>Apr<th>May<th>Jun" "<th>Jul<th>Aug<th>Sep" "<th>Oct<th>Nov<th>Dec\n"); o_header++; } if (o_year != y) { if (o_month >= 0) { for (o_month++; o_month <= 12; o_month++) buffer_appends(&dst, "<td> "); } buffer_appendf(&dst, "\n<tr><td>"); if (min_y != max_y) buffer_appendf(&dst, "<a href=\"%u/\">", y); buffer_appendf(&dst, "<b>%4u</b>", y); if (min_y != max_y) buffer_appends(&dst, "</a>"); o_year = y; o_month = 0; } for (o_month++; o_month < m; o_month++) buffer_appends(&dst, "<td> "); buffer_appendf(&dst, "<td><a href=\""); if (min_y != max_y) buffer_appendf(&dst, "%u/", y); buffer_appendf(&dst, "%02u/\">%u</a>", m, monthly_total[m - 1]); o_month = m; total += monthly_total[m - 1]; } } if (o_header) { if (o_year) { for (o_month++; o_month <= 12; o_month++) buffer_appends(&dst, "<td> "); } buffer_appends(&dst, "\n</table>\n"); } /* output Recent messages */ if (msg && recent_count) { buffer_appends(&dst, "<br>Recent messages:<br>\n<ul>\n"); for (i = recent_count - 1; i >= 0; i--) { buffer_appendf(&dst, "<li>%04u/%02u/%02u #%u: <a href=\"%04u/%02u/%02u/%u\">\n", msg[i].y + MIN_YEAR, msg[i].m, msg[i].d, (int)msg[i].offset, msg[i].y + MIN_YEAR, msg[i].m, msg[i].d, (int)msg[i].offset); output_strings(&dst, &msg[i], 1); buffer_appends(&dst, "\n"); } buffer_appends(&dst, "</ul>\n"); } free(msg); msg = NULL; /* output monthly calendars */ if (min_y == max_y) { y = min_y; buffer_appends(&dst, "\n<p>\n<table border=0 class=cal_big>"); for (m = 1; m <= 12; m++) { rday = YMD2ADAY(y - MIN_YEAR, m, 1) - aday; if (m % 3 == 1) { unsigned int n; buffer_appends(&dst, "\n<tr>"); for (n = m; n < m + 3; n++) { if (monthly_total[n - 1]) buffer_appendf(&dst, "<th><a href=\"%02u/\">%s</a>", n, month_name[n - 1]); else buffer_appendf(&dst, "<th>%s", month_name[n - 1]); } buffer_appends(&dst, "\n<tr>"); } buffer_appends(&dst, "<td valign=\"top\">"); html_output_month_cal(&dst, &mn[rday], y, m, L_MONTHLY); } buffer_appends(&dst, "</table>"); } if (total) buffer_appendf(&dst, "<p>%u message%s\n", total, total == 1 ? "" : "s"); else buffer_appends(&dst, "<p>No messages\n"); } /* HTML_BODY */ free(msg); free(mn); return html_send(&dst); }