~strahinja/poe

6604a5ec32d9102ed35338a8949c0205cb0ebf8a — Страхиња Радић 4 months ago 9b1a6e6
Finish conversion of po.c:save_file to u32_next_line

Signed-off-by: Страхиња Радић <contact@strahinja.org>
10 files changed, 137 insertions(+), 389 deletions(-)

M .gitignore
M config.def.h
M config.h
M draw.c
M draw.h
M po.c
M poe.c
M util.c
M util.h
A wrap_next_line_logic
M .gitignore => .gitignore +2 -0
@@ 1,5 1,6 @@
.cache
.redo
.gdbinit
*.session
.do_built
.do_built.dir


@@ 11,6 12,7 @@
*.swp
*.did
nohup.out
*.err
*.gz
*.xz
*.pdf

M config.def.h => config.def.h +4 -0
@@ 1,4 1,8 @@
/* See the file LICENSE for copyright and license details. */

#define SAVE_WRAP_WIDTH 70
#define WRAP_FIRST_MSGSTR 0

#define DLG_FG				TB_BLACK
#define DLG_BG				TB_WHITE
#define EDIT_MSGID_FG			TB_BLACK | TB_BOLD

M config.h => config.h +4 -0
@@ 1,4 1,8 @@
/* See the file LICENSE for copyright and license details. */

#define SAVE_WRAP_WIDTH 70
#define WRAP_FIRST_MSGSTR 0

#define DLG_FG				TB_BLACK
#define DLG_BG				TB_WHITE
#define EDIT_MSGID_FG			TB_BLACK | TB_BOLD

M draw.c => draw.c +3 -42
@@ 203,45 203,6 @@ set_nplurals(struct DrawState* state, struct PoEntry* entry)
	return state;
}

/*
 * num_lines - number of lines when split; set to 0 to automatically calculate
 * wrap - if >0, also wrap lines
 */
struct BufferLine*
split(const uint32_t* s, const size_t wrap)
{
	if (!s)
		return NULL;

	size_t nlines		   = 0;
	struct BufferLine* newbuf  = NULL;
	struct BufferLine* pnewbuf = NULL;
	const uint32_t* ps	   = s;

	nlines = u32_lines_in_string(s, wrap);
	newbuf = calloc(nlines, sizeof(struct BufferLine));
	if (!newbuf)
		return NULL;

	pnewbuf = newbuf;
	while (*ps)
	{
		uint32_t* newtext = NULL;
		size_t len = 0;

		init_bufferline(pnewbuf);
		len = u32_next_line(s, &ps, wrap);
		newtext = calloc(len, sizeof(uint32_t));
		if (!newtext)
			return NULL;
		pnewbuf->text = newtext;
		pnewbuf->length = len;
		pnewbuf++;
	}

	return newbuf;
}

/* Calculates display length of an input buffer line.
 * max_index = the input index up to which the length is calculated
 */


@@ 667,7 628,7 @@ draw_editbox(const struct DrawState* state)
			u32_draw_string(startx + 1, starty + 1 + i,
				curline->fg == 0 ? fg : curline->fg,
				curline->bg == 0 ? bg : curline->bg,
				curline->text, w - 1, w - 1, 1, 1, LEFT,
				curline->text, w - 2, w - 2, 1, 1, LEFT,
				state->info_first_shown_column, 1, NULL, 0, 0);
	}



@@ 695,7 656,7 @@ draw_editbox(const struct DrawState* state)
		dlen = display_length(state, curline->text, curline->length);
		if (dlen > state->input_first_shown_column)
			u32_draw_string(startx + 1, endy - h / 2 - 1 + i, fg,
				bg, curline->text, w - 1, w - 1, 1, 1, LEFT,
				bg, curline->text, w - 2, w - 2, 1, 1, LEFT,
				state->input_first_shown_column, 1, NULL, 0, 0);
	}



@@ 794,7 755,7 @@ draw_status(const struct DrawState* state)
				pseg->callback(buf, MAXBUFLINE, pseg->format,
					state);
			else
				strncpy(buf, pseg->format, MAXBUFLINE-1);
				strncpy(buf, pseg->format, MAXBUFLINE - 1);
			buf[MAXBUFLINE - 1] = 0;
			if (pseg == status_segments + LEN(status_segments) - 1)
				seg_size = state->maxx - 1 - current_start;

