/*
* 小学館ランダムハウス英語辞典検索ユーティリティー - csrd
*
* Written by Junn Ohta (ohta@src.ricoh.co.jp), Public Domain.
*/
char *progname = "csrd";
char *version = "1.0";
char *date = "1999/07/19";
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef UNIX
#include <unistd.h>
#endif
#ifdef MSDOS
#include <io.h>
#endif
typedef unsigned char uchr;
typedef unsigned int unt;
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define OK 0
#define ERR (-1)
#define TRUE 1
#define FALSE 0
#define SJIS1(c) ((c)>=0x81 && (c)<=0x9f || (c)>=0xe0 && (c)<=0xef)
#ifdef DEBUG
int debug = FALSE; /* デバッグフラグ */
int debug2 = FALSE; /* デバッグフラグ */
#endif
/* -------------------- ユーティリティー関数 -------------------- */
#define POOLSIZ 1024 /* 文字列プールの割り当て単位 */
uchr *pool = NULL; /* 文字列プール */
uchr *pfree = NULL; /* 文字列プールの空き領域先頭 */
int hexval();
uchr *escchar();
uchr *skipeq();
uchr *skipsp();
uchr *strpool();
void bsltosl();
int nspaces();
void lower();
/*
* hexval - 2桁の16進数が示す値を返す
*/
int
hexval(p)
uchr *p;
{
int i, n;
n = 0;
for (i = 0; i < 2; i++) {
n <<= 4;
if (*p >= '0' && *p <= '9')
n += *p - '0';
else if (*p >= 'a' && *p <= 'f')
n += *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
n += *p - 'A' + 10;
else
n = 0;
p++;
}
return n;
}
/*
* escchar - '\'でエスケープされた文字を調べ、次の位置を返す
*/
uchr *
escchar(str, cp)
uchr *str;
int *cp;
{
uchr *p;
p = str;
if (*p++ != '\\')
return str;
if (*p >= '0' && *p <= '7') {
sscanf(p, "%3o", cp);
return p + 3;
}
switch (*p) {
case 'x':
*cp = hexval(p + 1);
p += 3;
break;
case 'n':
*cp = '\n';
p++;
break;
case 't':
*cp = '\t';
p++;
break;
default:
*cp = *p++;
break;
}
return p;
}
/*
* skipeq - '='までを読み飛ばし、次の位置を返す
*/
uchr *
skipeq(str)
uchr *str;
{
while (*str && *str != '=')
str++;
if (*str == '=')
str++;
return str;
}
/*
* skipsp - 空白を読み飛ばし、次の位置を返す
*/
uchr *
skipsp(str)
uchr *str;
{
while (*str == ' ' || *str == '\t')
str++;
return str;
}
/*
* strpool - 文字列をプールに格納してそのアドレスを返す
* (解放を考慮しないstrdup)
*/
uchr *
strpool(str)
uchr *str;
{
int len;
uchr *p;
if (str == NULL)
return NULL;
len = strlen(str) + 1;
if (pool == NULL || pfree + len > pool + POOLSIZ) {
pool = (uchr *)malloc(POOLSIZ); /* 以前のpoolの値は忘れる */
if (pool == NULL)
return NULL;
pfree = pool;
}
p = pfree;
pfree += len;
return strcpy(p, str);
}
/*
* bsltosl - 文字列中のバックスラッシュ(\)をスラッシュ(/)に変換する
*/
void
bsltosl(str)
uchr *str;
{
if (str == NULL)
return;
while (*str) {
if (*str == '\\')
*str = '/';
if (SJIS1(*str))
str++;
str++;
}
}
/*
* nspaces - 文字列の先頭にあるスペースの量を数える
*/
int
nspaces(str)
uchr *str;
{
int n;
if (str == NULL)
return 0;
n = 0;
while (*str && isspace(*str)) {
switch (*str++) {
case ' ':
n++;
break;
case '\t':
n = (n | 0x07) + 1;
break;
case '\n':
case '\r':
n = 0;
break;
case '\b':
if (n > 0)
n--;
break;
}
}
return n;
}
/*
* lower - 英文字列を小文字化する
*/
void
lower(str)
uchr *str;
{
if (str == NULL)
return;
while (*str) {
if (isascii(*str) && isupper(*str))
*str = tolower(*str);
str++;
}
}
/* -------------------- バッファード入力 -------------------- */
#define BBUFSIZ 4096
typedef struct _bfile {
int fd;
long size;
long pos;
uchr *p, *ep;
uchr buf[BBUFSIZ];
} BFILE;
BFILE *bopen();
long btell();
int bseek();
int bread();
int bgetc();
int bgetcbw();
int bclose();
/*
* bopen - バッファード入力でファイルをオープンする
* bseek()で位置づけをするまで読み込みはできない
*/
BFILE *
bopen(file)
char *file;
{
int fd;
BFILE *bp;
struct stat st;
if ((fd = open(file, O_RDONLY|O_BINARY)) < 0)
return NULL;
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
bp = (BFILE *)malloc(sizeof(BFILE));
if (bp == NULL) {
close(fd);
return NULL;
}
bp->fd = fd;
bp->size = st.st_size;
bp->pos = 0L;
bp->p = bp->ep = NULL;
return bp;
}
/*
* btell - バッファード入力のtell()もどき
*/
long
btell(bp)
BFILE *bp;
{
if (bp->p == NULL)
return (long)ERR;
return bp->pos + (bp->p - bp->buf);
}
/*
* bseek - バッファード入力のlseek()もどき
*/
int
bseek(bp, pos)
BFILE *bp;
long pos;
{
int n;
if (bp->p
&& pos >= bp->pos
&& pos < bp->pos + (bp->ep - bp->buf)) {
bp->p = bp->buf + (pos - bp->pos);
return OK;
}
if (pos >= bp->size
|| lseek(bp->fd, pos, SEEK_SET) < 0
|| (n = read(bp->fd, bp->buf, BBUFSIZ)) <= 0) {
bp->pos = 0L;
bp->p = bp->ep = NULL;
return ERR;
}
bp->pos = pos;
bp->p = bp->buf;
bp->ep = bp->buf + n;
return OK;
}
/*
* bread - バッファード入力のread()もどき
*/
int
bread(bp, buf, len)
BFILE *bp;
uchr *buf;
int len;
{
int n;
uchr *p;
if (bp->p == NULL)
return ERR;
p = buf;
while (len > 0) {
n = bp->ep - bp->p;
if (n >= len) {
memcpy(p, bp->p, (size_t)len);
p += len;
bp->p += len;
len = 0;
} else if (n > 0) {
memcpy(p, bp->p, (size_t)n);
p += n;
bp->p += n;
len -= n;
} else {
n = read(bp->fd, bp->buf, BBUFSIZ);
if (n <= 0) {
bp->pos = 0L;
bp->p = bp->ep = NULL;
break;
}
bp->pos += bp->ep - bp->buf;
bp->p = bp->buf;
bp->ep = bp->buf + n;
}
}
return p - buf;
}
/*
* bgetc - バッファード入力のgetc()もどき
*/
int
bgetc(bp)
BFILE *bp;
{
int n;
if (bp->p == NULL)
return EOF;
if (bp->p < bp->ep)
return (int)*(bp->p++);
n = read(bp->fd, bp->buf, BBUFSIZ);
if (n <= 0) {
bp->pos = 0L;
bp->p = bp->ep = NULL;
return EOF;
}
bp->pos += bp->ep - bp->buf;
bp->p = bp->buf;
bp->ep = bp->buf + n;
return (int)*(bp->p++);
}
/*
* bgetcbw - 現在の位置からファイル先頭方向にbgetc()する
*/
int
bgetcbw(bp)
BFILE *bp;
{
int n;
long npos;
if (bp->p == NULL)
return EOF;
if (bp->p > bp->buf)
return (int)*(--bp->p);
n = BBUFSIZ;
npos = bp->pos - n;
if (bp->pos < 0L) {
npos = 0L;
n = bp->pos - npos;
if (n == 0)
return EOF;
}
if (lseek(bp->fd, npos, SEEK_SET) < 0
|| read(bp->fd, bp->buf, n) < n) {
bp->pos = 0L;
bp->p = bp->ep = NULL;
return EOF;
}
bp->pos = npos;
bp->ep = bp->buf + n;
bp->p = bp->ep;
return (int)*(--bp->p);
}
/*
* bclose - バッファード入力のclose()もどき
*/
int
bclose(bp)
BFILE *bp;
{
int fd;
fd = bp->fd;
free((char *)bp);
return close(fd);
}
/* -------------------- 日本語処理 -------------------- */
#define KC_JIS 0
#define KC_EUC 1
#define KC_SJIS 2
#ifdef UNIX
#define KC_DEF KC_EUC
#endif
#ifdef MSDOS
#define KC_DEF KC_SJIS
#endif
/*
* 外字表
*/
uchr *gaijitbl[8][256] = {
{ /* G0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"/",
0,0,0,0,0,0,0,0,0,0,":",0,0,"=",0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,"...",0,0,0,0,0,0,0,0,0,0,
0,0,0,"\"","\"",0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,"(C)",0,0,0,0,"(R)",0,
0,0,0,0,0,0,0,"/",0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G1 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,"(タブー)",0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G2 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,"▼",0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G3 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,"(P)",0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,"←→",0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G4 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,"→",0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"《",
"》","〔","〕",0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G5 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G6 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}, { /* G99 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,"#",0,0,0,0,0,0,0,0,0,0,0,"/",
0,0,0,0,0,0,0,0,0,0,0,0,"<",0,">",0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,"...",0,0,0,0,0,0,0,0,0,0,
0,0,0,"\"","\"",0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
"A","A",0,0,0,0,0,0,"E","E",0,0,"I","I",0,0,
0,0,"O","O",0,0,0,0,0,"U","U",0,0,0,0,0,
"a","a",0,0,0,0,0,0,"e","e",0,0,"i","i",0,0,
0,0,"o","o",0,0,0,0,0,"u","u",0,0,"y",0,0
}
};
/*
* デフォルト外字
*/
uchr *gdeftbl[8] = { 0, 0, 0, 0, 0, 0 ,"〓", 0 };
typedef struct _alttbl_t {
uchr org[4]; /* 元表記 */
uchr *alt; /* 代替表記 */
} ALTTBL;
#define ATBLINC 10 /* 代替表記表の増分 */
uchr have_alt[256]; /* その文字は代替表記を持つか? */
ALTTBL *alttbl = NULL; /* 代替表記表 */
int altnum = 0; /* 代替表記表要素数 */
int in_alt = FALSE; /* 代替表記中状態か? */
int curpos = 0; /* 現在の表示位置 */
int kcode = KC_DEF; /* 入出力漢字コード */
int jiskanji = 'B'; /* JIS漢字コードの漢字選択 */
int jisalpha = 'B'; /* JIS漢字コードの英字選択 */
int width = 0; /* 出力行幅 */
int indent = 0; /* インデント量 */
int kmode = FALSE; /* 端末がJIS漢字指示状態か? */
int rawmode = FALSE; /* 出力無加工モード */
int gfont = -1; /* 外字フォント番号 */
int hlink = FALSE; /* ハイパーリンク指定内 */
int add_alt();
int init_alt();
uchr *get_gaiji();
int load_gaiji();
uchr *tosjis();
void outchar();
void outstr();
void set_indent();
void newline();
/*
* add_alt - 代替表記表に代替表記を追加する
*/
int
add_alt(org, alt)
uchr *org, *alt;
{
int i;
uchr *p;
static int atblsiz = 0;
for (i = 0; i < altnum; i++) {
if (!strcmp(alttbl[i].org, org)) {
p = strpool(alt);
if (p == NULL)
return ERR;
alttbl[i].alt = p;
return OK;
}
}
if (alttbl == NULL) {
atblsiz = ATBLINC;
alttbl = (ALTTBL *)malloc(sizeof(ALTTBL) * atblsiz);
altnum = 0;
} else if (altnum >= atblsiz) {
atblsiz += ATBLINC;
alttbl = (ALTTBL *)realloc(alttbl, sizeof(ALTTBL) * atblsiz);
}
if (alttbl == NULL)
return ERR;
p = strpool(alt);
if (p == NULL)
return ERR;
strcpy(alttbl[altnum].org, org);
alttbl[altnum].alt = p;
have_alt[*org] = TRUE;
altnum++;
return OK;
}
/*
* init_alt - 代替表記表にデフォルト代替表記を登録する
*/
int
init_alt()
{
int err;
err = 0;
if (add_alt("\xa5", "/") == ERR) /* 1バイトカナの中点 */
err++;
return err;
}
/*
* get_gaiji - フォント番号とコードから外字文字列を返す
*/
uchr *
get_gaiji(g, ch)
int g, ch;
{
uchr *p;
if (g == 9)
g = 7;
p = gaijitbl[g][ch];
if (p == NULL)
p = gdeftbl[g];
return p;
}
/*
* load_gaiji - 外字代替表記ファイルを読んで外字を登録する
*/
int
load_gaiji(file)
uchr *file;
{
int c, ch, g, isalt;
int line, err;
uchr *p, *q;
FILE *fp;
uchr org[4], buf[256], tmp[256];
if ((fp = fopen(file, "r")) == NULL) {
outstr("ERR: 外字代替表記ファイルがオープンできません\n");
return ERR;
}
line = 0;
err = 0;
while (fgets(buf, 256, fp) != NULL) {
line++;
buf[strlen(buf) - 1] = '\0';
p = skipsp(buf);
if (*p == '\0' || *p == ';')
continue;
if (*p == '"') { /* 代替表記 */
p++;
if (*p == '\\') {
p = escchar(p, &c);
org[0] = c;
org[1] = '\0';
} else if (SJIS1(*p)) {
org[0] = *p++;
org[1] = *p++;
org[2] = '\0';
} else {
org[0] = *p++;
org[1] = '\0';
}
if (*p != '"') {
sprintf(tmp,
"ERR: line %d: 代替元文字が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
p++;
isalt = TRUE;
} else { /* 外字定義 */
if (*p != 'G' || !strchr("01234569", p[1]) || p[2] != '-' ||
!(isxdigit(p[3]) && isxdigit(p[4]) || p[3] == '*')) {
sprintf(tmp,
"ERR: line %d: 外字番号が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
g = p[1] - '0';
if (g == 9)
g = 7;
if (p[3] == '*') {
ch = -1;
p += 4;
} else {
ch = hexval(p + 3);
p += 5;
}
isalt = FALSE;
}
p = skipsp(p);
if (*p == '=')
p++;
p = skipsp(p);
if (*p != '"') {
sprintf(tmp,
"ERR: line %d: 代替表記文字列が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
p++;
q = tmp;
while (*p && *p != '"') {
if (*p == '\\') {
p = escchar(p, &c);
if (c == '\\' || c == '<' || c == '>')
*q++ = '\\';
*q++ = c;
continue;
}
if (SJIS1(*p)) {
*q++ = *p++;
*q++ = *p++;
continue;
}
if (*p == '<' || *p == '>' || *p == '#')
*q++ = '\\';
*q++ = *p++;
}
if (*p != '"') {
sprintf(tmp,
"ERR: line %d: 代替表記文字列が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
*q = '\0';
if (isalt) {
if (add_alt(org, tmp) == ERR) {
outstr("ERR: メモリーが足りません\n");
err++;
}
continue;
}
if ((q = strpool(tmp)) == NULL) {
outstr("ERR: メモリーが足りません\n");
err++;
continue;
}
if (ch >= 0)
gaijitbl[g][ch] = q;
else
gdeftbl[g] = q;
}
fclose(fp);
if (err)
return ERR;
return OK;
}
#ifdef MSDOS
uchr *
tosjis(str)
uchr *str;
{
return str;
}
void
outchar(c)
int c;
{
if (c == 0)
return;
putchar(c);
}
#endif
#ifdef UNIX
/*
* tosjis - kcodeで表現された文字列をシフトJISに変換する
* (コマンド行引数の変換に使う)
*/
uchr *
tosjis(str)
uchr *str;
{
int c, c1;
int c2, km;
uchr *p;
static uchr buf[128];
if (kcode == KC_SJIS) {
strcpy((char *)buf, str);
return buf;
}
km = FALSE;
p = buf;
c1 = 0;
while ((c = *str++) != '\0') {
if (c1 != 0) {
c1 &= 0x7f;
c &= 0x7f;
if ((c1 & 0x01) == 0) {
c += 0x7e;
} else {
c += 0x1f;
if (c > 0x7e)
c++;
}
c1 = (c1 + 0xe1) >> 1;
if (c1 > 0x9f)
c1 += 0x40;
*p++ = c1;
*p++ = c;
c1 = 0;
continue;
}
if (c == '\033') {
c1 = *str++;
c2 = *str++;
if (c1 == '$' && (c2 == '@' || c2 == 'B'))
km = TRUE;
else if (c1 == '(' && (c2 == 'J' || c2 == 'B'))
km = FALSE;
continue;
}
if ((c & 0x80) || km == 1) {
c1 = c;
continue;
}
*p++ = c;
}
*p = '\0';
return buf;
}
/*
* outchar - シフトJISの文字を状態遷移を管理しながら
* kcodeに変換して出力する
* 引数が0なら出力側の状態を英字に戻す(JISのとき必要)
*/
void
outchar(c)
int c;
{
static int knj1 = 0;
if (c == '\0') {
if (kmode) {
printf("\033(%c", jisalpha);
kmode = FALSE;
}
return;
}
if (knj1 != 0) {
if (kcode == KC_JIS && !kmode) {
printf("\033$%c", jiskanji);
kmode = TRUE;
}
if (kcode == KC_JIS || kcode == KC_EUC) {
if (knj1 > 0x9f)
knj1 -= 0x40;
knj1 += knj1;
if (c <= 0x9e) {
knj1 -= 0xe1;
if (c >= 0x80)
c -= 1;
c -= 0x1f;
} else {
knj1 -= 0xe0;
c -= 0x7e;
}
if (kcode == KC_EUC) {
knj1 += 0x80;
c += 0x80;
}
}
putchar(knj1);
putchar(c);
knj1 = 0;
return;
}
if (c >= 0x81) {
knj1 = c;
return;
}
if (kmode) {
printf("\033(%c", jisalpha);
kmode = FALSE;
}
putchar(c);
}
#endif
/*
* outstr - 外字を変換しながらoutchar経由で文字を出力する
*/
void
outstr(p)
uchr *p;
{
int i, g;
uchr *gstr;
uchr tmp[16];
while (*p) {
if (rawmode) {
outchar(*p++);
continue;
}
if (*p == '<') {
if (p[1] == '/') {
if (p[2] == 'G' && isdigit(p[3]))
gfont = -1;
else if (!strncmp(p+2, "RUBY>", 5))
outstr(")");
else if (!strncmp(p+2, "HL>", 3))
hlink = FALSE;
} else {
if (p[1] == 'G')
gfont = p[2] - '0';
else if (!strncmp(p+1, "RUBY>", 5))
outstr("(");
else if (!strncmp(p+1, "HL>", 3))
hlink = TRUE;
}
while (*p != '>')
p++;
p++;
continue;
}
if (*p == ':' && hlink) {
/*
* ハイパーリンク指定内の「:」以降はすべて無視
*/
p++;
while (*p && (*p != '<' || strncmp(p, "</HL>", 5))) {
if (SJIS1(*p))
p++;
p++;
}
p += 5;
hlink = FALSE;
continue;
}
if (*p == '#' && p[3] == '#') {
g = (gfont == -1)? 0: gfont;
gstr = get_gaiji(g, hexval(p+1));
if (gstr) {
outstr(gstr);
} else {
sprintf(tmp, "\\<G%d-%c%c\\>", g, p[1], p[2]);
outstr(tmp);
}
p += 4;
continue;
}
if (!in_alt && have_alt[*p]) {
for (i = 0; i < altnum; i++) {
if (*p == alttbl[i].org[0] &&
(!SJIS1(*p) || p[1] == alttbl[i].org[1]))
break;
}
if (i < altnum) {
in_alt = TRUE;
outstr(alttbl[i].alt);
in_alt = FALSE;
if (SJIS1(*p))
p++;
p++;
continue;
}
}
if (*p == '\\')
p++;
if (SJIS1(*p)) {
if (width > 0 && curpos >= width - 1)
newline();
outchar(*p++);
outchar(*p++);
curpos += 2;
continue;
}
if (*p < ' ' || *p == 0x7f) {
switch (*p) {
case '\n':
newline();
p++;
break;
case '\t':
if (width > 0 && ((curpos | 0x07) + 1) > width)
newline();
outchar(*p++);
curpos = (curpos | 0x07) + 1;
break;
default:
outchar(*p++);
break;
}
continue;
}
if (width > 0 && curpos >= width && !strchr("!),.:;?]}", *p))
newline();
outchar(*p++);
curpos++;
}
outchar(0);
}
/*
* set_indent - インデント量を設定する
*/
void
set_indent(n)
int n;
{
indent = n;
}
/*
* newline - 改行して設定量だけインデントする
*/
void
newline()
{
outchar('\n');
for (curpos = 0; curpos < indent; curpos++)
outchar(' ');
}
/* -------------------- 表示書式処理 -------------------- */
/*
* 本文データ行頭のラベル
*/
#define LBL_ERROR (-1)
#define LBL_CMT 0 /* 注釈(非表示) */
#define LBL_DR 1 /* 派生形 */
#define LBL_EN 2 /* 見出し語 */
#define LBL_ENN 3 /* 検索用異表記???(非表示) */
#define LBL_ENV 4 /* 異表記 */
#define LBL_ENVN 5 /* 別綴り異表記??? */
#define LBL_ET 6 /* 初出??? */
#define LBL_EV 7 /* 同義語 */
#define LBL_EX 8 /* 用例 */
#define LBL_EXKEY 9 /* 用例検索キー */
#define LBL_EXSUB 10 /* 用例サブ項目 */
#define LBL_F 11 /* IFの誤記???(tallith) */
#define LBL_ID 12 /* 成句 */
#define LBL_IDSUB 13 /* 成句サブ項目 */
#define LBL_IF 14 /* 不規則活用 */
#define LBL_IMG 15 /* 図版データ(非表示) */
#define LBL_J2E 16 /* 日本語から借用(adsuki bean) */
#define LBL_KEY 17 /* 検索キー(非表示) */
#define LBL_KEYEX 18 /* 用例検索キー(非表示) */
#define LBL_KEYID 19 /* 成句検索キー(非表示) */
#define LBL_LOC 20 /* 本文格納位置(非表示) */
#define LBL_MEN 21 /* MNの誤記??? */
#define LBL_MN 22 /* 意味 */
#define LBL_MNSUB 23 /* 意味サブ項目 */
#define LBL_NB 24 /* 註 */
#define LBL_NBP 25 /* 表現註 */
#define LBL_NBPSUB 26 /* 表現註サブ項目 */
#define LBL_NBSUB 27 /* 註サブ項目 */
#define LBL_NSBUS 28 /* NBSUBの誤記???(and) */
#define LBL_OT 29 /* 類語、発音、... */
#define LBL_OTSUB 30 /* 類語サブ項目 */
#define LBL_PR 31 /* 発音 */
#define LBL_PS 32 /* 品詞 */
#define LBL_RA 33 /* ???(非表示) */
#define LBL_RES 34 /* ???(非表示) */
#define LBL_RN 35 /* ???(非表示) */
#define LBL_SM 36 /* ???(非表示) */
#define LBL_SND 37 /* 音声データ(非表示) */
#define LBL_SRC 38 /* 語源 */
#define LBL_SRCSUB 39 /* 語源サブ項目 */
#define LBL_TL 40 /* 文献タイトル */
#define LBL_TLSUB 41 /* 文献タイトルサブ項目 */
#define LBL_TQ 42 /* 意味分類(getの「I 所有する」)*/
#define LBL_TR 43 /* 語意 */
#define LBL_TRSUB 44 /* 語意サブ項目 */
/*
* 以下はcsrd内部処理用
*/
#define LBL_ZEX 45 /* 成句・用例検索結果の用例 */
#define LBL_ZID 46 /* 成句・用例検索結果の成句 */
typedef struct _lbltbl_t {
int id; /* ラベル識別ID */
int disp; /* 出力するか? */
uchr *label; /* ラベル文字列 */
uchr *leader; /* 先頭に出力する文字列 */
} LBLTBL;
/*
* ラベル表
*/
LBLTBL labeltbl[] = {
{ LBL_CMT, FALSE, "CMT", "" },
{ LBL_DR, TRUE, "DR", "" },
{ LBL_EN, TRUE, "EN", "□ " },
{ LBL_ENN, FALSE, "ENN", "" },
{ LBL_ENV, TRUE, "ENV", "" },
{ LBL_ENVN, TRUE, "ENVN", "" },
{ LBL_ET, TRUE, "ET", "" },
{ LBL_EV, TRUE, "EV", "" },
{ LBL_EX, TRUE, "EX", " " },
{ LBL_EXKEY, FALSE, "EXKEY", "" },
{ LBL_EXSUB, TRUE, "EXSUB", "" },
{ LBL_F, TRUE, "F", "" },
{ LBL_ID, TRUE, "ID", "" },
{ LBL_IDSUB, TRUE, "IDSUB", "" },
{ LBL_IF, TRUE, "IF", "" },
{ LBL_IMG, FALSE, "IMG", "" },
{ LBL_J2E, TRUE, "J2E", "" },
{ LBL_KEY, FALSE, "KEY", "" },
{ LBL_KEYEX, FALSE, "KEYEX", "" },
{ LBL_KEYID, FALSE, "KEYID", "" },
{ LBL_LOC, FALSE, "LOC", "" },
{ LBL_MEN, TRUE, "MEN", "" },
{ LBL_MN, TRUE, "MN", "" },
{ LBL_MNSUB, TRUE, "MNSUB", "" },
{ LBL_NB, TRUE, "NB", "" },
{ LBL_NBP, TRUE, "NBP", " " },
{ LBL_NBPSUB, TRUE, "NBPSUB", "" },
{ LBL_NBSUB, TRUE, "NBSUB", "" },
{ LBL_NSBUS, TRUE, "NSBUS", "" },
{ LBL_OT, TRUE, "OT", "" },
{ LBL_OTSUB, TRUE, "OTSUB", "" },
{ LBL_PR, TRUE, "PR", " " },
{ LBL_PS, TRUE, "PS", "\n■" },
{ LBL_RA, FALSE, "RA", "" },
{ LBL_RES, FALSE, "RES", "" },
{ LBL_RN, FALSE, "RN", "" },
{ LBL_SM, TRUE, "SM", "" },
{ LBL_SND, FALSE, "SND", "" },
{ LBL_SRC, TRUE, "SRC", "" },
{ LBL_SRCSUB, TRUE, "SRCSUB", "" },
{ LBL_TL, TRUE, "TL", "" },
{ LBL_TLSUB, TRUE, "TLSUB", "" },
{ LBL_TQ, TRUE, "TQ", "\n" },
{ LBL_TR, TRUE, "TR", "" },
{ LBL_TRSUB, TRUE, "TRSUB", "" },
{ LBL_ZEX, TRUE, "ZEX", "" },
{ LBL_ZID, TRUE, "ZID", "" },
{ LBL_ERROR, FALSE, NULL, NULL }
};
LBLTBL *get_label();
int load_format();
int suppress();
/*
* get_label - 行頭のラベルを識別する
*/
LBLTBL *
get_label(str)
uchr *str;
{
uchr *p, *q;
LBLTBL *lp;
uchr tmp[128];
p = str;
q = tmp;
while (*p && isalpha(*p) && isupper(*p))
*q++ = *p++;
*q = '\0';
if (!strncmp(str, "J2E", 3))
strcpy(tmp, "J2E");
lp = labeltbl;
while (lp->label != NULL) {
if (!strncmp(tmp, lp->label, strlen(tmp)))
break;
lp++;
}
if (lp->id == LBL_OT) {
if (isdigit(str[2]) && str[3] == 'S')
lp++; /* OTの代わりにOTSUBを指すようにする */
}
return lp;
}
/*
* load_format - 書式ファイルを読んでラベル表を更新する
*/
int
load_format(file)
uchr *file;
{
int c, line, err, disp;
uchr *p, *q;
FILE *fp;
LBLTBL *lp;
uchr buf[256], tmp[256];
if ((fp = fopen(file, "r")) == NULL) {
outstr("ERR: 表示書式ファイルがオープンできません\n");
return ERR;
}
line = 0;
err = 0;
while (fgets(buf, 256, fp) != NULL) {
line++;
buf[strlen(buf) - 1] = '\0';
disp = TRUE;
p = skipsp(buf);
if (*p == '\0' || *p == ';')
continue;
if (*p == '!') {
disp = FALSE;
p++;
}
p = skipsp(p);
lp = get_label(p);
if (lp->id == LBL_ERROR) {
sprintf(tmp,
"ERR: line %d: 書式項目名が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
while (*p && (isupper(*p) || isdigit(*p)))
p++;
p = skipsp(p);
if (*p == '=')
p++;
p = skipsp(p);
if (*p != '"') {
sprintf(tmp,
"ERR: line %d: 書式文字列が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
p++;
q = tmp;
while (*p && *p != '"') {
if (*p == '\\') {
p = escchar(p, &c);
if (c == '\\' || c == '<' || c == '>')
*q++ = '\\';
*q++ = c;
continue;
}
if (SJIS1(*p)) {
*q++ = *p++;
*q++ = *p++;
continue;
}
if (*p == '<' || *p == '>' || *p == '#')
*q++ = '\\';
*q++ = *p++;
}
if (*p != '"') {
sprintf(tmp,
"ERR: line %d: 書式文字列が正しくありません\n", line);
outstr(tmp);
err++;
continue;
}
*q = '\0';
if ((q = strpool(tmp)) == NULL) {
outstr("ERR: メモリーが足りません\n");
err++;
continue;
}
lp->leader = q;
lp->disp = disp;
}
fclose(fp);
if (err)
return ERR;
return OK;
}
/*
* suppress - 文字列で指定された特定項目の表示を抑制する
*/
int
suppress(str)
uchr *str;
{
if (str == NULL)
return OK;
if (!strcmp(str, "a"))
str = "teio";
while (*str) {
switch (*str) {
case 't':
get_label("TR")->disp = FALSE;
get_label("TRSUB")->disp = FALSE;
break;
case 'e':
get_label("EX")->disp = FALSE;
get_label("EXSUB")->disp = FALSE;
get_label("ZEX")->disp = FALSE;
break;
case 'i':
get_label("ID")->disp = FALSE;
get_label("IDSUB")->disp = FALSE;
get_label("ZID")->disp = FALSE;
break;
case 'o':
get_label("OT")->disp = FALSE;
get_label("OTSUB")->disp = FALSE;
break;
default:
return ERR;
}
str++;
}
return OK;
}
/* -------------------- 本文表示 -------------------- */
#define MAIN_DAT "main.txt" /* 本文 */
#define REV_LF 0xf5 /* 0x0a(LF)のビット反転 */
#define LBUFSIZ 4096 /* 行バッファーのサイズ */
/* 現バージョンのmain.datの最大 */
/* 行長は2389だが余裕をみておく */
/*
* 発音記号列は「{;」と「2}」で囲まれる(VEGA対応仕様)
*/
#define BP_LEADER '{' /* csrd側点字発音記号列開始 */
#define BP_START ';' /* 点字発音記号列開始 */
#define BP_END '2' /* 点字発音記号列終了 */
#define BP_TRAILER '}' /* csrd側点字発音記号列終了 */
/*
* BPTBL.gcのマスク
*/
#define CHMASK 0x00ff /* 文字コード */
#define GRMASK 0x1f00 /* フォントグループ */
#define ITMASK 0x8000 /* イタリック */
#define GRNMASK 0x0f00 /* フォントグループ番号 */
#define GRUNDEF 0x1000 /* フォントグループ未定義 */
#define GNUM(g) (((g) == 0x0900)? 99: ((g) >> 8))
typedef struct _bptbl_t {
unt gc; /* フォントグループ+文字コード */
uchr bps[4]; /* 点字発音記号列 */
} BPTBL;
/*
* 点字発音記号列表
*/
BPTBL bptbl[] = {
{ 'a', "A" }, /* a */
{ 'b', "B" }, /* b */
{ 'd', "D" }, /* d */
{ 'e', "E" }, /* e */
{ 'f', "F" }, /* f */
{ 'g', "G" }, /* g */
{ 'h', "H" }, /* h */
{ 'i', "I" }, /* i */
{ 'j', "J" }, /* j */
{ 'k', "K" }, /* k */
{ 'l', "L" }, /* l */
{ 'm', "M" }, /* m */
{ 'n', "N" }, /* n */
{ 'o', "O" }, /* o */
{ 'p', "P" }, /* p */
{ 'r', "R" }, /* r */
{ 's', "S" }, /* s */
{ 't', "T" }, /* t */
{ 'u', "U" }, /* u */
{ 'v', "V" }, /* v */
{ 'w', "W" }, /* w */
{ 'z', "Z" }, /* z */
{ 0x00e0, "^A" }, /* a` */
{ 0x00e1, "_A" }, /* a´ */
{ 0x00e6, "%" }, /* aeの合字 */
{ 0x00e8, "^E" }, /* e` */
{ 0x00e9, "_E" }, /* e´ */
{ 0x00ec, "^I" }, /* i` */
{ 0x00ed, "_I" }, /* i´ */
{ 0x00f0, "\\]" }, /* theのth */
{ 0x00f2, "^O" }, /* o` */
{ 0x00f3, "_O" }, /* o´ */
{ 0x00f9, "^U" }, /* u` */
{ 0x00fa, "_U" }, /* u´ */
{ 0x0141, "*" }, /* とさかのないa */
{ 0x0142, "\\<" }, /* 左の開いたo */
{ 0x0143, "_+" }, /* 横棒のないAに´ */
{ 0x014a, "_%" }, /* aeの合字に´ */
{ 0x014b, "^%" }, /* aeの合字に` */
{ 0x014c, "_5" }, /* あいまい母音に´ */
{ 0x014d, "^5" }, /* あいまい母音に` */
{ 0x014e, "_*" }, /* とさかのないaに´ */
{ 0x014f, "^*" }, /* とさかのないaに` */
{ 0x0150, ":" }, /* sheのsh */
{ 0x0151, "_\\<" }, /* 左の開いたoに´ */
{ 0x0152, "^\\<" }, /* 左の開いたoに` */
{ 0x0153, "_\\>" }, /* 丸いEに´ */
{ 0x0154, "^\\>" }, /* 丸いEに` */
{ 0x016a, "?" }, /* throughのth */
{ 0x0173, "!" }, /* 柔らかいg */
{ 0x0176, "$" }, /* singのng */
{ 0x02e1, "^+" }, /* 横棒のないAに` */
{ 0x03b9, "5" }, /* あいまい母音 */
{ 0x0477, "3" } /* 伸ばす音 */
};
#define NBPS (sizeof(bptbl) / sizeof(bptbl[0]))
int do_braille = FALSE; /* 点字発音記号変換を行うか? */
int nobracket = FALSE; /* 元の発音囲み[]を削除するか? */
int firstidiom; /* その品詞の最初の成句 */
int have_en; /* 見出し単語表示直後(無改行時) */
uchr line[LBUFSIZ]; /* 1行データ表示用作業領域 */
uchr *bpstr();
uchr *bp_transfer();
BFILE *dic_open();
int dgetline();
int showline();
int show_data();
int show_idiom();
int show_header();
int show_version();
/*
* bpstr - 文字に対応する点字発音記号列を返す
*/
uchr *
bpstr(gc)
unt gc;
{
int i;
gc &= (GRNMASK|CHMASK); /* GRUNDEFは<G0>と同じ */
for (i = 0; i < NBPS; i++) {
if (gc == bptbl[i].gc)
return bptbl[i].bps;
}
return NULL;
}
/*
* bp_transfer - 発音記号列の点訳を試みる
* 結果は渡されたバッファーを上書きする形で書き込む
* 変換結果文字列ではタグの開閉が狂っている可能性あり
*/
uchr *
bp_transfer(line)
uchr *line;
{
int level;
unt c, it, nit, g, ng;
uchr *p, *q;
unt *u, *uu, *upto;
static unt tmp[1024]; /* 変換元データは最大776バイト */
#ifdef DEBUG
if (debug)
printf("line in= \"%s\"\n", line);
#endif
/*
* tmpにフォント/イタリック情報付き文字列を組み立てる
*/
g = GRUNDEF;
it = 0;
p = line;
u = tmp;
while (*p) {
if (*p == '<') {
if (p[1] == 'G')
g = (p[2] - '0') << 8;
else if (p[1] == '/' && p[2] == 'G')
g = GRUNDEF;
else if (p[1] == 'I' && p[2] == '>')
it = ITMASK;
else if (p[1] == '/' && p[2] == 'I' && p[3] == '>')
it = 0;
else {
while (*p != '>')
*u++ = it | g | *p++;
*u++ = it | g | *p++;
continue;
}
while (*p++ != '>')
;
continue;
}
if (SJIS1(*p)) {
*u++ = it | g | *p++;
*u++ = it | g | *p++;
continue;
}
if (*p == '#' && p[3] == '#') {
*u++ = it | g | hexval(p + 1);
p += 4;
continue;
}
*u++ = it | g | *p++;
}
*u = '\0';
/*
* 発音記号列を解釈しながらlineを作り直す
*/
g = GRUNDEF;
it = 0;
level = 0;
p = line;
u = tmp;
upto = NULL;
while (*u) {
nit = *u & ITMASK;
if (nit != it) {
strcpy(p, nit? "<I>": "</I>");
while (*p++ != '>')
;
it = nit;
}
ng = *u & GRMASK;
if (ng != g) {
if (g != GRUNDEF) {
sprintf(p, "</G%d>", GNUM(g));
while (*p++ != '>')
;
}
if (ng != GRUNDEF) {
sprintf(p, "<G%d>", GNUM(ng));
while (*p++ != '>')
;
}
g = ng;
}
if ((*u & GRUNDEF) != 0 && SJIS1(*u & CHMASK)) {
*p++ = (*u++ & CHMASK);
*p++ = (*u++ & CHMASK);
continue;
}
if (upto && u < upto)
goto notrans;
switch (*u & (GRNMASK|CHMASK)) {
case '[':
if (!nobracket)
*p++ = *u & CHMASK;
level++;
break;
case ']':
if (!nobracket)
*p++ = *u & CHMASK;
if (level > 0)
level--;
break;
default:
if (level > 0 && bpstr(*u) != NULL) {
uu = u;
while (*uu && bpstr(*uu)) {
uu++;
}
c = *uu & (GRMASK|CHMASK);
if (c == ' ' || c == ';' || c == ',' ||
c == '-' || c == ']' || c == '|') {
if (g != GRUNDEF) {
sprintf(p, "</G%d>", GNUM(g));
while (*p++ != '>')
;
g = GRUNDEF;
}
*p++ = BP_LEADER;
*p++ = BP_START;
while (u < uu) {
q = bpstr(*u++);
while (*q)
*p++ = *q++;
}
*p++ = BP_END;
*p++ = BP_TRAILER;
u = uu;
continue;
}
upto = uu;
}
notrans:
ng = *u & GRMASK;
c = *u & CHMASK;
if (ng == GRUNDEF) {
*p++ = c;
} else if (ng != 0 ||
c >= 0x80 || c == '/' || c == ':' || c == '=') {
sprintf(p, "#%02x#", c);
p += 4;
} else {
*p++ = c;
}
}
u++;
}
*p = '\0';
if (it) {
strcpy(p, "</I>");
p += 4;
}
if (g != GRUNDEF)
sprintf(p, "</G%d>", GNUM(g));
#ifdef DEBUG
if (debug)
printf("line out=\"%s\"\n", line);
#endif
return line;
}
/*
* dic_open - 辞書データファイルをbopen()する
*/
BFILE *
dic_open(dicdir, dicfile)
uchr *dicdir, *dicfile;
{
BFILE *bfp;
uchr buf[256];
sprintf(buf, "%s/%s", dicdir, dicfile);
if ((bfp = bopen(buf)) == NULL) {
outstr("ERR: 辞書ファイルがオープンできません(");
outstr(buf);
outstr(")\n");
return NULL;
}
return bfp;
}
/*
* dgetline - 本文データを1行読み込み、改行を除いた長さを返す
*/
int
dgetline(bfp, buf)
BFILE *bfp;
uchr *buf;
{
int c;
uchr *p;
p = buf;
while ((c = bgetc(bfp)) != REV_LF)
*p++ = ~c;
*p = '\0';
return p - buf;
}
/*
* showline - 1行の本文データを表示する
*/
int
showline(line)
uchr *line;
{
uchr *p, *q;
LBLTBL *lp;
if (rawmode) {
outstr(line);
outstr("\n");
return OK;
}
lp = get_label(line);
if (lp->id == LBL_ERROR) {
#ifdef DEBUG
if (debug) {
outstr("ERR> ");
outstr(line);
outstr("\n");
}
#endif
return ERR;
}
if (!lp->disp) {
#ifdef DEBUG
if (debug) {
outstr("[");
outstr(lp->label);
outstr("*]\n");
}
#endif
return OK;
}
if (have_en && lp->id != LBL_PR) {
set_indent(0);
outstr("\n");
}
have_en = FALSE;
#ifdef DEBUG
if (debug) {
outstr("[");
outstr(lp->label);
outstr("] ");
}
#endif
p = skipeq(line);
if (*p == '\0')
return OK;
set_indent(nspaces(lp->leader));
outstr(lp->leader);
switch (lp->id) {
case LBL_DR:
q = p;
while (*q && *q != '|')
q++;
*q = 0;
outstr(p);
set_indent(0);
outstr("\n");
break;
case LBL_EN:
q = p;
while (*q && *q != '|')
q++;
*q = 0;
outstr(p);
have_en = TRUE;
break;
case LBL_ID:
if (firstidiom) {
outstr("\n【成句】\n");
firstidiom = FALSE;
}
goto normal;
case LBL_PS:
firstidiom = TRUE;
goto normal;
case LBL_TRSUB:
if (!strncmp(p, "【", 2)) {
p += 2;
while (*p && strncmp(p, "】", 2)) {
if (SJIS1(*p))
p++;
p++;
}
if (*p)
p += 2;
}
goto normal;
case LBL_PR:
case LBL_IF:
if (do_braille)
p = bp_transfer(p);
goto normal;
default:
normal:
outstr(p);
set_indent(0);
outstr("\n");
break;
}
return OK;
}
/*
* show_data - 本文データを表示する
*/
int
show_data(bfp, dpos, dlen)
BFILE *bfp;
long dpos, dlen;
{
int len;
if (bseek(bfp, dpos) == ERR)
return ERR;
firstidiom = TRUE;
while (dlen > 0L) {
len = dgetline(bfp, line);
showline(line);
dlen -= (long)(len + 1);
}
return OK;
}
/*
* show_idiom - 成句・用例の検索結果を表示する
*/
int
show_idiom(bfp, dpos)
BFILE *bfp;
long dpos;
{
int idiom;
long npos;
uchr *p, *q;
LBLTBL *lp;
uchr ps[128], tr[32];
/*
* あとで項目先頭まで遡る必要があるので
* 成句・用例を読み出せるだけの余裕を残して
* ファイル先頭寄りにいったんbseek()し
* それから本来の位置にbseek()する
* こうすることでread()の回数が減らせるはず
*/
npos = dpos - (BBUFSIZ - 512);
if (npos < 0L)
npos = 0;
if (bseek(bfp, npos) == ERR)
return ERR;
if (bseek(bfp, dpos) == ERR)
return ERR;
dgetline(bfp, line);
if (rawmode) {
outstr(line);
outstr("\n");
return OK;
}
if (*line == 'I' || *line == 'D') {
lp = get_label("ZID");
idiom = TRUE;
} else {
lp = get_label("ZEX");
idiom = FALSE;
}
if (!lp->disp)
return OK;
set_indent(nspaces(lp->leader));
outstr(lp->leader);
outstr(skipeq(line));
/*
* ファイル先頭に遡ってEN=を探し、
* そこから現在位置まで必要な情報を読んで表示する
*/
if (bseek(bfp, dpos) == ERR)
return ERR;
for (;;) {
if ((bgetcbw(bfp) ^ 0xff) == '=' &&
(bgetcbw(bfp) ^ 0xff) == 'N' &&
(bgetcbw(bfp) ^ 0xff) == 'E' &&
(bgetcbw(bfp) ^ 0xff) == '\n')
break;
}
bgetc(bfp);
outstr(" (");
dgetline(bfp, line);
p = q = skipeq(line);
while (*q && *q != '|')
q++;
*q = '\0';
outstr(p);
*ps = *tr = '\0';
while (btell(bfp) < dpos) {
dgetline(bfp, line);
if (!strncmp(line, "PS=", 3)) {
strcpy(ps, line + 3);
*tr = '\0';
continue;
}
if (!idiom && !strncmp(line, "TR", 2)) {
p = line + 2;
if (*p == 'S') /* TRSUB */
p += 3;
q = tr;
while (*p && *p != '=')
*q++ = *p++;
*q = '\0';
}
}
if (*ps) {
outstr(", ");
outstr(ps);
if (*tr)
outstr(tr);
if (idiom)
outstr(" 成句");
}
outstr(")");
set_indent(0);
outstr("\n");
return OK;
}
/*
* show_header - ENにある見出しデータを表示する
*/
int
show_header(bfp, dpos)
BFILE *bfp;
long dpos;
{
uchr *p, *q;
if (bseek(bfp, dpos) == ERR)
return ERR;
for (;;) {
if (dgetline(bfp, line) <= 0)
return ERR;
if (get_label(line)->id != LBL_EN)
continue;
p = skipeq(line);
q = p;
while (*q && *q != '|')
q++;
*q = 0;
outstr(p);
break;
}
return OK;
}
/*
* show_version - 辞書本文データのバージョンを表示する
*/
int
show_version(dicdir)
uchr *dicdir;
{
uchr *p;
BFILE *bfp;
if ((bfp = dic_open(dicdir, MAIN_DAT)) == NULL)
return ERR;
bseek(bfp, 0L);
while (dgetline(bfp, line) > 0 && !strncmp(line, "CMT=", 4)) {
if (rawmode) {
outstr(line);
outstr("\n");
continue;
}
p = line + 4;
if (!strncmp(p, "***", 3) ||
!strncmp(p, "TITLE:", 6) ||
!strncmp(p, "Based", 5) ||
!strncmp(p, "DATE:", 5)) {
outstr(p);
outstr("\n");
}
}
bclose(bfp);
return OK;
}
/* --------------- 成句・用例検索作業ファイル管理 --------------- */
#define TT0SIZ 1000 /* 検索結果格納配列の要素数 */
/*
* データ格納先
*/
#define TF_USE0 0 /* 配列0だけを使う */
#define TF_USE01 1 /* 配列0とファイル1を使う */
#define TF_USE1 2 /* ファイル1だけを使う */
#define TF_USE12 3 /* ファイル1とファイル2を使う */
typedef struct _tftbl {
long val; /* データ値 */
long num; /* データ数 */
int n0; /* tt0のデータ数 */
int n0x; /* tt0の用例開始位置/現在位置 */
long n1; /* tf1のデータ数 */
long n1x; /* tf1の現在位置 */
long n2; /* tf2のデータ数 */
long n2x; /* tf2の現在位置 */
long *tt0; /* 作業配列0 */
uchr *tf1; /* 作業ファイル1 */
uchr *tf2; /* 作業ファイル2 */
FILE *fp1; /* 作業ファイル1 FP */
FILE *fp2; /* 作業ファイル2 FP */
long v1; /* tf1の先読みデータ */
long v2; /* tf2の先読みデータ */
int use; /* データ格納先 */
int open; /* オープンされているか? */
} TFTBL;
TFTBL *tftbl; /* 作業ファイル管理表 */
int setuptmp();
void cleantmp();
int twopen();
int twrite();
int twclose();
int tropen();
long tread();
int trclose();
int tisopen();
void tswap();
void tfree();
int lcmp();
long getlval();
/*
* setuptmp - 作業ファイル管理表を準備する
*/
int
setuptmp()
{
int n, len;
uchr *tmpdir;
TFTBL *tp;
uchr tmp[128];
tftbl = (TFTBL *)malloc(sizeof(TFTBL) * 3);
if (tftbl == NULL)
return ERR;
len = 0;
if ((tmpdir = getenv("TMP")) != NULL ||
(tmpdir = getenv("TEMP")) != NULL) {
strcpy(tmp, tmpdir);
bsltosl(tmp);
len = strlen(tmp);
if (tmp[len-1] != '/')
tmp[len++] = '/';
}
tp = tftbl;
for (n = 0; n < 3; n++) {
sprintf(tmp+len, "cs%d1XXXXXX", n);
tp->tf1 = strpool(tmp);
sprintf(tmp+len, "cs%d2XXXXXX", n);
tp->tf2 = strpool(tmp);
if (tp->tf1 == NULL || tp->tf2 == NULL)
return ERR;
mktemp(tp->tf1);
mktemp(tp->tf2);
tp->fp1 = NULL;
tp->fp2 = NULL;
tp->open = FALSE;
tp++;
}
tp = tftbl;
for (n = 0; n < 3; n++) {
tp->tt0 = (long *)malloc(TT0SIZ * sizeof(long));
/*
* メモリーが不足ならtt0は使えなくてもよい
* エラーにはしない
*/
tp++;
}
#ifdef DEBUG
if (debug2) {
tp = tftbl;
for (n = 0; n < 3; n++) {
printf("tftbl[%d]:\n", n);
printf(" tt0=%s\n", tp->tt0? "(in use)": "(not in use)");
printf(" tf1=%s\n", tp->tf1);
printf(" tf2=%s\n", tp->tf2);
tp++;
}
}
#endif
return OK;
}
/*
* cleantmp - 残っているかもしれない作業ファイルを削除する
*/
void
cleantmp()
{
int n;
TFTBL *tp;
if (tftbl == NULL)
return;
tp = tftbl;
for (n = 0; n < 3; n++) {
if (tp->fp1 != NULL) {
fclose(tp->fp1);
tp->fp1 = NULL;
}
if (tp->fp2 != NULL) {
fclose(tp->fp2);
tp->fp2 = NULL;
}
unlink(tp->tf1);
unlink(tp->tf2);
tp->open = FALSE;
tp++;
}
}
/*
* twopen - 作業ファイルセットを書き出しオープンする
*/
int
twopen(tn)
int tn;
{
TFTBL *tp;
tp = &tftbl[tn];
tp->val = 0L;
tp->num = 0L;
tp->n0 = tp->n0x = 0;
tp->n1 = tp->n1x = 0L;
tp->n2 = tp->n2x = 0L;
tp->fp1 = tp->fp2 = NULL;
tp->use = (tp->tt0 != NULL)? TF_USE0: TF_USE1;
tp->open = TRUE;
return OK;
}
/*
* twrite - 作業ファイルセットに書き出す
*/
int
twrite(tn, val)
int tn;
long val;
{
int n;
TFTBL *tp;
tp = &tftbl[tn];
switch (tp->use) {
case TF_USE0:
if (tp->n0 >= TT0SIZ) {
/*
* 配列に収まらなかったのでtf1を使う
*/
if ((tp->fp1 = fopen(tp->tf1, "w")) == NULL)
goto openerr;
#ifdef DEBUG
if (debug2) {
printf("twrite(%d): open tf1(%s), num=%ld, val=%07lx\n",
tn, tp->tf1, tp->num, val);
}
#endif
for (n = tp->n0x; n < TT0SIZ; n++) {
if (fprintf(tp->fp1, "%07lx\n", tp->tt0[n]) == EOF)
goto writeerr;
}
tp->n0 = tp->n0x;
tp->n1 = (long)(TT0SIZ - tp->n0x);
if (tp->n0x > 0) {
/*
* 配列中に成句と用例の境界があった
* 成句は残して用例だけtf1に移動された
* あとでtt0をソートする必要はない(n0x=0)
*/
tp->n0x = 0;
tp->use = TF_USE01;
goto use01;
}
/*
* 全体がtf1に移動された
*/
tp->use = TF_USE1;
goto use1;
}
if (val < tp->val) {
/*
* 成句と用例の境界が来た
*/
tp->n0x = tp->n0;
}
tp->tt0[tp->n0++] = val;
break;
case TF_USE01:
use01:
if (val < tp->val)
goto fmterr;
goto use1write;
case TF_USE1:
use1:
if (val < tp->val) {
/*
* 成句と用例の境界が来た
* 以後はtf2を使う
*/
if ((tp->fp2 = fopen(tp->tf2, "w")) == NULL)
goto openerr;
#ifdef DEBUG
if (debug2) {
printf("twrite(%d): open tf2(%s), num=%ld, val=%07lx\n",
tn, tp->tf1, tp->num, val);
}
#endif
tp->use = TF_USE12;
goto use12;
}
use1write:
if (fprintf(tp->fp1, "%07lx\n", val) == EOF)
goto writeerr;
tp->n1++;
break;
case TF_USE12:
if (val < tp->val)
goto fmterr;
use12:
if (fprintf(tp->fp2, "%07lx\n", val) == EOF)
return ERR;
tp->n2++;
break;
}
tp->val = val;
tp->num++;
return OK;
openerr:
outstr("ERR: 作業用ファイルが新規作成できません\n");
return ERR;
writeerr:
outstr("ERR: ディスクがいっぱいです\n");
return ERR;
fmterr:
outstr("PANIC: 成句・用例インデックスが予期しない構造です\n");
#ifdef DEBUG
if (debug2) {
printf("num=%ld, cur=%lx, prev=%lx\n", tp->num, val, tp->val);
}
#endif
return ERR;
}
/*
* twclose - 作業ファイルセットをクローズする
*/
int
twclose(tn)
int tn;
{
TFTBL *tp;
tp = &tftbl[tn];
#ifdef DEBUG
if (debug2) {
printf("twclose(%d): n0=%d, n1=%ld, n2=%ld\n",
tn, tp->n0, tp->n1, tp->n2);
}
#endif
switch (tp->use) {
case TF_USE0:
if (tp->n0x > 0) {
/*
* tt0の中に成句・用例の境界がある
* tt0をソートする必要がある
*/
qsort((uchr *)tp->tt0, (size_t)tp->n0, sizeof(long), lcmp);
}
break;
case TF_USE12:
/*
* tf1に成句、tf2に用例がある
*/
if (fclose(tp->fp2) == EOF)
goto closeerr;
tp->fp2 = NULL;
/* fall thru ... */
case TF_USE01:
/*
* tt0に成句、tf1に用例がある
*/
/* fall thru ... */
case TF_USE1:
/*
* tf1の中に成句と用例のいずれかまたはその両方がある
* 値は単調増加している
*/
if (fclose(tp->fp1) == EOF)
goto closeerr;
tp->fp1 = NULL;
break;
}
tp->open = FALSE;
return OK;
closeerr:
outstr("ERR: ディスクがいっぱいです\n");
return ERR;
}
/*
* tropen - 作業ファイルセットを読み込みオープンする
*/
int
tropen(tn)
int tn;
{
TFTBL *tp;
tp = &tftbl[tn];
switch (tp->use) {
case TF_USE0:
tp->n0x = 0;
break;
case TF_USE01:
tp->n0x = 0;
goto open1;
case TF_USE12:
if ((tp->fp2 = fopen(tp->tf2, "r")) == NULL)
goto openerr;
tp->v2 = getlval(tp->fp2);
tp->n2x = 0L;
/* fall thru ... */
case TF_USE1:
open1:
if ((tp->fp1 = fopen(tp->tf1, "r")) == NULL)
goto openerr;
tp->v1 = getlval(tp->fp1);
tp->n1x = 0L;
break;
}
tp->open = TRUE;
return OK;
openerr:
outstr("ERR: 作業用ファイルがオープンできません\n");
return ERR;
}
/*
* tread - 作業ファイルセットから読み込む
*/
long
tread(tn)
int tn;
{
long v;
TFTBL *tp;
tp = &tftbl[tn];
switch (tp->use) {
case TF_USE0:
if (tp->n0x >= tp->n0)
return EOF;
v = tp->tt0[tp->n0x++];
break;
case TF_USE01:
if (tp->n0x >= tp->n0) {
if (tp->n1x >= tp->n1) {
return EOF;
} else {
v = tp->v1;
tp->v1 = getlval(tp->fp1);
tp->n1x++;
}
} else {
if (tp->n1x >= tp->n1) {
v = tp->tt0[tp->n0x++];
} else {
if (tp->tt0[tp->n0x] < tp->v1) {
v = tp->tt0[tp->n0x++];
} else {
v = tp->v1;
tp->v1 = getlval(tp->fp1);
tp->n1x++;
}
}
}
break;
case TF_USE1:
if (tp->n1x >= tp->n1)
return EOF;
v = tp->v1;
tp->v1 = getlval(tp->fp1);
tp->n1x++;
break;
case TF_USE12:
if (tp->n1x >= tp->n1) {
if (tp->n2x >= tp->n2) {
return EOF;
} else {
v = tp->v2;
tp->v2 = getlval(tp->fp2);
tp->n2x++;
}
} else {
if (tp->n2x >= tp->n2) {
v = tp->v1;
tp->v1 = getlval(tp->fp1);
tp->n1x++;
} else {
if (tp->v1 < tp->v2) {
v = tp->v1;
tp->v1 = getlval(tp->fp1);
tp->n1x++;
} else {
v = tp->v2;
tp->v2 = getlval(tp->fp2);
tp->n2x++;
}
}
}
break;
}
return v;
}
/*
* trclose - 作業ファイルセットをクローズする
*/
int
trclose(tn)
int tn;
{
TFTBL *tp;
tp = &tftbl[tn];
switch (tp->use) {
case TF_USE0:
break;
case TF_USE12:
fclose(tp->fp2);
tp->fp2 = NULL;
/* fall thru ... */
case TF_USE01:
case TF_USE1:
fclose(tp->fp1);
tp->fp1 = NULL;
break;
}
tp->open = FALSE;
return OK;
}
/*
* tisopen - 作業ファイルセットはオープンされているか?
*/
int
tisopen(tn)
int tn;
{
return tftbl[tn].open;
}
/*
* tswap - TFTBLを交換する
*/
void
tswap(tn0, tn1)
int tn0, tn1;
{
TFTBL tftmp;
tftmp = tftbl[tn0];
tftbl[tn0] = tftbl[tn1];
tftbl[tn1] = tftmp;
}
/*
* tfree - tt0を解放する
*/
void
tfree(tn)
int tn;
{
TFTBL *tp;
if (tftbl == NULL)
return;
tp = &tftbl[tn];
if (tp->tt0) {
free((char *)tp->tt0);
tp->tt0 = NULL;
}
}
/*
* lcmp - long値どうしの比較(qsort用)
*/
int
lcmp(p1, p2)
long *p1, *p2;
{
if (*p1 < *p2)
return -1;
if (*p1 > *p2)
return 1;
return 0;
}
/*
* getlval - ファイルから1行の16進文字列を読んでlongとして返す
*/
long
getlval(fp)
FILE *fp;
{
uchr tmp[16];
long l;
if (fgets(tmp, 16, fp) == NULL)
return (long)EOF;
sscanf(tmp, "%lx", &l);
return l;
}
/* -------------------- 検索 -------------------- */
#define EN_SRCH 0 /* 英単語検索 */
#define TR_SRCH 1 /* 訳語検索 */
#define ID_SRCH 2 /* 成句・用例検索 */
#define X_MATCH 0 /* 完全一致検索 */
#define F_MATCH 1 /* 前方一致検索 */
#define R_MATCH 2 /* 後方一致検索 */
#define W_MATCH 3 /* ワイルドカード検索 */
#define EN_F_IDX "enf.idx" /* 英単語前方一致インデックス */
#define EN_R_IDX "enr.idx" /* 英単語後方一致インデックス */
#define TR_F_IDX "trf.idx" /* 訳語前方一致インデックス */
#define TR_R_IDX "trr.idx" /* 訳語後方一致インデックス */
#define EN_LIST "en.dat" /* 英単語リスト */
#define TR_LIST "tr.dat" /* 訳語リスト */
#define ID_IDX "id.idx" /* 成句・用例インデックス */
#define ID_LIST "id.dat" /* 成句・用例リスト */
#define EN_M_LIST "miden.txt" /* 英単語中間一致リスト */
#define TR_M_LIST "midtr.txt" /* 訳語中間一致リスト */
#define INODETOP 0x00000100L /* インデックスの先頭ノード位置 */
#define LENTTOP 0x00000100L /* リストエントリーの先頭位置 */
/*
* インデックスエントリー
*/
typedef struct _ient {
uchr lstpos[4]; /* リストファイル中の位置 */
uchr next[4]; /* 下位ノードのノード番号 */
} IENT;
/*
* インデックスノード
*/
typedef struct _inode {
uchr pageno[4]; /* 不明 */
uchr last[4]; /* ノード中の最終エントリー番号 */
IENT ent[7]; /* ノード中のエントリー */
} INODE;
/*
* リストエントリー
*/
typedef struct _lent {
long dpos; /* 本文データ位置 */
long dlen; /* 本文データサイズ */
uchr fkey[128]; /* 前方一致キー */
uchr rkey[128]; /* 後方一致キー */
uchr kstr[256]; /* 見出し文字列 */
} LENT;
/*
* 成句・用例リストエントリー
*/
typedef struct _ilent {
unt entid; /* 順序番号 */
unt nent; /* 同一単語個数??? */
long dpos; /* 本文データ位置 */
uchr idkey[24]; /* 構成単語文字列(最大17文字) */
} ILENT;
int stype = EN_SRCH; /* 検索種別(英単語/訳語/成句) */
int mtype = X_MATCH; /* マッチ(完全/前方/後方/中間) */
uchr *idxfile = NULL; /* 検索用インデックスファイル */
uchr *lstfile = NULL; /* 検索用リストファイル */
INODE inode; /* 作業用 */
LENT lent; /* 作業用 */
ILENT ilent; /* 作業用 */
long val();
uchr *fmtkstr();
void getlistkey();
int getfirstent();
void getlistent();
int index_search();
void getilistent();
int idiom_search();
uchr *mgetent();
int match();
int wild_search();
uchr *getword();
int search();
/*
* val - 文字列中の4バイト値をlongに変換
*/
long
val(str)
register uchr *str;
{
return ((long)str[3] << 24) +
((long)str[2] << 16) +
((long)str[1] << 8) +
(long)str[0];
}
/*
* fmtkstr - 見出し文字列中の「@」を改行に変換する
*/
uchr *
fmtkstr(kstr)
uchr *kstr;
{
int in;
uchr *p, *q;
static uchr knew[256];
in = FALSE;
p = kstr;
q = knew;
while (*p) {
if (*p == '<') {
if (!strncmp(p, "<G99>", 5))
in = TRUE;
else if (!strncmp(p, "</G99>", 6))
in = FALSE;
while (*p != '>')
*q++ = *p++;
*q++ = *p++;
continue;
}
if (!in && *p == '@') {
while (*p == '@')
p++;
*q++ = '\n';
continue;
}
*q++ = *p++;
}
if (q > knew && q[-1] == '\n')
q--;
*q = '\0';
return knew;
}
/*
* getlistkey - リストファイルから見出し文字列を取り出す
*/
void
getlistkey(lfp, buf, mtype)
BFILE *lfp;
uchr *buf;
int mtype;
{
int len;
uchr *p;
bgetc(lfp);
bgetc(lfp);
if (mtype == R_MATCH) {
len = bgetc(lfp);
while (len-- > 0)
bgetc(lfp);
bgetc(lfp);
bgetc(lfp);
}
len = bgetc(lfp);
p = buf;
while (len-- > 0)
*p++ = bgetc(lfp);
*p = '\0';
}
/*
* getfirstent - キーにマッチする最初のエントリーを探す
*/
int
getfirstent(ifp, lfp, word, ip, np)
BFILE *ifp, *lfp;
uchr *word;
INODE *ip;
int *np;
{
int i, n, last, len, cmp;
long ipos, lpos, nodeno;
uchr key[128];
#ifdef DEBUG
int first, level;
#endif
ipos = INODETOP;
#ifdef DEBUG
level = 0;
#endif
/*
* トップ〜中間段の処理
*/
for (;;) {
if (bseek(ifp, ipos) == ERR ||
bread(ifp, (uchr *)ip, sizeof(INODE)) < sizeof(INODE)) {
outstr("PANIC: インデックスファイルに不整合があります\n");
return ERR;
}
if (val(ip->ent[0].next) == 0L) {
/*
* 最終段→別の方法で処理する
*/
break;
}
#ifdef DEBUG
if (debug) {
printf("<level %d>\n", ++level);
printf("pageno=%08lx, last=%08lx\n",
val(ip->pageno), val(ip->last));
for (i = 0; i <= (int)val(ip->last); i++) {
lpos = val(ip->ent[i].lstpos);
printf("e[%d].lstpos=%08lx, e[%d].next=%08lx",
i, lpos, i, val(ip->ent[i].next));
if (lpos > 0L) {
bseek(lfp, lpos);
getlistkey(lfp, key, mtype);
printf(", key=[%s]", key);
}
printf("\n");
}
}
#endif
last = (int)val(ip->last);
for (i = 0; i < last; i++) {
lpos = val(ip->ent[i+1].lstpos);
if (bseek(lfp, lpos) == ERR) {
outstr("PANIC: リストファイルに不整合があります\n");
return ERR;
}
getlistkey(lfp, key, mtype);
#ifdef DEBUG
if (debug)
printf("i=%d, word=[%s], key=[%s]\n", i, word, key);
#endif
if (strcmp(word, key) <= 0)
break;
}
nodeno = val(ip->ent[i].next);
ipos = (nodeno - 1L) * sizeof(INODE) + INODETOP;
#ifdef DEBUG
if (debug)
printf("nodeno=%08lx, ipos=%08lx\n", nodeno, ipos);
#endif
}
/*
* 最終段の処理
*/
len = strlen(word);
last = (int)val(ip->last);
n = 0;
#ifdef DEBUG
first = TRUE;
#endif
for (;;) {
if (n > last) {
if (bread(ifp, (uchr *)ip, sizeof(INODE)) < sizeof(INODE) ||
val(ip->pageno) == 0L) {
/*
* インデックスの終端に達した
*/
return ERR;
}
last = (int)val(ip->last);
n = 0;
}
#ifdef DEBUG
if (debug && n == 0) {
if (first) {
printf("<last level>\n");
first = FALSE;
} else {
printf("<next node>\n");
}
printf("pageno=%08lx, last=%08lx\n",
val(ip->pageno), val(ip->last));
for (i = 0; i <= (int)val(ip->last); i++) {
lpos = val(ip->ent[i].lstpos);
bseek(lfp, lpos);
getlistkey(lfp, key, mtype);
printf("e[%d].lstpos=%08lx, key=[%s]\n", i, lpos, key);
}
}
#endif
lpos = val(ip->ent[n].lstpos);
if (bseek(lfp, lpos) == ERR) {
outstr("PANIC: リストファイルに不整合があります\n");
return ERR;
}
getlistkey(lfp, key, mtype);
cmp = strncmp(word, key, len);
if (cmp < 0)
return ERR;
if (cmp == 0) {
if (mtype == X_MATCH && strcmp(word, key) != 0)
return ERR;
*np = n;
return OK;
}
n++;
}
/* NOTREACHED */
}
/*
* getlistent - リストファイルから見出しデータを取り出す
*/
void
getlistent(lfp, lp)
BFILE *lfp;
LENT *lp;
{
int i, len;
uchr *p;
bgetc(lfp);
bgetc(lfp);
len = bgetc(lfp);
p = lp->fkey;
while (len-- > 0)
*p++ = bgetc(lfp);
*p = '\0';
bgetc(lfp);
bgetc(lfp);
len = bgetc(lfp);
p = lp->rkey;
while (len-- > 0)
*p++ = bgetc(lfp);
*p = '\0';
bgetc(lfp);
bgetc(lfp);
lp->dpos = 0L;
for (i = 0; i < 32; i += 8)
lp->dpos |= ((long)bgetc(lfp) << i);
bgetc(lfp);
bgetc(lfp);
lp->dlen = 0L;
for (i = 0; i < 32; i += 8)
lp->dlen |= ((long)bgetc(lfp) << i);
for (i = 0; i < 8; i++)
bgetc(lfp);
len = bgetc(lfp);
p = lp->kstr;
while (len-- > 0)
*p++ = bgetc(lfp);
*p = '\0';
}
/*
* index_search - 完全/前方/後方一致でインデックス検索を行う
*/
int
index_search(dicdir, showall, word)
uchr *dicdir, *word;
int showall;
{
int n, last, len, cmp, ret;
long lpos;
uchr *keyp;
BFILE *ifp, *lfp, *bfp;
#ifdef DEBUG
int i;
uchr key[128];
#endif
ret = OK;
ifp = lfp = bfp = NULL;
if ((ifp = dic_open(dicdir, idxfile)) == NULL ||
(lfp = dic_open(dicdir, lstfile)) == NULL)
goto err;
if (getfirstent(ifp, lfp, word, &inode, &n) == ERR)
goto err;
keyp = (mtype == R_MATCH)? lent.rkey: lent.fkey;
len = strlen(word);
last = (int)val(inode.last);
for (;;) {
if (n > last) {
if (bread(ifp, (uchr *)&inode, sizeof(INODE)) < sizeof(INODE) ||
val(inode.pageno) == 0L) {
/*
* インデックスの終端に達した
*/
break;
}
last = (int)val(inode.last);
n = 0;
}
#ifdef DEBUG
if (debug && n == 0) {
printf("<next node>\n");
printf("pageno=%08lx, last=%08lx\n",
val(inode.pageno), val(inode.last));
for (i = 0; i <= (int)val(inode.last); i++) {
lpos = val(inode.ent[i].lstpos);
bseek(lfp, lpos);
getlistkey(lfp, key, mtype);
printf("e[%d].lstpos=%08lx, key=[%s]\n", i, lpos, key);
}
}
#endif
lpos = val(inode.ent[n].lstpos);
if (bseek(lfp, lpos) == ERR) {
outstr("PANIC: リストファイルに不整合があります\n");
goto err;
}
getlistent(lfp, &lent);
cmp = strncmp(word, keyp, len);
if (cmp < 0)
break;
if (cmp > 0) {
n++;
continue;
}
if (showall || mtype == X_MATCH) {
if (mtype == X_MATCH && strcmp(word, keyp) != 0)
break;
if (bfp == NULL) {
if ((bfp = dic_open(dicdir, MAIN_DAT)) == NULL)
goto err;
} else {
outstr("\n");
}
#ifdef DEBUG
if (debug)
printf("show_dat: key=[%s], dpos=%lx, dlen=%lx\n",
lent.fkey, lent.dpos, lent.dlen);
#endif
if (show_data(bfp, lent.dpos, lent.dlen) == ERR)
goto err;
} else {
outstr(fmtkstr(lent.kstr));
if (stype == TR_SRCH) {
outstr(" [");
outstr(lent.fkey);
outstr("]");
}
outstr("\n");
}
n++;
}
goto done;
err:
ret = ERR;
done:
if (ifp != NULL)
bclose(ifp);
if (lfp != NULL)
bclose(lfp);
if (bfp != NULL)
bclose(bfp);
return ret;
}
/*
* getilistent - 成句・用例リストファイルから構成単語データを取り出す
*/
void
getilistent(lfp, ip)
BFILE *lfp;
ILENT *ip;
{
int i, len;
uchr *p;
ip->entid = bgetc(lfp);
ip->entid += (bgetc(lfp) << 8);
len = bgetc(lfp);
p = ip->idkey;
while (len-- > 0)
*p++ = bgetc(lfp);
*p = '\0';
bgetc(lfp);
bgetc(lfp);
ip->dpos = 0L;
for (i = 0; i < 32; i += 8)
ip->dpos |= ((long)bgetc(lfp) << i);
bgetc(lfp);
bgetc(lfp);
ip->nent = bgetc(lfp);
ip->nent += (bgetc(lfp) << 8);
for (i = 0; i < 4; i++)
bgetc(lfp);
}
/*
* idiom_search - 成句・用例検索を行う
*/
int
idiom_search(dicdir, ac, av)
uchr *dicdir;
int ac;
uchr **av;
{
int i, n, last, cmp, ret, nomore;
long lpos, odpos;
long l0, l1, num0, num1, num2, n0, n1;
uchr *word;
BFILE *ifp, *lfp, *bfp;
#ifdef DEBUG
uchr key[128];
#endif
/*
* 前準備
*/
for (i = 0; i < ac; i++) {
/*
* 検索指定文字列が正常かどうか
* 先にチェックだけしておく
*/
if (getword(tosjis(av[i])) == NULL)
return ERR;
}
ret = OK;
ifp = lfp = bfp = NULL;
if ((ifp = dic_open(dicdir, idxfile)) == NULL ||
(lfp = dic_open(dicdir, lstfile)) == NULL ||
(bfp = dic_open(dicdir, MAIN_DAT)) == NULL)
goto err;
if (setuptmp() == ERR) {
outstr("ERR: メモリーが足りません\n");
goto err;
}
/*
* 最初の単語を検索する
* 結果は作業セット0に書き出す
* ただし最後の単語ならそのまま表示して終わり
*/
word = getword(tosjis(*av));
if (getfirstent(ifp, lfp, word, &inode, &n) == ERR)
goto err;
#ifdef DEBUG
if (debug2)
printf("search1 start: word=%s\n", word);
#endif
nomore = (ac == 1);
num0 = 0L;
odpos = 0L;
last = (int)val(inode.last);
for (;;) {
if (n > last) {
if (bread(ifp, (uchr *)&inode, sizeof(INODE)) < sizeof(INODE) ||
val(inode.pageno) == 0L)
break;
last = (int)val(inode.last);
n = 0;
}
#ifdef DEBUG
if (debug && n == 0) {
printf("<next node>\n");
printf("pageno=%08lx, last=%08lx\n",
val(inode.pageno), val(inode.last));
for (i = 0; i <= (int)val(inode.last); i++) {
lpos = val(inode.ent[i].lstpos);
bseek(lfp, lpos);
getlistkey(lfp, key, X_MATCH);
printf("e[%d].lstpos=%08lx, key=[%s]\n", i, lpos, key);
}
}
#endif
lpos = val(inode.ent[n].lstpos);
if (bseek(lfp, lpos) == ERR) {
outstr("PANIC: リストファイルに不整合があります\n");
goto err;
}
getilistent(lfp, &ilent);
cmp = strcmp(word, ilent.idkey);
if (cmp < 0)
break;
if (cmp > 0) {
n++;
continue;
}
#ifdef DEBUG
if (debug)
printf("idkey=[%s], entid=%04x, nent=%04x, dpos=%08lx\n",
ilent.idkey, ilent.entid, ilent.nent, ilent.dpos);
#endif
if (ilent.dpos == odpos) {
n++;
continue;
}
odpos = ilent.dpos;
if (nomore) {
/*
* 検索指定文字列が1つだけだった
*/
#ifdef DEBUG
if (debug2) {
printf("dpos=%08lx\n", ilent.dpos);
num0++;
n++;
continue;
}
#endif
if (show_idiom(bfp, ilent.dpos) == ERR)
goto err;
num0++;
n++;
continue;
}
/*
* 検索結果を記録する
*/
if (!tisopen(0) && twopen(0) == ERR ||
twrite(0, ilent.dpos) == ERR)
goto err;
num0++;
n++;
}
#ifdef DEBUG
if (debug2)
printf("num0=%ld\n", num0);
#endif
if (tisopen(0) && twclose(0) == ERR)
goto err;
if (nomore || num0 == 0L) {
/*
* 最後の単語か、結果が0件だった
*/
goto done;
}
ac--, av++;
/*
* 残りの単語を検索する
* 結果は作業セット1に書き出す
* 作業セット0と作業セット1を突き合わせて
* 両方に存在するものだけを作業セット2に書き出す
* あるいは最後の単語なら結果を表示する
*/
while (ac > 0) {
word = getword(tosjis(*av));
if (getfirstent(ifp, lfp, word, &inode, &n) == ERR)
goto err;
#ifdef DEBUG
if (debug2)
printf("search2 start: word=%s\n", word);
#endif
nomore = (ac == 1);
num1 = 0L;
odpos = 0L;
last = (int)val(inode.last);
for (;;) {
if (n > last) {
if (bread(ifp, (uchr *)&inode, sizeof(INODE)) < sizeof(INODE) ||
val(inode.pageno) == 0L)
break;
last = (int)val(inode.last);
n = 0;
}
#ifdef DEBUG
if (debug && n == 0) {
printf("<next node>\n");
printf("pageno=%08lx, last=%08lx\n",
val(inode.pageno), val(inode.last));
for (i = 0; i <= (int)val(inode.last); i++) {
lpos = val(inode.ent[i].lstpos);
bseek(lfp, lpos);
getlistkey(lfp, key, X_MATCH);
printf("e[%d].lstpos=%08lx, key=[%s]\n", i, lpos, key);
}
}
#endif
lpos = val(inode.ent[n].lstpos);
if (bseek(lfp, lpos) == ERR) {
outstr("PANIC: リストファイルに不整合があります\n");
goto err;
}
getilistent(lfp, &ilent);
cmp = strcmp(word, ilent.idkey);
if (cmp < 0)
break;
if (cmp > 0) {
n++;
continue;
}
#ifdef DEBUG
if (debug)
printf("idkey=[%s], entid=%04x, nent=%04x, dpos=%08lx\n",
ilent.idkey, ilent.entid, ilent.nent, ilent.dpos);
#endif
if (ilent.dpos == odpos) {
n++;
continue;
}
odpos = ilent.dpos;
/*
* 検索結果を記録する
*/
if (!tisopen(1) && twopen(1) == ERR ||
twrite(1, ilent.dpos) == ERR)
goto err;
num1++;
n++;
}
#ifdef DEBUG
if (debug2)
printf("num1=%ld\n", num1);
#endif
if (tisopen(1) && twclose(1) == ERR)
goto err;
if (num1 == 0L) {
/*
* 結果が0件だった
*/
goto done;
}
/*
* 作業セット0と作業セット1を突き合わせて
* 両方に存在するものだけを作業セット2に書き出す
* その結果を新たな作業セット0とする
*/
if (tropen(0) == ERR || tropen(1) == ERR)
goto err;
#ifdef DEBUG
if (debug2) {
printf("compare start\n");
}
#endif
n0 = n1 = num2 = 0L;
l0 = tread(0);
l1 = tread(1);
for (;;) {
if (l0 < l1) {
if (++n0 >= num0)
break;
l0 = tread(0);
continue;
}
if (l1 < l0) {
if (++n1 >= num1)
break;
l1 = tread(1);
continue;
}
if (nomore) {
#ifdef DEBUG
if (debug2) {
printf("dpos=%08lx\n", l0);
goto next;
}
#endif
if (show_idiom(bfp, l0) == ERR)
goto err;
goto next;
}
/*
* 検索結果を記録する
*/
if (!tisopen(2) && twopen(2) == ERR ||
twrite(2, l0) == ERR)
goto err;
next:
if (++n0 >= num0)
break;
l0 = tread(0);
if (++n1 >= num1)
break;
l1 = tread(1);
num2++;
}
#ifdef DEBUG
if (debug2)
printf("num2=%ld\n", num2);
#endif
trclose(0);
trclose(1);
if (tisopen(2) && twclose(2) == ERR)
goto err;
if (num2 == 0L) {
/*
* 結果が0件だった
*/
goto done;
}
tswap(0, 2);
ac--, av++;
}
goto done;
err:
ret = ERR;
done:
tfree(0);
tfree(1);
tfree(2);
if (ifp != NULL)
bclose(ifp);
if (lfp != NULL)
bclose(lfp);
if (bfp != NULL)
bclose(bfp);
#ifdef DEBUG
if (debug2)
return ret;
#endif
cleantmp();
return ret;
}
/*
* mgetent - 中間一致リストを1行読み込む
*/
uchr *
mgetent(bfp, buf)
BFILE *bfp;
uchr *buf;
{
int c;
uchr *p;
if ((c = bgetc(bfp)) == EOF)
return NULL;
p = buf;
do {
*p++ = c;
} while ((c = bgetc(bfp)) != '\r');
*p = '\0';
return buf;
}
/*
* match - 文字列とパターンの照合を行う
*/
int
match(str, pat)
uchr *str, *pat;
{
unt c;
uchr *s, *p;
#ifdef DEBUG
if (debug2) {
printf("str=\"%s\", pat=\"%s\"\n", str, pat);
}
#endif
if (stype == EN_SRCH) {
/*
* 1バイト文字の照合
*/
while (*str) {
switch (*pat) {
case '?':
/*
* 任意の文字とマッチする
*/
break;
case '*':
/*
* strの残りを1文字ずつ減らしながら
* patの残りとマッチするかどうか調べる
*/
s = str;
do {
if (match(s, pat + 1))
return TRUE;
} while (*s++);
break;
case '[':
for (p = pat + 1; *p != ']'; p++) {
if (*str == *p)
break;
if (p[1] == '-') {
if (*str >= *p && *str <= p[2])
break;
p += 2;
}
}
if (*p == ']') {
/*
* マッチしなかった
*/
return FALSE;
}
while (*p != ']')
p++;
pat = p;
break;
case '\0':
/*
* パターンが先に尽きた
*/
return FALSE;
default:
if (*str != *pat) {
/*
* マッチしなかった
*/
return FALSE;
}
break;
}
str++;
pat++;
}
if (*pat == '\0') {
/*
* ファイル名とパターンが同時に尽きた
*/
return TRUE;
}
return FALSE;
}
/*
* 2バイト文字の照合
*/
while (*str) {
switch (*pat) {
case '?':
/*
* 任意の文字とマッチする
*/
str += 2;
pat++;
break;
case '*':
/*
* strの残りを1文字ずつ減らしながら
* patの残りとマッチするかどうか調べる
*/
s = str;
for (;;) {
if (match(s, pat + 1))
return TRUE;
if (*s == '\0')
break;
s += 2;
}
str += 2;
pat++;
break;
case '[':
p = pat + 1;
while (*p != ']') {
if (*str == *p && str[1] == p[1])
break;
if (p[2] == '-') {
c = (*str << 8 | str[1]);
if (c >= (p[0] << 8 | p[1]) &&
c <= (p[3] << 8 | p[4]))
break;
p += 3;
}
p += 2;
}
if (*p == ']') {
/*
* マッチしなかった
*/
return FALSE;
}
while (*p != ']') {
if (*p == '-') {
p++;
continue;
}
p += 2;
}
str += 2;
pat = p + 1;
break;
case '\0':
/*
* パターンが先に尽きた
*/
return FALSE;
default:
if (*str != *pat || str[1] != pat[1]) {
/*
* マッチしなかった
*/
return FALSE;
}
str += 2;
pat += 2;
break;
}
}
if (*pat == '\0') {
/*
* ファイル名とパターンが同時に尽きた
*/
return TRUE;
}
return FALSE;
}
/*
* wild_search - ワイルドカード検索を行う
*/
int
wild_search(dicdir, showall, pat)
uchr *dicdir, *pat;
int showall;
{
int ret, first;
long dpos, dlen, odpos;
uchr *p;
BFILE *lfp, *bfp;
uchr buf[256];
ret = OK;
lfp = bfp = NULL;
if ((lfp = dic_open(dicdir, lstfile)) == NULL ||
(bfp = dic_open(dicdir, MAIN_DAT)) == NULL)
goto err;
bseek(lfp, 0L);
first = TRUE;
odpos = 0L;
while (mgetent(lfp, buf) != NULL) {
p = buf;
while (*p && *p != '0')
p++;
*p = '\0';
if (!match(buf, pat))
continue;
sscanf(p+1, "%7lx%lx", &dpos, &dlen);
#ifdef DEBUG
if (debug)
printf("show_dat: key=[%s], dpos=%lx, dlen=%lx\n",
buf, dpos, dlen);
#endif
if (showall) {
if (first)
first = FALSE;
else
outstr("\n");
if (dpos == odpos)
continue;
if (show_data(bfp, dpos, dlen) == ERR)
goto err;
} else {
if (show_header(bfp, dpos) == ERR)
goto err;
if (stype == EN_SRCH)
lower(buf);
outstr(" [");
outstr(buf);
outstr("]\n");
}
}
goto done;
err:
ret = ERR;
done:
if (lfp != NULL)
bclose(lfp);
if (bfp != NULL)
bclose(bfp);
return ret;
}
/*
* getword - 検索指定文字列を受け取って検索単語その他の設定を行う
*/
uchr *
getword(str)
uchr *str;
{
int n, len, err;
int eng, knj, any, meta, bra;
uchr *s, *p, *q, ch;
static uchr buf[128];
len = strlen(str);
eng = knj = any = meta = 0;
err = 0;
bra = FALSE;
s = str;
while (*s) {
if (strchr("*?[]-", *s)) {
if (*s == '*' && (bra || s[1] == '*') ||
*s == '?' && bra ||
*s == '[' && (bra || s[1] == '-' || s[1] == ']') ||
*s == '-' && (!bra || s[1] == ']') ||
*s == ']' && !bra) {
err++;
break;
}
if (*s == '[')
bra = TRUE;
else if (*s == ']')
bra = FALSE;
else if (*s == '?')
any++;
s++;
meta++;
continue;
}
if (SJIS1(*s)) {
s += 2;
knj++;
continue;
}
s++;
eng++;
}
if (err || bra) {
outstr("ERR: ワイルドカード検索指定に誤りがあります\n");
return NULL;
}
if (knj > 0 && eng > 0) {
outstr("ERR: 検索単語に英語と日本語が混在しています\n");
return NULL;
}
if (knj == 0 && eng == 0 && any == 0) {
outstr("ERR: 検索単語が空です\n");
return NULL;
}
if (stype == ID_SRCH) {
if (knj) {
outstr("ERR: 成句・用例検索で日本語が指定されています\n");
return NULL;
}
if (mtype != X_MATCH) {
outstr("ERR: 成句・用例検索で不完全一致検索が指定されています\n");
return NULL;
}
}
if (meta == 0)
mtype = X_MATCH;
else if (meta == 1 && str[len-1] == '*')
mtype = F_MATCH;
else if (meta == 1 && *str == '*')
mtype = R_MATCH;
else
mtype = W_MATCH;
if (knj)
stype = TR_SRCH;
s = str;
p = buf;
if (mtype == F_MATCH || mtype == R_MATCH) {
len--;
if (mtype == R_MATCH)
s++;
}
n = len;
while (n > 0) {
if (SJIS1(*s)) {
*p++ = *s++;
*p++ = *s++;
n -= 2;
continue;
}
if (islower(*s)) {
*p++ = toupper(*s);
s++;
} else {
*p++ = *s++;
}
n--;
}
*p = '\0';
if (mtype == R_MATCH) {
/*
* 検索文字列を逆順にする
*/
p = buf;
while (*p) {
if (SJIS1(*p)) {
ch = *p;
*p = p[1];
p[1] = ch;
p++;
}
p++;
}
p = buf;
q = buf + len - 1;
while (p < q) {
ch = *p;
*p++ = *q;
*q-- = ch;
}
}
return buf;
}
/*
* search - 検索のメインルーチン
*/
int
search(dicdir, showall, ac, av)
uchr *dicdir;
int showall;
int ac;
uchr **av;
{
int ret;
uchr *word;
if ((word = getword(tosjis(*av))) == NULL)
return ERR;
switch (stype) {
case EN_SRCH:
switch (mtype) {
case X_MATCH:
case F_MATCH:
idxfile = EN_F_IDX;
lstfile = EN_LIST;
ret = index_search(dicdir, showall, word);
break;
case R_MATCH:
idxfile = EN_R_IDX;
lstfile = EN_LIST;
ret = index_search(dicdir, showall, word);
break;
case W_MATCH:
lstfile = EN_M_LIST;
ret = wild_search(dicdir, showall, word);
break;
}
break;
case TR_SRCH:
switch (mtype) {
case X_MATCH:
case F_MATCH:
idxfile = TR_F_IDX;
lstfile = TR_LIST;
ret = index_search(dicdir, showall, word);
break;
case R_MATCH:
idxfile = TR_R_IDX;
lstfile = TR_LIST;
ret = index_search(dicdir, showall, word);
break;
case W_MATCH:
lstfile = TR_M_LIST;
ret = wild_search(dicdir, showall, word);
break;
}
break;
case ID_SRCH:
idxfile = ID_IDX;
lstfile = ID_LIST;
ret = idiom_search(dicdir, ac, av);
break;
}
return ret;
}
/* -------------------- メイン -------------------- */
#define CSRD_ENV "CSRD" /* オプションを設定する環境変数 */
#define MINWIDTH 20 /* 出力行幅の下限 */
int showall = FALSE; /* 不完全一致でも項目表示するか?*/
int showver = FALSE; /* 辞書データバージョン表示 */
uchr *dicdir = NULL; /* 辞書ディレクトリー */
uchr *fmtfile = NULL; /* 表示書式ファイル */
uchr *gaifile = NULL; /* 外字代替表記ファイル */
uchr *supstr = NULL; /* 表示抑制項目 */
void usage();
int parse_opt();
#if defined(UNIX) && defined(RC_PATH)
int init_rcfile();
#endif
int init_env();
void onintr();
int main();
/*
* usage - 使用法を表示して終了する
*/
void
usage()
{
outstr("小学館ランダムハウス英語辞典検索ユーティリティー Ver.");
outstr(version);
outstr(" (");
outstr(date);
outstr(")\n Written by Junn Ohta (ohta@src.ricoh.co.jp),");
outstr(" Public Domain.\n\n使用法: ");
outstr(progname);
outstr(" [-d\\<辞書DIR\\>] [-f\\<書式ファイル\\>] [-g\\<外字ファイル\\>]\n");
outstr(" [-w\\<桁数\\>] [-s\\<非表示項目\\>] [-b[x]] [-a] [-v]");
#ifdef UNIX
outstr("\n [-c\\<コード\\>]");
#endif
outstr(" \\<検索指定\\>\n\n");
outstr("オプション: (環境変数");
outstr(CSRD_ENV);
outstr("で指定することもできます)\n");
outstr(" -d: 辞書ディレクトリー\n");
outstr(" -f: 表示書式ファイル\n");
outstr(" -g: 外字代替表記ファイル\n");
outstr(" -w: 出力行幅 (-w0:改行なし(標準))\n");
outstr(" -s: 特定項目を非表示にする\n");
outstr(" (-st:意味, -se:用例, -si:成句, -so:類語, -sa:すべて)\n");
outstr(" -b: 発音記号列を点訳する (-bx:[]を取り除く)\n");
outstr(" -a: 不完全一致でも項目内容を表示する\n");
outstr(" -v: 辞書データのバージョンを表示する\n");
#ifdef UNIX
outstr(" -c: 日本語コード (-cj:JIS, -ce:EUC(標準), -cs:シフトJIS)\n");
#endif
outstr("\n検索指定: (成句・用例検索以外では訳語からも検索できます)\n");
outstr(" 完全一致検索: \\<文字列\\> ワイルドカード検索: *?[]-を含む文字列\n");
outstr(" 前方一致検索: \\<文字列\\>* 成句・用例検索: -i \\<文字列\\> ...\n");
outstr(" 後方一致検索: *\\<文字列\\>\n");
exit(1);
}
/*
* parse_opt - 環境変数またはコマンド行引数で指定されたオプションを
* 解析して必要な設定を行う
*/
int
parse_opt(acp, avp)
int *acp;
uchr ***avp;
{
int n, ac;
uchr *s, **av;
ac = *acp;
av = *avp;
while (ac > 0 && **av == '-') {
s = *av + 1;
switch (*s++) {
case 'D':
case 'd':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
dicdir = strpool(s);
bsltosl(dicdir);
n = strlen(dicdir);
if (dicdir[n-1] == '/')
dicdir[n-1] = '\0';
break;
case 'F':
case 'f':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
fmtfile = strpool(s);
bsltosl(fmtfile);
break;
case 'G':
case 'g':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
gaifile = strpool(s);
bsltosl(gaifile);
break;
case 'A':
case 'a':
showall = TRUE;
break;
case 'W':
case 'w':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
if (!isdigit(*s))
return ERR;
width = atoi(s);
if (width != 0 && width < MINWIDTH)
width = MINWIDTH;
break;
case 'B':
case 'b':
do_braille = TRUE;
if (*s == 'x' || *s == 'X')
nobracket = TRUE;
else
nobracket = FALSE;
break;
#ifdef UNIX
case 'C':
case 'c':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
switch (*s) {
case 'J':
case 'j':
kcode = KC_JIS;
if (s[1] && s[2]) {
jiskanji = s[1];
jisalpha = s[2];
}
break;
case 'E':
case 'e':
kcode = KC_EUC;
break;
case 'S':
case 's':
kcode = KC_SJIS;
break;
default:
return ERR;
}
break;
#endif
case 'S':
case 's':
if (!*s) {
ac--, av++;
if (ac == 0 || **av == '-')
return ERR;
s = *av;
}
supstr = strpool(s);
break;
case 'I':
case 'i':
stype = ID_SRCH;
break;
case 'V':
case 'v':
showver = TRUE;
break;
case 'R':
case 'r':
rawmode = TRUE;
break;
#ifdef DEBUG
case 'Z':
case 'z':
if (*s == 'z' || *s == 'Z')
debug2 = TRUE;
else
debug = TRUE;
break;
#endif
default:
return ERR;
}
ac--, av++;
}
*acp = ac;
*avp = av;
return OK;
}
#if defined(UNIX) && defined(RC_PATH)
/*
* init_rcfile - ファイルで指定されたオプションを解釈する
* Contributed by 野首 貴嗣 (Nokubi Takatsugu)
*/
int
init_rcfile()
{
int ec;
uchr *env, *s, **ev, **pp;
FILE *fp;
struct stat st;
if (stat(RC_PATH, &st) < 0)
return OK;
if ((fp = fopen(RC_PATH, "r")) == NULL)
return ERR;
env = (uchr *)malloc(st.st_size + 1);
if (env == NULL)
return ERR;
if (fread(env, st.st_size, 1, fp) < 1)
return ERR;
*(env + st.st_size - 1) = '\0';
fclose(fp);
ec = 1;
for (s = env; *s; s++) {
if (*s == ' ' || *s == '\t')
ec++;
}
ev = (uchr **)malloc(sizeof(uchr *) * (ec + 1));
pp = ev;
while ((s = strtok(env, " \t")) != NULL) {
*pp++ = s;
env = NULL;
}
*pp = NULL;
pp = ev;
if (parse_opt(&ec, &ev) != OK) {
outstr("ERR: ファイル ");
outstr(RC_PATH);
outstr(" に誤りがあります\n");
return ERR;
}
free((char *)pp);
free((char *)env);
return OK;
}
#endif
/*
* init_env - 環境変数CSRDで指定されたオプションを解釈する
*/
int
init_env()
{
int ec;
uchr *env, *s, **ev, **pp;
if ((env = getenv(CSRD_ENV)) == NULL)
return OK;
ec = 1;
for (s = env; *s; s++) {
if (*s == ' ' || *s == '\t')
ec++;
}
ev = (uchr **)malloc(sizeof(uchr *) * (ec + 1));
pp = ev;
while ((s = strtok(env, " \t")) != NULL) {
*pp++ = s;
env = NULL;
}
*pp = NULL;
pp = ev;
if (parse_opt(&ec, &ev) != OK) {
outstr("ERR: 環境変数 ");
outstr(CSRD_ENV);
outstr(" に誤りがあります\n");
return ERR;
}
free((char *)pp);
return OK;
}
/*
* onintr - 割り込み時の終了処理
*/
void
onintr()
{
outchar(0); /* JIS漢字モードならASCIIに戻す(UNIX) */
cleantmp(); /* 成句・用例検索用の一時ファイルを削除する */
exit(0);
}
/*
* main - メインルーチン
*/
int
main(ac, av)
int ac;
uchr **av;
{
signal(SIGINT, onintr);
#if defined(UNIX) && defined(RC_PATH)
if (init_rcfile() != OK)
exit(1);
#endif
if (init_env() != OK)
exit(1);
ac--, av++;
if (parse_opt(&ac, &av) != OK)
usage();
if (!showver && (ac == 0 || stype != ID_SRCH && ac > 1))
usage();
if (dicdir == NULL) {
outstr("ERR: 辞書ディレクトリーが設定されていません\n");
exit(1);
}
if (showver) {
show_version(dicdir);
exit(0);
}
if (init_alt() == ERR)
exit(1);
if (gaifile != NULL) {
if (load_gaiji(gaifile) == ERR)
exit(1);
}
if (fmtfile != NULL) {
if (load_format(fmtfile) == ERR)
exit(1);
}
if (suppress(supstr) == ERR) {
outstr("ERR: 表示抑制指定(-sオプション)に誤りがあります\n");
exit(1);
}
if (search(dicdir, showall, ac, av) == ERR)
exit(1);
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1