Make talk(1) capable of displaying UTF-8 characters.
Sponsored by: Nginx, Inc.
This commit is contained in:
parent
7b04b74ec9
commit
7802205b1a
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user