about summary refs log tree commit diff stats
path: root/encode.c
diff options
context:
space:
mode:
authorAli Fardan <raiz@stellarbound.info>2020-10-22 13:31:28 +0300
committerAli Fardan <raiz@stellarbound.info>2020-10-22 13:31:28 +0300
commitde22e0ae21c46fc9eb1cc6717832bfb5fa0600e1 (patch)
tree1db412a2eb4974aeda045947db284dd806f021b1 /encode.c
parenta77f42d3c2d19dfa13e0f98935de8f9b59502a6a (diff)
downloadlibgemtext-de22e0ae21c46fc9eb1cc6717832bfb5fa0600e1.tar.gz
- implement the rest of decode.c functions: gemtext_decode_fd() and gemtext_decode_file()
- introduce gemtext_encode() with helper functions gemtext_encode_fd() and gemtext_encode_file()
- simplify handling of unordered lists in decode.c
- add test.c rule to makefile
Diffstat (limited to 'encode.c')
-rw-r--r--encode.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/encode.c b/encode.c
new file mode 100644
index 0000000..efe8aaa
--- /dev/null
+++ b/encode.c
@@ -0,0 +1,365 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gemtext.h"
+
+static char *
+_case_text(struct gemtext *t)
+{
+	struct gemtext_text *text;
+
+	text = (struct gemtext_text *)t;
+
+	return strdup(text->text);
+}
+
+static char *
+_case_link(struct gemtext *t)
+{
+	struct gemtext_link *link;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	link = (struct gemtext_link *)t;
+
+	retlen += strlen(link->link);
+	if (link->name)
+		retlen += strlen(link->name);
+	retlen += 3; /* three characters for "=> " */
+	retlen += 1; /* \0 */
+	if (link->name)
+		retlen += 1; /* additional whitespace separator */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "=> ", retlen);
+	strlcat(ret, link->link, retlen);
+	if (link->name) {
+		strlcat(ret, " ", retlen);
+		strlcat(ret, link->name, retlen);
+	}
+
+	return ret;
+}
+
+static char *
+_case_pre(struct gemtext *t)
+{
+	struct gemtext_pre *pre;
+
+	pre = (struct gemtext_pre *)t;
+
+	return strdup(pre->text);
+}
+
+static char *
+_case_h1(struct gemtext *t)
+{
+	struct gemtext_h1 *h1;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	h1 = (struct gemtext_h1 *)t;
+
+	retlen += strlen(h1->text);
+	retlen += 2; /* two characters for "# " */
+	retlen += 1; /* \0 */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "# ", retlen);
+	strlcat(ret, h1->text, retlen);
+
+	return ret;
+}
+
+static char *
+_case_h2(struct gemtext *t)
+{
+	struct gemtext_h2 *h2;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	h2 = (struct gemtext_h2 *)t;
+
+	retlen += strlen(h2->text);
+	retlen += 3; /* three characters for "## " */
+	retlen += 1; /* \0 */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "## ", retlen);
+	strlcat(ret, h2->text, retlen);
+
+	return ret;
+}
+
+static char *
+_case_h3(struct gemtext *t)
+{
+	struct gemtext_h3 *h3;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	h3 = (struct gemtext_h3 *)t;
+
+	retlen += strlen(h3->text);
+	retlen += 4; /* four characters for "### " */
+	retlen += 1; /* \0 */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "### ", retlen);
+	strlcat(ret, h3->text, retlen);
+
+	return ret;
+}
+
+
+static char *
+_case_ul(struct gemtext *t)
+{
+	struct gemtext_ul *ul;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	ul = (struct gemtext_ul *)t;
+
+	retlen += strlen(ul->text);
+	retlen += 2; /* two characters for "* " */
+	retlen += 1; /* \0 */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "* ", retlen);
+	strlcat(ret, ul->text, retlen);
+
+	return ret;
+}
+
+static char *
+_case_qt(struct gemtext *t)
+{
+	struct gemtext_qt *qt;
+	char *ret;
+	int retlen;
+
+	retlen = 0;
+	qt = (struct gemtext_qt *)t;
+
+	retlen += strlen(qt->text);
+	retlen += 2; /* two characters for *> " */
+	retlen += 1; /* \0 */
+
+	ret = malloc(retlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcpy(ret, "> ", retlen);
+	strlcat(ret, qt->text, retlen);
+
+	return ret;
+}
+
+static char *
+_line_append(char *dst, const char *src, int *len)
+{
+	int rlen;
+	char *ret;
+
+	rlen = *len;
+	rlen += strlen(src);
+	rlen += 1; /* \n */
+
+	ret = realloc(dst, rlen+1);
+	if (ret == NULL)
+		return NULL;
+
+	strlcat(ret, src, rlen+1);
+	strlcat(ret, "\n", rlen+1);
+
+	*len = rlen;
+	return ret;
+}
+
+int
+gemtext_encode(struct gemtext **list, char **text, int *len)
+{
+	int i;
+	int rtextlen;
+	char *rtext;
+	char *retbuf;
+
+	rtextlen = 0;
+	rtext = NULL;
+
+	for (i = 0; list[i] != NULL; i++) {
+		switch (list[i]->type) {
+		case GEMTEXT_TEXT:
+			retbuf = _case_text(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_LINK:
+			retbuf = _case_link(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_PRE:
+			retbuf = _case_pre(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H1:
+			retbuf = _case_h1(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H2:
+			retbuf = _case_h2(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_H3:
+			retbuf = _case_h3(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_UL:
+			retbuf = _case_ul(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		case GEMTEXT_QT:
+			retbuf = _case_qt(list[i]);
+			if (retbuf == NULL) {
+				free(rtext);
+				return -1;
+			}
+			rtext = _line_append(rtext, retbuf, &rtextlen);
+			free(retbuf);
+			if (rtext == NULL) {
+				free(rtext);
+				return -1;
+			}
+			break;
+		}
+	}
+
+	*text = rtext;
+	*len = rtextlen;
+
+	return 0;
+}
+
+
+int
+gemtext_encode_fd(struct gemtext **list, int fd)
+{
+	char *text;
+	int len;
+	int ecode;
+
+	if (gemtext_encode(list, &text, &len) == -1)
+		return -1;
+
+	ecode = write(fd, text, len);
+	if (ecode == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+gemtext_encode_file(struct gemtext **list, const char *path)
+{
+	int fd;
+	int ecode;
+
+	fd = open(path, O_WRONLY);
+	if (fd == -1)
+		return -1;
+
+	ecode = gemtext_encode_fd(list, fd);
+	close(fd);
+	if (ecode == -1)
+		return -1;
+
+	return 0;
+}