诅咒中的非间距字符

时间:2020-05-21 20:46:32

标签: c locale ncurses curses

我试图编写一个基本程序,以使用 curs non-spacing character 在C语言中打印ā(带上划线的a)。我已将语言环境设置为en_US.UTF-8,并且能够使用该语言环境打印国际语言字符。此代码仅打印不带上划线的。我也与ncurses得到类似的结果。要在屏幕上显示ā,我还需要做什么?

def _if(v, cond, yes, no = nil)
  if cond.call(v)
    yes.call(v)
  else
    no&.call(v)
  end
end

cond = lambda { |v| v > 2 }
yes = lambda { |v| v + 1 }
no = lambda { |v| 0 }

_if(1, cond, yes, no)
_if(3, cond, yes, no)
_if(1, cond, yes)

3 个答案:

答案 0 :(得分:0)

curses调用需要指向数据的指针,而不仅仅是指针。

可以为宽字符传递以null终止的数组,但是cchar_t数据的指针需要一些修复。

以下是该程序的修复程序:

> diff -u foo.c.orig foo.c
--- foo.c.orig  2020-05-21 19:50:48.000000000 -0400
+++ foo.c       2020-05-21 19:51:46.799849136 -0400
@@ -3,7 +3,7 @@
 #include <wchar.h>
 #include <assert.h>

-int main() {  
+int main(void) {  
     setlocale(LC_ALL, "");
     initscr();
     int s = 0x41;     // represents 'a'
@@ -12,11 +12,11 @@
     assert(wcwidth(ns) == 0);

     wchar_t wstr[] = { s, ns, L'\0'};
-    cchar_t *cc;
-    int x = setcchar(cc, wstr, 0x00, 0, NULL);
+    cchar_t cc;
+    int x = setcchar(&cc, wstr, 0x00, 0, NULL);
     assert(x == 0);

-    add_wch(cc);
+    add_wch(&cc);

     refresh();
     getch();

在xterm上产生带有横线的“ A”:

enter image description here

(对于价值而言, 0x61 为“ a”,而 0x41 为“ A”)。

答案 1 :(得分:0)

除了声明cc外,您的代码基本上是正确的。不过,建议您隐藏光标;我认为这可以防止您在以下字符位置看到错误绘制的横条。

我修改了您的代码,如下所示:

#include <curses.h>
#include <locale.h>
#include <wchar.h>
#include <assert.h>

int main() {  
    setlocale(LC_ALL, "");
    initscr();
    int s = 0x41;     // represents 'A'
    int ns = 0x0305;  // represents COMBINING OVERLINE (a non-spacing character)

    assert(wcwidth(ns) == 0);

    wchar_t wstr[] = { s, ns, L'\0'};
    cchar_t cc;                                 /* Changed *cc to cc */
    int x = setcchar(&cc, wstr, 0x00, 0, NULL); /* Changed cc to &cc */
    assert(x == 0);
    set_curs(0);                                /* Added to hide the cursor */
    add_wch(&cc);                               /* Changed cc to &cc */

    refresh();
    getch();
    endwin();
    return 0;
}

我在kubuntu系统上进行了测试,因为这很方便。生成的程序在xterm(具有丑陋的字体)上可以完美运行,但在konsole上则不能。在konsole上,它在下一个字符位置渲染了横线,这显然是一个渲染错误,因为如果有一个,则横线会出现在下一个字符的顶部。将konsole的字体更改为Liberation Mono后,测试程序运行完美。

渲染错误将不容易被发现,因为它很难复制,尽管从我的实验来看,当字体为DejaVu Sans Mono时,它似乎可以可靠地显示出来。奇怪的是,我的系统设置为使用DejaVu Sans Mono中的非间距字符作为其他字体(如Ubuntu Mono)的替代,当这些字符用作替代时,间距似乎是正确的。但是,Unicode渲染非常复杂,以至于我实际上无法证明替代字符确实来自配置的字体,并且渲染错误似乎来来往往。它可能取决于字体缓存,尽管我也不能证明。

如果我还有更多要做的事情,我将提交错误报告,并且如果我有动力明天再对此进行研究,我可能会发现一些东西。同时,其他人可以提供的任何信息无疑将是有用的。至少应包括操作系统和控制台仿真器,具有准确的版本号,并尝试使用的字体列表以及它们是否成功的指示。

顺便说一下,没有必要使用ncurses来查看此错误。在您的shell中进行测试就足够了:

printf '\u0041\u0305\u000a'

就足够了。我觉得测试很有趣

printf '\u0041\u0305\u0321\u000a'

也是。

我在以下系统上进行过测试:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:        18.04
Codename:       bionic
$ konsole --version
konsole 17.12.3
$ # Fonts showing bug
$ otfinfo -v /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf 
Version 2.37
$ # Fonts not showing bug
$ otfinfo -v /usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf 
Version 1.07.4

答案 2 :(得分:-2)

这里有多个问题。首先,将setcchar的结果存储在未初始化的指针cc的随机存储器中。每当函数使用指针进行输出时,都需要传递要存储结果的对象的地址,而不是未初始化的指针变量。输出必须是足够长的数组,以存储输入中的字符数。我不确定null终止约定是什么,所以为了安全起见,我会使用

cchar_t cc[3];
int x = setcchar(cc, wstr, 0x00, 0, NULL);

然后,add_wch函数仅需要添加一个字符,并根据它是空格还是非间距字符来替换或追加。因此,您需要为每个字符调用一次。