about summary refs log blame commit diff stats
path: root/encode.c
blob: e8674ad02cd0cb8bb45ff1003b860fbbb60e3de8 (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;
	if (dst == NULL)
		/* this ensures that the first byte strlcat()
		 * encounters is a null byte */
		memset(ret, 0, rlen+1);

	strlcat(ret, src, rlen+1);
	strlcat(ret, "\n", rlen+1);

	*len = rlen;
	return ret;
}

int
gemtext_encode(struct gemtext *line, char **text, int *len)
{
	switch (line->type) {
	case GEMTEXT_TEXT:
		*text = _case_text(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_LINK:
		*text = _case_link(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_PRE:
		*text = _case_pre(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_H1:
		*text = _case_h1(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_H2:
		*text = _case_h2(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_H3:
		*text = _case_h3(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_UL:
		*text = _case_ul(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	case GEMTEXT_QT:
		*text = _case_qt(line);
		if (*text == NULL)
			return -1;
		*len = strlen(*text);
		return 0;
	}

	/* NOT REACHED */
	return -1;
}

int
gemtext_encode_fd(struct gemtext *line, int fd)
{
	char *text;
	int len;
	int ecode;

	if (gemtext_encode(line, &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 *line, const char *path)
{
	int fd;
	int ecode;

	fd = open(path, O_WRONLY);
	if (fd == -1)
		return -1;

	ecode = gemtext_encode_fd(line, fd);
	close(fd);
	if (ecode == -1)
		return -1;

	return 0;
}

int
gemtext_list_encode(struct gemtext **list, char **text, int *len)
{
	int i;
	int encbuflen;
	int retbuflen;
	char *encbuf;
	char *appbuf;
	char *retbuf;

	retbuflen = 0;
	retbuf = NULL;

	for (i = 0; list[i] != NULL; i++) {
		if (gemtext_encode(list[i], &encbuf, &encbuflen) == -1) {
			free(retbuf);
			return -1;
		}
		appbuf = _line_append(retbuf, encbuf, &retbuflen);
		free(encbuf);
		if (appbuf == NULL) {
			free(retbuf);
			return -1;
		}
		retbuf = appbuf;
	}

	*text = retbuf;
	*len = retbuflen;

	return 0;
}


int
gemtext_list_encode_fd(struct gemtext **list, int fd)
{
	char *text;
	int len;
	int ecode;

	if (gemtext_list_encode(list, &text, &len) == -1)
		return -1;

	ecode = write(fd, text, len);
	free(text);
	if (ecode == -1)
		return -1;

	return 0;
}

int
gemtext_list_encode_file(struct gemtext **list, const char *path)
{
	int fd;
	int ecode;

	fd = open(path, O_WRONLY);
	if (fd == -1)
		return -1;

	ecode = gemtext_list_encode_fd(list, fd);
	close(fd);
	if (ecode == -1)
		return -1;

	return 0;
}