sfeed

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

commit 7e575e13c0cdcc4341fa2f0b6dcb90cb4bd3cd71
parent b2fa0c97f2b5d97631d39fa0cb3f7fe51a10a3c7
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sun, 21 Jun 2015 00:24:30 +0200

improvements

Diffstat:
Msfeed_frames.1 | 2+-
Msfeed_frames.c | 221+++++++++++++++++++++++++++++++++++++------------------------------------------
Msfeed_html.c | 154++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msfeed_plain.1 | 22++++++++++++++--------
Msfeed_plain.c | 56++++++++++++++++++++++++++++++++++++++++----------------
Msfeed_update.1 | 79+++++++++++++++++++++++++++----------------------------------------------------
Mutil.c | 14+++++++-------
Mutil.h | 28++++++++++++++--------------
8 files changed, 288 insertions(+), 288 deletions(-)

diff --git a/sfeed_frames.1 b/sfeed_frames.1 @@ -6,7 +6,7 @@ .Nd formats a feeds file to HTML with frames .Sh SYNOPSIS .Nm -.Op Ar directory path +.Op Ar feed... .Sh DESCRIPTION .Nm formats a feeds file (TSV) from diff --git a/sfeed_frames.c b/sfeed_frames.c @@ -12,15 +12,16 @@ #include <unistd.h> #include <utime.h> -#include "queue.h" #include "util.h" -static int showsidebar = 1; /* show sidebar ? */ -static FILE *fpindex = NULL, *fpitems = NULL, *fpmenu = NULL; -static FILE *fpcontent = NULL; static char *line = NULL; -static SLIST_HEAD(fhead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead); +size_t linesize = 0; + static struct utimbuf contenttime; +static time_t comparetime; +static unsigned long totalnew = 0; + +static struct feed **feeds = NULL; /* normalize path names, transform to lower-case and replace non-alpha and * non-digit with '-' */ @@ -34,7 +35,7 @@ normalizepath(const char *path, char *buf, size_t bufsiz) buf[i++] = tolower((int)*path); r = 0; } else { - /* don't repeat '-'. */ + /* don't repeat '-' */ if(!r) buf[i++] = '-'; r++; @@ -50,102 +51,53 @@ normalizepath(const char *path, char *buf, size_t bufsiz) return i; } -int -main(int argc, char *argv[]) +static void +printfeed(FILE *fpitems, FILE *fpin, struct feed *f) { - struct feed *f, *fcur = NULL; - char *fields[FieldLast]; - char name[256]; /* buffer for feedname */ char dirpath[PATH_MAX], filepath[PATH_MAX]; - char reldirpath[PATH_MAX], relfilepath[PATH_MAX]; - char *feedname = "", *basepath = "."; - unsigned long totalfeeds = 0, totalnew = 0; - unsigned int isnew; - time_t parsedtime, comparetime; - size_t linesize = 0, namelen, basepathlen; + char *fields[FieldLast], *feedname; + char name[PATH_MAX]; + size_t namelen; struct stat st; + FILE *fpcontent = NULL; + unsigned int isnew; + time_t parsedtime; int r; - if(argc > 1 && argv[1][0] != '\0') - basepath = argv[1]; - - /* 1 day is old news */ - comparetime = time(NULL) - 86400; - - basepathlen = strlen(basepath); - if(basepathlen > 0) { - mkdir(basepath, S_IRWXU); - err(1, "mkdir: %s", basepath); + if(f->name[0]) + feedname = f->name; + else + feedname = "unnamed"; + + /* make directory for feedname */ + if(!(namelen = normalizepath(feedname, name, sizeof(name)))) + return; + + if(strlcpy(dirpath, name, sizeof(dirpath)) >= sizeof(dirpath)) + errx(1, "strlcpy: path truncation"); + /* directory doesn't exist: try to create it. */ + if(stat(dirpath, &st) == -1 && mkdir(dirpath, S_IRWXU) == -1) + err(1, "mkdir: %s", dirpath); + + /* menu if not unnamed */ + if(f->name[0]) { + fputs("<h2 id=\"", fpitems); + printxmlencoded(f->name, fpitems); + fputs("\"><a href=\"#", fpitems); + printxmlencoded(f->name, fpitems); + fputs("\">", fpitems); + printxmlencoded(f->name, fpitems); + fputs("</a></h2>\n", fpitems); } - /* write main index page */ - esnprintf(dirpath, sizeof(dirpath), "%s/index.html", basepath); - if(!(fpindex = fopen(dirpath, "w+b"))) - err(1, "fopen: %s", dirpath); - esnprintf(dirpath, sizeof(dirpath), "%s/menu.html", basepath); - if(!(fpmenu = fopen(dirpath, "w+b"))) - err(1, "fopen: %s", dirpath); - esnprintf(dirpath, sizeof(dirpath), "%s/items.html", basepath); - if(!(fpitems = fopen(dirpath, "w+b"))) - err(1, "fopen: %s", dirpath); - fputs("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />" - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head>" - "<body class=\"frame\"><div id=\"items\">", fpitems); - - if(!(fcur = calloc(1, sizeof(struct feed)))) - err(1, "calloc"); - SLIST_INSERT_HEAD(&fhead, fcur, entry); - - while(parseline(&line, &linesize, fields, FieldLast, '\t', stdin) > 0) { - feedname = fields[FieldFeedName]; - if(feedname[0] == '\0') { - feedname = "unknown"; - /* assume single feed (hide sidebar) */ - if(!totalfeeds) - showsidebar = 0; - } - /* first of feed section or new feed section (differ from previous). */ - if(!totalfeeds || strcmp(fcur->name, feedname)) { - /* make directory for feedname */ - if(!(namelen = normalizepath(feedname, name, sizeof(name)))) - continue; - esnprintf(dirpath, sizeof(dirpath), "%s/%s", basepath, name); - - /* directory doesn't exist: try to create it. */ - if(stat(dirpath, &st) == -1 && mkdir(dirpath, S_IRWXU) == -1) - err(1, "mkdir: %s", dirpath); - if(strlcpy(reldirpath, name, sizeof(reldirpath)) >= sizeof(reldirpath)) - errx(1, "strlcpy: truncation"); - - if(!(f = calloc(1, sizeof(struct feed)))) - err(1, "calloc"); - if(!(f->name = strdup(feedname))) - err(1, "strdup"); - SLIST_INSERT_AFTER(fcur, f, entry); - fcur = f; - - /* end previous feed section. */ - if(totalfeeds) - fputs("</table>\n", fpitems); - - /* write menu link if new. */ - if(fields[FieldFeedName][0] != '\0') { - fputs("<h2 id=\"", fpitems); - printfeednameid(fcur->name, fpitems); - fputs("\"><a href=\"#", fpitems); - printfeednameid(fcur->name, fpitems); - fputs("\">", fpitems); - fputs(fcur->name, fpitems); - fputs("</a></h2>\n", fpitems); - } - fputs("<table cellpadding=\"0\" cellspacing=\"0\">\n", fpitems); - totalfeeds++; - } + fputs("<table cellpadding=\"0\" cellspacing=\"0\">\n", fpitems); + while(parseline(&line, &linesize, fields, FieldLast, '\t', fpin) > 0) { /* write content */ if(!(namelen = normalizepath(fields[FieldTitle], name, sizeof(name)))) continue; - esnprintf(filepath, sizeof(filepath), "%s/%s.html", dirpath, name); - esnprintf(relfilepath, sizeof(relfilepath), "%s/%s.html", reldirpath, name); + r = snprintf(filepath, sizeof(filepath), "%s/%s.html", dirpath, name); + if(r == -1 || (size_t)r >= sizeof(filepath)) + errx(1, "snprintf: path truncation"); /* file doesn't exist yet and has write access */ if(access(filepath, F_OK) != 0) { @@ -155,22 +107,17 @@ main(int argc, char *argv[]) "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head>\n" "<body class=\"frame\"><div class=\"content\">" "<h2><a href=\"", fpcontent); - if(fields[FieldBaseSiteUrl][0] != '\0') - printlink(fields[FieldLink], fields[FieldBaseSiteUrl], fpcontent); - else - printlink(fields[FieldLink], fields[FieldFeedUrl], fpcontent); + printxmlencoded(fields[FieldLink], fpcontent); fputs("\">", fpcontent); - printhtmlencoded(fields[FieldTitle], fpcontent); + printxmlencoded(fields[FieldTitle], fpcontent); fputs("</a></h2>", fpcontent); printcontent(fields[FieldContent], fpcontent); fputs("</div></body></html>", fpcontent); fclose(fpcontent); } - /* write item. */ - r = strtotime(fields[FieldUnixTimestamp], &parsedtime); - /* set modified and access time of file to time of item. */ + r = strtotime(fields[FieldUnixTimestamp], &parsedtime); if(r != -1) { contenttime.actime = parsedtime; contenttime.modtime = parsedtime; @@ -179,8 +126,8 @@ main(int argc, char *argv[]) isnew = (r != -1 && parsedtime >= comparetime) ? 1 : 0; totalnew += isnew; - fcur->totalnew += isnew; - fcur->total++; + f->totalnew += isnew; + f->total++; if(isnew) fputs("<tr class=\"n\">", fpitems); else @@ -191,32 +138,76 @@ main(int argc, char *argv[]) if(isnew) fputs("<b><u>", fpitems); fputs("<a href=\"", fpitems); - fputs(relfilepath, fpitems); + fputs(filepath, fpitems); fputs("\" target=\"content\">", fpitems); - printhtmlencoded(fields[FieldTitle], fpitems); + printxmlencoded(fields[FieldTitle], fpitems); fputs("</a>", fpitems); if(isnew) fputs("</u></b>", fpitems); fputs("</td></tr>\n", fpitems); } - if(totalfeeds) { - fputs("</table>\n", fpitems); + fputs("</table>\n", fpitems); +} + +int +main(int argc, char *argv[]) +{ + FILE *fpindex, *fpitems, *fpmenu, *fp; + int showsidebar = (argc > 1); + int i; + struct feed *f; + + if(!(feeds = calloc(argc, sizeof(struct feed *)))) + err(1, "calloc"); + + /* 1 day is old news */ + comparetime = time(NULL) - 86400; + + /* write main index page */ + if(!(fpindex = fopen("index.html", "w+b"))) + err(1, "fopen: index.html"); + if(!(fpmenu = fopen("menu.html", "w+b"))) + err(1, "fopen: menu.html"); + if(!(fpitems = fopen("items.html", "w+b"))) + err(1, "fopen: items.html"); + fputs("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />" + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head>" + "<body class=\"frame\"><div id=\"items\">", fpitems); + + if(argc == 1) { + if(!(feeds[0] = calloc(1, sizeof(struct feed)))) + err(1, "calloc"); + feeds[0]->name = ""; + printfeed(fpitems, stdin, feeds[0]); + } else { + for(i = 1; i < argc; i++) { + if(!(feeds[i - 1] = calloc(1, sizeof(struct feed)))) + err(1, "calloc"); + feeds[i - 1]->name = xbasename(argv[i]); + + if(!(fp = fopen(argv[i], "r"))) + err(1, "fopen: %s", argv[i]); + printfeed(fpitems, fp, feeds[i - 1]); + if(ferror(fp)) + err(1, "ferror: %s", argv[i]); + fclose(fp); + } } fputs("\n</div></body>\n</html>", fpitems); /* div items */ + if(showsidebar) { fputs("<html><head>" "<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n" "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" "</head><body class=\"frame\"><div id=\"sidebar\">", fpmenu); - SLIST_FOREACH(f, &fhead, entry) { - if(!f->name || f->name[0] == '\0') - continue; + for(i = 1; i < argc; i++) { + f = feeds[i - 1]; if(f->totalnew) fputs("<a class=\"n\" href=\"items.html#", fpmenu); else fputs("<a href=\"items.html#", fpmenu); - printfeednameid(f->name, fpmenu); + printxmlencoded(f->name, fpmenu); fputs("\" target=\"items\">", fpmenu); if(f->totalnew > 0) fputs("<b><u>", fpmenu); @@ -245,13 +236,9 @@ main(int argc, char *argv[]) "</frameset>\n" "</html>", fpindex); - /* cleanup */ - if(fpmenu) - fclose(fpmenu); - if(fpitems) - fclose(fpitems); - if(fpindex) - fclose(fpindex); + fclose(fpitems); + fclose(fpmenu); + fclose(fpindex); return 0; } diff --git a/sfeed_html.c b/sfeed_html.c @@ -5,80 +5,42 @@ #include <string.h> #include <time.h> -#include "queue.h" #include "util.h" -static int showsidebar = 1; /* show sidebar ? */ -static SLIST_HEAD(feedshead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead); +static struct feed **feeds = NULL; +static int showsidebar = 0; /* show sidebar ? */ static char *line = NULL; +static size_t linesize = 0; +static unsigned long totalnew = 0; +static time_t comparetime; -int -main(void) +static void +printfeed(FILE *fp, struct feed *f) { char *fields[FieldLast]; - unsigned long totalfeeds = 0, totalnew = 0; + time_t parsedtime; unsigned int islink, isnew; - struct feed *f, *fcur = NULL; - time_t parsedtime, comparetime; - size_t size = 0; int r; - /* 1 day old is old news */ - comparetime = time(NULL) - 86400; - - fputs("<!DOCTYPE HTML>\n" - "<html>\n" - "\t<head>\n" - "\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n" - "\t</head>\n" - "\t<body class=\"noframe\">\n", stdout); - - if(!(fcur = calloc(1, sizeof(struct feed)))) - err(1, "calloc"); - SLIST_INSERT_HEAD(&fhead, fcur, entry); + if(f->name[0] != '\0') { + fputs("<h2 id=\"", stdout); + printxmlencoded(f->name, stdout); + fputs("\"><a href=\"#", stdout); + printxmlencoded(f->name, stdout); + fputs("\">", stdout); + printxmlencoded(f->name, stdout); + fputs("</a></h2>\n", stdout); + } + fputs("<table cellpadding=\"0\" cellspacing=\"0\">\n", stdout); - while(parseline(&line, &size, fields, FieldLast, '\t', stdin) > 0) { + while(parseline(&line, &linesize, fields, FieldLast, '\t', fp) > 0) { r = strtotime(fields[FieldUnixTimestamp], &parsedtime); isnew = (r != -1 && parsedtime >= comparetime) ? 1 : 0; islink = (fields[FieldLink][0] != '\0') ? 1 : 0; - /* first of feed section or new feed section (differs from - * previous one). */ - if(!totalfeeds || strcmp(fcur->name, fields[FieldFeedName])) { - if(!(f = calloc(1, sizeof(struct feed)))) - err(1, "calloc"); - if(!(f->name = strdup(fields[FieldFeedName]))) - err(1, "strdup"); - - SLIST_INSERT_AFTER(fcur, f, entry); - fcur = f; - - if(totalfeeds) { /* end previous one. */ - fputs("</table>\n", stdout); - } else { - if(fields[FieldFeedName][0] == '\0' || !showsidebar) { - /* set nosidebar class on div for styling */ - fputs("\t\t<div id=\"items\" class=\"nosidebar\">\n", stdout); - showsidebar = 0; - } else { - fputs("\t\t<div id=\"items\">\n", stdout); - } - } - if(fields[FieldFeedName][0] != '\0') { - fputs("<h2 id=\"", stdout); - printfeednameid(fcur->name, stdout); - fputs("\"><a href=\"#", stdout); - printfeednameid(fcur->name, stdout); - fputs("\">", stdout); - fputs(fcur->name, stdout); - fputs("</a></h2>\n", stdout); - } - fputs("<table cellpadding=\"0\" cellspacing=\"0\">\n", stdout); - totalfeeds++; - } + totalnew += isnew; - fcur->totalnew += isnew; - fcur->total++; + f->totalnew += isnew; + f->total++; if(isnew) fputs("<tr class=\"n\">", stdout); @@ -91,34 +53,79 @@ main(void) fputs("<b><u>", stdout); if(islink) { fputs("<a href=\"", stdout); - if(fields[FieldBaseSiteUrl][0] != '\0') - printlink(fields[FieldLink], - fields[FieldBaseSiteUrl], stdout); - else - printlink(fields[FieldLink], - fields[FieldFeedUrl], stdout); + printxmlencoded(fields[FieldLink], stdout); fputs("\">", stdout); } - printhtmlencoded(fields[FieldTitle], stdout); + printxmlencoded(fields[FieldTitle], stdout); if(islink) fputs("</a>", stdout); if(isnew) fputs("</u></b>", stdout); fputs("</td></tr>\n", stdout); } - if(totalfeeds) - fputs("</table>\n\t\t</div>\n", stdout); /* div items */ + fputs("</table>\n", stdout); +} + +int +main(int argc, char *argv[]) +{ + struct feed *f; + FILE *fp; + int i; + + if(!(feeds = calloc(argc, sizeof(struct feed *)))) + err(1, "calloc"); + + /* 1 day old is old news */ + comparetime = time(NULL) - 86400; + + fputs("<!DOCTYPE HTML>\n" + "<html>\n" + "\t<head>\n" + "\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" + "\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n" + "\t</head>\n" + "\t<body class=\"noframe\">\n", stdout); + + showsidebar = (argc > 1); + if(showsidebar) + fputs("\t\t<div id=\"items\">\n", stdout); + else + fputs("\t\t<div id=\"items\" class=\"nosidebar\">\n", stdout); + + if(argc == 1) { + if(!(feeds[0] = calloc(1, sizeof(struct feed)))) + err(1, "calloc"); + feeds[0]->name = ""; + printfeed(stdin, feeds[0]); + if(ferror(stdin)) + err(1, "ferror: <stdin>:"); + } else { + for(i = 1; i < argc; i++) { + if(!(feeds[i - 1] = calloc(1, sizeof(struct feed)))) + err(1, "calloc"); + feeds[i - 1]->name = xbasename(argv[i]); + + if(!(fp = fopen(argv[i], "r"))) + err(1, "fopen: %s", argv[i]); + printfeed(fp, feeds[i - 1]); + if(ferror(fp)) + err(1, "ferror: %s", argv[i]); + fclose(fp); + } + } + fputs("</div>\n", stdout); /* div items */ + if(showsidebar) { fputs("\t<div id=\"sidebar\">\n\t\t<ul>\n", stdout); - SLIST_FOREACH(f, &fhead, entry) { - if(!f->name || f->name[0] == '\0') - continue; + for (i = 1; i < argc; i++) { + f = feeds[i - 1]; if(f->totalnew > 0) fputs("<li class=\"n\"><a href=\"#", stdout); else fputs("<li><a href=\"#", stdout); - printfeednameid(f->name, stdout); + printxmlencoded(f->name, stdout); fputs("\">", stdout); if(f->totalnew > 0) fputs("<b><u>", stdout); @@ -129,6 +136,7 @@ main(void) } fputs("\t\t</ul>\n\t</div>\n", stdout); } + fprintf(stdout, "\t</body>\n\t<title>Newsfeed (%lu)</title>\n</html>", totalnew); diff --git a/sfeed_plain.1 b/sfeed_plain.1 @@ -3,19 +3,25 @@ .Os .Sh NAME .Nm sfeed_plain -.Nd formats a feeds file to plain text +.Nd formats a feeds file to a plain-text list .Sh SYNOPSIS .Nm +.Op Ar file... .Sh DESCRIPTION .Nm -formats a feeds file (TSV) from -.Xr sfeed_update 1 -to plain text. It reads TSV data from stdin and writes formatted plain text to -stdout. For the exact TSV format see -.Xr sfeed_update 1 . +formats one or more +.Ar files +to a plain-text list. Each plain-text item will contain the feed name which +will be the filename. If no argument is given it will read a feed from stdin, +but there will not be a feed name. +The data read from +.Ar files +or stdin is in a TAB-separated-like format from +.Xr sfeed 1 +For a more detailed list of this format and its fields see +.Xr sfeed 1 .Sh SEE ALSO .Xr sfeed 1 , -.Xr sfeed_html 1 , -.Xr sfeed_update 1 +.Xr sfeed_html 1 .Sh AUTHORS .An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org diff --git a/sfeed_plain.c b/sfeed_plain.c @@ -1,3 +1,4 @@ +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -5,31 +6,54 @@ #include "util.h" -int -main(void) +static time_t comparetime; +static char *line = NULL; +static size_t size = 0; + +static void +printfeed(FILE *fp, const char *feedname) { - char *line = NULL, *fields[FieldLast]; - time_t parsedtime, comparetime; - size_t size = 0; + char *fields[FieldLast]; + time_t parsedtime; int r; - comparetime = time(NULL) - (3600 * 24); /* 1 day is old news */ - while(parseline(&line, &size, fields, FieldLast, '\t', stdin) > 0) { + while(parseline(&line, &size, fields, FieldLast, '\t', fp) > 0) { r = strtotime(fields[FieldUnixTimestamp], &parsedtime); if(r != -1 && parsedtime >= comparetime) - fputs(" N ", stdout); + fputs(" N ", stdout); else - fputs(" ", stdout); - if(fields[FieldFeedName][0] != '\0') - printf("%-15.15s ", fields[FieldFeedName]); - printf("%-30.30s ", fields[FieldTimeFormatted]); + fputs(" ", stdout); + + if(feedname[0]) + printf("%-15.15s ", feedname); + printf(" %-30.30s ", fields[FieldTimeFormatted]); printutf8pad(stdout, fields[FieldTitle], 70, ' '); fputs(" ", stdout); - if(fields[FieldBaseSiteUrl][0] != '\0') - printlink(fields[FieldLink], fields[FieldBaseSiteUrl], stdout); - else - printlink(fields[FieldLink], fields[FieldFeedUrl], stdout); + fputs(fields[FieldLink], stdout); putchar('\n'); } +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + int i; + + /* 1 day is old news */ + comparetime = time(NULL) - (3600 * 24); + + if(argc == 1) { + printfeed(stdin, ""); + } else { + for(i = 1; i < argc; i++) { + if(!(fp = fopen(argv[i], "r"))) + err(1, "fopen: %s", argv[i]); + printfeed(fp, xbasename(argv[i])); + if(ferror(fp)) + err(1, "ferror: %s", argv[i]); + fclose(fp); + } + } return 0; } diff --git a/sfeed_update.1 b/sfeed_update.1 @@ -9,80 +9,55 @@ .Op Ar configfile .Sh DESCRIPTION .Nm -updates feeds and merges the new data with the previous feeds. This is the file -$HOME/.sfeed/feeds by default. +updates feeds files and merges the new data with the previous files. These +are the files in the directory +.Pa $HOME/.sfeed/feeds +by default. .Sh OPTIONS .Bl -tag -width 17n .It Ar configfile -config file, if not specified uses the location $HOME/.sfeed/sfeedrc by default -see the +config file, if not specified uses the path +.Pa $HOME/.sfeed/sfeedrc +by default. See the .Sx FILES READ section for more information. .El -.Sh TAB-SEPARATED FORMAT FIELDS -The items are saved in a TSV-like format except newlines, tabs and -backslash are escaped with \\ (\\n, \\t and \\\\). Carriage returns (\\r) are -removed. -.Pp -The order and format of the fields are: -.Bl -tag -width 17n -.It Ar item timestamp -string, UNIX timestamp in GMT+0 -.It Ar item timestamp -string, date and time in the format: YYYY-mm-dd HH:MM:SS tzname[[+-][HHMM]] -.It Ar item title -string -.It Ar item link -string -.It Ar item content -string -.It Ar item content\-type -string, "html" or "plain" -.It Ar item id -string -.It Ar item author -string -.It Ar feed type -string, "rss" or "atom" -.El -.Sh EXTRA FIELDS -Extra fields added by sfeed_update: -.Bl -tag -width 17n -.It Ar feed name -string -.It Ar feed url -string -.It Ar item baseurl site -string -.El .Sh FILES READ .Bl -tag -width 17n .It Ar sfeedrc Config file, see the sfeedrc.example file for an example. -This file is evaluated as a shellscript in sfeed_update. +This file is evaluated as a shellscript in +.Nm . You can for example override the fetchfeed() function to -use wget, fetch or an other download program or you can -override the merge() function to change the merge logic. -The function feeds() is called to fetch the feeds. By -default the function feed() is executed as a parallel -job to speedup updating. +use +.Xr curl 1 , +.Xr wget 1 , +or an other network downloader or you can override the merge() function to +change the merge logic. The function feeds() is called to fetch the feeds. By +default the function feed() is executed as a parallel job to speedup updating. .El .Sh FILES WRITTEN .Bl -tag -width 17n -.It Ar feeds -Tab-separated format containing all feeds. +.It Ar feedname +Tab-separated format containing all items per feed. The sfeed_update script merges new items with this file. -.It Ar feeds.new +.It Ar feedname.new Temporary file used by sfeed_update to merge items. .El .Sh EXAMPLES -To update feeds and format the feeds file: +To update your feeds and format them in various formats: .Bd -literal +# Update sfeed_update "configfile" -sfeed_plain < $HOME/.sfeed/feeds > $HOME/.sfeed/feeds.txt -sfeed_html < $HOME/.sfeed/feeds > $HOME/.sfeed/feeds.html +# Plain-text list +sfeed_plain $HOME/.sfeed/feeds/* > $HOME/.sfeed/feeds.txt +# HTML +sfeed_html $HOME/.sfeed/feeds/* > $HOME/.sfeed/feeds.html +# HTML with frames +mkdir somedir && cd somedir && sfeed_frames $HOME/.sfeed/feeds/* .Ed .Sh SEE ALSO +.Xr sfeed 1 , .Xr sfeed_html 1 , .Xr sfeed_plain 1 , .Xr sh 1 diff --git a/util.c b/util.c @@ -14,7 +14,7 @@ #include "util.h" void -printurlencode(const char *s, size_t len, FILE *fp) +printurlencoded(const char *s, size_t len, FILE *fp) { size_t i; @@ -43,7 +43,7 @@ printlink(const char *link, const char *baseurl, FILE *fp) if(isrelative) { if((ebaseproto = strstr(baseurl, "://"))) { ebaseproto += strlen("://"); - printurlencode(baseurl, ebaseproto - baseurl, fp); + printurlencoded(baseurl, ebaseproto - baseurl, fp); } else { ebaseproto = baseurl; if(*baseurl || (link[0] == '/' && link[1] == '/')) @@ -54,19 +54,19 @@ printlink(const char *link, const char *baseurl, FILE *fp) link += 2; else if((ebasedomain = strchr(ebaseproto, '/'))) /* relative to baseurl and baseurl path. */ - printurlencode(ebaseproto, ebasedomain - ebaseproto, fp); + printurlencoded(ebaseproto, ebasedomain - ebaseproto, fp); else - printurlencode(ebaseproto, strlen(ebaseproto), fp); + printurlencoded(ebaseproto, strlen(ebaseproto), fp); } else if((ebasedomain = strrchr(ebaseproto, '/'))) { /* relative to baseurl and baseurl path. */ - printurlencode(ebaseproto, ebasedomain - ebaseproto + 1, fp); + printurlencoded(ebaseproto, ebasedomain - ebaseproto + 1, fp); } else { - printurlencode(ebaseproto, strlen(ebaseproto), fp); + printurlencoded(ebaseproto, strlen(ebaseproto), fp); if(*baseurl && *link) fputc('/', fp); } } - printurlencode(link, strlen(link), fp); + printurlencoded(link, strlen(link), fp); } /* read a field-separated line from 'fp', diff --git a/util.h b/util.h @@ -5,8 +5,6 @@ #include "compat.h" #endif -#include "queue.h" - #define ISUTF8(c) (((c) & 0xc0) != 0x80) #define LEN(x) (sizeof (x) / sizeof *(x)) @@ -17,20 +15,22 @@ struct feed { unsigned long total; /* total items */ time_t timenewest; char timenewestformat[64]; - SLIST_ENTRY(feed) entry; }; enum { FieldUnixTimestamp = 0, FieldTimeFormatted, FieldTitle, FieldLink, FieldContent, FieldContentType, FieldId, FieldAuthor, FieldFeedType, - FieldFeedName, FieldFeedUrl, FieldBaseSiteUrl, FieldLast }; + FieldLast }; + +ssize_t chartoxmlentity(int, char *, size_t); +int parseline(char **, size_t *, char **, unsigned int, int, FILE *); +void printcontent(const char *, FILE *); +void printxmlencoded(const char *, FILE *); +void printlink(const char *, const char *, FILE *); +void printurlencoded(const char *, size_t, FILE *); +void printutf8pad(FILE *, const char *, size_t, int); +int strtotime(const char *, time_t *); +char *trimstart(const char *); +char *trimend(const char *); +char *xbasename(const char *); + -int esnprintf(char *, size_t, const char *, ...); -int parseline(char **, size_t *, char **, unsigned int, int, FILE *); -void printcontent(const char *, FILE *); -void printfeednameid(const char *, FILE *); -void printhtmlencoded(const char *, FILE *); -void printlink(const char *, const char *, FILE *); -void printutf8pad(FILE *, const char *, size_t, int); -int strtotime(const char *, time_t *); -const char * trimstart(const char *); -const char * trimend(const char *);