dag

Djmoch's Auto Generator
git clone git://git.danielmoch.com/dag.git
Log | Files | Refs | README | LICENSE

commit a8bf54222273137d8e2dda2245495cd12f5849e8
parent c7e6009f9b72065e2c8d7d3a4cc36989ad8630b8
Author: Daniel Moch <daniel@danielmoch.com>
Date:   Sat, 13 Nov 2021 09:05:33 -0500

dagindex working

Diffstat:
MMakefile | 1+
Mdagindex.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mdb.c | 81++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mdb.h | 4++--
Mhtml.c | 18+++++++++++++++---
Mxml.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mxml.h | 6+++---
7 files changed, 219 insertions(+), 65 deletions(-)

diff --git a/Makefile b/Makefile @@ -35,6 +35,7 @@ install: dag dagindex uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dag + rm -f ${DESTDIR}${PREFIX}/bin/dagindex clean: rm -f *.o dag dagindex *_test y.tab.* lex.yy.c diff --git a/dagindex.c b/dagindex.c @@ -5,17 +5,20 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "db.h" #include "html.h" #include "string.h" #include "term.h" +#include "xml.h" enum { ERR_NONE, ERR_UNKNOWN_OPTION, - ERR_ARGS + ERR_ARGS, + ERR_TIME }; enum { @@ -44,12 +47,12 @@ usage(int rv) fprintf(fp, "usage: %s -Vh\n", argv0); fprintf(fp, "\t%s -A -t title -s slug -p date_published [-a author]\n", argv0); fprintf(fp, "\t\t[-u date_updated] [-c category] [-d description]\n"); - fprintf(fp, "\t%s -G -o fmt\n", argv0); + fprintf(fp, "\t%s -G -o fmt [-f fqdn]\n", argv0); exit(rv); } static char * -populate_field(const char *src, const char *dft) +populate_str(const char *src, const char *dft) { char *dst; @@ -66,21 +69,48 @@ populate_field(const char *src, const char *dft) dst = strdup(dft); } + if (dst == NULL) { + err(errno, "strdup failed in populate_str"); + } + return dst; } +/* + * Takes a string formatted like 2020-09-03 15:56:17 UTC-04:00 + * and returns a time_t + */ +static time_t +populate_time(char *time_str) +{ + struct tm time_tm; + time_t time = 0; + + if (time_str) { + if (strptime(time_str, "%F %T UTC%z", &time_tm) == NULL) { + err(ERR_TIME, "call to strptime failed"); + } + + if ((time = mktime(&time_tm)) == -1) { + err(ERR_TIME, "call to mktime failed"); + } + } + + return time; +} + int main(int argc, char **argv) { struct db_entry *entry; struct db_index *index; char ch, *author = NULL, *cat = NULL, *desc = NULL, - *fmt = NULL, *pub = NULL, *slug = NULL, + *fmt = NULL, *fqdn = NULL, *pub = NULL, *slug = NULL, *title = NULL, *updated = NULL; argv0 = basename(argv[0]); - while ((ch = getopt(argc, argv, "AGVa:c:d:ho:p:s:t:u:v")) != -1) { + while ((ch = getopt(argc, argv, "AGVa:c:d:f:ho:p:s:t:u:v")) != -1) { switch (ch) { case 'A': if (mode != NONE) { @@ -122,6 +152,13 @@ main(int argc, char **argv) } desc = optarg; break; + case 'f': + if (mode != GENERATE) { + warnx("specifying -f without -G makes no sense"); + usage(ERR_ARGS); + } + fqdn = optarg; + break; case 'h': usage(ERR_NONE); break; @@ -204,13 +241,13 @@ main(int argc, char **argv) switch (mode) { case ADD: - entry->author = populate_field(author, ""); - entry->category = populate_field(cat, ""); - entry->description = populate_field(desc, ""); - entry->date_published = populate_field(pub, ""); - entry->slug = populate_field(slug, ""); - entry->title = populate_field(title, ""); - entry->date_updated = populate_field(updated, ""); + entry->author = populate_str(author, ""); + entry->category = populate_str(cat, ""); + entry->description = populate_str(desc, ""); + entry->date_published = populate_time(pub); + entry->slug = populate_str(slug, ""); + entry->title = populate_str(title, ""); + entry->date_updated = populate_time(updated); entry->next = NULL; db_entry_add(index, entry); @@ -223,6 +260,20 @@ main(int argc, char **argv) else if (strncmp(fmt, "html", 5) == 0) { html_db_fmt(index); } + else if (strncmp(fmt, "sitemapindex", 13) == 0) { + if (fqdn == NULL) { + warnx("sitemapindex requires fqdn be set with -f"); + break; + } + xml_db_fmt_sitemapindex(fqdn, index); + } + else if (strncmp(fmt, "sitemap", 8) == 0) { + if (fqdn == NULL) { + warnx("sitemap requires fqdn be set with -f"); + break; + } + xml_db_fmt_sitemap(fqdn, index); + } else { warnx("unknown output format: %s", fmt); } diff --git a/db.c b/db.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <time.h> #include "db.h" @@ -20,17 +21,27 @@ static int entrycmp(struct db_entry *e1, struct db_entry *e2); struct db_index * db_index_open(const char *db_path) { - char *dir, *path = malloc(strlen(db_path + 1)); + char *dir, path[strlen(db_path + 1)]; struct stat sb; - struct db_index *index = malloc(sizeof(struct db_index)); + struct db_index *index; struct db_entry *cur_entry = NULL, *next_entry = NULL; - FILE *fp = fopen(db_path, "rb"); + FILE *fp; + + if ((index = malloc(sizeof(struct db_index))) == NULL) { + err(1, "call to malloc failed"); + } strcpy(path, db_path); dir = dirname(path); index->db_path = db_path; index->entries = NULL; + if ((fp = fopen(db_path, "rb")) == NULL) { + warn("failed to open file %s", db_path); + warnx("returning empty index"); + return index; + } + if (stat(dir, &sb)) { err(errno, "failed to stat parent directory %s", dir); } @@ -41,10 +52,6 @@ db_index_open(const char *db_path) goto exit; } - if (fp == NULL) { - err(errno, "failed to open %s for reading", db_path); - } - if ((cur_entry = getentry(fp)) == NULL) { warnx("empty db file: %s", db_path); goto exit; @@ -61,7 +68,6 @@ exit: if (fp != NULL) { fclose(fp); } - free(path); return index; } @@ -87,14 +93,12 @@ db_index_write(struct db_index *index) fwrite(&nul, sizeof(char), 1, fp); fputs(entry->description, fp); fwrite(&nul, sizeof(char), 1, fp); - fputs(entry->date_published, fp); - fwrite(&nul, sizeof(char), 1, fp); + fwrite(&(entry->date_published), sizeof(time_t), 1, fp); fputs(entry->slug, fp); fwrite(&nul, sizeof(char), 1, fp); fputs(entry->title, fp); fwrite(&nul, sizeof(char), 1, fp); - fputs(entry->date_updated, fp); - fwrite(&nul, sizeof(char), 1, fp); + fwrite(&(entry->date_updated), sizeof(time_t), 1, fp); entry = entry->next; } @@ -139,13 +143,11 @@ db_entry_add(struct db_index *index, struct db_entry *entry) } while (cur_entry != NULL) { - int dcmp = strncmp(entry->date_published, - cur_entry->date_published, DATE_STRING_LENGTH); int scmp = strcmp(entry->slug, cur_entry->slug); if (verbose >= 2) { - fprintf(stderr, "DEBUG: dcmp = %d, scmp = %d\n", dcmp, scmp); + fprintf(stderr, "DEBUG: scmp = %d\n", scmp); } - if (dcmp > 0) { + if (entry->date_published > cur_entry->date_published) { if (verbose) { warnx("inserting new entry %s", entry->slug); } @@ -158,7 +160,8 @@ db_entry_add(struct db_index *index, struct db_entry *entry) } break; } - else if ((dcmp == 0) && (scmp == 0)) { + else if ((entry->date_published == cur_entry->date_published) + && (scmp == 0)) { if (!entrycmp(cur_entry, entry)) { warnx("new entry %s matches existing one", entry->slug); break; @@ -193,13 +196,30 @@ db_entry_add(struct db_index *index, struct db_entry *entry) void db_entry_fprint(FILE *fp, struct db_entry *entry) { - fprintf(fp, "\tauthor = %s\n", entry->author); + struct tm *ptm = NULL, *utm = NULL; + char pstring[DATE_STRING_LENGTH], + ustring[DATE_STRING_LENGTH]; + + if ((ptm = gmtime(&(entry->date_published))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(pstring, DATE_STRING_LENGTH, "%FT%TZ", + ptm) == 0) { + errx(1, "failed to convert tm to string"); + } + if ((utm = gmtime(&(entry->date_updated))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(ustring, DATE_STRING_LENGTH, "%FT%TZ", + utm) == 0) { + errx(1, "failed to convert tm to string"); + } fprintf(fp, "\tcategory = %s\n", entry->category); fprintf(fp, "\tdescription = %s\n", entry->description); - fprintf(fp, "\tdate_published = %s\n", entry->date_published); + fprintf(fp, "\tdate_published = %s\n", pstring); fprintf(fp, "\tslug = %s\n", entry->slug); fprintf(fp, "\ttitle = %s\n", entry->title); - fprintf(fp, "\tdate_updated = %s\n", entry->date_updated); + fprintf(fp, "\tdate_updated = %s\n", ustring); } static struct db_entry * @@ -215,8 +235,11 @@ getentry(FILE *fp) return NULL; } - entry = malloc(sizeof(struct db_entry)); - entry->author = str; + if ((entry = malloc(sizeof(struct db_entry))) == NULL) { + err(errno, "call to malloc failed"); + } + + entry->author = str; if ((entry->category = getstring(fp)) == NULL) { errx(1, "index db file corrupt!"); @@ -224,7 +247,7 @@ getentry(FILE *fp) if((entry->description = getstring(fp)) == NULL) { errx(1, "index db file corrupt!"); } - if((entry->date_published = getstring(fp)) == NULL) { + if(fread(&(entry->date_published), sizeof(time_t), 1, fp) == 0) { errx(1, "index db file corrupt!"); } if((entry->slug = getstring(fp)) == NULL) { @@ -233,7 +256,7 @@ getentry(FILE *fp) if((entry->title = getstring(fp)) == NULL) { errx(1, "index db file corrupt!"); } - if((entry->date_updated = getstring(fp)) == NULL) { + if(fread(&(entry->date_updated), sizeof(time_t), 1, fp) == 0) { errx(1, "index db file corrupt!"); } entry->next = NULL; @@ -247,10 +270,8 @@ free_entry(struct db_entry *entry) free(entry->author); free(entry->category); free(entry->description); - free(entry->date_published); free(entry->slug); free(entry->title); - free(entry->date_updated); free(entry); } @@ -281,8 +302,8 @@ entrycmp(struct db_entry *e1, struct db_entry *e2) if ((cmp = strcmp(e1->description, e2->description)) != 0) { return cmp; } - if ((cmp = strcmp(e1->date_published, e2->date_published)) != 0) { - return cmp; + if (e1->date_published != e2->date_published) { + return 1; } if ((cmp = strcmp(e1->slug, e2->slug)) != 0) { return cmp; @@ -290,8 +311,8 @@ entrycmp(struct db_entry *e1, struct db_entry *e2) if ((cmp = strcmp(e1->title, e2->title)) != 0) { return cmp; } - if ((cmp = strcmp(e1->date_updated, e2->date_updated)) != 0) { - return cmp; + if (e1->date_updated != e2->date_updated) { + return 1; } return 0; diff --git a/db.h b/db.h @@ -6,10 +6,10 @@ struct db_entry { char *author; char *category; char *description; - char *date_published; + time_t date_published; char *slug; char *title; - char *date_updated; + time_t date_updated; struct db_entry *next; }; diff --git a/html.c b/html.c @@ -1,11 +1,15 @@ /* See LICENSE file for copyright and license details */ +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "db.h" #include "string.h" +static const int DATE_STRING_LENGTH = 30; /* TODO: use decl in db.c */ + static void htmlescape(char *s); void @@ -15,10 +19,18 @@ html_db_fmt(struct db_index *index) struct db_entry *entry = index->entries; while (entry != NULL) { - char *date = strdup(entry->date_published); - char *title = strdup(entry->title); + struct tm *pub_tm = NULL; + char pub[DATE_STRING_LENGTH]; + + if ((pub_tm = gmtime(&(entry->date_published))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(pub, DATE_STRING_LENGTH, "%F", pub_tm) == 0) { + errx(1, "call to strftime failed"); + } - date[10] = '\0'; /* only interested in YYYY-MM-DD */ + char *date = strdup(pub); + char *title = strdup(entry->title); htmlescape(date); htmlescape(title); diff --git a/xml.c b/xml.c @@ -1,36 +1,105 @@ /* See LICENSE file for copyright and license details */ +#include <err.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <time.h> #include "db.h" #include "string.h" +static const int DATE_STRING_LENGTH = 30; /* TODO: use decl in db.c */ + static void xmlescape(char *s); void -html_db_fmt(struct db_index *index) +xml_db_fmt_sitemapindex(char *fqdn, struct db_index *index) { - puts("<table>"); - struct db_entry *entry = index->entries; + struct stat sb; + struct tm *time_tm; + char mod[DATE_STRING_LENGTH], *xfqdn = strdup(fqdn); - while (entry != NULL) { - char *date = strdup(entry->date_published); - char *title = strdup(entry->title); + if (stat(index->db_path, &sb) == -1) { + err(errno, "unable to stat %s", index->db_path); + } + if ((time_tm = gmtime(&(sb.st_mtim.tv_sec))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(mod, DATE_STRING_LENGTH, "%FT%TZ", time_tm) == 0) { + errx(1, "call to strftime failed"); + } - date[10] = '\0'; /* only interested in YYYY-MM-DD */ + xmlescape(mod); + xmlescape(xfqdn); - htmlescape(date); - htmlescape(title); + puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + puts("<sitemapindex"); + puts(" xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\""); + puts(" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\""); + puts(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); + puts(" xsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9"); + puts(" http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\">"); + puts("<sitemap>"); + printf(" <loc>%s/sitemap.xml</loc>\n", xfqdn); + printf(" <lastmod>%s</lastmod>\n", mod); + puts("</sitemap>"); + puts("</sitemapindex>"); - printf("<tr><td><time>%s</time></td>", date); - printf("<td><a href=\"/%s\">%s</a></td></tr>\n", entry->slug, title); - entry = entry->next; + free(xfqdn); +} + +void +xml_db_fmt_sitemap(char *fqdn, struct db_index *index) +{ + struct db_entry *entry = index->entries; + char *xfqdn = strdup(fqdn); + struct tm *tmp_tm; + char upd[DATE_STRING_LENGTH], pub[DATE_STRING_LENGTH]; + + xmlescape(xfqdn); - free(date); - free(title); + puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + puts("<urlset"); + puts(" xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\""); + puts(" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\""); + puts(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); + puts(" xsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9"); + puts(" http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\">"); + while (entry != NULL) { + if ((tmp_tm = gmtime(&(entry->date_published))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(pub, DATE_STRING_LENGTH, "%FT%TZ", tmp_tm) == 0) { + errx(1, "call to strftime failed"); + } + if ((tmp_tm = gmtime(&(entry->date_updated))) == NULL) { + errx(1, "call to gmtime failed"); + } + if (strftime(upd, DATE_STRING_LENGTH, "%FT%TZ", tmp_tm) == 0) { + errx(1, "call to strftime failed"); + } + puts("<url>"); + printf(" <loc>%s/%s</loc>\n", xfqdn, entry->slug); + if (entry->date_updated) { + printf(" <lastmod>%s</lastmod>\n", upd); + } + else { + printf(" <lastmod>%s</lastmod>\n", pub); + } + puts("</url>"); + entry = entry->next; } - puts("</table>"); + puts("</urlset>"); + + free(xfqdn); +} + +void +xml_db_fmt_rss(struct db_index *index) +{ + index = NULL; } static void diff --git a/xml.h b/xml.h @@ -2,8 +2,8 @@ #ifndef __XML_H #define __XML_H -void xml_db_fmt_sitemapindex(struct db_index *index); -void xml_db_fmt_sitemap(struct db_index *index); -void xml_db_fmt_rss(struct db_index *index); +void xml_db_fmt_sitemapindex(char *fqdn, struct db_index *index); +void xml_db_fmt_sitemap(char *fqdn, struct db_index *index); +void xml_db_fmt_rss(char *fqdn, struct db_index *index); #endif