sfeed

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

sfeed_atom.c (4241B)


      1 #include <sys/types.h>
      2 
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <time.h>
      6 
      7 #include "util.h"
      8 
      9 static struct tm tmnow;
     10 static time_t now;
     11 static char *line;
     12 static size_t linesize;
     13 
     14 static void
     15 printcontent(const char *s)
     16 {
     17 	for (; *s; ++s) {
     18 		switch (*s) {
     19 		case '<':  fputs("&lt;",   stdout); break;
     20 		case '>':  fputs("&gt;",   stdout); break;
     21 		case '\'': fputs("&#39;",  stdout); break;
     22 		case '&':  fputs("&amp;",  stdout); break;
     23 		case '"':  fputs("&quot;", stdout); break;
     24 		case '\\':
     25 			s++;
     26 			switch (*s) {
     27 			case 'n':  putchar('\n'); break;
     28 			case '\\': putchar('\\'); break;
     29 			case 't':  putchar('\t'); break;
     30 			}
     31 			break;
     32 		default:  putchar(*s);
     33 		}
     34 	}
     35 }
     36 
     37 static void
     38 printfeed(FILE *fp, const char *feedname)
     39 {
     40 	char *fields[FieldLast], *p, *tmp;
     41 	struct tm parsedtm, *tm;
     42 	time_t parsedtime;
     43 	ssize_t linelen;
     44 	int c;
     45 
     46 	while ((linelen = getline(&line, &linesize, fp)) > 0 &&
     47 	       !ferror(stdout)) {
     48 		if (line[linelen - 1] == '\n')
     49 			line[--linelen] = '\0';
     50 		parseline(line, fields);
     51 
     52 		fputs("<entry>\n\t<title>", stdout);
     53 		if (feedname[0]) {
     54 			fputs("[", stdout);
     55 			xmlencode(feedname, stdout);
     56 			fputs("] ", stdout);
     57 		}
     58 		xmlencode(fields[FieldTitle], stdout);
     59 		fputs("</title>\n", stdout);
     60 		if (fields[FieldLink][0]) {
     61 			fputs("\t<link rel=\"alternate\" href=\"", stdout);
     62 			xmlencode(fields[FieldLink], stdout);
     63 			fputs("\" />\n", stdout);
     64 		}
     65 		/* prefer link over id for Atom <id>. */
     66 		fputs("\t<id>", stdout);
     67 		if (fields[FieldLink][0])
     68 			xmlencode(fields[FieldLink], stdout);
     69 		else if (fields[FieldId][0])
     70 			xmlencode(fields[FieldId], stdout);
     71 		fputs("</id>\n", stdout);
     72 		if (fields[FieldEnclosure][0]) {
     73 			fputs("\t<link rel=\"enclosure\" href=\"", stdout);
     74 			xmlencode(fields[FieldEnclosure], stdout);
     75 			fputs("\" />\n", stdout);
     76 		}
     77 
     78 		parsedtime = 0;
     79 		if (strtotime(fields[FieldUnixTimestamp], &parsedtime) ||
     80 		    !(tm = gmtime_r(&parsedtime, &parsedtm)))
     81 			tm = &tmnow;
     82 		fprintf(stdout, "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n",
     83 		        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
     84 		        tm->tm_hour, tm->tm_min, tm->tm_sec);
     85 
     86 		if (fields[FieldAuthor][0]) {
     87 			fputs("\t<author><name>", stdout);
     88 			xmlencode(fields[FieldAuthor], stdout);
     89 			fputs("</name></author>\n", stdout);
     90 		}
     91 		if (fields[FieldContent][0]) {
     92 			if (!strcmp(fields[FieldContentType], "html")) {
     93 				fputs("\t<content type=\"html\">", stdout);
     94 			} else {
     95 				/* NOTE: an RSS/Atom viewer may or may not format
     96 				   whitespace such as newlines.
     97 				   Workaround: type="html" and <![CDATA[<pre></pre>]]> */
     98 				fputs("\t<content type=\"text\">", stdout);
     99 			}
    100 			printcontent(fields[FieldContent]);
    101 			fputs("</content>\n", stdout);
    102 		}
    103 		for (p = fields[FieldCategory]; (tmp = strchr(p, '|')); p = tmp + 1) {
    104 			c = *tmp;
    105 			*tmp = '\0'; /* temporary NUL-terminate */
    106 			if (*p) {
    107 				fputs("\t<category term=\"", stdout);
    108 				xmlencode(p, stdout);
    109 				fputs("\" />\n", stdout);
    110 			}
    111 			*tmp = c; /* restore */
    112 		}
    113 		fputs("</entry>\n", stdout);
    114 	}
    115 }
    116 
    117 int
    118 main(int argc, char *argv[])
    119 {
    120 	struct tm *tm;
    121 	FILE *fp;
    122 	char *name;
    123 	int i;
    124 
    125 	if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1)
    126 		err(1, "pledge");
    127 
    128 	if ((now = time(NULL)) == (time_t)-1)
    129 		errx(1, "time");
    130 	if (!(tm = gmtime_r(&now, &tmnow)))
    131 		err(1, "gmtime_r");
    132 
    133 	fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
    134 	      "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
    135 	      "\t<title type=\"text\">Newsfeed</title>\n"
    136 	      "\t<author><name>sfeed</name></author>\n", stdout);
    137 	printf("\t<id>urn:newsfeed:%lld</id>\n"
    138 	       "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n",
    139 	       (long long)now,
    140 	       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
    141 	       tm->tm_hour, tm->tm_min, tm->tm_sec);
    142 
    143 	if (argc == 1) {
    144 		printfeed(stdin, "");
    145 		checkfileerror(stdin, "<stdin>", 'r');
    146 	} else {
    147 		for (i = 1; i < argc; i++) {
    148 			if (!(fp = fopen(argv[i], "r")))
    149 				err(1, "fopen: %s", argv[i]);
    150 			name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
    151 			printfeed(fp, name);
    152 			checkfileerror(fp, argv[i], 'r');
    153 			checkfileerror(stdout, "<stdout>", 'w');
    154 			fclose(fp);
    155 		}
    156 	}
    157 
    158 	fputs("</feed>\n", stdout);
    159 
    160 	checkfileerror(stdout, "<stdout>", 'w');
    161 
    162 	return 0;
    163 }