#include #include #include #include #include "util.h" static struct tm tmnow; static time_t now; static char *line; static size_t linesize; static void printcontent(const char *s) { for (; *s; ++s) { switch (*s) { case '<': fputs("<", stdout); break; case '>': fputs(">", stdout); break; case '\'': fputs("'", stdout); break; case '&': fputs("&", stdout); break; case '"': fputs(""", stdout); break; case '\\': s++; switch (*s) { case 'n': putchar('\n'); break; case '\\': putchar('\\'); break; case 't': putchar('\t'); break; } break; default: putchar(*s); } } } static void printfeed(FILE *fp, const char *feedname) { char *fields[FieldLast], *p, *tmp; struct tm parsedtm, *tm; time_t parsedtime; ssize_t linelen; int c; while ((linelen = getline(&line, &linesize, fp)) > 0 && !ferror(stdout)) { if (line[linelen - 1] == '\n') line[--linelen] = '\0'; parseline(line, fields); fputs("\n\t", stdout); if (feedname[0]) { fputs("[", stdout); xmlencode(feedname, stdout); fputs("] ", stdout); } xmlencode(fields[FieldTitle], stdout); fputs("\n", stdout); if (fields[FieldLink][0]) { fputs("\t\n", stdout); } /* prefer link over id for Atom . */ fputs("\t", stdout); if (fields[FieldLink][0]) xmlencode(fields[FieldLink], stdout); else if (fields[FieldId][0]) xmlencode(fields[FieldId], stdout); fputs("\n", stdout); if (fields[FieldEnclosure][0]) { fputs("\t\n", stdout); } parsedtime = 0; if (strtotime(fields[FieldUnixTimestamp], &parsedtime) || !(tm = gmtime_r(&parsedtime, &parsedtm))) tm = &tmnow; fprintf(stdout, "\t%04d-%02d-%02dT%02d:%02d:%02dZ\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if (fields[FieldAuthor][0]) { fputs("\t", stdout); xmlencode(fields[FieldAuthor], stdout); fputs("\n", stdout); } if (fields[FieldContent][0]) { if (!strcmp(fields[FieldContentType], "html")) { fputs("\t", stdout); } else { /* NOTE: an RSS/Atom viewer may or may not format whitespace such as newlines. Workaround: type="html" and ]]> */ fputs("\t", stdout); } printcontent(fields[FieldContent]); fputs("\n", stdout); } for (p = fields[FieldCategory]; (tmp = strchr(p, '|')); p = tmp + 1) { c = *tmp; *tmp = '\0'; /* temporary NUL-terminate */ if (*p) { fputs("\t\n", stdout); } *tmp = c; /* restore */ } fputs("\n", stdout); } } int main(int argc, char *argv[]) { struct tm *tm; FILE *fp; char *name; int i; if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1) err(1, "pledge"); if ((now = time(NULL)) == (time_t)-1) errx(1, "time"); if (!(tm = gmtime_r(&now, &tmnow))) err(1, "gmtime_r"); fputs("\n" "\n" "\tNewsfeed\n" "\tsfeed\n", stdout); printf("\turn:newsfeed:%lld\n" "\t%04d-%02d-%02dT%02d:%02d:%02dZ\n", (long long)now, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if (argc == 1) { printfeed(stdin, ""); checkfileerror(stdin, "", 'r'); } else { for (i = 1; i < argc; i++) { if (!(fp = fopen(argv[i], "r"))) err(1, "fopen: %s", argv[i]); name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i]; printfeed(fp, name); checkfileerror(fp, argv[i], 'r'); fclose(fp); } } fputs("\n", stdout); checkfileerror(stdout, "", 'w'); return 0; }