чување 81972837bddb516e0ca00476632bd77303058dbf
родитељ 5ba662b56983e43c4a8c3ba769dd73adf32d8bd7
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sun, 6 Jun 2021 13:35:41 +0200
Split code into several files, changed copyright notices to match suckless standards
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | all.do | | | 1 | + |
| A | config.def.h | | | 10 | ++++++++++ |
| A | config.h | | | 10 | ++++++++++ |
| A | default.do | | | 4 | ++++ |
| A | default.h.do | | | 6 | ++++++ |
| A | draw.c | | | 221 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | draw.h | | | 50 | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | po.h | | | 14 | ++++++++++++++ |
| M | poe.c | | | 332 | +++---------------------------------------------------------------------------- |
| M | poe.do | | | 2 | +- |
| A | util.c | | | 29 | +++++++++++++++++++++++++++++ |
| A | util.h | | | 14 | ++++++++++++++ |
измењених датотека: 12, додавања: 372(+), брисања: 321(-)
diff --git a/all.do b/all.do
@@ -1,3 +1,4 @@
+redo-ifchange config.def.h config.h
for f in *.c; do
echo $f | sed -e's/\.c$/.o/g'
done | xargs redo-ifchange
diff --git a/config.def.h b/config.def.h
@@ -0,0 +1,10 @@
+/* See the file LICENSE for copyright and license details. */
+void format_filename(char* result, size_t result_size, const char* format);
+void format_msgs(char* result, size_t result_size, const char* format);
+
+static const StatusSegment status_segments[] = {
+ { "%s", format_filename, TB_BLACK, TB_WHITE, LEFT },
+ { "msg:%ld/%ld", format_msgs, TB_WHITE | TB_BOLD, TB_BLUE, CENTER },
+ { "H=HELP, q=QUIT", NULL, TB_BLACK, TB_WHITE, RIGHT },
+};
+
diff --git a/config.h b/config.h
@@ -0,0 +1,10 @@
+/* See the file LICENSE for copyright and license details. */
+void format_filename(char* result, size_t result_size, const char* format);
+void format_msgs(char* result, size_t result_size, const char* format);
+
+static const StatusSegment status_segments[] = {
+ { "%s", format_filename, TB_BLACK, TB_WHITE, LEFT },
+ { "msg:%ld/%ld", format_msgs, TB_WHITE | TB_BOLD, TB_BLUE, CENTER },
+ { "H=HELP, q=QUIT", NULL, TB_BLACK, TB_WHITE, RIGHT },
+};
+
diff --git a/default.do b/default.do
@@ -0,0 +1,4 @@
+for f in *.h; do
+ echo $f
+done | xargs redo-ifchange
+
diff --git a/default.h.do b/default.h.do
@@ -0,0 +1,6 @@
+redo-ifchange $2.def.h
+if [ -f $2.def.h ]; then
+ cat $2.def.h > $3
+fi
+
+
diff --git a/draw.c b/draw.c
@@ -0,0 +1,221 @@
+/* See the file LICENSE for copyright and license details. */
+#include <bits/stdint-uintn.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "termbox.h"
+#include "util.h"
+#include "po.h"
+#include "draw.h"
+#include "config.h"
+
+static const char* title = " poe - .po File Editor ";
+static const char* help[] = {
+ "ESC - Close dialog, clear error",
+ "H | F1 - Show this screen",
+ "g | Home - First entry",
+ "k | \u2191 - Previous entry",
+ "j | \u2193 - Next entry",
+ "G | End - Last entry",
+ "q - Quit"
+};
+const char* errors[] = {
+ [ERR_UNKNOWN_KEY] = "Unknown key (press H for help)",
+ [ERR_NO_PREV] = "No previous entry",
+ [ERR_NO_NEXT] = "No next entry",
+ [ERR_EXIT_KEY] = "Press q to quit"
+};
+const char* flag_strings[] = {
+ [FL_C_FORMAT] = "c-format",
+ [FL_FUZZY] = "fuzzy"
+};
+const char* empty_msgid = "*** No msgid ***";
+const char* empty_msgstr = "*** No msgstr ***";
+const char* program_name = "poe";
+
+void
+draw_box(const int startx, const int endx, const int starty, const int endy,
+ const uint16_t fg, const uint16_t bg)
+{
+ int x, y;
+
+ tb_change_cell(startx+1, starty, BORDER_NW, fg, bg);
+ for (x = startx+2; x < endx-2; x++)
+ tb_change_cell(x, starty, BORDER_HOR, fg, bg);
+ tb_change_cell(endx-2, starty, BORDER_NE, fg, bg);
+
+ for (y = starty+1; y < endy-2; y++)
+ {
+ tb_change_cell(startx+1, y, BORDER_VER, fg, bg);
+ for (x = startx+2; x < endx-2; x++)
+ tb_change_cell(x, y, ' ', fg, bg);
+ tb_change_cell(endx-2, y, BORDER_VER, fg, bg);
+ tb_change_cell(endx-1, y, ' ', SHADOW_FG, SHADOW_BG);
+ }
+
+ tb_change_cell(startx+1, endy-2, BORDER_SW, fg, bg);
+ for (x = startx+2; x < endx-2; x++)
+ tb_change_cell(x, endy-2, BORDER_HOR, fg, bg);
+ tb_change_cell(endx-2, endy-2, BORDER_SE, fg, bg);
+ tb_change_cell(endx-1, endy-2, ' ', SHADOW_FG, SHADOW_BG);
+
+ for (x = startx+2; x < endx; x++)
+ tb_change_cell(x, endy-1, ' ', SHADOW_FG, SHADOW_BG);
+}
+
+void
+draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
+ const char* s, const int max_cols, const int fill_cols,
+ const int padding, const Alignment align)
+{
+ int col;
+ uint32_t* us = calloc(strlen(s)+1, sizeof(uint32_t));
+ uint32_t* pus = NULL;
+ size_t us_len = 0;
+ us_len = u8_string_to_unicode(us, s);
+ pus = us;
+
+ if (align == LEFT)
+ {
+ for (col = 0; col < fill_cols; col++)
+ tb_change_cell(x+col, y, ' ', fg, bg);
+ col = 0;
+ }
+ else if (align == RIGHT)
+ {
+ for (col = 0; col < fill_cols; col++)
+ tb_change_cell(x+col, y, ' ', fg, bg);
+ col = max_cols-us_len-padding-1;
+ }
+ else if (align == CENTER)
+ {
+ for (col = (max_cols-fill_cols)/2;
+ col < (max_cols+fill_cols)/2; col++)
+ tb_change_cell(x+col, y, ' ', fg, bg);
+
+ if (s)
+ {
+ if (us_len > max_cols)
+ {
+ pus += (us_len-max_cols)/2;
+ col = 0;
+ }
+ else
+ col = (max_cols-us_len)/2-padding;
+ }
+ }
+
+ while (*pus && col < max_cols-padding)
+ {
+ tb_change_cell(x+col+padding, y, *pus, fg, bg);
+ pus++;
+ col++;
+ }
+ if (us)
+ free(us);
+}
+
+void
+draw_help()
+{
+ int startx, endx, starty, endy;
+ int w = 50;
+ int h = 20;
+ int row = 0;
+
+ startx = w > maxx ? 0 : (maxx - w) / 2;
+ endx = w > maxx ? maxx-1 : maxx-startx;
+
+ starty = h > maxy-1 ? 0 : (maxy-h)/2;
+ endy = h > maxy-1 ? maxy-2 : maxy-starty;
+
+ draw_box(startx, endx, starty, endy, TB_BLACK, TB_WHITE);
+ draw_string(startx+1, starty, TB_BLACK | TB_BOLD | TB_REVERSE, TB_WHITE,
+ title, w-2, strlen(title)+2, 1, CENTER);
+ while (row < LEN(help))
+ {
+ draw_string(startx+2, starty+3+row, TB_BLACK, TB_WHITE,
+ help[row], w-4, w-4, 2, LEFT);
+ row++;
+ }
+}
+
+void
+draw_status()
+{
+ char buf[MAXBUF];
+ int seg_size = maxx/3;
+ int current_start = 0;
+ const StatusSegment* pseg = status_segments;
+
+ if (error[0])
+ draw_string(0, maxy-1, ERROR_FG, ERROR_BG, error, maxx, maxx,
+ 1, CENTER);
+ else
+ while (pseg < status_segments + LEN(status_segments))
+ {
+ buf[0] = 0;
+ if (pseg->callback)
+ pseg->callback(buf, MAXBUF, pseg->format);
+ else
+ strncpy(buf, pseg->format, MAXBUF);
+ buf[MAXBUF-1] = 0;
+ draw_string(current_start, maxy-1, pseg->fg, pseg->bg,
+ buf, seg_size, seg_size, 1,
+ pseg->alignment);
+ pseg++;
+ current_start += seg_size;
+ }
+}
+
+void
+draw_entry(PoEntry* entry)
+{
+ uint16_t flags;
+
+ if (entry)
+ {
+ draw_string(0, maxy/3, MSGID_FG, MSGID_BG, entry->msgid,
+ maxx, maxx, maxx/4, LEFT);
+ flags = entry->flags;
+ while (flags)
+ {
+ if (flags & FL_C_FORMAT)
+ {
+ flags &= ~FL_C_FORMAT;
+ draw_string(0, 1, FLAG_FG, FLAG_BG,
+ flag_strings[FL_C_FORMAT], maxx, maxx, 1, LEFT);
+ }
+ else if (flags & FL_FUZZY)
+ {
+ flags &= ~FL_FUZZY;
+ draw_string(10, 1, FLAG_FG, FLAG_BG,
+ flag_strings[FL_FUZZY], maxx-10, maxx-10, 1, LEFT);
+ }
+ }
+ draw_string(0, 2*maxy/3, MSGSTR_FG, MSGSTR_BG, entry->msgstr,
+ maxx, maxx, maxx/4, LEFT);
+ }
+ else
+ {
+ draw_string(0, maxy/3, MSGID_FG, MSGID_BG, empty_msgid,
+ maxx, maxx, maxx/4, LEFT);
+ draw_string(0, 2*maxy/3, MSGSTR_FG, MSGSTR_BG, empty_msgstr,
+ maxx, maxx, maxx/4, LEFT);
+ }
+}
+
+void
+draw()
+{
+ if (msgid_number > 0)
+ draw_entry(&entries[msgid_number-1]);
+ else
+ draw_entry(NULL);
+
+ if (show_help)
+ draw_help();
+
+ draw_status();
+}
+
diff --git a/draw.h b/draw.h
@@ -0,0 +1,50 @@
+/* See the file LICENSE for copyright and license details. */
+#define BORDER_NW u'\u250c'
+#define BORDER_NE u'\u2510'
+#define BORDER_SW u'\u2514'
+#define BORDER_SE u'\u2518'
+#define BORDER_VER u'\u2502'
+#define BORDER_HOR u'\u2500'
+
+#define ERROR_FG TB_WHITE | TB_BOLD
+#define ERROR_BG TB_RED
+#define FLAG_FG TB_YELLOW | TB_BOLD
+#define FLAG_BG TB_DEFAULT
+#define MSGID_FG TB_GREEN
+#define MSGID_BG TB_DEFAULT
+#define MSGSTR_FG TB_WHITE
+#define MSGSTR_BG TB_DEFAULT
+#define SHADOW_FG TB_BLACK
+#define SHADOW_BG TB_BLACK | TB_BOLD
+
+typedef enum {
+ LEFT,
+ CENTER,
+ RIGHT
+} Alignment;
+
+typedef struct {
+ const char* format;
+ void (*callback)(char*, size_t, const char*);
+ uint16_t fg;
+ uint16_t bg;
+ Alignment alignment;
+} StatusSegment;
+
+extern char error[MAXBUF];
+extern PoEntry entries[];
+extern long msgid_count;
+extern long msgid_number;
+extern int show_help;
+extern int maxx, maxy;
+
+void draw_box(const int startx, const int endx, const int starty, const int endy,
+ const uint16_t fg, const uint16_t bg);
+void draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
+ const char* s, const int max_cols, const int fill_cols,
+ const int padding, const Alignment align);
+void draw_help();
+void draw_status();
+void draw_entry(PoEntry* entry);
+void draw();
+
diff --git a/po.h b/po.h
@@ -0,0 +1,14 @@
+/* See the file LICENSE for copyright and license details. */
+
+typedef enum {
+ FL_NONE = 0,
+ FL_C_FORMAT = 1,
+ FL_FUZZY = 1 << 1,
+} Flags;
+
+typedef struct {
+ Flags flags;
+ char* msgid;
+ char* msgstr;
+} PoEntry;
+
diff --git a/poe.c b/poe.c
@@ -1,22 +1,4 @@
-/*
- * poe - .po file editor
- * Copyright (C) 2021 Страхиња Радић
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
+/* See the file LICENSE for copyright and license details. */
#include <bits/stdint-uintn.h>
#include <errno.h>
#include <stdarg.h>
@@ -28,106 +10,24 @@
#include <time.h>
#include "termbox.h"
+#include "util.h"
+#include "po.h"
+#include "draw.h"
+#include "config.h"
-#define BORDER_NW u'\u250c'
-#define BORDER_NE u'\u2510'
-#define BORDER_SW u'\u2514'
-#define BORDER_SE u'\u2518'
-#define BORDER_VER u'\u2502'
-#define BORDER_HOR u'\u2500'
-
-#define ERROR_FG TB_WHITE | TB_BOLD
-#define ERROR_BG TB_RED
-#define FLAG_FG TB_YELLOW | TB_BOLD
-#define FLAG_BG TB_DEFAULT
-#define MSGID_FG TB_GREEN
-#define MSGID_BG TB_DEFAULT
-#define MSGSTR_FG TB_WHITE
-#define MSGSTR_BG TB_DEFAULT
-#define SHADOW_FG TB_BLACK
-#define SHADOW_BG TB_BLACK | TB_BOLD
-
-#define LEN(x) (sizeof(x) / sizeof(x[0]))
-
-typedef enum {
- LEFT,
- CENTER,
- RIGHT
-} Alignment;
-
-typedef enum {
- FL_NONE = 0,
- FL_C_FORMAT = 1,
- FL_FUZZY = 1 << 1,
-} Flags;
-
-enum {
- ERR_UNKNOWN_KEY,
- ERR_NO_PREV,
- ERR_NO_NEXT,
- ERR_EXIT_KEY
-};
-
-typedef struct {
- const char* format;
- void (*callback)(char*, size_t, const char*);
- uint16_t fg;
- uint16_t bg;
- Alignment alignment;
-} StatusSegment;
-
-typedef struct {
- Flags flags;
- char* msgid;
- char* msgstr;
-} PoEntry;
-
-static const char* title = " poe - .po File Editor ";
-static const char* help[] = {
- "ESC - Close dialog, clear error",
- "H | F1 - Show this screen",
- "g | Home - First entry",
- "k | \u2191 - Previous entry",
- "j | \u2193 - Next entry",
- "G | End - Last entry",
- "q - Quit"
-};
-static const char* errors[] = {
- [ERR_UNKNOWN_KEY] = "Unknown key (press H for help)",
- [ERR_NO_PREV] = "No previous entry",
- [ERR_NO_NEXT] = "No next entry",
- [ERR_EXIT_KEY] = "Press q to quit"
-};
-static const char* flag_strings[] = {
- [FL_C_FORMAT] = "c-format",
- [FL_FUZZY] = "fuzzy"
-};
-static const char* empty_msgid = "*** No msgid ***";
-static const char* empty_msgstr = "*** No msgstr ***";
-static const char* program_name = "poe";
-
-void format_filename(char* result, size_t result_size, const char* format);
-void format_msgs(char* result, size_t result_size, const char* format);
-
-static const StatusSegment status_segments[] = {
- { "%s", format_filename, TB_BLACK, TB_WHITE, LEFT },
- { "msg:%ld/%ld", format_msgs, TB_WHITE | TB_BOLD, TB_BLUE, CENTER },
- { "H=HELP, q=QUIT", NULL, TB_BLACK, TB_WHITE, RIGHT },
-};
-
-#define MAXBUF 255
-#define MAXPATH 1024
+extern const char* errors[];
+extern const char* program_name;
char filename[MAXPATH];
char error[MAXBUF];
/* Test */
-static PoEntry entries[] = {
+PoEntry entries[] = {
{ flags: FL_C_FORMAT | FL_FUZZY, msgid: "First msgid: %s",
- msgstr: "Први msgid: %s" },
+ msgstr: "Први msgid: %s" },
{ flags: FL_NONE, msgid: "Test msgid",
- msgstr: "Пробни msgstr" },
+ msgstr: "Пробни msgstr" },
{ flags: FL_FUZZY, msgid: "Final text",
- msgstr: "Последњи текст" },
+ msgstr: "Последњи текст" },
};
long msgid_count = 0;
@@ -165,214 +65,6 @@ format_msgs(char* result, size_t result_size, const char* format)
snprintf(result, result_size, format, msgid_number, msgid_count);
}
-void
-draw_box(const int startx, const int endx, const int starty, const int endy,
- const uint16_t fg, const uint16_t bg)
-{
- int x, y;
-
- tb_change_cell(startx+1, starty, BORDER_NW, fg, bg);
- for (x = startx+2; x < endx-2; x++)
- tb_change_cell(x, starty, BORDER_HOR, fg, bg);
- tb_change_cell(endx-2, starty, BORDER_NE, fg, bg);
-
- for (y = starty+1; y < endy-2; y++)
- {
- tb_change_cell(startx+1, y, BORDER_VER, fg, bg);
- for (x = startx+2; x < endx-2; x++)
- tb_change_cell(x, y, ' ', fg, bg);
- tb_change_cell(endx-2, y, BORDER_VER, fg, bg);
- tb_change_cell(endx-1, y, ' ', SHADOW_FG, SHADOW_BG);
- }
-
- tb_change_cell(startx+1, endy-2, BORDER_SW, fg, bg);
- for (x = startx+2; x < endx-2; x++)
- tb_change_cell(x, endy-2, BORDER_HOR, fg, bg);
- tb_change_cell(endx-2, endy-2, BORDER_SE, fg, bg);
- tb_change_cell(endx-1, endy-2, ' ', SHADOW_FG, SHADOW_BG);
-
- for (x = startx+2; x < endx; x++)
- tb_change_cell(x, endy-1, ' ', SHADOW_FG, SHADOW_BG);
-}
-
-size_t
-u8_string_to_unicode(uint32_t* us, const char* s)
-{
- uint32_t uch;
- uint32_t* pus = us;
- int u8_len = 0;
- size_t result = 0;
-
- while (*s && u8_len != TB_EOF)
- {
- u8_len = tb_utf8_char_to_unicode(&uch, s);
- *pus++ = uch;
- if (u8_len != TB_EOF)
- {
- s += u8_len;
- result++;
- }
- }
- return result;
-}
-
-void
-draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
- const char* s, const int max_cols, const int fill_cols,
- const int padding, const Alignment align)
-{
- int col;
- uint32_t* us = calloc(strlen(s)+1, sizeof(uint32_t));
- uint32_t* pus = NULL;
- size_t us_len = 0;
- us_len = u8_string_to_unicode(us, s);
- pus = us;
-
- if (align == LEFT)
- {
- for (col = 0; col < fill_cols; col++)
- tb_change_cell(x+col, y, ' ', fg, bg);
- col = 0;
- }
- else if (align == RIGHT)
- {
- for (col = 0; col < fill_cols; col++)
- tb_change_cell(x+col, y, ' ', fg, bg);
- col = max_cols-us_len-padding-1;
- }
- else if (align == CENTER)
- {
- for (col = (max_cols-fill_cols)/2;
- col < (max_cols+fill_cols)/2; col++)
- tb_change_cell(x+col, y, ' ', fg, bg);
-
- if (s)
- {
- if (us_len > max_cols)
- {
- pus += (us_len-max_cols)/2;
- col = 0;
- }
- else
- col = (max_cols-us_len)/2-padding;
- }
- }
-
- while (*pus && col < max_cols-padding)
- {
- tb_change_cell(x+col+padding, y, *pus, fg, bg);
- pus++;
- col++;
- }
- if (us)
- free(us);
-}
-
-void
-draw_help()
-{
- int startx, endx, starty, endy;
- int w = 50;
- int h = 20;
- int row = 0;
-
- startx = w > maxx ? 0 : (maxx - w) / 2;
- endx = w > maxx ? maxx-1 : maxx-startx;
-
- starty = h > maxy-1 ? 0 : (maxy-h)/2;
- endy = h > maxy-1 ? maxy-2 : maxy-starty;
-
- draw_box(startx, endx, starty, endy, TB_BLACK, TB_WHITE);
- draw_string(startx+1, starty, TB_BLACK | TB_BOLD | TB_REVERSE, TB_WHITE,
- title, w-2, strlen(title)+2, 1, CENTER);
- while (row < LEN(help))
- {
- draw_string(startx+2, starty+3+row, TB_BLACK, TB_WHITE,
- help[row], w-4, w-4, 2, LEFT);
- row++;
- }
-}
-
-void
-draw_status()
-{
- int seg_size = maxx/3;
- char buf[MAXBUF];
- int current_start = 0;
- const StatusSegment* pseg = status_segments;
-
- if (error[0])
- draw_string(0, maxy-1, ERROR_FG, ERROR_BG, error, maxx, maxx,
- 1, CENTER);
- else
- while (pseg < status_segments + LEN(status_segments))
- {
- buf[0] = 0;
- if (pseg->callback)
- pseg->callback(buf, MAXBUF, pseg->format);
- else
- strncpy(buf, pseg->format, MAXBUF);
- draw_string(current_start, maxy-1, pseg->fg, pseg->bg,
- buf, seg_size, seg_size, 1,
- pseg->alignment);
- pseg++;
- current_start += seg_size;
- }
-}
-
-void
-draw_entry(PoEntry* entry)
-{
- char flags_buf[MAXBUF];
- uint16_t flags;
-
- if (entry)
- {
- draw_string(0, maxy/3, MSGID_FG, MSGID_BG, entry->msgid,
- maxx, maxx, maxx/4, LEFT);
- flags = entry->flags;
- flags_buf[0] = 0;
- while (flags)
- {
- if (flags & FL_C_FORMAT)
- {
- flags &= ~FL_C_FORMAT;
- draw_string(0, 1, FLAG_FG, FLAG_BG,
- flag_strings[FL_C_FORMAT], maxx, maxx, 1, LEFT);
- }
- else if (flags & FL_FUZZY)
- {
- flags &= ~FL_FUZZY;
- draw_string(10, 1, FLAG_FG, FLAG_BG,
- flag_strings[FL_FUZZY], maxx-10, maxx-10, 1, LEFT);
- }
- }
- draw_string(0, 2*maxy/3, MSGSTR_FG, MSGSTR_BG, entry->msgstr,
- maxx, maxx, maxx/4, LEFT);
- }
- else
- {
- draw_string(0, maxy/3, MSGID_FG, MSGID_BG, empty_msgid,
- maxx, maxx, maxx/4, LEFT);
- draw_string(0, 2*maxy/3, MSGSTR_FG, MSGSTR_BG, empty_msgstr,
- maxx, maxx, maxx/4, LEFT);
- }
-}
-
-void
-draw()
-{
- if (msgid_number > 0)
- draw_entry(&entries[msgid_number-1]);
- else
- draw_entry(NULL);
-
- if (show_help)
- draw_help();
-
- draw_status();
-}
-
int
main(int argc, char** argv)
{
@@ -385,7 +77,7 @@ main(int argc, char** argv)
if (argc > 1)
{
- strncpy(filename, argv[1], MAXPATH-1);
+ strncpy(filename, argv[1], MAXPATH);
filename[MAXPATH-1] = 0;
if (!filename[0])
print_error(EINVAL, "Invalid argument");
diff --git a/poe.do b/poe.do
@@ -1,5 +1,5 @@
for f in *.c; do
echo $f
done | xargs redo-ifchange
-gcc -g -Wall -o $3 poe.o termbox.o utf8.o
+gcc -g -Wall -o $3 poe.o draw.o termbox.o utf8.o util.o
diff --git a/util.c b/util.c
@@ -0,0 +1,29 @@
+/* See the file LICENSE for copyright and license details. */
+#include <bits/stdint-uintn.h>
+#include <stdlib.h>
+
+#include "termbox.h"
+#include "po.h"
+#include "util.h"
+
+size_t
+u8_string_to_unicode(uint32_t* us, const char* s)
+{
+ uint32_t uch;
+ uint32_t* pus = us;
+ int u8_len = 0;
+ size_t result = 0;
+
+ while (*s && u8_len != TB_EOF)
+ {
+ u8_len = tb_utf8_char_to_unicode(&uch, s);
+ *pus++ = uch;
+ if (u8_len != TB_EOF)
+ {
+ s += u8_len;
+ result++;
+ }
+ }
+ return result;
+}
+
diff --git a/util.h b/util.h
@@ -0,0 +1,14 @@
+#define LEN(x) (sizeof(x) / sizeof(x[0]))
+
+enum {
+ ERR_UNKNOWN_KEY,
+ ERR_NO_PREV,
+ ERR_NO_NEXT,
+ ERR_EXIT_KEY
+};
+
+#define MAXBUF 255
+#define MAXPATH 1024
+
+size_t u8_string_to_unicode(uint32_t* us, const char* s);
+