summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAli Fardan <raiz@stellarbound.space>2020-11-04 07:24:41 +0300
committerAli Fardan <raiz@stellarbound.space>2020-11-04 07:24:41 +0300
commit7ddf10843fa6c5247a809824344d391d7729fc73 (patch)
tree4f92887ceedc05f9600ed15dece5c1184b37801e
parent7922a3ee3743d9b707010bcf5a886df982cbc15e (diff)
downloadgemlog-7ddf10843fa6c5247a809824344d391d7729fc73.tar.gz
html write html generator
-rw-r--r--Makefile2
-rw-r--r--gemlog.h4
-rw-r--r--html.c256
-rw-r--r--main.c40
4 files changed, 283 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 9694799..100e062 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ OUT = gemlog
 
 PREFIX = /usr
 
-OBJS = gemlog.o free.o main.o strlcpy.o strlcat.o
+OBJS = gemlog.o html.o free.o main.o strlcpy.o strlcat.o
 MANPAGES = 
 
 all: $(OUT)
diff --git a/gemlog.h b/gemlog.h
index 7c84039..e74058b 100644
--- a/gemlog.h
+++ b/gemlog.h
@@ -1,5 +1,6 @@
 #define GEMLOG_TITLE_FILENAME "title"
 #define GEMLOG_CONTENT_FILENAME "content.gmi"
