Capital ÅÄÖ 打印不正确

Capital ÅÄÖ not printing correctly

我对在 UNIX-talk 克隆中正确打印 UTF-8 和瑞典语字符 ÅÄÖ 时遇到的问题感到困惑。

我已经使用 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, '[=10=]', 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, '[=10=]', 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

如有任何帮助,我们将不胜感激!

尝试在您的函数中使用 unsigned char 而不是 int

在putch中,你不需要wchar_tunsigned char(一个字节)在UTF-8中就可以了(http://www.science.co.il/language/Character-code.asp?s=1252)。

其实wchar_t位就够了,符号扩展问题不太可能出现。

但是,在两个线程(senderreader)中使用 ncurses 的应用程序,除非您对其进行了特殊编译并允许互斥锁,否则它不会很好地工作。 ncurses(就像 curses 的任何实现一样)使用全局变量来维护屏幕。多个线程将以意想不到的方式运行库。

延伸阅读: