sfeed_atom.c (4241B)
1 #include <sys/types.h> 2 3 #include <stdio.h> 4 #include <string.h> 5 #include <time.h> 6 7 #include "util.h" 8 9 static struct tm tmnow; 10 static time_t now; 11 static char *line; 12 static size_t linesize; 13 14 static void 15 printcontent(const char *s) 16 { 17 for (; *s; ++s) { 18 switch (*s) { 19 case '<': fputs("<", stdout); break; 20 case '>': fputs(">", stdout); break; 21 case '\'': fputs("'", stdout); break; 22 case '&': fputs("&", stdout); break; 23 case '"': fputs(""", stdout); break; 24 case '\\': 25 s++; 26 switch (*s) { 27 case 'n': putchar('\n'); break; 28 case '\\': putchar('\\'); break; 29 case 't': putchar('\t'); break; 30 } 31 break; 32 default: putchar(*s); 33 } 34 } 35 } 36 37 static void 38 printfeed(FILE *fp, const char *feedname) 39 { 40 char *fields[FieldLast], *p, *tmp; 41 struct tm parsedtm, *tm; 42 time_t parsedtime; 43 ssize_t linelen; 44 int c; 45 46 while ((linelen = getline(&line, &linesize, fp)) > 0 && 47 !ferror(stdout)) { 48 if (line[linelen - 1] == '\n') 49 line[--linelen] = '\0'; 50 parseline(line, fields); 51 52 fputs("<entry>\n\t<title>", stdout); 53 if (feedname[0]) { 54 fputs("[", stdout); 55 xmlencode(feedname, stdout); 56 fputs("] ", stdout); 57 } 58 xmlencode(fields[FieldTitle], stdout); 59 fputs("</title>\n", stdout); 60 if (fields[FieldLink][0]) { 61 fputs("\t<link rel=\"alternate\" href=\"", stdout); 62 xmlencode(fields[FieldLink], stdout); 63 fputs("\" />\n", stdout); 64 } 65 /* prefer link over id for Atom <id>. */ 66 fputs("\t<id>", stdout); 67 if (fields[FieldLink][0]) 68 xmlencode(fields[FieldLink], stdout); 69 else if (fields[FieldId][0]) 70 xmlencode(fields[FieldId], stdout); 71 fputs("</id>\n", stdout); 72 if (fields[FieldEnclosure][0]) { 73 fputs("\t<link rel=\"enclosure\" href=\"", stdout); 74 xmlencode(fields[FieldEnclosure], stdout); 75 fputs("\" />\n", stdout); 76 } 77 78 parsedtime = 0; 79 if (strtotime(fields[FieldUnixTimestamp], &parsedtime) || 80 !(tm = gmtime_r(&parsedtime, &parsedtm))) 81 tm = &tmnow; 82 fprintf(stdout, "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n", 83 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 84 tm->tm_hour, tm->tm_min, tm->tm_sec); 85 86 if (fields[FieldAuthor][0]) { 87 fputs("\t<author><name>", stdout); 88 xmlencode(fields[FieldAuthor], stdout); 89 fputs("</name></author>\n", stdout); 90 } 91 if (fields[FieldContent][0]) { 92 if (!strcmp(fields[FieldContentType], "html")) { 93 fputs("\t<content type=\"html\">", stdout); 94 } else { 95 /* NOTE: an RSS/Atom viewer may or may not format 96 whitespace such as newlines. 97 Workaround: type="html" and <![CDATA[<pre></pre>]]> */ 98 fputs("\t<content type=\"text\">", stdout); 99 } 100 printcontent(fields[FieldContent]); 101 fputs("</content>\n", stdout); 102 } 103 for (p = fields[FieldCategory]; (tmp = strchr(p, '|')); p = tmp + 1) { 104 c = *tmp; 105 *tmp = '\0'; /* temporary NUL-terminate */ 106 if (*p) { 107 fputs("\t<category term=\"", stdout); 108 xmlencode(p, stdout); 109 fputs("\" />\n", stdout); 110 } 111 *tmp = c; /* restore */ 112 } 113 fputs("</entry>\n", stdout); 114 } 115 } 116 117 int 118 main(int argc, char *argv[]) 119 { 120 struct tm *tm; 121 FILE *fp; 122 char *name; 123 int i; 124 125 if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1) 126 err(1, "pledge"); 127 128 if ((now = time(NULL)) == (time_t)-1) 129 errx(1, "time"); 130 if (!(tm = gmtime_r(&now, &tmnow))) 131 err(1, "gmtime_r"); 132 133 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 134 "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" 135 "\t<title type=\"text\">Newsfeed</title>\n" 136 "\t<author><name>sfeed</name></author>\n", stdout); 137 printf("\t<id>urn:newsfeed:%lld</id>\n" 138 "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n", 139 (long long)now, 140 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 141 tm->tm_hour, tm->tm_min, tm->tm_sec); 142 143 if (argc == 1) { 144 printfeed(stdin, ""); 145 checkfileerror(stdin, "<stdin>", 'r'); 146 } else { 147 for (i = 1; i < argc; i++) { 148 if (!(fp = fopen(argv[i], "r"))) 149 err(1, "fopen: %s", argv[i]); 150 name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i]; 151 printfeed(fp, name); 152 checkfileerror(fp, argv[i], 'r'); 153 checkfileerror(stdout, "<stdout>", 'w'); 154 fclose(fp); 155 } 156 } 157 158 fputs("</feed>\n", stdout); 159 160 checkfileerror(stdout, "<stdout>", 'w'); 161 162 return 0; 163 }