sfeed_json.c - sfeed - RSS and Atom parser
(HTM) git clone git://git.codemadness.org/sfeed
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
sfeed_json.c (3719B)
---
1 #include <stdio.h>
2 #include <string.h>
3 #include <time.h>
4
5 #include "util.h"
6
7 static char *line;
8 static size_t linesize;
9 static int firstitem = 1;
10
11 /* Unescape / decode fields printed by string_print_encoded() */
12 static void
13 printcontent(const char *s)
14 {
15 for (; *s; s++) {
16 switch (*s) {
17 case '\\':
18 if (*(s + 1) == '\0')
19 break;
20 s++;
21 switch (*s) {
22 case 'n': fputs("\\n", stdout); break;
23 case '\\': fputs("\\\\", stdout); break;
24 case 't': fputs("\\t", stdout); break;
25 }
26 break; /* ignore invalid escape sequence */
27 case '"': fputs("\\\"", stdout); break;
28 default:
29 putchar(*s);
30 break;
31 }
32 }
33 }
34
35 static void
36 printfield(const char *s)
37 {
38 for (; *s; s++) {
39 if (*s == '\\')
40 fputs("\\\\", stdout);
41 else if (*s == '"')
42 fputs("\\\"", stdout);
43 else
44 putchar(*s);
45 }
46 }
47
48 static void
49 printfeed(FILE *fp, const char *feedname)
50 {
51 char *fields[FieldLast], timebuf[32];
52 struct tm parsedtm, *tm;
53 time_t parsedtime;
54 ssize_t linelen;
55 int ch;
56 char *p, *s;
57
58 while ((linelen = getline(&line, &linesize, fp)) > 0 &&
59 !ferror(stdout)) {
60 if (line[linelen - 1] == '\n')
61 line[--linelen] = '\0';
62 parseline(line, fields);
63
64 if (!firstitem)
65 fputs(",\n", stdout);
66 firstitem = 0;
67
68 fputs("{\n\t\"id\": \"", stdout);
69 printfield(fields[FieldId]);
70 fputs("\"", stdout);
71
72 parsedtime = 0;
73 if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) &&
74 (tm = gmtime_r(&parsedtime, &parsedtm)) &&
75 strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", tm)) {
76 fputs(",\n\t\"date_published\": \"", stdout);
77 fputs(timebuf, stdout);
78 fputs("\"", stdout);
79 }
80
81 fputs(",\n\t\"title\": \"", stdout);
82 if (feedname[0]) {
83 fputs("[", stdout);
84 printfield(feedname);
85 fputs("] ", stdout);
86 }
87 printfield(fields[FieldTitle]);
88 fputs("\"", stdout);
89
90 if (fields[FieldLink][0]) {
91 fputs(",\n\t\"url\": \"", stdout);
92 printfield(fields[FieldLink]);
93 fputs("\"", stdout);
94 }
95
96 if (fields[FieldAuthor][0]) {
97 fputs(",\n\t\"authors\": [{\"name\": \"", stdout);
98 printfield(fields[FieldAuthor]);
99 fputs("\"}]", stdout);
100 }
101
102 if (fields[FieldCategory][0]) {
103 fputs(",\n\t\"tags\": [", stdout);
104
105 for (p = s = fields[FieldCategory]; ; s++) {
106 if (*s == '|' || *s == '\0') {
107 if (p != fields[FieldCategory])
108 fputs(", ", stdout);
109 ch = *s;
110 *s = '\0'; /* temporary NUL terminate */
111 fputs("\"", stdout);
112 printfield(p);
113 fputs("\"", stdout);
114 *s = ch; /* restore */
115 p = s + 1;
116 }
117 if (*s == '\0')
118 break;
119 }
120 fputs("]", stdout);
121 }
122
123 if (fields[FieldEnclosure][0]) {
124 fputs(",\n\t\"attachments\": [{\"url\": \"", stdout);
125 printfield(fields[FieldEnclosure]);
126 fputs("\"}]", stdout);
127 }
128
129 if (!strcmp(fields[FieldContentType], "html"))
130 fputs(",\n\t\"content_html\": \"", stdout);
131 else
132 fputs(",\n\t\"content_text\": \"", stdout);
133 printcontent(fields[FieldContent]);
134 fputs("\"\n}", stdout);
135 }
136 }
137
138 int
139 main(int argc, char *argv[])
140 {
141 FILE *fp;
142 char *name;
143 int i;
144
145 if (pledge(argc <= 1 ? "stdio" : "stdio rpath", NULL) == -1)
146 err(1, "pledge");
147
148 fputs("{\n"
149 "\"version\": \"https://jsonfeed.org/version/1.1\",\n"
150 "\"title\": \"Newsfeed\",\n"
151 "\"items\": [\n", stdout);
152
153 if (argc <= 1) {
154 printfeed(stdin, "");
155 checkfileerror(stdin, "<stdin>", 'r');
156 } else {
157 for (i = 1; i < argc; i++) {
158 if (!(fp = fopen(argv[i], "r")))
159 err(1, "fopen: %s", argv[i]);
160 name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
161 printfeed(fp, name);
162 checkfileerror(fp, argv[i], 'r');
163 checkfileerror(stdout, "<stdout>", 'w');
164 fclose(fp);
165 }
166 }
167 fputs("]\n}\n", stdout);
168
169 checkfileerror(stdout, "<stdout>", 'w');
170
171 return 0;
172 }