sfeed_json.c - sfeed - RSS and Atom parser | |
git clone git://git.codemadness.org/sfeed | |
Log | |
Files | |
Refs | |
README | |
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:%… | |
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 term… | |
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\": \"", std… | |
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 +… | |
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 } |