diff Wnn/romkan/rk_read.c @ 0:bbc77ca4def5

initial import
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Thu, 13 Dec 2007 04:30:14 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wnn/romkan/rk_read.c	Thu Dec 13 04:30:14 2007 +0900
@@ -0,0 +1,1560 @@
+/*
+ *  $Id: rk_read.c,v 1.6 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_read.c
+                                                88. 6.11  改 正
+
+        rk_main.c の部品。変換対応表の読み込みを担当。
+***********************************************************************/
+/*  Version 3.0  */
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if STDC_HEADERS
+#  include <string.h>
+#elif HAVE_STRINGS_H
+#  include <strings.h>
+#endif /* STDC_HEADERS */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "rk_header.h"
+#include "rk_extvars.h"
+
+letter onescan (), *rangekettei ();
+char *ename ();
+
+extern letter *ltrgrow (), *ltrend (), letterpick (), *ltr1cut ();
+extern char *chrcat (), *strend ();
+
+static int termsscan (), evalandcpy (), eval1cpy (), partscan (), evlis (), atermscan (), serfun (), hensrc_tourk (), blankpass (), modsrcL (), chkL_get_int ();
+static void ERRLIN (), ERHOPN (), readhyo (), ltr1tostr (), ERRHYO (), vchk (), rangeset (), de_bcksla (), listscan (), singleqscan (), doubleqscan ();
+extern void BUGreport (), choosehyo (), readmode ();
+extern int ltrcmp (), ltrstrcmp (), readfnm (), fixednamep ();
+
+#define IHENSU (1 << 24)        /* 内部表現の上位1バイトで、変数を表す */
+#define IKANSU (2 << 24)        /*           〃              関数を表す */
+#define IMODNM (3 << 24)        /*           〃              モード名を表す */
+
+#define ENDOF_NestFileArea ((FILE *)~0)
+         /** includeファイルのディスクリプタ格納エリアのエンドマーク*/
+
+
+ /**    一行読み込み。一字も読み込まないうちにEOFにつきあたったら0を返す。
+        但しincludeを考慮している。対応表には空白文字以外のコントロール文字は
+        生では混じらないものとし、混じっていたらチェックする。*/
+int
+readln (buf)
+     uns_chr *buf;
+{
+  register uns_chr *p;
+  register int c;
+
+  if (NULL == *base)
+    {
+      *buf = '\0';
+      return (0);
+    }
+
+  p = buf;
+  while (1)
+    {
+      while (EOF == (c = getc (*base)))
+        {
+          fclose (*base);
+          if (NULL == *--base)
+            {
+              c = EOF;
+              break;
+            }
+        }
+      if (c == EOF || c == '\n')
+        break;
+
+      if (is_cntrl (c) && !isspace (c))
+        {
+          sprintf (hcurread, "\\%03o", c);
+          ERRLIN (21);
+        }
+      *p++ = c;
+    }
+  *p = '\0';
+  return (p != buf || c != EOF);
+}
+
+letter *memptr, *ltrbufptr, *hensumei, *hen_iki, *term, **henptr;
+letter *dummy;
+struct dat *datptr;
+struct hensuset
+{
+  unsigned regdflg:1;           /* 既登録の変数を表す */
+  unsigned curlinflg:1;         /* 現在行に既出の変数を表す */
+  unsigned constflg:1;          /* 定数として定義されたことを表す */
+  letter *name;
+  letter *range;
+}
+ *hentourkptr, *henorg;
+
+ /** 与えられたファイルがディレクトリなら非0を返す */
+int
+isdir (fnm)
+     char *fnm;
+{
+  struct stat statbuf;
+/*
+        return(stat(fnm, &statbuf) == 0 && (statbuf.st_mode & S_IFDIR));
+*/
+  return (stat (fnm, &statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR));
+}
+
+ /**    nameで与えられた名の変換対応表をオープンする。固定名と見なされない
+        名前(fixednamep()参照)に対しては、サーチパスを見る。その場合、
+        オープンに成功したら、パス名を *dirnamptrに入れて返る。その他の場合は
+        *dirnamptrに空文字列が入る。*errcodには次のエラーコードが入る。
+        与えられたファイルがディレクトリの時1(サーチパスを探した時は3)、
+        ファイルをオープンできない時2(同4)。*/
+FILE *
+trytoopen (name, dirnamptr, errptr)
+     char *name, **dirnamptr;
+     int *errptr;
+{
+  char **src, taio_fnm[REALFN];
+  FILE *opened;
+
+  *dirnamptr = nulstr;
+  *errptr = 0;
+
+  if (fixednamep (name))
+    {
+      if (isdir (name))
+        {
+          *errptr = 1;
+          return (NULL);
+        }
+      if (NULL == (opened = fopen (name, "r")))
+        {
+          *errptr = 2;
+          return (NULL);
+        }
+      if (flags & RK_VERBOS)
+        {
+          fprintf (stderr, "romkan: using Taio-hyo %s ...\r\n", name);
+        }
+      return (opened);
+    }
+  else
+    {
+      for (src = pathmeiorg; *src != NULL; src++)
+        {
+          strcpy (taio_fnm, (*dirnamptr = *src));
+          strcat (taio_fnm, name);
+
+          if (isdir (taio_fnm))
+            {
+              *errptr = 3;
+              return (NULL);
+            }
+          if (NULL == (opened = fopen (taio_fnm, "r")))
+            continue;
+
+          /* Now Taio-hyo found */
+          if (flags & RK_VERBOS)
+            fprintf (stderr, "romkan: using Taio-hyo %s ...\r\n", taio_fnm);
+          return (opened);
+        }
+      if (flags & RK_VERBOS)
+        {                       /* Taio-hyo not found */
+          char *p, *q;
+
+          fprintf (stderr, "no %s in", name);
+          for (src = pathmeiorg; *src != NULL; src++)
+            {
+              fputc (' ', stderr);
+              q = *src;
+              if (*q == KUGIRI && *(q + 1) == '\0')
+                q++;
+              else
+                q = strend (q);
+              for (p = *src; p < q; p++)
+                fputc (*p, stderr);
+            }
+          fprintf (stderr, ".\n");
+        }
+      *dirnamptr = nulstr;
+      *errptr = 4;
+      return (NULL);
+    }
+}
+
+ /** 表全部の読み込み */
+void
+readdata (memory, data, hensudefhyo, modf)
+     letter *memory;            /* 対応表の内部表現を入れる配列の先頭番地を渡される */
+     struct dat *data;          /* 対応表の行ごとのデータを入れる配列の番地 */
+     letter **hensudefhyo;      /* 変数定義のデータを入れる配列の番地 */
+     char *modf;                /* モード定義表の名又はそのパス名が入っている */
+{
+  int i, j;
+  char *hyomeibgn[HYOMAX];
+  /* 表の名へのポインタを入れる配列 */
+  char hyomeimem_[HYOMEI];
+  /* 表の名の実際の文字列を入れる配列 */
+  char *pathmeibgn[PTHMAX];
+  /* サーチパス名へのポインタを入れる配列 */
+  char pathmeimem_[PTHMEI];
+  /* サーチパス名の実際の文字列を入れる配列 */
+  char modfnm[REALFN];
+  /* モード表のファイル名をここへコピる のちにはそのパス名が入る */
+
+  memptr = memory;
+  datptr = data;
+  henptr = hensudefhyo;
+  *(pathmeiptr = pathmeiorg = pathmeibgn) = NULL;
+  *(pathmeimem = pathmeimem_) = '\0';
+  *(hyomeiptr = hyomeiorg = hyomeibgn) = NULL;
+  *(hyomeimem = hyomeimem_) = '\0';
+  *(modmeiptr = modmeibgn) = NULL;
+  *(modmeimem = modmeimem_) = '\0';
+  *(dspnamptr = dspnambgn) = NULL;
+  *(dspcod = dspcod_) = '\0';
+  *(naibu = naibu_) = '\0';
+
+  strcpy (modfnm, modf);
+  /* modfnmが与えたファイル名。パス名だけ与えられたら、デフォルトの
+     モード表名"mode"をつなぐ。KUGIRI=ディレクトリの区切り文字 */
+
+  if (*modfnm == '\0' || *(strend (modfnm)) == KUGIRI)
+    {
+      strcat (modfnm, "mode");
+    }
+  else if (isdir (modfnm))
+    {
+      chrcat (modfnm, KUGIRI);
+      strcat (modfnm, "mode");
+    }
+
+  curdir = nulstr;
+  readmode (curfnm = modfnm);
+
+  for (i = 0; hyomeiorg[i] != NULL; i++)
+    {
+      int err;
+
+      for (j = 0; j < FILNST; j++)
+        nestfile[j] = NULL;
+      nestfile[FILNST - 1] = ENDOF_NestFileArea;
+      base = nestfile + 1;
+
+      *base = trytoopen (curfnm = hyomeiorg[i], &curdir, &err);
+      if (err)
+        {
+          switch (err)
+            {
+            case 1:
+            case 3:
+              ERHOPN (1);
+            case 2:
+            case 4:
+              ERHOPN (0);
+            }
+        }
+      readhyo (i);
+    }
+
+  hyo_n[i].data = NULL;
+  choosehyo ();
+}
+
+ /** ファイル名からパス名を除いた部分の先頭を返す。*/
+char *
+ename (s)
+     char *s;
+{
+  char *p;
+
+  p = strrchr (s, KUGIRI);
+  return (p == NULL ? s : p + 1);
+}
+
+ /**    ファイル名のチェック。先頭(パス名は除く)が'1'〜'3'でないといけない。
+        正当なものなら1〜3(前・本・後処理表の区別を表す)を返し、そうでないと
+        0を返す。*/
+int
+filnamchk (s)
+     char *s;
+{
+  char c;
+
+  c = *(ename (s)) - '0';
+  return ((1 <= c && c <= 3) ? c : 0);
+}
+
+ /**    linbufに入っているunsigned charの列をletterの列にしてltrbufに入れる。
+        エンドマークはEOLTTRになる。flgが非0の時は、先頭の空白文字は飛ばす。*/
+void
+ustrtoltr (linbuf, ltrbuf, flg)
+     uns_chr *linbuf;
+     int flg;
+     register letter *ltrbuf;
+{
+  register letter l;
+
+  if (flg)
+    {
+      while (l = letterpick (&linbuf), is_eolsp (l))
+        {
+          if (l == EOLTTR)
+            {
+              *ltrbuf = EOLTTR;
+              return;
+            }
+        }
+      *ltrbuf++ = l;
+    }
+  while ((*ltrbuf++ = letterpick (&linbuf)) != EOLTTR);
+}
+
+ /**    letterの列を文字列にコンバート。二つのポインタが同一番地であっても
+        動作を保証すること。*/
+void
+ltrtostr (ltrbuf, linbuf)
+     char *linbuf;
+     letter *ltrbuf;
+{
+  letter l;
+
+  while ((l = *ltrbuf++) != EOLTTR)
+    ltr1tostr (l, &linbuf);
+  *linbuf = '\0';
+}
+
+ /** letterを文字列にコンバート */
+static void
+ltr1tostr (l, sptr)
+     char **sptr;
+     letter l;
+{
+  int i;
+
+  for (i = 0; i < 3 && 0 == (l & (0xff000000)); i++)
+    l <<= 8;
+  for (; i < 4; i++)
+    {
+      *(*sptr)++ = (char) (l >> 24);
+      l <<= 8;
+    }
+}
+
+ /** 変数の「現在行既出フラグ」を全てクリア */
+void
+hen_useflgclr (hensu)
+     struct hensuset *hensu;
+{
+  for (; hensu->name != NULL; hensu++)
+    hensu->curlinflg = 0;       /* 現在行に未出 */
+}
+
+ /** 対応表一つ読み込み */
+static void
+readhyo (n)
+     int n;
+{
+  uns_chr linbuf[LINSIZ];
+  letter ltrbuf[LINSIZ], *lp;
+  letter termbuf[SIZALL];       /* エラーを考慮して、表のサイズ分取っておく */
+  letter dummybuf[TRMSIZ], hensumei_[VARLEN], hen_iki_[SIZALL];
+  struct hensuset hensu[VARMAX];
+  int m, hyosw, rsltyp[3];
+
+  hcurread = (char *) linbuf;   /* エラー処理用 */
+  ltrbufbgn = ltrbuf;
+
+  *(hensumei = hensumei_) = EOLTTR;
+  *(hen_iki = hen_iki_) = EOLTTR;
+  (henorg = hentourkptr = hensu)->name = NULL;
+  dummy = dummybuf;
+
+  hyo_n[n].hensudef = henptr;
+  hyo_n[n].data = datptr;
+
+  hyosw = hyoshu[n];
+  while (readln (linbuf))
+    {
+      hen_useflgclr (henorg);
+      ustrtoltr (linbuf, ltrbuf, 1);
+      ltrbufptr = ltrbuf;
+
+      for (m = 0; termsscan (&ltrbufptr, term = termbuf, 1); m++)
+        {
+          /* mは、何番目の項目を見ているかを表す */
+          if (*term == ';')
+            break;              /* 注釈行 */
+          if (m == 3)
+            ERRLIN (15);
+          if (m != 0 && rsltyp[0] == 4)
+            ERRLIN (12);
+
+          datptr->code[m] = memptr;
+          if ((rsltyp[m] = evalandcpy (&term, m)) == 4)
+            {
+              if (m)
+                ERRLIN (14);
+              /* 宣言は最初の項目にしか来れない。
+                 funstr[]のappearフラグでもチェックしているが
+                 将来のために一応ここにもチェックを入れておく。 */
+            }
+          else
+            {
+              /* 宣言の時には内部表現へのポインタは進めない */
+              totail (memptr);
+              memptr++;
+            }
+        }
+
+      if (m != 0 && rsltyp[0] != 4)
+        {
+          for ( /* m=? */ ; m < 3; m++)
+            {
+              datptr->code[m] = nil;
+              rsltyp[m] = -1;   /* doesn't exist */
+            }
+          datptr++;
+
+          /* rsltyp: 0=文字項 1=文字列連 2=データ連 3=機能項 4=宣言項 -1=存在せず */
+          switch (hyosw)
+            {
+              /* 前・後処理は、表の内容に制限がある。それを検査 */
+            case 1:
+              if (!(rsltyp[0] == 0 && rsltyp[1] == 0 && rsltyp[2] == -1))
+                ERRLIN (17);
+              break;
+            case 2:
+              if (rsltyp[1] == 3 && rsltyp[2] != -1)
+                ERRLIN (19);
+              break;
+            case 3:
+              if (!(rsltyp[0] == 0 && (rsltyp[1] == 0 || rsltyp[1] == 1) && rsltyp[2] == -1))
+                ERRLIN (18);
+              break;
+            default:
+              BUGreport (10);
+            }
+
+        }
+    }
+
+  (datptr++)->code[0] = NULL;
+
+  /* 変数登録ここでまとめてする */
+  for (lp = hen_iki_; lp < hen_iki;)
+    *memptr++ = *lp++;
+  for (hentourkptr = henorg; hentourkptr->name != NULL; hentourkptr++)
+    {
+      if (hentourkptr->regdflg == 0)
+        ERRHYO (0);
+      *henptr++ = memptr - (lp - hentourkptr->range);
+    }
+  *henptr++ = NULL;
+
+  /* ここで fclose(*base); は不要。readln内ですんでいる */
+}
+
+ /**    変換対応表の項目一つを、解釈して、内部形式のデータエリアにコピーする。
+        返す値は、解釈した項目が文字項なら0、それ以外で文字列連なら1、それ以外
+        でデータ連なら2、機能項なら3、宣言項なら4。それ以外はエラー。*/
+static int
+evalandcpy (socp, m)
+     register letter **socp;    /* 項目へのポインタ(へのポインタ) */
+     int m;                     /* 対応表の何番目の項目を見ているかを表す。入力コード部を
+                                   見ているときは0、出力コード部なら1、バッファ残り部なら2 */
+{
+#define TYPMAX  5
+
+  char exist[TYPMAX], total;
+  /* existは、それぞれタイプ0〜4の項の出現のフラグ(eval1cpy()参照)。
+     totalは全体としての出現フラグ。どちらも、1=未出 2=一回出 その他の
+     時は下2ビット0 */
+  int type;
+
+#define TIME_0(flag) ((flag) == 1)
+#define TIME_1(flag) ((flag) == 2)
+#define TIME_n(flag) (((flag) & 3) == 0)
+
+  total = 1;
+  for (type = 0; type < TYPMAX; type++)
+    exist[type] = 1;
+
+  while (!is_eolsp (**socp))
+    {
+      if (!(0 <= (type = eval1cpy (socp, m, 0)) && type < TYPMAX))
+        BUGreport (3);
+      exist[type] <<= 1;
+      total <<= 1;
+    }
+
+  if (TIME_0 (total))
+    BUGreport (13);             /* 項目が空ならevalandcpyは実行しない筈 */
+  if (!TIME_0 (exist[3]) || !TIME_0 (exist[4]))
+    {
+      if (TIME_n (total))
+        ERRLIN (9);
+      return (type);            /* 3又は4。typeが値を保持している筈 */
+    }
+  if (TIME_1 (total) && TIME_1 (exist[0]))
+    return (0);
+  return (!TIME_0 (exist[2]) ? 2 : 1);
+}
+
+ /**    対応表の項目の中の項一つを解釈し、内部形式のデータエリアにコピーし、
+        それのタイプ(文字項=0 文字列項=1 特殊関数項=2 機能項=3 宣言項=4)を
+        返す。flgが非0なら、再帰的に呼ばれたことを意味し、その場合、
+        現在行に未出の変数を検出したらエラー。また、mが非0のとき(入力コード部
+        以外の所を見ている時)も、現在行に未出の変数を検出したらエラー。*/
+static int
+eval1cpy (socp, m, flg)
+     letter **socp;             /* flg以外の引数の意味はevalandcpyと同じ */
+     int m, flg;
+{
+  letter t1buf[TRMSIZ], *t1bufp;
+
+  t1bufp = t1buf;
+
+  *memptr = EOLTTR;
+  switch (partscan (socp, t1bufp))
+    {
+    case 1:                     /* 単文字 */
+      memptr = ltrgrow (memptr, t1bufp);
+      *memptr = EOLTTR;
+      return (0);
+    case 2:                     /* 引用文字 */
+      t1bufp++;
+      *memptr++ = onescan (&t1bufp, dummy);
+      *memptr = EOLTTR;
+      return (0);
+    case 3:                     /* 引用文字列 */
+      t1bufp++;
+      while (*t1bufp != '"')
+        {
+          *memptr++ = onescan (&t1bufp, dummy);
+        }
+      *memptr = EOLTTR;
+      return (1);
+    case 0:                     /* リスト */
+      return (evlis (m, &t1bufp, flg));
+      /* evlis内で *memptr = EOLTTR; をしている。 */
+    default:
+      BUGreport (4);
+      return (-1);
+     /*NOTREACHED*/}
+ /*NOTREACHED*/}
+
+#define bitchk(x, n) ((x) & (1 << (n)))
+
+#define get_ltr(lp) (*(lp)++)
+#define unget_ltr(l, lp) (*--(lp) = (l))
+
+ /** globalなポインタから指されているletter列から一文字取ってくる。*/
+/* *INDENT-OFF* */
+letter
+get1ltr ()
+/* *INDENT-ON* */
+{
+  return (get_ltr (lptr));
+}
+
+/* *INDENT-OFF* */
+letter
+unget1ltr (l)
+     letter l;
+/* *INDENT-ON* */
+
+{
+  return (unget_ltr (l, lptr));
+}
+
+int
+int_get1ltr ()
+{
+  return ((int) (get1ltr ()));
+}
+
+int
+int_unget1ltr (c)
+     letter c;
+{
+  return ((int) (unget1ltr ((letter) c)));
+}
+
+ /** 汚いことこの上なし!なぜ関数の型のcastができないの?
+    「(int ()) get1ltr」と書きたい! */
+
+ /**    includeファイル名のletter列をstringに取り出す作業を、letter列の終わり
+        まで続ける。flg & 01が非0なら、'/'でも終了。*/
+/* *INDENT-OFF* */
+letter
+getfrom_dblq (socp, destp, flg)
+     letter **socp;
+     char **destp;
+     int flg;
+/* *INDENT-ON* */
+{
+  letter l;
+
+  while (**socp != EOLTTR && !(flg & 01 && **socp == KUGIRI))
+    {
+      if (**socp == '\\')
+        *(*destp)++ = '\\';
+      l = onescan (socp, dummy);
+      ltr1tostr (l, destp);
+    }
+  *(*destp)++ = '\0';
+  return (**socp);
+}
+
+int
+getfrom_lptr (sptr, flg)
+     char **sptr;
+     int flg;
+{
+  return ((int) getfrom_dblq (&lptr, sptr, flg));
+}
+
+ /**    リストを解釈して内部表現にする。返値は、そのリストのタイプを表す数。
+        文字変数項又は文字関数項:0 文字列関数項:1 特殊関数項:2
+        機能項:3 宣言項:4 */
+static int
+evlis (m, socp, flg)
+     letter **socp;             /* 引数の意味はeval1cpyを参照 */
+     int m, flg;
+{
+  int fnnum, hennum, i;
+  letter t1buf[TRMSIZ];
+
+  (*socp)++;                    /* '('をスキップ */
+  atermscan (socp, t1buf, 3);
+
+  fnnum = serfun (t1buf);
+  if (fnnum != -1 && !bitchk (func[fnnum].appear, m))
+    ERRLIN (14);
+  /* mの値によって、現れてはいけない所への出現かどうか見ている。 */
+
+  switch (fnnum)
+    {                           /* defaultの所以外は func[fnnum].argnumを使ってない */
+    case -1:                    /* 変数 */
+      vchk (t1buf);
+      atermscan (socp, dummy, 2);       /* あればERR */
+      hennum = hensrc_tourk (t1buf, ((m == 0 && !flg) ? 0 : 1));
+      *memptr++ = (henorg[hennum].constflg ? *(henorg[hennum].range) : hennum | IHENSU);
+      break;
+
+    case 0:                     /* fn No.0 defvar */
+      atermscan (socp, t1buf, 3);
+      if (*t1buf == '(')
+        {
+          letter *soc2, t1buf2[TRMSIZ], t1buf3[TRMSIZ];
+          letter *common_hen;
+
+          atermscan (socp, t1buf3, 3);
+
+          soc2 = t1buf + 1;     /* skip '(' */
+
+          atermscan (&soc2, t1buf2, 3);
+          vchk (t1buf2);
+          if (-1 != serfun (t1buf2))
+            ERRLIN (11);
+          hennum = hensrc_tourk (t1buf2, 2);
+          common_hen = rangekettei (hennum, t1buf3);
+
+          while (atermscan (&soc2, t1buf2, 0))
+            {
+              vchk (t1buf2);
+              if (-1 != serfun (t1buf2))
+                ERRLIN (11);
+              hennum = hensrc_tourk (t1buf2, 2);
+              rangeset (hennum, common_hen);
+            }
+        }
+      else
+        {
+          vchk (t1buf);
+          if (-1 != serfun (t1buf))
+            ERRLIN (11);
+          hennum = hensrc_tourk (t1buf, 2);
+          /* defvar・defconstの変数名の重複を避けるため */
+          atermscan (socp, t1buf, 3);
+          rangekettei (hennum, t1buf);
+        }
+      atermscan (socp, dummy, 2);
+      break;
+    case 36:                    /* fn No.36 defconst */
+      atermscan (socp, t1buf, 3);
+      vchk (t1buf);
+      if (-1 != serfun (t1buf))
+        ERRLIN (11);
+
+      hennum = hensrc_tourk (t1buf, 6);
+      /* defvar・defconstの変数名重複を避けるため */
+
+      rangeset (hennum, hen_iki);
+
+      blankpass (socp, 1);
+      if (*(*socp)++ != '\'')
+        ERRLIN (8);
+      *hen_iki++ = onescan (socp, dummy);
+      (*socp)++;                /*「'」が閉じていることの検査は済んでいる */
+      *hen_iki++ = EOLTTR;      /* needed? */
+      *hen_iki = EOLTTR;
+
+      atermscan (socp, dummy, 2);
+      break;
+
+    case 1:                     /* fn No.1 include */
+      {
+        char fnmtmparea[REALFN], *s, *dirnamptr;
+        int dummyc = 0, err;
+
+        blankpass (socp, 1);
+        if (3 != partscan (socp, t1buf))
+          ERRLIN (22);
+        atermscan (socp, dummy, 2);
+        /* 余分にあればERR */
+
+        ltr1cut (lptr = t1buf + 1);
+        *(s = fnmtmparea) = '\0';
+        err = readfnm (int_get1ltr, int_unget1ltr, getfrom_lptr, &s, &dummyc);
+
+        if (err)
+          {
+            hcurread = s;
+            switch (err)
+              {
+              case 1:
+              case 3:
+                ERRLIN (25);
+              case 2:
+                ERRLIN (26);
+              case 4:
+                ERRLIN (27);
+              }
+          }
+        de_bcksla (fnmtmparea, fnmtmparea);
+
+        if (*++base == ENDOF_NestFileArea)
+          {
+            base--;
+            ERRLIN (23);
+          }
+        *base = trytoopen (fnmtmparea, &dirnamptr, &err);
+        if (err)
+          {
+            switch (err)
+              {
+              case 1:
+              case 3:
+              case 2:
+              case 4:
+                base--;
+                ERRLIN (24);
+              }
+          }
+      }
+      break;
+
+      /* モード名一つを引数に取るもの */
+    case 4:                     /* fn No.4〜6 off,on,switch */
+    case 5:
+    case 6:
+    case 20:                    /* fn No.20,21 if,unless */
+    case 21:
+      *memptr++ = fnnum | IKANSU;
+      atermscan (socp, t1buf, 3);
+      *memptr++ = modsrcL (t1buf) | IMODNM;
+      atermscan (socp, t1buf, 2);
+      break;
+
+      /* モード名と文字 一つずつを引数に取るもの */
+    case 37:                    /* fn No.37〜43 setmodeなど */
+    case 38:
+    case 39:
+    case 40:
+    case 41:
+    case 42:
+    case 43:
+      {
+        int err, n;
+        modetyp stat;
+
+        *memptr++ = fnnum | IKANSU;
+        atermscan (socp, t1buf, 3);
+        *memptr++ = (n = modsrcL (t1buf)) | IMODNM;
+        atermscan (socp, t1buf, 3);
+        err = chkL_get_int (t1buf, &stat, modesw[n].moderng);
+        if (err != 0)
+          ERRLIN (29);
+        *memptr++ = stat;
+        atermscan (socp, t1buf, 2);
+        break;
+      }
+
+      /* 普通(引数を取らないものを含む) */
+    default:                    /* toupper,tolower… */
+      *memptr++ = fnnum | IKANSU;
+      *memptr = EOLTTR;
+      for (i = 0; i < func[fnnum].argnum; i++)
+        {
+          blankpass (socp, 1);
+          if (eval1cpy (socp, m, 1) != 0)
+            ERRLIN (13);
+        }
+      atermscan (socp, dummy, 2);       /* 余分にあればERR */
+      break;
+    }
+  *memptr = EOLTTR;
+  return (fnnum == -1 ? 0 : func[fnnum].fntype);
+}
+
+ /** 文字列中の「\」を抜く */
+static void
+de_bcksla (s, r)
+     char *s, *r;
+{
+  for (; *s; *r++ = *s++)
+    if (*s == '\\')
+      s++;
+  *r = '\0';
+}
+
+ /**    defvarの第二引数(shikiに入る)を解釈して、その変数の変域を決定する。
+        変数列の最後にエンドマークもちゃんと入る。返値は、変域を格納した
+        所へのポインタ。*/
+letter *
+rangekettei (num, shiki)
+     letter *shiki;
+     int num;                   /* 変域を決定しつつある変数の内部番号 */
+{
+  letter hyoukabuf[TRMSIZ];
+
+  rangeset (num, hen_iki);
+  *hen_iki = EOLTTR;
+
+  if (*shiki++ != '(')
+    ERRLIN (8);
+  atermscan (&shiki, hyoukabuf, 1);
+
+  if (!ltrstrcmp (hyoukabuf, "all"))
+    {
+      *hen_iki++ = VARRNG;
+      *hen_iki++ = 0;
+      *hen_iki++ = LTRHUG;      /* 変域は全文字 */
+      *hen_iki++ = EOLTTR;
+      *hen_iki = EOLTTR;
+      atermscan (&shiki, dummy, 2);     /* 余分にあればERR */
+    }
+  else if (!ltrstrcmp (hyoukabuf, "between"))
+    {
+      int i;
+
+      *hen_iki++ = VARRNG;
+      while (blankpass (&shiki, 1), *shiki != ')')
+        {
+          for (i = 1; i <= 2; i++)
+            {
+              switch (*shiki)
+                {
+                case '\'':
+                  shiki++;
+                  *hen_iki++ = onescan (&shiki, dummy);
+                  shiki++;
+                  break;
+                case ')':
+                case '"':
+                case '(':
+                  ERRLIN (8);
+                default:
+                  *hen_iki++ = *shiki++;
+                }
+              if (i < 2)
+                {
+                  if (!is_eolsp (*shiki))
+                    ERRLIN (8);
+                  blankpass (&shiki, 1);
+                }
+            }
+        }
+      *hen_iki++ = EOLTTR;
+      *hen_iki = EOLTTR;
+    }
+  else if (!ltrstrcmp (hyoukabuf, "list"))
+    {
+      while (blankpass (&shiki, 1), *shiki != ')')
+        {
+          switch (*shiki)
+            {
+            case '"':
+            case '(':
+              ERRLIN (8);
+            case '\'':
+              shiki++;
+              *hen_iki++ = onescan (&shiki, dummy);
+              shiki++;          /* 本当に「'」が閉じているか
+                                   どうかの検査はもう済んでいる。 */
+              break;
+            default:
+              *hen_iki++ = *shiki++;
+            }
+          if (!is_eolsp (*shiki))
+            ERRLIN (8);
+        }
+      *hen_iki++ = EOLTTR;
+      *hen_iki = EOLTTR;
+    }
+  else
+    {
+      ERRLIN (8);               /* 将来はこの他の構文も許す予定であった */
+    }
+
+  return (henorg[num].range);
+}
+
+ /**    num番目の変数の変域を指すべきポインタの指し先を決定し、その変数を
+        既登録状態にする。*/
+static void
+rangeset (num, range)
+     letter *range;             /* 変域の入る場所のポインタ */
+     int num;
+{
+  henorg[num].range = range;
+  henorg[num].regdflg = 1;
+}
+
+ /**    nameで指定された名の変数を探し、なければ登録。変数名の最後に
+        エンドマークもちゃんと入る。
+        flg & 01が非0の時、その名の変数が現在行に未出ならエラー(constとして
+        既登録の時を除く)。また flg & 02が非0の時、その名の変数が既定義なら
+        エラー(defvarの重複チェック用)。flg & 04が非0ならconstとして登録。*/
+static int
+hensrc_tourk (name, flg)
+     letter *name;
+     int flg;
+{
+  int i;
+
+  for (i = 0; henorg[i].name != NULL; i++)
+    {
+      if (ltrcmp (henorg[i].name, name))
+        continue;
+      /* found */
+      if (flg & 04)
+        ERRLIN (28);
+      if (flg & 02 && henorg[i].regdflg != 0)
+        ERRLIN (10);
+      if (flg & 01 && henorg[i].curlinflg == 0 && henorg[i].constflg == 0)
+        ERRLIN (5);
+      henorg[i].curlinflg = 1;
+      return (i);
+    }
+  if (henorg + i != hentourkptr)
+    BUGreport (5);
+
+  /* ここへ来たということは、初出の変数ということ。当然、flg & 01が
+     非0ならエラー。 */
+  if (flg & 01)
+    ERRLIN (5);
+  hentourkptr->name = hensumei;
+  hentourkptr->curlinflg = 1;
+  hentourkptr->regdflg = 0;     /* 初出だからrangeのdefは未だの筈 */
+  hentourkptr->constflg = ((flg & 04) != 0);
+  (++hentourkptr)->name = NULL;
+  hensumei = ltrgrow (hensumei, name);
+  *++hensumei = EOLTTR;
+
+  return (i);
+}
+
+ /** 組み込み関数・機能名に対してはその番号を、そうでないものなら-1を返す */
+static int
+serfun (lp)
+     register letter *lp;       /* 関数・機能名もしくは変数名 */
+{
+  register int i;
+
+  for (i = 0; func[i].fnname != NULL; i++)
+    {
+      if (!ltrstrcmp (lp, func[i].fnname))
+        return (i);
+    }
+  return (-1);
+}
+
+ /** 変数の名前のチェック おかしいとエラー */
+static void
+vchk (lp)
+     letter *lp;
+{
+  if (is_digit (*lp))
+    ERRLIN (3);
+  for (; *lp != EOLTTR; lp++)
+    {
+      /*    if(is_lower(*lp)) *lp = to_upper(*lp);  */
+      if (!is_alnum (*lp) && *lp != '_')
+        ERRLIN (3);
+    }
+}
+
+ /**    一項目を取り出す。取り出しに成功すると1を返す。flgが非0の時は、')'が
+        見つかるとエラー、';'はそれだけで一項目扱い。*/
+static int
+termsscan (socp, dest, flg)
+     register letter **socp, *dest;
+         /* socpの指しているポインタが指している所から取り出してdestに入れる。
+            その後、socpが指しているポインタを進める。このファイルの **scan()
+            という関数は全てそうなってる。 */
+     int flg;
+{
+  letter *bgn;
+
+  bgn = dest;
+
+  if (blankpass (socp, 0) == 0)
+    {
+      if (flg && **socp == ';')
+        {
+          *dest++ = *(*socp)++;
+        }
+      else
+        while (!is_eolsp (**socp))
+          {
+            if (**socp == ')')
+              {
+                if (flg)
+                  ERRLIN (0);
+                break;
+              }
+            else
+              {
+                partscan (socp, dest);
+                totail (dest);
+              }
+          }
+    }
+
+  *dest = EOLTTR;
+  return (bgn != dest);
+}
+
+ /**    リスト一つか、単純項の一まとまりを取り出す。成功したら1を返す。
+        flgが1のとき、')'が見つかるとエラー。
+        flgが2のとき、取り出しに成功したらエラー。
+        flgが3のとき、取り出しに失敗したらエラー。*/
+static int
+atermscan (socp, dest, flg)
+     register letter **socp, *dest;
+     int flg;
+{
+  letter *bgn;
+  int found;
+
+  bgn = dest;
+
+  if (blankpass (socp, 0) == 0)
+    {
+      if (**socp == '(')
+        {
+          listscan (socp, dest);
+          totail (dest);
+        }
+      else
+        {
+          while (!is_eolsp (**socp) && **socp != '(')
+            {
+              if (**socp == ')')
+                {
+                  if (flg == 1)
+                    ERRLIN (0);
+                  break;
+                }
+              else
+                {
+                  partscan (socp, dest);
+                  totail (dest);
+                }
+            }
+        }
+    }
+
+  *dest = EOLTTR;
+
+  found = (bgn != dest);
+  if ((!found && flg == 3) || (found && flg == 2))
+    ERRLIN (7);
+  return (found);
+}
+
+ /**    項一つを取り出す。取り出したものがリストなら返値は0、単文字なら1、
+        引用文字なら2、引用文字列なら3。*/
+static int
+partscan (socp, dest)
+     register letter **socp, *dest;
+{
+  switch (**socp)
+    {
+    case '(':
+      listscan (socp, dest);
+      return (0);
+    case '\'':
+      singleqscan (socp, dest);
+      return (2);
+    case '"':
+      doubleqscan (socp, dest);
+      return (3);
+    default:
+      *dest++ = *(*socp)++;
+      *dest = EOLTTR;
+      return (1);
+    }
+}
+
+ /** シングルクォート表現一つを取り出す。*/
+static void
+singleqscan (socp, dest)
+     letter **socp, *dest;
+{
+  *dest++ = *(*socp)++;
+  onescan (socp, dest);
+  totail (dest);
+  if ((*dest++ = *(*socp)++) != '\'')
+    ERRLIN (1);
+
+  *dest = EOLTTR;
+}
+
+ /** ダブルクォート表現一つを取り出す。*/
+static void
+doubleqscan (socp, dest)
+     letter **socp, *dest;
+{
+  *dest++ = *(*socp)++;
+  while (**socp != '"')
+    {
+      if (**socp == EOLTTR)
+        ERRLIN (1);
+      onescan (socp, dest);
+      totail (dest);
+    }
+  *dest++ = *(*socp)++;
+
+  *dest = EOLTTR;
+}
+
+ /**    8・10・16進コード用キャラクタを実際のコードに直す。入力のチェックは
+        せず、英文字と数字以外の入力に対しては単に0を返す。*/
+int
+ltov (l)
+     letter l;
+{
+  if (is_upper (l))
+    return (l - 'A' + 10);
+  if (is_lower (l))
+    return (l - 'a' + 10);
+  if (is_digit (l))
+    return (l - '0');
+  else
+    return (0);
+}
+
+ /** ltovの逆 */
+/* *INDENT-OFF* */
+letter
+vtol (l)
+     letter l;
+/* *INDENT-ON* */
+{
+  if (BASEMX <= l)
+    return ('*');
+  return (l + (l < 10 ? '0' : 'A' - 10));
+}
+
+ /**    シングル・ダブルクォートの中での一文字取り出し。
+        「^」によるコントロールコード表現、「\」による8・10・16進表現にも
+        対応。「\」表現は、「\[o又はd又はx]数字の並び[;]」である。*/
+/* *INDENT-OFF* */
+letter
+onescan (socp, dest)
+     letter **socp, *dest;
+/* *INDENT-ON* */
+{
+  letter l, realcode;
+  int digflg;
+
+  switch (realcode = *dest++ = *(*socp)++)
+    {
+    case '^':
+      if (!(' ' <= (l = *(*socp)++) && l < '\177'))
+        ERRLIN (2);
+      realcode = ((*dest++ = l) == '?' ? '\177' : l & 0x1f);
+      break;
+    case '\\':
+      digflg = 0;
+      switch (**socp)
+        {
+        case 'n':
+          *dest++ = *(*socp)++;
+          realcode = '\n';
+          break;
+        case 't':
+          *dest++ = *(*socp)++;
+          realcode = '\t';
+          break;
+        case 'b':
+          *dest++ = *(*socp)++;
+          realcode = '\b';
+          break;
+        case 'r':
+          *dest++ = *(*socp)++;
+          realcode = '\r';
+          break;
+        case 'f':
+          *dest++ = *(*socp)++;
+          realcode = '\f';
+          break;
+        case 'e':
+        case 'E':
+          *dest++ = *(*socp)++;
+          realcode = ESCCHR;
+          break;
+        case 'o':
+          *dest++ = *(*socp)++;
+          for (realcode = 0; is_octal (**socp);)
+            {
+              digflg = 1;
+              realcode <<= 3;
+              realcode += ltov (*dest++ = *(*socp)++);
+            }
+          if (!digflg)
+            ERRLIN (2);
+          if (**socp == ';')
+            *dest++ = *(*socp)++;
+          break;
+        case 'x':
+          *dest++ = *(*socp)++;
+          for (realcode = 0; is_xdigit (**socp);)
+            {
+              digflg = 1;
+              realcode <<= 4;
+              realcode += ltov (*dest++ = *(*socp)++);
+            }
+          if (!digflg)
+            ERRLIN (2);
+          if (**socp == ';')
+            *dest++ = *(*socp)++;
+          break;
+        case 'd':
+          *dest++ = *(*socp)++;
+          for (realcode = 0; is_digit (**socp);)
+            {
+              digflg = 1;
+              realcode *= 10;
+              realcode += ltov (*dest++ = *(*socp)++);
+            }
+          if (!digflg)
+            ERRLIN (2);
+          if (**socp == ';')
+            *dest++ = *(*socp)++;
+          break;
+        default:
+          if (is_octal (**socp))
+            {
+              for (realcode = 0; is_octal (**socp);)
+                {
+                  realcode <<= 3;
+                  realcode += ltov (*dest++ = *(*socp)++);
+                }
+              if (**socp == ';')
+                *dest++ = *(*socp)++;
+            }
+          else
+            {
+              realcode = *dest++ = *(*socp)++;
+            }
+        }
+      break;
+    default:;
+    }
+
+  *dest = EOLTTR;
+  return (realcode);
+}
+
+ /**    letterの列の先頭にある空白をスキップする。
+        行末に達したら、flgが0のときは1を返し、そうでないとエラー。*/
+static int
+blankpass (pptr, flg)
+     register letter **pptr;
+         /* letterの列のポインタへのポインタ。これが指しているものを進める */
+     int flg;
+{
+  while (is_eolsp (**pptr))
+    {
+      if (EOLTTR == **pptr)
+        {
+          if (flg)
+            ERRLIN (4);
+          return (1);
+        }
+      (*pptr)++;
+    }
+  return (0);
+}
+
+ /** リスト一個取り出し */
+static void
+listscan (socp, dest)
+     register letter **socp, *dest;
+{
+  int eofreach;
+
+  *dest++ = *(*socp)++;         /* = '(' */
+  *dest++ = ' ';
+
+  while (eofreach = blankpass (socp, 0), **socp != ')')
+    {
+      if (eofreach)
+        {
+          if (!readln ((uns_chr *) hcurread))
+            ERRLIN (20);
+          ustrtoltr ((uns_chr *) hcurread, (*socp = ltrbufbgn), 1);
+          /* listの中で行が切れている場合、一行追加読み込みを
+             する。uns_chr用のバッファも、letter用のものも、
+             以前の物を先頭から再利用しているので注意。また、
+             エラーが起きた場合、 エラーの位置にかかわらず、
+             現在行として表示されるのは、最後に読まれた行のみ */
+        }
+      else
+        {
+          termsscan (socp, dest, 0);
+          totail (dest);
+          *dest++ = ' ';
+        }
+    }
+  *dest++ = *(*socp)++;         /* = ')' */
+  *dest = EOLTTR;
+}
+
+ /** lpで指定されたモード名を探す。見つからないとエラー */
+static int
+modsrcL (lp)
+     letter *lp;
+{
+  int n;
+
+  for (n = 0; modmeibgn[n] != NULL; n++)
+    if (!ltrstrcmp (lp, modmeibgn[n]))
+      return (n);
+
+  ERRLIN (16);
+   /*NOTREACHED*/ return (-1);
+}
+
+ /** chk_get_int(rk_modread.c)のletter版 */
+static int
+chkL_get_int (lp, ip, range)
+     letter *lp;
+     modetyp *ip;
+     modetyp range;
+{
+  int sgn = 1;
+  modetyp out;
+
+  if (*lp == '-')
+    {
+      lp++;
+      sgn = -1;
+    }
+  for (out = 0; *lp != EOLTTR; lp++)
+    {
+      if (!is_digit (*lp))
+        return (-1);
+      out *= 10;
+      out += ltov (*lp);
+    }
+  if (range != 0)
+    out %= range;
+  if (sgn == -1 && out != 0)
+    out = range - out;
+  *ip = out;
+  return (0);
+}
+
+ /**    この先は、表読み込みでエラった時に警告するルーチン。nはエラーコード。
+        またこれらは全て、romkan_initのエラーコードとして、longjmp経由で
+        1を返す。*/
+
+void
+ERMOPN (n)                      /* モード定義表がオープンできない */
+     unsigned int n;
+{
+  static char *ermes[] = {
+    /*  0 */ "Can't open Mode-hyo",
+    "Unprintable error"
+  };
+
+  if (n >= numberof (ermes))
+    n = 1;
+
+  fprintf (stderr, "\r\nMode-hyo %s ---\r\n", curfnm);
+  fprintf (stderr, "%d: %s.\r\n", n, ermes[n]);
+  longjmp (env0, 1);
+}
+
+static void
+ERHOPN (n)                      /* 変換対応表がオープンできない */
+     unsigned int n;
+{
+  static char *ermes[] = {
+    /*  0 */ "Can't open Taio-hyo",
+    "Is a directory",
+    "Unprintable error"
+  };
+
+  if (n >= numberof (ermes))
+    n = 2;
+
+  fprintf (stderr, "\r\nTaio-hyo %s%s ---\r\n", curdir, curfnm);
+  fprintf (stderr, "%d: %s.\r\n", n, ermes[n]);
+  longjmp (env0, 1);
+}
+
+void
+ERRMOD (n)                      /* モード定義表のエラー */
+     unsigned int n;
+{
+  static char *ermes[] = {
+    /*  0 */ "Table incomplete",
+    "')' mismatch",
+    "Unprintable error",
+    "Illegal filename",
+    "Illegal modename",
+    /*  5 */ "Undefined mode",
+    "Illegal content(s) of list",
+    "Illegal ^,\\o,\\x or \\d expression",
+    "Illegal defmode",
+    "Unrecognized keyword",
+    /* 10 */ "Incomplete string",
+    "Search path specified after filename",
+    "Argument must be a string",
+    "Can't get home directory",
+    "Illegal @-keyword",
+    /* 15 */ "User doesn't exist",
+    "Illegal character",
+    "Defmode or set-path placed wrong"
+  };
+
+  if (n >= numberof (ermes))
+    n = 2;
+
+  fprintf (stderr, "\r\nMode-hyo %s%s ---\r\n%s\r\n", curdir, curfnm, mcurread);
+  fprintf (stderr, "%d: %s.\r\n", n, ermes[n]);
+  fclose (modefile);
+  longjmp (env0, 1);
+}
+
+static void
+ERRLIN (n)                      /* 変換対応表のエラー */
+     unsigned int n;
+{
+  static char *ermes[] = {
+    /*  0 */ "')' mismatch",
+    "Incomplete single-quote or double-quote expression",
+    "Illegal ^,\\o,\\x or \\d expression",
+    "Illegal variable name",
+    "Incomplete line",
+    /*  5 */ "Evaluation of unbound variable",
+    "Unprintable error",
+    "Too many or too few contents of list",
+    "Illegal defvar/defconst",
+    "Faculity or declaration joined other item(s)",
+    /* 10 */ "Duplicate defvar/defconst",
+    "Variable/constant name conflicts with Function name",
+    "A line contains both declaration and other output item(s)",
+    "Argument isn't a letter",
+    "Function, faculity or declaration in illegal place",
+    /* 15 */ "More than 3 items",
+    "Undefined mode",
+    "Against the restriction of pre-transform table",
+    "Against the restriction of after-transform table",
+    "Item comes after faculity",
+    /* 20 */ "Incomplete list",
+    "Illegal character",
+    "Illegal include",
+    "Too many levels of 'include' nest",
+    "Can't open include file",
+    /* 25 */ "Can't get home directory",
+    "Illegal @-keyword",
+    "User doesn't exist",
+    "Constant must be defined before used",
+    "Illegal mode status"
+  };
+
+  if (n >= numberof (ermes))
+    n = 6;
+
+  fprintf (stderr, "\r\nTaio-hyo %s%s ---\r\n%s\r\n", curdir, curfnm, hcurread);
+  fprintf (stderr, "%d: %s.\r\n", n, ermes[n]);
+
+  while (NULL != *base)
+    fclose (*base--);
+
+  longjmp (env0, 1);
+}
+
+static void
+ERRHYO (n)                      /* ERRLINと同様、対応表のエラーだが、一行だけの誤りでなく
+                                   全体を見ないとわからない誤り。今の所、「未定義変数の出現」のみ。 */
+     unsigned int n;
+{
+  static char *ermes[] = {
+    /*  0 */ "Undefined variable was found",
+    "Unprintable error"
+  };
+
+  if (n >= numberof (ermes))
+    n = 1;
+
+  fprintf (stderr, "\r\nTaio-hyo %s%s ---\r\n", curdir, curfnm);
+  fprintf (stderr, "%d: %s.\r\n", n, ermes[n]);
+
+  while (NULL != *base)
+    fclose (*base--);
+
+  longjmp (env0, 1);
+}