/*
 * $Id: jl.c,v 2.113.2.4 2000/09/01 09:31:20 kaneda Exp $	
 */

/*
WNN6 CLIENT LIBRARY--SOFTWARE LICENSE TERMS AND CONDITIONS


Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993

Preamble

These Wnn6 Client Library--Software License Terms and Conditions
 (the "License Agreement") shall state the conditions under which you are
 permitted to copy, distribute or modify the software which can be used
 to create Wnn6 Client Library (the "Wnn6 Client Library").  The License
 Agreement can be freely copied and distributed verbatim, however, you
 shall NOT add, delete or change anything on the License Agreement.

OMRON Corporation and OMRON Software Co., Ltd. (collectively referred to
 as "OMRON") jointly developed the Wnn6 Software (development code name
 is FI-Wnn), based on the Wnn Software.  Starting from November, 1st, 1998,
 OMRON publishes the source code of the Wnn6 Client Library, and OMRON
 permits anyone to copy, distribute or change the Wnn6 Client Library under
 the License Agreement.

Wnn6 Client Library is based on the original version of Wnn developed by
 Kyoto University Research Institute for Mathematical Sciences (KURIMS),
 OMRON Corporation and ASTEC Inc.

Article 1.  Definition.

"Source Code" means the embodiment of the computer code, readable and
 understandable by a programmer of ordinary skills.  It includes related
 source code level system documentation, comments and procedural code.

"Object File" means a file, in substantially binary form, which is directly
 executable by a computer after linking applicable files.

"Library" means a file, composed of several Object Files, which is directly
 executable by a computer after linking applicable files.

"Software" means a set of Source Code including information on its use.

"Wnn6 Client Library" the computer program, originally supplied by OMRON,
 which can be used to create Wnn6 Client Library.

"Executable Module" means a file, created after linking Object Files or
 Library, which is directly executable by a computer.

"User" means anyone who uses the Wnn6 Client Library under the License
 Agreement.

Article 2.  Copyright

2.1  OMRON Corporation and OMRON Software Co., Ltd. jointly own the Wnn6
 Client Library, including, without limitation, its copyright.

2.2  Following words followed by the above copyright notices appear
 in all supporting documentation of software based on Wnn6 Client Library:

  This software is based on the original version of Wnn6 Client Library
  developed by OMRON Corporation and OMRON Software Co., Ltd. and also based on
  the original version of Wnn developed by Kyoto University Research Institute
  for Mathematical Sciences (KURIMS), OMRON Corporation and ASTEC Inc.

Article 3.  Grant

3.1  A User is permitted to make and distribute verbatim copies of
 the Wnn6 Client Library, including verbatim of copies of the License
 Agreement, under the License Agreement.

3.2  A User is permitted to modify the Wnn6 Client Library to create
 Software ("Modified Software") under the License Agreement.  A User
 is also permitted to make or distribute copies of Modified Software,
 including verbatim copies of the License Agreement with the following
 information.  Upon modifying the Wnn6 Client Library, a User MUST insert
 comments--stating the name of the User, the reason for the modifications,
 the date of the modifications, additional terms and conditions on the
 part of the modifications if there is any, and potential risks of using
 the Modified Software if they are known--right after the end of the
 License Agreement (or the last comment, if comments are inserted already).

3.3  A User is permitted to create Library or Executable Modules by
 modifying the Wnn6 Client Library in whole or in part under the License
 Agreement.  A User is also permitted to make or distribute copies of
 Library or Executable Modules with verbatim copies of the License
 Agreement under the License Agreement.  Upon modifying the Wnn6 Client
 Library for creating Library or Executable Modules, except for porting
 a computer, a User MUST add a text file to a package of the Wnn6 Client
 Library, providing information on the name of the User, the reason for
 the modifications, the date of the modifications, additional terms and
 conditions on the part of the modifications if there is any, and potential
 risks associated with using the modified Wnn6 Client Library, Library or
 Executable Modules if they are known.

3.4  A User is permitted to incorporate the Wnn6 Client Library in whole
 or in part into another Software, although its license terms and
 conditions may be different from the License Agreement, if such
 incorporation or use associated with the incorporation does NOT violate
 the License Agreement.

Article 4. Warranty

THE WNN6 CLIENT LIBRARY IS PROVIDED BY OMRON ON AN "AS IS" BAISIS.
  OMRON EXPRESSLY DISLCIAMS ANY AND ALL WRRANTIES, EXPRESS OR IMPLIED,
 INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, IN CONNECTION WITH THE WNN6 CLIENT LIBRARY
 OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT LIBRARY.  IN NO EVENT
 SHALL OMRON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, PUNITIVE
 OR CONSEQUENTIAL DAMAGES OF ANY KIND WHATSOEVER IN CONNECTION WITH THE
 WNN6 CLIENT LIBRARY OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT
LIBRARY.

***************************************************************************
Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993
***************************************************************************

Comments on Modifications:
*/

/*	Version 4
 */
/*
	Nihongo Henkan Hi-level Library
*/

#include "commonhd.h"
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#ifdef SYSVR2
#   include <string.h>
#endif
#ifdef BSD42
#   include <strings.h>
#endif
#include <sys/file.h>
#include <ctype.h>
#include <pwd.h>

#include "wnnerror.h"
#include "jd_sock.h"
#include "jslib.h"
#include "jllib.h"
#include "mt_jlib.h"

#include "msg.h"
#include "serverdefs.h"
#include "wnn_string.h"
extern struct msg_cat *wnn_msg_cat;


#define MAXENVS WNN_MAX_ENV_OF_A_CLIENT

#define MAXINCLUDE 10

#define DEFAULT_BUN_LEN 3

#define DEFAULT_ZENKOUHO_LEN 3

#define DEFAULT_HEAP_LEN 3

#define INCREMENT 2

#define SHO 0
#define DAI 1
#define IKEIJI 2 /* ==WNN_IKEIJI */

#define BUN 0
#define ZENKOUHO 1   /* Must not change!, they are assigned to two bit flag */
#define ZENKOUHO_DAI 3 /* DAI << 1 | ZENKOUHO */
#define ZENKOUHO_IKEIJI_DAI 5 /* IKEIJI << 1 | ZENKOUHO */

#define	if_dead_disconnect(env) \
{ \
	if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) { \
		jl_disconnect_if_server_dead_body((WNN_ENV_INT *)env);\
	} \
}

#define	if_dead_disconnect_b(buf) \
{ \
	if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD) { \
       jl_disconnect_if_server_dead_body((WNN_ENV_INT *) \
					 ((WNN_BUF_MT *)buf)->orig.env);\
		((WNN_BUF_MT *)buf)->orig.env = NULL; \
	} \
}

#define ARGS char
#define env_wnn_errorno_set wnn_errorno
#define env_wnn_errorno_eql wnn_errorno
#define env_wnn_errorno_copy(env) {}
#define buf_wnn_errorno_set wnn_errorno
#define buf_wnn_errorno_eql wnn_errorno
#define buf_wnn_errorno_copy(buf) {}
#define env_rb rb
#define buf_rb rb

static struct wnn_ret_buf rb = {0, NULL};
static struct wnn_ret_buf dicrb = {0, NULL};
static struct wnn_ret_buf wordrb = {0, NULL};

static int dumbhinsi;
static w_char *mae_fzk;
static int syuutanv;
static int syuutanv1;

int confirm_state;
# ifdef KOREAN
static int kwnn_tankan = -1;
static int kwnn_hangul = -1;
static int kwnn_meisi = -1;
static int kwnn_fuzokugo = -1;
# endif /* KOREAN */
static int wnn_rendaku = -1;
static int wnn_settou = -1;
static int wnn_meisi = -1;
/* 学習情報自動セーブ用確定カウンター */
static int kakutei_count = 0;

#define jl_get_yomi_body(buf, bun_no, bun_no2, area) \
                   wnn_get_area_body(buf, bun_no, bun_no2, area, WNN_YOMI)

#define jl_get_kanji_body(buf, bun_no, bun_no2, area) \
                   wnn_get_area_body(buf, bun_no, bun_no2, area, WNN_KANJI)

#define CONFIRM  1
#define CONFIRM1 2
#define CREATE_WITHOUT_CONFIRM  3
#define NO_CREATE 4

static void add_down_bnst();
static int alloc_heap();
static int call_error_handler();
static int change_ascii_to_int();
static int create_file();
static int dai_end();
static int expand_expr();
static int expand_expr_all();
static int file_discard();
static int file_exist();
static int file_read();
static int file_remove();
static int find_same_kouho();
static int find_same_kouho_dai();
static void free_bun();
static void free_down();
static void free_sho();
static void free_zenkouho();
static int get_c_jikouho();
static int get_c_jikouho_dai();
static int get_c_jikouho_from_zenkouho();
static int get_c_jikouho_from_zenkouho_dai();
static int get_pwd();
static int insert_dai();
static int insert_sho();
static int jl_set_env_wnnrc1_body();
static int jl_yomi_len_body();
static int make_dir1();
static int make_dir_rec1();
static void make_space_for();
static void make_space_for_bun();
static void make_space_for_zenkouho();
static void message_out();
static int ren_conv1(), ren_conv_sub();
static int nobi_conv_sub();
static void set_dai();
static void set_sho();
static int tan_conv1(), tan_conv_sub();
static int wnn_get_area_body();
static w_char *wnn_area();
static void _Sstrcpy();
static int jl_hinsi_number_e_body();
static int zen_conv_sho1();
static int zen_conv_dai1();
static int set_ima_off();
static int optimize_in_lib();
static int optimize_in_server();

static int insert_dai_or_ikeiji();
static int jl_dic_save_all_e_body();

/*
 * Sub-routines to handle files, enviroments and connections.
 */

struct wnn_file_name_id {
    struct wnn_file_name_id *next;
    int id;
    char name[1];
};

struct wnn_jl_env{
    WNN_JSERVER_ID *js;
    struct wnn_env_int *env;
    char env_n[WNN_ENVNAME_LEN];
    char server_n[WNN_HOSTLEN];
    char lang[32];
    int ref_cnt;
    struct wnn_file_name_id *file;
} envs[MAXENVS];

static void
initialize_envs()
{
    int i;
    for (i = 0; i < MAXENVS; i++) {
        envs[i].ref_cnt = 0;
    }
}

/* 
 * File management routines.
 */

static 
struct wnn_jl_env *find_jl_env(env)
register struct wnn_env_int *env;
{
    register int k;
    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].env == env) return(envs + k);
    }
    return(NULL);
}


static
struct wnn_env_int *
find_env_of_same_js_id(js_id)
register WNN_JSERVER_ID *js_id;
{
    register int k;

    for(k = 0 ; k < MAXENVS; k++){
	if (envs[k].js == NULL) continue;
	if (envs[k].js->sd == js_id->sd){
	    return(envs[k].env);
	}
    }
    return(NULL);
}

static
WNN_JSERVER_ID *
find_same_env_server(env_n, server_n, lang)
register char *env_n, *server_n, *lang;
{
    register int k;

    if (server_n == NULL || lang == NULL) return(NULL);
    for(k = 0 ; k < MAXENVS; k++){
	if(strncmp(envs[k].server_n, server_n, WNN_HOSTLEN - 1) == 0 &&
	   strcmp(envs[k].lang, lang) == 0){
	    return(envs[k].js);
	}
    }
    return(NULL);
}

static int
find_same_server_from_id(js)
register WNN_JSERVER_ID *js;
{
    register int k;
    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].js == NULL) continue;
	if(envs[k].js->sd == js->sd) return(1);
    }
    return(0);
}



static
struct wnn_env_int *
find_same_env(js, env_n, lang)
register WNN_JSERVER_ID *js;
register char *env_n;
char *lang;
{
    register int k;

    if (env_n == NULL || lang == NULL) return(NULL);
    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].js == js && strcmp(envs[k].env_n, env_n) == 0
			    && strcmp(envs[k].lang, lang) == 0){
	    envs[k].ref_cnt++;
	    return(envs[k].env);
	}
    }
    return(NULL);
}

static char *
env_name(env)
register struct wnn_env_int *env;
{
    register int k;

    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].env == env){
	    return(envs[k].env_n);
	}
    }
    return(NULL);
}


static void
add_new_env(js, env, env_n, server_n, lang)
register WNN_JSERVER_ID *js;
register struct wnn_env_int *env;
char *env_n, *server_n, *lang;
{
    register int k;

    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].ref_cnt == 0){
	    strncpy(envs[k].server_n, server_n, WNN_HOSTLEN - 1);
	    envs[k].server_n[WNN_HOSTLEN - 1] = '\0';
	    strncpy(envs[k].env_n, env_n, WNN_ENVNAME_LEN - 1);
	    envs[k].env_n[WNN_ENVNAME_LEN - 1] = '\0';
	    strncpy(envs[k].lang, lang, sizeof(envs[k].lang) - 1);
	    envs[k].lang[sizeof(envs[k].lang) - 1] = 0;
	    envs[k].js = js;
	    envs[k].env = env;
	    envs[k].ref_cnt = 1;
	    envs[k].file = NULL;
	    break;
	}
    }
}

static int
delete_env(env)
register struct wnn_env_int *env;
{
    register int k;

    for(k = 0 ; k < MAXENVS; k++){
	if(envs[k].env == env){
	    if(--envs[k].ref_cnt == 0){
		strcpy(envs[k].server_n, "");
		strcpy(envs[k].env_n, "");
		strcpy(envs[k].lang, "");
		envs[k].js = NULL;
		envs[k].env = NULL;
		return(1);	/* Need To delete env */
	    }else{
		return(0);	/* Need not to delete env */
	    }
	}
    }
    return(-1);			/* This must not happen */
}

/* Routines to manipulate files */

static int
add_file_to_env(env, id, name)
struct wnn_env_int *env;
int id;
register char *name;
{
    register struct wnn_file_name_id *f, *f1;
    if((f = (struct wnn_file_name_id *)malloc(sizeof(struct wnn_file_name_id) +
					     strlen(name) + 1)) == NULL){
	env_wnn_errorno_set=WNN_ALLOC_FAIL;
	return(-1);
    }
    strcpy(f->name, name);
    f->id = id;
    LockMutex(&envs_lock);
    f1 = find_jl_env(env)->file;
    f->next = f1;
    find_jl_env(env)->file = f;
    UnlockMutex(&envs_lock);
    return(0);
}
    
static char *
find_file_name_from_id(env, id)
struct wnn_env_int *env;
register int id;
{
    register struct wnn_file_name_id *f;
    f = find_jl_env(env)->file;
    for(;f; f = f->next){
	if(f->id == id){
	    return(f->name);
	}
    }
/*    env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT; */
    return(NULL);
}

static int
delete_file_from_env(env, id)
struct wnn_env_int *env;
register int id;
{
    struct wnn_file_name_id *f;
    register struct wnn_file_name_id **prev;
    register struct wnn_jl_env *jl_env_p;

    LockMutex(&envs_lock);
    jl_env_p = find_jl_env(env);
    if (!jl_env_p->file) {
	UnlockMutex(&envs_lock);
	return(0);
    }
    for(prev = &jl_env_p->file; (f = *prev); prev = &f->next){
	if (f->id == id) {
	    *prev = f->next;
	    free(f);
	    UnlockMutex(&envs_lock);
	    return(0);
	}
    }
    UnlockMutex(&envs_lock);
    env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT;
    return(-1);
}

/*
 * Libraries which handle Connection To Jserver
 */

struct wnn_env *
jl_connect_lang(env_n, server_n, lang, wnnrc_n, error_handler, message_handler, timeout)
register char *env_n, *server_n, *wnnrc_n, *lang;
int  (*error_handler)(), (*message_handler)();
int timeout;
{
    register WNN_JSERVER_ID	*js = NULL;
    struct wnn_env_int *env;
    int env_exist, cnt;
    char p_lang[16];
    register char *p, *l;
    static int initialized_envs = 0;
    extern char *getenv();

    DoOnce( &once, _InitMutexs );
    LockMutex(&open_lock);
    if (!initialized_envs) {
        initialize_envs();
        initialized_envs = 1;
    }

    wnn_errorno = 0;
    /* if lang not specified use $LANG */
    if(!lang || !*lang){
	lang = getenv("LANG");
    }
    if (!lang || !*lang){
/* Sorry! Default is Japanese. :-) */
	strcpy(p_lang, "ja_JP");

    } else {
	/* Use only [language]_[teritorry] */
	for(p = p_lang, l = lang, cnt = 0;
	    (*l != '@') && (*l != '.') && (*l != 0) &&
	    (cnt < sizeof(p_lang) - 1)
	    ; p++, l++, cnt++)
	    *p = *l;
	*p = 0;
    }

    LockMutex(&envs_lock);
   /* To See serverdefs file when server_n is not specified. */
    if(!server_n || !*server_n){
	/* find server machine name from table by lang */
	if ((server_n = wnn_get_machine_of_serverdefs(p_lang))) {
	    if((js = find_same_env_server(env_n, server_n, p_lang)) == NULL){
		if((js = js_open_lang(server_n, p_lang, timeout)) == NULL){
		    server_n = NULL;
		}
	    }
	}
	if (!server_n || !*server_n) {
	    server_n = "unix";
	}
    }

    if (js == NULL) {
	if((js = find_same_env_server(env_n, server_n, p_lang)) == NULL){
	    if((js = js_open_lang(server_n, p_lang, timeout)) == NULL){
		UnlockMutex(&envs_lock);
		UnlockMutex(&open_lock);
		return(NULL);
	    }
    /*	js_hinsi_list(js); */
	}
    }
    if ((env_exist = js_env_exist(js, env_n)) < 0) {
	UnlockMutex(&envs_lock);
	UnlockMutex(&open_lock);
	return (NULL);
    }
    if((env = find_same_env(js, env_n, p_lang)) == NULL){ /* Incr ref_cnt */
	if((env = (WNN_ENV_INT *)js_connect_lang(js, env_n, p_lang)) == NULL){
	    UnlockMutex(&envs_lock);
	    UnlockMutex(&open_lock);
	    return(NULL);
	}
	InitMutex(&(env->env_lock));
# ifdef KOREAN
        if(!strncmp(lang, WNN_K_LANG, 5)) {
            w_char tmp[8];
            _Sstrcpy(tmp, "咾蹼"); kwnn_tankan = jl_hinsi_number_e_body(env, tmp);
            _Sstrcpy(tmp, "廃越"); kwnn_hangul = jl_hinsi_number_e_body(env, tmp);
            _Sstrcpy(tmp, "截溟"); kwnn_meisi = jl_hinsi_number_e_body(env, tmp);
            _Sstrcpy(tmp, "歉疸繃"); kwnn_fuzokugo = jl_hinsi_number_e_body(env, tmp);
        }
# endif /* KOREAN */
	if(!strncmp(lang, WNN_J_LANG, 5)) {
            w_char tmp[8];
	    _Sstrcpy(tmp, WNN_HINSI_RENDAKU);
	    wnn_rendaku = jl_hinsi_number_e_body(env, tmp);
	    _Sstrcpy(tmp, WNN_HINSI_SETTOUO);
	    wnn_settou = jl_hinsi_number_e_body(env, tmp);
	    _Sstrcpy(tmp, WNN_HINSI_MEISI);
	    wnn_meisi = jl_hinsi_number_e_body(env, tmp);
	}
	add_new_env(js, env, env_n, server_n, p_lang);
    }
    UnlockMutex(&envs_lock);
    if(env_exist == 0 && wnnrc_n){
	jl_set_env_wnnrc(env, wnnrc_n, error_handler, message_handler);
    } else {
	unsigned long mask = WNN_ENV_BUNSETSUGIRI_LEARN_MASK |
			     WNN_ENV_MUHENKAN_LEARN_MASK;
	struct wnn_henkan_env henv;
	if(wnnrc_n) 
	    jl_set_env_wnnrc1_body(env, wnnrc_n, error_handler,
				   message_handler, 0, 1);
	if(js_get_henkan_env(env, &henv) == 0) {
	    env->orig.muhenkan_mode = henv.muhenkan_flag;
	    env->orig.bunsetsugiri_mode = henv.bunsetsugiri_flag;
	} else {
	    env->orig.muhenkan_mode = WNN_DIC_RDONLY;
	    env->orig.bunsetsugiri_mode = WNN_DIC_RDONLY;
	}
    }
    UnlockMutex(&open_lock);
    return((struct wnn_env *)env);
}


static void
jl_disconnect_body(env)
register struct wnn_env_int *env;
{
    int ret;

    env_wnn_errorno_set = 0;
    LockMutex(&envs_lock);
    if((ret = delete_env(env)) < 0){
	UnlockMutex(&envs_lock);
	return;
    } else if (ret) {
	js_disconnect((WNN_ENV *)env);
    }
    if(!find_same_server_from_id(env->orig.js_id)){
	js_close(env->orig.js_id);
	env->orig.js_id = 0;
    }
    UnlockMutex(&envs_lock);
}

void
jl_disconnect(env)
register struct wnn_env *env;
{
    if(!env) return;
    LockMutex(&ENV_LOCK(env));
    jl_disconnect_body((WNN_ENV_INT *)env);
    UnlockMutex(&ENV_LOCK(env));
}

int
jl_isconnect_e(env)
register struct wnn_env *env;
{
    if(!env) return(0);
    LockMutex(&ENV_LOCK(env));
    if (js_isconnect(env) == 0) {
	UnlockMutex(&ENV_LOCK(env));
	return(1);
    } else {
	UnlockMutex(&ENV_LOCK(env));
	return (0);
    }
}

