about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--encode.c34
-rw-r--r--gemtext.c12
-rw-r--r--gemtext.h10
-rw-r--r--gemtext_encode.339
-rw-r--r--gemtext_type.318
-rw-r--r--html.c303
7 files changed, 391 insertions, 27 deletions
diff --git a/Makefile b/Makefile
index 452443d..22e6c93 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ TARGET_LIB_STATIC = libgemtext.a
 
 PREFIX = /usr
 
-OBJS = decode.o encode.o free.o gemtext.o gemtext_list.o strlcat.o strlcpy.o
+OBJS = decode.o encode.o html.o free.o gemtext.o gemtext_list.o strlcat.o strlcpy.o
 MANPAGES = gemtext_decode.3 gemtext_encode.3 gemtext_free.3\
            gemtext_text_new.3 gemtext_text_string.3 gemtext_type.3\
            gemtext_list_append.3
diff --git a/encode.c b/encode.c
index dc13d23..75afb18 100644
--- a/encode.c
+++ b/encode.c
@@ -23,7 +23,7 @@ _case_link(struct gemtext *t)
 {
 	struct gemtext_link *link;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	link = (struct gemtext_link *)t;
@@ -55,7 +55,7 @@ _case_pre(struct gemtext *t)
 {
 	struct gemtext_pre *pre;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	pre = (struct gemtext_pre *)t;
@@ -81,7 +81,7 @@ _case_h1(struct gemtext *t)
 {
 	struct gemtext_h1 *h1;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	h1 = (struct gemtext_h1 *)t;
@@ -105,7 +105,7 @@ _case_h2(struct gemtext *t)
 {
 	struct gemtext_h2 *h2;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	h2 = (struct gemtext_h2 *)t;
@@ -129,7 +129,7 @@ _case_h3(struct gemtext *t)
 {
 	struct gemtext_h3 *h3;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	h3 = (struct gemtext_h3 *)t;
@@ -154,7 +154,7 @@ _case_ul(struct gemtext *t)
 {
 	struct gemtext_ul *ul;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	ul = (struct gemtext_ul *)t;
@@ -178,7 +178,7 @@ _case_qt(struct gemtext *t)
 {
 	struct gemtext_qt *qt;
 	char *ret;
-	int retlen;
+	size_t retlen;
 
 	retlen = 0;
 	qt = (struct gemtext_qt *)t;
@@ -198,9 +198,9 @@ _case_qt(struct gemtext *t)
 }
 
 static char *
-_line_append(char *dst, const char *src, int *len)
+_line_append(char *dst, const char *src, size_t *len)
 {
-	int rlen;
+	size_t rlen;
 	char *ret;
 
 	rlen = *len;
@@ -223,7 +223,7 @@ _line_append(char *dst, const char *src, int *len)
 }
 
 int
-gemtext_encode(struct gemtext *line, char **text, int *len)
+gemtext_encode(struct gemtext *line, char **text, size_t *len)
 {
 	switch (line->type) {
 	case GEMTEXT_TEXT:
@@ -292,7 +292,7 @@ int
 gemtext_encode_fd(struct gemtext *line, int fd)
 {
 	char *text;
-	int len;
+	size_t len;
 	int ecode;
 
 	if (gemtext_encode(line, &text, &len) == -1)
@@ -325,11 +325,11 @@ gemtext_encode_file(struct gemtext *line, const char *path)
 }
 
 int
-gemtext_list_encode(struct gemtext **list, char **text, int *len)
+gemtext_list_encode(struct gemtext **list, char **text, size_t *len)
 {
 	int i;
-	int encbuflen;
-	int retbuflen;
+	size_t encbuflen;
+	size_t retbuflen;
 	char *encbuf;
 	char *appbuf;
 	char *retbuf;
@@ -362,7 +362,7 @@ int
 gemtext_list_encode_fd(struct gemtext **list, int fd)
 {
 	char *text;
-	int len;
+	size_t len;
 	int ecode;
 
 	if (gemtext_list_encode(list, &text, &len) == -1)
@@ -382,9 +382,11 @@ gemtext_list_encode_file(struct gemtext **list, const char *path)
 	int fd;
 	int ecode;
 
-	fd = open(path, O_WRONLY);
+	fd = open(path, O_WRONLY|O_TRUNC|O_CREAT);
 	if (fd == -1)
 		return -1;
+	/* file does not have to be owned by user, so errors are expected */
+	fchmod(fd, 0644);
 
 	ecode = gemtext_list_encode_fd(list, fd);
 	close(fd);
diff --git a/gemtext.c b/gemtext.c
index 79e6c84..40d8bac 100644
--- a/gemtext.c
+++ b/gemtext.c
@@ -178,6 +178,14 @@ gemtext_type(struct gemtext *t)
 	return t->type;
 }
 
+int
+gemtext_link_has_label(struct gemtext *t)
+{
+	if (((struct gemtext_link *)t)->name)
+		return 1;
+	return 0;
+}
+
 char *
 gemtext_text_string(struct gemtext *t)
 {
@@ -247,7 +255,9 @@ gemtext_link_link_strlen(struct gemtext *t)
 size_t
 gemtext_link_label_strlen(struct gemtext *t)
 {
-	return strlen(((struct gemtext_link *)t)->name);
+	if (gemtext_link_has_label(t))
+		return strlen(((struct gemtext_link *)t)->name);
+	return 0;
 }
 
 size_t
diff --git a/gemtext.h b/gemtext.h
index 06f27ea..809e7c6 100644
--- a/gemtext.h
+++ b/gemtext.h
@@ -67,13 +67,18 @@ struct gemtext **gemtext_list_decode_fd(int);
 struct gemtext **gemtext_list_decode_file(const char *);
 
 /* encode.c */
-int gemtext_encode(struct gemtext *, char **, int *);
+int gemtext_encode(struct gemtext *, char **, size_t *);
 int gemtext_encode_fd(struct gemtext *, int);
 int gemtext_encode_file(struct gemtext *, const char *);
-int gemtext_list_encode(struct gemtext **, char **, int *);
+int gemtext_list_encode(struct gemtext **, char **, size_t *);
 int gemtext_list_encode_fd(struct gemtext **, int);
 int gemtext_list_encode_file(struct gemtext **, const char *);
 
+/* html.c */
+int gemtext_list_encode_to_html(struct gemtext **, char **, size_t *);
+int gemtext_list_encode_to_html_fd(struct gemtext **, int);
+int gemtext_list_encode_to_html_file(struct gemtext **, const char *);
+
 /* gemtext.c */
 struct gemtext *gemtext_text_new(const char *);
 struct gemtext *gemtext_link_new(const char *, const char *);
@@ -84,6 +89,7 @@ struct gemtext *gemtext_h3_new(const char *);
 struct gemtext *gemtext_ul_new(const char *);
 struct gemtext *gemtext_qt_new(const char *);
 int gemtext_type(struct gemtext *);
+int gemtext_link_has_label(struct gemtext *);
 char *gemtext_text_string(struct gemtext *);
 char *gemtext_link_link_string(struct gemtext *);
 char *gemtext_link_label_string(struct gemtext *);
diff --git a/gemtext_encode.3 b/gemtext_encode.3
index 046d21e..28fb5cc 100644
--- a/gemtext_encode.3
+++ b/gemtext_encode.3
@@ -15,7 +15,7 @@
 .Fo gemtext_encode
 .Fa "struct gemtext *line"
 .Fa "char **textptr"
-.Fa "int *lenptr"
+.Fa "size_t *lenptr"
 .Fc
 .Ft int
 .Fo gemtext_encode_fd
@@ -31,7 +31,7 @@
 .Fo gemtext_list_encode
 .Fa "struct gemtext **list"
 .Fa "char **textptr"
-.Fa "int *lenptr"
+.Fa "size_t *lenptr"
 .Fc
 .Ft int
 .Fo gemtext_list_encode_fd
@@ -43,6 +43,22 @@
 .Fa "struct gemtext **list"
 .Fa "const char *path"
 .Fc
+.Ft int
+.Fo gemtext_list_encode_to_html
+.Fa "struct gemtext **list"
+.Fa "char **textptr"
+.Fa "size_t *lenptr"
+.Fc
+.Ft int
+.Fo gemtext_list_encode_to_html_fd
+.Fa "struct gemtext **list"
+.Fa "int fd"
+.Fc
+.Ft int
+.Fo gemtext_list_encode_to_html_file
+.Fa "struct gemtext **list"
+.Fa "const char *path"
+.Fc
 .Sh DESCRIPTION
 .Fn gemtext_encode
 encodes
@@ -52,7 +68,7 @@ to
 and sets pointer pointed to by
 .Em textptr
 to the encoded text and sets
-.Em int
+.Em size_t
 pointed to by
 .Em lenptr
 to the size of the encoded text excluding terminating NULL byte, this can be discarded by setting
@@ -88,14 +104,27 @@ behave the same as the
 family of functions, except they operate on a list of
 .Em struct gemtext*
 terminated by a NULL pointer.
+.Pp
+.Fn gemtext_list_encode_to_html ,
+.Fn gemtext_list_encode_to_html_fd
+and
+.Fn gemtext_list_encode_to_html_file
+behave the same as the
+.Fn gemtext_list_encode
+family of functions, except the output provided in
+.Em textptr
+is formatted in HTML instead of gemtext.
 .Sh RETURN VALUES
 .Fn gemtext_encode ,
 .Fn gemtext_encode_fd ,
 .Fn gemtext_encode_file ,
 .Fn gemtext_list_encode ,
-.Fn gemtext_list_encode_fd
+.Fn gemtext_list_encode_fd ,
+.Fn gemtext_list_encode_file ,
+.Fn gemtext_list_encode_to_html ,
+.Fn gemtext_list_encode_to_html_fd
 and
-.Fn gemtext_list_encode_file
+.Fn gemtext_list_encode_to_html_file
 all return
 .Em 0
 on success or
diff --git a/gemtext_type.3 b/gemtext_type.3
index 32ec3b9..34436c0 100644
--- a/gemtext_type.3
+++ b/gemtext_type.3
@@ -2,16 +2,30 @@
 .Dt gemtext 3
 .Os
 .Sh NAME
-.Nm gemtext_type
-.Nd show gemtext line type
+.Nm gemtext_type ,
+.Nm gemtext_link_has_label
+.Nd read information from gemtext objects
 .Sh SYNOPSIS
 .In gemtext.h
 .Ft int
 .Fn gemtext_type "struct gemtext *line"
+.Ft int
+.Fn gemtext_link_has_label "struct gemtext *line"
 .Sh DESCRIPTION
 .Fn gemtext_type
 returns the type of gemtext object specified in
 .Em line .
+.Pp
+.Fn gemtext_link_has_label
+operates under the assumption that
+.Em line
+is of type
+.Em GEMTEXT_LINK
+and returns non-zero if link object contained in
+.Em line
+has a label, or
+.Em 0
+if it doesn't.
 .Sh TYPES
 This is a list of all possible return values for
 .Fn gemtext_type :
diff --git a/html.c b/html.c
new file mode 100644
index 0000000..1f78adb
--- /dev/null
+++ b/html.c
@@ -0,0 +1,303 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gemtext.h"
+
+static int
+_case_text(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_text_strlen(line);
+	*outlen += 7; /* <p></p> */
+
+	app = realloc(*out, (*outlen+1));
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<p>", (*outlen+1));
+	strlcat(*out, gemtext_text_string(line), (*outlen)+1);
+	strlcat(*out, "</p>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_link(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_link_link_strlen(line);
+	*outlen += gemtext_link_label_strlen(line);
+	*outlen += 22; /* <p><a href=""></a></p> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<p><a href=\"", (*outlen)+1);
+	strlcat(*out, gemtext_link_link_string(line), (*outlen)+1);
+	strlcat(*out, "\">", (*outlen)+1);
+	if (gemtext_link_has_label(line))
+		strlcat(*out, gemtext_link_label_string(line), (*outlen)+1);
+	strlcat(*out, "</a></p>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_pre(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_pre_strlen(line);
+	*outlen += 18; /* <p><pre></pre></p> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<p><pre>", (*outlen)+1);
+	strlcat(*out, gemtext_pre_string(line), (*outlen)+1);
+	strlcat(*out, "</pre></p>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_h1(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_h1_strlen(line);
+	*outlen += 9; /* <h1></h1> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<h1>", (*outlen)+1);
+	strlcat(*out, gemtext_h1_string(line), (*outlen)+1);
+	strlcat(*out, "</h1>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_h2(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_h2_strlen(line);
+	*outlen += 9; /* <h2></h2> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<h2>", (*outlen)+1);
+	strlcat(*out, gemtext_h2_string(line), (*outlen)+1);
+	strlcat(*out, "</h2>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_h3(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_h3_strlen(line);
+	*outlen += 9; /* <h3></h3> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<h3>", (*outlen)+1);
+	strlcat(*out, gemtext_h3_string(line), (*outlen)+1);
+	strlcat(*out, "</h3>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_ul(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_ul_strlen(line);
+	*outlen += 9; /* <li></li> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<li>", (*outlen)+1);
+	strlcat(*out, gemtext_ul_string(line), (*outlen)+1);
+	strlcat(*out, "</li>", (*outlen)+1);
+
+	return 0;
+}
+
+static int
+_case_qt(struct gemtext *line, char **out, size_t *outlen)
+{
+	char *app;
+
+	*outlen += gemtext_qt_strlen(line);
+	*outlen += 25; /* <blockquote></blockquote> */
+
+	app = realloc(*out, (*outlen)+1);
+	if (app == NULL)
+		return -1;
+	*out = app;
+
+	strlcat(*out, "<blockquote>", (*outlen)+1);
+	strlcat(*out, gemtext_qt_string(line), (*outlen)+1);
+	strlcat(*out, "</blockquote>", (*outlen)+1);
+
+	return 0;
+}
+
+int
+gemtext_list_encode_to_html(struct gemtext **list, char **out, size_t *outlen)
+{
+	char *app;
+	int i;
+	int ulindic;
+
+	*out = NULL;
+	*outlen = 0;
+	ulindic = 0;
+
+	*out = malloc(1);
+	if (*out == NULL)
+		return -1;
+	*out[0] = '\0'; /* for strlcat() */
+
+	for (i = 0; list[i] != NULL; i++) {
+		if (gemtext_type(list[i]) != GEMTEXT_UL && ulindic) {
+			*outlen += 5; /* </ul> */
+			app = realloc(*out, (*outlen)+1);
+			if (app == NULL) {
+				free(*out);
+				return -1;
+			}
+			*out = app;
+			strlcat(*out, "</ul>", (*outlen)+1);
+			ulindic = 0;
+		}
+		switch (gemtext_type(list[i])) {
+		case GEMTEXT_TEXT:
+			if (_case_text(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_LINK:
+			if (_case_link(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_PRE:
+			if (_case_pre(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H1:
+			if (_case_h1(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H2:
+			if (_case_h2(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H3:
+			if (_case_h3(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_UL:
+			if (!ulindic) {
+				*outlen += 4; /* <ul> */
+				app = realloc(*out, (*outlen)+1);
+				if (app == NULL) {
+					free(*out);
+					return -1;
+				}
+				*out = app;
+				strlcat(*out, "<ul>", (*outlen)+1);
+				ulindic = 1;
+			}
+			if (_case_ul(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		case GEMTEXT_QT:
+			if (_case_qt(list[i], out, outlen) == -1) {
+				free(*out);
+				return -1;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int
+gemtext_list_encode_to_html_fd(struct gemtext **list, int fd)
+{
+	char *out;
+	size_t len;
+
+	if (gemtext_list_encode_to_html(list, &out, &len) == -1)
+		return -1;
+	if (write(fd, out, len) == -1) {
+		free(out);
+		return -1;
+	}
+	free(out);
+
+	return 0;
+}
+
+int
+gemtext_list_encode_to_html_file(struct gemtext **list, const char *file)
+{
+	int fd;
+
+	fd = open(file, O_WRONLY|O_TRUNC|O_CREAT);
+	if (fd == -1)
+		return -1;
+	/* file does not have to be owned by user, so errors are expected */
+	fchmod(fd, 0644);
+	if (gemtext_list_encode_to_html_fd(list, fd) == -1) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	return 0;
+}