Unicode support using str->wcs and char->wchar_t - iomenu - interactive terminal-based selection menu
HTML git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR README
DIR LICENSE
---
DIR commit b29fc218d36185be00fbb8952e26264d0d61508a
DIR parent 04f14a2a3fbe38525721285139ebf8af4350876f
HTML Author: Josuah Demangeonā ā µ <mail@josuah.net>
Date: Fri, 24 Mar 2017 22:45:33 +0100
Unicode support using str->wcs and char->wchar_t
Diffstat:
M iomenu.c | 127 ++++++++++++++++---------------
1 file changed, 67 insertions(+), 60 deletions(-)
---
DIR diff --git a/iomenu.c b/iomenu.c
@@ -1,10 +1,12 @@
-#include <ctype.h>
#include <fcntl.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
#include <sys/ioctl.h>
@@ -22,11 +24,11 @@ static struct termios termios;
FILE *tty_fp = NULL;
int tty_fd;
-static char input[BUFSIZ], formatted[BUFSIZ * 8];
-static int current = 0, offset = 0, prev = 0, next = 0;
-static int linec = 0, matchc = 0;
-static char **linev = NULL, **matchv = NULL;
-static int opt_l = 0;
+static int current = 0, offset = 0, prev = 0, next = 0;
+static int linec = 0, matchc = 0;
+static wchar_t **linev = NULL, **matchv = NULL;
+static wchar_t input[BUFSIZ], formatted[BUFSIZ * 8];
+static int opt_l = 0;
static void
@@ -73,45 +75,45 @@ set_terminal(void)
static void
read_lines(void)
{
- char buffer[BUFSIZ];
+ wchar_t buffer[BUFSIZ];
int size = 1 << 6;
- linev = malloc(sizeof (char **) * size);
- matchv = malloc(sizeof (char **) * size);
+ linev = malloc(sizeof (wchar_t **) * size);
+ matchv = malloc(sizeof (wchar_t **) * size);
if (linev == NULL || matchv == NULL)
die("malloc");
linev[0] = matchv[0] = NULL;
/* read the file into an array of lines */
- for (; fgets(buffer, sizeof buffer, stdin); linec++, matchc++) {
- int len = strlen(buffer);
+ for (; fgetws(buffer, sizeof buffer, stdin); linec++, matchc++) {
+ int len = wcslen(buffer);
if (len > 0 && buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
if (linec >= size) {
size *= 2;
- linev = realloc(linev, sizeof (char **) * size);
- matchv = realloc(matchv, sizeof (char **) * size);
+ linev = realloc(linev, sizeof (wchar_t **) * size);
+ matchv = realloc(matchv, sizeof (wchar_t **) * size);
if (linev == NULL || matchv == NULL)
die("realloc");
}
- linev[linec] = matchv[matchc] = malloc(len);
+ linev[linec] = matchv[matchc] = malloc(len * sizeof (wchar_t));
if (linev[linec] == NULL)
die("malloc");
- strcpy(linev[linec], buffer);
+ wcscpy(linev[linec], buffer);
}
}
static int
-match_line(char *line, char **tokv, int tokc)
+match_line(wchar_t *line, wchar_t **tokv, int tokc)
{
for (int i = 0; i < tokc; i++)
- if (strstr(line, tokv[i]) == NULL)
+ if (wcsstr(line, tokv[i]) == NULL)
return 0;
return 1;
@@ -119,45 +121,46 @@ match_line(char *line, char **tokv, int tokc)
int
-screen_width(char *str)
+screen_width(wchar_t *wcs)
{
int len = 0;
- for (int i = 0; str[i]; i++, len++)
- if (str[i] == '\t')
+ for (int i = 0; wcs[i]; i++, len++)
+ if (wcs[i] == '\t')
len += (len + 7) % 8;
return len;
}
-static char *
-format(char *str, int cols)
+static wchar_t *
+format(wchar_t *wcs, int cols)
{
int j = 0;
- for (int i = 0; str[i] && j < cols; i++) {
+ for (int i = 0; wcs[i] && j < cols; i++) {
- if (str[i] == '\t') {
+ if (wcs[i] == L'\t') {
for (int t = (j + 7) % 8 + 1; t > 0 && j < cols; t--)
- formatted[j++] = ' ';
+ formatted[j++] = L' ';
} else {
- formatted[j++] = str[i];
+ formatted[j++] = wcs[i];
}
}
- formatted[j] = '\0';
+ formatted[j] = L'\0';
return formatted;
}
static void
-print_string(char *str, int current)
+print_string(wchar_t *wcs, int current)
{
- fputs(current ? "\033[30;47m" : "", stderr);
- fputs(opt_l ? "\033[K " : " ", stderr);
- fprintf(stderr, "%s \033[m", format(str, ws.ws_col - 2));
+ fputws(current ? L"\033[30;47m" : L"", stderr);
+ fputws(opt_l ? L"\033[K " : L" ", stderr);
+ fputws(format(wcs, ws.ws_col - 2), stderr);
+ fputws(L" \033[m", stderr);
}
@@ -168,12 +171,12 @@ print_lines(int count)
offset = current / count * count;
for (int i = offset; p < count && i < matchc; p++, i++) {
- fputc('\n', stderr);
+ fputwc(L'\n', stderr);
print_string(matchv[i], i == current);
}
while (p++ <= count)
- fputs("\n\033[K", stderr);
+ fputws(L"\n\033[K", stderr);
}
@@ -210,13 +213,13 @@ print_columns(void)
next = next_page(offset, ws.ws_col - OFFSET - 4);
}
- fputs(offset > 0 ? "< " : " ", stderr);
+ fputws(offset > 0 ? L"< " : L" ", stderr);
for (int i = offset; i < next && i < matchc; i++)
print_string(matchv[i], i == current);
if (next < matchc)
- fprintf(stderr, "\033[%dC>", ws.ws_col - OFFSET);
+ fwprintf(stderr, L"\033[%dC>", ws.ws_col - OFFSET);
}
@@ -230,42 +233,45 @@ print_screen(void)
count = MIN(opt_l, ws.ws_row - 2);
- fputs("\r\033[K", stderr);
+ fputws(L"\r\033[K", stderr);
if (opt_l) {
print_lines(count);
- fprintf(stderr, "\033[%dA", count + 1);
+ fwprintf(stderr, L"\033[%dA", count + 1);
} else {
- fputs("\033[30C", stderr);
+ fputws(L"\033[30C", stderr);
print_columns();
}
format(input, opt_l || matchc == 0 ? ws.ws_col : OFFSET - 3);
- fprintf(stderr, "\r %s", formatted);
+ fputws(L"\r ", stderr);
+ fputws(formatted, stderr);
+
+ fflush(stderr);
}
static void
-print_clear(int lines)
+clear(int lines)
{
for (int i = 0; i < lines + 1; i++)
- fputs("\r\033[K\n", stderr);
- fprintf(stderr, "\033[%dA", lines + 1);
+ fputws(L"\r\033[K\n", stderr);
+ fwprintf(stderr, L"\033[%dA", lines + 1);
}
static void
filter_lines(void)
{
- char **tokv = NULL, *s, buffer[sizeof (input)];
- int tokc = 0, n = 0;
+ wchar_t **tokv = NULL, *tok, *s, buffer[sizeof (input)];
+ int tokc = 0, n = 0;
current = offset = prev = next = 0;
- strcpy(buffer, input);
+ wcscpy(buffer, input);
- for (s = strtok(buffer, " "); s; s = strtok(NULL, " "), tokc++) {
+ for (s = wcstok(buffer, L" ", &tok); s; s = wcstok(NULL, L" ", &tok), tokc++) {
if (tokc >= n) {
tokv = realloc(tokv, ++n * sizeof (*tokv));
@@ -289,13 +295,13 @@ filter_lines(void)
static void
remove_word_input()
{
- int len = strlen(input) - 1;
+ int len = wcslen(input) - 1;
- for (int i = len; i >= 0 && isspace(input[i]); i--)
+ for (int i = len; i >= 0 && iswspace(input[i]); i--)
input[i] = '\0';
- len = strlen(input) - 1;
- for (int i = len; i >= 0 && !isspace(input[i]); i--)
+ len = wcslen(input) - 1;
+ for (int i = len; i >= 0 && !iswspace(input[i]); i--)
input[i] = '\0';
filter_lines();
@@ -305,9 +311,9 @@ remove_word_input()
static void
add_character(char key)
{
- int len = strlen(input);
+ int len = wcslen(input);
- if (isprint(key)) {
+ if (iswprint(key)) {
input[len] = key;
input[len + 1] = '\0';
}
@@ -319,8 +325,8 @@ add_character(char key)
static void
print_selection(void)
{
- fputs("\r\033[K", stderr);
- puts(matchc > 0 ? matchv[current] : input);
+ fputws(L"\r\033[K", stderr);
+ fputws(matchc > 0 ? matchv[current] : input, stdout);
}
@@ -330,12 +336,12 @@ print_selection(void)
static int
input_key(void)
{
- char key = fgetc(tty_fp);
+ wchar_t key = fgetwc(tty_fp);
switch (key) {
case CONTROL('C'):
- print_clear(opt_l);
+ clear(opt_l);
return EXIT_FAILURE;
case CONTROL('U'):
@@ -349,7 +355,7 @@ input_key(void)
case 127:
case CONTROL('H'): /* backspace */
- input[strlen(input) - 1] = '\0';
+ input[wcslen(input) - 1] = '\0';
filter_lines();
break;
@@ -363,7 +369,7 @@ input_key(void)
case CONTROL('I'): /* tab */
if (linec > 0)
- strcpy(input, matchv[current]);
+ wcscpy(input, matchv[current]);
filter_lines();
break;
@@ -408,7 +414,7 @@ input_get(void)
static void
usage(void)
{
- fputs("usage: iomenu [-l lines]\n", stderr);
+ fputws(L"usage: iomenu [-l lines]\n", stderr);
exit(EXIT_FAILURE);
}
@@ -433,6 +439,7 @@ main(int argc, char *argv[])
}
}
+ setlocale(LC_ALL, "");
read_lines();
tty_fp = fopen("/dev/tty", "r");
@@ -442,7 +449,7 @@ main(int argc, char *argv[])
exit_code = input_get();
tcsetattr(tty_fd, TCSANOW, &termios);
- print_clear(opt_l);
+ clear(opt_l);
fclose(tty_fp);
close(tty_fd);
free_all();