commit 009f6e1affd8c8501f66526f100bfa273307e640
parent 018278e40b6794b23f98f57f154bfa1a30d56672
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 18 Jan 2020 19:19:41 +0100
add sfeed_gopher: generic gopher formatting program, remove sfeed_gph
Diffstat:
M | Makefile | | | 2 | +- |
M | README | | | 2 | +- |
A | sfeed_gopher.1 | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | sfeed_gopher.c | | | 159 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | sfeed_gph.1 | | | 45 | --------------------------------------------- |
D | sfeed_gph.c | | | 152 | ------------------------------------------------------------------------------- |
6 files changed, 220 insertions(+), 199 deletions(-)
diff --git a/Makefile b/Makefile
@@ -19,7 +19,7 @@ BIN = \
sfeed\
sfeed_atom\
sfeed_frames\
- sfeed_gph \
+ sfeed_gopher \
sfeed_html\
sfeed_mbox\
sfeed_opml_import\
diff --git a/README b/README
@@ -127,7 +127,7 @@ sfeed - Read XML RSS or Atom feed data from stdin. Write feed data
in TAB-separated format to stdout.
sfeed_atom - Format feed data (TSV) to an Atom feed.
sfeed_frames - Format feed data (TSV) to HTML file(s) with frames.
-sfeed_gph - Format feed data (TSV) to geomyidae .gph files.
+sfeed_gopher - Format feed data (TSV) to Gopher files.
sfeed_html - Format feed data (TSV) to HTML.
sfeed_opml_export - Generate an OPML XML file from a sfeedrc config file.
sfeed_opml_import - Generate a sfeedrc config file from an OPML XML file.
diff --git a/sfeed_gopher.1 b/sfeed_gopher.1
@@ -0,0 +1,59 @@
+.Dd January 18, 2020
+.Dt SFEED_GOPHER 1
+.Os
+.Sh NAME
+.Nm sfeed_gopher
+.Nd format feed data to Gopher files
+.Sh SYNOPSIS
+.Nm
+.Op Ar file...
+.Sh DESCRIPTION
+.Nm
+formats feed data (TSV) from
+.Xr sfeed 1
+from stdin or
+.Ar file
+to stdout in the raw Gopher output format.
+.Pp
+If one or more
+.Ar file
+are specified, the basename of the
+.Ar file
+is used as the feed name in the output.
+.Nm
+creates a index index file and for each feed creates a file in the
+format feedname.
+.Pp
+If no
+.Ar file
+parameters are specified and the data is read from stdin then the data is
+written to stdout and no files are written.
+.Pp
+Items with a timestamp from the last day compared to the system time at the
+time of formatting are counted and marked as new.
+.Bl -tag -width Ds
+.It Ev SFEED_GOPHER_PATH
+This environment variable can be used as the prefix for each path in the
+index file.
+The default is "/".
+.It Ev SFEED_GOPHER_HOST
+This environment variable can be used as the Gopher Host field.
+The default is "127.0.0.1".
+.It Ev SFEED_GOPHER_PORT
+This environment variable can be used as the Gopher Port field.
+The default is "70".
+.El
+.Sh SEE ALSO
+.Xr sfeed 1 ,
+.Xr sfeed 5
+.Sh STANDARDS
+.Rs
+.%D March 1993
+.%R RFC 1436
+.%T The Internet Gopher Protocol
+.Re
+.Sh AUTHORS
+.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org
+.Sh CAVEATS
+The common-used 'h' and 'i' types are used in this program.
+These types are an extension to Gopher.
diff --git a/sfeed_gopher.c b/sfeed_gopher.c
@@ -0,0 +1,159 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "util.h"
+
+static struct feed f;
+static char *prefixpath = "/", *host = "127.0.0.1", *port = "70"; /* default */
+static char *line;
+static size_t linesize;
+static time_t comparetime;
+
+/* Escape characters in gopher, CR and LF are ignored */
+void
+gophertext(FILE *fp, const char *s)
+{
+ for (; *s; s++) {
+ switch (*s) {
+ case '\r': /* ignore CR */
+ case '\n': /* ignore LF */
+ break;
+ case '\t':
+ fputs(" ", fp);
+ break;
+ default:
+ fputc(*s, fp);
+ break;
+ }
+ }
+}
+
+static void
+printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
+{
+ char *fields[FieldLast];
+ ssize_t linelen;
+ unsigned int isnew;
+ struct tm *tm;
+ time_t parsedtime;
+
+ if (f->name[0]) {
+ fprintf(fpitems, "i%s\t\t%s\t%s\r\n", f->name, host, port);
+ fprintf(fpitems, "i\t\t%s\t%s\r\n", host, port);
+ }
+
+ while ((linelen = getline(&line, &linesize, fpin)) > 0) {
+ if (line[linelen - 1] == '\n')
+ line[--linelen] = '\0';
+ if (!parseline(line, fields))
+ break;
+
+ parsedtime = 0;
+ if (strtotime(fields[FieldUnixTimestamp], &parsedtime))
+ continue;
+ if (!(tm = localtime(&parsedtime)))
+ err(1, "localtime");
+
+ isnew = (parsedtime >= comparetime) ? 1 : 0;
+ f->totalnew += isnew;
+ f->total++;
+
+ if (fields[FieldLink][0]) {
+ fputs("h", fpitems);
+ fprintf(fpitems, "%c %04d-%02d-%02d %02d:%02d ",
+ isnew ? 'N' : ' ',
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ gophertext(fpitems, fields[FieldTitle]);
+ fputs("\tURL:", fpitems);
+ gophertext(fpitems, fields[FieldLink]);
+
+ } else {
+ fprintf(fpitems, "i%c %04d-%02d-%02d %02d:%02d ",
+ isnew ? 'N' : ' ',
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ gophertext(fpitems, fields[FieldTitle]);
+ fputs("\t", fpitems);
+ }
+ fprintf(fpitems, "\t%s\t%s\r\n", host, port);
+ }
+ fputs(".\r\n", fpitems);
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fpitems, *fpindex, *fp;
+ char *name, *p, path[PATH_MAX + 1];
+ int i, r;
+
+ if (pledge(argc == 1 ? "stdio" : "stdio rpath wpath cpath", NULL) == -1)
+ err(1, "pledge");
+
+ if ((comparetime = time(NULL)) == -1)
+ err(1, "time");
+ /* 1 day is old news */
+ comparetime -= 86400;
+
+ if ((p = getenv("SFEED_GOPHER_HOST")))
+ host = p;
+ if ((p = getenv("SFEED_GOPHER_PORT")))
+ port = p;
+
+ if (argc == 1) {
+ f.name = "";
+ printfeed(stdout, stdin, &f);
+ } else {
+ if ((p = getenv("SFEED_GOPHER_PATH")))
+ prefixpath = p;
+
+ /* write main index page */
+ if (!(fpindex = fopen("index", "wb")))
+ err(1, "fopen: index");
+
+ for (i = 1; i < argc; i++) {
+ memset(&f, 0, sizeof(f));
+ name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
+ f.name = name;
+
+ if (!(fp = fopen(argv[i], "r")))
+ err(1, "fopen: %s", argv[i]);
+
+ r = snprintf(path, sizeof(path), "%s", name);
+ if (r < 0 || (size_t)r >= sizeof(path))
+ errx(1, "path truncation: %s", path);
+ if (!(fpitems = fopen(path, "wb")))
+ err(1, "fopen");
+ printfeed(fpitems, fp, &f);
+ if (ferror(fp))
+ err(1, "ferror: %s", argv[i]);
+ fclose(fp);
+ fclose(fpitems);
+
+ /* append directory item to index */
+ fputs("1", fpindex);
+ gophertext(fpindex, name);
+ fprintf(fpindex, " (%lu/%lu)\t", f.totalnew, f.total);
+ gophertext(fpindex, prefixpath);
+ gophertext(fpindex, path);
+ fprintf(fpindex, "\t%s\t%s\r\n", host, port);
+ }
+ fputs(".\r\n", fpindex);
+ fclose(fpindex);
+ }
+
+ return 0;
+}
diff --git a/sfeed_gph.1 b/sfeed_gph.1
@@ -1,45 +0,0 @@
-.Dd July 20, 2019
-.Dt SFEED_GPH 1
-.Os
-.Sh NAME
-.Nm sfeed_gph
-.Nd format feed data to geomyidae .gph files
-.Sh SYNOPSIS
-.Nm
-.Op Ar file...
-.Sh DESCRIPTION
-.Nm
-formats feed data (TSV) from
-.Xr sfeed 1
-from stdin or
-.Ar file
-to stdout in the geomyidae .gph file format.
-.Pp
-If one or more
-.Ar file
-are specified, the basename of the
-.Ar file
-is used as the feed name in the output.
-.Nm
-creates a index.gph index file and for each feed creates a file in the
-format feedname.gph.
-.Pp
-If no
-.Ar file
-parameters are specified and the data is read from stdin then the gph data
-is written to stdout and no files are written.
-.Pp
-Items with a timestamp from the last day compared to the system time at the
-time of formatting are counted and marked as new.
-.Bl -tag -width Ds
-.It Ev SFEED_GPH_PATH
-This environment variable can be used as the prefix for each path in the
-index.gph file.
-The default is "/".
-.El
-.Sh SEE ALSO
-.Xr sfeed 1 ,
-.Xr sfeed 5 ,
-.Xr geomyidae 8
-.Sh AUTHORS
-.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org
diff --git a/sfeed_gph.c b/sfeed_gph.c
@@ -1,152 +0,0 @@
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "util.h"
-
-static struct feed f;
-static char *prefixpath;
-static char *line;
-static size_t linesize;
-static time_t comparetime;
-
-/* Escape characters in links in geomyidae .gph format */
-void
-gphlink(FILE *fp, const char *s, size_t len)
-{
- size_t i;
-
- for (i = 0; *s && i < len; s++, i++) {
- switch (*s) {
- case '\r': /* ignore CR */
- case '\n': /* ignore LF */
- break;
- case '\t':
- fputs(" ", fp);
- break;
- case '|': /* escape separators */
- fputs("\\|", fp);
- break;
- default:
- fputc(*s, fp);
- break;
- }
- }
-}
-
-static void
-printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
-{
- char *fields[FieldLast];
- ssize_t linelen;
- unsigned int isnew;
- struct tm *tm;
- time_t parsedtime;
-
- if (f->name[0])
- fprintf(fpitems, "t%s\n\n", f->name);
-
- while ((linelen = getline(&line, &linesize, fpin)) > 0) {
- if (line[linelen - 1] == '\n')
- line[--linelen] = '\0';
- if (!parseline(line, fields))
- break;
-
- parsedtime = 0;
- if (strtotime(fields[FieldUnixTimestamp], &parsedtime))
- continue;
- if (!(tm = localtime(&parsedtime)))
- err(1, "localtime");
-
- isnew = (parsedtime >= comparetime) ? 1 : 0;
- f->totalnew += isnew;
- f->total++;
-
- if (fields[FieldLink][0]) {
- fputs("[h|", fpitems);
- fprintf(fpitems, "%c %04d-%02d-%02d %02d:%02d ",
- isnew ? 'N' : ' ',
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min);
- gphlink(fpitems, fields[FieldTitle], strlen(fields[FieldTitle]));
- fputs("|URL:", fpitems);
- gphlink(fpitems, fields[FieldLink], strlen(fields[FieldLink]));
- fputs("|server|port]\n", fpitems);
- } else {
- fprintf(fpitems, "%c %04d-%02d-%02d %02d:%02d %s\n",
- isnew ? 'N' : ' ',
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, fields[FieldTitle]);
- }
- }
-}
-
-int
-main(int argc, char *argv[])
-{
- FILE *fpitems, *fpindex, *fp;
- char *name, path[PATH_MAX + 1];
- int i, r;
-
- if (pledge(argc == 1 ? "stdio" : "stdio rpath wpath cpath", NULL) == -1)
- err(1, "pledge");
-
- if ((comparetime = time(NULL)) == -1)
- err(1, "time");
- /* 1 day is old news */
- comparetime -= 86400;
-
- if (argc == 1) {
- f.name = "";
- printfeed(stdout, stdin, &f);
- } else {
- if (!(prefixpath = getenv("SFEED_GPH_PATH")))
- prefixpath = "/";
-
- /* write main index page */
- if (!(fpindex = fopen("index.gph", "wb")))
- err(1, "fopen: index.gph");
-
- for (i = 1; i < argc; i++) {
- memset(&f, 0, sizeof(f));
- name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
- f.name = name;
-
- if (!(fp = fopen(argv[i], "r")))
- err(1, "fopen: %s", argv[i]);
-
- r = snprintf(path, sizeof(path), "%s.gph", name);
- if (r < 0 || (size_t)r >= sizeof(path))
- errx(1, "path truncation: %s", path);
- if (!(fpitems = fopen(path, "wb")))
- err(1, "fopen");
- printfeed(fpitems, fp, &f);
- if (ferror(fp))
- err(1, "ferror: %s", argv[i]);
- fclose(fp);
- fclose(fpitems);
-
- /* append directory item to index */
- fprintf(fpindex, "[1|");
- gphlink(fpindex, name, strlen(name));
- fprintf(fpindex, " (%lu/%lu)|", f.totalnew, f.total);
- gphlink(fpindex, prefixpath, strlen(prefixpath));
- gphlink(fpindex, path, strlen(path));
- fputs("|server|port]\n", fpindex);
- }
- fclose(fpindex);
- }
-
- return 0;
-}