Mercurial > freewnn
view Wnn/romkan/rk_modread.c @ 2:b605a0e60f5b
- reverted jdata.h
- fixed the bug which occurred on changing length of bunsetsu.
author | Yoshiki Yazawa <yaz@cc.rim.or.jp> |
---|---|
date | Thu, 13 Dec 2007 17:42:01 +0900 |
parents | bbc77ca4def5 |
children | a7ccf412ba02 |
line wrap: on
line source
/* * $Id: rk_modread.c,v 1.9 2005/04/10 15:26:38 aonoto Exp $ */ /* * FreeWnn is a network-extensible Kana-to-Kanji conversion system. * This file is part of FreeWnn. * * Copyright Kyoto University Research Institute for Mathematical Sciences * 1987, 1988, 1989, 1990, 1991, 1992 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992 * Copyright FreeWnn Project 1999, 2000, 2002 * * Maintainer: FreeWnn Project <freewnn@tomo.gr.jp> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /********************************************************************** rk_modread.c 88. 6.16 改 正 モード定義表の読み込みを担当するプログラム。 ***********************************************************************/ /* Version 3.0 */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #if STDC_HEADERS # include <stdlib.h> # include <string.h> #elif HAVE_STRINGS_H # include <strings.h> #endif /* STDC_HEADERS */ #include <sys/types.h> #include <pwd.h> #if HAVE_UNISTD_H # include <unistd.h> #endif #include "rk_header.h" #include "rk_extvars.h" #ifdef WNNDEFAULT # include "wnn_config.h" /* マクロLIBDIRの定義(のためだけ)。コンパイル時は、ヘッダファイルの サーチパスに、Wnnのインクルードファイルのありかを設定しておくこと。 */ #endif #define Terminator 0 /* intの列(naibu[])の終止コード */ extern char *chrcat (), *strend (), *ename (); extern void romkan_clear (); char *modhyopath; static void cond_evl (), mystrcpy (), rd_bcksla (), rd_ctrl (), hyouse (), look_choose (); void choosehyo (); static int mystrcmp (), read1tm (), mod_evl (), fnmsrc_tourk (), dspnamsrc_tourk (), scan1tm (), modsrc_tourk (), chk_get_int (), pathsrc_tourk (), modnamchk (), ctov (), look_cond (), evlcond (), chkchar_getc (); static char codeeval (); extern void ERRMOD (), ERMOPN (), BUGreport (); extern int filnamchk (); struct kwdpair { /* キーワードとその内部表現の対応を与える構造体。内部表現を 持たないものに対しては0が与えられている。 */ char *name; int code; } modfn[] = { "defmode", 0, "if", XY2INT (2, 0), "when", XY2INT (2, 1), "path", 0, "search", 0, "on_dispmode", XY2INT (5, 0), "off_dispmode", XY2INT (5, 1), "on_unchg", XY2INT (6, 0), "off_unchg", XY2INT (6, 1), NULL}; /* 下を見よ キーワード定義表はまだあと二つあるのだ */ struct kwdpair modcond[] = { "not", XY2INT (3, 0), "and", XY2INT (3, 1), "or", XY2INT (3, 2), "true", XY2INT (3, 3), "false", XY2INT (3, 4), "=", XY2INT (3, 5), "!=", XY2INT (3, 6), "<", XY2INT (3, 7), ">", XY2INT (3, 8), NULL }; int condarg[] = { 1, 2, 2, 0, 0, 2, 2, 2, 2 }; /* 条件判断関数の引数個数 */ struct kwdpair swstat[] = { "on", 0, "off", 0, NULL }; /* 1×2^24代はモード名、4×2^24代はモード表示文字列、7×2^24代はモード状態定 数の内部表現に使っている */ /** キーワード(if, andなど)が正当なものかチェックし、その番号を返す */ static int kwdsrc (hyo, wd) struct kwdpair *hyo; /* どのキーワード表を使うか */ char *wd; /* チェックされるキーワード */ { int i; for (i = 0; hyo[i].name != NULL; i++) if (!mystrcmp (hyo[i].name, wd)) return (i); ERRMOD (9); /*NOTREACHED*/ } /** モード表の読み込み */ void readmode (modfname) char *modfname; /* モード表の名 */ { char buf[MDHMAX], *bufp; #ifdef RKMODPATH char *genv, *pathenv, *pathp; #endif mcurread = buf; /* エラー処理用 */ #ifdef RKMODPATH if (!fixednamep (modfname) && NULL != (pathenv = genv = getenv (RKMODPATH)) && *genv != '\0') { /* PATHに少なくとも一つのサーチパスがある場合 */ for (;;) { /* サーチパスの各々を入れる領域には、pathmeimemを借用 している。後で、サーチパスの先頭に、モード表のある ディレクトリを設定するので、その便宜のためもある */ for (pathp = pathmeimem; *genv != ':' && *genv; genv++) *pathp++ = *genv; *pathp = '\0'; if (*(strend (pathmeimem)) != KUGIRI) *pathp++ = KUGIRI; /* pathの区切りはDG(MV)であっても'/' */ strcpy (pathp, modfname); if (NULL != (modefile = fopen (pathmeimem, "r"))) { /* Now Mode-hyo found */ if (flags & RK_VERBOS) fprintf (stderr, "romkan: using Mode-hyo %s ...\r\n", pathmeimem); curdir = pathmeimem; /* この時点ではファイル名 込みだが、あとでパス名だけになる */ curfnm = ename (modfname); break; } if (*genv != ':') { /* Mode-hyo not found */ if (flags & RK_VERBOS) { fprintf (stderr, "no %s in ", modfname); for (genv = pathenv; *genv; genv++) { fputc ((*genv == ':' ? ' ' : *genv), stderr); } fprintf (stderr, ".\n"); } ERMOPN (0); } else genv++; /* coutinues searching Mode-hyo */ } } else #endif { if (NULL == (modefile = fopen (modfname, "r"))) ERMOPN (0); if (flags & RK_VERBOS) fprintf (stderr, "romkan: using Mode-hyo %s ...\r\n", modfname); strcpy (pathmeimem, modfname); } /* サーチパスの先頭に、モード表のあるディレクトリを設定している。 */ *(ename (pathmeimem)) = '\0'; modhyopath = *pathmeiptr++ = pathmeimem; *pathmeiptr = NULL; strtail (pathmeimem); *(pathareaorg = ++pathmeimem) = '\0'; /* pathareaorgは、pathmeimem_[]のうちモード表のあるディレクトリ名を 格納した残りの部分の先頭を指す。 */ while (bufp = buf, read1tm (&bufp, 0)) mod_evl (buf); fclose (modefile); } /** 固定された(サーチパスを見る必要のない)ファイル名に対しては非0を 返す。現在のところ、 / ./ ../ のどれかで始まるものとしているが(作者の 独断)、適当に変えてよい。strchr(s,'/')!=NULL とする方が良いかも */ int fixednamep (s) char *s; { return (!strncmp ("/", s, 1) || !strncmp ("./", s, 2) || !strncmp ("../", s, 3)); } /** モード表の一かたまり(リスト、ファイル名、モード表示文字列)を 解釈する。返す値は、defmode,search及びpathの時0、それ以外なら1。*/ static int mod_evl (s) char *s; /* モード表の内部表現の列へのポインタ */ { char md1[MDT1LN], *bgn, *end; int num, retval = 1; if (*s != '(') { if (*s != '"') { num = fnmsrc_tourk (s); *naibu++ = XY2INT (4, num); } else { s++; if (*(end = strend (s)) != '"') ERRMOD (10); *end = '\0'; num = dspnamsrc_tourk (s); *naibu++ = XY2INT (5, 0); *naibu++ = num; } } else { s++; scan1tm (&s, md1, 1); switch (num = kwdsrc (modfn, md1)) { case 0: /* defmode */ retval = 0; scan1tm (&s, md1, 1); /* modename */ num = modsrc_tourk (md1, 0); if (scan1tm (&s, md1, 0) == 0) { /* 初期on-offについて何も書いてない時の defaultはoff */ modesw[num].moderng = 2; modesw[num].curmode = 0; break; } if (*md1 == '(') { char tmp[MDT1LN], *s; unsigned int i, j; s = md1 + 1; scan1tm (&s, tmp, 1); if (chk_get_int (tmp, &i, 0) != 0) ERRMOD (8); modesw[num].moderng = i; scan1tm (&s, tmp, 1); if (chk_get_int (tmp, &j, modesw[num].moderng) != 0) ERRMOD (8); modesw[num].curmode = j; if ( #ifdef ModeNotInt modesw[num].moderng != i || modesw[num].curmode != j || #endif i == 1 || (i != 0 && j >= i)) { ERRMOD (8); } scan1tm (&s, tmp, 2); } else { switch (kwdsrc (swstat, md1)) { case 0: modesw[num].curmode = 1; break; case 1: modesw[num].curmode = 0; break; } modesw[num].moderng = 2; } scan1tm (&s, md1, 2); /* あればerr */ break; case 1: /* if */ case 2: /* when */ *naibu++ = modfn[num].code; scan1tm (&s, md1, 1); /* condition */ cond_evl (md1); while (scan1tm (&s, md1, 0)) { if (mod_evl (md1) == 0) ERRMOD (17); } *naibu++ = Terminator; break; case 3: /* path */ *(pathmeimem = pathareaorg) = '\0'; *(pathmeiptr = pathmeiorg) = NULL; case 4: /* search */ retval = 0; if (hyomeiptr != hyomeiorg) ERRMOD (11); /* サーチパスの指定はファイル名の出現より 先行しなければならないとしておく。 */ while (scan1tm (&s, md1, 0)) { /* find pathname */ pathsrc_tourk (md1); } break; case 5: /* on_dispmode */ case 6: /* off_dispmode */ *naibu++ = modfn[num].code; scan1tm (&s, md1, 1); /* dispmode string */ if (*(bgn = md1) != '"') ERRMOD (12); bgn++; if (*(end = strend (bgn)) != '"') ERRMOD (10); *end = '\0'; *naibu++ = dspnamsrc_tourk (bgn); scan1tm (&s, md1, 2); /* あればerr */ break; case 7: /* on_unchg */ case 8: /* off_unchg */ *naibu++ = modfn[num].code; scan1tm (&s, md1, 2); /* あればerr */ break; } } *naibu = Terminator; return (retval); } /** 条件式(モード名 又はnot,andなどの式)一つを解釈 */ static void cond_evl (cod) char *cod; /* 条件式の内部表現の列へのポインタ */ { char md1[MDT1LN]; unsigned int num; int i; if (is_digit (*cod) || *cod == '-') { *naibu++ = XY2INT (7, 0); if (0 != chk_get_int (cod, &num, 0)) ERRMOD (4); *naibu++ = num; } else if (*cod != '(') { num = modsrc_tourk (cod, 1); *naibu++ = XY2INT (1, num); } else { cod++; scan1tm (&cod, md1, 1); /* not;and;or */ num = kwdsrc (modcond, md1); *naibu++ = XY2INT (3, num); for (i = condarg[num]; i; i--) { scan1tm (&cod, md1, 0); cond_evl (md1); } scan1tm (&cod, md1, 2); } *naibu = Terminator; } /** sで指定されたファイル名が既登録か探し、なければ登録。但し、既登録か どうかのチェックは厳密ではないが(例えば、同じファイルでも、 パス名付きと無しとでは、同じと見ない)、ファイル名が既登録かどうか チェックするのは、メモリ節約のために同じ表を読み込むのを防ぐため だけなので、それ以外には別に困る点はない。*/ static int fnmsrc_tourk (s) char *s; { int n; for (n = 0; hyomeiorg[n] != NULL; n++) if (!mystrcmp (hyomeiorg[n], s)) return (n); if (hyomeiorg + n != hyomeiptr) BUGreport (101); *hyomeiptr++ = hyomeimem; *hyomeiptr = NULL; mystrcpy (hyomeimem, s); if (!(hyoshu[n] = filnamchk (hyomeimem))) ERRMOD (3); strtail (hyomeimem); *++hyomeimem = '\0'; return (n); } /** sで指定されたサーチパス名が既登録か探し、なければ登録。但し、fnmsrc_ tourk()同様、既登録かどうかのチェックは厳密ではないが問題ない。*/ static int pathsrc_tourk (s) char *s; { int n; char fnm_addsla[MDT1LN]; mystrcpy (fnm_addsla, s); if (!(*fnm_addsla == '\0' || *(strend (fnm_addsla)) == KUGIRI)) chrcat (fnm_addsla, KUGIRI); /* パス名が'/'で終わってなければ、それを付加する。 */ for (n = 0; pathmeiorg[n] != NULL; n++) if (!strcmp (pathmeiorg[n], fnm_addsla)) return (n); if (pathmeiorg + n != pathmeiptr) BUGreport (104); *pathmeiptr++ = pathmeimem; *pathmeiptr = NULL; strcpy (pathmeimem, fnm_addsla); strtail (pathmeimem); *++pathmeimem = '\0'; return (n); } /** sで指定されたモード表示文字列が既登録か探し、なければ登録 */ static int dspnamsrc_tourk (s) char *s; { int n; for (n = 0; dspnambgn[n] != NULL; n++) if (!mystrcmp (dspnambgn[n], s)) return (n); if (dspnambgn + n != dspnamptr) BUGreport (103); *dspnamptr++ = dspcod; *dspnamptr = NULL; mystrcpy (dspcod, s); strtail (dspcod); *++dspcod = '\0'; return (n); } /** 登録されているモード名の中から、sで指定されたモード名を探す。*np に モード番号が入る。見つからないと現モード名の総数が入る。その場合 返値は0。*/ static int modnam_src (s, np) char *s; int *np; { for (*np = 0; modmeibgn[*np] != NULL; (*np)++) if (!mystrcmp (modmeibgn[*np], s)) return (1); return (0); } /** sで指定されたモード名を探し、なければ登録。但し、flgが非0なら、 見つからなければエラー */ static int modsrc_tourk (s, flg) char *s; int flg; { int n; if (modnam_src (s, &n)) return (n); if (flg) ERRMOD (5); if (modmeibgn + n != modmeiptr) BUGreport (102); *modmeiptr++ = modmeimem; *modmeiptr = NULL; mystrcpy (modmeimem, s); if (!modnamchk (modmeimem)) ERRMOD (4); strtail (modmeimem); *++modmeimem = '\0'; return (n); } /** ファイルから一文字読む(空白文字は飛ばす)。読んだ文字がEOFなら0を返す */ static char fspcpass () { register int c; while (EOF != (c = chkchar_getc (modefile)) && is_nulsp (c)); return (c == EOF ? '\0' : c); } /** モード表には空白文字以外のコントロール文字は生では混じらないものと する。混じっていた場合はチェックしつつ、getcを行う。*/ static int chkchar_getc (f) FILE *f; { register int c; c = getc (f); if (is_cntrl (c) && !isspace (c)) { sprintf (mcurread, "\\%03o", c); ERRMOD (16); } return (c); } static int modehyo_getc () { return (chkchar_getc (modefile)); } static int modehyo_ungetc (c) register int c; { return (ungetc (c, modefile)); } /** socの名のユーザのログイン・ディレクトリ名をdestに入れ、*destにその 末尾を指させる。但しsocが空列なら自分のログイン・ディレクトリ名、 NULLなら自分のホーム・ディレクトリ名。いずれの場合も、不成功時は 何もしない。返値は、不成功時-1(getenv("HOME")失敗時だけは-2)。*/ static int get_hmdir (dest, soc) char **dest, *soc; { struct passwd *usr; char *p; if (soc == NULL) { if (NULL == (p = getenv ("HOME"))) return (-2); } else { if (NULL == (usr = (*soc ? getpwnam (soc) : getpwuid (getuid ())))) return (-1); p = usr->pw_dir; } strcpy (*dest, p); strtail (*dest); return (0); } /** モード表・対応表中の、ファイル名の部分の読み込み。先頭が @ 又は ~ の 時は、特殊処理を行う。引数は、一字読み込み・一字戻し・文字列取り出しの 関数と、結果を入れるエリアの番地へのポインタ、次に読まれる文字を入れる ポインタ。返値は、正常終了時0、@HOMEでホーム・ディレクトリが取れない時 1、@のあとに変なものが来たら2、~で自分のホーム・ディレクトリが取れない 時3、~のあとに存在しないユーザ名が来たら4。*/ int readfnm (readchar_func, unreadc_func, readstr_func, areap, lastcptr) register int (*readchar_func) (), (*unreadc_func) (), (*readstr_func) (); char **areap; int *lastcptr; { char *head; register int c; c = (*readchar_func) (); if (c == '@') { /* @HOME, @MODEDIR, @LIBDIR */ *(*areap)++ = c; head = *areap; (*readstr_func) (areap, 1); if (mystrcmp ("HOME", head) == 0) { *areap = --head; if (get_hmdir (areap, (char *) NULL) != 0) { *areap = head; return (1); } } else if (mystrcmp ("MODEDIR", head) == 0) { strcpy (*areap = --head, modhyopath); if (KUGIRI == *(*areap = strend (*areap))) **areap = '\0'; } else #ifdef WNNDEFAULT if (mystrcmp ("LIBDIR", head) == 0) { strcpy (*areap = --head, LIBDIR); strtail (*areap); } else #endif { *areap = --head; return (2); } } else if (c == '~') { /* ~user */ int err; *(*areap)++ = c; head = *areap; (*readstr_func) (areap, 1); mystrcpy (head, head); *areap = head - 1; if ((err = get_hmdir (areap, (*head ? head : NULL))) != 0) { *areap = --head; return (err == -2 ? 3 : 4); } } else { (*unreadc_func) (c); } *lastcptr = (*readstr_func) (areap, 0); return (0); } /** モード表から一文字分取り出す作業を、空白・括弧のどれか 又はEOFが来るまで続ける。flg & 01が非0なら、'/'が来ても 終わる。返値は、次に読まれる文字。*/ static int rd_string (readfile, sptr, flg) register FILE *readfile; char **sptr; int flg; { int c; while (EOF != (c = chkchar_getc (readfile)) && !(is_nulsp (c) || c == '(' || c == ')') && !(flg & 01 && c == KUGIRI)) { switch (c) { case '\\': rd_bcksla (readfile, sptr); break; case '^': rd_ctrl (readfile, sptr); break; default: *(*sptr)++ = c; } } **sptr = '\0'; return (ungetc (c, readfile)); } static int rd_str_from_modefile (sptr, flg) char **sptr; int flg; { return (rd_string (modefile, sptr, flg)); } /** モード表からバックスラッシュ形式の一文字分を取り出し、'\(8進);' の形に直す。但し、先頭の'\\'は既に読まれたあと。*/ static void rd_bcksla (readfile, sptr) register FILE *readfile; char **sptr; { int c, code = 0, digflg = 0; switch (c = chkchar_getc (readfile)) { case 'n': code = '\n'; digflg = 1; break; case 't': code = '\t'; digflg = 1; break; case 'b': code = '\b'; digflg = 1; break; case 'r': code = '\r'; digflg = 1; break; case 'f': code = '\f'; digflg = 1; break; case 'e': case 'E': code = ESCCHR; digflg = 1; break; case 'o': while (c = chkchar_getc (readfile), is_octal (c)) { code <<= 3; code += ctov (c); digflg = 1; } if (c != ';') ungetc (c, readfile); break; case 'd': while (c = chkchar_getc (readfile), is_digit (c)) { code *= 10; code += ctov (c); digflg = 1; } if (c != ';') ungetc (c, readfile); break; case 'x': while (c = chkchar_getc (readfile), is_xdigit (c)) { code <<= 4; code += ctov (c); digflg = 1; } if (c != ';') ungetc (c, readfile); break; default: if (is_octal (c)) { digflg = 1; code = ctov (c); while (c = chkchar_getc (readfile), is_octal (c)) { code <<= 3; code += ctov (c); } if (c != ';') ungetc (c, readfile); } else { code = c; digflg = 1; } } if (digflg == 0) ERRMOD (7); sprintf (*sptr, "\\%o;", code); strtail (*sptr); } /** モード表からコントロールコード形式の一文字分を取り出し、 '\(8進);' の形に直す。但し、先頭の'^'は既に読まれたあと。*/ static void rd_ctrl (readfile, sptr) register FILE *readfile; char **sptr; { int c; if (!(' ' <= (c = chkchar_getc (readfile)) && c < '\177')) ERRMOD (7); if (c == '?') c = '\177'; else c &= 0x1f; sprintf (*sptr, "\\%o;", c); strtail (*sptr); } /** モード表の一かたまり(リスト、ファイル名、モード表示文字列)を 切り出す。その際、特殊な表記('^','\'による)は、'\(8進);' の 形に直す。flgが非0なら、EOFでエラーを起こし、')'で0を返す。*/ static int read1tm (sptr, flg) char **sptr; /* モード表の内部表現の列へのポインタへのポインタ。 rd_bcksla()、rd_ctrl()、codeeval()でも同様 */ int flg; { int c, err, retval = 1; char *s; s = *sptr; while ((c = fspcpass ()) == ';') { /* 注釈文を検出したら、行末までとばして再試行。 */ while ((c = chkchar_getc (modefile)) != '\n' && c != EOF); } switch (c) { case '\0': /* EOFを表す */ if (flg) ERRMOD (0); else retval = 0; break; case ')': if (flg) retval = 0; else ERRMOD (1); break; case '(': *s++ = c; *s++ = ' '; while (read1tm (&s, 1)) *s++ = ' '; *s++ = ')'; break; case '"': *s++ = c; while ((c = chkchar_getc (modefile)) != '"') { switch (c) { case EOF: ERRMOD (0); case '\\': rd_bcksla (modefile, &s); break; case '^': rd_ctrl (modefile, &s); break; default: *s++ = c; } } *s++ = '"'; break; default: ungetc (c, modefile); /* 先頭が @ 又は ~ の時は、特殊処理。 */ err = readfnm (modehyo_getc, modehyo_ungetc, rd_str_from_modefile, &s, &c); if (err) { mcurread = s; switch (err) { case 1: case 3: ERRMOD (13); case 2: ERRMOD (14); case 4: ERRMOD (15); } } if (c == EOF && flg) ERRMOD (0); if (c == ')' && !flg) ERRMOD (1); } *s = '\0'; *sptr = s; return (retval); } /** 8・10・16進コード用のキャラクタを実際のコードに直す。入力のチェックは しない。*/ static int ctov (c) char c; { if (is_upper (c)) return (c - 'A' + 10); if (is_lower (c)) return (c - 'a' + 10); return (c - '0'); } /** リストの中身のscanに専用。')'で0を返す。EOLは来ないはず。 flg == 1 のとき、取り出しに失敗したらエラー。 flg == 2 のとき、取り出しに成功したらエラー。 特殊なコード表記は既に全て '\(8進);' の形に直っている筈。*/ static int scan1tm (socp, dest, flg) char **socp, *dest; /* socpの指しているポインタが指している所から取り出してdestに入れる。 その後、socpが指しているポインタを進める。 */ int flg; { char c; int retval = 1; while (c = *(*socp)++, is_nulsp (c)) if (c == '\0') ERRMOD (6); switch (c) { case ')': retval = 0; break; case '(': *dest++ = c; *dest++ = ' '; while (scan1tm (socp, dest, 0)) { strtail (dest); *dest++ = ' '; } *dest++ = ')'; break; case '"': *dest++ = c; while ((c = *dest++ = *(*socp)++) != '"') { if (c == '\\') { /* '\(8進);'の解釈 */ while (c = *dest++ = *(*socp)++, is_octal (c)); } } break; default: *dest++ = c; while (!is_nulsp (**socp)) *dest++ = *(*socp)++; } *dest = '\0'; if ((flg == 1 && retval == 0) || (flg == 2 && retval == 1)) ERRMOD (6); return (retval); } /** モード名として正当かチェック。英数字からなっていればいい */ static int modnamchk (s) char *s; { if (is_digit (*s)) return (0); for (; *s; s++) if (!is_alnum (*s) && *s != '_') return (0); return (1); } #define modu1(a, b) ((b) ? ((a) % (b)) : (a)) #define curmod(num) (modesw[num] . curmode) #define modrng(num) (modesw[num] . moderng) /** num番目のモードをチェンジし、変換表を選択し直す。引数 mode の値が0なら モードをoff、1ならonすることになる。なお、旧modeの値を返す。*/ /* *INDENT-OFF* */ modetyp chgmod (num, mode) int num; modetyp mode; /* *INDENT-ON* */ { modetyp oldmod; oldmod = curmod (num); curmod (num) = modu1 (mode, modrng (num)); choosehyo (); return (oldmod); } /** 全モードをまとめて切り替える */ void allchgmod (mode) modetyp mode; { int i; for (i = 0; modmeibgn[i] != NULL; i++) { curmod (i) = modu1 (mode, modrng (i)); } choosehyo (); } /** num番目のモードを指定した数だけインクリメントし、旧modeの値を返す。*/ /* *INDENT-OFF* */ modetyp incmod (num, dmode) int num; modetyp dmode; /* *INDENT-ON* */ { modetyp oldmod, newmod; newmod = oldmod = curmod (num); newmod += dmode; if (oldmod > newmod) newmod -= modrng (num); return (chgmod (num, newmod)); } /** num番目のモードを指定した数だけデクリメントし、旧modeの値を返す。都合 により、incmodとは別に用意しなくてはならない。*/ /* *INDENT-OFF* */ modetyp decmod (num, dmode) int num; modetyp dmode; /* *INDENT-ON* */ { modetyp oldmod, newmod; newmod = oldmod = curmod (num); newmod -= dmode; if (oldmod < newmod) newmod += modrng (num); return (chgmod (num, newmod)); } /** nameの名のモードがなければ非0を返し、あればそのモード番号・及びその 状態の最大値+1と現在の状態を取ってくる */ int romkan_getmode (name, nump, modep, moderngp) char *name; int *nump; modetyp *modep, *moderngp; { if (!modnam_src (name, nump)) return (-1); *modep = curmod (*nump); *moderngp = modrng (*nump); return (0); } /** nameの名のモードがなければ非0を返し、あればその状態をセットして 変換表を再選択の後、旧状態を取り込んで0を返す。*/ int romkan_setmode (name, modep) char *name; modetyp *modep; { modetyp oldmode, moderng; int modenum; if (romkan_getmode (name, &modenum, &oldmode, &moderng) != 0) return (-1); chgmod (modenum, *modep); *modep = oldmode; return (0); } /** 変換表のクリア */ void romkan_reset () { naibu_[0] = Terminator; choosehyo (); romkan_clear (); } /** 変換対応表の選択を行う */ void choosehyo () { int *naibup, i; naibup = naibu_; usemaehyo[0] = usehyo[0] = useatohyo[0] = -1; for (i = 0; i < 2; i++) { dspmod[1][i] = dspmod[0][i]; dspmod[0][i] = NULL; } look_choose (&naibup, 1); } /** モード表の内部形式を順次見ていき、使用表の選択及びモード表示文字列の 選択を行っていく。但しflgが0ならスキップするだけ */ static void look_choose (naibupp, flg) int **naibupp; /* モード表の内部表現の列へのポインタへのポインタ。 look_cond()、evlcond()でも同様 */ int flg; { int *naibup, naibu1, naibu2, branch, lcrsl; naibup = *naibupp; while ((naibu1 = *naibup++) != Terminator) { switch (SHUBET (naibu1)) { case 4: /* 表名 */ if (flg) hyouse (LWRMSK (naibu1)); break; case 2: /* 条件式 */ branch = LWRMSK (naibu1); /* if;when */ lcrsl = look_cond (&naibup, flg); if (branch == 0 && lcrsl) flg = 0; break; case 5: /* romkanがon・off時それぞれの モード表示文字列 */ naibu2 = *naibup++; if (flg) dspmod[0][LWRMSK (naibu1)] = dspnambgn[naibu2]; break; case 6: /* romkanがそれぞれon・off時のモード表示 文字列を前のままに */ if (flg) dspmod[0][LWRMSK (naibu1)] = dspmod[1][LWRMSK (naibu1)]; break; default: BUGreport (6); } } *naibupp = naibup; } /** *naibupp が、内部表現の列で条件式を表すところを指している筈なので、 それを評価し、真ならその続きを解釈しにいく。偽なら読み飛ばす。 返値は、最初に評価した条件式の真偽値。*/ static int look_cond (naibupp, flg) int **naibupp, flg; { int *naibup, condrsl; naibup = *naibupp; condrsl = evlcond (&naibup); /* 必ず評価しないといけないため */ flg = flg && condrsl; look_choose (&naibup, flg); *naibupp = naibup; return (flg); } /** 条件式の真偽値の評価 返値は0か1とは限らんぞ */ static int evlcond (naibupp) int **naibupp; { int *naibup, naibu1, retval = -1, tmpval[ARGMAX], i, imax; naibup = *naibupp; naibu1 = *naibup++; switch (SHUBET (naibu1)) { case 7: /* 数値 */ retval = *naibup++; break; case 1: /* モード名 */ retval = modesw[LWRMSK (naibu1)].curmode; break; case 3: /* andなど */ imax = condarg[LWRMSK (naibu1)]; for (i = 0; i < imax; i++) tmpval[i] = evlcond (&naibup); switch (LWRMSK (naibu1)) { /* 上から順にtrue,false,not,and,or */ case 0: retval = !tmpval[0]; break; case 1: retval = tmpval[0] && tmpval[1]; break; case 2: retval = tmpval[0] || tmpval[1]; break; case 3: retval = 1; break; case 4: retval = 0; break; case 5: retval = (tmpval[0] == tmpval[1]); break; case 6: retval = (tmpval[0] != tmpval[1]); break; case 7: retval = ((unsigned int) tmpval[0] < (unsigned int) tmpval[1]); break; case 8: retval = ((unsigned int) tmpval[0] > (unsigned int) tmpval[1]); break; } break; } *naibupp = naibup; return (retval); } /** num番目の表を、使用するものとして登録する。前・本・後処理の区別もする */ static void hyouse (num) int num; { int *ptr; switch (hyoshu[num]) { case 1: ptr = usemaehyo; break; case 2: ptr = usehyo; break; case 3: ptr = useatohyo; break; default: BUGreport (11); return; } for (; *ptr != -1; ptr++) if (*ptr == num) return; *ptr = num; *++ptr = -1; } /** strcmpと同等 但し、'\(8進);'も解釈する。*/ static int mystrcmp (s1, s2) char *s1, *s2; { char c1, c2; while ((c1 = codeeval (&s1)) == (c2 = codeeval (&s2))) if (c1 == '\0') return (0); return (c1 > c2 ? 1 : -1); } /** strcpyと同等 但し'\(8進);'も解釈する。s1 <= s2なら正常動作するはず */ static void mystrcpy (s1, s2) char *s1, *s2; { while (*s1++ = codeeval (&s2)); } /** 一文字の解釈を行う。普通の文字はそのまま、'\(8進);'は実際のコードに 直す。その後、文字列へのポインタを一文字分進めておく(少なくとも 1バイト分進むことが保証されるはず)。*/ static char codeeval (sptr) register char **sptr; { register char c; char code = 0; if ((c = *(*sptr)++) != '\\') return (c); while (c = *(*sptr)++, is_octal (c)) { code <<= 3; code += ctov (c); } if (c != ';') BUGreport (12); return (code); } /** romkanがon時のモード表示文字列を返す関数。無指定であってRK_DSPNILフラグが 立っている時は空文字列を返す。*/ char * romkan_dispmode () { return (dspmod[0][0] == NULL && (flags & RK_DSPNIL) ? nulstr : dspmod[0][0]); } /** romkanがoff時のモード表示文字列を返す関数。無指定であってRK_DSPNILフラグ が立っている時は空文字列を返す。*/ char * romkan_offmode () { return (dspmod[0][1] == NULL && (flags & RK_DSPNIL) ? nulstr : dspmod[0][1]); } /** 文字列が10進整数ならその解釈をし、そうでなければ非0を返す */ static int chk_get_int (p, ip, range) char *p; unsigned int *ip; modetyp range; { int sgn = 1; modetyp out; if (*p == '-') { p++; sgn = -1; } for (out = 0; *p; p++) { if (!is_digit (*p)) return (-1); out *= 10; out += ctov (*p); } if (range != 0) out %= range; if (sgn == -1 && out != 0) out = range - out; *ip = out; return (0); }