/*
*/
/*
WNN7 CLIENT LIBRARY--SOFTWARE LICENSE TERMS AND CONDITIONS
Wnn7 Client Library :
(C) Copyright OMRON Corporation. 1995,1998,2000,2001 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000,2001 all rights reserved.
Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992, 1993
Preamble
These Wnn7 Client Library--Software License Terms and Conditions
(the "License Agreement") shall state the conditions under which you are
permitted to copy, distribute or modify the software which can be used
to create Wnn7 Client Library (the "Wnn7 Client Library"). The License
Agreement can be freely copied and distributed verbatim, however, you
shall NOT add, delete or change anything on the License Agreement.
OMRON Corporation and OMRON Software Co., Ltd. (collectively referred to
as "OMRON") jointly developed the Wnn7 Software (development code name
is FI-Wnn), based on the Wnn Software. Starting from November, 1st, 1998,
OMRON publishes the source code of the Wnn7 Client Library, and OMRON
permits anyone to copy, distribute or change the Wnn7 Client Library under
the License Agreement.
Wnn7 Client Library is based on the original version of Wnn developed by
Kyoto University Research Institute for Mathematical Sciences (KURIMS),
OMRON Corporation and ASTEC Inc.
Article 1. Definition.
"Source Code" means the embodiment of the computer code, readable and
understandable by a programmer of ordinary skills. It includes related
source code level system documentation, comments and procedural code.
"Object File" means a file, in substantially binary form, which is directly
executable by a computer after linking applicable files.
"Library" means a file, composed of several Object Files, which is directly
executable by a computer after linking applicable files.
"Software" means a set of Source Code including information on its use.
"Wnn7 Client Library" the computer program, originally supplied by OMRON,
which can be used to create Wnn7 Client Library.
"Executable Module" means a file, created after linking Object Files or
Library, which is directly executable by a computer.
"User" means anyone who uses the Wnn7 Client Library under the License
Agreement.
Article 2. Copyright
2.1 OMRON Corporation and OMRON Software Co., Ltd. jointly own the Wnn7
Client Library, including, without limitation, its copyright.
2.2 Following words followed by the above copyright notices appear
in all supporting documentation of software based on Wnn7 Client Library:
This software is based on the original version of Wnn7 Client Library
developed by OMRON Corporation and OMRON Software Co., Ltd. and also based on
the original version of Wnn developed by Kyoto University Research Institute
for Mathematical Sciences (KURIMS), OMRON Corporation and ASTEC Inc.
Article 3. Grant
3.1 A User is permitted to make and distribute verbatim copies of
the Wnn7 Client Library, including verbatim of copies of the License
Agreement, under the License Agreement.
3.2 A User is permitted to modify the Wnn7 Client Library to create
Software ("Modified Software") under the License Agreement. A User
is also permitted to make or distribute copies of Modified Software,
including verbatim copies of the License Agreement with the following
information. Upon modifying the Wnn7 Client Library, a User MUST insert
comments--stating the name of the User, the reason for the modifications,
the date of the modifications, additional terms and conditions on the
part of the modifications if there is any, and potential risks of using
the Modified Software if they are known--right after the end of the
License Agreement (or the last comment, if comments are inserted already).
3.3 A User is permitted to create Library or Executable Modules by
modifying the Wnn7 Client Library in whole or in part under the License
Agreement. A User is also permitted to make or distribute copies of
Library or Executable Modules with verbatim copies of the License
Agreement under the License Agreement. Upon modifying the Wnn7 Client
Library for creating Library or Executable Modules, except for porting
a computer, a User MUST add a text file to a package of the Wnn7 Client
Library, providing information on the name of the User, the reason for
the modifications, the date of the modifications, additional terms and
conditions on the part of the modifications if there is any, and potential
risks associated with using the modified Wnn7 Client Library, Library or
Executable Modules if they are known.
3.4 A User is permitted to incorporate the Wnn7 Client Library in whole
or in part into another Software, although its license terms and
conditions may be different from the License Agreement, if such
incorporation or use associated with the incorporation does NOT violate
the License Agreement.
Article 4. Warranty
THE WNN7 CLIENT LIBRARY IS PROVIDED BY OMRON ON AN "AS IS" BAISIS.
OMRON EXPRESSLY DISLCIAMS ANY AND ALL WRRANTIES, EXPRESS OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, IN CONNECTION WITH THE WNN7 CLIENT LIBRARY
OR THE USE OR OTHER DEALING IN THE WNN7 CLIENT LIBRARY. IN NO EVENT
SHALL OMRON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, PUNITIVE
OR CONSEQUENTIAL DAMAGES OF ANY KIND WHATSOEVER IN CONNECTION WITH THE
WNN7 CLIENT LIBRARY OR THE USE OR OTHER DEALING IN THE WNN7 CLIENT
LIBRARY.
***************************************************************************
Wnn7 Client Library :
(C) Copyright OMRON Corporation. 1995,1998,2000,2001 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000,2001 all rights reserved.
Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992, 1993
***************************************************************************
Comments on Modifications:
*/
/**********************************************************************
rk_modread.c
88. 6.16 改 正
93.10.19
モード定義表の読み込みを担当するプログラム。
***********************************************************************/
/* Version 3.0
*/
#include "rk_multi.h"
#ifdef WNNDEFAULT
# include "config.h"
/* マクロLIBDIRの定義(のためだけ)。コンパイル時は、ヘッダファイルの
サーチパスに、Wnnのインクルードファイルのありかを設定しておくこと。*/
#endif
#include <pwd.h>
#define Terminator 0 /* intの列(naibu[])の終止コード */
char *getenv();
extern char *chrcat(), *strend(), *ename();
extern void romkan_clear_body();
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, 0}}; /* 下を見よ キーワード定義表はまだあと二つあるのだ */
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, 0}};
int condarg[] = {
1, 2, 2, 0, 0, 2, 2, 2, 2}; /* 条件判断関数の引数個数 */
struct kwdpair swstat[] = {
{ "on", 0 },
{ "off", 0 },
{ "r", 0 },
{ "nr", 0 },
{ NULL, 0 }};
/* 1×2^24代はモード名、4×2^24代はモード表示文字列、7×2^24代はモード状態定
数の内部表現に使っている */
/** キーワード(if, andなど)が正当なものかチェックし、その番号を返す */
static int
kwdsrc(hyo, wd, cur_rk)
struct kwdpair *hyo; /* どのキーワード表を使うか */
char *wd; /* チェックされるキーワード */
ARGS *cur_rk;
{
int i;
for(i = 0; hyo[i] . name != NULL; i++)
if(!mystrcmp(hyo[i] . name, wd)) return(i);
ERRMOD(9, cur_rk);
/*NOTREACHED*/
return(0);
}
/** モード表の読み込み */
void
readmode(modfname, cur_rk)
char *modfname; /* モード表の名 */
ARGS *cur_rk;
{
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;
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, cur_rk);
} else genv++; /* coutinues searching Mode-hyo */
}
} else
#endif
{
if(NULL == (modefile = fopen(modfname, "r"))) ERMOPN(0, cur_rk);
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, cur_rk)) mod_evl(buf, cur_rk);
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, cur_rk)
char *s; /* モード表の内部表現の列へのポインタ */
ARGS *cur_rk;
{
char md1[MDT1LN], *bgn, *end;
int num, romkan_ret, retval = 1;
if(*s != '('){
if(*s != '"'){
num = fnmsrc_tourk(s, cur_rk);
*naibu++ = XY2INT(4, num);
} else {
s++;
if(*(end = strend(s)) != '"') ERRMOD(10, cur_rk);
*end = '\0';
num = dspnamsrc_tourk(s, cur_rk);
*naibu++ = XY2INT(5, 0);
*naibu++ = num;
}
} else {
s++;
scan1tm(&s, md1, 1, cur_rk);
switch(num = kwdsrc(modfn, md1, cur_rk)){
case 0: /* defmode */
retval = 0;
scan1tm(&s, md1, 1, cur_rk); /* modename */
num = modsrc_tourk(md1, 0, cur_rk);
if(scan1tm(&s, md1, 0, cur_rk) == 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, cur_rk);
if(chk_get_int(tmp, &i, 0) != 0)
ERRMOD(8, cur_rk);
modesw[num] . moderng = i;
scan1tm(&s, tmp, 1, cur_rk);
if(chk_get_int(tmp, &j,
modesw[num] . moderng) != 0)
ERRMOD(8, cur_rk);
modesw[num] . curmode = j;
if(
#ifdef ModeNotInt
modesw[num] . moderng != i ||
modesw[num] . curmode != j ||
#endif
i == 1 || (i != 0 && j >= i)){
ERRMOD(8, cur_rk);
}
scan1tm(&s, tmp, 2, cur_rk);
} else {
switch(kwdsrc(swstat, md1, cur_rk)){
case 0:
modesw[num] . curmode
= 1;
break;
case 1:
modesw[num] . curmode
= 0;
break;
/* New mode for xwnmo */
case 2:
case 3:
break;
}
modesw[num] . moderng = 2;
/* skip mode data for xwnmo */
romkan_ret = scan1tm(&s, md1, 0, cur_rk);
if(romkan_ret)
scan1tm(&s, md1, 2, cur_rk); /* あればerr */
}
break;
case 1: /* if */
case 2: /* when */
*naibu++ = modfn[num] . code;
scan1tm(&s, md1, 1, cur_rk); /* condition */
cond_evl(md1, cur_rk);
while(scan1tm(&s, md1, 0, cur_rk)){
if(mod_evl(md1, cur_rk) == 0) ERRMOD(17, cur_rk);
}
*naibu++ = Terminator;
break;
case 3: /* path */
*(pathmeimem = pathareaorg) = '\0';
*(pathmeiptr = pathmeiorg) = NULL;
case 4: /* search */
retval = 0;
if(hyomeiptr != hyomeiorg) ERRMOD(11, cur_rk);
/* サーチパスの指定はファイル名の出現より
先行しなければならないとしておく。*/
while(scan1tm(&s, md1, 0, cur_rk)){/* find pathname */
pathsrc_tourk(md1, cur_rk);
}
break;
case 5: /* on_dispmode */
case 6: /* off_dispmode */
*naibu++ = modfn[num] . code;
scan1tm(&s, md1, 1, cur_rk); /* dispmode string */
if(*(bgn = md1) != '"') ERRMOD(12, cur_rk);
bgn++;
if(*(end = strend(bgn)) != '"') ERRMOD(10, cur_rk);
*end = '\0';
*naibu++ = dspnamsrc_tourk(bgn, cur_rk);
scan1tm(&s, md1, 2, cur_rk); /* あればerr */
break;
case 7: /* on_unchg */
case 8: /* off_unchg */
*naibu++ = modfn[num] . code;
scan1tm(&s, md1, 2, cur_rk); /* あればerr */
break;
}
}
*naibu = Terminator;
return(retval);
}
/** 条件式(モード名 又はnot,andなどの式)一つを解釈 */
static void
cond_evl(cod, cur_rk)
char *cod; /* 条件式の内部表現の列へのポインタ */
ARGS *cur_rk;
{
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, cur_rk);
*naibu++ = num;
} else if(*cod != '('){
num = modsrc_tourk(cod, 1, cur_rk);
*naibu++ = XY2INT(1, num);
} else {
cod++;
scan1tm(&cod, md1, 1, cur_rk); /* not;and;or */
num = kwdsrc(modcond, md1, cur_rk);
*naibu++ = XY2INT(3, num);
for(i = condarg[num]; i; i--){
scan1tm(&cod, md1, 0, cur_rk);
cond_evl(md1, cur_rk);
}
scan1tm(&cod, md1, 2, cur_rk);
}
*naibu = Terminator;
}
/** sで指定されたファイル名が既登録か探し、なければ登録。但し、既登録か
どうかのチェックは厳密ではないが(例えば、同じファイルでも、
パス名付きと無しとでは、同じと見ない)、ファイル名が既登録かどうか
チェックするのは、メモリ節約のために同じ表を読み込むのを防ぐため
だけなので、それ以外には別に困る点はない。*/
static int
fnmsrc_tourk(s, cur_rk)
char *s;
ARGS *cur_rk;
{
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, cur_rk);
strtail(hyomeimem);
*++hyomeimem = '\0';
return(n);
}
/** sで指定されたサーチパス名が既登録か探し、なければ登録。但し、fnmsrc_
tourk()同様、既登録かどうかのチェックは厳密ではないが問題ない。*/
static int
pathsrc_tourk(s, cur_rk)
char *s;
ARGS *cur_rk;
{
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, cur_rk)
char *s;
ARGS *cur_rk;
{
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, cur_rk)
char *s;
int *np;
ARGS *cur_rk;
{
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, cur_rk)
char *s;
int flg;
ARGS *cur_rk;
{
int n;
if(modnam_src(s, &n, cur_rk)) return(n);
if(flg) ERRMOD(5, cur_rk);
if(modmeibgn + n != modmeiptr) BUGreport(102);
*modmeiptr++ = modmeimem;
*modmeiptr = NULL;
mystrcpy(modmeimem, s);
if(!modnamchk(modmeimem)) ERRMOD(4, cur_rk);
strtail(modmeimem);
*++modmeimem = '\0';
return(n);
}
/** ファイルから一文字読む(空白文字は飛ばす)。読んだ文字がEOFなら0を返す */
static char
fspcpass(cur_rk)
ARGS *cur_rk;
{
register int c;
while(EOF != (c = chkchar_getc(modefile, cur_rk)) && is_nulsp(c));
return(c == EOF ? '\0' : c);
}
/** モード表には空白文字以外のコントロール文字は生では混じらないものと
する。混じっていた場合はチェックしつつ、getcを行う。*/
static int
chkchar_getc(f, cur_rk)
FILE *f;
ARGS *cur_rk;
{
register int c;
c = getc(f);
if(is_cntrl(c) && !isspace(c)){
sprintf(mcurread, "\\%03o", c);
ERRMOD(16, cur_rk);
}
return(c);
}
static int
modehyo_getc(cur_rk)
ARGS *cur_rk;
{
return(chkchar_getc(modefile, cur_rk));
}
static int
modehyo_ungetc(c, cur_rk)
register int c;
ARGS *cur_rk;
{
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 {
usr = (*soc? getpwnam(soc) : getpwuid(getuid()));
endpwent();
if(usr == NULL)
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, cur_rk)
register int (*readchar_func)(), (*unreadc_func)(), (*readstr_func)();
char **areap;
int *lastcptr;
ARGS *cur_rk;
{
char *head;
register int c;
c = (*readchar_func)(cur_rk);
if(c == '@'){ /* @HOME, @MODEDIR, @LIBDIR */
*(*areap)++ = c;
head = *areap;
(*readstr_func)(areap, 1, cur_rk);
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, cur_rk);
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, cur_rk);
}
*lastcptr = (*readstr_func)(areap, 0, cur_rk);
return(0);
}
/** モード表から一文字分取り出す作業を、空白・括弧のどれか
又はEOFが来るまで続ける。flg & 01が非0なら、'/'が来ても
終わる。返値は、次に読まれる文字。*/
static int
rd_string(readfile, sptr, flg, cur_rk)
register FILE *readfile;
char **sptr;
int flg;
ARGS *cur_rk;
{
int c;
while(EOF != (c = chkchar_getc(readfile, cur_rk)) &&
!(is_nulsp(c) || c == '(' || c == ')') &&
!(flg & 01 && c == KUGIRI)){
switch(c){
case '\\':
rd_bcksla(readfile, sptr, cur_rk);
break;
case '^':
rd_ctrl(readfile, sptr, cur_rk);
break;
default:
*(*sptr)++ = c;
}
}
**sptr = '\0';
return(ungetc(c, readfile));
}
static int
rd_str_from_modefile(sptr, flg, cur_rk)
char **sptr;
int flg;
ARGS *cur_rk;
{
return(rd_string(modefile, sptr, flg, cur_rk));
}
/** モード表からバックスラッシュ形式の一文字分を取り出し、'\(8進);'
の形に直す。但し、先頭の'\\'は既に読まれたあと。*/
static void
rd_bcksla(readfile, sptr, cur_rk)
register FILE *readfile;
char **sptr;
ARGS *cur_rk;
{
int c, code = 0, digflg = 0;
switch(c = chkchar_getc(readfile, cur_rk)){
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, cur_rk), is_octal(c)){
code <<= 3;
code += ctov(c);
digflg = 1;
}
if(c != ';') ungetc(c, readfile);
break;
case 'd':
while(c = chkchar_getc(readfile, cur_rk), is_digit(c)){
code *= 10;
code += ctov(c);
digflg = 1;
}
if(c != ';') ungetc(c, readfile);
break;
case 'x':
while(c = chkchar_getc(readfile, cur_rk), 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, cur_rk), is_octal(c)){
code <<= 3;
code += ctov(c);
}
if(c != ';') ungetc(c, readfile);
} else {
code = c;
digflg = 1;
}
}
if(digflg == 0) ERRMOD(7, cur_rk);
sprintf(*sptr, "\\%o;", code);
strtail(*sptr);
}
/** モード表からコントロールコード形式の一文字分を取り出し、
'\(8進);' の形に直す。但し、先頭の'^'は既に読まれたあと。*/
static void
rd_ctrl(readfile, sptr, cur_rk)
register FILE *readfile;
char **sptr;
ARGS *cur_rk;
{
int c;
if(!(' ' <= (c = chkchar_getc(readfile, cur_rk)) && c < '\177')) ERRMOD(7, cur_rk);
if(c == '?') c = '\177';
else c &= 0x1f;
sprintf(*sptr, "\\%o;", c);
strtail(*sptr);
}
/** モード表の一かたまり(リスト、ファイル名、モード表示文字列)を
切り出す。その際、特殊な表記('^','\'による)は、'\(8進);' の
形に直す。flgが非0なら、EOFでエラーを起こし、')'で0を返す。*/
static int
read1tm(sptr, flg, cur_rk)
char **sptr; /* モード表の内部表現の列へのポインタへのポインタ。
rd_bcksla()、rd_ctrl()、codeeval()でも同様 */
int flg;
ARGS *cur_rk;
{
int c, err, retval = 1;
char *s;
s = *sptr;
while((c = fspcpass(cur_rk)) == ';'){
/* 注釈文を検出したら、行末までとばして再試行。*/
while((c = chkchar_getc(modefile, cur_rk)) != '\n' && c != EOF);
}
switch(c){
case '\0': /* EOFを表す */
if(flg) ERRMOD(0, cur_rk);
else retval = 0;
break;
case ')':
if(flg) retval = 0;
else ERRMOD(1, cur_rk);
break;
case '(':
*s++ = c;
*s++ = ' ';
while(read1tm(&s, 1, cur_rk)) *s++ = ' ';
*s++ = ')';
break;
case '"':
*s++ = c;
while((c = chkchar_getc(modefile, cur_rk)) != '"'){
switch(c){
case EOF :
ERRMOD(0, cur_rk);
case '\\':
rd_bcksla(modefile, &s, cur_rk);
break;
case '^' :
rd_ctrl(modefile, &s, cur_rk);
break;
default :
*s++ = c;
}
}
*s++ = '"';
break;
default:
ungetc(c, modefile);
/* 先頭が @ 又は ~ の時は、特殊処理。*/
err = readfnm(modehyo_getc, modehyo_ungetc,
rd_str_from_modefile, &s, &c, cur_rk);
if(err){
mcurread = s;
switch(err){
case 1:
case 3:
ERRMOD(13, cur_rk);
case 2:
ERRMOD(14, cur_rk);
case 4:
ERRMOD(15, cur_rk);
}
}
if(c == EOF && flg) ERRMOD(0, cur_rk);
if(c == ')' && !flg) ERRMOD(1, cur_rk);
}
*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, cur_rk)
char **socp, *dest;
/* socpの指しているポインタが指している所から取り出してdestに入れる。
その後、socpが指しているポインタを進める。*/
int flg;
ARGS *cur_rk;
{
char c;
int retval = 1;
while(c = *(*socp)++, is_nulsp(c)) if(c == '\0') ERRMOD(6, cur_rk);
switch(c){
case ')':
retval = 0;
break;
case '(':
*dest++ = c;
*dest++ = ' ';
while(scan1tm(socp, dest, 0, cur_rk)){
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, cur_rk);
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の値を返す。*/
modetyp
chgmod(num, mode, cur_rk)
int num;
modetyp mode;
ARGS *cur_rk;
{
modetyp oldmod;
oldmod = curmod(num);
curmod(num) = modu1(mode, modrng(num));
choosehyo(cur_rk);
return(oldmod);
}
/** 全モードをまとめて切り替える */
void
allchgmod(mode, cur_rk)
modetyp mode;
ARGS *cur_rk;
{
int i;
for(i = 0; modmeibgn[i] != NULL; i++){
curmod(i) = modu1(mode, modrng(i));
}
choosehyo(cur_rk);
}
/** num番目のモードを指定した数だけインクリメントし、旧modeの値を返す。*/
modetyp
incmod(num, dmode, cur_rk)
int num;
modetyp dmode;
ARGS *cur_rk;
{
modetyp oldmod, newmod;
newmod = oldmod = curmod(num);
newmod += dmode;
if(oldmod > newmod) newmod -= modrng(num);
return(chgmod(num, newmod, cur_rk));
}
/** num番目のモードを指定した数だけデクリメントし、旧modeの値を返す。都合
により、incmodとは別に用意しなくてはならない。*/
modetyp
decmod(num, dmode, cur_rk)
int num;
modetyp dmode;
ARGS *cur_rk;
{
modetyp oldmod, newmod;
newmod = oldmod = curmod(num);
newmod -= dmode;
if(oldmod < newmod) newmod += modrng(num);
return(chgmod(num, newmod, cur_rk));
}
/** nameの名のモードがなければ非0を返し、あればそのモード番号・及びその
状態の最大値+1と現在の状態を取ってくる */
int
romkan_getmode_body(name, nump, modep, moderngp, cur_rk)
char *name;
int *nump;
modetyp *modep, *moderngp;
ARGS *cur_rk;
{
if(!modnam_src(name, nump, cur_rk)) {
return(-1);
}
*modep = curmod(*nump);
*moderngp = modrng(*nump);
return(0);
}
int
romkan_getmode(name, nump, modep, moderngp)
char *name;
int *nump;
modetyp *modep, *moderngp;
{
int x;
ARGS *cur_rk = NULL;
x = romkan_getmode_body(name, nump, modep, moderngp, cur_rk);
return x;
}
/** nameの名のモードがなければ非0を返し、あればその状態をセットして
変換表を再選択の後、旧状態を取り込んで0を返す。*/
int
romkan_setmode_body(name, modep, cur_rk)
char *name;
modetyp *modep;
ARGS *cur_rk;
{
modetyp oldmode, moderng;
int modenum;
if(romkan_getmode_body(name, &modenum, &oldmode, &moderng, cur_rk)!= 0) {
return(-1);
}
chgmod(modenum, *modep, cur_rk);
*modep = oldmode;
return(0);
}
int
romkan_setmode(name, modep)
char *name;
modetyp *modep;
{
int x;
ARGS *cur_rk = NULL;
x = romkan_setmode_body(name, modep, cur_rk);
return x;
}
/** 変換表のクリア */
void
romkan_reset_body(cur_rk)
ARGS *cur_rk;
{
naibu_[0] = Terminator;
choosehyo(cur_rk);
romkan_clear_body(cur_rk);
}
void
romkan_reset()
{
ARGS *cur_rk = NULL;
romkan_reset_body(cur_rk);
}
/** 変換対応表の選択を行う */
void
choosehyo(cur_rk)
ARGS *cur_rk;
{
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, cur_rk);
}
/** モード表の内部形式を順次見ていき、使用表の選択及びモード表示文字列の
選択を行っていく。但しflgが0ならスキップするだけ */
static void
look_choose(naibupp, flg, cur_rk)
int **naibupp; /* モード表の内部表現の列へのポインタへのポインタ。
look_cond()、evlcond()でも同様 */
int flg;
ARGS *cur_rk;
{
int *naibup, naibu1, naibu2, branch, lcrsl;
naibup = *naibupp;
while((naibu1 = *naibup++) != Terminator){
switch(SHUBET(naibu1)){
case 4: /* 表名 */
if(flg) hyouse(LWRMSK(naibu1), cur_rk);
break;
case 2: /* 条件式 */
branch = LWRMSK(naibu1); /* if;when */
lcrsl = look_cond(&naibup, flg, cur_rk);
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, cur_rk)
int **naibupp, flg;
ARGS *cur_rk;
{
int *naibup, condrsl;
naibup = *naibupp;
condrsl = evlcond(&naibup, cur_rk); /* 必ず評価しないといけないため */
flg = flg && condrsl;
look_choose(&naibup, flg, cur_rk);
*naibupp = naibup;
return(flg);
}
/** 条件式の真偽値の評価 返値は0か1とは限らんぞ */
static int
evlcond(naibupp, cur_rk)
int **naibupp;
ARGS *cur_rk;
{
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, cur_rk);
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, cur_rk)
int num;
ARGS *cur_rk;
{
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_body(cur_rk)
ARGS *cur_rk;
{
char *x;
if(dspmod[0][0] == NULL && (flags & RK_DSPNIL))
x = nulstr;
else
x = dspmod[0][0];
return x;
}
char *
romkan_dispmode()
{
char *x;
ARGS *cur_rk = NULL;
x = romkan_dispmode_body(cur_rk);
return x;
}
/** romkanがoff時のモード表示文字列を返す関数。無指定であってRK_DSPNILフラグ
が立っている時は空文字列を返す。*/
char *
romkan_offmode_body(cur_rk)
ARGS *cur_rk;
{
char *x;
if(dspmod[0][1] == NULL && (flags & RK_DSPNIL))
x = nulstr;
else
x = dspmod[0][1];
return x;
}
char *
romkan_offmode()
{
char *x;
ARGS *cur_rk = NULL;
x = romkan_offmode_body(cur_rk);
return x;
}
/** 文字列が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);
#if defined(UX386) || defined(sun386)
out = out * 10;
#else
out *= 10;
#endif
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