1 /* SPDX-License-Identifier: GPL-2.0 */
20 #include "tfortune.lsg.h"
22 #define TF_SEP "---- "
34 static void mmap_file(const char *path, struct tf_map *map)
44 map->len = lseek(fd, 0, SEEK_END);
45 if (map->len == (off_t)-1) {
49 map->map = mmap(NULL, map->len, PROT_READ, MAP_PRIVATE, fd, 0);
50 if (map->map == MAP_FAILED) {
58 static bool tag_given(const char *tag, const char *tags, size_t sz)
61 char *p, *str = strndup(tags, sz);
66 //fprintf(stderr, "sz: %zu, compare: %s <-> %.*s\n", sz, tag, (int) sz, p);
67 if (strcmp(p, tag) == 0) {
71 p = strtok(NULL, ",");
77 static bool tags_ok(const char *tags, size_t sz, struct lls_parse_result *lpr)
80 const struct lls_opt_result *r;
83 r = lls_opt_result(LSG_TFORTUNE_TFORTUNE_OPT_ACCEPT, lpr);
84 given = lls_opt_given(r);
87 /* check if any of the given accept tags is set */
88 for (n = 0; n < given; n++) {
89 arg = lls_string_val(n, r);
90 if (tag_given(arg, tags, sz))
93 return false; /* accept tag(s) given, but none was set */
95 /* check if none of the given reject tags is set */
96 r = lls_opt_result(LSG_TFORTUNE_TFORTUNE_OPT_REJECT, lpr);
97 given = lls_opt_given(r);
98 for (n = 0; n < given; n++) {
99 arg = lls_string_val(n, r);
100 if (tag_given(arg, tags, sz))
106 static void print_tags(const char *tags, size_t sz, FILE *f)
108 char *p, *str = strndup(tags, sz);
111 p = strtok(str, ",");
113 fprintf(f, "%s\n", p);
114 p = strtok(NULL, ",");
119 static void print_random_cookie(const struct tf_cookie *cookies,
120 unsigned num_cookies, const struct tf_map *maps)
123 const struct tf_cookie *cookie;
126 if (num_cookies == 0) {
127 fprintf(stderr, "no matching cookie\n");
130 gettimeofday(&tv, NULL);
131 srandom((unsigned)tv.tv_usec);
132 r = ((num_cookies + 0.0) * (random() / (RAND_MAX + 1.0)));
133 cookie = cookies + r;
134 assert(r < num_cookies);
135 printf("%.*s", (int)cookie->len,
136 (char *)maps[cookie->input_num].map + cookie->offset);
139 static void make_cookies(struct tf_map *maps, struct lls_parse_result *lpr)
141 struct tf_cookie *cookies = NULL;
142 unsigned n, cookies_size = 0, num_cookies = 0, num_inputs;
143 size_t sep_len = strlen(TF_SEP);
144 const struct lls_opt_result *r_s;
147 r_s = lls_opt_result(LSG_TFORTUNE_TFORTUNE_OPT_STATISTICS, lpr);
148 if (lls_opt_given(r_s)) {
149 f = popen("sort | uniq -c | sort -n", "w");
152 num_inputs = lls_num_inputs(lpr);
153 for (n = 0; n < num_inputs; n++) {
154 struct tf_map *m = maps + n;
155 const char *start = m->map, *end = m->map + m->len;
156 const char *buf = start, *cookie_start = start;
159 struct tf_cookie *cookie;
160 const char *p, *cr, *tags;
163 cr = memchr(buf, '\n', end - buf);
169 if (p + sep_len >= end)
171 if (strncmp(p, TF_SEP, sep_len) != 0) {
176 cr = memchr(tags, '\n', end - tags);
181 if (!tags_ok(tags, sz, lpr)) {
189 if (lls_opt_given(r_s)) {
190 print_tags(tags, sz, f);
196 if (num_cookies > cookies_size) {
197 cookies_size = 2 * cookies_size + 1;
198 cookies = realloc(cookies,
199 cookies_size * sizeof(*cookies));
202 cookie = cookies + num_cookies - 1;
203 cookie->input_num = n;
204 cookie->offset = cookie_start - start;
205 cookie->len = p - cookie_start;
212 if (!lls_opt_given(r_s))
213 print_random_cookie(cookies, num_cookies, maps);
215 printf("num cookies: %d\n", num_cookies);
219 int main(int argc, char **argv)
222 struct lls_parse_result *lpr;
225 unsigned n, num_inputs;
226 const struct lls_command *cmd = lls_cmd(0, tfortune_suite);
228 ret = lls_parse(argc, argv, cmd, &lpr, &errctx);
230 fprintf(stderr, "%s: %s\n", errctx? errctx : "",
235 if (lls_num_inputs(lpr) == 0) {
236 char *help = lls_short_help(cmd);
237 fprintf(stderr, "%s\n", help);
242 num_inputs = lls_num_inputs(lpr);
243 maps = xmalloc(num_inputs * sizeof(*maps));
244 for (n = 0; n < num_inputs; n++)
245 mmap_file(lls_input(n, lpr), maps + n);
246 make_cookies(maps, lpr);
250 lls_free_parse_result(lpr, cmd);