sfeed_json.c (3719B)
1#include <stdio.h> 2#include <string.h> 3#include <time.h> 4 5#include "util.h" 6 7static char *line; 8static size_t linesize; 9static int firstitem = 1; 10 11/* Unescape / decode fields printed by string_print_encoded() */ 12static void 13printcontent(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 35static void 36printfield(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 48static void 49printfeed(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 138int 139main(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}