sfeed_atom.c - sfeed - RSS and Atom parser | |
git clone git://git.codemadness.org/sfeed | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
sfeed_atom.c (4200B) | |
--- | |
1 #include <stdio.h> | |
2 #include <string.h> | |
3 #include <time.h> | |
4 | |
5 #include "util.h" | |
6 | |
7 static struct tm tmnow; | |
8 static time_t now; | |
9 static char *line; | |
10 static size_t linesize; | |
11 | |
12 static void | |
13 printcontent(const char *s) | |
14 { | |
15 for (; *s; ++s) { | |
16 switch (*s) { | |
17 case '<': fputs("<", stdout); break; | |
18 case '>': fputs(">", stdout); break; | |
19 case '\'': fputs("'", stdout); break; | |
20 case '&': fputs("&", stdout); break; | |
21 case '"': fputs(""", stdout); break; | |
22 case '\\': | |
23 if (*(s + 1) == '\0') | |
24 break; | |
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=\"", stdou… | |
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=\"", stdou… | |
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:%02… | |
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\">", stdou… | |
94 } else { | |
95 /* NOTE: an RSS/Atom viewer may or may n… | |
96 * whitespace such as newlines. | |
97 * Workaround: type="html" and <![CDATA[… | |
98 fputs("\t<content>", stdout); | |
99 } | |
100 printcontent(fields[FieldContent]); | |
101 fputs("</content>\n", stdout); | |
102 } | |
103 for (p = fields[FieldCategory]; (tmp = strchr(p, '|')); … | |
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: can't get current time"); | |
132 | |
133 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
134 "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" | |
135 "\t<title>Newsfeed</title>\n", stdout); | |
136 printf("\t<id>urn:newsfeed:%lld</id>\n" | |
137 "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n", | |
138 (long long)now, | |
139 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, | |
140 tm->tm_hour, tm->tm_min, tm->tm_sec); | |
141 | |
142 if (argc == 1) { | |
143 printfeed(stdin, ""); | |
144 checkfileerror(stdin, "<stdin>", 'r'); | |
145 } else { | |
146 for (i = 1; i < argc; i++) { | |
147 if (!(fp = fopen(argv[i], "r"))) | |
148 err(1, "fopen: %s", argv[i]); | |
149 name = ((name = strrchr(argv[i], '/'))) ? name +… | |
150 printfeed(fp, name); | |
151 checkfileerror(fp, argv[i], 'r'); | |
152 checkfileerror(stdout, "<stdout>", 'w'); | |
153 fclose(fp); | |
154 } | |
155 } | |
156 | |
157 fputs("</feed>\n", stdout); | |
158 | |
159 checkfileerror(stdout, "<stdout>", 'w'); | |
160 | |
161 return 0; | |
162 } |