poe

Уређивач .po фајлова
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 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:
Mall.do | 1+
Aconfig.def.h | 10++++++++++
Aconfig.h | 10++++++++++
Adefault.do | 4++++
Adefault.h.do | 6++++++
Adraw.c | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adraw.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Apo.h | 14++++++++++++++
Mpoe.c | 332+++----------------------------------------------------------------------------
Mpoe.do | 2+-
Autil.c | 29+++++++++++++++++++++++++++++
Autil.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); +