sfeed

simple feed reader - forked from git.codemadness.org/sfeed
git clone git://src.gearsix.net/sfeedsfeed.zip
Log | Files | Refs | Atom | README | LICENSE

sfeed_json.c (raw) (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 }