int
jl_isconnect(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = jl_isconnect_e(buf->env);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/* JSERVER が死んだら env を disconnect して回る */
static void
jl_disconnect_if_server_dead_body(env)
register struct wnn_env *env;
{
    register struct wnn_env_int *same_env;
    int ret;

    LockMutex(&envs_lock);
    if((ret = delete_env((WNN_ENV_INT *)env)) < 0){
	UnlockMutex(&envs_lock);
	return;
    } else if (ret) {
	js_disconnect(env);
    }

    while ((same_env = find_env_of_same_js_id(env->js_id)) != 0) {
	if(delete_env(same_env)){
	    LockMutex(&(same_env->env_lock));
	    js_disconnect((WNN_ENV *)same_env);
	    UnlockMutex(&(same_env->env_lock));
	}
    }
    UnlockMutex(&envs_lock);

    js_close(env->js_id);

    /* jserver が死んだ後でも js_id を参照する関数が存在するので、
       NULL ポインタ初期化は行わず、js_dead フラグにより jserver が
       死んでいるかどうかのチェックを行う */
    /* env->js_id = 0; */
}


void
jl_disconnect_if_server_dead(env)
register struct wnn_env *env;
{
    if(!env) return;
    LockMutex(&ENV_LOCK(env));
    jl_disconnect_if_server_dead_body((WNN_ENV_INT *)env);
    UnlockMutex(&ENV_LOCK(env));
}

struct wnn_buf *
jl_open_lang(env_n, server_n, lang, wnnrc_n, error_handler, message_handler, timeout)
char *env_n, *server_n, *wnnrc_n, *lang;
int  (*error_handler)(), (*message_handler)();
int timeout;
{
    register int k, dmy;
    register struct wnn_buf_mt *buf;
    struct wnn_env *env;

    wnn_errorno = 0;
    if(rb.size == 0) rb.buf = (char *)malloc((unsigned)(rb.size = 1024));

#define ALLOC_SET(pter, type, size, size_var) \
    ((pter) = ((type *)malloc((unsigned)(sizeof(type) * ((size_var) = (size))))))

    if(!ALLOC_SET(buf, struct wnn_buf_mt, 1, dmy)){
	wnn_errorno=WNN_ALLOC_FAIL;return NULL;
    }

    buf->orig.bun_suu = 0;
    buf->orig.zenkouho_suu = 0;
    buf->orig.zenkouho_daip = 0;
    buf->orig.c_zenkouho = -1;
    buf->orig.zenkouho_bun = -1;
    buf->orig.zenkouho_end_bun = -1;
    buf->orig.free_heap = NULL;
    buf->orig.heap = NULL;
    buf->orig.zenkouho_dai_suu = 0;
    buf->orig.env = NULL;
    /*
     * Hideyuki Kishiba (Sep. 20, 1994)
     * 使用ＦＩ関係受け取り用構造体を初期化する
     */
    buf->orig.fi_rb.size = buf->orig.fi_rb.num = 0;
    buf->orig.fi_rb.fi_buf = NULL;
    /* 直前確定情報配列の初期化 */
    for(k = 0; k < WNN_PREV_BUN_SUU; k++) {
	buf->orig.prev_bun[k].dic_no = -2;
	buf->orig.prev_bun[k].real_kanjilen = 0;
	buf->orig.prev_bun[k].kouho[0] = 0;
    }

    if(!ALLOC_SET(buf->orig.bun, WNN_BUN *, DEFAULT_BUN_LEN, buf->orig.msize_bun) ||
       !ALLOC_SET(buf->orig.zenkouho_dai, int, DEFAULT_ZENKOUHO_LEN + 1, buf->orig.msize_zenkouho) ||
       !ALLOC_SET(buf->orig.zenkouho, WNN_BUN *, DEFAULT_ZENKOUHO_LEN, buf->orig.msize_zenkouho) ||
       !ALLOC_SET(buf->orig.down_bnst, WNN_BUN *, DEFAULT_BUN_LEN, buf->orig.msize_bun)
       ){
	wnn_errorno=WNN_ALLOC_FAIL;return NULL;
    }
       
    for(k = 0 ; k < DEFAULT_BUN_LEN ; k++){
	buf->orig.down_bnst[k] = NULL;
    }

    if(alloc_heap(buf, DEFAULT_HEAP_LEN) == -1){
	return NULL;
    }

    env = jl_connect_lang(env_n, server_n, lang, wnnrc_n, error_handler, message_handler, timeout);
    buf->orig.env = env;
    InitMutex(&BUF_LOCK(buf));

    return((struct wnn_buf *)buf);
}


static void
_Sstrcpy(ws, s)
w_char *ws;
unsigned char *s;
{
    register int eesiz = -1;
    register unsigned char x;
    register w_char *ie;
    register unsigned char *ee;
    register int cs_id, non_limit = 1;
    int _etc_cs[3];
    int cs_mask[3];

	_etc_cs[0] = 2;
	_etc_cs[1] = 1;
	_etc_cs[2] = 2;
	cs_mask[0] = 0x8080;
	cs_mask[1] = 0x0080;
	cs_mask[2] = 0x8000;
    ie=ws;ee=s;

    for(;(non_limit?(*ee):(eesiz>0));){
        x = *ee++;
        if(x > 0x9f || x == 0x8e || x == 0x8f){
            cs_id = ((x == 0x8e)? 1 : ((x == 0x8f)? 2: 0));
            if (cs_id == 1 || cs_id == 2) x = *ee++;
            if (_etc_cs[cs_id] <= 0) continue;
            if (_etc_cs[cs_id] > 1) {
                *ie = (w_char)(x & 0x7f) << 8;
                x = *ee++;
            } else {
                *ie = (w_char)0;
            }
            *ie |= (x & 0x7f);
            *ie++ |= cs_mask[cs_id];
            eesiz -= _etc_cs[cs_id] + 1;
        }else{
            *ie++ = x;
            eesiz--;
        }
    }

    non_limit = ((char *)ie - (char *)ws) / sizeof(w_char);
    ws[non_limit] = 0;
}

static int
alloc_heap(buf, len)
struct wnn_buf_mt *buf;
register int len;
{
    char **c;
    register WNN_BUN *d;

    if((c =(char **)malloc((unsigned)(len * sizeof(WNN_BUN) + sizeof(char *)))) == NULL){
	    buf_wnn_errorno_set=WNN_ALLOC_FAIL;
	return(-1);
    }

    *c = buf->orig.heap;
    buf->orig.heap = (char *)c;
    d = (WNN_BUN *)(c + 1);
    for(--len; len > 0 ; len--, d++){
	d->free_next = d + 1;
    }
    d->free_next = buf->orig.free_heap;
    buf->orig.free_heap = (WNN_BUN *)(c + 1);
    return(0);
}

void
jl_close(buf)
register struct wnn_buf *buf;
{
    register char *c, *next;
    struct wnn_buf_mt tmpbuf;

    if(buf == NULL) return;
    tmpbuf = *(WNN_BUF_MT *)buf;
    LockMutex(&(tmpbuf.buf_lock));
    if(buf->env){
	LockMutex(&(envmt->env_lock));
	buf_wnn_errorno_set = 0;
	jl_disconnect_body((WNN_ENV_INT *)buf->env);
	UnlockMutex(&(envmt->env_lock));
	buf->env = 0;
    }

    if(buf->bun) free((char *)buf->bun);
    if(buf->zenkouho) free((char *)buf->zenkouho);
    if(buf->zenkouho_dai) free((char *)buf->zenkouho_dai);
    if(buf->down_bnst) free((char *)buf->down_bnst);
    for(c = buf->heap; c; c = next) {
	next = *(char **)c;
	free(c);
    }
    free((char *)buf);
    UnlockMutex(&(tmpbuf.buf_lock));
}

/*
 * Conversion Libraries 
 */

/*:::DOC_START
 *
 *    Function Name: jl_ren_conv
 *    Description  : 連文節変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_ren_conv(buf, yomi, bun_no, bun_no2, use_maep)
register struct wnn_buf *buf;
register w_char *yomi;
int bun_no, bun_no2;
int use_maep;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    x = ren_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		     0, 0, NULL, 0);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_ren_conv */

/*:::DOC_START
 *
 *    Function Name: jl_ren_conv_with_hinsi_name
 *    Description  : 変換に使用する品詞を限定して連文節変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *	   nhinsi :   (In) 品詞指定変換時の指定品詞数
 *         hlist :    (In) 品詞指定変換時の指定品詞名配列へのポインタ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_ren_conv_with_hinsi_name(buf, yomi, bun_no, bun_no2, use_maep, nhinsi, hname)
register struct wnn_buf *buf;
register w_char *yomi;
int bun_no, bun_no2;
int use_maep, nhinsi;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(nhinsi) {
        hsize = abs(nhinsi);
        hno = (int *)malloc(hsize * sizeof(int));
        for(i = 0; i < hsize; i++) {
            _Sstrcpy(tmp, hname[i]);
            if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
                free((char *)hno);
                UnlockMutex(&BUF_LOCK(buf));
                return(-1);
            }
        }
    }

    x = ren_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		     0, nhinsi, hno, 0);
    if(nhinsi) free((char *)hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_ren_conv_with_hinsi_name */

/*:::DOC_START
 *
 *    Function Name: jl_fi_ren_conv
 *    Description  : 連文節ＦＩ変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *	   yomi :     (In) 変換読み文字列へのポインタ
 *	   bun_no :   (In) 削除する文節の先頭文節番号
 *	   bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 * 	   use_maep : (In) 前後の接続を（使う／否）フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_fi_ren_conv(buf, yomi, bun_no, bun_no2, use_maep)
register struct wnn_buf *buf;
register w_char *yomi;
int bun_no, bun_no2;
int use_maep;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }

    x = ren_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		     0, 0, NULL, 1);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_fi_ren_conv */

/*:::DOC_START
 *
 *    Function Name: ren_conv_sub
 *    Description  : 連文節変換のサブルーチン関数その１
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *	   fuku :     (In) 複合語優先変換フラグ
 *	   nhinsi :   (In) 品詞指定変換時の指定品詞数
 * 	   hlist :    (In) 品詞指定変換時の指定品詞番号配列へのポインタ
 * 	   fi_flag :  (In) 使用したＦＩ関係情報を（受け取らない／
 *			   受け取る）フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
ren_conv_sub(buf, yomi, bun_no, bun_no2, use_maep, fuku, nhinsi, hlist, fi_flag)
register struct wnn_buf *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, fuku, nhinsi, *hlist, fi_flag;
{
    int x;

    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;
    free_down(buf, bun_no, bun_no2);
    x = ren_conv1((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		  fuku, nhinsi, hlist, fi_flag);
    return x;
} /* End of ren_conv_sub */
    
/*:::DOC_START
 *
 *    Function Name: ren_conv1
 *    Description  : 連文節変換のサブルーチン関数その２
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *         fuku :     (In) 複合語優先変換フラグ
 *         nhinsi :   (In) 品詞指定変換時の指定品詞数
 *         hlist :    (In) 品詞指定変換時の指定品詞番号配列へのポインタ
 *         fi_flag :  (In) 使用したＦＩ関係情報を（受け取らない／
 *                         受け取る）フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
ren_conv1(buf, yomi, bun_no, bun_no2, use_maep, fuku, nhinsi, hlist, fi_flag)
register struct wnn_buf_mt *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, fuku, nhinsi, *hlist, fi_flag;
{
    int dcnt;
    struct wnn_dai_bunsetsu *dp;
    int size;
    w_char yomi1[LENGTHBUNSETSU];

    if (yomi == NULL || *yomi == (w_char)0) return(0);
    if(bun_no2 >= buf->orig.bun_suu || bun_no2 < 0) 
        bun_no2 = buf->orig.bun_suu;

    if (use_maep & WNN_USE_MAE && bun_no > 0) {
	dumbhinsi = buf->orig.bun[bun_no - 1]->hinsi;
	jl_get_yomi_body(buf, bun_no - 1, bun_no, yomi1);
	mae_fzk = yomi1 + buf->orig.bun[bun_no - 1]->jirilen;
    } else {
	dumbhinsi = WNN_BUN_SENTOU;
	mae_fzk = (w_char *)0;
    }
    if(use_maep & WNN_USE_ATO && bun_no2 < buf->orig.bun_suu){
	syuutanv = buf->orig.bun[bun_no2]->kangovect;
	syuutanv1 = WNN_VECT_KANREN;
    }else{
	syuutanv = WNN_VECT_KANREN;
	syuutanv1 = WNN_VECT_NO;
	if(bun_no2 < buf->orig.bun_suu){
	    buf->orig.bun[bun_no2]->dai_top = 1;
	}
    }
    if(!(buf->orig.env)) return(-1);
    LockMutex(&(envmt->env_lock));
    if(fuku == 0 && nhinsi == 0) {
	if(fi_flag == 0) {
	    /* 連文節変換 */
	    if((dcnt = js_kanren(buf->orig.env, yomi, dumbhinsi, mae_fzk,
				 syuutanv, syuutanv1, WNN_VECT_BUNSETSU,
				 &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf);
		if_dead_disconnect_b(buf);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    /* 連文節ＦＩ変換 */
	    if((dcnt = js_fi_kanren(buf->orig.env, yomi, dumbhinsi, mae_fzk,
				    syuutanv, syuutanv1, WNN_VECT_BUNSETSU,
				    buf->orig.prev_bun, &buf_rb, &(buf->orig.fi_rb))) < 0){
                buf_wnn_errorno_copy(buf);
                if_dead_disconnect_b(buf);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
            }
	}
    } else {
	/* 変換環境指定連文節変換 */
	if((dcnt = js_henkan_with_data(buf->orig.env, fuku, nhinsi, hlist,
				       WNN_KANREN, yomi, dumbhinsi, mae_fzk, 
				       syuutanv, syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0) {
	    buf_wnn_errorno_copy(buf);
            if_dead_disconnect_b(buf);
            UnlockMutex(&(envmt->env_lock));
            return(-1);
        }
    }

    dp = (struct wnn_dai_bunsetsu *)buf_rb.buf;

    free_bun(buf, bun_no, bun_no2);

    if(use_maep & WNN_USE_ATO && bun_no2 < buf->orig.bun_suu){
	buf->orig.bun[bun_no2]->dai_top =
	    (dp[dcnt-1].sbn[dp[dcnt-1].sbncnt-1].status_bkwd == WNN_CONNECT_BK)? 0:1;
    }

    size = insert_dai(buf, BUN, bun_no, bun_no2, dp, dcnt, 0, fuku, nhinsi, hlist);
    if(buf->orig.zenkouho_end_bun > bun_no && buf->orig.zenkouho_bun < bun_no2){
	free_zenkouho(buf);
    }else if(buf->orig.zenkouho_bun >= bun_no2){
	buf->orig.zenkouho_bun += size - bun_no2;
	buf->orig.zenkouho_end_bun += size - bun_no2;

    }	
    UnlockMutex(&(envmt->env_lock));
    return(buf->orig.bun_suu);
} /* End of ren_conv1 */

/*:::DOC_START
 *
 *    Function Name: jl_tan_conv
 *    Description  : 単文節変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *         ich_shop : (In) （小文節／大文節）変換フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_tan_conv(buf, yomi, bun_no, bun_no2, use_maep, ich_shop)
register struct wnn_buf *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, ich_shop;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    if(tan_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		    ich_shop, 0, 0, NULL) == -1) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_tan_conv */

/*:::DOC_START
 *
 *    Function Name: jl_tan_conv_hinsi_flag
 *    Description  : 変換に使用する品詞を限定して単文節変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *         ich_shop : (In) （小文節／大文節）変換フラグ
 *	   hinsi_op : (In) 品詞指定変換時の指定品詞フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_tan_conv_hinsi_flag(buf, yomi, bun_no, bun_no2, use_maep, ich_shop, hinsi_op)
register struct wnn_buf *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, ich_shop, hinsi_op;
{
    int x, hno;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(hinsi_op == WNN_ZIP)
        _Sstrcpy(tmp, WNN_HINSI_ZIPCODE);
    else if(hinsi_op == WNN_TEL)
        _Sstrcpy(tmp, WNN_HINSI_TELNO);
    else if(hinsi_op == WNN_TANKAN)
        _Sstrcpy(tmp, WNN_HINSI_TANKAN);
    else {
	UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if((hno = jl_hinsi_number_e(buf->env, tmp)) == -1) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    if(tan_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		    ich_shop, 0, 1, &hno) == -1) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* jl_tan_conv_hinsi_flag */

/*:::DOC_START
 *
 *    Function Name: jl_tan_conv_with_hinsi_name
 *    Description  : 変換に使用する品詞を限定して単文節変換を行う
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *         ich_shop : (In) （小文節／大文節）変換フラグ
 *         nhinsi :   (In) 品詞指定変換時の指定品詞数
 *         hlist :    (In) 品詞指定変換時の指定品詞名配列へのポインタ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *	16-May-96: 岸場:  使用済ＦＩ関係データを初期化
 *
 *:::DOC_END
 */
int
jl_tan_conv_with_hinsi_name(buf, yomi, bun_no, bun_no2, use_maep, ich_shop, nhinsi, hname)
register struct wnn_buf *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, ich_shop, nhinsi;
char **hname;
{
    int i, x, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;

    /* 使用済ＦＩ関係データを初期化する。 05/16/96  H.Kishiba */
    buf->fi_rb.num = 0;

    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
/*    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5) || nhinsi == 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    } */
    if(nhinsi) {
	hsize = abs(nhinsi);
	hno = (int *)malloc(hsize * sizeof(int));
	for(i = 0; i < hsize; i++) {
	    _Sstrcpy(tmp, hname[i]);
	    if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
		free((char *)hno);
		UnlockMutex(&BUF_LOCK(buf));
		return(-1);
	    }
	}
    }

    if(tan_conv_sub((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		    ich_shop, 0, nhinsi, hno) == -1) {
	if(nhinsi) free((char *)hno);
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(nhinsi) free((char *)hno);
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* jl_tan_conv_with_hinsi_name */

/*:::DOC_START
 *
 *    Function Name: tan_conv_sub
 *    Description  : 単文節変換のサブルーチン関数その１
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *         ich_shop : (In) （小文節／大文節）変換フラグ
 *         fuku :     (In) 複合語優先変換フラグ
 *         nhinsi :   (In) 品詞指定変換時の指定品詞数
 *         hlist :    (In) 品詞指定変換時の指定品詞番号配列へのポインタ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
tan_conv_sub(buf, yomi, bun_no, bun_no2, use_maep, ich_shop, fuku, nhinsi, hlist)
register struct wnn_buf *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, ich_shop, fuku, nhinsi, *hlist;
{
    int x;

    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;
    free_down(buf, bun_no, bun_no2);
    x = tan_conv1((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2, use_maep,
		  ich_shop, fuku, nhinsi, hlist);
    return x;
} /* End of tan_conv_sub */

/*:::DOC_START
 *
 *    Function Name: tan_conv1
 *    Description  : 単文節変換のサブルーチン関数その２
 *    Parameter    :
 *         buf :      (InOut) バッファへのポインタ
 *         yomi :     (In) 変換読み文字列へのポインタ
 *         bun_no :   (In) 削除する文節の先頭文節番号
 *         bun_no2 :  (In) 削除する文節の最終文節の直後の文節番号
 *         use_maep : (In) 前後の接続を（使う／否）フラグ
 *	   ich_shop : (In) （小文節／大文節）変換フラグ
 *         fuku :     (In) 複合語優先変換フラグ
 *         nhinsi :   (In) 品詞指定変換時の指定品詞数
 *         hlist :    (In) 品詞指定変換時の指定品詞番号配列へのポインタ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
tan_conv1(buf, yomi, bun_no, bun_no2, use_maep, ich_shop, fuku, nhinsi, hlist)
register struct wnn_buf_mt *buf;
w_char *yomi;
register int bun_no, bun_no2;
int use_maep, ich_shop, fuku, nhinsi, *hlist;
{
    int dcnt;
    struct wnn_dai_bunsetsu *dp;
    struct wnn_sho_bunsetsu *sp;
    int ret;
    w_char yomi1[LENGTHBUNSETSU];

    if (yomi == NULL || *yomi == (w_char)0) return(0);
    if(bun_no2 >= buf->orig.bun_suu || bun_no2 < 0) bun_no2 = buf->orig.bun_suu;

    if (use_maep & WNN_USE_MAE && bun_no > 0) {
	dumbhinsi = buf->orig.bun[bun_no - 1]->hinsi;
	jl_get_yomi_body(buf, bun_no - 1, bun_no, yomi1);
	mae_fzk = yomi1 + buf->orig.bun[bun_no - 1]->jirilen;
    } else {
	dumbhinsi = WNN_BUN_SENTOU;
	mae_fzk = (w_char *)0;
    }
    if(use_maep & WNN_USE_ATO && bun_no2 < buf->orig.bun_suu){
	syuutanv = buf->orig.bun[bun_no2]->kangovect;
	syuutanv1 = WNN_VECT_KANTAN;
    }else{
	syuutanv = WNN_VECT_KANTAN;
	syuutanv1 = WNN_VECT_NO;
	if(bun_no2 < buf->orig.bun_suu){
	    buf->orig.bun[bun_no2]->dai_top = 1;
	}
    }
    if(!(buf->orig.env)) return(-1);
    LockMutex(&(envmt->env_lock));
    if(ich_shop == WNN_SHO){
	if(fuku == 0 && nhinsi == 0) {
	    /* 小文節単文節変換 */
	    if((dcnt = js_kantan_sho(buf->orig.env, yomi, dumbhinsi, mae_fzk,
				     syuutanv, syuutanv1, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf);
		if_dead_disconnect_b(buf);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    /* 変換環境指定小文節単文節変換 */
	    if((dcnt = js_henkan_with_data(buf->orig.env, fuku, nhinsi, hlist,
					   WNN_KANTAN_SHO, yomi, dumbhinsi, mae_fzk,
					   syuutanv, syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0) {
		buf_wnn_errorno_copy(buf);
                if_dead_disconnect_b(buf);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
	    }
	}
	sp = (struct wnn_sho_bunsetsu *)buf_rb.buf;
	if(use_maep & WNN_USE_ATO && bun_no2 < buf->orig.bun_suu){
	    buf->orig.bun[bun_no2]->dai_top =
		(sp[dcnt-1].status_bkwd == WNN_CONNECT_BK)? 0:1;
	}
	free_bun(buf, bun_no, bun_no2);
	ret = insert_sho(buf, BUN, bun_no, bun_no2, sp, dcnt, 0, fuku, nhinsi, hlist);
    } else {
	if(fuku == 0 && nhinsi == 0) {
	    /* 大文節単文節変換 */
	    if((dcnt = js_kantan_dai(buf->orig.env, yomi, dumbhinsi, mae_fzk,
				     syuutanv, syuutanv1, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf);
		if_dead_disconnect_b(buf);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    /* 変換環境指定大文節単文節変換 */
	    if((dcnt = js_henkan_with_data(buf->orig.env, fuku, nhinsi, hlist,
					   WNN_KANTAN_DAI, yomi, dumbhinsi, mae_fzk,
					   syuutanv, syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0) {
		buf_wnn_errorno_copy(buf);
                if_dead_disconnect_b(buf);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
            }
	}
	dp = (struct wnn_dai_bunsetsu *)buf_rb.buf;
	if(use_maep & WNN_USE_ATO && bun_no2 < buf->orig.bun_suu){
	    buf->orig.bun[bun_no2]->dai_top =
		(dp[dcnt-1].sbn[dp[dcnt-1].sbncnt-1].status_bkwd == WNN_CONNECT_BK)? 0:1;
	}
	free_bun(buf, bun_no, bun_no2);
	ret = insert_dai(buf, BUN, bun_no, bun_no2, dp, dcnt, 0, fuku, nhinsi, hlist);
    }
    if(buf->orig.zenkouho_end_bun > bun_no && buf->orig.zenkouho_bun < bun_no2){
	free_zenkouho(buf);
    }else if(buf->orig.zenkouho_bun >= bun_no2){
	buf->orig.zenkouho_bun += ret - bun_no2;
	buf->orig.zenkouho_end_bun += ret - bun_no2;
    }	
    UnlockMutex(&(envmt->env_lock));
    return(ret);
} /* End of tan_conv1 */

/*:::DOC_START
 *
 *    Function Name: jl_nobi_conv
 *    Description  : 延び変換を行う
 *    Parameter    :
 *         buf :       (InOut) バッファへのポインタ
 *         bun_no :    (In) 変換文節の先頭文節番号
 *         ichbn_len : (In) 第一文節目の長さ
 *         bun_no2 :   (In) 変換文節の最終文節の直後の文節番号
 *         use_maep :  (In) 前後の接続を（使う／否）フラグ
 *         ich_shop :  (In) 一文節目を（小文節／大文節）変換するフラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_nobi_conv(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop)
register struct wnn_buf *buf;
int ichbn_len, use_maep, ich_shop;
register int bun_no, bun_no2;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    if(nobi_conv_sub(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop,
                     0, NULL, 0) == -1) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_nobi_conv */

/*:::DOC_START
 *
 *    Function Name: jl_nobi_conv_hinsi_flag
 *    Description  : 変換に使用する品詞を限定して延び変換を行う
 *    Parameter    :
 *         buf :       (InOut) バッファへのポインタ
 *         bun_no :    (In) 変換文節の先頭文節番号
 *         ichbn_len : (In) 第一文節目の長さ
 *         bun_no2 :   (In) 変換文節の最終文節の直後の文節番号
 *         use_maep :  (In) 前後の接続を（使う／否）フラグ
 *         ich_shop :  (In) 一文節目を（小文節／大文節）変換するフラグ
 *	   hinsi_op :  (In) 品詞指定変換時の指定品詞フラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_nobi_conv_hinsi_flag(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop, hinsi_op)
register struct wnn_buf *buf;
int ichbn_len, use_maep, ich_shop, hinsi_op;
register int bun_no, bun_no2;
{
    int x, hno;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(hinsi_op == WNN_ZIP)
        _Sstrcpy(tmp, WNN_HINSI_ZIPCODE);
    else if(hinsi_op == WNN_TEL)
        _Sstrcpy(tmp, WNN_HINSI_TELNO);
    else if(hinsi_op == WNN_TANKAN)
        _Sstrcpy(tmp, WNN_HINSI_TANKAN);
    else {
	UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if((hno = jl_hinsi_number_e(buf->env, tmp)) == -1) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    if(nobi_conv_sub(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop,
                     1, &hno, 0) == -1) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* jl_nobi_conv_hinsi_flag */

/*:::DOC_START
 *
 *    Function Name: jl_nobi_conv_with_hinsi_name
 *    Description  : 変換に使用する品詞を限定して延び変換を行う
 *    Parameter    :
 *         buf :       (InOut) バッファへのポインタ
 *         bun_no :    (In) 変換文節の先頭文節番号
 *         ichbn_len : (In) 第一文節目の長さ
 *         bun_no2 :   (In) 変換文節の最終文節の直後の文節番号
 *         use_maep :  (In) 前後の接続を（使う／否）フラグ
 *         ich_shop :  (In) 一文節目を（小文節／大文節）変換するフラグ
 *         nhinsi :    (In) 品詞指定変換時の指定品詞数
 *         hname :     (In) 品詞指定変換時の指定品詞名配列へのポインタ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_nobi_conv_with_hinsi_name(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop, nhinsi, hname)
register struct wnn_buf *buf;
int ichbn_len, use_maep, ich_shop, nhinsi;
register int bun_no, bun_no2;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
/*    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5) || nhinsi == 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    } */
    if(nhinsi) {
	hsize = abs(nhinsi);
	hno = (int *)malloc(hsize * sizeof(int));
	for(i = 0; i < hsize; i++) {
	    _Sstrcpy(tmp, hname[i]);
	    if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
		free((char *)hno);
		UnlockMutex(&BUF_LOCK(buf));
		return(-1);
	    }
	}
    }

    if(nobi_conv_sub(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop,
		     nhinsi, hno, 0) == -1) {
	if(nhinsi) free((char *)hno);
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(nhinsi) free((char *)hno);
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_nobi_conv_with_hinsi_name */

/*:::DOC_START
 *
 *    Function Name: jl_fi_nobi_conv
 *    Description  : ＦＩ延び変換を行う
 *    Parameter    :
 *         buf :       (InOut) バッファへのポインタ
 *         bun_no :    (In) 変換文節の先頭文節番号
 *         ichbn_len : (In) 第一文節目の長さ
 *         bun_no2 :   (In) 変換文節の最終文節の直後の文節番号
 *         use_maep :  (In) 前後の接続を（使う／否）フラグ
 *         ich_shop :  (In) 一文節目を（小文節／大文節）変換するフラグ
 *
 *    Return value : -1==ERROR, else 変換文節数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fi_nobi_conv(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop)
register struct wnn_buf *buf;
int ichbn_len, use_maep, ich_shop;
register int bun_no, bun_no2;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }

    if(nobi_conv_sub(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop,
                     0, NULL, 1) == -1) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_fi_nobi_conv */

/*:::DOC_START
 *
 *    Function Name: nobi_conv_sub
 *    Description  : 延び変換のサブルーチン関数
 *    Parameter    :
 *         buf :       (InOut) バッファへのポインタ
 *         bun_no :    (In) 変換文節の先頭文節番号
 *	   ichbn_len : (In) 第一文節目の長さ
 *         bun_no2 :   (In) 変換文節の最終文節の直後の文節番号
 *         use_maep :  (In) 前後の接続を（使う／否）フラグ
 *	   ich_shop :  (In) 一文節目を（小文節／大文節）変換するフラグ
 *         nhinsi :    (In) 品詞指定変換時の指定品詞数
 *         hlist :     (In) 品詞指定変換時の指定品詞番号配列へのポインタ
 *         fi_flag :   (In) 使用したＦＩ関係情報を（受け取らない／
 *                         受け取る）フラグ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
nobi_conv_sub(buf, bun_no, ichbn_len, bun_no2, use_maep, ich_shop, nhinsi, hlist, fi_flag)
register struct wnn_buf *buf;
int ichbn_len, use_maep, ich_shop, nhinsi, *hlist, fi_flag;
register int bun_no, bun_no2;
{
    w_char yomi[LENGTHCONV], ytmp;
    int ret;
    int len1;
    register WNN_BUN *b1;  /* 学習がうまくいくように変更しました。H.T. */

    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;
    
    len1 = jl_get_yomi_body((WNN_BUF_MT *)buf, bun_no, bun_no2, yomi);
    ytmp = yomi[ichbn_len];
    if(len1 < ichbn_len){
        ichbn_len = len1;
    }
    yomi[ichbn_len] = 0;

    if(buf->bun[bun_no]->nobi_top != 1){  /* need to add down_bnst */
        if(buf->bun[bun_no]) add_down_bnst((WNN_BUF_MT *)buf, bun_no,
                                           buf->bun[bun_no]);
        if(bun_no + 1 < buf->bun_suu){
            add_down_bnst((WNN_BUF_MT *)buf, bun_no, buf->bun[bun_no + 1]);
	                /* 全て bun_no の down_bnst に加えるように変更 */
        }
    }
    b1 = buf->down_bnst[bun_no];
    buf->down_bnst[bun_no] = NULL;
    free_down((WNN_BUF_MT *)buf, bun_no, bun_no2);
    
    if((ret = tan_conv1((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2,
			use_maep & WNN_USE_MAE, ich_shop,
			0, nhinsi, hlist)) == -1)
        return(-1);

    yomi[ichbn_len] = ytmp;    
    if(ytmp){
        int maep;
        if(ich_shop){
            maep = use_maep & ~WNN_USE_MAE;
        }else{
            maep = use_maep | WNN_USE_MAE;
        }
        if(ren_conv1((WNN_BUF_MT *)buf, yomi + ichbn_len, ret, ret,
                     maep, 0, 0, NULL, fi_flag) == -1)
	    return(-1);
    }
    buf->bun[bun_no]->nobi_top = 1;
    buf->down_bnst[bun_no] = b1;
    return(0);
} /* End of nobi_conv_sub */

int
jl_nobi_conv_e2(buf, env, bun_no, ichbn_len, bun_no2, use_maep, ich_shop)
register struct wnn_buf *buf;
struct wnn_env *env;
int ichbn_len, use_maep, ich_shop;
register int bun_no, bun_no2;
{
    w_char yomi[LENGTHCONV], ytmp;
    int ret;
    int len1;
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;
    
    len1 = jl_get_yomi_body((WNN_BUF_MT *)buf, bun_no, bun_no2, yomi);
    ytmp = yomi[ichbn_len];
    if(len1 < ichbn_len){
	ichbn_len = len1;
    }
    yomi[ichbn_len] = 0;

    if(buf->bun[bun_no]->nobi_top != 1){  /* need to add down_bnst */
	if(buf->bun[bun_no]) add_down_bnst((WNN_BUF_MT *)buf, bun_no,
					   buf->bun[bun_no]);
	if(bun_no + 1 < buf->bun_suu){
	    if(ichbn_len < jl_yomi_len_body((WNN_BUF_MT *)buf, bun_no,
					    bun_no + 1)){
		add_down_bnst((WNN_BUF_MT *)buf, bun_no + 1,
			      buf->bun[bun_no + 1]);
		free_down((WNN_BUF_MT *)buf, bun_no + 2, bun_no2);
	    }else{
		add_down_bnst((WNN_BUF_MT *)buf, bun_no, buf->bun[bun_no + 1]);
		free_down((WNN_BUF_MT *)buf, bun_no + 1, bun_no2);
	    }
	}
    }

    if((ret = tan_conv1((WNN_BUF_MT *)buf, yomi, bun_no, bun_no2,
			use_maep & WNN_USE_MAE, ich_shop, 0, 0, NULL)) == -1){
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }

    buf->env = env;

    yomi[ichbn_len] = ytmp;    
    if(ytmp){
	int maep;
	if(ich_shop){
	    maep = use_maep & ~WNN_USE_MAE;
	}else{
	    maep = use_maep | WNN_USE_MAE;
	}
	if(ren_conv1((WNN_BUF_MT *)buf, yomi + ichbn_len, ret, ret,
		     maep, 0, 0, NULL, 0) == -1){
	    UnlockMutex(&BUF_LOCK(buf));
	    return(-1);
	}
    }
    buf->bun[bun_no]->nobi_top = 1;
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));

    return x;
}

int
jl_kill(buf, bun_no, bun_no2)
struct wnn_buf *buf;
register int bun_no, bun_no2;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(0);
    }
    if(bun_no2 < bun_no || bun_no2 < 0) bun_no2 = buf->bun_suu;
    free_zenkouho((WNN_BUF_MT *)buf);     /* toriaezu */
    free_down((WNN_BUF_MT *)buf, bun_no, bun_no2);
    free_bun((WNN_BUF_MT *)buf, bun_no, bun_no2);
    bcopy((char *)&buf->bun[bun_no2], (char *)&buf->bun[bun_no],
	 (buf->bun_suu - bun_no2) * sizeof(WNN_BUN *));
    bcopy((char *)&buf->down_bnst[bun_no2], (char *)&buf->down_bnst[bun_no],
	 (buf->bun_suu - bun_no2) * sizeof(WNN_BUN *));
    buf->bun_suu -= bun_no2 - bun_no;
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho(buf, bun_no, use_maep, uniq_level)
register struct wnn_buf *buf;
int bun_no, use_maep, uniq_level;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    x = zen_conv_sho1(buf, bun_no, use_maep, uniq_level, 0, 0, NULL);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
zen_conv_sho1(buf, bun_no, use_maep, uniq_level, fuku, nhinsi, hlist)
register struct wnn_buf *buf;
int bun_no, use_maep, uniq_level, fuku, nhinsi, *hlist;
{
    register struct wnn_buf_mt *buf_m = (WNN_BUF_MT *)buf;
    int cnt;
    w_char yomi[LENGTHBUNSETSU], yomi1[LENGTHBUNSETSU];
    struct wnn_sho_bunsetsu *sp;
    register int k;
    int x;
    int nobi_top;

    jl_get_yomi_body(buf_m, bun_no, bun_no + 1, yomi);
    if (use_maep & WNN_USE_MAE && bun_no > 0) {
	dumbhinsi = buf->bun[bun_no - 1]->hinsi;
	jl_get_yomi_body(buf_m, bun_no - 1, bun_no, yomi1);
	mae_fzk = yomi1 + buf->bun[bun_no - 1]->jirilen;
    } else {
	dumbhinsi = WNN_BUN_SENTOU;
	mae_fzk = (w_char *)0;
    }
    if(use_maep & WNN_USE_ATO && bun_no + 1 < buf->bun_suu){
	syuutanv = buf->bun[bun_no+1]->kangovect;
	syuutanv1 = WNN_VECT_KANZEN;
	buf->zenkouho_endvect = syuutanv;
    }else{
	syuutanv = WNN_VECT_KANZEN;
	syuutanv1 = WNN_VECT_NO;
	if(bun_no + 1 < buf->bun_suu){
	    buf->bun[bun_no + 1]->dai_top = 1;
	}
	buf->zenkouho_endvect = -1;
    }

    if(!(buf->env)) return(-1);
    LockMutex(&(envmt->env_lock));
    if(fuku == 0 && nhinsi == 0) {
	if(buf->bun[bun_no]->fukugou == 0 && buf->bun[bun_no]->num_hinsi == 0) {
	    if((cnt = js_kanzen_sho(buf->env, yomi, dumbhinsi, mae_fzk,
				    syuutanv, syuutanv1, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf_m);
		if_dead_disconnect_b(buf_m);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    fuku = buf->bun[bun_no]->fukugou;
	    nhinsi = buf->bun[bun_no]->num_hinsi;
	    hlist = buf->bun[bun_no]->hinsi_list;
	    if((cnt = js_henkan_with_data(buf->env, fuku, nhinsi, hlist,
			  WNN_KANZEN_SHO, yomi, dumbhinsi, mae_fzk, syuutanv,
			  syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf_m);
		if_dead_disconnect_b(buf_m);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	}
    } else {
	if((cnt = js_henkan_with_data(buf->env, fuku, nhinsi, hlist,
		      WNN_KANZEN_SHO, yomi, dumbhinsi, mae_fzk, syuutanv,
		      syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0){
	    buf_wnn_errorno_copy(buf_m);
	    if_dead_disconnect_b(buf_m);
	    UnlockMutex(&(envmt->env_lock));
	    return(-1);
	}
    }

    sp = (struct wnn_sho_bunsetsu *)buf_rb.buf;
    free_zenkouho(buf_m);
    nobi_top = buf->bun[bun_no]->nobi_top;
    /* 大文節次候補を取ったあと、品詞指定変換（小文節）をして全候補数 (cnt) が
       0 の場合空の次候補リストが表示されるので、チェックを追加して正しく
       処理されるようにする。06/05/96  H.Kishiba */
    if((buf->bun[bun_no]->from_zenkouho & 1) == BUN || cnt == 0){
	set_sho(buf->bun[bun_no], &buf->zenkouho[0]);
	buf->zenkouho_suu = 1;
				/* Connection information of Old bunsetsu
				 * May not be correct.
				 */
	k = get_c_jikouho(sp, cnt, buf->bun[bun_no]);
	if(k >= 0){
	    buf->zenkouho[0]->dai_top = (sp[k].status == WNN_CONNECT)? 0:1;
	    buf->zenkouho[0]->dai_end = (sp[k].status_bkwd == WNN_CONNECT_BK)? 0:1;
	}
	if(uniq_level || k < 0){
	    insert_sho(buf_m, ZENKOUHO, -1, -1, sp, cnt, uniq_level, fuku, nhinsi, hlist);
	}else{
	    insert_sho(buf_m, ZENKOUHO, -1, -1, sp, k, uniq_level, fuku, nhinsi, hlist);
	    insert_sho(buf_m, ZENKOUHO, -1, -1, sp + k + 1, cnt - k - 1,
		       uniq_level, fuku, nhinsi, hlist);
	}
	buf->c_zenkouho = 0;
    }else{
	insert_sho(buf_m, ZENKOUHO, -1, -1, sp, cnt, uniq_level, fuku, nhinsi, hlist);
	k = get_c_jikouho_from_zenkouho(buf_m, buf->bun[bun_no]);
	if(k < 0){
	    k = 0;	/* Only when the kouho has been removed from dict. */
	}
	buf->c_zenkouho = k;
    }
    buf->zenkouho_bun = bun_no;
    buf->zenkouho_end_bun = bun_no + 1;
    buf->zenkouho_daip = SHO;
    for(k = 0 ; k < buf->zenkouho_suu; k++){
	/* 次候補リストの先頭の候補に対しては必ず今ビットを落とすようにする
	   （文節長最終使用最優先） */
	if(k == 0 ||
	   (buf->zenkouho[k]->ima && buf->zenkouho[k]->dic_no != -1)){
	    add_down_bnst(buf_m, bun_no, buf->zenkouho[k]);
	}
	/*
	 * 文節伸ばし/縮めを行った後次候補を取った場合には、次候補の文節情報
	 * にも文節伸ばし/縮めの情報をつけておく。文節切り学習で使用する。
	 */
	if (nobi_top) buf->zenkouho[k]->nobi_top = 1;
    }
    x = buf->c_zenkouho;
    UnlockMutex(&(envmt->env_lock));
    return x;
}

int
jl_zenkouho_hinsi_flag(buf, bun_no, use_maep, uniq_level, hinsi_op)
register struct wnn_buf *buf;
int bun_no, use_maep, uniq_level, hinsi_op;
{
    int x, hno;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(hinsi_op == WNN_ZIP)
        _Sstrcpy(tmp, WNN_HINSI_ZIPCODE);
    else if(hinsi_op == WNN_TEL)
        _Sstrcpy(tmp, WNN_HINSI_TELNO);
    else if(hinsi_op == WNN_TANKAN)
        _Sstrcpy(tmp, WNN_HINSI_TANKAN);
    else {
	UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if((hno = jl_hinsi_number_e(buf->env, tmp)) == -1) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    x = zen_conv_sho1(buf, bun_no, use_maep, uniq_level, 0, 1, &hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_with_hinsi_name(buf, bun_no, use_maep, uniq_level, nhinsi, hname)
register struct wnn_buf *buf;
int bun_no, use_maep, uniq_level, nhinsi;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
/*    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5) || nhinsi == 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    } */
    if(nhinsi){
	hsize = abs(nhinsi);
	hno = (int *)malloc(hsize * sizeof(int));
	for(i = 0; i < hsize; i++) {
	    _Sstrcpy(tmp, hname[i]);
	    if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
		free((char *)hno);
		UnlockMutex(&BUF_LOCK(buf));
		return(-1);
	    }
	}
    }
    x = zen_conv_sho1(buf, bun_no, use_maep, uniq_level, 0, nhinsi, hno);
    if(nhinsi) free((char *)hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_dai(buf, bun_no, bun_no2, use_maep, uniq_level)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    x = zen_conv_dai1(buf, bun_no, bun_no2, use_maep, uniq_level, 0, 0, NULL);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
zen_conv_dai1(buf, bun_no, bun_no2, use_maep, uniq_level, fuku, nhinsi, hlist)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level, fuku, nhinsi, *hlist;
{
    register struct wnn_buf_mt *buf_m = (WNN_BUF_MT *)buf;
    int cnt;
    w_char yomi[LENGTHBUNSETSU], yomi1[LENGTHBUNSETSU];
    struct wnn_dai_bunsetsu *dp;
    int tmp;
    register int k;
    int x;
    int nobi_top;
    
    if(bun_no2 > (tmp = dai_end(buf_m, bun_no)) ||
	bun_no2 < 0) bun_no2 = tmp;
    jl_get_yomi_body(buf_m, bun_no, bun_no2, yomi);
    if (use_maep & WNN_USE_MAE && bun_no > 0) {
	dumbhinsi = buf->bun[bun_no - 1]->hinsi;
	jl_get_yomi_body(buf_m, bun_no - 1, bun_no, yomi1);
	mae_fzk = yomi1 + buf->bun[bun_no - 1]->jirilen;
    } else {
	dumbhinsi = WNN_BUN_SENTOU;
	mae_fzk = (w_char *)0;
    }
    if(use_maep & WNN_USE_ATO && bun_no2 < buf->bun_suu){
	syuutanv = buf->bun[bun_no2]->kangovect;
	syuutanv1 = WNN_VECT_KANZEN; 
	buf->zenkouho_endvect = syuutanv;
    }else{
	syuutanv = WNN_VECT_KANZEN;
	syuutanv1 = WNN_VECT_NO;
	if(bun_no2 < buf->bun_suu){
	    buf->bun[bun_no2]->dai_top = 1;
	}
	buf->zenkouho_endvect = -1;
    }
    if(!(buf->env)) return(-1);
    LockMutex(&(envmt->env_lock));
    if(fuku == 0 && nhinsi == 0) {
	if(buf->bun[bun_no]->fukugou == 0 && buf->bun[bun_no]->num_hinsi == 0) {
	    if((cnt = js_kanzen_dai(buf->env, yomi, dumbhinsi, mae_fzk,
				    syuutanv, syuutanv1, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf_m);
		if_dead_disconnect_b(buf_m);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    fuku = buf->bun[bun_no]->fukugou;
	    nhinsi = buf->bun[bun_no]->num_hinsi;
	    hlist = buf->bun[bun_no]->hinsi_list;
	    if((cnt = js_henkan_with_data(buf->env, fuku, nhinsi, hlist,
			  WNN_KANZEN_DAI, yomi, dumbhinsi, mae_fzk, syuutanv,
			  syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0) {
		buf_wnn_errorno_copy(buf_m);
                if_dead_disconnect_b(buf_m);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
            }
	}
    } else {
	if((cnt = js_henkan_with_data(buf->env, fuku, nhinsi, hlist,
		      WNN_KANZEN_DAI, yomi, dumbhinsi, mae_fzk, syuutanv,
		      syuutanv1, WNN_VECT_BUNSETSU, &buf_rb)) < 0) {
	    buf_wnn_errorno_copy(buf_m);
	    if_dead_disconnect_b(buf_m);
	    UnlockMutex(&(envmt->env_lock));
	    return(-1);
	}
    }

    dp = (struct wnn_dai_bunsetsu *)buf_rb.buf;

    free_zenkouho(buf_m);
		/* Wander if it is OK, that is, only when all the
		 * zenkouho's are got from zenkouho_dai, we need not move
		 * the current dai-bunsetsu to the top of zenkouho's
		 */
    for(k = bun_no; k < bun_no2; k++){
	if(buf->bun[k]->from_zenkouho != ZENKOUHO_DAI)break;
    }
    if (k >= bun_no2) k--;
    nobi_top = buf->bun[k]->nobi_top;
    if(k != bun_no2){		/* move the current to the top. */
	make_space_for(buf_m, ZENKOUHO, buf->zenkouho_suu, buf->zenkouho_suu,
		       bun_no2 - bun_no);
	set_dai(&buf->bun[bun_no], &buf->zenkouho[0], bun_no2 - bun_no);
	buf->zenkouho_dai[0] = 0;
	buf->zenkouho_dai[1] = bun_no2 - bun_no;
	buf->zenkouho_dai_suu = 1;
	buf->zenkouho_suu = bun_no2 - bun_no;
	k = get_c_jikouho_dai(dp, cnt, buf->bun, bun_no);
	if(k >= 0){
	    buf->zenkouho[0]->dai_top = 
		(dp[k].sbn->status == WNN_CONNECT)? 0:1;
	    buf->zenkouho[bun_no2-bun_no-1]->dai_end = 
		(dp[k].sbn[dp[k].sbncnt-1].status_bkwd == WNN_CONNECT_BK)? 0:1;
	    /* KURI *//* USO*?*/
	} else if (cnt == 0) {
	    /* 「・」は候補数が 0 なので、dai_top, dai_end を
	       強制的に 1 にする */
	    buf->zenkouho[0]->dai_top = 1;
	    buf->zenkouho[bun_no2-bun_no-1]->dai_end = 1;
	}
	if(uniq_level || k < 0){
	    insert_dai(buf_m, ZENKOUHO, -1, -1, dp, cnt, uniq_level, fuku, nhinsi, hlist);
	}else{
	    insert_dai(buf_m, ZENKOUHO, -1, -1, dp, k, uniq_level, fuku, nhinsi, hlist);
	    insert_dai(buf_m, ZENKOUHO, -1, -1, dp + k + 1, cnt - k - 1,
		       uniq_level, fuku, nhinsi, hlist);
	}
	buf->c_zenkouho = 0;
    }else{
	insert_dai(buf_m, ZENKOUHO, -1, -1, dp, cnt, uniq_level, fuku, nhinsi, hlist);
	k = get_c_jikouho_from_zenkouho_dai(buf_m, buf->bun[bun_no]);
	if(k < 0){
	    k = 0;	/* Only when the kouho has been removed from dict. */
	}
	buf->c_zenkouho = k;
    }
    buf->zenkouho_bun = bun_no;
    buf->zenkouho_end_bun = bun_no2;
    buf->zenkouho_daip = DAI;
    for(k = 0 ; k < buf->zenkouho_suu; k++){
        /* 次候補リストの先頭の候補に対しては必ず今ビットを落とすようにする
           （文節長最終使用最優先） */
        if(k == 0 ||
	   (buf->zenkouho[k]->ima && buf->zenkouho[k]->dic_no != -1)) {
	    add_down_bnst(buf_m, bun_no, buf->zenkouho[k]);
	}
	/*
	 * 文節伸ばし/縮めを行った後次候補を取った場合には、次候補の文節情報
	 * にも文節伸ばし/縮めの情報をつけておく。文節切り学習で使用する。
	 */
	if (nobi_top) buf->zenkouho[k]->nobi_top = 1;
    }
    x = buf->c_zenkouho;
    UnlockMutex(&(envmt->env_lock));
    return x;
}

int
jl_zenkouho_dai_hinsi_flag(buf, bun_no, bun_no2, use_maep, uniq_level, hinsi_op)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level, hinsi_op;
{
    int x, hno;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(hinsi_op == WNN_ZIP)
        _Sstrcpy(tmp, WNN_HINSI_ZIPCODE);
    else if(hinsi_op == WNN_TEL)
        _Sstrcpy(tmp, WNN_HINSI_TELNO);
    else if(hinsi_op == WNN_TANKAN)
        _Sstrcpy(tmp, WNN_HINSI_TANKAN);
    else {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if((hno = jl_hinsi_number_e(buf->env, tmp)) == -1) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    x = zen_conv_dai1(buf, bun_no, bun_no2, use_maep, uniq_level, 0, 1, &hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_dai_with_hinsi_name(buf, bun_no, bun_no2, use_maep, uniq_level, nhinsi, hname)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level, nhinsi;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
/*    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5) || nhinsi == 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
	} */
    if(nhinsi){
        hsize = abs(nhinsi);
        hno = (int *)malloc(hsize * sizeof(int));
        for(i = 0; i < hsize; i++) {
            _Sstrcpy(tmp, hname[i]);
            if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
                free((char *)hno);
                UnlockMutex(&BUF_LOCK(buf));
                return(-1);
            }
        }
    }
    x = zen_conv_dai1(buf, bun_no, bun_no2, use_maep, uniq_level, 0, nhinsi, hno);
    if(nhinsi) free((char *)hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_set_jikouho(buf, offset)
register struct wnn_buf *buf;
register int offset;
{
    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(buf->zenkouho_suu <= 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(buf->zenkouho_daip == DAI){
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    offset = (offset + buf->zenkouho_suu) % buf->zenkouho_suu;
    if(buf->zenkouho_bun+1 < buf->bun_suu && buf->zenkouho_endvect != -1)
	buf->bun[buf->zenkouho_bun+1]->dai_top = buf->zenkouho[offset]->dai_end;
    free_sho((WNN_BUF_MT *)buf, &buf->bun[buf->zenkouho_bun]);
    set_sho(buf->zenkouho[offset], &buf->bun[buf->zenkouho_bun]);
    buf->c_zenkouho = offset;
    UnlockMutex(&BUF_LOCK(buf));
    return(offset);
}


int
jl_set_jikouho_dai(buf, offset)
register struct wnn_buf *buf;
int offset;
{
    register int st, end, bun, k;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(buf->zenkouho_suu <= 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(buf->zenkouho_daip == SHO){
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    offset = (offset + buf->zenkouho_dai_suu) % buf->zenkouho_dai_suu;
    if(buf->zenkouho_end_bun < buf->bun_suu && buf->zenkouho_endvect != -1)
	buf->bun[buf->zenkouho_end_bun]->dai_top =
		buf->zenkouho[buf->zenkouho_dai[offset+1]-1]->dai_end;
    free_bun((WNN_BUF_MT *)buf, buf->zenkouho_bun, buf->zenkouho_end_bun);
    st = buf->zenkouho_dai[offset];
    end = buf->zenkouho_dai[offset + 1];
    make_space_for((WNN_BUF_MT *)buf, BUN, buf->zenkouho_bun,
		   buf->zenkouho_end_bun, end - st);
    for(bun = buf->zenkouho_bun, k = st; k < end;){
	set_sho(buf->zenkouho[k++], &buf->bun[bun++]);
    }
    buf->zenkouho_end_bun = buf->zenkouho_bun + end - st;
    buf->c_zenkouho = offset;
    UnlockMutex(&BUF_LOCK(buf));
    return(offset);
}

/*:::DOC_START
 *
 *    Function Name: do_autolearning
 *    Description  : 自動学習を行う
 *		     js_auto_word_add()を呼ぶ
 *    Parameter    :
 *         buf :      (In) wnn_buf構造体へのポインタ
 *         type :     (In) 学習するタイプ(カタカナ/文節切り)
 *         yomi :     (In) 読み
 *         kanji :    (In) 漢字
 *         hinsi :    (In) 品詞
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *	15-May-96: 岸場: js_autolearning_word_add() がエラーでも env の
 *			 学習設定は変更しない
 *
 *:::DOC_END
 */
static int
do_autolearning(env, type, yomi, kanji, hinsi)
struct wnn_env *env;
int type;
w_char *yomi, *kanji;
int hinsi;
{
    int ret;

    if ((ret = js_autolearning_word_add(env, type, yomi, kanji, NULL, hinsi,
					0)) == -1) {
	if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
	    jl_disconnect_body(env);
	}
	return(-1);
    }
    return(ret);
}

#ifdef KOREAN
/* 単漢学習
 * 単漢字を選んだ場合は、その前の漢字文字列とあわせて辞書登録する。
 * 「注文書」で、「注文」が辞書にあって、「書」が、単漢の場合は、「注文書」
 * を辞書登録する。
 * 今は、品詞は名詞として登録している。
 */
static int
tankan_auto_learning(buf, k, hinsi)
register struct wnn_buf *buf;
int k;
int hinsi;
{
    int i, j;
    w_char tmp[LENGTHYOMI];
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];

    for (i = k; i > 0; i--) {
	if (buf->bun[i]->dic_no == -1) {
	    i++;
	    break;
	}
	wnn_area(buf->bun[i], tmp, WNN_KANJI);
	for (j = 0; j < buf->bun[i]->kanjilen; j++) {
	    if (!ishanja(tmp[j])) {
		i++;
		goto _find;;
	    }
	}
    }
_find:

    yomi[0] = kanji[0] = 0;
    for ( ; i <= k; i++) {
	wnn_area(buf->bun[i], tmp, WNN_YOMI);
	wnn_Strncat(yomi, tmp, buf->bun[i]->jirilen);
	wnn_area(buf->bun[i], tmp, WNN_KANJI);
	wnn_Strncat(kanji, tmp, buf->bun[i]->kanjilen);
    }

    return(do_autolearning(buf->env, WNN_MUHENKAN_LEARNING, yomi, kanji,
			   hinsi));
}

/* ハングル学習
 * 変換時に第一候補として漢字が選ばれたが、ハングルを確定した場合にそのハ
 * ングルを登録する。
 * 品詞はハングルとして登録している
 */
static int
hangul_auto_learning(buf, k, hinsi, bun_no2)
register struct wnn_buf *buf;
int k;
int hinsi;
int bun_no2;
{
    int i, j;
    int find;
    w_char tmp[LENGTHYOMI];
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];

    yomi[0] = kanji[0] = 0;
    find = 0;
    for (i = k; i < bun_no2; i++) {
	wnn_area(buf->bun[i], tmp, WNN_KANJI);
	for (j = 0; j < buf->bun[i]->kanjilen; j++) {
	    if (!ishangul(tmp[j])) {
		if (tmp[j] != ' ' && tmp[j] != JSPACE)
		    goto _find_hangul;
		tmp[j] = 0;
		find = 1;
		break;
	    }
	}
	wnn_Strncat(kanji, tmp, j);
	wnn_area(buf->bun[i], tmp, WNN_YOMI);
	wnn_Strncat(yomi, tmp, j);
	if (find == 1)	break;
    }
_find_hangul:

    return(do_autolearning(buf->env, WNN_MUHENKAN_LEARNING, yomi, kanji,
			   hinsi));
}

/* 付属語学習
 * 自立語＋ハングルを確定した場合に、そのハングル文字列をその自立語に接続
 * 可能な付属語として登録する。
 * 今は、疑似文節の「付属語」品詞として登録している。
 */
static int
fuzokugo_auto_learning(buf, k, hinsi, bun_no2)
register struct wnn_buf *buf;
int k;
int hinsi;
int bun_no2;
{
    int i, j;
    int find;
    w_char tmp[LENGTHYOMI];
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];

    if (k <= 0 || buf->bun[k-1]->dic_no == -1)
	return (0);
    wnn_area(buf->bun[k-1], tmp, WNN_KANJI);
    for (j = 0; j < buf->bun[k-1]->kanjilen; j++) {
	if (!ishanja(tmp[j]))
	    return(0);
    }

    yomi[0] = kanji[0] = 0;
    find = 0;
    for (i = k; i < bun_no2; i++) {
	wnn_area(buf->bun[i], tmp, WNN_KANJI);
	for (j = 0; j < buf->bun[i]->kanjilen; j++) {
	    if (!ishangul(tmp[j])) {
		if (tmp[j] != ' ' && tmp[j] != JSPACE)
		    goto _find_fzk;
		tmp[j] = 0;
		find = 1;
		break;
	    }
	}
	wnn_Strncat(kanji, tmp, j);
	wnn_area(buf->bun[i], tmp, WNN_YOMI);
	wnn_Strncat(yomi, tmp, j);
	if (find == 1)	break;
    }
_find_fzk:

    return(do_autolearning(buf->env, WNN_BUNSETSUGIRI_LEARNING, yomi, kanji,
			   hinsi));
}
#endif /* KOREAN */

static int
muhenkan_auto_learning(buf, wb)
struct wnn_buf *buf;
register WNN_BUN *wb;
{
    int hinsi;
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];

    wnn_area(wb, yomi, WNN_YOMI);
    wnn_area(wb, kanji, WNN_KANJI);
    yomi[wb->jirilen] = (w_char)0;
    kanji[wb->real_kanjilen] = (w_char)0;
    if(wb->entry == WNN_IKEIJI_ENTRY)
        hinsi = wb->hinsi;
    else
        hinsi = wnn_meisi;
    return(do_autolearning(buf->env, WNN_MUHENKAN_LEARNING, yomi, kanji,
			   hinsi));
}

static int
bunsetsugiri_auto_learning(buf, wb, bun_no, bun_no2)
register struct wnn_buf *buf;
register WNN_BUN *wb;
int bun_no, bun_no2;
{
    register int i;
    register WNN_BUN *wb1;
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];
    int yomilen, kanjilen, fuzokugolen, found_dai_top;

    wnn_area(wb, yomi, WNN_YOMI);
    wnn_area(wb, kanji, WNN_KANJI);
    yomilen = wb->yomilen;
    kanjilen = wb->kanjilen;
    wb1 = buf->bun[bun_no+1];
    wnn_area(wb1, &yomi[yomilen], WNN_YOMI);
    wnn_area(wb1, &kanji[kanjilen], WNN_KANJI);
    yomilen += wb1->yomilen;
    kanjilen += wb1->kanjilen;
    fuzokugolen = wb1->yomilen - wb1->jirilen;
    yomi[yomilen - fuzokugolen] = (w_char)0;
    kanji[kanjilen - fuzokugolen] = (w_char)0;
    return(do_autolearning(buf->env, WNN_BUNSETSUGIRI_LEARNING, yomi, kanji,
			   wb1->hinsi));
}

static int
rendaku_learning(buf, mode, wb1, bun_no, bun_no2)
register struct wnn_buf *buf;
register WNN_BUN *wb1;
int mode, bun_no, bun_no2;
{
    register int i;
    register WNN_BUN *wb;
    w_char yomi[LENGTHYOMI];
    w_char kanji[LENGTHKANJI];
    int yomilen, kanjilen, fuzokugolen, found_dai_top;

    wb = buf->bun[bun_no];
    wnn_area(wb, yomi, WNN_YOMI);
    wnn_area(wb, kanji, WNN_KANJI);
    yomilen = wb->yomilen;
    kanjilen = wb->kanjilen;
    wnn_area(wb1, &yomi[yomilen], WNN_YOMI);
    wnn_area(wb1, &kanji[kanjilen], WNN_KANJI);
    yomilen += wb1->yomilen;
    kanjilen += wb1->kanjilen;
    fuzokugolen = wb1->yomilen - wb1->jirilen;
    yomi[yomilen - fuzokugolen] = (w_char)0;
    kanji[kanjilen - fuzokugolen] = (w_char)0;
    if (mode != WNN_DIC_RW) {
	if (js_temporary_word_add(buf->env, yomi, kanji, NULL, wnn_meisi, 0) == -1) {
	    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
		jl_disconnect_body(buf->env);
	    }
	    return(-1);
	}
	return(0);
    }
    return(do_autolearning(buf->env, WNN_BUNSETSUGIRI_LEARNING, yomi, kanji,
			   wnn_meisi));
}

/*:::DOC_START
 *
 *    Function Name: jl_update_hindo
 *    Description  : 確定文節から頻度情報（今ビット・頻度）の更新と
 *		     jlib で判断できる学習処理を行う
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *         bun_no :   (In) 確定した文節の先頭文節番号
 *         bun_no2 :  (In) 確定した文節の最終文節の直後の文節番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_update_hindo(buf, bun_no, bun_no2)  
register struct wnn_buf *buf;
int bun_no, bun_no2;
{
    register int k;
    register WNN_BUN *wb;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0 || !(buf->env)) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;

    LockMutex(&(envmt->env_lock));

    if(
       /* 今ビットを落とすべき候補の今ビットを落とす */
       set_ima_off(buf, bun_no, bun_no2, 0) == -1 ||
       /* jlib 内で判断できる学習処理を行う */
       optimize_in_lib(buf, bun_no, bun_no2) == -1) {
	buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
	if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD) goto ERROR_RET;
    }

    /* 確定した候補の今ビット・頻度を上げる */
    for(k = bun_no; k < bun_no2; k++) {
        if(buf->bun[k]->hindo_updated != 1) continue;
        buf->bun[k]->hindo_updated = 2;
        wb = buf->bun[k];
	if(js_hindo_set(buf->env, wb->dic_no, wb->entry,
			WNN_IMA_ON, WNN_HINDO_INC) == -1){
	    buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
	    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD) goto ERROR_RET;
	}
    }

    /* 学習情報自動セーブ確定回数に達したら、自動セーブを行う */
    kakutei_count ++;
    if(buf->env->autosave > 0 && kakutei_count >= buf->env->autosave) {
	jl_dic_save_all_e_body(buf->env);
	kakutei_count = 0;
    }

    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return(0);
 
 ERROR_RET:
    jl_disconnect_body(buf->env);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return(-1);
} /* End of jl_update_hindo */

/*:::DOC_START
 *
 *    Function Name: jl_optimize_fi
 *    Description  : 確定文節から頻度情報（今ビット・頻度）の更新と、
 *                   Wnn5 で追加した学習処理とＦＩ学習処理を行う
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *         bun_no :   (In) 確定した文節の先頭文節番号
 *         bun_no2 :  (In) 確定した文節の最終文節の直後の文節番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_optimize_fi(buf, bun_no, bun_no2)
register struct wnn_buf *buf;
int bun_no, bun_no2;
{
    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0 || !(buf->env)) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) {
	UnlockMutex(&BUF_LOCK(buf));
	return(jl_update_hindo(buf, bun_no, bun_no2));
    }
    if(bun_no2 >= buf->bun_suu || bun_no2 < 0) bun_no2 = buf->bun_suu;

    LockMutex(&(envmt->env_lock));

    if(
       /* 今ビットを落とすべき候補とＦＩ接続関係の今ビットを落とす */
       set_ima_off(buf, bun_no, bun_no2, 1) == -1 ||
       /* jlib 内で判断できる学習処理を行う */
       optimize_in_lib(buf, bun_no, bun_no2) == -1 ||
       /* server 内で判断する Wnn5 学習処理とＦＩ学習処理を行う */
       optimize_in_server(buf, bun_no, bun_no2) == -1) {
	buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
	if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD) goto ERROR_RET;
    }

    /* 学習情報自動セーブ確定回数に達したら、自動セーブを行う */
    kakutei_count ++;
    if(buf->env->autosave > 0 && kakutei_count >= buf->env->autosave) {
	jl_dic_save_all_e_body(buf->env);
	kakutei_count = 0;
    }

    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return(0);
ERROR_RET:
    jl_disconnect_body(buf->env);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return(-1);
} /* End of jl_optimize_fi */

/*:::DOC_START
 *
 *    Function Name: jl_reset_prev_bun
 *    Description  : 前確定文節情報を初期化する
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_reset_prev_bun(buf)
register struct wnn_buf *buf;
{
    int i;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(!(buf->env)) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
    }

    for(i = 0; i < WNN_PREV_BUN_SUU; i++) buf->prev_bun[i].dic_no = -2;

    UnlockMutex(&BUF_LOCK(buf));
    return(0);
} /* End of jl_reset_prev_bun */

/*:::DOC_START
 *
 *    Function Name: set_ima_off
 *    Description  : 変換に使用されなかった候補の今ビットを落とし、ＦＩ変換中に
 *		     使用したＦＩ接続関係の今ビットをすべて落とす
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *         bun_no :   (In) 確定した文節の先頭文節番号
 *         bun_no2 :  (In) 確定した文節の最終文節の直後の文節番号
 *         fi_flag :  (In) ＦＩ学習（しない／する）フラグ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
set_ima_off(buf, bun_no, bun_no2, fi_flag)  
register struct wnn_buf *buf;
int bun_no, bun_no2, fi_flag;
{
    register int k;
    register WNN_BUN *wb;

    /* 候補の今ビットを落とす */
    for(k = bun_no; k < bun_no2; k++){
        if(buf->bun[k]->hindo_updated == 1) continue;
        for(wb = buf->down_bnst[k]; wb; wb = wb->down){
            if(wb->bug == 1) break;
            wb->bug = 1;
            if(wb->dic_no != -1){
                if(js_hindo_set(buf->env, wb->dic_no, wb->entry,
                                WNN_IMA_OFF, WNN_HINDO_NOP) == -1) {
                    buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
                    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
                }
            }
        }
    }
    free_down((WNN_BUF_MT *)buf, bun_no, bun_no2);

    /* ＦＩ接続関係の今ビットを落とす */
    if(fi_flag) {
	if(js_set_fi_priority(buf->env, &(buf->fi_rb)) == -1) {
	    buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
	    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
	        return(-1);
	}
	/* ＦＩ接続関係管理構造体の初期化 */
	buf->fi_rb.num = 0;
    }

    return(0);
} /* End of set_ima_off */

/*:::DOC_START
 *
 *    Function Name: optimize_in_lib
 *    Description  : jlib 内で行う学習処理をする
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *         bun_no :   (In) 確定した文節の先頭文節番号
 *         bun_no2 :  (In) 確定した文節の最終文節の直後の文節番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
optimize_in_lib(buf, bun_no, bun_no2)
register struct wnn_buf *buf;
int bun_no, bun_no2;
{
    register int k;
    register WNN_BUN *wb;

    for(k = bun_no; k < bun_no2; k++){
        if(buf->bun[k]->hindo_updated == 1) continue;
        buf->bun[k]->hindo_updated = 1;
        wb = buf->bun[k];

#ifdef KOREAN
	if(!strncmp(js_get_lang(buf->env), WNN_K_LANG, 5)) {
	    /* 単漢学習 */
	    if ((wb->hinsi == kwnn_tankan) &&       /* Tankan */
		(buf->env->muhenkan_mode != WNN_DIC_RDONLY)) {
		if (tankan_auto_learning(buf, k, kwnn_meisi) == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
	    }
	    /* 間違って漢字に変換したのをハングル列として辞書に登録 */
	    if ((wb->from_zenkouho & 1) == ZENKOUHO &&
		wb->hinsi == kwnn_hangul && wb->dic_no == -1 &&
		                                /* Hangul */
		(buf->env->muhenkan_mode != WNN_DIC_RDONLY) ) {
		if (hangul_auto_learning(buf, k, kwnn_hangul, bun_no2) == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
                }
            }
	    /* 付属語学習 */
	    if (k > 0 && wb->hinsi == kwnn_hangul && wb->dic_no == -1 &&
		                               /* Hangul */
		(buf->env->bunsetsugiri_mode != WNN_DIC_RDONLY)) {
		if (fuzokugo_auto_learning(buf, k, kwnn_fuzokugo, bun_no2) == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
	    }
	} else
#endif /* KOREAN */
	{
	    /* ひらがな学習・カタカナ学習・異形字学習 */
	    if (((wb->dic_no == -1) &&
		 (buf->env->muhenkan_mode != WNN_DIC_RDONLY) &&
		 ((wb->entry == WNN_KATAKANA) || (wb->entry == WNN_HIRAGANA))&&
		 (wb->jirilen >= WNN_KATAKANA_LEARNING_LEN)) ||
		wb->entry == WNN_IKEIJI_ENTRY) {
		int entry;

		if ((entry = muhenkan_auto_learning(buf, wb)) == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
		wb->dic_no = WNN_MUHENKAN_DIC;
		wb->entry = entry;
	    }

	    /* 大文節学習 */
	    if (wb->dai_top && ((k + 1) < bun_no2) &&
		!buf->bun[k + 1]->dai_top) {
                if (rendaku_learning(buf, buf->env->bunsetsugiri_mode,
                                     buf->bun[k + 1], k, k+1) == -1) {
                    buf_wnn_errorno_copy(buf);
                    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
                }
	    } else
	    /* 連濁学習 */
	    if ((k > bun_no) && (wb->hinsi == wnn_rendaku) &&
		(buf->bun[k-1]->yomilen == buf->bun[k-1]->jirilen)) {
		if (rendaku_learning(buf, buf->env->bunsetsugiri_mode, wb, k-1, k)
		    == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
	    } else
	    /* 接頭語(お)学習 */
	    if (((k + 1) < bun_no2) && (wb->hinsi == wnn_settou)) {
		if (rendaku_learning(buf, buf->env->bunsetsugiri_mode, 
				     buf->bun[k + 1], k, k+1)
		    == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
	    } else
	    /* 文節切り学習 */
	    if (wb->nobi_top &&
		(buf->env->bunsetsugiri_mode != WNN_DIC_RDONLY) &&
		((k + 1) < bun_no2) &&
		(buf->bun[k+1]->hinsi != wnn_rendaku &&
		 buf->bun[k]->hinsi != wnn_settou)) {
		if (bunsetsugiri_auto_learning(buf, wb, k, bun_no2) == -1) {
		    buf_wnn_errorno_copy(buf);
		    if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD)
		        return(-1);
		}
	    }
	}
    }
    return(0);
} /* End of optimize_in_lib */

/*:::DOC_START
 *
 *    Function Name: optimize_in_server
 *    Description  : jserver 内で行う学習処理をする
 *    Parameter    :
 *         buf :     (In) バッファへのポインタ
 *         bun_no :  (In) 確定した文節の先頭文節番号
 *         bun_no2 : (In) 確定した文節の最終文節の直後の文節番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
optimize_in_server(buf, bun_no, bun_no2)
register struct wnn_buf *buf;
int bun_no, bun_no2;
{
    register int k, j;
    register WNN_BUN *wb;

    int nkouho, *dic, *entry, *ima, *hindo, *kmoji;
    w_char **kouho, *tmp;
    struct wnn_prev_bun *prev;

    /* 日本語のみをサポート */
    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5)) return(0);

    /* 前確定文節情報分を確定候補数に加える */
    nkouho = bun_no2 - bun_no + WNN_PREV_BUN_SUU;

    if ( (dic = (int *)malloc(nkouho * sizeof(int))) == NULL )
      return(-1);

    if ( (entry = (int *)malloc(nkouho * sizeof(int))) == NULL ) {
      free(dic);
      return(-1);
    }
    if ( (ima = (int *)malloc(nkouho * sizeof(int))) == NULL ) {
      free(dic);
      free(entry);
      return(-1);
    }
    if ( (hindo = (int *)malloc(nkouho * sizeof(int))) == NULL ) {
      free(dic);
      free(entry);
      free(ima);
      return(-1);
    }
    if ( (kmoji = (int *)malloc(nkouho * sizeof(int))) == NULL ) {
      free(dic);
      free(entry);
      free(ima);
      free(hindo);
      return(-1);
    }
    if ( (kouho = (w_char **)malloc(nkouho * sizeof(w_char *))) == NULL ) {
      free(dic);
      free(entry);
      free(ima);
      free(hindo);
      free(kmoji);
      return(-1);
    }
    if ( (tmp = (w_char *)malloc(nkouho * sizeof(w_char) * LENGTHKANJI)) == NULL ) {
      free(dic);
      free(entry);
      free(ima);
      free(hindo);
      free(kmoji);
      free(kouho);
      return(-1);
    }
    for(k = 0; k < nkouho; k++) {
	kouho[k] = tmp;
	tmp += LENGTHKANJI;
    }

    /* 前確定文節情報を確定文節情報に入れる */
    prev = buf->prev_bun;
    for(j = 0, k = WNN_PREV_BUN_SUU - 1; j < WNN_PREV_BUN_SUU; j++, k--) {
	dic[j] = prev[k].dic_no;
	entry[j] = prev[k].entry;
	ima[j] = WNN_HINDO_NOP;
	hindo[j] = WNN_HINDO_NOP;
	kmoji[j] = prev[k].real_kanjilen;
	wnn_Strcpy(kouho[j], prev[k].kouho);
    }
	
    for(k = WNN_PREV_BUN_SUU; k < nkouho; k++) {
	wb = buf->bun[(k - WNN_PREV_BUN_SUU) + bun_no];
	dic[k] = wb->dic_no;		/* 辞書番号 */
	entry[k] = wb->entry;		/* エントリ番号 */
	if(wb->hindo_updated == 1) {
	    ima[k] = WNN_IMA_ON;	/* 今ビットの設定方法 */
	    hindo[k] = WNN_HINDO_INC;	/* 頻度の設定方法 */
	    wb->hindo_updated = 2;
	} else {
	    ima[k] = WNN_HINDO_NOP;	/* 今ビットの設定方法 */
	    hindo[k] = WNN_HINDO_NOP;	/* 頻度の設定方法 */
	}
	kmoji[k] = wb->real_kanjilen;	/* 候補文字数（付属語なし）*/
	wnn_area(wb, kouho[k], WNN_KANJI); /* 候補文字列（付属語あり）*/
    }

    /* 直前確定記憶文節数より確定文節数が少ないときは、
       確定文節数分古い文節情報を消去し、全体で直前確定記憶文節数の
       文節情報を覚えておくようにする */
    for(j = WNN_PREV_BUN_SUU - 1, k = WNN_PREV_BUN_SUU - (bun_no2 - bun_no) - 1;
	k >= 0; j--, k--) {
	prev[j].dic_no = prev[k].dic_no;
	prev[j].entry = prev[k].entry;
	prev[j].real_kanjilen = prev[k].real_kanjilen;
	wnn_Strcpy(prev[j].kouho, prev[k].kouho);
	prev[j].jirilen = prev[k].jirilen;
        prev[j].hinsi = prev[k].hinsi;
    }
    /* 今回の確定情報を直前確定情報に代入する */
    for(j = 0, k = nkouho - WNN_PREV_BUN_SUU - 1;
	j < WNN_PREV_BUN_SUU && k >= 0;
	j++, k--) {
	wb = buf->bun[k + bun_no];
	prev[j].dic_no = wb->dic_no;
	prev[j].entry = wb->entry;
	prev[j].real_kanjilen = wb->real_kanjilen;
	wnn_area(wb, prev[j].kouho, WNN_KANJI);
	prev[j].jirilen = wb->jirilen;
	prev[j].hinsi = wb->hinsi;
    }

    /* Wnn5 学習＋ＦＩ学習 */
    k = js_optimize_fi(buf->env, nkouho, dic, entry, ima, hindo, kmoji, kouho);

    if(k == -1) {
	buf_wnn_errorno_copy((WNN_BUF_MT *)buf)
	if (buf_wnn_errorno_eql == WNN_JSERVER_DEAD) {
	  free(dic);
	  free(entry);
	  free(ima);
	  free(hindo);
	  free(kmoji);
	  free(kouho[0]);
	  free(kouho);
	  return(-1);
	}
    }
    free(dic);
    free(entry);
    free(ima);
    free(hindo);
    free(kmoji);
    free(kouho[0]);
    free(kouho);
    return(0);
} /* End of optimize_in_server */


static w_char *
wnn_area(bp, area, kanjip)
WNN_BUN *bp;
w_char *area;
int kanjip;
{
    register WNN_BUN *bp1;
    register w_char *c, *end;

    for(bp1 = bp; bp1; bp1 = bp1->next){
	if(bp1 != bp) c = (w_char *)bp1;
	else c = bp1->yomi;
	end = (w_char *)&bp1->next;
	for(;c < end;){
	    if(!kanjip){
		if((*area++ = *c++) == 0){ area--; goto out;}
	    }else{
		if(*c++ == 0) kanjip--;
	    }
	}
    }
 out:
    return(area);
}	

static int
dai_end(buf, bun_no)
register struct wnn_buf_mt *buf;
register int bun_no;
{
    bun_no++;
    for(;bun_no < buf->orig.bun_suu && !buf->orig.bun[bun_no]->dai_top; bun_no++);
    return(bun_no);
}

#define dai_end_zenkouho(buf, bun_no) (buf->zenkouho_dai[bun_no + 1])

#ifdef	CONVERT_by_STROKE
/* 筆形 (Bi Xing) */
void
jl_get_zenkouho_yomi(buf, zen_num, area)
register struct wnn_buf *buf;
int zen_num;
w_char *area;
{
    register int k, end;

    if(!buf) return;
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(buf->zenkouho_daip==SHO){
	wnn_area(buf->zenkouho[zen_num], area, WNN_YOMI);
    }else{
	end = dai_end_zenkouho(buf, zen_num);
	for(k = buf->zenkouho_dai[zen_num]; k < end; k++){
	    area = wnn_area(buf->zenkouho[k], area, WNN_KANJI);
	}
    }
    UnlockMutex(&BUF_LOCK(buf));
}
#endif

void
jl_get_zenkouho_kanji(buf, zen_num, area)
register struct wnn_buf *buf;
int zen_num;
w_char *area;
{
    register int k, end;

    if(!buf) return;
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(buf->zenkouho_daip==SHO){
	wnn_area(buf->zenkouho[zen_num], area, WNN_KANJI);
    }else{
	end = dai_end_zenkouho(buf, zen_num);
	for(k = buf->zenkouho_dai[zen_num]; k < end; k++){
	    area = wnn_area(buf->zenkouho[k], area, WNN_KANJI);
	}
    }
    UnlockMutex(&BUF_LOCK(buf));
}

static int
wnn_get_area_body(buf, bun_no, bun_no2, area, kanjip)
struct wnn_buf_mt *buf;
register int bun_no, bun_no2;
w_char *area;
int kanjip;
{
    register int k;
    w_char *area1 = area;
    int x;

    if(bun_no < 0) {
	return(0);
    }
    if(bun_no2 >= buf->orig.bun_suu || bun_no2 < 0) bun_no2 = buf->orig.bun_suu;

    for(k = bun_no; k < bun_no2; k++){
	area = wnn_area(buf->orig.bun[k], area, kanjip);
    }
    x = area - area1;
    return x;
}

int
wnn_get_area(buf, bun_no, bun_no2, area, kanjip)
struct wnn_buf *buf;
register int bun_no, bun_no2;
w_char *area;
int kanjip;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = wnn_get_area_body((WNN_BUF_MT *)buf, bun_no, bun_no2, area, kanjip);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

#define JISHO 1
#define HINDO 2
#define FI_JISHO 3	/* Hideyuki Kishiba (Jul. 7, 1994) */
#define FI_HINDO 4	/* New type for FI-Wnn */

/*********************************/
static int
jl_dic_add_e_body(env,dic_name,hindo_name,rev, prio,rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_env_int *env;
char *dic_name;
char *hindo_name;
int prio;
int rw, hrw, rev;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    char tmp[256];
    char pwd[WNN_PASSWD_LEN], hpwd[WNN_PASSWD_LEN];
    int fid, hfid = -1;
    register int ret;
	
    if(file_exist(env, dic_name) == -1) {
    	/* failed, try to access compressed dictionary,
	   but this may cause error */
	char t_dic_name[1024]; char *t_dic_ext = ".gz";
	char t_dic_name2[1024]; char *t_dic_ext2 = ".Z";
        strcpy(t_dic_name, dic_name); strcat(t_dic_name, t_dic_ext);
        strcpy(t_dic_name2, dic_name); strcat(t_dic_name2, t_dic_ext2);
        if( (file_exist(env, t_dic_name) == -1) &&
            (file_exist(env, t_dic_name2) == -1) ) {
	    env_wnn_errorno_copy(env);
	    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
		jl_disconnect_body(env);
		return(-1);
	    }
	    if((int)error_handler == WNN_NO_CREATE || 
	       (rw == WNN_DIC_RDONLY)){
		LockMutex(&msg_lock);
		sprintf(tmp, "%s \"%s\" %s",
			msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
			dic_name,
			msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL));
		        /*
			  "辞書ファイル \"%s\" が無いよ。",
			 */
		message_out(message_handler, tmp);
		UnlockMutex(&msg_lock);
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	    LockMutex(&msg_lock);
	    sprintf(tmp, "%s \"%s\" %s%s",
		    msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
		    dic_name,
		    msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
		    msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));

	            /*
		      "辞書ファイル \"%s\" が無いよ。作る?(Y/N)",
		     */
	    UnlockMutex(&msg_lock);
	    if((int)error_handler == WNN_CREATE || 
	       call_error_handler(error_handler, tmp, env)){
		if(create_file(env, dic_name,JISHO, rw,
			       pwd_dic, 
			       (hindo_name && *hindo_name)? "": pwd_hindo,
			       error_handler, message_handler) == -1) {
		    env_wnn_errorno_copy(env);
		    return(-1);
		}
	    }else{
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	}
    }

    if((fid = file_read(env, dic_name)) == -1) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
    }
    if(hindo_name && *hindo_name){
	if(file_exist(env, hindo_name) == -1) {
	    env_wnn_errorno_copy(env);
	    if(env_wnn_errorno_eql == WNN_JSERVER_DEAD)	{
		jl_disconnect_body(env);
		return(-1);
	    }
	    if((int)error_handler == WNN_NO_CREATE ||
	       (hrw == WNN_DIC_RDONLY)){
		LockMutex(&msg_lock);
		sprintf(tmp, "%s \"%s\" %s",
			msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
			hindo_name,
			msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL));
			/*
			"頻度ファイル \"%s\" が無いよ。",
			*/
		message_out(message_handler, tmp);
		UnlockMutex(&msg_lock);
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	    LockMutex(&msg_lock);
	    sprintf(tmp, "%s \"%s\" %s%s",
		    msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
		    hindo_name,
		    msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
		    msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));
		    /*
		    "頻度ファイル \"%s\" が無いよ。作る?(Y/N)",
		    */
	    UnlockMutex(&msg_lock);
	    if((int)error_handler == WNN_CREATE || 
	       call_error_handler(error_handler, tmp, env)){
		if(create_file(env, hindo_name, HINDO, fid, 
			       "", pwd_hindo, error_handler,
			       message_handler) == -1) {
		    env_wnn_errorno_copy(env);
		    return(-1);
		}
	    }else{
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	}
	if((hfid = file_read(env, hindo_name)) == -1){
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
    }

    /* Hideyuki Kishiba (Dec. 3, 1994)
       グループ辞書の場合は read write、マージ辞書の場合は read only で
       dic_add を行う */
    if(rw == WNN_DIC_GROUP) rw = WNN_DIC_RW;
    else if(rw == WNN_DIC_MERGE) rw = WNN_DIC_RDONLY;

    if(get_pwd(pwd_dic, pwd, env) == -1)return(-1);
    if(get_pwd(pwd_hindo, hpwd, env) == -1)return(-1);
    if((ret = js_dic_add(env, fid, hfid, rev, prio, rw, hrw, pwd, hpwd)) < 0) {
	env_wnn_errorno_copy(env);
	if(env_wnn_errorno_eql == WNN_JSERVER_DEAD){
	    jl_disconnect_body(env);
	    return(-1);
	}else if(env_wnn_errorno_eql == WNN_HINDO_NO_MATCH){
	    if((int)error_handler == WNN_NO_CREATE){
		return(-1);
	    }
	    LockMutex(&msg_lock);
	    sprintf(tmp,
		    msg_get(wnn_msg_cat, 204, NULL, env->orig.lang, NULL),
		    hindo_name);
		    /*
		    "頻度ファイル \"%s\" が指定された辞書の頻度ファイルではありません。作り直しますか?(Y/N)",
		    */
	    UnlockMutex(&msg_lock);
	    if(!((int)error_handler == WNN_CREATE ||
		 call_error_handler(error_handler, tmp, env))){
		return(-1);
	    }
	    if(file_discard(env, hfid) == -1) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	    if(file_remove(env->orig.js_id, hindo_name, hpwd) == -1) {
		env_wnn_errorno_copy(env);
	        if_dead_disconnect(env);
		return(-1);
	    }
	    if(create_file(env,hindo_name, HINDO, fid, NULL, pwd_hindo, WNN_CREATE, message_handler) == -1) {
		env_wnn_errorno_copy(env);
		return(-1);
	    }
	    if((hfid = file_read(env, hindo_name)) == -1) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	    if((ret = js_dic_add(env, fid, hfid, rev, prio, rw, hrw, pwd, hpwd))< 0) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	}
    }
    return(ret);
}

int
jl_dic_add_e(env,dic_name,hindo_name,rev, prio,rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_env *env;
char *dic_name;
char *hindo_name;
int prio;
int rw, hrw, rev;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_add_e_body((WNN_ENV_INT *)env, dic_name, hindo_name, rev, prio,
			  rw, hrw, pwd_dic, pwd_hindo, error_handler,
			  message_handler);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_add(buf, dic_name, hindo_name, rev, prio, rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_buf *buf;
char *dic_name;
char *hindo_name;
int prio;
int rw, hrw, rev;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_add_e_body((WNN_ENV_INT *)buf->env, dic_name, hindo_name, rev,
			  prio, rw, hrw, pwd_dic, pwd_hindo, error_handler,
			  message_handler);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_fi_dic_add_e_body
 *    Description  : jl_fi_dic_add[_e] のサブルーチン関数
 *    Parameter    :
 *         env :             (In) 環境へのポインタ
 *         dic_name :        (In) ＦＩ関係辞書ファイル名
 *         hindo_name :      (In) ＦＩ関係頻度ファイル名
 *	   suflag :          (In) システム辞書ｏｒユーザ辞書
 *	   rw :              (In) 辞書更新が可能ｏｒ不可能
 *	   hrw :             (In) 頻度更新が可能ｏｒ不可能
 *	   pwd_dic :         (In) ＦＩ関係辞書ファイルのパスワード
 *	   pwd_hindo :       (In) ＦＩ関係頻度ファイルのパスワード
 *	   error_handler :   (In) エラーハンドラ−
 *	   message_handler : (In) メッセージハンドラー
 *
 *    Return value : -1==ERROR, else 登録辞書番号
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
jl_fi_dic_add_e_body(env, dic_name, hindo_name, suflag, rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_env_int *env;
char *dic_name;
char *hindo_name;
int suflag;
int rw, hrw;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    char tmp[256];
    char pwd[WNN_PASSWD_LEN], hpwd[WNN_PASSWD_LEN];
    int fid, hfid = -1;
    register int ret;

    if(file_exist(env, dic_name) == -1) {
	/* ＦＩ関係辞書ファイルが存在しない */
	env_wnn_errorno_copy(env);
	if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
	    /* jserver が死んでいる */
	    jl_disconnect_body(env);
	    return(-1);
	}
	if((int)error_handler == WNN_NO_CREATE) {
	    LockMutex(&msg_lock);
	    sprintf(tmp, "%s \"%s\" %s",
		    msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
		    dic_name,
		    msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL));
		    /*
		    "辞書ファイル \"%s\" が無いよ。",
		    */
	    message_out(message_handler, tmp);
	    UnlockMutex(&msg_lock);
	    env_wnn_errorno_set = WNN_NO_EXIST;
	    return(-1);
	}
	LockMutex(&msg_lock);
	sprintf(tmp, "%s \"%s\" %s%s",
		msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
		dic_name,
		msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
		msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));
		/*
		"辞書ファイル \"%s\" が無いよ。作る?(Y/N)",
		*/
	UnlockMutex(&msg_lock);
	if((int)error_handler == WNN_CREATE || 
	   call_error_handler(error_handler, tmp, env)){
	    /* ＦＩ関係辞書の作成 */
	    if(create_file(env, dic_name, FI_JISHO, -1, /* -1 is dummy */
			      pwd_dic, 
			      (hindo_name && *hindo_name)? "": pwd_hindo,
			      error_handler, message_handler) == -1) {
		env_wnn_errorno_copy(env);
		return(-1);
	    }
	}else{
	    env_wnn_errorno_set = WNN_NO_EXIST;
	    return(-1);
	}
    }
    /* ＦＩ関係辞書の読み込み */
    if((fid = file_read(env, dic_name)) == -1) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
    }
    if(hindo_name && *hindo_name){
	if(file_exist(env, hindo_name) == -1) {
	    /* ＦＩ関係頻度ファイルが存在しない */
	    env_wnn_errorno_copy(env);
	    if(env_wnn_errorno_eql == WNN_JSERVER_DEAD)	{
		/* jserver が死んでいる */
		jl_disconnect_body(env);
		return(-1);
	    }
	    if((int)error_handler == WNN_NO_CREATE ||
	       (hrw == WNN_DIC_RDONLY)){
		LockMutex(&msg_lock);
		sprintf(tmp, "%s \"%s\" %s",
			msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
			hindo_name,
			msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL));
			/*
			"頻度ファイル \"%s\" が無いよ。",
			*/
		message_out(message_handler, tmp);
		UnlockMutex(&msg_lock);
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	    LockMutex(&msg_lock);
	    sprintf(tmp, "%s \"%s\" %s%s",
		    msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
		    hindo_name,
		    msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
		    msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));
		    /*
		    "頻度ファイル \"%s\" が無いよ。作る?(Y/N)",
		    */
	    UnlockMutex(&msg_lock);
	    if((int)error_handler == WNN_CREATE || 
	       call_error_handler(error_handler, tmp, env)){
		/* ＦＩ関係頻度ファイルの作成 */
		if(create_file(env, hindo_name, FI_HINDO, fid, 
			       "", pwd_hindo, error_handler,
			       message_handler) == -1) {
		    env_wnn_errorno_copy(env);
		    return(-1);
		}
	    }else{
		env_wnn_errorno_set = WNN_NO_EXIST;
		return(-1);
	    }
	}
	/* ＦＩ関係頻度ファイルの読み込み */
	if((hfid = file_read(env, hindo_name)) == -1){
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
    }

    /* パスワードの取得 */
    if(get_pwd(pwd_dic, pwd, env) == -1)return(-1);
    if(get_pwd(pwd_hindo, hpwd, env) == -1)return(-1);

    /* ＦＩ関係辞書と頻度の整合性チェック */
    if((ret = js_fi_dic_add(env, fid, hfid, suflag, rw, hrw, pwd, hpwd)) < 0) {
	env_wnn_errorno_copy(env);
	if(env_wnn_errorno_eql == WNN_JSERVER_DEAD){
	    /* jserver が死んでいる */
	    jl_disconnect_body(env);
	    return(-1);
	}else if(env_wnn_errorno_eql == WNN_HINDO_NO_MATCH){
	    /* 辞書と頻度の整合性が無い */
	    if((int)error_handler == WNN_NO_CREATE){
		return(-1);
	    }
	    LockMutex(&msg_lock);
	    sprintf(tmp,
		    msg_get(wnn_msg_cat, 204, NULL, env->orig.lang, NULL),
		    hindo_name);
		    /*
		    "頻度ファイル \"%s\" が指定された辞書の頻度ファイルではありません。作り直しますか?(Y/N)",
		    */
	    UnlockMutex(&msg_lock);
	    if(!((int)error_handler == WNN_CREATE ||
		 call_error_handler(error_handler, tmp, env))){
		return(-1);
	    }
	    /* 頻度ファイルのメモリ解放 */
	    if(file_discard(env, hfid) == -1) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	    /* 頻度ファイルのディスクからの削除 */
	    if(file_remove(env->orig.js_id, hindo_name, hpwd) == -1) {
		env_wnn_errorno_copy(env);
	        if_dead_disconnect(env);
		return(-1);
	    }
	    /* ＦＩ関係頻度ファイルの作成 */
	    if(create_file(env,hindo_name, FI_HINDO, fid, NULL, pwd_hindo, WNN_CREATE, message_handler) == -1) {
		env_wnn_errorno_copy(env);
		return(-1);
	    }
	    /* ＦＩ関係頻度ファイルの読み込み */
	    if((hfid = file_read(env, hindo_name)) == -1) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	    /* ＦＩ関係辞書と頻度の整合性チェック */
	    if((ret = js_fi_dic_add(env, fid, hfid, suflag, rw, hrw, pwd, hpwd))< 0) {
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	}
    }
    return(ret);
} /* End of jl_fi_dic_add_e_body */

/*:::DOC_START
 *
 *    Function Name: jl_fi_dic_add_e
 *    Description  : 環境にＦＩ辞書を追加する
 *    Parameter    :
 *         env :             (In) 環境へのポインタ
 *         dic_name :        (In) ＦＩ関係辞書ファイル名
 *         hindo_name :      (In) ＦＩ関係頻度ファイル名
 *	   suflag :          (In) システム辞書ｏｒユーザ辞書
 *	   rw :              (In) 辞書更新が可能ｏｒ不可能
 *	   hrw :             (In) 頻度更新が可能ｏｒ不可能
 *	   pwd_dic :         (In) ＦＩ関係辞書ファイルのパスワード
 *	   pwd_hindo :       (In) ＦＩ関係頻度ファイルのパスワード
 *	   error_handler :   (In) エラーハンドラ−
 *	   message_handler : (In) メッセージハンドラー
 *
 *    Return value : -1==ERROR, else 登録辞書番号
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fi_dic_add_e(env, dic_name, hindo_name, suflag ,rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_env *env;
char *dic_name;
char *hindo_name;
int suflag;
int rw, hrw;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    /* サブルーチン関数のコール */
    x = jl_fi_dic_add_e_body((WNN_ENV_INT *)env, dic_name, hindo_name, suflag,
			  rw, hrw, pwd_dic, pwd_hindo, error_handler,
			  message_handler);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_fi_dic_add_e */

/*:::DOC_START
 *
 *    Function Name: jl_fi_dic_add
 *    Description  : バッファにＦＩ辞書を追加する
 *    Parameter    :
 *         buf :             (In) バッファへのポインタ
 *         dic_name :        (In) ＦＩ関係辞書ファイル名
 *         hindo_name :      (In) ＦＩ関係頻度ファイル名
 *	   suflag :          (In) システム辞書ｏｒユーザ辞書
 *	   rw :              (In) 辞書更新が可能ｏｒ不可能
 *	   hrw :             (In) 頻度更新が可能ｏｒ不可能
 *	   pwd_dic :         (In) ＦＩ関係辞書ファイルのパスワード
 *	   pwd_hindo :       (In) ＦＩ関係頻度ファイルのパスワード
 *	   error_handler :   (In) エラーハンドラ−
 *	   message_handler : (In) メッセージハンドラー
 *
 *    Return value : -1==ERROR, else 登録辞書番号
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fi_dic_add(buf, dic_name, hindo_name, suflag, rw, hrw, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_buf *buf;
char *dic_name;
char *hindo_name;
int suflag;
int rw, hrw;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    /* サブルーチン関数のコール */
    x = jl_fi_dic_add_e_body((WNN_ENV_INT *)buf->env, dic_name, hindo_name,
			  suflag, rw, hrw, pwd_dic, pwd_hindo, error_handler,
			  message_handler);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_fi_dic_add */

static int
jl_dic_delete_e_body(env, dic_no)
register struct wnn_env_int *env;
register int dic_no;
{
    WNN_DIC_INFO dic;

    if(js_dic_info(env,dic_no,&dic) < 0){
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    if(js_dic_delete(env, dic_no) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    /*	dic Body	*/
    if (file_discard(env,dic.body) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    /*	dic hindo	*/
    if(dic.hindo != -1){
	if (file_discard(env,dic.hindo) < 0){
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
    }
    return(0);
}

int
jl_dic_delete_e(env, dic_no)
register struct wnn_env *env;
register int dic_no;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_delete_e_body((WNN_ENV_INT *)env, dic_no);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_delete(buf, dic_no)
register struct wnn_buf *buf;
register int dic_no;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_delete_e_body((WNN_ENV_INT *)buf->env, dic_no);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
get_pwd(pwd_dic, pwd, env)
register char *pwd_dic, *pwd;
ARGS *env;
{
    FILE *fp;
	    
    if(pwd_dic && *pwd_dic){
	if((fp = fopen(pwd_dic, "r")) == NULL){
	    env_wnn_errorno_set = WNN_CANT_OPEN_PASSWD_FILE;
	    return(-1);
	}
	fgets(pwd, WNN_PASSWD_LEN, fp);
	fclose(fp);
    }else {
	pwd[0] = 0;
    }
    return(0);
}

static int
create_pwd_file(env, pwd_file, error_handler, message_handler)
register struct wnn_env_int *env;
char *pwd_file;
int  (*error_handler)(), (*message_handler)();
{
    FILE *fp;
    char gomi[256];

    if(pwd_file == NULL || *pwd_file == 0) return(0);
    if(access(pwd_file, F_OK) != -1) return(0);
    LockMutex(&msg_lock);
    sprintf(gomi, "%s \"%s\" %s%s",
	    msg_get(wnn_msg_cat, 205, NULL, env->orig.lang, NULL),
	    pwd_file,
	    msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
	    msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));
	    /*
	    "password_file \"%s\" が無いよ。作る?(Y/N)",
	    */
    UnlockMutex(&msg_lock);
    /* error_handler != WNN_CREATE のチェックが抜けていたので追加 */
    if((int)error_handler != WNN_CREATE && call_error_handler(error_handler,gomi, env) == 0){
	env_wnn_errorno_set = WNN_NO_EXIST;
	return(-1);
    }
    if((fp = fopen(pwd_file, "w")) == NULL){
	env_wnn_errorno_set = WNN_CANT_OPEN_PASSWD_FILE;
	message_out(message_handler, wnn_perror_lang(env->orig.lang, env));
	return(-1);
    }
#ifdef SYSVR2
    srand(time(0)+getuid());
    fprintf(fp,"%d\n",rand());
#else
    srandom(time(0)+getuid());
    fprintf(fp,"%d\n",random());
#endif
    fclose(fp);
#define	MODE_PWD (0000000 | 0000400)
    chmod(pwd_file,MODE_PWD);
    return(0);
}


/**	jl_fuzokugo_set	**/
static int
jl_fuzokugo_set_e_body(env,fname)
struct wnn_env_int *env;
char *fname;
{
    register int fid, orgfid;
    int	ret;

    orgfid = js_fuzokugo_get(env);
    /* If orgfid == -1, it must be
       because no fuzokugo_file is set to the env
       */
    if((fid=file_read(env,fname)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    if ((ret = js_fuzokugo_set(env,fid)) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(ret);
    }
    if(fid != orgfid && orgfid != -1){
	js_file_discard(env, orgfid);
    }
    return(ret);
}

int
jl_fuzokugo_set_e(env,fname)
struct wnn_env *env;
char *fname;
{
    int x;
    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_fuzokugo_set_e_body((WNN_ENV_INT *)env,fname);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_fuzokugo_set(buf, fname)
register struct wnn_buf *buf;
char *fname;
{
    int x;
    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_fuzokugo_set_e_body((WNN_ENV_INT *)buf->env, fname);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/**	jl_fuzokugo_get	**/
static int
jl_fuzokugo_get_e_body(env, fname)
register struct wnn_env_int *env;
char *fname;
{
    WNN_FILE_INFO_STRUCT file;
    int fid;
    char *c;

    fname[0] = 0;
    if((fid = js_fuzokugo_get(env)) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    if (js_file_info(env,fid,&file) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    LockMutex(&envs_lock);
    c = find_file_name_from_id(env, fid);
    if(c == NULL){
	c = file.name;
    }
    strcpy(fname, c);
    UnlockMutex(&envs_lock);
    return(fid);
}

int
jl_fuzokugo_get_e(env, fname)
register struct wnn_env *env;
char *fname;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_fuzokugo_get_e_body((WNN_ENV_INT *)env, fname);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_fuzokugo_get(buf, fname)
register struct wnn_buf *buf;
char *fname;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_fuzokugo_get_e_body((WNN_ENV_INT *)buf->env, fname);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/**	jl_dic_save	**/
static int
jl_dic_save_e_body(env,dic_no)
register struct wnn_env_int *env;
int	dic_no;
{
    WNN_DIC_INFO dic;
    WNN_FILE_INFO_STRUCT file;
    char *c;

    if(js_dic_info(env,dic_no,&dic) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    /*	dic Body	*/
    LockMutex(&envs_lock);
    c = find_file_name_from_id(env, dic.body);
    if(c == NULL){
	if(dic.localf){
	    c = dic.fname;
	}else{
	    UnlockMutex(&envs_lock);
	    env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT;
	    return(-1); 
	}
    } 
    if(c[0] != C_LOCAL){
	if (js_file_write(env,dic.body,c) < 0) {
	    env_wnn_errorno_copy(env);
	    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
		UnlockMutex(&envs_lock);
		jl_disconnect_if_server_dead_body(env);
		return(-1);
	    }
	}
    }else{
	if (js_file_receive(env,dic.body,c + 1) < 0) {
	    env_wnn_errorno_copy(env);
	    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
		UnlockMutex(&envs_lock);
		jl_disconnect_if_server_dead_body(env);
		return(-1);
	    }
	}
    }
 /*	dic hindo	*/
    if(dic.hindo != -1){
	if (js_file_info(env,dic.hindo,&file) < 0) {
	    UnlockMutex(&envs_lock);
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
	c = find_file_name_from_id(env, file.fid);
	if(c == NULL){
	    if(dic.hlocalf){
		c = dic.hfname;
	    }else{
		UnlockMutex(&envs_lock);
		env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT;
		return(-1);
	    }
	}
	if(c[0] != C_LOCAL){
	    if (js_file_write(env,dic.hindo,c) < 0) {
		UnlockMutex(&envs_lock);
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	}else{
	    if (js_file_receive(env,dic.hindo,c + 1) < 0) {
		UnlockMutex(&envs_lock);
		env_wnn_errorno_copy(env);
		if_dead_disconnect(env);
		return(-1);
	    }
	}
    }
    UnlockMutex(&envs_lock);
    return(0);
}

int
jl_dic_save_e(env,dic_no)
register struct wnn_env *env;
int     dic_no;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_save_e_body((WNN_ENV_INT *)env,dic_no);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_save(buf, dic_no)
register struct wnn_buf *buf;
int     dic_no;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_save_e_body((WNN_ENV_INT *)buf->env, dic_no);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_dic_save_all_e_body(env)
struct wnn_env_int *env;
{
    register WNN_DIC_INFO *dic;
    register int k;
    char *c;
    register int cnt;
    register unsigned long dmask = 0;

    /* テンポラリ辞書以外の辞書情報を得る */
    dmask |= WNN_DIC_ALL_MASK & ~WNN_DIC_TEMPORARY_MASK;

    if((cnt = js_fi_dic_list(env, dmask, &dicrb)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    dic = (WNN_DIC_INFO *)dicrb.buf;
    LockMutex(&envs_lock);
    for(k = 0 ; k < cnt ; k++, dic++){
	if((c = find_file_name_from_id(env, dic->body)) == NULL){
	    if(dic->localf){
		c = dic->fname;
	    }else{
		env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT;
	    }
	}
	if(c){
	    if(c[0] != C_LOCAL){
		if (js_file_write(env,dic->body,c) < 0) {
		    env_wnn_errorno_copy(env);
		    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
			UnlockMutex(&envs_lock);
			jl_disconnect_if_server_dead_body(env);
			return(-1);
		    }
		}
	    }else{
		if (js_file_receive(env,dic->body,c + 1) < 0) {
		    env_wnn_errorno_copy(env);
		    if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
			UnlockMutex(&envs_lock);
			jl_disconnect_if_server_dead_body(env);
			return(-1);
		    }
		}
	    }
	}
 /*	dic hindo	*/
	if(dic->hindo != -1){
	    c = find_file_name_from_id(env, dic->hindo);
	    if(c == NULL){
		if(dic->hlocalf){
		    c = dic->hfname;
		}else{
		    env_wnn_errorno_set=WNN_FILE_NOT_READ_FROM_CLIENT;
		}
	    }
	    if(c){
		if(c[0] != C_LOCAL){
		    if (js_file_write(env,dic->hindo,c) < 0) {
			env_wnn_errorno_copy(env);
			if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
			    UnlockMutex(&envs_lock);
			    if_dead_disconnect(env);
			    return(-1);
			}
		    }
		}else{
		    if (js_file_receive(env,dic->hindo,c + 1) < 0) {
			env_wnn_errorno_copy(env);
			if (env_wnn_errorno_eql == WNN_JSERVER_DEAD) {
			    UnlockMutex(&envs_lock);
			    if_dead_disconnect(env);
			    return(-1);
			}
		    }
		}
	    }
	}
    }
    UnlockMutex(&envs_lock);
    env_wnn_errorno_copy(env);
    if(env_wnn_errorno_eql)
        return(-1);
    else
        return(0);
}

int
jl_dic_save_all_e(env)
struct wnn_env *env;
{
    int x;
    
    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_save_all_e_body((WNN_ENV_INT *)env);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_save_all(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_save_all_e_body((WNN_ENV_INT *)buf->env);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/*
 *
 * bun manipulate  routines
 *
 */

static void
free_sho(buf, wbp)
register struct wnn_buf_mt *buf;
WNN_BUN **wbp;
{
    register WNN_BUN *wb, *wb1;
    wb = *wbp;

    if(--wb->ref_cnt <= 0){
	for(wb1 = wb; wb;){
	    if((wb1 == wb) && (wb->hinsi_list != NULL)) {
		free((char *)(wb->hinsi_list));
		wb->hinsi_list = NULL;
	    }
	    wb->free_next = buf->orig.free_heap;
	    buf->orig.free_heap = wb;
	    wb = wb->next;
	}
    }
    *wbp = NULL;
}

static void
free_zenkouho(buf)
register struct wnn_buf_mt *buf;
{
    register int k;

    for(k = 0 ; k < buf->orig.zenkouho_suu; k++){
	free_sho(buf, &buf->orig.zenkouho[k]);
    }
    buf->orig.zenkouho_suu = 0;
    buf->orig.zenkouho_dai_suu = 0;
    buf->orig.c_zenkouho = -1;
    buf->orig.zenkouho_bun = -1;
    buf->orig.zenkouho_end_bun = -1;
}

static void
free_bun(buf, bun_no, bun_no2)
struct wnn_buf_mt *buf;
register int bun_no, bun_no2;
{
    register int k;

    for(k = bun_no; k < bun_no2; k++){
	free_sho(buf, &buf->orig.bun[k]);
    }
}

static void
free_down(buf, bun_no, bun_no2)
struct wnn_buf_mt *buf;
int bun_no, bun_no2;
{
    register WNN_BUN **wbp, **wbp1;
    int k;

    for(k = bun_no; k < bun_no2; k++){
	for(wbp = &buf->orig.down_bnst[k]; *wbp; wbp = wbp1){
	    wbp1 = &(*wbp)->down;
	    free_sho(buf, wbp);
	}
    }
}

static
WNN_BUN *
get_new_bun(buf)
register struct wnn_buf_mt *buf;
{
    register WNN_BUN *wb;


    if(buf->orig.free_heap == NULL){
	if(alloc_heap(buf, INCREMENT) == -1)return(NULL);
    }
    wb = buf->orig.free_heap;
    buf->orig.free_heap = wb->free_next;
    wb->free_next = NULL;
    wb->daihyoka = -1;
    return(wb);
}

static
WNN_BUN *
get_sho(buf, sb, zenp, daip, fuku, nhinsi, hlist)
struct wnn_buf_mt *buf;
struct wnn_sho_bunsetsu *sb;
int zenp, daip, fuku, nhinsi, *hlist;
{
    register w_char *c, *end, *s;
    register WNN_BUN *wb;
    WNN_BUN *wb1;
    int where = 1;
    int len;

    if((wb = get_new_bun(buf)) == NULL) return(NULL);

    wb->jirilen = sb->jiriend - sb->start + 1;
    wb->dic_no = sb->dic_no;
    wb->entry = sb->entry;
    wb->kangovect = sb->kangovect;
    wb->hinsi = sb->hinsi;	
    wb->hindo = sb->hindo;	
    wb->ima = sb->ima;
    wb->hindo_updated = 0;
    wb->bug = 0;
    wb->dai_top = 0;
    wb->nobi_top = 0;
    wb->ref_cnt = 1;		
    wb->hyoka = sb->hyoka;
    wb->down = NULL;
    wb->from_zenkouho = daip << 1 | zenp;
    len = wnn_Strlen(sb->fuzoku);
    wb->yomilen = wnn_Strlen(sb->yomi) + len;
    wb->real_kanjilen = wnn_Strlen(sb->kanji);
    wb->kanjilen = wb->real_kanjilen + len;
    wb->fukugou = fuku;
    wb->num_hinsi = nhinsi;
    if(nhinsi) {
	int hsize = abs(nhinsi) * sizeof(int);
	if((wb->hinsi_list = (int *)malloc(hsize)) == NULL) return(NULL);
	bcopy(hlist, wb->hinsi_list, hsize);
    } else
        wb->hinsi_list = NULL;
/*
    wb->dai_top = (sb->status == WNN_CONNECT)? 0:1;
大文節の先頭以外の小文節に関しては、status はいい加減な値が入っている。
*/  
    s = sb->yomi;

    for(wb1 = wb; ;){
	if(wb1 == wb) c = wb1->yomi;
	else c = (w_char *)wb1;
	end = (w_char *)&wb1->next;

	for(; c < end;) {
	    if((*c++ = *s++) == 0){
		if(where == 1){
		    where = 3;
		    c--;
		    s = sb->fuzoku;
		}else if(where == 3){
		    where = 0;
		    s = sb->kanji;
		}else if(where == 0){
		    where = 4;
		    c--;
		    s = sb->fuzoku;
		}else{
		    goto out;
		}
	    }
	}
	wb1->next = get_new_bun(buf);
	wb1 = wb1->next;
    }
    out:
    wb1->next = NULL;
    return(wb);
}

static void
make_space_for(buf, zenp, bun_no, bun_no2, cnt)
register struct wnn_buf_mt *buf;
int bun_no, bun_no2, zenp;
int cnt;
{
    switch(zenp){
    case BUN:
	make_space_for_bun(buf,bun_no, bun_no2, cnt);
	break;
    case ZENKOUHO:
	make_space_for_zenkouho(buf,bun_no, bun_no2, cnt);
    }
}

static void
make_space_for_bun(buf, bun_no, bun_no2, cnt)
register struct wnn_buf_mt *buf;
int bun_no, bun_no2;
int cnt;
{
    int newsize;
    register int k;

    newsize = buf->orig.bun_suu + cnt - (bun_no2 - bun_no);

#define Realloc(a, b) realloc((char *)(a), (unsigned)(b))

    if(newsize > buf->orig.msize_bun){
	buf->orig.bun = (WNN_BUN **)Realloc(buf->orig.bun, newsize * sizeof(WNN_BUN *));
	buf->orig.down_bnst = (WNN_BUN **)Realloc(buf->orig.down_bnst, newsize * sizeof(WNN_BUN *));
	buf->orig.msize_bun = newsize;
    }


    for(k = buf->orig.bun_suu; k < newsize; k++){
	buf->orig.down_bnst[k] = NULL;
    }
    bcopy((char *)&buf->orig.bun[bun_no2], (char *)&buf->orig.bun[bun_no + cnt],
	  (buf->orig.bun_suu - bun_no2) * sizeof(WNN_BUN *));
    bcopy((char *)&buf->orig.down_bnst[bun_no2], (char *)&buf->orig.down_bnst[bun_no + cnt],
	  (buf->orig.bun_suu - bun_no2) * sizeof(WNN_BUN *));
    if(bun_no2 < bun_no + cnt){
	bzero((char *)&buf->orig.down_bnst[bun_no2], (bun_no + cnt - bun_no2) * sizeof(WNN_BUN *));
    }
    buf->orig.bun_suu = newsize;
}

static void
make_space_for_zenkouho(buf, bun_no, bun_no2, cnt)
struct wnn_buf_mt *buf;
int bun_no, bun_no2;
register int cnt;
{
    register int newsize;

    newsize = buf->orig.zenkouho_suu + cnt - (bun_no2 - bun_no);

    if(newsize > buf->orig.msize_zenkouho){
	buf->orig.zenkouho = (WNN_BUN **)Realloc(buf->orig.zenkouho, newsize * sizeof(WNN_BUN *));
	buf->orig.zenkouho_dai = (int *)Realloc(buf->orig.zenkouho_dai, (1 + newsize) * sizeof(int *));
	buf->orig.msize_zenkouho = newsize;
    }
    bcopy((char *)&buf->orig.zenkouho[bun_no2],
	  (char *)&buf->orig.zenkouho[bun_no + cnt],
	  (buf->orig.zenkouho_suu - bun_no2) * sizeof(WNN_BUN *));
    buf->orig.zenkouho_suu = newsize;
}


static int
insert_sho(buf, zenp, bun_no, bun_no2, sp, cnt, uniq_level, fuku, nhinsi, hlist)
struct wnn_buf_mt *buf;
int bun_no, bun_no2;
register struct wnn_sho_bunsetsu *sp;
int cnt;
int zenp;			/* daip */
int uniq_level;			/* uniq is only supported when bun_no = -1
				   and zenp == ZENKOUHO */
int fuku, nhinsi, *hlist;
{
    register WNN_BUN **b;
    register int k;

    if(bun_no == -1){
	bun_no = bun_no2 = (zenp == BUN)? buf->orig.bun_suu: buf->orig.zenkouho_suu;
    }

    /* It will make too big space when uniq_level > 0, but That's OK! */
    make_space_for(buf, zenp, bun_no, bun_no2, cnt);

    b = ((zenp == BUN)? buf->orig.bun: buf->orig.zenkouho) + bun_no;
    for(k = bun_no ; k < bun_no + cnt ; k++, sp++){
	/* 品詞指定変換の際は、find_same_kouho() をして、
	   次候補リストのダブリを防ぐ */
	if(uniq_level && ((k < bun_no + cnt - 2) || nhinsi)){
	    if(find_same_kouho(sp, buf->orig.zenkouho, b,uniq_level))continue;
	}
	*b = get_sho(buf, sp, zenp, SHO, fuku, nhinsi, hlist);
	(*b)->dai_top = (sp->status == WNN_CONNECT)? 0:1;
	if(zenp != BUN){
	    if(buf->orig.zenkouho_endvect != -1){
		(*b)->dai_end = (sp->status_bkwd == WNN_CONNECT_BK)? 0:1;
	    }else{
		(*b)->dai_end = 1;
	    }
	}
	b++;
    }
    if(uniq_level && zenp == ZENKOUHO){
	buf->orig.zenkouho_suu = b - buf->orig.zenkouho;
    }
    return(cnt + bun_no);
}

	/* for zenkouho, assume bun_no = bun_no2 = zenkouho_suu */
static int
insert_dai(buf, zenp, bun_no, bun_no2, dp, dcnt, uniq_level, fuku, nhinsi, hlist)
struct wnn_buf_mt *buf;
int bun_no, bun_no2;
struct wnn_dai_bunsetsu *dp;
int dcnt;
int zenp;
int uniq_level;
int fuku, nhinsi, *hlist;
{
    register WNN_BUN **b, **b0;
    register int k, l, m;
    register int cnt = 0;
    struct wnn_sho_bunsetsu *sp, *sp1;

    if(bun_no == -1){
	bun_no = bun_no2 = (zenp == BUN)? buf->orig.bun_suu: buf->orig.zenkouho_suu;
    }

    for(k = 0; k < dcnt ; k++){
	cnt += dp[k].sbncnt;
    }
    make_space_for(buf, zenp, bun_no, bun_no2, cnt);
				/* zenkouho_dai_suu must not be initialized */

    b = ((zenp == BUN)? buf->orig.bun: buf->orig.zenkouho) + bun_no;

    for(k = 0, m = buf->orig.zenkouho_dai_suu ; k < dcnt; k++){
	/* 品詞指定変換の際は、find_same_kouho_dai() をして、
	   次候補リストのダブリを防ぐ */
	if(uniq_level && ((k < dcnt - 2) || nhinsi)){
	    if(find_same_kouho_dai(&dp[k], buf, m, uniq_level))
		continue;
	}
	sp = dp[k].sbn;
	if(zenp == ZENKOUHO){
	    buf->orig.zenkouho_dai[m++] = b - buf->orig.zenkouho;
	}
	b0 = b;
	sp1 = sp;
	for(l = 0 ; l < dp[k].sbncnt; l++){
	    *b = get_sho(buf, sp, zenp, DAI, fuku, nhinsi, hlist);
	    if(zenp == ZENKOUHO){
		if (l == dp[k].sbncnt -1){
		    if(buf->orig.zenkouho_endvect != -1){
			(*b)->dai_end = (sp->status_bkwd == WNN_CONNECT_BK)? 0:1;
		    }else{
			(*b)->dai_end = 0;
		    }
		}else{
		    (*b)->dai_end = 0;
		}
	    }
	    b++;
	    sp++;
	}
	(*b0)->dai_top = (sp1->status == WNN_CONNECT)? 0:1;
	(*b0)->daihyoka = dp[k].hyoka;
    }
    if(zenp == ZENKOUHO){
	buf->orig.zenkouho_dai[m] = b - buf->orig.zenkouho;
	buf->orig.zenkouho_suu = b - buf->orig.zenkouho;
	buf->orig.zenkouho_dai_suu = m;
    }
    return(cnt + bun_no);
}

static void
set_sho(b, p)
register WNN_BUN *b;
register WNN_BUN **p;
{
    b->ref_cnt++;
    *p = b;
}

static void
set_dai(b, p, n)
register WNN_BUN **b;
register WNN_BUN **p;
register int n;
{
    for(;n;n--){
	(*b)->ref_cnt++;
	*p++ = *b++;
    }
}

static int
get_c_jikouho_from_zenkouho(buf, dest)
struct wnn_buf_mt *buf;
WNN_BUN *dest;
{
    register int k;
    w_char area[LENGTHKANJI];
    w_char area1[LENGTHKANJI];
    register WNN_BUN *b;

    wnn_area(dest, area, WNN_KANJI);
    for(k = 0; k < buf->orig.zenkouho_suu; k++){
	b = buf->orig.zenkouho[k];
	if(b->entry == dest->entry && b->dic_no == dest->dic_no){
	    wnn_area(b, area1, WNN_KANJI);
	    if(wnn_Strcmp(area, area1) == 0){
		return(k);
	    }
	}
    }
    return(-1);
}

static int
get_c_jikouho_from_zenkouho_dai(buf, dest)
struct wnn_buf_mt *buf;
WNN_BUN *dest;
{
    register int k;
    w_char area[LENGTHKANJI];
    w_char area1[LENGTHKANJI];
    register WNN_BUN *b;
    register int l;

    wnn_area(dest, area, WNN_KANJI);
    for(k = 0; k < buf->orig.zenkouho_dai_suu; k++){
	b = buf->orig.zenkouho[buf->orig.zenkouho_dai[k]];
	for(l = 0 ; l < buf->orig.zenkouho_dai[k + 1]; l++, dest++, b++){
	    if(b->entry != dest->entry || b->dic_no != dest->dic_no) break;
	    wnn_area(b, area1, WNN_KANJI);
	    if(wnn_Strcmp(area, area1) != 0){
		break;
	    }
	}
	if(l == buf->orig.zenkouho_dai[k + 1]){
	    return(k);
	}
    }
    return(-1);
}


static int
get_c_jikouho(sp, cnt, dest)
struct wnn_sho_bunsetsu *sp;
int cnt;
WNN_BUN *dest;
{
    register int k;
    register int len;
    w_char area[LENGTHKANJI];

    wnn_area(dest, area, WNN_KANJI);
    for(k = 0; k < cnt; k++,sp++){
	if(sp->entry == dest->entry && sp->dic_no == dest->dic_no
	   && sp->kangovect == dest->kangovect){
	    if(wnn_Strncmp(area, sp->kanji, len = wnn_Strlen(sp->kanji)) == 0 &&
	       wnn_Strcmp(area + len, sp->fuzoku) == 0){
		return(k);
	    }
	}
    }
    return(-1);
}

static int
get_c_jikouho_dai(dp, cnt, dest, bun_no)
struct wnn_dai_bunsetsu *dp;
int cnt;
WNN_BUN **dest;
int bun_no;
{
    register int k, l;
    register int len;
    w_char area[LENGTHKANJI];
    register struct wnn_sho_bunsetsu *sp;    

    for(k = 0; k < cnt; k++,dp++){
	sp = dp->sbn;
	for(l = 0 ; l < dp->sbncnt; l++, sp++){
	    if(sp->entry != (dest[bun_no + l])->entry ||
	       sp->kangovect != (dest[bun_no + l])->kangovect ||
	       sp->dic_no != (dest[bun_no + l])->dic_no){
		break;
	    }
	    wnn_area(dest[bun_no + l], area, WNN_KANJI);
	    if(wnn_Strncmp(area, sp->kanji, len = wnn_Strlen(sp->kanji)) != 0 ||
	       wnn_Strcmp(area + len, sp->fuzoku) != 0){
		break;
	    }
	}
	if(l == dp->sbncnt) return(k);
    }
    return(-1);
}


static int
find_same_kouho(sp, st, end, level)
struct wnn_sho_bunsetsu *sp;
register WNN_BUN **st, **end;
int level;
{
    register int len;
    w_char area[LENGTHKANJI];
    register WNN_BUN *b;

    if(level == WNN_UNIQ){
	for(; st < end; st++){
	    b = *st;
	    if(sp->hinsi == b->hinsi){
		wnn_area(b, area, WNN_KANJI);
		if(wnn_Strncmp(area, sp->kanji, len = wnn_Strlen(sp->kanji)) == 0 &&
		   wnn_Strcmp(area + len, sp->fuzoku) == 0){
		    return(1);
		}
	    }
	}
    }else{ /* level = WNN_UNIQ_KNJ */
	for(; st < end; st++){
	    b = *st;
	    wnn_area(b, area, WNN_KANJI);
	    if(wnn_Strncmp(area, sp->kanji, len = wnn_Strlen(sp->kanji)) == 0 &&
	       wnn_Strcmp(area + len, sp->fuzoku) == 0){
		return(1);
	    }
	}
    }	
    return(0);
}
    
static int
find_same_kouho_dai(dp, buf, top, level)
struct wnn_dai_bunsetsu *dp;
struct wnn_buf_mt *buf;
int top;
int level;
{
    int len;
    register int k, l;
    w_char area[LENGTHKANJI];
    WNN_BUN *b;
    register struct wnn_sho_bunsetsu *sp;

    for(k = 0 ; k < top ; k++){
	for(l = 0,sp = dp->sbn ; l < dp->sbncnt; l++, sp++){
	    b = buf->orig.zenkouho[buf->orig.zenkouho_dai[k] + l];
	    if(sp->end - sp->start + 1 != b->yomilen) break;/* From: tsuiki */
	    if(level != WNN_UNIQ_KNJ){
		if(sp->hinsi != b->hinsi) break;
	    }
	    wnn_area(b, area, WNN_KANJI);
	    if(wnn_Strncmp(area, sp->kanji, len = wnn_Strlen(sp->kanji)) != 0 ||
	       wnn_Strcmp(area + len, sp->fuzoku) != 0){
		break;
	    }
	}
	if(l == dp->sbncnt)
	    return(1);
    }
    return(0);
}

int
wnn_cnt_free(buf)
struct wnn_buf *buf;
{
    register int n;
    register WNN_BUN *b;

    for(n = 0, b = buf->free_heap;b;n++, b = b->free_next);
    return(n);
}

static struct wnn_jdata *
jl_word_info_e_body(env, dic_no, entry)
register struct wnn_env_int *env;
int dic_no, entry;
{
    struct wnn_jdata *x;

    if (js_word_info(env,dic_no, entry, &wordrb) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(NULL);
    }
    x = (struct wnn_jdata *)(wordrb.buf);
    return x;
}    

struct wnn_jdata *
jl_word_info_e(env, dic_no, entry)
register struct wnn_env *env;
int dic_no, entry;
{
    struct wnn_jdata *x;

    if(!env) return(NULL);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_info_e_body((WNN_ENV_INT *)env, dic_no, entry);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

struct wnn_jdata *
jl_word_info(buf, dic_no, entry)
register struct wnn_buf *buf;
int dic_no, entry;
{
    struct wnn_jdata *x;

    if(!buf || !(buf->env)) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_info_e_body((WNN_ENV_INT *)buf->env, dic_no, entry);
    if(x == NULL) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_dic_list_e_body
 *    Description  : 辞書情報取得のサブルーチン
 *    Parameter    :
 *         env :     (InOut) 環境へのポインタ
 *	   dmask :   (In) 辞書群設定マスク
 *	   dicinfo : (Ont) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
jl_dic_list_e_body(env, dmask, dicinfo)
struct wnn_env_int *env;
unsigned long dmask;
WNN_DIC_INFO **dicinfo;
{
    WNN_DIC_INFO *info;
    int cnt;
    register int k;
    register char *c;

    if(dmask == 0)
        cnt = js_dic_list(env, &dicrb);
    else
        cnt = js_fi_dic_list(env, dmask, &dicrb);

    if (cnt < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    info = (WNN_DIC_INFO *)(dicrb.buf);

/* If the file is loaded from this client, change the file name to the one
   used in loading it. */
    LockMutex(&envs_lock);
    for(k = 0 ; k < cnt ; k++){
	c = find_file_name_from_id(env, info[k].body);
	if(c != NULL){
	    strcpy(info[k].fname, c);
	}

	c = find_file_name_from_id(env, info[k].hindo);
	if(c != NULL){
	    strcpy(info[k].hfname, c);
	}
    }

    *dicinfo = info;
    UnlockMutex(&envs_lock);
    return(cnt);
} /* End of jl_dic_list_e_body */

/*:::DOC_START
 *
 *    Function Name: jl_dic_list_e
 *    Description  : 環境に登録されているＷｎｎ辞書情報を得る
 *    Parameter    :
 *         env :     (InOut) 環境へのポインタ
 *         dicinfo : (Ont) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_dic_list_e(env, dicinfo)
struct wnn_env *env;
WNN_DIC_INFO **dicinfo;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_list_e_body((WNN_ENV_INT *)env, 0, dicinfo);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_dic_list_e */

/*:::DOC_START
 *
 *    Function Name: jl_dic_list
 *    Description  : 環境に登録されているＷｎｎ辞書情報を得る
 *    Parameter    :
 *         buf : (InOut) バッファへのポインタ
 *         dip : (Ont) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_dic_list(buf, dip)
register struct wnn_buf *buf;
WNN_DIC_INFO **dip;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_list_e_body((WNN_ENV_INT *)buf->env, 0, dip);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_dic_list */

/*:::DOC_START
 *
 *    Function Name: jl_fi_dic_list_e
 *    Description  : 環境に登録されている辞書の内、指定した辞書群の
 *		     情報を得る
 *    Parameter    :
 *         env :     (InOut) 環境へのポインタ
 *	   dmask :   (In) 辞書群設定マスク
 *         dicinfo : (Ont) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fi_dic_list_e(env, dmask, dicinfo)
struct wnn_env *env;
unsigned long dmask;
WNN_DIC_INFO **dicinfo;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_list_e_body((WNN_ENV_INT *)env, dmask, dicinfo);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_fi_dic_list_e */

/*:::DOC_START
 *
 *    Function Name: jl_fi_dic_list
 *    Description  : 環境に登録されている辞書の内、指定した辞書群の
 *                   情報を得る
 *    Parameter    :
 *         buf :   (InOut) バッファへのポインタ
 *	   dmask : (In) 辞書群設定マスク
 *         dip :   (Ont) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fi_dic_list(buf, dmask, dip)
register struct wnn_buf *buf;
unsigned long dmask;
WNN_DIC_INFO **dip;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_list_e_body((WNN_ENV_INT *)buf->env, dmask, dip);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_fi_dic_list */

/*:::DOC_START
 *
 *    Function Name: jl_fuzokugo_list_e_body
 *    Description  : 付属語情報取得のサブルーチン
 *    Parameter    :
 *         env :     (InOut) 環境へのポインタ
 *         curfzk :  (Out) 現在使用ファイル識別子
 *         fzkinfo : (Out) 付属語情報受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 読込み付属語数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
jl_fuzokugo_list_e_body(env, curfzk, fzkinfo)
struct wnn_env *env;
int *curfzk;
WNN_FZK_INFO **fzkinfo;
{
    int cnt;

    if((cnt = js_fuzokugo_list(env, curfzk, fzkinfo)) < 0) {
	env_wnn_errorno_copy(env);
        if_dead_disconnect(env);
        return(-1);
    }
    return(cnt);
} /* End of jl_fuzokugo_list_e_body */

/*:::DOC_START
 *
 *    Function Name: jl_fuzokugo_list_e
 *    Description  : 指定されたサーバに読み込まれている全付属語情報と
 *                   環境に現在設定されている情報の識別子を返す
 *    Parameter    :
 *         env :     (In) 環境へのポインタ
 *         curfzk :  (Out) 現在使用ファイル識別子
 *         fzkinfo : (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 読込み付属語数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fuzokugo_list_e(env, curfzk, fzkinfo)
struct wnn_env *env;
int *curfzk;
WNN_FZK_INFO **fzkinfo;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_fuzokugo_list_e_body((WNN_ENV_INT *)env, curfzk, fzkinfo);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_fuzokugo_list_e */

/*:::DOC_START
 *
 *    Function Name: jl_fuzokugo_list
 *    Description  : 指定されたサーバに読み込まれている全付属語情報と
 *                   環境に現在設定されている情報の識別子を返す
 *    Parameter    :
 *         buf :    (In) バッファへのポインタ
 *         curfzk : (Out) 現在使用ファイル識別子
 *         fzkp :   (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 読込み付属語数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_fuzokugo_list(buf, curfzk, fzkp)
register struct wnn_buf *buf;
int *curfzk;
WNN_FZK_INFO **fzkp;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_fuzokugo_list_e_body((WNN_ENV_INT *)buf->env, curfzk, fzkp);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_fuzokugo_list */

/*:::DOC_START
 *
 *    Function Name: jl_free
 *    Description  : 変換品詞情報、付属語情報を free する
 *    Parameter    :
 *	   ptr : 対象ポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_free(ptr)
char *ptr;
{
    free(ptr);
    return(0);
} /* End of jl_free */


static int
sort_func_ws(a,b)
register char *a, *b;
{
    int ah, bh, ai, bi, iah, ibh, iai, ibi;
    ah = ((struct wnn_jdata *)a)->hindo;
    bh = ((struct wnn_jdata *)b)->hindo;
    iah = ((struct wnn_jdata *)a)->int_hindo;
    ibh = ((struct wnn_jdata *)b)->int_hindo;
    ai = ((struct wnn_jdata *)a)->ima;
    bi = ((struct wnn_jdata *)b)->ima;
    iai = ((struct wnn_jdata *)a)->int_ima;
    ibi = ((struct wnn_jdata *)b)->int_ima;

    if(ai == WNN_IMA_OFF && ah == WNN_ENTRY_NO_USE) return(1);
    if(bi == WNN_IMA_OFF && bh == WNN_ENTRY_NO_USE) return(-1);
    if(iai == WNN_IMA_OFF && iah == WNN_ENTRY_NO_USE) return(1);
    if(ibi == WNN_IMA_OFF && ibh == WNN_ENTRY_NO_USE) return(-1);

    if(ai != bi){
	if(ai < bi) return(1);
	return(-1);
    }
    if(iah >= 0){
	ah += iah;
	bh += ibh;
    }
    if(ah > bh)return(-1);
    if(ah < bh)return(1);
    return(0);
}

static int
jl_word_search_e_body(env,dic_no, yomi, jdp)
register struct wnn_env_int *env;
int dic_no;
w_char *yomi;
struct wnn_jdata **jdp;
{
    register int cnt;
    struct wnn_jdata *jd;

    if ((cnt = js_word_search(env,dic_no, yomi, &wordrb)) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    jd = (struct wnn_jdata *)wordrb.buf;
    qsort((char *)jd,cnt,sizeof(struct wnn_jdata),sort_func_ws);
    *jdp = jd;
    return(cnt);
}

int
jl_word_search_e(env,dic_no, yomi, jdp)
register struct wnn_env *env;
int dic_no;
w_char *yomi;
struct wnn_jdata **jdp;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_search_e_body((WNN_ENV_INT *)env,dic_no, yomi, jdp);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_search(buf, dic_no, yomi, jdp)
register struct wnn_buf *buf;
int dic_no;
w_char *yomi;
struct wnn_jdata **jdp;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_search_e_body((WNN_ENV_INT *)buf->env, dic_no, yomi, jdp);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int 
jl_word_search_by_env_e_body(env, yomi, jdp)
register struct wnn_env_int *env;
struct wnn_jdata **jdp;
w_char *yomi;
{
    register int cnt;
    struct wnn_jdata *jd;

    if ((cnt = js_word_search_by_env(env, yomi, &wordrb)) < 0) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    jd = (struct wnn_jdata *)wordrb.buf;
    qsort((char *)jd,cnt,sizeof(struct wnn_jdata),sort_func_ws);
    *jdp = jd;
    return(cnt);
}

int
jl_word_search_by_env_e(env, yomi, jdp)
register struct wnn_env *env;
struct wnn_jdata **jdp;
w_char *yomi;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_search_by_env_e_body((WNN_ENV_INT *)env, yomi, jdp);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_search_by_env(buf, yomi, jdp)
register struct wnn_buf *buf;
struct wnn_jdata **jdp;
w_char *yomi;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_search_by_env_e_body((WNN_ENV_INT *)buf->env, yomi, jdp);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}



static void
add_down_bnst(buf, k, b)
register struct wnn_buf_mt *buf;
register int k;
register WNN_BUN *b;
{
    if(b->down) return; /* In order to prevent roop! */
    if(b == buf->orig.down_bnst[k]) return; /* In order to prevent roop! */
				/* It occurs when Zenkouho-->Nobi-conv */
    b->down = buf->orig.down_bnst[k];
    buf->orig.down_bnst[k] = b;
    b->ref_cnt ++;
}


#define REAL_PARAM(x) (strcmp(x, "-"))

/** wnnrc を見てのパラメータの設定 */
int
jl_set_env_wnnrc(env, wnnrc_n, error_handler, message_handler)
register struct wnn_env *env;
char *wnnrc_n;
int  (*error_handler)(), (*message_handler)();
{
    int level = 0;
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    if((int)error_handler ==  WNN_CREATE){
	confirm_state = CREATE_WITHOUT_CONFIRM;
    }else if((int)error_handler ==  WNN_NO_CREATE){
	confirm_state = NO_CREATE;
    }else{
	confirm_state = CONFIRM;
    }

    x = jl_set_env_wnnrc1_body((WNN_ENV_INT *)env, wnnrc_n, error_handler, message_handler, level, 0);

    confirm_state = 0;
    UnlockMutex(&ENV_LOCK(env));
    return(x);
}	

static int
jl_set_env_wnnrc1_body(env, wnnrc_n, error_handler, message_handler, level, local)
register struct wnn_env_int *env;
char *wnnrc_n;
int  (*error_handler)(), (*message_handler)();
int level;
int local;
{
    register int num, rev, prio;
    char s[20][EXPAND_PATH_LENGTH];
    char code[EXPAND_PATH_LENGTH];
    char tmp[1024];
    int tmplen;
    register FILE *fp;
    unsigned long vmask = 0;
    int *flag;
    struct wnn_henkan_env henv;
    int  (*error_handler1)() = (int (*)())0;
    char *p;
    extern char *getenv();

    if(level > MAXINCLUDE){
	LockMutex(&msg_lock);
	message_out(message_handler,
		    msg_get(wnn_msg_cat, 206, NULL, env->orig.lang, NULL));
		    /*
		    "include のレベルが多過ぎます。"
		    */
	UnlockMutex(&msg_lock);
	return(-1);
    }
    if (!strcmp(wnnrc_n, DEFAULT_RC_NAME)) {
	/*
	 * デフォルトのwnnenvrcを探しに行く
         */
	if(!(p = getenv("HOME")))
	    goto Default_WNVRC;
	tmplen = sizeof(tmp);
	strncpy(tmp, p, tmplen - 1);
	tmp[tmplen - 1] = 0;
	if (strlen(tmp) + strlen(FIWNN_DIR) >= tmplen)
	    goto Default_WNVRC;
	strcat(tmp, FIWNN_DIR);
	if (strlen(tmp) + strlen(ENVRCFILE) >= tmplen)
	    goto Default_WNVRC;
	strcat(tmp, ENVRCFILE);
	if ((fp = fopen(tmp, "r")) == NULL) {
Default_WNVRC:
	    /*
	     * ユーザのデフォルトファイルが無かったので、システムのデフォルトを
	     * 見に行く
	     */
	        sprintf(tmp, "%s/%s%s", LIBDIR, WNN_DEFAULT_LANG, ENVRCFILE);
	        /* /usr/local/lib/wnn/ja_JP/wnnenvrc */
	        if((fp = fopen(tmp, "r")) == NULL) {
		    /*
		     * システムのデフォルトもなかったのでエラーにする
		     */
		    message_out(message_handler,
		    	    msg_get(wnn_msg_cat, 111, NULL, env->orig.lang,
		    		    NULL));
		    UnlockMutex(&msg_lock);
		    return(-1);
	        }
	}
    } else {
	if((fp = fopen(wnnrc_n, "r")) == NULL){
	    LockMutex(&msg_lock);
	    /*
	     * 指定されたwnnennvrcがオープンできない
             */
	    message_out(message_handler,
			msg_get(wnn_msg_cat, 207, NULL, env->orig.lang, NULL),
			wnnrc_n);
	    UnlockMutex(&msg_lock);
	    return(-1);
	}
    }
    while(fgets(tmp,1024,fp  ) != NULL){
	num = sscanf(tmp,
	"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",code,
		     s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],
		     s[11],s[12],s[13],s[14],s[15],s[16],s[17],s[18],s[19]) ;
	if (num <= 0) { 
	    continue;
	}
	if(code[0] == ';'){
	    continue;
	}else if (strcmp(code, "include") == 0){
	    expand_expr_all(s[0], env);
	    if(jl_set_env_wnnrc1_body(env, s[0], error_handler,
				      message_handler, level + 1,
				      local) == -1){
		fclose(fp);
		return(-1);
	    }
	    continue;
	}
	switch (code[0]) {
	case 'a':
	    if (!strcmp(code, "autosave")) env->orig.autosave = atoi(s[0]);
	    break;
	case 'k':
	    if (!strcmp(code, "kutouten")) {
		/* 句読点 */
		if (num < 2) goto _Err_happend;
		vmask |= WNN_ENV_KUTOUTEN_MASK;
		flag = &henv.kutouten_flag;
		goto _set_flag;
	    } else if (!strcmp(code, "kakko")) {
		/* 括弧 */
		if (num < 2) goto _Err_happend;
		vmask |= WNN_ENV_KAKKO_MASK;
		flag = &henv.kakko_flag;
		goto _set_flag;
	    } else if (!strcmp(code, "kigou")) {
		/* 記号 */
		if (num < 2) goto _Err_happend;
		vmask |= WNN_ENV_KIGOU_MASK;
		flag = &henv.kigou_flag;
		goto _set_flag;
	    }
	}
	if (local == 0) {
	    switch (code[0]) {
	    case 'b':
		if (!strcmp(code, "bunsetsugiri_gakusyuu")) {
		    int dic_no, mode, type;
AUTO_LEARNING:
		    if (num < 6) goto _Err_happend;
		    if (!strcmp(code, "muhenkan_gakusyuu")) {
			type = WNN_MUHENKAN_LEARNING;
		    } else {
			type = WNN_BUNSETSUGIRI_LEARNING;
		    }
		    if (((dic_no = js_get_autolearning_dic(env, type)) == -1)
			&& env_wnn_errorno_eql) {
			if (env_wnn_errorno_eql != WNN_JSERVER_DEAD) {
			    message_out(message_handler, "%s :%s\n", s[0],
					wnn_perror_lang(env->orig.lang, env));
			} else
			message_out(message_handler, "%s\n",
				    wnn_perror_lang(env->orig.lang, env));
			goto _Err_happend;
		    }
		    expand_expr_all(s[0], env);
		    mode = atoi(s[1]);
		    if ((mode > 2) || (mode < 0)) goto _Err_happend;
		    if (!REAL_PARAM(s[3])) {
			s[3][0] = '\0';
		    } else {
			expand_expr_all(s[3], env);
		    }
		    if (dic_no == WNN_NO_LEARNING) {
			/* まだ辞書をロードしていないので、ロードする */
			prio = REAL_PARAM(s[2])? atoi(s[2]) :
			WNN_DIC_PRIO_DEFAULT;
			rev = REAL_PARAM(s[4])? atoi(s[4]) : 0;
			/* 自動学習の辞書は勝手に作る */
			if (((dic_no = jl_dic_add_e_body(env, s[0], NULL, rev,
							 prio, 0, 0, NULL,
							 NULL,
							 (int (*)())WNN_CREATE,
							 message_handler))
			     == -1) && (env_wnn_errorno_eql != 0)) {
			    if (env_wnn_errorno_eql != WNN_JSERVER_DEAD) {
				message_out(message_handler, "%s :%s\n", s[0],
					    wnn_perror_lang(env->orig.lang,
							    env));
			    } else
			    message_out(message_handler, "%s\n",
					wnn_perror_lang(env->orig.lang, env));
			    goto _Err_happend;
			}
			js_set_autolearning_dic(env, type, dic_no);
		    }
		    if (!js_is_loaded_temporary_dic(env)) {
			/* まだテンポラリ辞書をロードしていないので、
			   ロードする */
			if ((js_temporary_dic_add(env, rev) == -1) &&
			    (env_wnn_errorno_eql != 0)){
			    if (env_wnn_errorno_eql == WNN_NOT_SUPPORT_PACKET){
				message_out(message_handler,
					    msg_get(wnn_msg_cat, 211,
	 "You can not temporary dictionary because server's version is old.",
						    env->orig.lang, NULL));
				continue;
			    } else if (env_wnn_errorno_eql !=
				       WNN_JSERVER_DEAD) {
				message_out(message_handler, "%s :%s\n", s[0],
					    wnn_perror_lang(env->orig.lang,
							    env));
			    } else
			    message_out(message_handler, "%s\n",
					wnn_perror_lang(env->orig.lang, env));
			    goto _Err_happend;
			}
		    }
		    /* 学習のモードを設定する */
		    if (type == WNN_MUHENKAN_LEARNING) {
			henv.muhenkan_flag = mode;
			vmask |= WNN_ENV_MUHENKAN_LEARN_MASK;
		    } else {
			henv.bunsetsugiri_flag = mode;
			vmask |= WNN_ENV_BUNSETSUGIRI_LEARN_MASK;
		    }
		}
		break;

	    case 'c':
		if (!strcmp(code, "confirm")){
		    confirm_state = CONFIRM;
		} else if (!strcmp(code, "confirm1")) {
		    confirm_state = CONFIRM1;
		} else if (!strcmp(code, "create_without_confirm")) {
		    confirm_state = CREATE_WITHOUT_CONFIRM;
		}
		break;

	    case 'f':
		if (!strcmp(code, "fi_hindo_kakuritu")) {
		    /* Ｗｎｎ／ＦＩ関係頻度上昇確率関数 */
		    int is_wnn;
HINDO_KAKURITU:
		    if(!strcmp(code, "hindo_kakuritu")) {
			flag = &henv.freq_func_flag;
			is_wnn = 1;
		    } else {
			flag = &henv.fi_freq_func_flag;
			is_wnn = 0;
		    }
		    switch (s[0][0]) {
		    case 'n':
		    case 'N':
			if(!strncmp(s[0], "not", 3) ||
			   !strncmp(s[0], "NOT", 3)) {
			    /* 頻度学習しない */
			    *flag = WNN_HINDO_NOT;
			} else {
			    /* 普通学習 */
			    *flag = WNN_HINDO_NORMAL;
			}
			break;
		    case 'a':
		    case 'A':
			/* 必ず頻度学習する */
			*flag = WNN_HINDO_ALWAYS;
			break;
		    case 'h':
		    case 'H':
			/* 一夜漬け学習 */
			*flag = WNN_HINDO_HIGH;
			break;
		    case 'l':
		    case 'L':
			/* じわじわ学習 */
			*flag = WNN_HINDO_LOW;
			break;
		    default:
			goto _Err_happend;
		    }
		    if(is_wnn) vmask |= WNN_ENV_FREQ_FUNC_MASK;
		    else vmask |= WNN_ENV_FI_FREQ_FUNC_MASK;
		    break;
		} else if (!strcmp(code, "fukugou_yuusen")) {
		    /* 複合語優先変換 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_COMPLEX_CONV_MASK;
		    flag = &henv.complex_flag;
		    goto _set_flag;
		}
		break;
	    case 'g':
		if (!strcmp(code, "giji_number")) {
		    /* 疑似数字の初期表示方法 */
		    switch (s[0][0]) {
		    case 'k':
		    case 'K':
			if(!strcmp(s[0], "kansuuji")||
			   !strcmp(s[0], "KANSUUJI")) {
			    henv.numeric_flag = WNN_NUM_KANSUUJI;
			} else if(!strcmp(s[0], "kanold") ||
				  !strcmp(s[0], "KANOLD")) {
			    henv.numeric_flag = WNN_NUM_KANOLD;	
			} else if(!strcmp(s[0], "kan") ||
				  !strcmp(s[0], "KAN")) {
			    henv.numeric_flag = WNN_NUM_KAN;
			}
			break;
		    case 'h':
		    case 'H':
			if(!strcmp(s[0], "hancan") ||
			   !strcmp(s[0], "HANCAN")) {
			    henv.numeric_flag = WNN_NUM_HANCAN;
			} else if(!strcmp(s[0], "han") ||
				  !strcmp(s[0], "HAN")) {
			    henv.numeric_flag = WNN_NUM_HAN;
			}
			break;
		    case 'z':
		    case 'Z':
			if(!strcmp(s[0], "zencan") ||
			   !strcmp(s[0], "ZENCAN")) {
			    henv.numeric_flag = WNN_NUM_ZENCAN;
			} else if(!strcmp(s[0], "zen") ||
				  !strcmp(s[0], "ZEN")) {
			    henv.numeric_flag = WNN_NUM_ZEN;
			}
			break;
		    default:
			goto _Err_happend;
		    }
		    vmask |= WNN_ENV_NUMERIC_MASK;
		} else if (!strcmp(code, "giji_eisuu")) {
		    /* 疑似アルファベットの初期表示方法 */
		    switch (s[0][0]) {
		    case 'h':
		    case 'H':
			henv.alphabet_flag = WNN_ALP_HAN;
			break;
		    case 'z':
		    case 'Z':
			henv.alphabet_flag = WNN_ALP_ZEN;
			break;
		    default:
			goto _Err_happend;
		    }
		    vmask |= WNN_ENV_ALPHABET_MASK;
		} else if (!strcmp(code, "giji_kigou")) {
		    /* 疑似記号の初期表示方法 */
		    switch (s[0][0]) {
		    case 'h':
		    case 'H':
			henv.symbol_flag = WNN_KIG_HAN;
			break;
		    case 'j':
		    case 'J':
			henv.symbol_flag = WNN_KIG_JIS;
			break;
		    case 'a':
		    case 'A':
			henv.symbol_flag = WNN_KIG_ASC;
			break;
		    default:
			goto _Err_happend;
		    }
		    vmask |= WNN_ENV_SYMBOL_MASK;
		}
		break;
	    case 'h':
		if (!strcmp(code, "hindo_kakuritu")) {
		    goto HINDO_KAKURITU;
		} else if (strcmp(code, "hanyou_gakusyu") == 0) {
		    /* 汎用語学習 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_COMMON_LAERN_MASK;
		    flag = &henv.common_learn_flag;
		    goto _set_flag;
		}
		break;
	    case 'm':
		if (!strcmp(code, "muhenkan_gakusyuu")) {
		    goto AUTO_LEARNING;
		}
		break;
	    case 'n':
		if (strcmp(code, "no_create") == 0){
		    confirm_state = NO_CREATE;
		}
		break;
	    case 'o':
		if (strcmp(code, "okuri_gakusyu") == 0) {
		    /* 送り基準学習 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_OKURI_LEARN_MASK;
		    flag = &henv.okuri_learn_flag;
		    goto _set_flag;
		} else if (strcmp(code, "okuri_kijun") == 0) {
		    /* 送り基準処理 */
		    switch (s[0][0]) {
		    case 'r':
		    case 'R':
			/* 本則 */
			henv.okuri_flag = WNN_OKURI_REGULATION;
			break;
		    case 'n':
		    case 'N':
			/* 送らない */
			henv.okuri_flag = WNN_OKURI_NO;
			break;
		    case 'y':
		    case 'Y':
			/* 送る */
			henv.okuri_flag = WNN_OKURI_YES;
			break;
		    default:
			goto _Err_happend;
		    }
		    vmask |= WNN_ENV_OKURI_MASK;
		}
		break;
	    case 'r':
		if (strcmp(code, "rendaku") == 0) {
		    /* 連濁処理 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_RENDAKU_MASK;
		    flag = &henv.rendaku_flag;
		    goto _set_flag;
		}
		break;
	    case 's':
		if (!strcmp(code, "setdic")){
		    /* dic_add */
		    int rdonly, hrdonly;
		    expand_expr_all(s[0], env);
		    if(num < 3 || !REAL_PARAM(s[1])){
			s[1][0] = 0;
		    }else{
			expand_expr_all(s[1], env);
		    }
		    prio = (num >= 4 && REAL_PARAM(s[2]))? atoi(s[2]) :
		    WNN_DIC_PRIO_DEFAULT;
		    rdonly = (num >= 5 && REAL_PARAM(s[3]))? atoi(s[3]) : 0;
		    hrdonly = (num >= 6 && REAL_PARAM(s[4]))? atoi(s[4]) : 0;
		    if(num < 7 || !REAL_PARAM(s[5])) s[5][0] = 0;
		    if(num < 8 || !REAL_PARAM(s[6])) s[6][0] = 0;
		    rev = (num >= 9 && REAL_PARAM(s[7]))? atoi(s[7]) : 0;

		    switch (confirm_state) {
		    case CONFIRM:
		    case CONFIRM1:
			error_handler1 = error_handler;
			break;
		    case CREATE_WITHOUT_CONFIRM:
			error_handler1 = (int (*)())WNN_CREATE;
			break;
		    case NO_CREATE:
			error_handler1 = (int (*)())WNN_NO_CREATE;
			break;
		    }

		    if((jl_dic_add_e_body(env, s[0], s[1], rev, prio, rdonly,
					  hrdonly, s[5], s[6], error_handler1,
					  message_handler) == -1)
		       && (env_wnn_errorno_eql != 0)) {
			if (env_wnn_errorno_eql != WNN_JSERVER_DEAD)
			message_out(message_handler, "%s (%s) :%s\n",
				    s[0], s[1], wnn_perror_lang(env->orig.lang,
								env));
			else
			message_out(message_handler, "%s\n",
				    wnn_perror_lang(env->orig.lang, env));
			goto _Err_happend;
		    }
		    break;
		}else if (!strcmp(code, "setfuzokugo") ||
			  !strcmp(code, "setgrammar")) {
		    /* fuzokugo_set */
		    expand_expr_all(s[0], env);
		    if(jl_fuzokugo_set_e_body(env,s[0]) == -1){
			if (env_wnn_errorno_eql != WNN_JSERVER_DEAD)
			message_out(message_handler, "%s :%s\n", s[0],
				    wnn_perror_lang(env->orig.lang, env));
			else
			message_out(message_handler, "%s\n",
				    wnn_perror_lang(env->orig.lang, env));
			goto _Err_happend;
		    }
		    break;
		} else if (!strcmp(code, "setparam")){
		    struct wnn_param para;
		    /* setparam --- set parameter */
		    change_ascii_to_int(s[0], &para.n);
		    change_ascii_to_int(s[1], &para.nsho);
		    change_ascii_to_int(s[2], &para.p1);
		    change_ascii_to_int(s[3], &para.p2);
		    change_ascii_to_int(s[4], &para.p3);
		    change_ascii_to_int(s[5], &para.p4);
		    change_ascii_to_int(s[6], &para.p5);
		    change_ascii_to_int(s[7], &para.p6);
		    change_ascii_to_int(s[8], &para.p7);
		    change_ascii_to_int(s[9], &para.p8);
		    change_ascii_to_int(s[10], &para.p9);
		    change_ascii_to_int(s[11], &para.p10);
		    change_ascii_to_int(s[12], &para.p11);
		    change_ascii_to_int(s[13], &para.p12);
		    change_ascii_to_int(s[14], &para.p13);
		    change_ascii_to_int(s[15], &para.p14);
		    change_ascii_to_int(s[16], &para.p15);

		    if (js_param_set(env,&para) < 0) {
			fclose(fp);
			LockMutex(&msg_lock);
			message_out(message_handler,
				    msg_get(wnn_msg_cat, 208, NULL,
					    env->orig.lang, NULL), wnnrc_n);
			/*
			 * "ファイル \"%s\" で環境設定中に、エラーが発生した
			 * ために、設定を中止します。\n",
			 */
			UnlockMutex(&msg_lock);
			env_wnn_errorno_copy(env);
			if_dead_disconnect(env);
			return(-1);
		    }
		    break;
		} else if (!strcmp(code, "saisyu_siyou")) {
		    /* 最終使用最優先 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_LAST_IS_FIRST_MASK;
		    flag = &henv.last_is_first_flag;
		    goto _set_flag;
		} else if (!strcmp(code, "settou_gakusyu")) {
		    /* 接頭語学習 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_PREFIX_LEARN_MASK;
		    flag = &henv.prefix_learn_flag;
		    goto _set_flag;
		} else if (!strcmp(code, "settou_kouho")) {
		    /* 接頭語候補 */
		    switch (s[0][0]) {
		    case 'h':
		    case 'H':
			/* ひらがな（お）*/
			vmask |= WNN_ENV_PREFIX_MASK;
			henv.prefix_flag = WNN_KANA_KOUHO;
			break;
		    case 'k':
		    case 'K':
			/* 漢字（御）*/
			vmask |= WNN_ENV_PREFIX_MASK;
			henv.prefix_flag = WNN_KANJI_KOUHO;
			break;
		    default:
			break;
		    }
		    break;
		} else if (strcmp(code, "setubi_gakusyu") == 0) {
		    /* 接尾語学習 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_SUFFIX_LEARN_MASK;
		    flag = &henv.suffix_learn_flag;
		    goto _set_flag;
	/*
	 * Hideyuki Kishiba (Jul. 12, 1994)
	 * ＦＩ関係システム辞書とＦＩ関係ユーザ辞書の設定
	 */
		} else if (strcmp(code, "set_fi_system_dic") == 0) {
		    char nul = 0;
		    int hrdonly;
		    /* ファイル名の @, ~ を展開する */
		    expand_expr_all(s[0], env);
		    if(num < 3 || !REAL_PARAM(s[1])){
			s[1][0] = 0;
		    }else{
			expand_expr_all(s[1], env);
		    }
		    /* ＦＩ関係頻度は R_ONLY or R/W か？ */
		    hrdonly = (num >= 4 && REAL_PARAM(s[2]))? atoi(s[2]) : WNN_DIC_RDONLY;
		    /* ＦＩ関係頻度のパスワードファイル */
		    if(num < 5 || !REAL_PARAM(s[3])) s[3][0] = 0;
	    
		    switch (confirm_state) {
		    case CONFIRM:
		    case CONFIRM1:
			error_handler1 = error_handler;
			break;
		    case CREATE_WITHOUT_CONFIRM:
			error_handler1 = (int (*)())WNN_CREATE;
			break;
		    case NO_CREATE:
			error_handler1 = (int (*)())WNN_NO_CREATE;
			break;
		    }

		    if((jl_fi_dic_add_e_body(env, s[0], s[1],
					     WNN_FI_SYSTEM_DICT,
					     WNN_DIC_RDONLY,
					     hrdonly, &nul, s[3],
					     error_handler1, message_handler)
			== -1) && (env_wnn_errorno_eql != 0)) {
			if (env_wnn_errorno_eql != WNN_JSERVER_DEAD)
			message_out(message_handler, "%s (%s) :%s\n",
				    s[0], s[1], wnn_perror_lang(env->orig.lang,
								env));
			else
			message_out(message_handler, "%s\n",
				    wnn_perror_lang(env->orig.lang, env));
			goto _Err_happend;
		    }
		} else if (!strcmp(code, "set_fi_user_dic")) {
		    int rdonly, hrdonly;
		    /* ファイル名の @, ~ を展開する */
		    expand_expr_all(s[0], env);
		    /* ＦＩ関係辞書は R_ONLY or R/W か？ */
		    rdonly = (num >= 3 && REAL_PARAM(s[1]))? atoi(s[1]) : WNN_DIC_RDONLY;
		    /* ＦＩ関係辞書のパスワードファイル */
		    if(num < 4 || !REAL_PARAM(s[2])) s[2][0] = 0;

		    switch (confirm_state) {
		    case CONFIRM:
		    case CONFIRM1:
			error_handler1 = error_handler;
			break;
		    case CREATE_WITHOUT_CONFIRM:
			error_handler1 = (int (*)())WNN_CREATE;
			break;
		    case NO_CREATE:
			error_handler1 = (int (*)())WNN_NO_CREATE;
			break;
		    }

		    if((jl_fi_dic_add_e_body(env, s[0], NULL, WNN_FI_USER_DICT,
					     rdonly, WNN_DIC_RDONLY, s[2], NULL,
					     error_handler1, message_handler)
			== -1) && (env_wnn_errorno_eql != 0)) {
			if (env_wnn_errorno_eql != WNN_JSERVER_DEAD)
			message_out(message_handler, "%s (%s) :%s\n",
				    s[0], s[1], wnn_perror_lang(env->orig.lang,
								env));
			else
			message_out(message_handler, "%s\n",
				    wnn_perror_lang(env->orig.lang, env));
			goto _Err_happend;
		    }
		    henv.fi_relation_learn_flag = rdonly;
		    vmask |= WNN_ENV_FI_RELATION_LEARN_MASK;
		}
		break;
	    case 'u':
		if (!strcmp(code, "use_hinsi") ||
		    !strcmp(code, "unuse_hinsi")) {
		    /* 変換使用・不使用品詞 */
		    int ii, *hlist, nhinsi = num - 1;
		    w_char whname[64];
		    if(nhinsi) {
			if(!(hlist = (int *)malloc(nhinsi * sizeof(int))))
			goto _Err_happend;
			for(ii = 0; ii < nhinsi; ii++) {
			    _Sstrcpy(whname, s[ii]);
			    if((hlist[ii] =
				jl_hinsi_number_e_body(env, whname)) == -1) {
				free((char *)hlist);
				goto _Err_happend;
			    }
			}
			if(strcmp(code, "unuse_hinsi") == 0) nhinsi *= -1;
			if(js_set_henkan_hinsi(env, 1, nhinsi, hlist) < 0) {
			    free((char *)hlist);
			    goto _Err_happend;
			}
			free((char *)hlist);
		    }
		} 
		break;
	    case 'y':
		if (strcmp(code, "yuragi") == 0) {
		    /* 長音・揺ぎ処理 */
		    if (num < 2) goto _Err_happend;
		    vmask |= WNN_ENV_YURAGI_MASK;
		    flag = &henv.yuragi_flag;
		    goto _set_flag;
		}
		break;
	    }
	    continue;
	    _set_flag:
	    switch (s[0][0]) {
	    case 't':
	    case 'T':
		*flag = True;
		break;
	    case 'f':
	    case 'F':
		*flag = False;
		break;
	    default:
		goto _Err_happend;
	    }
	}
    }
    if(vmask) {
	if(js_set_henkan_env(env, vmask, &henv) < 0) goto _Err_happend;
    }
    fclose(fp);
    return(0);

_Err_happend:
    LockMutex(&msg_lock);
    message_out(message_handler, "%s set Error!!\n", code);
    message_out(message_handler,
		msg_get(wnn_msg_cat, 208, NULL, env->orig.lang, NULL),
		wnnrc_n);
		/*
		 * "ファイル \"%s\" で環境設定中に、エラーが発生したために、
		 * 設定を中止します。\n",
		 */
    UnlockMutex(&msg_lock);
    fclose(fp);
    return(-1);
}
int
jl_set_env_wnnrc1(env, wnnrc_n, error_handler, message_handler, level)
register struct wnn_env *env;
char *wnnrc_n;
int  (*error_handler)(), (*message_handler)();
int level;
{
    int x;
    
    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_set_env_wnnrc1_body((WNN_ENV_INT *)env, wnnrc_n, error_handler, message_handler, level, 0);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

static int
expand_expr_all(s, env)
struct wnn_env_int *env;
register char *s;
{
    register char *c;

    for(c = s; *c; c++){
	if(*c == '~' || *c == '@'){
	    if(expand_expr(c, env) == -1) return(-1);
	}
    }
    return(0);
}

/* copy of js.c */
static	char *
getlogname()
{
    extern struct passwd *getpwuid();
    struct passwd *p;

    if ((p = getpwuid(getuid())) == NULL)
	return(NULL);
    return(p->pw_name);
}


static int
expand_expr(s, env)
struct wnn_env_int *env;
 /**	~user、@HOME、@LIBDIR @ENV @USR の展開(但し、文字列の先頭のみ)。
   できない時は-1が
   返り、その場合sの中身は着々とそのまんま。sの長さ＜256と仮定してる。*/
register char	*s;
{
	char	*p, *s1;
	char	tmp[EXPAND_PATH_LENGTH];
	char    buf[EXPAND_PATH_LENGTH];
	int	noerr, expandsuc;
	struct	passwd	*u;
        extern char *getenv();
	extern struct	passwd	*getpwnam();
#ifdef	SYSVR2
#ifndef	AIXV3
	extern char * strchr();
#endif /* AIXV3 */
#endif

	if(*s != '~' && *s != '@') return(0);
	if((int)strlen(s) >= EXPAND_PATH_LENGTH) return(-1);

	s1 = s;
#ifdef BSD42
	if(NULL != (p = index(++s1, '/'))){
#else
	if(NULL != (p = strchr(++s1, '/'))){
#endif
		strcpy(tmp, p);
		*p = '\0';
	} else *tmp = '\0';
 /* ここまでは準備。s…先頭、s1…２文字目、p…最初の'/'のあったところ
    （ここで一旦切る）、tmp…それ以後のコピー。*/

	if(*s == '~'){
		if(*s1){
			noerr = expandsuc = 
			(NULL != (u = getpwnam(s1)) &&
			 (int)strlen(p = u -> pw_dir) + (int)strlen(tmp) <
			 EXPAND_PATH_LENGTH );

		} else {
			noerr = expandsuc =
			(NULL != (p = getenv("HOME")) &&
			 (int)strlen(p) + (int)strlen(tmp) < EXPAND_PATH_LENGTH);
		}

	} else { /* then, *s must be '@' */
		if(!strcmp(s1, "HOME")){
			noerr = expandsuc = 
			(NULL != (p = getenv("HOME")) &&
			 (int)strlen(p) + (int)strlen(tmp) < EXPAND_PATH_LENGTH);
		}else if(!strcmp(s1, "WNN_DIC_DIR")){
			noerr = expandsuc = 
			    (NULL != (p = getenv("HOME")) &&
			     (int)strlen(p) + (int)strlen(tmp) < EXPAND_PATH_LENGTH);
			if (expandsuc) {
			    strcpy(buf, p);
			    if (strlen(buf) + strlen("/") < sizeof(buf)) {
				strcat(buf, "/");
				p = getenv("WNN_DIC_DIR");
				if (!p)
				    p = "Wnn";
				if (strlen(buf) + strlen(p) < sizeof(buf)) {
				    strcat(buf, p);
				    p = buf;
				} else
				    noerr = expandsuc = 0;
			    } else
				noerr = expandsuc = 0;
			}
		} else if (!strcmp(s1, "LIBDIR")){
			noerr = expandsuc = 
			((int)strlen(p= LIBDIR)+ (int)strlen(tmp) < EXPAND_PATH_LENGTH);
		} else if (!strcmp(s1, "ENV")){  /* Added */
			noerr = expandsuc = 
			(NULL != (p = env_name(env)) &&
			 (int)strlen(p)+ (int)strlen(tmp) < EXPAND_PATH_LENGTH);
		}else if (!strcmp(s1, "USR")){
			noerr = expandsuc = 
			(NULL != (p = getlogname()) &&
			 (int)strlen(p)+ (int)strlen(tmp) < EXPAND_PATH_LENGTH);
		} else { /* @HOME, @LIBDIR @ENV igai ha kaenai */
			noerr = 1; expandsuc = 0;
		}
	}

	if(expandsuc) strcpy(s, p);
	strcat(s, tmp);
	return(noerr ? 0 : -1);
}

static int
change_ascii_to_int(st,dp)
register char *st;
int *dp;
{
    register int total,flag;

    total = 0;
    flag = 0;
    while(*st != NULL){
	if (isdigit(*st)){
	    total = total * 10 + (*st - '0');
	} else if (*st == '+') {
	    if (flag != 0) { return(-1); }
	    flag = 1;
	} else if (*st == '-') {
	    if (flag != 0) { return(-1); }
	    flag = -1;
	} else { return(-1); }
	st++;
    }
    if (flag == 0){
	flag = 1;
    }
    *dp = total * flag;
    return(1);
}

static int
file_exist(env, n)
struct wnn_env_int *env;
char *n;
{
    if(n[0] == C_LOCAL){
 	return(access(n + 1, 4));
     }else{
	 return(js_access(env,n,4));
    }
}    

static int
create_file(env,n, d, fid, pwd_dic, pwd_hindo, error_handler, message_handler)
register struct wnn_env_int *env;
char *n;
int d;
int fid;
char *pwd_dic, *pwd_hindo;
int  (*error_handler)(), (*message_handler)();
{
    char pwd[WNN_PASSWD_LEN], hpwd[WNN_PASSWD_LEN];
    int rev_dict_type;
    int x;	/* result for creating file	Hideyuki Kishiba (Jul. 7, 1994) */

    if(
       make_dir_rec1(env, n, error_handler, message_handler) == -1){
	env_wnn_errorno_set = WNN_MKDIR_FAIL;
	return(-1);
    }
    if(d == HINDO || d == FI_HINDO){
	/*
	 * Hideyuki Kishiba (Jul. 7, 1994)
	 * ＦＩ関係頻度の作成処理を追加
	 */
	if(create_pwd_file(env, pwd_hindo, error_handler, message_handler) == -1)return(-1);
	if(get_pwd(pwd_hindo, hpwd, env) == -1)return(-1);
	if(n[0] == C_LOCAL){
	    /*
	     * Hideyuki Kishiba (Jul. 7, 1994)
	     * クライアント側に頻度ファイルを作成する
	     */
	    if(d == HINDO)
	        x = js_hindo_file_create_client(env, fid, n + 1, NULL, hpwd);
	    else
	        x = js_fi_hindo_file_create_client(env, fid, n + 1, NULL, hpwd);

	    if(x == -1){
		message_out(message_handler, wnn_perror_lang(env->orig.lang, env));
		if_dead_disconnect(env);
		return(-1);
	    }else{
		LockMutex(&msg_lock);
		message_out(message_handler,
			    "%s \"%s\" %s",
			    msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
			    n,
			    msg_get(wnn_msg_cat, 209, NULL, env->orig.lang, NULL));
			    /*
			    "頻度ファイル \"%s\" を作りました。",
			    */
		UnlockMutex(&msg_lock);
		chown(n + 1, getuid(), -1); /* H.T. */
		return(0);
	    }
	}else{
	    /*
             * Hideyuki Kishiba (Jul. 7, 1994)
             * サーバ側に頻度ファイルを作成する
             */
            if(d == HINDO)
	        x = js_hindo_file_create(env, fid, n, NULL, hpwd);
	    else
	        x = js_fi_hindo_file_create(env, fid, n, NULL, hpwd);

	    if(x == -1){
		message_out(message_handler, wnn_perror_lang(env->orig.lang, env));
		if_dead_disconnect(env);
		return(-1);
	    }else{
		LockMutex(&msg_lock);
		message_out(message_handler,
			    "%s \"%s\" %s",
			    msg_get(wnn_msg_cat, 203, NULL, env->orig.lang, NULL),
			    n,
			    msg_get(wnn_msg_cat, 209, NULL, env->orig.lang, NULL));
			    /*
			    "頻度ファイル \"%s\" を作りました。",
			    */
		UnlockMutex(&msg_lock);
		return(0);
	    }
	}
    } else {
	if(create_pwd_file(env, pwd_hindo, error_handler, message_handler) == -1)return(-1);
	if(get_pwd(pwd_hindo, hpwd, env) == -1)return(-1);
	if(create_pwd_file(env, pwd_dic, error_handler, message_handler) == -1)return(-1);
	if(get_pwd(pwd_dic, pwd, env) == -1)return(-1);

	/*
	 * Hideyuki Kishiba (Jul. 7, 1994)
	 * ＦＩ関係辞書の作成処理を追加
	 */
	if(d == JISHO) {
#ifdef	CONVERT_with_SiSheng
	    if(!strncmp(js_get_lang(env), WNN_C_LANG, 5) ||
	       !strncmp(js_get_lang(env), WNN_T_LANG, 5))
	        rev_dict_type = CWNN_REV_DICT;
	    else
#endif
	    /* Hideyuki Kishiba (Dec. 3, 1994) 
	       dic_add 時の rw フラグにより、グループ辞書、マージ辞書の
	       作成を行うようにする */
	    {
		if(fid == WNN_DIC_GROUP)
		    rev_dict_type = WNN_GROUP_DICT;
		else if(fid == WNN_DIC_MERGE)
		    rev_dict_type = WNN_MERGE_DICT;
		else
	            rev_dict_type = WNN_REV_DICT;
	    }
	} else
	    rev_dict_type = WNN_FI_USER_DICT;

	if(n[0] == C_LOCAL){
	    if(js_dic_file_create_client(env, n + 1, rev_dict_type,
						NULL, pwd, hpwd) == -1){
		message_out(message_handler, wnn_perror_lang(env->orig.lang, env));
		if_dead_disconnect(env);
		return(-1);
	    }else{
		LockMutex(&msg_lock);
		message_out(message_handler,
			    "%s \"%s\" %s",
			    msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
			    n,
			    msg_get(wnn_msg_cat, 209, NULL, env->orig.lang, NULL));
			    /*
			    "辞書ファイル \"%s\" を作りました。",
			    */
		UnlockMutex(&msg_lock);
		chown(n + 1, getuid(), -1);
		return(0);
	    }
	}else{
	    if(js_dic_file_create(env, n, rev_dict_type, NULL, pwd, hpwd)== -1){
		message_out(message_handler, wnn_perror_lang(env->orig.lang, env));
		if_dead_disconnect(env);
		return(-1);
	    }else{
		LockMutex(&msg_lock);
		message_out(message_handler,
			    "%s \"%s\" %s",
			    msg_get(wnn_msg_cat, 200, NULL, env->orig.lang, NULL),
			    n,
			    msg_get(wnn_msg_cat, 209, NULL, env->orig.lang, NULL));
			    /*
			    "辞書ファイル \"%s\" を作りました。",
			    */
		UnlockMutex(&msg_lock);
		return(0);
	    }
	}
    }
}

static int
make_dir_rec1(env, path, error_handler, message_handler)
struct wnn_env_int *env;
register char *path;
int  (*error_handler)(), (*message_handler)();
{
    char gomi[128];
    register char *c;
    for(c = path;*c;c++){
	if(*c == '/'){
	    strncpy(gomi,path,c - path);
	    gomi[c - path] = 0;
	    if(make_dir1(env, gomi, error_handler, message_handler) == -1){
		return(-1);
	    }
	}
    }
    return(0);
}

static int
make_dir1(env, dirname, error_handler, message_handler)
register struct wnn_env_int *env;
register char *dirname;
int  (*error_handler)(), (*message_handler)();
{
    char gomi[128];
    if(dirname[0] == C_LOCAL){
	if(*(dirname + 1) == 0) return(0);
	if(access(dirname + 1 , 0) == 0){ /* check for existence */
	    return(0); /* dir already exists */ 
	}
    }else{
	if(*dirname == 0) return(0);
	if(js_access(env, dirname , 0) == 0){ /* check for existence */
	    return(0); /* dir already exists */ 
	}
    }
    if((int)error_handler != WNN_CREATE){
	LockMutex(&msg_lock);
	sprintf(gomi, "%s \"%s\" %s%s",
		msg_get(wnn_msg_cat, 210, NULL, env->orig.lang, NULL),
		dirname,
		msg_get(wnn_msg_cat, 201, NULL, env->orig.lang, NULL),
		msg_get(wnn_msg_cat, 202, NULL, env->orig.lang, NULL));
		/*
		"directry \"%s\" が無いよ。作る?(Y/N)",
		*/
	UnlockMutex(&msg_lock);
	if(call_error_handler(error_handler,gomi, env) == 0){
	    env_wnn_errorno_set = WNN_MKDIR_FAIL;
	    return(-1);
	}
    }
    if(dirname[0] == C_LOCAL){  /* Create Directory */
#define	MODE (0000000 | 0000777)
	uid_t euid;
	int ret;

	euid = geteuid();
	seteuid(getuid());
	ret = mkdir(dirname + 1 , MODE );
	seteuid(euid);
	if (ret != 0 ) {
	    env_wnn_errorno_set=WNN_MKDIR_FAIL;
	    return(-1);
	}
    }else{
	if(js_mkdir(env, dirname)){
	    if_dead_disconnect(env);
	    return(-1);
	}
    }
    return(0);
}


static  int
call_error_handler(error_handler, c, env)
int (*error_handler)();
char *c;
ARGS *env;
{
    register int x;
    x = error_handler(c);
    if(confirm_state == CONFIRM1){
	if(x) confirm_state = CREATE_WITHOUT_CONFIRM;
	else  confirm_state = NO_CREATE;
    }
    return(x);
}

static void
message_out(message_handler, format, s1, s2, s3, s4, s5, s6, s7, s8)
int (*message_handler)();
char *format;
char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8;
{
    char buf[256];

    if(message_handler){
	sprintf(buf, format, s1, s2, s3, s4, s5, s6, s7, s8);
	(*message_handler)(buf);
    }
}

static int
jl_yomi_len_body(buf, bun_no, bun_no2) 
struct wnn_buf_mt *buf;
register int bun_no, bun_no2;
{
    register int len = 0;

    if(bun_no2 >= buf->orig.bun_suu || bun_no2 < 0)
	bun_no2 = buf->orig.bun_suu;
    for(;bun_no < bun_no2;bun_no++){
	len += buf->orig.bun[bun_no]->yomilen;
    }
    return(len);
}

int
jl_yomi_len(buf, bun_no, bun_no2)
struct wnn_buf *buf;
register int bun_no, bun_no2;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    x = jl_yomi_len_body((WNN_BUF_MT *)buf, bun_no, bun_no2);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_kanji_len(buf, bun_no, bun_no2)
struct wnn_buf *buf;
register int bun_no, bun_no2;
{
    register int len = 0;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(bun_no < 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(0); 
    }
    if(bun_no2 >= buf->bun_suu || bun_no2 < 0)
	bun_no2 = buf->bun_suu;
    for(;bun_no < bun_no2;bun_no++){
	len += buf->bun[bun_no]->kanjilen;
    }
    UnlockMutex(&BUF_LOCK(buf));
    return(len);
}

int wnn_word_use_initial_hindo = 0;

static int
jl_word_use_e_body(env, dic_no, entry)
register struct wnn_env_int *env;
int dic_no, entry;
{
    register struct wnn_jdata *jd;

    if(js_word_info(env,dic_no,entry, &env_rb) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    jd = (struct wnn_jdata *)(env_rb.buf);
    if(jd->hindo != -1){
	if(js_hindo_set(env, dic_no, entry,WNN_IMA_OFF, WNN_ENTRY_NO_USE) == -1) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
    }else{
	if(js_hindo_set(env, dic_no, entry,
			(wnn_word_use_initial_hindo & 0x80) ?
				WNN_IMA_ON : WNN_IMA_OFF ,
			wnn_word_use_initial_hindo & 0x7f) == -1) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
	}
    }
    return(0);
}    

int
jl_word_use_e(env, dic_no, entry)
register struct wnn_env *env;
int dic_no, entry;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_use_e_body((WNN_ENV_INT *)env, dic_no, entry);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_use(buf, dic_no, entry)
register struct wnn_buf *buf;
int dic_no, entry;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_use_e_body((WNN_ENV_INT *)buf->env, dic_no, entry);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

void
jl_env_set(buf, env)
register struct wnn_env *env;
register struct wnn_buf *buf;
{
    if(!buf) return;
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    buf->env = env;
    UnlockMutex(&BUF_LOCK(buf));
}


struct wnn_env *
jl_env_get(buf)
register struct wnn_buf *buf;
{
    struct wnn_env *x;

    if(!buf) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    x = buf->env;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_param_set_e_body(env, para)
register struct wnn_env_int *env;
struct wnn_param *para;
{
    register int x;

    if((x = js_param_set(env, para)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_param_set_e(env, para)
register struct wnn_env *env;
struct wnn_param *para;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_param_set_e_body((WNN_ENV_INT *)env, para);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_param_set(buf, para)
register struct wnn_buf *buf;
struct wnn_param *para;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_param_set_e_body((WNN_ENV_INT *)buf->env, para);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_set_henkan_env_e_body(env, valuemask, henv)
register struct wnn_env_int *env;
unsigned long valuemask;
struct wnn_henkan_env *henv;
{
    register int x;

    if((x = js_set_henkan_env(env, valuemask, henv)) == -1) {
        env_wnn_errorno_copy(env);
        if_dead_disconnect(env);
        return(-1);
    }
    return (x);
}

int
jl_set_henkan_env_e(env, valuemask, henv)
register struct wnn_env *env;
unsigned long valuemask;
struct wnn_henkan_env *henv;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_set_henkan_env_e_body((WNN_ENV_INT *)env, valuemask, henv);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_set_henkan_env(buf, valuemask, henv)
register struct wnn_buf *buf;
unsigned long valuemask;
struct wnn_henkan_env *henv;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_set_henkan_env_e_body((WNN_ENV_INT *)buf->env, valuemask, henv);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_set_henkan_hinsi_e_body(env, mode, nhinsi, hname)
register struct wnn_env_int *env;
int mode, nhinsi;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[32];

    if(nhinsi) {
        hsize = abs(nhinsi);
        hno = (int *)malloc(hsize * sizeof(int));
        for(i = 0; i < hsize; i++) {
            _Sstrcpy(tmp, hname[i]);
            if((hno[i] = jl_hinsi_number_e_body(env, tmp)) == -1) {
                free((char *)hno);
                return(-1);
            }
        }
    }
    
    if((x = js_set_henkan_hinsi(env, mode, nhinsi, hno)) == -1) {
        env_wnn_errorno_copy(env);
        if_dead_disconnect(env);
	 if(nhinsi) free((char *)hno);
        return(-1);
    }
    if(nhinsi) free((char *)hno);
    return (x);
}

int
jl_set_henkan_hinsi_e(env, mode, nhinsi, hname)
register struct wnn_env *env;
int mode, nhinsi;
char **hname;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_set_henkan_hinsi_e_body((WNN_ENV_INT *)env, mode, nhinsi, hname);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_set_henkan_hinsi(buf, mode, nhinsi, hname)
register struct wnn_buf *buf;
int mode, nhinsi;
char **hname;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_set_henkan_hinsi_e_body((WNN_ENV_INT *)buf->env, mode, nhinsi, hname);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_param_get_e_body(env, para)
struct wnn_env_int *env;
struct wnn_param *para;
{
    register int x;

    if((x = js_param_get(env, para)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_param_get_e(env, para)
struct wnn_env *env;
struct wnn_param *para;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_param_get_e_body((WNN_ENV_INT *)env, para);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_param_get(buf, para)
register struct wnn_buf *buf;
struct wnn_param *para;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_param_get_e_body((WNN_ENV_INT *)buf->env, para);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_env_e_body
 *    Description  : サーバ内の変換環境を得るサブルーチン
 *    Parameter    :
 *         env :   (In) 環境へのポインタ
 *         henv :  (Out) 変換環境受け取り用構造体へのポインタ
 *	   local : (In) 変換環境を得る対象フラグ
 *	  		（0 == jserver, else client）
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
jl_get_henkan_env_e_body(env, henv, local)
struct wnn_env_int *env;
struct wnn_henkan_env *henv;
int local;
{
    register int x;

    if ((local && ((x = js_get_henkan_env_local(env, henv)) == -1)) ||
	(!local && ((x = js_get_henkan_env(env, henv)) == -1))) {
        env_wnn_errorno_copy(env);
        if_dead_disconnect(env);
        return(-1);
    }
    return (x);
}

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_env_e
 *    Description  : サーバ内の変換環境を得る
 *    Parameter    :
 *         env :  (In) 環境へのポインタ
 *	   henv : (Out) 変換環境受け取り用構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_env_e(env, henv)
struct wnn_env *env;
struct wnn_henkan_env *henv;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_get_henkan_env_e_body((WNN_ENV_INT *)env, henv, 0);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_get_henkan_env_e */

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_env
 *    Description  : サーバ内の変換環境を得る
 *    Parameter    :
 *         buf :  (In) バッファへのポインタ
 *         henv : (Out) 変換環境受け取り用構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_env(buf, henv)
register struct wnn_buf *buf;
struct wnn_henkan_env *henv;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_get_henkan_env_e_body((WNN_ENV_INT *)buf->env, henv, 0);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_get_henkan_env */

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_env_local_e
 *    Description  : 変換環境の内，ライブラリにあるものを取る
 *                   句読点，括弧，記号
 *    Parameter    :
 *         env :      (In) 環境へのポインタ
 *         henv :     (Out) 変換環境の構造体へのポインタ
 *
 *    Return value : 0==SUCCESS,-1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_env_local_e(env, henv)
struct wnn_env *env;
struct wnn_henkan_env *henv;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_get_henkan_env_e_body((WNN_ENV_INT *)env, henv, 1);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_env_local
 *    Description  : 変換環境の内，ライブラリにあるものを取る
 *                   句読点，括弧，記号
 *    Parameter    :
 *         buf :      (In) バッファへのポインタ
 *         henv :     (Out) 変換環境の構造体へのポインタ
 *
 *    Return value : 0==SUCCESS,-1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_env_local(buf, henv)
register struct wnn_buf *buf;
struct wnn_henkan_env *henv;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_get_henkan_env_e_body((WNN_ENV_INT *)buf->env, henv, 1);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_hinsi_e_body
 *    Description  : 変換に（使用／不使用）する品詞群を得るサブルーチン
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *         nhinsi : (Out) 設定品詞数（負 == 不使用, 正 使用）
 *         hlist :  (Out) 設定品詞リストへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
jl_get_henkan_hinsi_e_body(env, nhinsi, hlist)
struct wnn_env_int *env;
int *nhinsi, **hlist;
{
    register int x;

    if((x = js_get_henkan_hinsi(env, nhinsi, hlist)) == -1) {
        env_wnn_errorno_copy(env);
        if_dead_disconnect(env);
        return(-1);
    }
    return (x);
} /* End of jl_get_henkan_hinsi_e_body */

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_hinsi_e
 *    Description  : 変換に（使用／不使用）する品詞群を得る
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *         nhinsi : (Out) 設定品詞数（負 == 不使用, 正 使用）
 *         hlist :  (Out) 設定品詞リストへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_hinsi_e(env, nhinsi, hlist)
struct wnn_env *env;
int *nhinsi, **hlist;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_get_henkan_hinsi_e_body((WNN_ENV_INT *)env, nhinsi, hlist);
    UnlockMutex(&ENV_LOCK(env));
    return x;
} /* End of jl_get_henkan_hinsi_e */

/*:::DOC_START
 *
 *    Function Name: jl_get_henkan_hinsi
 *    Description  : 変換に（使用／不使用）する品詞群を得る
 *    Parameter    :
 *         env :    (In) バッファへのポインタ
 *         nhinsi : (Out) 設定品詞数（負 == 不使用, 正 使用）
 *         hlist :  (Out) 設定品詞リストへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
jl_get_henkan_hinsi(buf, nhinsi, hlist)
register struct wnn_buf *buf;
int *nhinsi, **hlist;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_get_henkan_hinsi_e_body((WNN_ENV_INT *)buf->env, nhinsi, hlist);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
} /* End of jl_get_henkan_hinsi */

static int
jl_dic_use_e_body(env, dic_no, flag)
struct wnn_env_int *env;
int	dic_no,flag;
{
    register int x;

    if((x = js_dic_use(env, dic_no, flag)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_dic_use_e(env, dic_no, flag)
struct wnn_env *env;
int     dic_no,flag;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_use_e_body((WNN_ENV_INT *)env, dic_no, flag);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_use(buf, dic_no, flag)
register struct wnn_buf *buf;
int     dic_no,flag;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_use_e_body((WNN_ENV_INT *)buf->env, dic_no, flag);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_word_add_e_body(env, dic_no, yomi, kanji, comment, hinsi, init_hindo)
struct wnn_env_int *env;
int	dic_no;
w_char	*yomi,*kanji,*comment;
int	hinsi,init_hindo;
{
    register int x;

    if((x = js_word_add(env, dic_no, yomi, kanji, comment, hinsi, init_hindo)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_word_add_e(env, dic_no, yomi, kanji, comment, hinsi, init_hindo)
struct wnn_env *env;
int     dic_no;
w_char  *yomi,*kanji,*comment;
int     hinsi,init_hindo;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_add_e_body((WNN_ENV_INT *)env, dic_no, yomi, kanji, comment, hinsi, init_hindo);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_add(buf, dic_no, yomi, kanji, comment, hinsi, init_hindo)
register struct wnn_buf *buf;
int     dic_no;
w_char  *yomi,*kanji,*comment;
int     hinsi,init_hindo;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_add_e_body((WNN_ENV_INT *)buf->env, dic_no, yomi, kanji,
			   comment, hinsi, init_hindo);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_word_delete_e_body(env, dic_no, entry)
struct wnn_env_int *env;
int	dic_no;
int	entry;
{
    register int x;

    if((x = js_word_delete(env, dic_no, entry)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_word_delete_e(env, dic_no, entry)
struct wnn_env *env;
int     dic_no;
int     entry;
{
    int x;
    
    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_delete_e_body((WNN_ENV_INT *)env, dic_no, entry);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_delete(buf, dic_no, entry)
register struct wnn_buf *buf;
int     dic_no;
int     entry;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_delete_e_body((WNN_ENV_INT *)buf->env, dic_no, entry);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
file_read(env, fname)
struct wnn_env_int *env;
char *fname;
{
    register int fid;
    if(fname[0] == C_LOCAL){
	fid = js_file_send(env, fname + 1);
    }else{
	fid = js_file_read(env, fname);
    }
    if(fid >= 0){
	add_file_to_env(env, fid, fname);
    }
    return(fid);
}

static int
file_remove(server, fname, pwd)
register WNN_JSERVER_ID *server;
char *fname;
char *pwd;
{
    if(fname[0] == C_LOCAL){
	return(js_file_remove_client(server, fname + 1, pwd));
    }else{
	return(js_file_remove(server, fname, pwd));
    }
}


static int
file_discard(env, fid)
register struct wnn_env_int *env;
register int fid;
{
    delete_file_from_env(env, fid);
    return(js_file_discard(env, fid));
}

static int
jl_hinsi_number_e_body(env, name)
register struct wnn_env_int *env;
w_char *name;
{
    register int x;

    if((x = js_hinsi_number(env->orig.js_id, name)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_hinsi_number_e(env, name)
register struct wnn_env *env;
w_char *name;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_hinsi_number_e_body((WNN_ENV_INT *)env, name);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_hinsi_number(buf, name)
register struct wnn_buf *buf;
w_char *name;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_hinsi_number_e_body((WNN_ENV_INT *)buf->env, name);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static w_char *jl_hinsi_name_e_body(env, no)
register struct wnn_env_int *env;
register int no;
{
    w_char *x;

    if(js_hinsi_name(env->orig.js_id, no, &env_rb) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(NULL);
    }
    x = (w_char *)(env_rb.buf);
    return x;
}

w_char *jl_hinsi_name_e(env, no)
register struct wnn_env *env;
register int no;
{
    w_char *x;

    if(!env) return(NULL);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_hinsi_name_e_body((WNN_ENV_INT *)env, no);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

w_char *
jl_hinsi_name(buf, no)
register struct wnn_buf *buf;
register int no;
{
    w_char *x;

    if(!buf || !(buf->env)) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_hinsi_name_e_body((WNN_ENV_INT *)buf->env, no);
    if(x == NULL) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_hinsi_list_e_body(env, dic_no, name, area)
register struct wnn_env_int *env;
int dic_no;
w_char *name;
w_char ***area;
{
    int x;

    if((x = js_hinsi_list(env, dic_no, name, &env_rb)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    *area = (w_char **)(env_rb.buf);
    return(x);
}

int
jl_hinsi_list_e(env, dic_no, name, area)
register struct wnn_env *env;
int dic_no;
w_char *name;
w_char ***area;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_hinsi_list_e_body((WNN_ENV_INT *)env, dic_no, name, area);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_hinsi_list(buf, dic_no, name, area)
register struct wnn_buf *buf;
int dic_no;
w_char *name;
w_char ***area;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_hinsi_list_e_body((WNN_ENV_INT *)buf->env, dic_no, name, area);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_hinsi_dicts_e_body(env, no, area)
register struct wnn_env_int *env;
int no;
int **area;
{
    int x;

    if((x = js_hinsi_dicts(env, no, &env_rb)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    *area = (int *)(env_rb.buf);
    return(x);
}

int
jl_hinsi_dicts_e(env, no, area)
register struct wnn_env *env;
int no;
int **area;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_hinsi_dicts_e_body((WNN_ENV_INT *)env, no, area);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_hinsi_dicts(buf, no, area)
register struct wnn_buf *buf;
int no;
int **area;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_hinsi_dicts_e_body((WNN_ENV_INT *)buf->env, no, area);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_word_comment_set_e_body(env, dic_no, entry, comment)
register struct wnn_env_int *env;
int	dic_no,entry;
w_char *comment;
{
    register int x;

    if((x = js_word_comment_set(env, dic_no, entry, comment)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_word_comment_set_e(env, dic_no, entry, comment)
register struct wnn_env *env;
int     dic_no,entry;
w_char *comment;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_word_comment_set_e_body((WNN_ENV_INT *)env, dic_no, entry, comment);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_word_comment_set(buf, dic_no, entry, comment)
register struct wnn_buf *buf;
int     dic_no,entry;
w_char *comment;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_comment_set_e_body((WNN_ENV_INT *)buf->env, dic_no, entry,
				   comment);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

static int
jl_dic_comment_set_e_body(env, dic_no, comment)
register struct wnn_env_int *env;
int dic_no;
w_char *comment;
{
    register int x;
    WNN_DIC_INFO dic;
    WNN_FILE_INFO_STRUCT file;

    if(js_dic_info(env,dic_no,&dic) < 0) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
    }
    /*	dic Body	*/
    if (js_file_info(env,dic.body,&file) < 0) {
	    env_wnn_errorno_copy(env);
	    if_dead_disconnect(env);
	    return(-1);
    }
    if((x = js_file_comment_set(env, file.fid, comment)) == -1) {
	env_wnn_errorno_copy(env);
	if_dead_disconnect(env);
	return(-1);
    }
    return (x);
}

int
jl_dic_comment_set_e(env, dic_no, comment)
register struct wnn_env *env;
int dic_no;
w_char *comment;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    x = jl_dic_comment_set_e_body((WNN_ENV_INT *)env, dic_no, comment);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_dic_comment_set(buf, dic_no, comment)
register struct wnn_buf *buf;
int dic_no;
w_char *comment;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_dic_comment_set_e_body((WNN_ENV_INT *)buf->env, dic_no, comment);
    if(x == -1) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}


int
jl_bun_suu(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->bun_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_suu(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    if(buf->zenkouho_daip)
        x = buf->zenkouho_dai_suu;
    else
        x = buf->zenkouho_suu;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_bun(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->zenkouho_bun;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_c_zenkouho(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->c_zenkouho;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_zenkouho_daip(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->zenkouho_daip;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_dai_top(buf, k)
register struct wnn_buf *buf;
int	k;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->bun[k]->dai_top;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_jiri_len(buf, k)
register struct wnn_buf *buf;
int	k;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = buf->bun[k]->jirilen;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

struct wnn_env *
jl_env(buf)
register struct wnn_buf *buf;
{
    struct wnn_env *x;

    if(!buf) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    x = buf->env;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_get_wnn_errorno_env(env)
register struct wnn_env *env;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    x = env_wnn_errorno_eql;
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_get_wnn_errorno_buf(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    x = buf_wnn_errorno_eql;
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

struct wnn_jdata *
jl_inspect(buf, bun_no)
register struct wnn_buf *buf;
int bun_no;
{
    struct wnn_jdata *x;

    if(!buf || !(buf->env)) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = jl_word_info_e_body((WNN_ENV_INT *)buf->env, buf->bun[bun_no]->dic_no,
			    buf->bun[bun_no]->entry);
    if(x == NULL) buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_env_sticky_e(env)
register struct wnn_env *env;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    env_wnn_errorno_set = 0;
    if((x = js_env_sticky(env)) == -1) env_wnn_errorno_copy((WNN_ENV_INT *)env);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_env_sticky(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    if((x = jl_env_sticky_e((WNN_ENV_INT *)buf->env)) == -1)
	buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

int
jl_env_un_sticky_e(env)
register struct wnn_env *env;
{
    int x;

    if(!env) return(-1);
    LockMutex(&ENV_LOCK(env));
    if((x = js_env_un_sticky(env)) == -1) env_wnn_errorno_copy((WNN_ENV_INT *)env);
    UnlockMutex(&ENV_LOCK(env));
    return x;
}

int
jl_env_un_sticky(buf)
register struct wnn_buf *buf;
{
    int x;

    if(!buf || !(buf->env)) return(-1);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    if((x = jl_env_un_sticky_e((WNN_ENV_INT *)buf->env)) == -1)
	buf_wnn_errorno_copy((WNN_BUF_MT *)buf);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

char *
jl_get_lang(buf)
register struct wnn_buf *buf;
{
    char *x;

    if(!buf || !(buf->env)) return(NULL);
    LockMutex(&BUF_LOCK(buf));
    LockMutex(&(envmt->env_lock));
    buf_wnn_errorno_set = 0;
    x = js_get_lang((WNN_ENV_INT *)buf->env);
    UnlockMutex(&(envmt->env_lock));
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}


/* パラメータオートチューニング */
typedef struct _InfoShoRec {
    int		hindo;
    int		ima;
    int		jirilength;
    int		bunlength;
    int		dictnice;
    int		hyoka;
    int		daihyoka;
    int		dai_top;
    w_char	*yomi;
    int		serial;
    int		kangovect;
    struct _InfoShoRec *next;
} InfoShoRec;

typedef struct _InfoDaiRec {
    int		n;
    int		hindo;
    int		ima;
    int		jirilength;
    int		sholength;
    int		dictnice;
    int		dailength;
    struct _InfoDaiRec *next;
} InfoDaiRec;

typedef InfoDaiRec InfoTotalRec;

typedef struct _WnnAutoTune {
    InfoDaiRec		*s_dai_info;
    InfoDaiRec		*e_dai_info;
    InfoShoRec		*s_sho_info;
    InfoShoRec		*e_sho_info;
    InfoTotalRec	*s_total_info;
    InfoTotalRec	*e_total_info;
    struct wnn_param	new_param;
    struct wnn_param	get_param;
} WnnAutoTune;

static int
Giji_Hinsi_Check(info)
InfoShoRec *info;
{
    InfoShoRec *p = info;

    for (; p; p = p->next) {
	if ((p->serial == -11) || (p->serial == -1)) {
	    return(0);
	}
    }
    return(1);
}

static int
Chval(h, o)
int h, o;
{
    if (h > o) return(-1);
    if (h == o) return(0);
    return(1);
}

static int
Sho_Info(buf, bun_no, info)
struct wnn_buf *buf;
int bun_no;
InfoShoRec *info;
{
    WNN_BUN *data = NULL;
    WNN_DIC_INFO dic;
    w_char *yomi;

    if (!buf || !buf->bun || !(data = buf->bun[bun_no])) return(-1);
    if (js_dic_info(buf->env, data->dic_no, &dic) < 0)
	return(-1);
    if (!(yomi = (w_char *)malloc(sizeof(w_char) * (data->yomilen + 1))))
	return(-1);
    wnn_Strncpy(yomi, data->yomi, data->yomilen);
    yomi[data->yomilen] = (w_char)0;
    info->yomi = yomi;
    info->serial = data->entry;
    info->hindo = data->hindo;
    info->dictnice = dic.nice;
    info->ima = data->ima;
    info->hyoka = data->hyoka;
    info->daihyoka = data->daihyoka;
    info->kangovect = data->kangovect;
    info->dai_top = data->dai_top;
    info->jirilength = data->jirilen;
    info->bunlength = data->kanjilen;
    return(0);
}

static InfoShoRec *
Atume(buf)
register struct wnn_buf *buf;
{
    int max = jl_bun_suu(buf);
    int i;
    InfoShoRec *info, *prev;

    if (max <= 0) return(NULL);
    if (!(info = (InfoShoRec *)malloc(sizeof(InfoShoRec) * max))) return(NULL);
    bzero((char *)info, sizeof(InfoShoRec) * max);

    for (i = 0; i < max; i++) {
	if (Sho_Info(buf, i, &info[i]) < 0) {
	    free((char *)info);
	    return(NULL);
	}
	info[i].next = NULL;
	if (i > 0) prev->next = &info[i];
	prev = &info[i];
    }
    return(info);
}

static InfoTotalRec *
Total(p)
InfoDaiRec *p;
{
    int nn;
    InfoTotalRec *info;

    if (!p) return(NULL);
    if (!(info = (InfoTotalRec *)malloc(sizeof(InfoTotalRec)))) return(NULL);
    bzero((char *)info, sizeof(InfoTotalRec));

    for (; p; p = p->next) {
	nn = p->n;
	info->n += nn;
	info->hindo += p->hindo/nn;
	info->ima += p->ima/nn;
	info->jirilength += p->jirilength/nn;
	info->sholength += p->sholength/nn;
	info->dictnice += p->dictnice/nn;
	info->dailength += p->dailength;
    }
    return(info);
}

static InfoDaiRec *
Dai_Info(sho_p)
InfoShoRec *sho_p;
{
    int cnt, i;
    InfoShoRec *p = sho_p;
    InfoDaiRec *d, *info, *prev;

    for (cnt = 0; p; p = p->next) {
	if (p->dai_top) cnt++;
    }

    if (cnt <= 0) return(NULL);
    if (!(info = (InfoDaiRec *)malloc(sizeof(InfoDaiRec) * cnt))) return(NULL);
    bzero((char *)info, sizeof(InfoDaiRec) * cnt);

    d = &info[0];
    for (i = 0, p = sho_p; p; p = p->next) {
	if (p->dai_top) {
	    d = &info[i];
	    if (i > 0) prev->next = d;
	    prev = d;
	    i++;
	}
	d->n++;
	d->hindo += p->hindo;
	d->ima += p->ima;
	d->jirilength += p->jirilength;
	d->sholength += p->bunlength;
	d->dictnice += p->dictnice;
	d->dailength = d->sholength;
    }
    return(info);
}


static int
wnn_set_area_body(buf, bun_no, area, kanjip)
struct wnn_buf_mt *buf;
register int bun_no;
w_char *area;
int kanjip;
{
    register WNN_BUN *wb, *wb1;
    w_char *c, *end, *area1 = area;
    int len;

    if ((kanjip != WNN_KANJI ) || (bun_no < 0) ||
	!(wb = buf->orig.bun[bun_no])) {
	return(0);
    }

    for(wb1 = wb; ;){
	if(wb1 != wb) c = (w_char *)wb1;
	else c = wb1->yomi;
	end = (w_char *)&wb1->next;
	for(;c < end;){
	    if(!kanjip){
		if((*c++ = *area++) == 0){ area--; goto out;}
	    }else{
		if(*c++ == 0) kanjip--;
	    }
	}
	if (!*end) {
	    wb1->next = get_new_bun(buf);
	}
	wb1 = wb1->next;
    }
out:
    wb1->next = NULL; 	/* 95/6/13 waya */
    len = area - area1;
    wb->kanjilen = wb->real_kanjilen = len;
    wb->jirilen = wb->yomilen;
    return 0;
}

int
wnn_set_area(buf, bun_no, area, kanjip)
struct wnn_buf *buf;
register int bun_no;
w_char *area;
int kanjip;
{
    int x;

    if(!buf) return(0);
    LockMutex(&BUF_LOCK(buf));
    x = wnn_set_area_body((WNN_BUF_MT *)buf, bun_no, area, kanjip);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}

/* --------------- for ikeiji ---------- */
extern int js_ikeiji_with_data();
int jl_zenikeiji_dai_with_hinsi_name();

/*:::DOC_START
 *
 *    Function Name: jl_zenikeiji_dai
 *    Description  :
 *         do ikeiji-henkan with some conditions
 *          
 *    Parameter    :
 *         buf :      (InOut) kanji buffer
 *         bun_no :     (In) staring bun no.
 *         bun_no2 :     (In) ending bun no. (exclusive)
 *         use_maep :     (In)  connective info.
 *         uniq_level :     (In) unique level
 *
 *    Return value : no. of dai-bunsetsu
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
int
jl_zenikeiji_dai(buf, bun_no, bun_no2, use_maep, uniq_level)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level;
{
int nhinsi = 1; char hname[32];
char * p_hname = &hname[0];
    int x;
 strcpy(hname, "異形字");
    x = jl_zenikeiji_dai_with_hinsi_name(buf, bun_no, bun_no2, use_maep, uniq_level, nhinsi, &p_hname );
    return x;
}

/*:::DOC_START
 *
 *    Function Name: zen_conv_dai_ikeiji1
 *    Description  :
 *         do ikeiji-henkan with some conditions
 *          
 *    Parameter    :
 *         buf :      (InOut) kanji buffer
 *         bun_no :     (In) staring bun no.
 *         bun_no2 :     (In) ending bun no. (exclusive)
 *         use_maep :     (In)  connective info.
 *         uniq_level :     (In) unique level
 *         fuku :     (In) fukugou-go
 *         nhinsi :     (In) no. of hinsi
 *         hlist :     (In) hinsi-list
 *
 *    Return value : no. of dai-bunsetsu
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
static int
zen_conv_dai_ikeiji1(buf, bun_no, bun_no2, use_maep, uniq_level, fuku, nhinsi, hlist)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level, fuku, nhinsi, *hlist;
{
    register struct wnn_buf_mt *buf_m = (WNN_BUF_MT *)buf;
    int cnt;
    w_char yomi[LENGTHBUNSETSU], yomi1[LENGTHBUNSETSU];
    struct wnn_dai_bunsetsu *dp;
    int tmp;
    register int k;
    int x;
    int nobi_top;
    w_char yomi_orig[LENGTHBUNSETSU];
    
    if(bun_no2 > (tmp = dai_end(buf_m, bun_no)) ||
	bun_no2 < 0) bun_no2 = tmp;
    jl_get_kanji_body(buf_m, bun_no, bun_no2, yomi);
    jl_get_yomi_body(buf_m, bun_no, bun_no2, yomi_orig);

    if(bun_no == buf->zenkouho_bun && buf->zenkouho_daip == IKEIJI){
	x = buf->c_zenkouho;
	return x;
    }
    if (use_maep & WNN_USE_MAE && bun_no > 0) {
	dumbhinsi = buf->bun[bun_no - 1]->hinsi;
	jl_get_yomi_body(buf_m, bun_no - 1, bun_no, yomi1);
	mae_fzk = yomi1 + buf->bun[bun_no - 1]->jirilen;
    } else {
	dumbhinsi = WNN_BUN_SENTOU;
	mae_fzk = (w_char *)0;
    }
    if(use_maep & WNN_USE_ATO && bun_no2 < buf->bun_suu){
	syuutanv = buf->bun[bun_no2]->kangovect;
	syuutanv1 = WNN_VECT_KANZEN; 
	buf->zenkouho_endvect = syuutanv;
    }else{
	syuutanv = WNN_VECT_KANZEN;
	syuutanv1 = WNN_VECT_NO;
	if(bun_no2 < buf->bun_suu){
	    buf->bun[bun_no2]->dai_top = 1;
	}
	buf->zenkouho_endvect = -1;
    }
    if(!(buf->env)) return(-1);
    LockMutex(&(envmt->env_lock));
    if(fuku == 0 && nhinsi == 0) {
/* ?? error for this henkan */
#if 0
	if(buf->bun[bun_no]->fukugou == 0 && buf->bun[bun_no]->num_hinsi == 0) {
	    if((cnt = js_kanzen_dai(buf->env, yomi, dumbhinsi, mae_fzk,
				    syuutanv, syuutanv1, &buf_rb)) < 0){
		buf_wnn_errorno_copy(buf_m);
		if_dead_disconnect_b(buf_m);
		UnlockMutex(&(envmt->env_lock));
		return(-1);
	    }
	} else {
	    if((cnt = js_ikeiji_with_data(buf->env, buf->bun[bun_no]->fukugou,
			  buf->bun[bun_no]->num_hinsi, buf->bun[bun_no]->hinsi_list,
			  WNN_IKEIJI_DAI, yomi, dumbhinsi, mae_fzk, syuutanv,
			  syuutanv1, WNN_VECT_BUNSETSU,
		      /* need fugokugo-len, hinsi, etc */ buf->bun[bun_no], yomi_orig,
			  &buf_rb)) < 0) {
		buf_wnn_errorno_copy(buf_m);
                if_dead_disconnect_b(buf_m);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
            }
	}
#else
/* ?? need set
		buf_wnn_errorno_copy(buf_m);
*/
                if_dead_disconnect_b(buf_m);
                UnlockMutex(&(envmt->env_lock));
                return(-1);
#endif /* 0 */
    } else {
	if((cnt = js_ikeiji_with_data(buf->env, fuku, nhinsi, hlist,
		      WNN_IKEIJI_DAI, yomi, dumbhinsi, mae_fzk, syuutanv,
		      syuutanv1, WNN_VECT_BUNSETSU,
		      /* need fugokugo-len, hinsi, etc */ buf->bun[bun_no], yomi_orig,
		      &buf_rb)) < 0) {
	    buf_wnn_errorno_copy(buf_m);
	    if_dead_disconnect_b(buf_m);
	    UnlockMutex(&(envmt->env_lock));
	    return(-1);
	}
    }

    dp = (struct wnn_dai_bunsetsu *)buf_rb.buf;

    free_zenkouho(buf_m);
		/* Wander if it is OK, that is, only when all the
		 * zenkouho's are got from zenkouho_dai, we need not move
		 * the current dai-bunsetsu to the top of zenkouho's
		 */
    for(k = bun_no; k < bun_no2; k++){
	if(buf->bun[k]->from_zenkouho != ZENKOUHO_IKEIJI_DAI)break;
    }
    nobi_top = buf->bun[k]->nobi_top;
    if(k != bun_no2){		/* move the current to the top. */
	make_space_for(buf_m, ZENKOUHO, buf->zenkouho_suu, buf->zenkouho_suu,
		       bun_no2 - bun_no);
	set_dai(&buf->bun[bun_no], &buf->zenkouho[0], bun_no2 - bun_no);
	buf->zenkouho_dai[0] = 0;
	buf->zenkouho_dai[1] = bun_no2 - bun_no;
	buf->zenkouho_dai_suu = 1;
	buf->zenkouho_suu = bun_no2 - bun_no;
	k = get_c_jikouho_dai(dp, cnt, buf->bun, bun_no);
	if(k >= 0){
	    buf->zenkouho[0]->dai_top = 
		(dp[k].sbn->status == WNN_CONNECT)? 0:1;
	    buf->zenkouho[bun_no2-bun_no-1]->dai_end = 
		(dp[k].sbn[dp[k].sbncnt-1].status_bkwd == WNN_CONNECT_BK)? 0:1;
	    /* KURI *//* USO*?*/
	} else if (cnt == 0) {
            /* 「・」は候補数が 0 なので、dai_top, dai_end を
               強制的に 1 にする */
            buf->zenkouho[0]->dai_top = 1;
            buf->zenkouho[bun_no2-bun_no-1]->dai_end = 1;
	}
	if(uniq_level || k < 0){
	    insert_dai_or_ikeiji(buf_m, ZENKOUHO, -1, -1, dp, cnt, uniq_level, 0, 0, NULL, IKEIJI);
	}else{
	    insert_dai_or_ikeiji(buf_m, ZENKOUHO, -1, -1, dp, k, uniq_level, 0, 0, NULL, IKEIJI);
	    insert_dai_or_ikeiji(buf_m, ZENKOUHO, -1, -1, dp + k + 1, cnt - k - 1,
		       uniq_level, 0, 0, NULL, IKEIJI);
	}
	buf->c_zenkouho = 0;
    }else{
	insert_dai_or_ikeiji(buf_m, ZENKOUHO, -1, -1, dp, cnt, uniq_level, 0, 0, NULL, IKEIJI);
	k = get_c_jikouho_from_zenkouho_dai(buf_m, buf->bun[bun_no]);
	if(k < 0){
	    k = 0;	/* Only when the kouho has been removed from dict. */
	}
	buf->c_zenkouho = k;
    }
    buf->zenkouho_bun = bun_no;
    buf->zenkouho_end_bun = bun_no2;
    buf->zenkouho_daip = IKEIJI;
    for(k = 0 ; k < buf->zenkouho_suu; k++){
	if(buf->zenkouho[k]->ima && buf->zenkouho[k]->dic_no != -1){
	    add_down_bnst(buf_m, bun_no, buf->zenkouho[k]);
	}
	/*
	 * 文節伸ばし/縮めを行った後次候補を取った場合には、次候補の文節情報
	 * にも文節伸ばし/縮めの情報をつけておく。文節切り学習で使用する。
	 */
	if (nobi_top) buf->zenkouho[k]->nobi_top = 1;
    }
    x = buf->c_zenkouho;
    UnlockMutex(&(envmt->env_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: jl_zenikeiji_dai_with_hinsi_name
 *    Description  :
 *         do ikeiji-henkan with some conditions
 *          
 *    Parameter    :
 *         buf :      (InOut) kanji buffer
 *         bun_no :     (In) staring bun no.
 *         bun_no2 :     (In) ending bun no. (exclusive)
 *         use_maep :     (In)  connective info.
 *         uniq_level :     (In) unique level
 *         nhinsi :     (In) no. of hinsi-name
 *         hname :     (In) hinsi name-list
 *
 *    Return value : no. of dai-bunsetsu
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
int
jl_zenikeiji_dai_with_hinsi_name(buf, bun_no, bun_no2, use_maep, uniq_level, nhinsi, hname)
register struct wnn_buf *buf;
int bun_no, bun_no2, use_maep, uniq_level, nhinsi;
char **hname;
{
    int x, i, hsize, *hno = NULL;
    w_char tmp[64];

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
/*    if(strncmp(js_get_lang(buf->env), WNN_J_LANG, 5) || nhinsi == 0) {
        UnlockMutex(&BUF_LOCK(buf));
        return(-1);
	} */
    if(nhinsi){
        hsize = abs(nhinsi);
        hno = (int *)malloc(hsize * sizeof(int));
        for(i = 0; i < hsize; i++) {
            _Sstrcpy(tmp, hname[i]);
            if((hno[i] = jl_hinsi_number_e(buf->env, tmp)) == -1) {
                free((char *)hno);
                UnlockMutex(&BUF_LOCK(buf));
                return(-1);
            }
        }
    }
    x = zen_conv_dai_ikeiji1(buf, bun_no, bun_no2, use_maep, uniq_level, 0, nhinsi, hno);
    if(nhinsi) free((char *)hno);
    UnlockMutex(&BUF_LOCK(buf));
    return x;
}
/* end of jl_zenikeiji_dai_with_hinsi_name */

/*:::DOC_START
 *
 *    Function Name: insert_dai_or_ikeiji
 *    Description  :
 *         insert dai-bunsetsu in to kanji-buffer
 *          
 *    Parameter    :
 *         buf :      (InOut) kanji buffer
 *         zenp :     (In) zen-kouho type.
 *         bun_no :     (In) staring bun no.
 *         bun_no2 :     (In) ending bun no. (exclusive)
 *         dp :     (In)  dai-bunsetsu
 *         dcnt :     (In)  no. of dai-bunsetsu
 *         uniq_level :     (In) unique level
 *         fuku :     (In)  fukugou-go
 *         nhinsi :     (In)  no. of hinsi
 *         hlist :     (In)  hinsi list
 *         daip :     (In)  henkan type
 *
 *    Return value : no. of dai-bunsetsu
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
/* from insert_dai */
	/* for zenkouho, assume bun_no = bun_no2 = zenkouho_suu */
static int
insert_dai_or_ikeiji(buf, zenp, bun_no, bun_no2, dp, dcnt, uniq_level, fuku, nhinsi, hlist, daip)
struct wnn_buf_mt *buf;
int bun_no, bun_no2;
struct wnn_dai_bunsetsu *dp;
int dcnt;
int zenp;
int uniq_level;
int fuku, nhinsi, *hlist;
int daip;
{
    register WNN_BUN **b, **b0;
    register int k, l, m;
    register int cnt = 0;
    struct wnn_sho_bunsetsu *sp, *sp1;

    if(bun_no == -1){
	bun_no = bun_no2 = (zenp == BUN)? buf->orig.bun_suu: buf->orig.zenkouho_suu;
    }

    for(k = 0; k < dcnt ; k++){
	cnt += dp[k].sbncnt;
    }
    make_space_for(buf, zenp, bun_no, bun_no2, cnt);
				/* zenkouho_dai_suu must not be initialized */

    b = ((zenp == BUN)? buf->orig.bun: buf->orig.zenkouho) + bun_no;

    for(k = 0, m = buf->orig.zenkouho_dai_suu ; k < dcnt; k++){
	/* 異形字変換の際は、find_same_kouho_dai() をして、
	   次候補リストのダブリを防ぐ */
	if(uniq_level){
	    if(find_same_kouho_dai(&dp[k], buf, m, uniq_level))
		continue;
	}
	sp = dp[k].sbn;
	if(zenp == ZENKOUHO){
	    buf->orig.zenkouho_dai[m++] = b - buf->orig.zenkouho;
	}
	b0 = b;
	sp1 = sp;
	for(l = 0 ; l < dp[k].sbncnt; l++){
	    *b = get_sho(buf, sp, zenp, daip, fuku, nhinsi, hlist);
	    if(zenp == ZENKOUHO){
		if (l == dp[k].sbncnt -1){
		    if(buf->orig.zenkouho_endvect != -1){
			(*b)->dai_end = (sp->status_bkwd == WNN_CONNECT_BK)? 0:1;
		    }else{
			(*b)->dai_end = 0;
		    }
		}else{
		    (*b)->dai_end = 0;
		}
	    }
	    b++;
	    sp++;
	}
	(*b0)->dai_top = (sp1->status == WNN_CONNECT)? 0:1;
	(*b0)->daihyoka = dp[k].hyoka;
    }
    if(zenp == ZENKOUHO){
	buf->orig.zenkouho_dai[m] = b - buf->orig.zenkouho;
	buf->orig.zenkouho_suu = b - buf->orig.zenkouho;
	buf->orig.zenkouho_dai_suu = m;
    }
    return(cnt + bun_no);
}


/*:::DOC_START
 *
 *    Function Name: jl_set_ikeiji_dai
 *    Description  :
 *         set current kouho
 *          
 *    Parameter    :
 *         buf :      (InOut) kanji buffer
 *         offset :     (In) target bun no.
 *
 *    Return value : current bun no.
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
/* ?? need, identical jl_set_jikouho_dai */
int
jl_set_ikeiji_dai(buf, offset)
register struct wnn_buf *buf;
int offset;
{
    register int st, end, bun, k;

    if(!buf) return(-1);
    LockMutex(&BUF_LOCK(buf));
    buf_wnn_errorno_set = 0;
    if(buf->zenkouho_suu <= 0) {
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    if(buf->zenkouho_daip == SHO){
	UnlockMutex(&BUF_LOCK(buf));
	return(-1);
    }
    offset = (offset + buf->zenkouho_dai_suu) % buf->zenkouho_dai_suu;
    if(buf->zenkouho_end_bun < buf->bun_suu && buf->zenkouho_endvect != -1)
	buf->bun[buf->zenkouho_end_bun]->dai_top =
		buf->zenkouho[buf->zenkouho_dai[offset+1]-1]->dai_end;
    free_bun((WNN_BUF_MT *)buf, buf->zenkouho_bun, buf->zenkouho_end_bun);
    st = buf->zenkouho_dai[offset];
    end = buf->zenkouho_dai[offset + 1];
    make_space_for((WNN_BUF_MT *)buf, BUN, buf->zenkouho_bun,
		   buf->zenkouho_end_bun, end - st);
    for(bun = buf->zenkouho_bun, k = st; k < end;){
	set_sho(buf->zenkouho[k++], &buf->bun[bun++]);
    }
    buf->zenkouho_end_bun = buf->zenkouho_bun + end - st;
    buf->c_zenkouho = offset;
    UnlockMutex(&BUF_LOCK(buf));
    return(offset);
}

