首都ÅÄÖ打印不正确

时间:2016-07-11 15:58:43

标签: c character-encoding pthreads ncurses

当我试图让UTF-8和瑞典字符ÅÄÖ在UNIX-talk克隆中正确打印时,我感到困惑。

我已经将setLocale()的语言环境设置为sv_SE,并且我使用宽字符来尝试正确显示字符,小写åäö工作正常,但不知何故资本变体不起作用。

下面是完整的代码,我怀疑在reader()sender()或putch()中有一些我缺少的字符大小。

#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ncurses.h>
#include <pthread.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sched.h>
#include <pthread.h>
#include <locale.h>
#include <wchar.h>
#define MATRIXSIZE 1000
#define STACKSIZE 10000
#define CHATLEN 2048

#include <syslog.h>

int r = 0, i = 0, mode = -1;
wchar_t mybuf[CHATLEN], tmbuf[CHATLEN];

WINDOW *me;
WINDOW *them;

struct stuff {
    unsigned int col, row, size, realsize;
    pid_t childpid;
    pid_t mainpid;
    char matrix[MATRIXSIZE];
    char nukeline[1024];
    int nukesize;
    int terminate;
    struct massaskit {
        int writechan;
        int readchan;
        int sockfd;
        struct sockaddr_in server;
        struct sockaddr_in writeclient;
        struct sockaddr_in readclient;
        int c;
        struct hostent *serverhost;
        char hostname[256];
        uint16_t port;
    } bertil;
};

pthread_mutex_t scr_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t sendthread;  // Thread that listens to user's typing, and
                       //    puts the characters on the screen, and
                       //    transmits them over the network.

pthread_t readthread;  // Thread that reads characters from the network
                       //    and shows them on the screen.

