Make talk(1) capable of displaying UTF-8 characters.

Sponsored by:	Nginx, Inc.
This commit is contained in:
glebius 2014-03-17 11:58:48 +00:00
parent 7b04b74ec9
commit 7802205b1a
4 changed files with 143 additions and 122 deletions

View File

@ -4,7 +4,7 @@
PROG= talk
SRCS= ctl.c ctl_transact.c display.c get_addrs.c get_iface.c get_names.c \
init_disp.c invite.c io.c look_up.c msgs.c talk.c
DPADD= ${LIBCURSES}
LDADD= -lcurses
DPADD= ${LIBCURSESW}
LDADD= -lcursesw
.include <bsd.prog.mk>

View File

@ -41,9 +41,14 @@ static const char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
*/
#include <ctype.h>
#include <unistd.h>
#include <wctype.h>
#define _XOPEN_SOURCE_EXTENDED
#include <curses.h>
#include "talk.h"
void display(xwin_t *, wchar_t *);
xwin_t my_win;
xwin_t his_win;
WINDOW *line_win;
@ -61,111 +66,130 @@ max(int a, int b)
return (a > b ? a : b);
}
static cchar_t *
makecchar(wchar_t in)
{
static cchar_t cc;
wchar_t wc[2];
wc[0] = in;
wc[1] = L'\0';
if (setcchar(&cc, wc, A_NORMAL, 0, NULL) != OK)
p_error("settchar(3) failure");
return (&cc);
}
/*
* Display some text on somebody's window, processing some control
* Display a symbol on somebody's window, processing some control
* characters while we are at it.
*/
void
display(xwin_t *win, char *text, int size)
display(xwin_t *win, wchar_t *wc)
{
int i;
char cch;
for (i = 0; i < size; i++) {
if (*text == '\n' || *text == '\r') {
waddch(win->x_win, '\n');
getyx(win->x_win, win->x_line, win->x_col);
text++;
continue;
}
if (*text == 004 && win == &my_win) {
/* control-D clears the screen */
/*
* Alas, can't use variables in C switch statement.
* Workaround these 3 cases with goto.
*/
if (*wc == win->kill)
goto kill;
else if (*wc == win->cerase)
goto cerase;
else if (*wc == win->werase)
goto werase;
switch (*wc) {
case L'\n':
case L'\r':
wadd_wch(win->x_win, makecchar(L'\n'));
getyx(win->x_win, win->x_line, win->x_col);
wrefresh(win->x_win);
return;
case 004:
if (win == &my_win) {
/* Ctrl-D clears the screen. */
werase(my_win.x_win);
getyx(my_win.x_win, my_win.x_line, my_win.x_col);
wrefresh(my_win.x_win);
werase(his_win.x_win);
getyx(his_win.x_win, his_win.x_line, his_win.x_col);
wrefresh(his_win.x_win);
text++;
continue;
}
return;
/* erase character */
if ( *text == win->cerase
|| *text == 010 /* BS */
|| *text == 0177 /* DEL */
) {
wmove(win->x_win, win->x_line, max(--win->x_col, 0));
getyx(win->x_win, win->x_line, win->x_col);
waddch(win->x_win, ' ');
wmove(win->x_win, win->x_line, win->x_col);
getyx(win->x_win, win->x_line, win->x_col);
text++;
continue;
}
/* Erase character. */
case 010: /* BS */
case 0177: /* DEL */
cerase:
wmove(win->x_win, win->x_line, max(--win->x_col, 0));
getyx(win->x_win, win->x_line, win->x_col);
waddch(win->x_win, ' ');
wmove(win->x_win, win->x_line, win->x_col);
getyx(win->x_win, win->x_line, win->x_col);
wrefresh(win->x_win);
return;
case 027: /* ^W */
werase:
{
/*
* On word erase search backwards until we find
* the beginning of a word or the beginning of
* the line.
*/
if ( *text == win->werase
|| *text == 027 /* ^W */
) {
int endcol, xcol, ii, c;
int endcol, xcol, c;
endcol = win->x_col;
xcol = endcol - 1;
while (xcol >= 0) {
c = readwin(win->x_win, win->x_line, xcol);
if (c != ' ')
break;
xcol--;
}
while (xcol >= 0) {
c = readwin(win->x_win, win->x_line, xcol);
if (c == ' ')
break;
xcol--;
}
wmove(win->x_win, win->x_line, xcol + 1);
for (ii = xcol + 1; ii < endcol; ii++)
waddch(win->x_win, ' ');
wmove(win->x_win, win->x_line, xcol + 1);
getyx(win->x_win, win->x_line, win->x_col);
text++;
continue;
endcol = win->x_col;
xcol = endcol - 1;
while (xcol >= 0) {
c = readwin(win->x_win, win->x_line, xcol);
if (c != ' ')
break;
xcol--;
}
/* line kill */
if ( *text == win->kill
|| *text == 025 /* ^U */
) {
wmove(win->x_win, win->x_line, 0);
wclrtoeol(win->x_win);
getyx(win->x_win, win->x_line, win->x_col);
text++;
continue;
while (xcol >= 0) {
c = readwin(win->x_win, win->x_line, xcol);
if (c == ' ')
break;
xcol--;
}
if (*text == '\f') {
if (win == &my_win)
wrefresh(curscr);
text++;
continue;
}
if (*text == '\7') {
write(STDOUT_FILENO, text, 1);
text++;
continue;
}
if (!isprint((unsigned char)*text) && *text != '\t') {
waddch(win->x_win, '^');
getyx(win->x_win, win->x_line, win->x_col);
cch = (*text & 63) + 64;
waddch(win->x_win, cch);
} else
waddch(win->x_win, (unsigned char)*text);
wmove(win->x_win, win->x_line, xcol + 1);
for (int i = xcol + 1; i < endcol; i++)
waddch(win->x_win, ' ');
wmove(win->x_win, win->x_line, xcol + 1);
getyx(win->x_win, win->x_line, win->x_col);
text++;
wrefresh(win->x_win);
return;
}
case 025: /* ^U */
kill:
wmove(win->x_win, win->x_line, 0);
wclrtoeol(win->x_win);
getyx(win->x_win, win->x_line, win->x_col);
wrefresh(win->x_win);
return;
case L'\f':
if (win == &my_win)
wrefresh(curscr);
return;
case L'\7':
write(STDOUT_FILENO, wc, sizeof(*wc));
return;
}
if (iswprint(*wc) || *wc == L'\t')
wadd_wch(win->x_win, makecchar(*wc));
else
beep();
getyx(win->x_win, win->x_line, win->x_col);
wrefresh(win->x_win);
}

View File

@ -46,14 +46,17 @@ static const char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define _XOPEN_SOURCE_EXTENDED
#include <curses.h>
#include "talk.h"
#include "talk_ctl.h"
#define A_LONG_TIME 10000000
extern void display(xwin_t *, wchar_t *);
volatile sig_atomic_t gotwinch = 0;
@ -65,9 +68,10 @@ talk(void)
{
struct hostent *hp, *hp2;
int nb;
fd_set read_set, read_template;
char buf[BUFSIZ], **addr, *his_machine_name;
struct timeval wait;
fd_set read_set;
wchar_t buf[BUFSIZ];
char **addr, *his_machine_name;
FILE *sockfp;
his_machine_name = NULL;
hp = gethostbyaddr((const char *)&his_machine_addr.s_addr,
@ -85,64 +89,58 @@ talk(void)
}
if (his_machine_name == NULL)
his_machine_name = strdup(inet_ntoa(his_machine_addr));
snprintf(buf, sizeof(buf), "Connection established with %s@%s.",
snprintf((char *)buf, sizeof(buf), "Connection established with %s@%s.",
msg.r_name, his_machine_name);
free(his_machine_name);
message(buf);
message((char *)buf);
write(STDOUT_FILENO, "\007\007\007", 3);
current_line = 0;
if ((sockfp = fdopen(sockt, "w+")) == NULL)
p_error("fdopen");
setvbuf(sockfp, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
/*
* Wait on both the other process (sockt_mask) and
* standard input ( STDIN_MASK )
* Wait on both the other process (sockt) and standard input.
*/
FD_ZERO(&read_template);
FD_SET(sockt, &read_template);
FD_SET(fileno(stdin), &read_template);
for (;;) {
read_set = read_template;
wait.tv_sec = A_LONG_TIME;
wait.tv_usec = 0;
nb = select(32, &read_set, 0, 0, &wait);
FD_ZERO(&read_set);
FD_SET(sockt, &read_set);
FD_SET(fileno(stdin), &read_set);
nb = select(32, &read_set, 0, 0, NULL);
if (gotwinch) {
resize_display();
gotwinch = 0;
}
if (nb <= 0) {
if (errno == EINTR) {
read_set = read_template;
if (errno == EINTR)
continue;
}
/* panic, we don't know what happened */
/* Panic, we don't know what happened. */
p_error("Unexpected error from select");
quit();
}
if (FD_ISSET(sockt, &read_set)) {
/* There is data on sockt */
nb = read(sockt, buf, sizeof buf);
if (nb <= 0) {
wint_t w;
/* There is data on sockt. */
w = fgetwc(sockfp);
if (w == WEOF) {
message("Connection closed. Exiting");
quit();
}
display(&his_win, buf, nb);
display(&his_win, &w);
}
if (FD_ISSET(fileno(stdin), &read_set)) {
/*
* We can't make the tty non_blocking, because
* curses's output routines would screw up
*/
int i;
ioctl(0, FIONREAD, (void *) &nb);
if (nb > (ssize_t)(sizeof buf))
nb = sizeof buf;
nb = read(STDIN_FILENO, buf, nb);
display(&my_win, buf, nb);
/* might lose data here because sockt is non-blocking */
for (i = 0; i < nb; ++i)
if (buf[i] == '\r')
buf[i] = '\n';
write(sockt, buf, nb);
wint_t w;
if ((w = getwchar()) != WEOF) {
display(&my_win, &w);
(void )fputwc(w, sockfp);
(void )fflush(sockfp);
}
}
}
}

View File

@ -69,7 +69,6 @@ extern int check_local(void);
extern void check_writeable(void);
extern void ctl_transact(struct in_addr,CTL_MSG,int,CTL_RESPONSE *);
extern void disp_msg(int);
extern void display(xwin_t *, char *, int);
extern void end_msgs(void);
extern void get_addrs(const char *, const char *);
extern int get_iface(struct in_addr *, struct in_addr *);