Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Mar 2014 11:58:49 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r263264 - head/usr.bin/talk
Message-ID:  <201403171158.s2HBwnQ7027877@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Mon Mar 17 11:58:48 2014
New Revision: 263264
URL: http://svnweb.freebsd.org/changeset/base/263264

Log:
  Make talk(1) capable of displaying UTF-8 characters.
  
  Sponsored by:	Nginx, Inc.

Modified:
  head/usr.bin/talk/Makefile
  head/usr.bin/talk/display.c
  head/usr.bin/talk/io.c
  head/usr.bin/talk/talk.h

Modified: head/usr.bin/talk/Makefile
==============================================================================
--- head/usr.bin/talk/Makefile	Mon Mar 17 09:01:01 2014	(r263263)
+++ head/usr.bin/talk/Makefile	Mon Mar 17 11:58:48 2014	(r263264)
@@ -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>

Modified: head/usr.bin/talk/display.c
==============================================================================
--- head/usr.bin/talk/display.c	Mon Mar 17 09:01:01 2014	(r263263)
+++ head/usr.bin/talk/display.c	Mon Mar 17 11:58:48 2014	(r263264)
@@ -41,9 +41,14 @@ static const char sccsid[] = "@(#)displa
  */
 #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;
-
-			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;
-		}
-		/* 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;
-		}
-		if (*text == '\f') {
-			if (win == &my_win)
-				wrefresh(curscr);
-			text++;
-			continue;
-		}
-		if (*text == '\7') {
-			write(STDOUT_FILENO, text, 1);
-			text++;
-			continue;
+		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--;
 		}
-		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);
+		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);
-		text++;
+		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);
 }
 

Modified: head/usr.bin/talk/io.c
==============================================================================
--- head/usr.bin/talk/io.c	Mon Mar 17 09:01:01 2014	(r263263)
+++ head/usr.bin/talk/io.c	Mon Mar 17 11:58:48 2014	(r263264)
@@ -46,14 +46,17 @@ static const char sccsid[] = "@(#)io.c	8
 #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);
+			}
 		}
 	}
 }

Modified: head/usr.bin/talk/talk.h
==============================================================================
--- head/usr.bin/talk/talk.h	Mon Mar 17 09:01:01 2014	(r263263)
+++ head/usr.bin/talk/talk.h	Mon Mar 17 11:58:48 2014	(r263264)
@@ -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 *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403171158.s2HBwnQ7027877>