sfeed

Simple RSS and Atom feed parser
git clone https://git.sinitax.com/codemadness/sfeed
Log | Files | Refs | README | LICENSE | Upstream | sfeed.txt

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}