int srv1(void *ptr)
{
    struct massaskit *sockstuff = (struct massaskit *)ptr;
    int opt = 1;

    if ((sockstuff->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket();");
        exit(-1);
    }

    sockstuff->server.sin_family = AF_INET;
    sockstuff->server.sin_addr.s_addr = INADDR_ANY;
    sockstuff->server.sin_port = htons(sockstuff->port);
    setsockopt(sockstuff->sockfd, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if (bind
        (sockstuff->sockfd, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) < 0) {
        perror("bind failed");
        exit(-1);
    }

    if ((listen(sockstuff->sockfd, 3)) < 0)
    {
        perror("listen");
        exit(-1);
    }

    sockstuff->c = sizeof(struct sockaddr_in);
    printf("waiting for readchan on %i sockstuff->port..\n",
           sockstuff->port);
    sockstuff->readchan =
        accept(sockstuff->sockfd,
           (struct sockaddr *)&sockstuff->readclient,
           (socklen_t *) & sockstuff->c);

    printf("got a connection! now need a connection on writechan (p:%i)\n",
           sockstuff->port);

    sockstuff->writechan =
        accept(sockstuff->sockfd,
           (struct sockaddr *)&sockstuff->writeclient,
           (socklen_t *) & sockstuff->c);

    printf("got a connection! both read/write  (p:%i)\n", sockstuff->port);
    shutdown(sockstuff->writechan, SHUT_RD);
    shutdown(sockstuff->readchan, SHUT_WR);

    if (close(sockstuff->sockfd) != 0)
    {
        exit(1);
    }

    return 0;
}

int cli1(void *ptr)
{
    /* srv1 starts with readchan, we start with writechan :-) */
    struct massaskit *sockstuff = (struct massaskit *)ptr;
    int opt = 1;
    sockstuff->sockfd = -1; /* make it broken so other function understand */
    if ((sockstuff->writechan = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("writechan->socket()");
        exit(-1);
    }
    else
    {
        printf("socket init is ok.got fd[%i] [writechan]\n",
               sockstuff->writechan);
    }

    setsockopt(sockstuff->writechan, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if ((sockstuff->serverhost =
         gethostbyname(sockstuff->hostname)) == NULL) {
        perror("error in resolving hostname :/\n");
        exit(-1);
    }
    else
    {
        printf("ok, resolved host, now making connection [writechan]!\n");
    }

    memset(&sockstuff->server, '\0', sizeof(struct in_addr));
    sockstuff->server.sin_family = AF_INET;
    memcpy(&sockstuff->server.sin_addr.s_addr,
           sockstuff->serverhost->h_addr,
           (size_t) sockstuff->serverhost->h_length);
    sockstuff->server.sin_port = htons(sockstuff->port);

    if (connect
        (sockstuff->writechan, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) == -1) {
        perror("connection");
        exit(-1);
    }
    else
    {
        printf("%s%s", "writechan established,starting readchan and", "sleeping 2s so other end can initalize the readchan.\n");
    }
    if ((sockstuff->readchan = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket();");
        exit(-1);
    }
    else
    {
        printf("readchan socket init ok.\n");
        fflush(stdout);
    }

    setsockopt(sockstuff->readchan, SOCK_STREAM, SO_REUSEADDR, &opt,
           sizeof(opt));

    if ((sockstuff->serverhost = gethostbyname(sockstuff->hostname)) == NULL)
    {
        perror("error in recieve channel, could'nt resolve host bailing.\n");
        exit(-1);
    }
    else
    {
        printf("readchan could resolve host nice shit alabama\n");
        fflush(stdout);
    }

    memset(&sockstuff->server, '\0', sizeof(struct in_addr));
    sockstuff->server.sin_family = AF_INET;
    memcpy(&sockstuff->server.sin_addr.s_addr,
           sockstuff->serverhost->h_addr,
           (size_t) sockstuff->serverhost->h_length);

    sockstuff->server.sin_port = htons(sockstuff->port);
    if (connect
        (sockstuff->readchan, (struct sockaddr *)&sockstuff->server,
         sizeof(sockstuff->server)) == -1) {
        perror("connect()");
        exit(-1);
    }
    else
    {
        printf("read chan estabiled. starting program!\n");
        fflush(stdout);
    }

    return 0;
}

void putch(WINDOW * win, wchar_t ch)
{
    syslog(LOG_INFO, "%04x", ch);
    if (ch == 4 || ch == 7) // Translate left-arrow, backspace to CTL-H
        ch = '\b';
    if(ch < ' ' && ch != '\t' &&
        ch != '\n' && ch != '\b'
    )
    {
        return;
    }

    pthread_mutex_lock(&scr_mutex);  // Get exclusive access to screen.
    wechochar(win, ch);

    if (ch == '\b')
    {
        wdelch(win);
        refresh();
    }

    pthread_mutex_unlock(&scr_mutex);
}

void setupscreen()
{
    int rows, cols;
    initscr();
    cbreak();
    noecho();
    intrflush(stdscr, FALSE);
    rows = (LINES - 3) / 2;
    cols = COLS - 2;
    me = newwin(rows, cols, 1, 1);
    them = newwin(rows, cols, rows + 2, 1);
    idlok(me, TRUE);
    scrollok(me, TRUE);
    keypad(me, TRUE);
    idlok(them, TRUE);
    scrollok(them, TRUE);
    border(0, 0, 0, 0, 0, 0, 0, 0);
    move(rows + 1, 1);
    hline(0, cols);
    refresh();
}

void* sender(void *ptr) {
    struct stuff *s = (struct stuff *)ptr;
    setupscreen();

    int ch;
    while (1)
    {
        if (i > CHATLEN - 1)
        {
            i = 0;
        }

        ch = wgetch(me);
        mybuf[i] = ch;
        if (ch == KEY_RESIZE)
        {
            clear();
            endwin();
            setupscreen();
            wchar_t *p = &mybuf[0];
            while (&(*p) < &mybuf[CHATLEN - 1])
            {
                putch(me, (*p));
                p++;
            }

            p = &tmbuf[0];
            while (&(*p) < &tmbuf[CHATLEN - 1])
            {
                putch(them, (*p));
                p++;
            }

            refresh();
        }
        else
        {
            putch(me, mybuf[i]);
            int writefd = s->bertil.writechan;
            write(writefd, &mybuf[i], sizeof(mybuf[i]));
        }
            i++;
    }
    pthread_cancel(sendthread);
    return NULL;
}

void* reader(void *ptr) {
    struct stuff *s = (struct stuff *)ptr;
    int ch;

    while(1)
    {
        if(r> CHATLEN - 1)
        {
            r = 0;
        }

        int readfd=s->bertil.readchan;
        if((read(readfd,&ch,sizeof(ch))) == 0)
        {
            endwin();
            refresh();
            return 0;
        }

        tmbuf[r] = ch;
        putch(them, tmbuf[r]);
        r++;
    }
        pthread_cancel(readthread);
        return NULL;
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "sv_SE");
    memset(mybuf, 0, CHATLEN);
    memset(tmbuf, 0, CHATLEN);

    struct stuff s;
    memset(&s, 0, sizeof(struct stuff));

    if (argc == 1)
    {
        printf("usage %s port        [host server on port]\n", argv[0]);
        printf("usage %s port host   [connecto  host:port]\n", argv[0]);
        exit(1);
    }
    else if (argc == 3)
    {
        s.bertil.port = (uint16_t) atoi(argv[1]);
        memset(s.bertil.hostname, 0, 256);
        memcpy(s.bertil.hostname, argv[2], strlen(argv[2]));
        cli1(&s.bertil);
    }
    else if (argc == 2)
    {
        s.bertil.port = (uint16_t) atoi(argv[1]);
        srv1(&s.bertil);
    }

    pthread_create(&readthread, NULL, reader, &s);  
    pthread_create(&sendthread, NULL, sender, &s);  
    pthread_join(sendthread, NULL);
    pthread_join(readthread,NULL);  
}

如果您想尝试该程序,请按如下方式编译:

  

gcc file.c -lpthread -lncurses

服务:

  

./ a.out 1234

连接:

  

./ a.out 1234 localhost

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

Actually, wchar_t is enough bits, and sign-extension problems do not appear likely.

However, the application using ncurses in two threads (sender and reader), and unless you have compiled it specially and allowed for mutexes, it won't work well. ncurses (like any implementation of curses) uses global variables for maintaining the screen. Multiple threads will exercise the library in unexpected ways.

Further reading:

答案 1 :(得分:1)

尝试在您的函数中使用unsigned char代替int

在putch中,您不需要wchar_tunsigned char(一个字节)在UTF-8(http://www.science.co.il/language/Character-code.asp?s=1252)中没问题。