Author: ngie
Date: Thu Oct 23 00:39:19 2014
New Revision: 273496
URL: https://svnweb.freebsd.org/changeset/base/273496

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

Modified:
  stable/10/usr.bin/talk/Makefile
  stable/10/usr.bin/talk/display.c
  stable/10/usr.bin/talk/io.c
  stable/10/usr.bin/talk/talk.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/usr.bin/talk/Makefile
==============================================================================
--- stable/10/usr.bin/talk/Makefile     Thu Oct 23 00:37:52 2014        
(r273495)
+++ stable/10/usr.bin/talk/Makefile     Thu Oct 23 00:39:19 2014        
(r273496)
@@ -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: stable/10/usr.bin/talk/display.c
==============================================================================
--- stable/10/usr.bin/talk/display.c    Thu Oct 23 00:37:52 2014        
(r273495)
+++ stable/10/usr.bin/talk/display.c    Thu Oct 23 00:39:19 2014        
(r273496)
@@ -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: stable/10/usr.bin/talk/io.c
==============================================================================
--- stable/10/usr.bin/talk/io.c Thu Oct 23 00:37:52 2014        (r273495)
+++ stable/10/usr.bin/talk/io.c Thu Oct 23 00:39:19 2014        (r273496)
@@ -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: stable/10/usr.bin/talk/talk.h
==============================================================================
--- stable/10/usr.bin/talk/talk.h       Thu Oct 23 00:37:52 2014        
(r273495)
+++ stable/10/usr.bin/talk/talk.h       Thu Oct 23 00:39:19 2014        
(r273496)
@@ -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 *);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to