/*
* $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);
}
syntax highlighted by Code2HTML, v. 0.9.1