add uft-8 support - lchat - A line oriented chat front end for ii.
 (HTM) git clone git://git.suckless.org/lchat
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 0f8af7612e393d40705e953306bc0555f026c2f7
 (DIR) parent 569292df0c821cf2c977d224345ec009e344cb1c
 (HTM) Author: Jan Klemkow <j.klemkow@wemelug.de>
       Date:   Sat,  9 Jul 2016 20:30:21 +0200
       
       add uft-8 support
       
       Diffstat:
         M Makefile                            |      26 +++++++++++++++++++++-----
         M lchat.c                             |      44 +++++++++++++++++++++----------
         M slackline.c                         |     151 ++++++++++++++++++++++++-------
         M slackline.h                         |      18 ++++++++++++++++--
       
       4 files changed, 183 insertions(+), 56 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       @@ -1,18 +1,34 @@
       -CC=cc
       -CFLAGS=-std=c99 -pedantic -Wall -Wextra
       +CC ?= cc
       +CFLAGS = -std=c99 -pedantic -Wall -Wextra -g
        
       -.PHONY: all clean
       +# utf.h
       +CFLAGS += -I/usr/local/include
       +LIBS = -L/usr/local/lib -lutf
       +
       +.PHONY: all clean test debug
        
        all: lchat
        clean:
       -        rm -f lchat *.o
       +        rm -f lchat *.o *.core
       +
       +test: sl_test
       +        ./sl_test
       +
       +debug:
       +        gdb lchat lchat.core
        
        lchat: lchat.o slackline.o
       -        $(CC) -o $@ lchat.o slackline.o
       +        $(CC) -o $@ lchat.o slackline.o $(LIBS)
        
        lchat.o: lchat.c
                $(CC) -c $(CFLAGS) -D_BSD_SOURCE -D_XOPEN_SOURCE -D_GNU_SOURCE \
                    -o $@ lchat.c
        
       +sl_test.o: sl_test.c slackline.h
       +        $(CC) $(CFLAGS) -c -o $@ sl_test.c
       +
       +sl_test: sl_test.o slackline.o slackline.h
       +        $(CC) $(CFLAGS) -o $@ sl_test.o slackline.o $(LIBS)
       +
        slackline.o: slackline.c slackline.h
                $(CC) -c $(CFLAGS) -o $@ slackline.c
 (DIR) diff --git a/lchat.c b/lchat.c
       @@ -112,9 +112,9 @@ line_output(struct slackline *sl, char *file)
                        err(EXIT_FAILURE, "open: %s", file);
        
                /* replace NUL-terminator with newline as line separator for file */
       -        sl->buf[sl->len] = '\n';
       +        sl->buf[sl->blen] = '\n';
        
       -        if (write(fd, sl->buf, sl->len + 1) == -1)
       +        if (write(fd, sl->buf, sl->blen + 1) == -1)
                        err(EXIT_FAILURE, "write");
        
                if (close(fd) == -1)
       @@ -137,7 +137,7 @@ main(int argc, char *argv[])
                struct termios term;
                struct slackline *sl = sl_init();
                int fd = STDIN_FILENO;
       -        int c;
       +        char c;
                int ch;
                bool empty_line = false;
                bool bell_flag = true;
       @@ -285,15 +285,28 @@ main(int argc, char *argv[])
        
                        /* handle keyboard intput */
                        if (pfd[0].revents & POLLIN) {
       -                        c = getchar();
       -                        if (c == 13) {        /* return */
       -                                if (sl->len == 0 && empty_line == false)
       +                        ssize_t ret = read(fd, &c, sizeof c);
       +
       +                        if (ret == -1)
       +                                err(EXIT_FAILURE, "read");
       +
       +                        if (ret == 0)
       +                                return EXIT_SUCCESS;
       +
       +                        switch (c) {
       +                        case 4:                /* eot */
       +                                return EXIT_SUCCESS;
       +                                break;
       +                        case 13:        /* return */
       +                                if (sl->rlen == 0 && empty_line == false)
                                                goto out;
                                        line_output(sl, in_file);
                                        sl_reset(sl);
       +                                break;
       +                        default:
       +                                if (sl_keystroke(sl, c) == -1)
       +                                        errx(EXIT_FAILURE, "sl_keystroke");
                                }
       -                        if (sl_keystroke(sl, c) == -1)
       -                                errx(EXIT_FAILURE, "sl_keystroke");
                        }
        
                        /* handle tail command error and its broken pipe */
       @@ -324,19 +337,22 @@ main(int argc, char *argv[])
                        fputs(sl->buf, stdout);
        
                        /* save amount of overhanging lines */
       -                loverhang = (prompt_len + sl->len) / winsize.ws_col;
       +                loverhang = (prompt_len + sl->rlen) / winsize.ws_col;
        
                        /* correct line wrap handling */
       -                if ((prompt_len + sl->len) > 0 &&
       -                    (prompt_len + sl->len) % winsize.ws_col == 0)
       +                if ((prompt_len + sl->rlen) > 0 &&
       +                    (prompt_len + sl->rlen) % winsize.ws_col == 0)
                                fputs("\n", stdout);
        
       -                if (sl->cur < sl->len) {        /* move the cursor */
       +                if (sl->rcur < sl->rlen) {        /* move the cursor */
                                putchar('\r');
                                /* HACK: because \033[0C does the same as \033[1C */
       -                        if (sl->cur + prompt_len > 0)
       -                                printf("\033[%zuC", sl->cur + prompt_len);
       +                        if (sl->rcur + prompt_len > 0)
       +                                printf("\033[%zuC", sl->rcur + prompt_len);
                        }
       +
       +                if (fflush(stdout) == EOF)
       +                        err(EXIT_FAILURE, "fflush");
                }
                return EXIT_SUCCESS;
        }
 (DIR) diff --git a/slackline.c b/slackline.c
       @@ -1,5 +1,5 @@
        /*
       - * Copyright (c) 2015 Jan Klemkow <j.klemkow@wemelug.de>
       + * Copyright (c) 2015-2016 Jan Klemkow <j.klemkow@wemelug.de>
         *
         * Permission to use, copy, modify, and distribute this software for any
         * purpose with or without fee is hereby granted, provided that the above
       @@ -14,10 +14,12 @@
         * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
         */
        
       +#include <stdbool.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
       -#include <stdbool.h>
       +
       +#include <utf.h>
        
        #include "slackline.h"
        
       @@ -35,6 +37,9 @@ sl_init(void)
                        return NULL;
                }
        
       +        memset(sl->ubuf, 0, sizeof(sl->ubuf));
       +        sl->ubuf_len = 0;
       +
                sl_reset(sl);
        
                return sl;
       @@ -51,15 +56,58 @@ void
        sl_reset(struct slackline *sl)
        {
                sl->buf[0] = '\0';
       -        sl->len = 0;
       -        sl->cur = 0;
       +        sl->ptr = sl->buf;
       +        sl->last = sl->buf;
       +
       +        sl->bcur = 0;
       +        sl->blen = 0;
       +        sl->rcur = 0;
       +        sl->rlen = 0;
       +
                sl->esc = ESC_NONE;
       +        sl->ubuf_len = 0;
       +}
       +
       +static size_t
       +sl_postobyte(struct slackline *sl, size_t pos)
       +{
       +        char *ptr = &sl->buf[0];
       +        size_t byte = 0;
       +
       +        for (;pos > 0; pos--) {
       +                for (size_t i = 0;; i++) {
       +                        if (fullrune(ptr, i) == 1) {
       +                                ptr += i;
       +                                byte += i;
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        return byte;
       +}
       +
       +static char *
       +sl_postoptr(struct slackline *sl, size_t pos)
       +{
       +        char *ptr = &sl->buf[0];
       +
       +        for (;pos > 0; pos--) {
       +                for (size_t i = 0;; i++) {
       +                        if (fullrune(ptr, i) == 1) {
       +                                ptr += i;
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        return ptr;
        }
        
        int
        sl_keystroke(struct slackline *sl, int key)
        {
       -        if (sl == NULL || sl->len < sl->cur)
       +        if (sl == NULL || sl->rlen < sl->rcur)
                        return -1;
        
                /* handle escape sequences */
       @@ -75,55 +123,88 @@ sl_keystroke(struct slackline *sl, int key)
                        case 'B':        /* down  */
                                break;
                        case 'C':        /* right */
       -                        if (sl->cur < sl->len)
       -                                sl->cur++;
       +                        if (sl->rcur < sl->rlen)
       +                                sl->rcur++;
       +                        sl->bcur = sl_postobyte(sl, sl->rcur);
                                break;
                        case 'D':        /* left */
       -                        if (sl->cur > 0)
       -                                sl->cur--;
       +                        if (sl->rcur > 0)
       +                                sl->rcur--;
       +                        sl->bcur = sl_postobyte(sl, sl->rcur);
                                break;
                        case 'H':        /* Home  */
       -                        sl->cur = 0;
       +                        sl->bcur = sl->rcur = 0;
                                break;
                        case 'F':        /* End   */
       -                        sl->cur = sl->len;
       +                        sl->rcur = sl->rlen;
       +                        sl->bcur = sl_postobyte(sl, sl->rcur);
                                break;
                        }
                        sl->esc = ESC_NONE;
                        return 0;
                }
        
       -        /* add character to buffer */
       -        if (key >= 32 && key < 127) {
       -                if (sl->cur < sl->len) {
       -                        memmove(sl->buf + sl->cur + 1, sl->buf + sl->cur,
       -                            sl->len - sl->cur);
       -                        sl->buf[sl->cur++] = key;
       -                } else {
       -                        sl->buf[sl->cur++] = key;
       -                        sl->buf[sl->cur] = '\0';
       -                }
       -                sl->len++;
       -                return 0;
       -        }
       -
                /* handle ctl keys */
                switch (key) {
                case 27:        /* Escape */
                        sl->esc = ESC;
       -                break;
       +                return 0;
                case 127:        /* backspace */
                case 8:                /* backspace */
       -                if (sl->cur == 0)
       -                        break;
       -                if (sl->cur < sl->len)
       -                        memmove(sl->buf + sl->cur - 1, sl->buf + sl->cur,
       -                            sl->len - sl->cur);
       -                sl->cur--;
       -                sl->len--;
       -                sl->buf[sl->len] = '\0';
       -                break;
       +                if (sl->rcur == 0)
       +                        return 0;
       +
       +                char *ncur = sl_postoptr(sl, sl->rcur - 1);
       +
       +                if (sl->rcur < sl->rlen)
       +                        memmove(ncur, sl->ptr, sl->last - sl->ptr);
       +
       +                sl->rcur--;
       +                sl->rlen--;
       +                sl->last -= sl->ptr - ncur;
       +                sl->ptr = ncur;
       +                sl->bcur = sl_postobyte(sl, sl->rcur);
       +                sl->blen = sl_postobyte(sl, sl->rlen);
       +                *sl->last = '\0';
       +                return 0;
                }
        
       +        /* byte-wise composing of UTF-8 runes */
       +        sl->ubuf[sl->ubuf_len++] = key;
       +        if (fullrune(sl->ubuf, sl->ubuf_len) == 0)
       +                return 0;
       +
       +        if (sl->blen + sl->ubuf_len >= sl->bufsize) {
       +                char *nbuf;
       +
       +                if ((nbuf = realloc(sl->buf, sl->bufsize * 2)) == NULL)
       +                        return -1;
       +
       +                sl->buf = nbuf;
       +                sl->bufsize *= 2;
       +        }
       +
       +        /* add character to buffer */
       +        if (sl->rcur < sl->rlen) {        /* insert into buffer */
       +                char *ncur = sl_postoptr(sl, sl->rcur + 1);
       +                char *cur = sl_postoptr(sl, sl->rcur);
       +                char *end = sl_postoptr(sl, sl->rlen);
       +
       +                memmove(ncur, cur, end - cur);
       +        }
       +
       +        memcpy(sl->last, sl->ubuf, sl->ubuf_len);
       +
       +        sl->ptr  += sl->ubuf_len;
       +        sl->last += sl->ubuf_len;
       +        sl->bcur += sl->ubuf_len;
       +        sl->blen += sl->ubuf_len;
       +        sl->ubuf_len = 0;
       +
       +        sl->rcur++;
       +        sl->rlen++;
       +
       +        *sl->last = '\0';
       +
                return 0;
        }
 (DIR) diff --git a/slackline.h b/slackline.h
       @@ -6,11 +6,25 @@
        enum esc_seq {ESC_NONE, ESC, ESC_BRACKET};
        
        struct slackline {
       +        /* buffer */
                char *buf;
       +        char *ptr;        /* ptr of cursor */
       +        char *last;        /* ptr of last byte of string */
                size_t bufsize;
       -        size_t len;
       -        size_t cur;
       +
       +        /* byte positions */
       +        size_t bcur;        /* first byte of the rune of the cursor */
       +        size_t blen;        /* amount of bytes of current string */
       +
       +        /* rune positions */
       +        size_t rcur;        /* cursor */
       +        size_t rlen;        /* amount of runes */
       +
                enum esc_seq esc;
       +
       +        /* UTF-8 handling */
       +        char ubuf[6];        /* UTF-8 buffer */
       +        size_t ubuf_len;
        };
        
        struct slackline *sl_init(void);