S-Code User Level Functions

在此, 所謂一個 S-string 就是一個整數序列, 其最後一個整數是 0 (NULL). 簡稱 S-string. 每一個 S-string 有一個長度, 意即序列中整數的個數 (不含 NULL); 有一個寬度, 意即序列中每個 S-code 所佔的字元寬度和.


int s_wd(int s);
int s_punct(int s);
int s_digit(int s);
int s_space(int s);

這些方程像是 內的方程. s_wd 檢查一個 S-code 的位元寬度 --- 寬度為一者, 當是 ASCII 或 Latin-1 碼. s_punct 檢查是否為符號 --- 0 代表不是, 1 代表是半形符號, 亦即被 中的 ispunct 還回非零值者 (所有可印字元, 除了字母與數目字者); 大於 1 者代表是全形標點符號或可作字串分隔的符號. 特別是標點符號者, 其還回值為 3, 4, 5, 6, 分別代表是橫排前置, 橫排後置, 直排前置, 直排後置的標點符號. 注意, 我們並不把所有的全形符號考慮在內, 這和 的 ispunct 並不類似. 而且, 西方人的空格不當作標點, 但中文可用空格當作標點, 常見於詩詞排版中. 所以, ASCII 的 space 不算 punct, 但全形的 space 就算.

s_digit 檢查是否為數目字符號 --- 0 代表不是, 1 代表是半形的阿拉伯數目字, 2 代表是全形的阿拉伯數目字. s_space 檢查是否為空白符號 --- 0 代表不是, 1 代表是 ASCII 碼被 中的 isspace 定義成空白者, 應該包括 space, formfeed, newline, carriage return, tab, vertical tab; 2 代表是全形的空格. 注意, 在 CNS 碼中, 有兩個碼看起來都是空格. 一個是 2121, 這個才是空格; 另一個是 256D, 這個應該是注音符號的一聲聲調符號.


int s_len(int *ss);
int s_width(int *ss);

這兩個方程很像 裡面的 strlen. 但因為一個 S-code 可代表一個字母 或一個中國字, 故用 s_len 計算此 S-string 中共有幾個 S-code (結尾的 NULL 不算), 而用 s_width 計算整個 S-string 的寬度. 亦即, 若是 ASCII 或 Latin-1 碼則算 一個字元寬, 否則算兩個字元寬. 注意, 此程式沒有理會可能出現的 ASCII 控制字元, 例如 \n, bell, backspace, 等等. 我們假設讀入的是一個純文字檔, 裡面不應該有 奇怪的控制字元.


int char2s(unsigned char *cs, int *ss, int catg);

將一個 character string (cs) 轉換到一個 S-string (ss). 假設原來的 cs 是以 catg 編碼. 此方程還回去的整數是 ss 的字元寬度, 等於 strlen(cs).


int s_getline(FILE *fp, int *ss, int lim, int catg)

從 fp 讀一行, 存入 S-string s, 假設原檔案的編碼是 catg, 預設一行的 S-code 長度不得超過 lim-1 (包括 \n); 注意, 是 S-code 長度而非字元寬度. 這樣的設計是因為主程式中必須確定此整數序列的長度, 而 lim 在此是保衛此序列不致脹破. 但是在檔案中若有中英夾雜, 此長度沒什麼意義. 所以, 建議設定 lim 為即使一行中全是英文時的最大長度; 如此, 則若一行中全是中文時, 只須大約 lim/2 個 S-code. 此程式不檢查 fp 是否可讀, 亦不能檢查 s 是否足夠長. 如果檔案中有一行太長, 會自動切斷成兩行, 給警告訊息. 此方程還回去的整數是 ss 的長度, 等於 s_len(ss). 我們沒有提供一個專門從 stdin 讀入的方程, 請將 fp 寫成 stdin 即可.


int s_putstr(int *ss, FILE *fp, int catg);

將一個 S-string ss 以 catg 編碼寫入檔案 fp. 字串後並沒有加 \n, 完全由 ss 決定. 還回去列印字元數, 有如 s_width(ss); 若是有誤則還回去 EOF. 此程式並不檢查 fp 是否可寫. 我們沒有提供一個專門寫到 stdout 的方程, 請將 fp 寫成 stdout 即可.


#include "s_code.h"
#include <ctype.h>
#define iny(n) (((BL0 <= n) && (n <= BL1)) || ((BH0 <= n) && (n <= BH1)))

int s_wd(int s) {
    return ((s&SM) == 0) ? 1 : 2;
}

int s_punct(int s) {
    int c=0, t;
    if ((s&SM) == 0)
        if (ispunct(s) != 0)
            c = 1;
    else if (s_gets(s) == SF) {
        t = (s&TM);
	if ((0x01000000 < t) && (t < 0x10000000)) {
            switch(t) {
            case PUNRF: c=3; break;
            case PUNRL: c=4; break;
            case PUNCF: c=5; break;
            case PUNCL: c=6; break;
            default:    c=2; break;
            }
        }
    }
    return c;
}

int s_digit(int s) {
    int c=0;
    if ( ((s&SM) == 0) && (isdigit(s) != 0) )
        c = 1;
    else if ( (s_gets(s) == SF) && ((s&TM) == NUMARB) )
        c = 2;
    return c;
}

int s_space(int s) {
    int c=0;
    if ( ((s&SM) == 0) && (isspace(s) != 0) )
        c = 1;
    else if ( (s_gets(s) == SF) && ((s&TM) == WHITE) )
        c = 2;
    return c;
}

int s_len(int *s) {
    int *t;
    t=s;
    while (*t++ != 0);
    return t-s-1;
}

int s_width(int *s) {
    int *t, x, n=0;
    t=s;
    while ((x = *t++) != 0)
        n += s_wd(x);
    return n;
}

int char2s(char *cs, int *ss, int catg) {
    void *v;
    unsigned char *c, *s;
    int *t, x;

    v = cs;
    c = (unsigned char*) v;
    s = c;
    t = ss;
    switch(catg) {
    case BIG5:
        while ((x = *c++) != '\0') {
            if ( ((BX0 <= x) && (x <= BX1)) && iny(*c) )
                *t++ = big5_s(x, *c++);
            else
                *t++ = x;
        }
        *t = 0;
        break;
    default:
        fprintf(stderr, "ERROR. char2s: unknown category %d.\n", catg);
        exit(5);
    }
    return (c-s)-1;
}

int s_getline(FILE *fp, int *ss, int lim, int catg) {
    int *s, len=lim, c, n=0;
    s = ss;
    while (--lim>1 && (c=s_getc(fp, catg)) != EOF && c != '\n')
        *s++ = c;
    if (c == '\n')
        *s++ = c;
    else if (lim == 1) {
        *s++ = '\n';
        fprintf(stderr, "WARNING. s_getline: Line too long, splitted.\n");
    }
    *s = 0;
    return s - ss;
}

int s_putstr(int *ss, FILE *fp, int catg) {
    int *s, x, n;
    s = ss;
    while ((x=*s++) != 0)
        if (s_putc(x, fp, catg) == EOF)
            return EOF;
        else
            n += s_wd(x);
    return n;
}


Created: Jan 14, 1996
Last Revised: Jan 14, 1996
© Copyright 1996 Wei-Chang Shann

shann@math.ncu.edu.tw