+#define GEMLOG_CONTENT_HTML_FILENAME "content.html"
 
 struct gemlog_entry {
 	char *title;
@@ -16,6 +17,9 @@ size_t strlcat(char *, const char *, size_t);
 /* gemlog.c */
 struct gemlog_entry **gemlog_readdir(const char *);
 
+/* html.c */
+int gemlog_write_html(struct gemlog_entry **, const char *);
+
 /* free.c */
 void gemlog_entry_free(struct gemlog_entry *);
 void gemlog_entry_list_free(struct gemlog_entry **);
diff --git a/html.c b/html.c
new file mode 100644
index 0000000..fa83f2c
--- /dev/null
+++ b/html.c
@@ -0,0 +1,256 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <gemtext.h>
+
+#include "gemlog.h"
+
+/* TODO: allow user to specify custom header/footer */
+#define HTML_HEADER_BEGIN "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"
+#define HTML_HEADER_END   "</head><body>"
+#define HTML_FOOTER       "</body></html>"
+
+static int
+gemlog_write_html_text(struct gemtext *text, int fd)
+{
+	if (write(fd, "<p>", strlen("<p>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_text *)text)->text, strlen(((struct gemtext_text *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</p>\n", strlen("</p>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_link(struct gemtext *text, int fd)
+{
+	if (write(fd, "<p><a href=\"", strlen("<p><a href=\"")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_link *)text)->link, strlen(((struct gemtext_link *)text)->link)) == -1)
+		return -1;
+	if (write(fd, "\">", strlen("\">")) == -1)
+		return -1;
+	if (((struct gemtext_link *)text)->name) {
+		if (write(fd, ((struct gemtext_link *)text)->name, strlen(((struct gemtext_link *)text)->name)) == -1)
+			return -1;
+	}
+	if (write(fd, "</a></p>\n", strlen("</a></p>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_pre(struct gemtext *text, int fd)
+{
+	if (write(fd, "<p><pre>", strlen("<p><pre>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_pre *)text)->text, strlen(((struct gemtext_pre *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</pre></p>\n", strlen("</pre></p>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_h1(struct gemtext *text, int fd)
+{
+	if (write(fd, "<h1>", strlen("<h1>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_h1 *)text)->text, strlen(((struct gemtext_h1 *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</h1>\n", strlen("</h1>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_h2(struct gemtext *text, int fd)
+{
+	if (write(fd, "<h2>", strlen("<h2>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_h2 *)text)->text, strlen(((struct gemtext_h2 *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</h2>\n", strlen("</h2>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_h3(struct gemtext *text, int fd)
+{
+	if (write(fd, "<h3>", strlen("<h3>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_h3 *)text)->text, strlen(((struct gemtext_h3 *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</h3>\n", strlen("</h3>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_ul(struct gemtext *text, int fd)
+{
+	if (write(fd, "<li>", strlen("<li>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_ul *)text)->text, strlen(((struct gemtext_ul *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</li>\n", strlen("</li>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+static int
+gemlog_write_html_qt(struct gemtext *text, int fd)
+{
+	if (write(fd, "<blockquote>", strlen("<blockquote>")) == -1)
+		return -1;
+	if (write(fd, ((struct gemtext_qt *)text)->text, strlen(((struct gemtext_qt *)text)->text)) == -1)
+		return -1;
+	if (write(fd, "</blockquote>\n", strlen("</blockquote>\n")) == -1)
+		return -1;
+	return 0;
+}
+
+int
+gemlog_write_html(struct gemlog_entry **feed, const char *path)
+{
+	int i;
+	int x;
+	int ulindicator;
+	int fd;
+	char pathbuf[PATH_MAX+1];
+	char fmtbuf[PATH_MAX+1];
+
+	if (mkdir(path, 0755) == -1) {
+		if (errno != EEXIST)
+			return -1;
+	}
+
+	for (i = 0; feed[i] != NULL; i++) {
+		strlcpy(pathbuf, path, sizeof(pathbuf));
+		strlcat(pathbuf, "/", sizeof(pathbuf));
+		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_year+1900);
+		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
+		if (mkdir(pathbuf, 0755) == -1) {
+			if (errno != EEXIST)
+				return -1;
+		}
+
+		strlcat(pathbuf, "/", sizeof(pathbuf));
+		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_mon+1);
+		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
+		if (mkdir(pathbuf, 0755) == -1) {
+			if (errno != EEXIST)
+				return -1;
+		}
+
+		strlcat(pathbuf, "/", sizeof(pathbuf));
+		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_mday);
+		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
+		if (mkdir(pathbuf, 0755) == -1) {
+			if (errno != EEXIST)
+				return -1;
+		}
+
+		strlcat(pathbuf, "/", sizeof(pathbuf));
+		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_hour);
+		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
+		if (mkdir(pathbuf, 0755) == -1) {
+			if (errno != EEXIST)
+				return -1;
+		}
+
+		strlcat(pathbuf, "/", sizeof(pathbuf));
+		strlcat(pathbuf, GEMLOG_CONTENT_HTML_FILENAME, sizeof(pathbuf));
+		fd = open(pathbuf, O_WRONLY|O_CREAT|O_TRUNC);
+		if (fd == -1)
+			return -1;
+		if (chmod(pathbuf, 0644) == -1) {
+			close(fd);
+			return -1;
+		}
+
+		/* write header */
+		if (write(fd, HTML_HEADER_BEGIN, strlen(HTML_HEADER_BEGIN)) == -1) {
+			close(fd);
+			return -1;
+		}
+		if (write(fd, "<title>", strlen("<title>")) == -1) {
+			close(fd);
+			return -1;
+		}
+		if (write(fd, feed[i]->title, strlen(feed[i]->title)) == -1) {
+			close(fd);
+			return -1;
+		}
+		if (write(fd, "</title>", strlen("</title>")) == -1) {
+			close(fd);
+			return -1;
+		}
+		if (write(fd, HTML_HEADER_END, strlen(HTML_HEADER_END)) == -1) {
+			close(fd);
+			return -1;
+		}
+
+		ulindicator = 0;
+		for (x = 0; feed[i]->content[x] != NULL; x++) {
+			if (ulindicator) {
+				if (gemtext_type(feed[i]->content[x]) != GEMTEXT_UL) {
+					if (write(fd, "</ul>\n", strlen("</ul>\n")) == -1) {
+						close(fd);
+						return -1;
+					}
+					ulindicator = 0;
+				}
+			}
+			switch (gemtext_type(feed[i]->content[x])) {
+			case GEMTEXT_TEXT:
+				gemlog_write_html_text(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_LINK:
+				gemlog_write_html_link(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_PRE:
+				gemlog_write_html_pre(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_H1:
+				gemlog_write_html_h1(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_H2:
+				gemlog_write_html_h2(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_H3:
+				gemlog_write_html_h3(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_UL:
+				if (!ulindicator) {
+					if (write(fd, "<ul>\n", strlen("<ul>\n")) == -1) {
+						close(fd);
+						return -1;
+					}
+					ulindicator = 1;
+				}
+				gemlog_write_html_ul(feed[i]->content[x], fd);
+				break;
+			case GEMTEXT_QT:
+				gemlog_write_html_qt(feed[i]->content[x], fd);
+				break;
+			default:
+				close(fd);
+				return -1;
+			}
+		}
+		close(fd);
+	}
+
+	return 0;
+}
diff --git a/main.c b/main.c
index 1d4577f..713fcae 100644
--- a/main.c
+++ b/main.c
@@ -14,8 +14,8 @@ _print_gemlog(struct gemlog_entry **list)
 	char timestamp[50];
 
 	for (i = 0; list[i] != NULL; i++) {
-		strftime(timestamp, sizeof(timestamp), "%F: ", &(list[i]->date));
-		printf("%s%s\n", timestamp, list[i]->title);
+		strftime(timestamp, sizeof(timestamp), "%F", &(list[i]->date));
+		printf("%s %d: %s\n", timestamp, list[i]->date.tm_hour, list[i]->title);
 	}
 }
 
@@ -23,35 +23,29 @@ int
 main(int argc, char *argv[])
 {
 	struct gemlog_entry **log;
-	int aflag;
-	int hflag;
+	char *aflag;
+	char *hflag;
 	int ch;
 
-	aflag = 0;
-	hflag = 0;
+	aflag = NULL;
+	hflag = NULL;
 
-	while ((ch = getopt(argc, argv, "ah")) != -1) {
+	while ((ch = getopt(argc, argv, "a:h:")) != -1) {
 		switch (ch) {
 		case 'a':
-			aflag = 1;
+			aflag = optarg;
 			break;
 		case 'h':
-			hflag = 1;
+			hflag = optarg;
 			break;
 		default:
-			fprintf(stderr, "Usage: %s <-a | -h> <path>\n", argv[0]);
+			fprintf(stderr, "Usage: %s [-a file] [-h path] path\n", argv[0]);
 			return 1;
 		}
 	}
 
-	if (aflag && hflag)
-		errx(1, "can't have -a and -h used simultaneously");
-	if (!aflag && !hflag) {
-		fprintf(stderr, "Usage: %s <-a | -h> <path>\n", argv[0]);
-		return 1;
-	}
 	if (optind >= argc) {
-		fprintf(stderr, "Usage: %s <-a | -h> <path>\n", argv[0]);
+		fprintf(stderr, "Usage: %s [-a file] [-h path] path\n", argv[0]);
 		return 1;
 	}
 
@@ -59,7 +53,17 @@ main(int argc, char *argv[])
 	if (log == NULL)
 		err(1, "gemlog_readdir");
 
-	_print_gemlog(log);
+	if (!aflag && !hflag)
+		_print_gemlog(log);
+
+//	if (aflag) {
+//		if (gemlog_write_atom(log, aflag) == -1)
+//			err(1, "gemlog_write_atom");
+//	}
+	if (hflag) {
+		if (gemlog_write_html(log, hflag) == -1)
+			err(1, "gemlog_write_html");
+	}
 
 	gemlog_entry_list_free(log);
 	return 0;