about summary refs log blame commit diff stats
path: root/encode.c
blob: 708ac0e2a2236bca8b9b3d1a20e6749043052aa4 (plain) (tree)





















































































































































































































































































































































                                                                       
                   






















                                                            
#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);
	free(text);
	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;
}