M draw.h => draw.h +1 -2
@@ 91,7 91,7 @@ struct StatusSegment {
	Alignment alignment;
};

extern struct PoEntry entries[];
extern struct PoEntry* entries;

void init_bufferline(struct BufferLine* bl);
void free_bufferline(struct BufferLine* bl);


@@ 99,7 99,6 @@ void init_drawstate(struct DrawState* state, char* error, char* filename,
	char* prompt);
void free_drawstate(struct DrawState* state);
struct DrawState* set_nplurals(struct DrawState* state, struct PoEntry* entry);
struct BufferLine* split(const uint32_t* s, const size_t wrap);
size_t display_length(const struct DrawState* state, uint32_t* buffer,
	const size_t max_index);
size_t input_length(const struct DrawState* state, uint32_t* buffer,

M po.c => po.c +14 -168
@@ 6,6 6,7 @@

#include "po.h"
#include "draw.h"
#include "config.h"
#include "util.h"
#include "version.h"



@@ 592,8 593,8 @@ save_loop_entries_start:
	if (current->msgid)
	{
		size_t msgid_size = current->msgid_size * UTF8REPMAX;
		size_t num_lines
			= u32_lines_in_string(current->msgid, SAVE_WRAP_WIDTH);
		size_t num_lines  = u32_lines_in_string(current->msgid, 1,
			 SAVE_WRAP_WIDTH);
		if (num_lines > 1)
		{
			const uint32_t* pumsgid = current->msgid;


@@ 606,7 607,7 @@ save_loop_entries_start:
				char* u8_msgid		    = NULL;
				const uint32_t* old_pumsgid = pumsgid;

				len = u32_next_line(current->msgid, &pumsgid,
				len = u32_next_line(current->msgid, &pumsgid, 1,
					SAVE_WRAP_WIDTH);
				if (len == 0)
					continue;


@@ 619,38 620,6 @@ save_loop_entries_start:
				fprintf(output, "\"%s\"\n", u8_msgid);
				free(u8_msgid);
			}

			/*
			 *                        struct BufferLine* msgid_split
			 * = split(current->msgid, SAVE_WRAP_WIDTH); struct
			 * BufferLine* pmsgid_split = NULL;
			 *
			 *                        if (!msgid_split)
			 *                                return
			 * SAVE_ERR_CANT_ALLOC;
			 *
			 *                        fprintf(output, "msgid
			 * \"\"\n"); for (size_t i = 0; i < num_lines; i++)
			 *                        {
			 *                                pmsgid_split   =
			 * msgid_split + i; int last       = i == num_lines - 1;
			 *                                char* u8_msgid =
			 * calloc(current->msgid_size, UTF8REPMAX); if
			 * (!u8_msgid) return SAVE_ERR_CANT_ALLOC; size_t len =
			 * u32_strlen(pmsgid_split->text);
			 *                                unicode_string_to_u8(u8_msgid,
			 *                                        pmsgid_split->text,
			 * msgid_size); if (!(last && len == 0)) fprintf(output,
			 * "\"%s\"\n", u8_msgid); free(u8_msgid);
			 *                        }
			 *                        for (size_t i = 0; i <
			 * num_lines; i++)
			 *                        {
			 *                                pmsgid_split =
			 * msgid_split + i; free_bufferline(pmsgid_split);
			 *                        }
			 *                        free(msgid_split);
			 */
		}
		else
		{


@@ 671,7 640,7 @@ save_loop_entries_start:
	{
		size_t msgid_plural_size
			= current->msgid_plural_size * UTF8REPMAX;
		size_t num_lines = u32_lines_in_string(current->msgid_plural,
		size_t num_lines = u32_lines_in_string(current->msgid_plural, 1,
			SAVE_WRAP_WIDTH);
		if (num_lines > 1)
		{


@@ 686,7 655,7 @@ save_loop_entries_start:
				const uint32_t* old_pumsgid = pumsgid;

				len = u32_next_line(current->msgid_plural,
					&pumsgid, SAVE_WRAP_WIDTH);
					&pumsgid, 1, SAVE_WRAP_WIDTH);
				if (len == 0)
					continue;



@@ 698,41 667,6 @@ save_loop_entries_start:
				fprintf(output, "\"%s\"\n", u8_msgid);
				free(u8_msgid);
			}

			/*
			 *                        struct BufferLine* msgid_split
			 *                                =
			 * split(current->msgid_plural, SAVE_WRAP_WIDTH); struct
			 * BufferLine* pmsgid_split = NULL;
			 *
			 *                        if (!msgid_split)
			 *                                return
			 * SAVE_ERR_CANT_ALLOC;
			 *
			 *                        fprintf(output, "msgid_plural
			 * \"\"\n"); for (size_t i = 0; i < num_lines; i++)
			 *                        {
			 *                                pmsgid_split =
			 * msgid_split + i; int last     = i == num_lines - 1;
			 *                                char* u8_msgid
			 *                                        =
			 * calloc(current->msgid_plural_size, UTF8REPMAX); if
			 * (!u8_msgid) return SAVE_ERR_CANT_ALLOC; size_t len =
			 * u32_strlen(pmsgid_split->text);
			 *                                unicode_string_to_u8(u8_msgid,
			 *                                        pmsgid_split->text,
			 * msgid_plural_size); if (!(last && len == 0))
			 *                                        fprintf(output,
			 * "\"%s\"\n", u8_msgid); free(u8_msgid);
			 *                        }
			 *                        for (size_t i = 0; i <
			 * num_lines; i++)
			 *                        {
			 *                                pmsgid_split =
			 * msgid_split + i; free_bufferline(pmsgid_split);
			 *                        }
			 *                        free(msgid_split);
			 */
		}
		else
		{


@@ 749,7 683,7 @@ save_loop_entries_start:

	if (current->msgstr_count == 1)
	{
		size_t num_lines = u32_lines_in_string(*current->msgstr,
		size_t num_lines = u32_lines_in_string(*current->msgstr, 1,
			SAVE_WRAP_WIDTH);
		if (num_lines > 1)
		{


@@ 771,7 705,11 @@ save_loop_entries_start:
				const uint32_t* old_pumsgstr = pumsgstr;

				len = u32_next_line(*current->msgstr, &pumsgstr,
					SAVE_WRAP_WIDTH);
					1,
					((first_entry && WRAP_FIRST_MSGSTR)
						|| !first_entry)
						? SAVE_WRAP_WIDTH
						: 0);

				if (len == 0)
					continue;


@@ 806,61 744,6 @@ save_loop_entries_start:
			if (first_entry && !seen_generator)
				fprintf(output, "\"X-Generator: poe %s\"\n",
					VERSION);

			/*
			 *                        struct BufferLine*
			 * msgstr_split = split(*current->msgstr,
			 * SAVE_WRAP_WIDTH); struct BufferLine* pmsgstr_split =
			 * NULL;
			 *
			 *                        if (!msgstr_split)
			 *                                return
			 * SAVE_ERR_CANT_ALLOC;
			 *
			 *                        fprintf(output, "msgstr
			 * \"\"\n"); for (size_t i = 0; i < num_lines; i++)
			 *                        {
			 *                                pmsgstr_split =
			 * msgstr_split + i; int last      = i == num_lines - 1;
			 *                                char
			 * u8_msgstr[MAXMSGLINE * UTF8REPMAX]; size_t len =
			 * u32_strlen(pmsgstr_split->text);
			 *                                unicode_string_to_u8(u8_msgstr,
			 *                                        pmsgstr_split->text,
			 *                                        MAXMSGLINE *
			 * UTF8REPMAX);
			 *
			 *                                if (first_entry
			 *                                        &&
			 * starts_with(u8_msgstr, "PO-Revision-Date: "))
			 *                                        fprintf(output,
			 *                                                "\"PO-Revision-Date:"
			 *                                                "
			 * %s\\n\"\n", now); else if (first_entry
			 *                                        &&
			 * starts_with(u8_msgstr, "X-Generator: "))
			 *                                {
			 *                                        seen_generator
			 * = 1; fprintf(output,
			 *                                                "\"X-Generator:"
			 *                                                " poe
			 * %s"
			 *                                                "\\n\"\n",
			 *                                                VERSION);
			 *                                }
			 *                                else if (!(last && len
			 * == 0)) fprintf(output, "\"%s\"\n", u8_msgstr);
			 *                        }
			 *                        if (first_entry &&
			 * !seen_generator) fprintf(output, "\"X-Generator: poe
			 * %s\"\n", VERSION); for (size_t i = 0; i < num_lines;
			 * i++)
			 *                        {
			 *                                pmsgstr_split =
			 * msgstr_split + i; free_bufferline(pmsgstr_split);
			 *                        }
			 *                        free(msgstr_split);
			 */
		}
		else if (current->msgid_plural
			&& (!*current->msgstr || !**current->msgstr))


@@ 879,7 762,7 @@ save_loop_entries_start:
		for (size_t m = 0; m < current->msgstr_count; m++)
		{
			size_t num_lines = u32_lines_in_string(*current->msgstr,
				SAVE_WRAP_WIDTH);
				1, SAVE_WRAP_WIDTH);
			if (num_lines > 1)
			{
				const uint32_t* pumsgstr


@@ 895,7 778,7 @@ save_loop_entries_start:

					len = u32_next_line(*(current->msgstr
								    + m),
						&pumsgstr, SAVE_WRAP_WIDTH);
						&pumsgstr, 1, SAVE_WRAP_WIDTH);
					if (len == 0)
						continue;



@@ 908,43 791,6 @@ save_loop_entries_start:
					fprintf(output, "\"%s\"\n", u8_msgstr);
					free(u8_msgstr);
				}

				/*
				 *                                struct BufferLine*
				 * msgstr_split = split(*(current->msgstr + m),
				 *                                                SAVE_WRAP_WIDTH);
				 *                                struct BufferLine*
				 * pmsgstr_split = NULL;
				 *
				 *                                if (!msgstr_split)
				 *                                        return
				 * SAVE_ERR_CANT_ALLOC;
				 *
				 *                                fprintf(output,
				 * "msgstr[%ld] \"\"\n", m); for (size_t i = 0;
				 * i < num_lines; i++)
				 *                                {
				 *                                        pmsgstr_split
				 * = msgstr_split + i; int last      = i == num_lines
				 * - 1; char u8_msgstr[MAXMSGLINE * UTF8REPMAX];
				 *                                        size_t
				 * len = u32_strlen( pmsgstr_split->text);
				 *                                        unicode_string_to_u8(u8_msgstr,
				 *                                                pmsgstr_split->text,
				 *                                                MAXMSGLINE
				 * * UTF8REPMAX); if (!(last && len == 0))
				 *                                                fprintf(output,
				 * "\"%s\"\n", u8_msgstr);
				 *                                }
				 *                                for (size_t i
				 * = 0; i < num_lines; i++)
				 *                                {
				 *                                        pmsgstr_split
				 * = msgstr_split + i;
				 *                                        free_bufferline(pmsgstr_split);
				 *                                }
				 *                                free(msgstr_split);
				 */
			}
			else
			{

M poe.c => poe.c +50 -47
@@ 214,9 214,9 @@ load_info(struct DrawState* state)
{
	struct PoEntry* first	= &state->entries[0];
	struct PoEntry* current = &state->entries[state->msgid_number - 1];
	size_t msgid_num_lines	= u32_lines_in_string(current->msgid, 0);
	size_t msgid_num_lines	= u32_lines_in_string(current->msgid, 0, 0);
	size_t msgid_plural_num_lines
		= u32_lines_in_string(current->msgid_plural, 0);
		= u32_lines_in_string(current->msgid_plural, 0, 0);
	size_t num_lines	   = 0;
	struct BufferLine* newbuf  = NULL;
	struct BufferLine* pnewbuf = NULL;


@@ 258,8 258,8 @@ load_info(struct DrawState* state)

	state->info_rows_count = num_lines;

	pnewbuf		  = newbuf;
	size_t newlen	  = 0;
	pnewbuf			= newbuf;
	size_t newlen		= 0;
	const uint32_t* pumsgid = NULL;
	if (current->msgid)
	{


@@ 273,10 273,10 @@ load_info(struct DrawState* state)
		pnewbuf++;
		while (*pumsgid)
		{
			size_t len = 0;
			size_t len		    = 0;
			const uint32_t* old_pumsgid = pumsgid;

			len = u32_next_line(current->msgid, &pumsgid, 0);
			len = u32_next_line(current->msgid, &pumsgid, 0, 0);
			u32_strncpy(pnewbuf->text, old_pumsgid,
				MIN(len + 1, MAXBUFLINE));
			newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE);


@@ 299,10 299,11 @@ load_info(struct DrawState* state)
		pumsgid = current->msgid_plural;
		while (*pumsgid)
		{
			size_t len = 0;
			size_t len		    = 0;
			const uint32_t* old_pumsgid = pumsgid;

			len = u32_next_line(current->msgid_plural, &pumsgid, 0);
			len = u32_next_line(current->msgid_plural, &pumsgid, 0,
				0);
			u32_strncpy(pnewbuf->text, old_pumsgid,
				MIN(len + 1, MAXBUFLINE));
			newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE);


@@ 407,8 408,7 @@ load_msgstr(struct DrawState* state)
	struct PoEntry* current	   = &state->entries[state->msgid_number - 1];
	size_t num_lines	   = current->msgstr_count == 0
			  ? 1
			  : u32_lines_in_string(
					  *(current->msgstr + msgstr_index), 0);
			  : u32_lines_in_string(*(current->msgstr + msgstr_index), 0, 0);
	struct BufferLine* newbuf  = NULL;
	struct BufferLine* pnewbuf = NULL;



@@ 441,10 441,12 @@ load_msgstr(struct DrawState* state)
			pnewbuf = newbuf;
			while (*pumsgstr)
			{
				size_t len    = 0;
				size_t newlen = 0;
				size_t len		     = 0;
				size_t newlen		     = 0;
				const uint32_t* old_pumsgstr = pumsgstr;
				len = u32_next_line(*(current->msgstr + msgstr_index), &pumsgstr, 0);
				len = u32_next_line(*(current->msgstr
							    + msgstr_index),
					&pumsgstr, 0, 0);
				u32_strncpy(pnewbuf->text, old_pumsgstr,
					MIN(len + 1, MAXBUFLINE));
				newlen		= u32_decode_tabs(pnewbuf->text,


@@ 757,12 759,12 @@ move_search_prev_word(struct DrawState* state)
	int i		= state->search_column;
	uint32_t* pline = state->search;

	if (i > 0 && u32_is_word_boundary(pline[i - 1]))
	if (i > 0 && u32_is_word_boundary(pline[i - 1], 0))
		i--;
	while (i > 0 && u32_is_word_boundary(pline[i]))
	while (i > 0 && u32_is_word_boundary(pline[i], 0))
		i--;
	while (i > 0 && !u32_is_word_boundary(pline[i])
		&& !u32_is_word_boundary(pline[i - 1]))
	while (i > 0 && !u32_is_word_boundary(pline[i], 0)
		&& !u32_is_word_boundary(pline[i - 1], 0))
		i--;

	state->search_column = i;


@@ 788,9 790,9 @@ move_search_next_word(struct DrawState* state)
	uint32_t* pline = state->search;
	size_t len	= u32_strlen(state->search);

	while (i < len && !u32_is_word_boundary(pline[i]))
	while (i < len && !u32_is_word_boundary(pline[i], 0))
		i++;
	while (i < len && u32_is_word_boundary(pline[i]))
	while (i < len && u32_is_word_boundary(pline[i], 0))
		i++;
	state->search_column = i;
	state->search_display_column


@@ 814,12 816,12 @@ erase_search_prev_word(struct DrawState* state)

	uint32_t* pline = state->search;

	if (i > 0 && u32_is_word_boundary(pline[i - 1]))
	if (i > 0 && u32_is_word_boundary(pline[i - 1], 0))
		i--;
	while (i > 0 && u32_is_word_boundary(pline[i]))
	while (i > 0 && u32_is_word_boundary(pline[i], 0))
		i--;
	while (i > 0 && !u32_is_word_boundary(pline[i])
		&& !u32_is_word_boundary(pline[i - 1]))
	while (i > 0 && !u32_is_word_boundary(pline[i], 0)
		&& !u32_is_word_boundary(pline[i - 1], 0))
		i--;

	int d = state->search_column - i;


@@ 868,7 870,7 @@ copy_msgid_to_input(struct DrawState* state)
	}

	struct PoEntry* current = &state->entries[state->msgid_number - 1];
	size_t msgid_num_lines	= u32_lines_in_string(current->msgid, 0);
	size_t msgid_num_lines	= u32_lines_in_string(current->msgid, 0, 0);
	size_t lines_to_init	= state->input_rows_count < msgid_num_lines
		   ? msgid_num_lines - state->input_rows_count
		   : 0;


@@ 899,13 901,12 @@ copy_msgid_to_input(struct DrawState* state)
	pbuffer = newbuf;
	while (pmsgid && *pmsgid)
	{
		size_t len    = 0;
		size_t newlen = 0;
		size_t len		   = 0;
		size_t newlen		   = 0;
		const uint32_t* old_pmsgid = pmsgid;
		len = u32_next_line(current->msgid, &pmsgid, 0);
		u32_strncpy(pbuffer->text, old_pmsgid,
			MIN(len + 1, MAXBUFLINE));
		newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE);
		len = u32_next_line(current->msgid, &pmsgid, 0, 0);
		u32_strncpy(pbuffer->text, old_pmsgid, MIN(len + 1, MAXBUFLINE));
		newlen		= u32_decode_tabs(pbuffer->text, MAXBUFLINE);
		pbuffer->length = newlen;
		pbuffer++;
	}


@@ 949,7 950,7 @@ yank_msgstr_to_paste_buffer(struct DrawState* state)

	msgstr_num_lines
		= u32_lines_in_string(*(current->msgstr + state->msgstr_index),
			0);
			0, 0);
	lines_to_init = state->paste_rows_count < msgstr_num_lines
		? msgstr_num_lines - state->paste_rows_count
		: 0;


@@ 983,13 984,15 @@ yank_msgstr_to_paste_buffer(struct DrawState* state)
	pbuffer = newbuf;
	while (*pmsgstr)
	{
		size_t len    = 0;
		size_t newlen = 0;
		size_t len		    = 0;
		size_t newlen		    = 0;
		const uint32_t* old_pmsgstr = pmsgstr;

		len = u32_next_line(*(current->msgstr + state->msgstr_index), &pmsgstr, 0);
		u32_strncpy(pbuffer->text, old_pmsgstr, MIN(len + 1, MAXBUFLINE));
		newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE);
		len = u32_next_line(*(current->msgstr + state->msgstr_index),
			&pmsgstr, 0, 0);
		u32_strncpy(pbuffer->text, old_pmsgstr,
			MIN(len + 1, MAXBUFLINE));
		newlen		= u32_decode_tabs(pbuffer->text, MAXBUFLINE);
		pbuffer->length = newlen;
		pbuffer++;
	}


@@ 1448,12 1451,12 @@ move_prev_word(struct DrawState* state)
	int i		= state->input_column;
	uint32_t* pline = state->input_buffer[state->input_row].text;

	if (i > 0 && u32_is_word_boundary(pline[i - 1]))
	if (i > 0 && u32_is_word_boundary(pline[i - 1], 0))
		i--;
	while (i > 0 && u32_is_word_boundary(pline[i]))
	while (i > 0 && u32_is_word_boundary(pline[i], 0))
		i--;
	while (i > 0 && !u32_is_word_boundary(pline[i])
		&& !u32_is_word_boundary(pline[i - 1]))
	while (i > 0 && !u32_is_word_boundary(pline[i], 0)
		&& !u32_is_word_boundary(pline[i - 1], 0))
		i--;

	state->input_column	    = i;


@@ 1477,9 1480,9 @@ move_next_word(struct DrawState* state)
	uint32_t* pline = state->input_buffer[state->input_row].text;
	size_t len	= state->input_buffer[state->input_row].length;

	while (i < len && !u32_is_word_boundary(pline[i]))
	while (i < len && !u32_is_word_boundary(pline[i], 0))
		i++;
	while (i < len && u32_is_word_boundary(pline[i]))
	while (i < len && u32_is_word_boundary(pline[i], 0))
		i++;
	state->input_column	    = i;
	state->input_display_column = display_length(state,


@@ 1505,12 1508,12 @@ erase_prev_word(struct DrawState* state)

	uint32_t* pline = state->input_buffer[state->input_row].text;

	if (i > 0 && u32_is_word_boundary(pline[i - 1]))
	if (i > 0 && u32_is_word_boundary(pline[i - 1], 0))
		i--;
	while (i > 0 && u32_is_word_boundary(pline[i]))
	while (i > 0 && u32_is_word_boundary(pline[i], 0))
		i--;
	while (i > 0 && !u32_is_word_boundary(pline[i])
		&& !u32_is_word_boundary(pline[i - 1]))
	while (i > 0 && !u32_is_word_boundary(pline[i], 0)
		&& !u32_is_word_boundary(pline[i - 1], 0))
		i--;

	int d = state->input_column - i;


@@ 2235,7 2238,7 @@ main(int argc, char** argv)
	state.first_shown_msgid = state.msgid_number;

	tb_init();
	error[0] = 0;
	error[0]   = 0;
	state.maxx = 0;

	while (state.running)

M util.c => util.c +32 -120
@@ 48,10 48,10 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max)
	while (*pus)
	{
		int len = tb_utf8_unicode_to_char(ch, *pus);
		ch[len] = 0;
		if (added + len + 1 > max)
		if (added + 1 > max)
			break;
		strncat(s, ch, 8);
		strncat(s, ch, len);
		added++;
		pus++;
	}
	return added;


@@ 218,100 218,12 @@ u8_u32_strncpy(char* to, const uint32_t* from, size_t max)
	return strlen(to);
}

/*
 *size_t
 *u8_line_length(const char* s, const char** sptr, const size_t wrap)
 *{
 *        size_t len = 0;
 *        if (!s)
 *                return len;
 *        const char* ps	       = s;
 *        size_t last_nonblank   = 0;
 *        int have_last_nonblank = 0;
 *        if (sptr)
 *                *sptr = ps;
 *        while (*ps)
 *        {
 *                if (wrap > 0 && ps > s + wrap)
 *                        return have_last_nonblank ? last_nonblank + 1 : wrap;
 *                if (!u8_is_word_boundary(*ps) && u8_is_word_boundary(*(ps + 1)))
 *                {
 *                        last_nonblank	   = ps - s;
 *                        have_last_nonblank = 1;
 *                }
 *                if (*ps == '\\' && *(ps + 1) == 'n')
 *                        return len;
 *                ps++;
 *                len++;
 *                if (sptr)
 *                        *sptr = ps;
 *        }
 *        return len;
 *}
 */

/*
 *size_t
 *u32_line_length(const uint32_t* s, const uint32_t** sptr, const size_t wrap)
 *{
 *        size_t len = 0;
 *        if (!s)
 *                return len;
 *        const uint32_t* ps     = s;
 *        size_t last_nonblank   = 0;
 *        int have_last_nonblank = 0;
 *        if (sptr)
 *                *sptr = ps;
 *        while (*ps)
 *        {
 *                if (wrap > 0 && ps > s + wrap)
 *                        return have_last_nonblank ? last_nonblank : wrap;
 *                if (!u32_is_word_boundary(*ps) && u32_is_word_boundary(*(ps + 1)))
 *                {
 *                        last_nonblank	   = ps - s;
 *                        have_last_nonblank = 1;
 *                }
 *                if (*ps == '\\' && *(ps + 1) == 'n')
 *                        return len;
 *                ps++;
 *                len++;
 *                if (sptr)
 *                        *sptr = ps;
 *        }
 *        return len;
 *}
 */

/* wrap - if >0, also wrap lines
 * */
/*
 *size_t
 *u8_lines_in_string(const char* s, const size_t wrap)
 *{
 *        size_t result = 1;
 *        const char* ps = NULL;
 *        size_t len = 0;
 *
 *        if (!s)
 *                return result;
 *
 *        ps = s;
 *        while (*ps)
 *        {
 *                len = u8_line_length(s, &ps, wrap);
 *                ps += len;
 *                result++;
 *        }
 *        return result;
 *}
 */

/* wrap - if >0, also wrap lines
 * */
size_t
u32_lines_in_string(const uint32_t* s, const size_t wrap)
u32_lines_in_string(const uint32_t* s, const int include_eol, const size_t wrap)
{
	size_t result = 1;
	size_t result	   = 1;
	const uint32_t* ps = NULL;

	if (!s)


@@ 320,7 232,7 @@ u32_lines_in_string(const uint32_t* s, const size_t wrap)
	ps = s;
	while (*ps)
	{
		u32_next_line(s, &ps, wrap);
		u32_next_line(s, &ps, include_eol, wrap);
		if (*ps)
			result++;
	}


@@ 334,14 246,15 @@ u32_lines_in_string(const uint32_t* s, const size_t wrap)
 * wrap - wrap lines to this many characters (runes); if 0, don't wrap
 */
size_t
u32_next_line(const uint32_t* s, const uint32_t** next_line, const size_t wrap)
u32_next_line(const uint32_t* s, const uint32_t** next_line,
	const int include_eol, const size_t wrap)
{
	size_t result = 0;
	const uint32_t* ps = NULL;
	const uint32_t* start = NULL;
	size_t last_nonblank = 0;
	size_t result	       = 0;
	const uint32_t* ps     = NULL;
	const uint32_t* start  = NULL;
	size_t last_nonblank   = 0;
	int have_last_nonblank = 0;
	

	if (!s)
		return result;



@@ 351,26 264,29 @@ u32_next_line(const uint32_t* s, const uint32_t** next_line, const size_t wrap)
	ps = start;
	while (*ps)
	{
		if (wrap > 0 && ps > start + wrap)
		if (wrap > 0 && result > wrap)
		{
			size_t cutoff = wrap;

			if (have_last_nonblank)
				cutoff = last_nonblank + 1;
			if (next_line)
			{
				if (have_last_nonblank)
					*next_line = start + last_nonblank;
			}
			return have_last_nonblank ? have_last_nonblank : wrap;
				*next_line = start + cutoff;

			return cutoff;
		}

		if (*ps == '\\' && *(ps+1) == 'n')
		if (*ps == '\\' && *(ps + 1) == 'n')
		{
			if (next_line)
				*next_line = ps + 2;
			return result;
			return result + (include_eol ? 2 : 0);
		}
		
		if (!u32_is_word_boundary(*ps) && u32_is_word_boundary(*(ps+1)))

		if (!u32_is_word_boundary(*ps, 1)
			&& u32_is_word_boundary(*(ps + 1), 1))
		{
			last_nonblank = ps - start;
			last_nonblank	   = ps - start;
			have_last_nonblank = 1;
		}



@@ 381,19 297,15 @@ u32_next_line(const uint32_t* s, const uint32_t** next_line, const size_t wrap)
	if (next_line)
		*next_line = ps;

	return result;
}

int
u8_is_word_boundary(const uint8_t ch)
{
	return u32_strchr((uint32_t*)L" \t()[]{},.;:/\\", ch) != NULL;
	return result + 1;
}

int
u32_is_word_boundary(const uint32_t ch)
u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace)
{
	return u32_strchr((uint32_t*)L" \t()[]{},.;:/\\", ch) != NULL;
	return strictly_whitespace
		? u32_strchr((uint32_t*)L" \v\t", ch) != NULL
		: u32_strchr((uint32_t*)L" \v\t()[]{},.;:/\\", ch) != NULL;
}

int

M util.h => util.h +4 -10
@@ 24,7 24,6 @@ enum {
#define MAXMSGLINE	1024
#define MSGDELTA	1024
#define MAXPATH		1024
#define SAVE_WRAP_WIDTH 70
/* maximum chars for UTF-8 representations of Unicode chars, per Unicode char */
#define UTF8REPMAX 6



@@ 39,15 38,10 @@ size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max);
size_t u32_strncat(uint32_t* to, const uint32_t* from, size_t max);
size_t u32_u8_strncpy(uint32_t* to, const char* from, size_t max);
size_t u8_u32_strncpy(char* to, const uint32_t* from, size_t max);
/*
 *size_t u8_line_length(const char* s, const char** sptr, const size_t wrap);
 *size_t u32_line_length(const uint32_t* s, const uint32_t** sptr, const size_t wrap);
 */
size_t u8_lines_in_string(const char* s, const size_t wrap);
size_t u32_lines_in_string(const uint32_t* s, const size_t wrap);
size_t u32_next_line(const uint32_t* s, const uint32_t** sptr, const size_t wrap);
int u8_is_word_boundary(const uint8_t ch);
int u32_is_word_boundary(const uint32_t ch);
size_t u32_lines_in_string(const uint32_t* s, const int include_eol, const size_t wrap);
size_t u32_next_line(const uint32_t* s, const uint32_t** sptr,
	const int include_eol, const size_t wrap);
int u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace);
int starts_with(const char* s, const char* with);
int u32_starts_with(const uint32_t* s, const uint32_t* with);
const char* u8_basename(const char* path);

A wrap_next_line_logic => wrap_next_line_logic +23 -0
@@ 0,0 1,23 @@
                                                                                
          01234567890123456789012345678901234567                                
                        | wrap = 13                                             
         "Quickbrown fox|umps overthesleepy dog."                               
          ^        ^^   |                                                       
          |        ||   ps = 14 > start + (wrap = 13)                           
          |        |`------ start + last_nonblank + 1 = 10                      
          |        last_nonblank = 9                                            
          start                                                                 
                                                                                
                                       | wrap = 28                              
         "Quickbrown foxjumps overthesl|epy dog."                               
          ^        ^        ^          |                                        
          |        |        |          ps = 29 > start + (wrap = 28)           
          |        |        new last_nonblank = 18                              
          |        last_nonblank = 9                                            
          start