sfeed

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

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