;; SKK (Simple Kana to Kanji conversion program)
;; version 8.6 of May 17, 1995
;; Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995
;; Masahiko Sato (masahiko@sato.riec.tohoku.ac.jp)

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either versions 2, or (at your option)
;; any later version.

;; This program is distributed in the hope that it will be useful
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with SKK, see the file COPYING.  If not, write to the Free
;; Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;; Following people contributed modifications to skk.el:
;;	Masakazu Takahashi (masaka-t@ascii.co.jp)
;;	Tsugutomo Enami (enami@ptgd.sony.co.jp)
;;	MORI, Koichi (kmori@onsei2.rilp.m.u-tokyo.ac.jp)
;;	Jun-ichi Nakamura (nakamura@pluto.ai.kyutech.ac.jp)
;;	Kazuo Hirokawa (hirokawa@ricsgw.rics.co.jp)
;;	Wataru Matsui (matsui@atr-rd.atr.co.jp)
;;	Tomoyuki Hiro (hiro@momo.it.okayama-u.ac.jp)
;;	Masahiko Suzuki (suzmasa@sm.sony.co.jp)
;;	Katuya Tomioka (tomioka@culle.l.chiba-u.ac.jp)
;;	Kiyotaka Sakai (ksakai@mtl.t.u-tokyo.ac.jp)
;;	MIYOSHI Tsutomu (minkov@fuzzy.or.jp)
;;	Kazushi Marukawa (kazushi@kubota.co.jp)
;;	Ryoichi Hashimoto (gnu@ipri.go.jp)
;;	Hisao Kuroda (kuroda@msi.co.jp)
;;	Masahiro Doteguchi (xdote@rp.open.cs.fujitsu.co.jp)
;;	Naoki HAMADA (nao@mimo.jaist-east.ac.jp)
;;	Chikanobu Toyofuku (unbound@papaya.juice.or.jp)
;;	Shuji Ashizawa (ashizawa@zuken.co.jp)
;;	GUNJI Takao (gunji@lisa.lang.osaka-u.ac.jp)
;;	IIDA Yosiaki (iida@secom-sis.co.jp)
;;	Kimura Chikahiro (kimura@oa1.kb.nec.co.jp)
;;	Motohiko Mouri (mouri@jaist.ac.jp)
;;	Takeshi OHTANI (ohtani@iias.flab.fujitsu.co.jp)
;;	Haru Mizuno (mizu@cs3.cs.oki.co.jp)
;;	Mikio Nakajima (PBC01764@niftyserve.or.jp)
;;	中津山 恒 (hisashi@rst.fujixerox.co.jp)

;; version 8.6 released 1995.5.17
;; version 7.18 released 1994.6.7
;; version 6.32 released 1993.4.24
;; version 5.30 released 1992.5.9
;; version 4.33 released 1991.5.9
;; version 3.47 released 1990.4.29
;; version 2.25 released 1989.4.15
;; version 1.13 released 1988.4.22

(defun skk-version ()
  (interactive)
  (if (interactive-p)
      (message "SKK version %s of May 17, 1995" (skk-version))
    "8.6"))

(defun skk-server-version ()
  (interactive)
  (if (interactive-p)
      (message (skk-server-version))
    (if skk-server-host
	(let (v)
	  (set-buffer (get-buffer-create " *skkserv*"))
	  (erase-buffer)
	  (if (process-status "skkservd")
	      (progn
		(process-send-string "skkservd" "2")
		;; modified by Kiyotaka Sakai, 1994.9.9.
		(while (= (buffer-size) 0)
		  (accept-process-output))
		(setq v (buffer-substring (point-min) (1- (point-max))))
		(erase-buffer)
		(process-send-string "skkservd" "3")
		;; modified by Kiyotaka Sakai, 1994.9.9.
		(while (= (buffer-size) 0)
		  (accept-process-output))
		(format "SKK SERVER %s running on HOST %s." v
			(buffer-substring
			 (point-min)
			 (progn
			   (goto-char (point-min))
			   (search-forward ":")
			   (- (point) 1)))))
	    "SKK SERVER is not active."))
      "You are not using SKK SERVER.")))

;; variable declarations

(defvar j-count-touroku 0)
(defvar j-count-kakutei 0)

(defvar j-kakutei-early nil)
(defvar j-kakutei-key nil)

(defvar skk-isearch-message nil
  "User must not change the value of this value.  This variable is used in
conjunction with skk-isearch.")

(defvar j-skk-mode-invoked nil
  "The value is t if skk-mode was invoked in this Emacs session.")

(defvar skk-mode nil
  "The value is t if skk-mode is currently invoked on the current buffer,
it is nil otherwise.")
(make-variable-buffer-local 'skk-mode)

(defvar j-mode-line-format nil
  "Save mode-line-format of the current buffer.  This variable may also be
used to test if skk-mode has been called on the current buffer.")
(make-variable-buffer-local 'j-mode-line-format)

(defvar j-current-local-map nil
  "Save current-local-map")
(make-variable-buffer-local 'j-current-local-map)

(defvar j-vip-current-mode nil
  "Save vip-current-mode")
(make-variable-buffer-local 'j-vip-current-mode)

;; Tsugutomo Enami suggested that the variables skk-map, skk-zenkaku-map and
;; skk-abbrev-map be initially set to nil, 1990.7.13.

(defvar skk-map nil
  "Keymap for kana mode.")
(make-variable-buffer-local 'skk-map)

(defvar skk-zenkaku-map nil
  "Keymap for zenkaku mode.")
(make-variable-buffer-local 'skk-zenkaku-map)

(defvar skk-abbrev-map nil
  "Keymap for abbrev input.")
(make-variable-buffer-local 'skk-abbrev-map)

(defvar skk-minibuff-map nil
  "Keymap used when reading string from minibuffer.")

(defvar j-emacs-local-map nil
  "Original keymap for emacs mode.")
(make-variable-buffer-local 'j-emacs-local-map)

(defvar j-mode-line-skk nil)
(make-variable-buffer-local 'j-mode-line-skk)

(defvar j-prefix "")

(defvar j-mode nil)
(make-variable-buffer-local 'j-mode)

(defvar j-henkan-on nil)
(make-variable-buffer-local 'j-henkan-on)

(defvar j-henkan-start-point nil
  "Henkan start point as a marker.")
(make-variable-buffer-local 'j-henkan-start-point)

(defvar j-henkan-end-point nil
  "Henkan end point as a marker.")
(make-variable-buffer-local 'j-henkan-end-point)

(defvar j-kana-start-point nil
  "Start point of a kana character as a marker.")

(defvar j-okurigana nil
  "If t, it means that okurigana part of henkan word is being input.")
(make-variable-buffer-local 'j-okurigana)

(defvar j-okurigana-start-point nil
  "Start point of okurigana")
(make-variable-buffer-local 'j-okurigana-start-point)

(defvar j-okuri-char ""
  "The roman prefix for the okurigana part of henkan word as a string.")
(make-variable-buffer-local 'j-okuri-char)

(defvar j-henkan-count 0)
(make-variable-buffer-local 'j-henkan-count)

(defvar j-okuri-index-min 0)
(make-variable-buffer-local 'j-okuri-index-min)

(defvar j-okuri-index-max 0)
(make-variable-buffer-local 'j-okuri-index-max)

(defvar j-henkan-active nil)
(make-variable-buffer-local 'j-henkan-active)

(defvar j-katakana nil
  "t means katakana and nil means hirakana input.")
(make-variable-buffer-local 'j-katakana)

(defvar j-okuri-ari)
(make-variable-buffer-local 'j-okuri-ari)

(defvar j-henkan-key)
(make-variable-buffer-local 'j-henkan-key)

(defvar j-henkan-key2 nil)
(make-variable-buffer-local 'j-henkan-key2)

(defvar j-henkan-okurigana nil)
(make-variable-buffer-local 'j-henkan-okurigana)

(defvar j-henkan-vector (vector))
(make-variable-buffer-local 'j-henkan-vector)

(defvar j-jisyo-buffer-modified nil)

(defvar j-search-prog-list nil)
(make-variable-buffer-local 'j-search-prog-list)

(defvar j-zenkaku)
(make-variable-buffer-local 'j-zenkaku)

(defvar j-abbrev nil)
(make-variable-buffer-local 'j-abbrev)

(defvar j-completion-word "")

(defvar j-zenkaku-alist
  '((?  . "　") 
    (?! . "！")
    (?\" . "”")
    (?# . "＃")
    (?$ . "＄")
    (?% . "％")
    (?& . "＆")
    (?' . "’")
    (?( . "（")
    (?) . "）")
    (?* . "＊")
    (?+ . "＋")
    (?, . "，")
    (?- . "−")
    (?. . "．")
    (?/ . "／")
    (?: . "：")
    (?; . "；")
    (?< . "＜")
    (?= . "＝")
    (?> . "＞")
    (?? . "？")
    (?@ . "＠")
    (?[ . "［")
    (?\\ . "￥")
    (?] . "］")
    (?^ . "＾")
    (?_ . "＿")
    (?{ . "｛")
    (?| . "｜")
    (?} . "｝")
    (?~ . "￣")))

(defvar j-num-list ()
  "list of numeric arguments obtained from j-henkan-key.  for instance,
if j-henkan-key is \"2がつ25にち\", j-num-list will be set to
(\"2\" \"25\").")
(make-variable-buffer-local 'j-num-list)

(defvar j-search-key nil
  "string used as the search key for midashi search in jisyo buffer. the value
of this variable is set by using j-henkan-key.  for instance, if j-henkan-key
is \"2がつ25にち\", j-search-key will be set to \"#がつ#にち\".")
(make-variable-buffer-local 'j-search-key)

;(defvar j-okuri-ari-min nil)
;(make-variable-buffer-local 'j-okuri-ari-min)
;(defvar j-okuri-ari-max nil)
;(make-variable-buffer-local 'j-okuri-ari-max)
;(defvar j-okuri-nasi-min nil)
;(make-variable-buffer-local 'j-okuri-nasi-min)
(defvar j-jisyo-okuri-info nil)
;(make-variable-buffer-local 'j-jisyo-okuri-info)

;; variables for the function input-by-code-or-menu

(defvar j-code-n1-min 161)
(defvar j-code-n1-max 244)
(defvar j-code-n2-min 161)
(defvar j-code-n2-max 254)
(defvar j-code-null 128)
(defvar j-input-by-code-or-menu-jump-default j-code-n1-min)

;; The following variable was introduced at the suggestion of Masakazu
;; Takahashi, 1991.10.1.

(defvar j-remote-shell-program "rsh")
(defvar system-type 'skkinput)

;; The following variable was introduced at the suggestion of Masahiko
;; Suzuki, 1992.7.13.
;; modified by Mikio Nakajima, 1994.12.4
;(defvar skk-init-file (if (eq system-type 'ms-dos) "~/_skk" "~/.skk")
;  "*The name of the skk initialization file.")
(defvar skk-init-file (if (eq system-type 'ms-dos) "~/_skkinput_el" "~/.skkinput.el")
  "*The name of the skk initialization file.")

;; The following variable was introduced at the suggestion of Ryoichi
;; Hashimoto, 1993.4.1.

(defvar j-special-midashi-char-list '(?> ?< ??)
  "*List of chars used to spicify pre/post-fixes.")

;; The following variable was introduced by Tsugutomo Enami, 1994.5.30.

(defvar j-henkan-okuri-strictly nil
  "If non-nil, okurigana should also be matched.")

;; Create mutex object for locking jisyo-save
(defvar skk-jisyo-mutex (get-mutex-create nil nil))

;; The following variable was introduced by Kiyotaka Sakai, 1994.6.14.

(defconst j-kanji-len (length "あ"))

;; constants

;; Customization of these constants cannot be done in .emacs file.  This
;; should be done in .skk file or by using skk-mode-hook.

;; We are using `defconst' rather than `defvar' here for the following
;; reason:  The SKK tutorial program, which is intended for the beginners,
;; must be run on a vanilla SKK.  To achieve this, the tutorial program
;; loads SKK (even if it has been loaded already) and undoes the customization
;; which might have been done by the user.  (Note that `defconst' always sets
;; a new value, while `defvar' does that only when the value is unbound when
;; `defvar' is executed.)

(defconst skk-kakutei-jisyo nil
  "*Name of a sorted jisyo file.  If non-nil, the file will be read in a
buffer and will be used to compute henkan candidates.  The file should be
such that each yomi has exactly one candidate.  This file is used by the
function j-search-kakutei-jisyo-file.")

(defconst skk-initial-search-jisyo nil
  "*Name of a sorted jisyo file.  If non-nil, the file will be read in a
buffer and will be used to compute henkan candidates.  Normally, this
file will be searched before the user's private jisyo.")

(defconst skk-large-jisyo nil
  "*Name of a sorted jisyo file.  If non-nil, the file will be read in a
buffer and will be used to compute henkan candidates.  Normally, the
file be searched after the user's private jisyo.")

(defconst skk-aux-large-jisyo nil
  "*Name of a sorted jisyo file.  If non-nil, the file will be used when
skk server is not active.")

(defconst skk-search-prog-list
  '(
    (j-search-kakutei-jisyo-file skk-kakutei-jisyo 10000 t)
    (j-search-jisyo-file skk-initial-search-jisyo 10000 t)
    (j-merge-search-jisyo-file skkinput-jisyo skk-jisyo)
    (j-merge-okuri-search skkinput-jisyo skk-jisyo)
;    (j-search-jisyo-file skkinput-jisyo 0 t)
;    (j-okuri-search)
    (j-search-jisyo-file skk-large-jisyo 10000)
    (j-search-server skk-aux-large-jisyo 10000)
    )
  "*List of sexps such that each element, when evaluated, returns a vector
of henkan candidates for j-henkan-key.")

;; modified by Mikio Nakajima, 1994.12.4
(defconst skkinput-jisyo (if (eq system-type 'ms-dos) "~/_skkinput-jisyo" "~/.skkinput-jisyo")
  "*The name of the skk jisyo file.")

(defconst skk-jisyo (if (eq system-type 'ms-dos) "~/_skk-jisyo" "~/.skk-jisyo")
  "*The name of the skk jisyo file.")

;; modified by Mikio Nakajima, 1994.12.4
(defconst skkinput-backup-jisyo
  (if (eq system-type 'ms-dos) "~/_skk-jisyo.BAK" "~/.skkinput-jisyo.BAK")
  "*The name of the skk backup jisyo file.")

;; suggested by Koichi Mori, 1990.8.20
(defconst skk-jisyo-code nil
  "*If non-nil, it is used as the value of kanji-fileio-code for the jisyo
buffer.")

;; modified by Mikio Nakajima, 1994.12.4
(defconst skk-record-file
  (if (eq system-type 'ms-dos) "~/_skk-record" "~/.skkinput-record")
  "*The name of the skk record file.")

(defconst skk-kakutei-key "\C-j"
  "*Key sequence that will invoke the command j-kakutei.")

;; suggested by Koichi Mori, 1991.1.27.
(defconst skk-date-ad nil
  "*If non-nil, j-date is in A.D.  If nil, it is in Nengo (Heisei).")

;; suggested by Koichi Mori, 1991.1.27.
(defconst skk-number-style 1
  "*If nil or 0, numbers in j-date are in Hankaku. If t or 1, in Zenkaku.
Otherwise Kanji.")

(defconst skk-keep-record t
  "*If t, skk will keep record of the success rate of kana to kanji conversion
etc. in the file ~/.skkinput-record.")

(defconst skk-use-vip nil
  "*If t, skk will assume that the user will use vip-mode at the same time.")

(defconst skk-auto-okuri-process nil
  "*If t, skk automatically recognizes okuri-gana part.  For instance, you
can just type `Uresii ' and it will be converted as you expect. This
behavior is available only if SKK-PROCESS-OKURI-EARLY is nil.")

(defconst skk-process-okuri-early nil
  "*If t, skk will start kana to kanji conversion when it reads the first
roman character for okurigana, if nil then kana to kanji conversion will
start only when it reads a complete roman representation for a kana
character.")

;; introduced by Wataru Matsui 1991.8.19
(defconst skk-egg-like-newline nil
  "*If non-nil, no newline is inserted in any henkan mode.")

(defconst skk-kakutei-early t
  "*If t, the values of J-HENKAN-ACTIVE is also t, and SKK-PROCESS-OKURI-EARLY
is nil, then skk will kakutei the current candidate when j-kana-input is
called.")

;; the following three variables were introduced by Kiyotaka Sakai, 1994.7.3.

(defconst j-henkan-show-candidates-keys '(?a ?s ?d ?f ?j ?k ?l)
  "*Chars when you select candidates by menu. This list should contain 7
characters.")

(defconst j-input-by-code-menu-keys1 '(?a ?s ?d ?f ?g ?h ?q ?w ?e ?r ?t ?y)
  "*Chars when you input JIS characters by menu at first. This list should
contain 12 characters.")

(defconst j-input-by-code-menu-keys2
  '(?a ?s ?d ?f ?g ?h ?j ?k ?l ?q ?w ?e ?r ?t ?y ?u)
  "*Chars when you input JIS characters by menu in the second. This list
should contain 16 characters.")

(defconst skk-mode-string "--SKK:"
  "*The value of this constant is used in the mode line when skk is in ascii
mode.")

(defconst skk-hirakana-mode-string "--かな"
  "*The value of this constant is used in the mode line when skk is in hirakana
mode.")

(defconst skk-katakana-mode-string "--カナ"
  "*The value of this constant is used in the mode line when skk is in katakana
mode.")

(defconst skk-zenei-mode-string "--全英"
  "*The value of this constant is used in the mode line when skk is in zenei
mode.")

(defconst skk-echo t
  "*If T, echoes prefix for kana characters.")

(defconst skk-server-host (getenv "SKKSERVER")
  "*Name of the host running SKK Jisyo Server")

(defconst skk-serv (getenv "SKKSERV")
  "*Name of the SKK Jisyo Server program")

;; introduced by Kiyotaka Sakai 1993.7.28
(defconst skk-server-list nil
  "*List of the SKK Jisyo Server")

(defconst skk-portnum nil
  "*If the value is non-nil, it must be the PORTNUM defined in skkserv.h")

(defconst skk-report-server-response nil
  "*When SKK sends a request to SKK SERVER, SKK waits for the process output
by repeatedly executing the accept-process-output function.  If this constant
is t, then SKK will report the number of times the function is called.")

(defconst skk-use-numeric-conversion t
  "*If t, convert numerals in the henkan word appropriately.")

(defconst skk-nemacs-v2 (not (boundp 'self-insert-after-hook))
  "If t, it means that skk is running under Nemacs version 2 (very old
Nemacs.")

(defconst skk-mule t ;(and (boundp 'MULE) MULE)
  "If t, it means that skk is running under Mule.")

;; introduced by Kiyotaka Sakai 1994.1.10
;; modified by Mikio Nakajima, 1994.12.4
;; modified by 中津山  恒, 1995.4.10
;; modified by Mikio Nakajima, 1995.4.11
;(defconst skk-emacs19 (string-match "^19" emacs-version)
;  "If non-nil, it means that skk is running under emacs-19.")
(defconst skk-emacs19 t)

(defconst skk-dabbrev-like-completion nil
  "*If t, completion will be done like dabbrev-expand.  namely, if one tries
completion successively, completion will be done for the initial completion
word rather than the most recently completed word.")

(defconst skk-delete-implies-kakutei t
  "*This variable is use to control the behavior of the function
j-delete-backward-char when it is called with j-henkan-active being t.
If the variable is non-nil, the previous charater will be deleted and
j-kakutei will be called.  If nil, j-previous-candidate will be called
instead.")

(defconst skk-delete-okuri-when-quit nil)

(defconst skk-num-type-list
  '((?0 . identity) ; modified by Mikio Nakajima, 1995.4.19
    (?1 . j-zenkaku-num-str)
    (?2 . j-kanji-num-str)
    (?3 . j-kanji-num-str2)
    (?9 . j-shogi-num-str))
  "*association list of type-function pairs used in the conversion of numeric
arguments in henkan key.")

(defconst skk-char-type-vector
  [0 0 0 0 0 0 0 0
   5 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0
   0 4 4 4 4 4 4 4
   4 4 4 4 0 4 4 4
   4 0 4 4 4 4 4 4
   0 4 4 0 0 0 0 0
   0 3 1 1 1 3 1 1
   1 3 1 1 0 1 2 3
   1 0 1 1 1 3 1 1
   2 1 1 0 0 0 0 5]
  "*char type is interpreted as follows.
0 exit rom-kana conversion (not used at present)
1 consonant that can be part of sokuon
2 other consonants (n, x)
3 vowel
4 bound to j-set-henkan-point in skk-mode
5 delete prefix")

(defconst skk-kana-rom-vector
  ["x" "a" "x" "i" "x" "u" "x" "e" "x" "o" "k" "g" "k" "g" "k" "g"
   "k" "g" "k" "g" "s" "z" "s" "j" "s" "z" "s" "z" "s" "z" "t" "d"
   "t" "d" "x" "t" "d" "t" "d" "t" "d" "n" "n" "n" "n" "n" "h" "b"
   "p" "h" "b" "p" "h" "b" "p" "h" "b" "p" "h" "b" "p" "m" "m" "m"
   "m" "m" "x" "y" "x" "y" "x" "y" "r" "r" "r" "r" "r" "x" "w" "x"
   "x" "w" "n"]
  "*kana to roman conversion giving only the first roman character
corresponding to the following kana characters.  For the characters
「じ」, 「ち」,「ふ」, you might want to change the values for them to
\"z\", \"c\", \"f\".
    ぁ  あ  ぃ  い  ぅ  う  ぇ  え  ぉ  お  か  が  き  ぎ  く  ぐ
    け  げ  こ  ご  さ  ざ  し  じ  す  ず  せ  ぜ  そ  ぞ  た  だ
    ち  ぢ  っ  つ  づ  て  で  と  ど  な  に  ぬ  ね  の  は  ば
    ぱ  ひ  び  ぴ  ふ  ぶ  ぷ  へ  べ  ぺ  ほ  ぼ  ぽ  ま  み  む
    め  も  ゃ  や  ゅ  ゆ  ょ  よ  ら  り  る  れ  ろ  ゎ  わ  ゐ
    ゑ  を  ん")

(defconst skk-prefix-list
  '("by" "ch" "cy" "dh" "dy" "fy" "gy" "hy" "jy" "ky" "my" "py" "ry" "sh" "sy"
    "th" "ts" "ty" "xk" "xt" "xts" "xw" "xy" "zy"))

(defconst skk-rom-kana-rule-list
  '(("nn" nil ("ン" . "ん"))
    ("n'" nil ("ン" . "ん"))))

(defconst skk-rom-kana-rule-tree nil)

(defconst skk-roma-kana-a
  '(("" . ("あ" . "ア"))
    ("b" . ("ば" . "バ")) ("by" . ("びゃ" . "ビャ"))
    ("ch" . ("ちゃ" . "チャ")) ("cy" . ("ちゃ" . "チャ")) 
    ("d" . ("だ" . "ダ")) ("dh" . ("でゃ" . "デャ"))
    ("dy" . ("ぢゃ" . "ヂャ"))
    ("f" . ("ふぁ" . "ファ")) ("fy" . ("ふゃ" . "フャ"))
    ("g" . ("が" . "ガ")) ("gy" . ("ぎゃ" . "ギャ"))
    ("h" . ("は" . "ハ")) ("hy" . ("ひゃ" . "ヒャ"))
    ("j" . ("じゃ" . "ジャ")) ("jy" . ("じゃ" . "ジャ"))
    ("k" . ("か" . "カ")) ("ky" . ("きゃ" . "キャ"))
    ("m" . ("ま" . "マ")) ("my" . ("みゃ" . "ミャ"))
    ("n" . ("な" . "ナ")) ("ny" . ("にゃ" . "ニャ"))
    ("p" . ("ぱ" . "パ")) ("py" . ("ぴゃ" . "ピャ"))
    ("r" . ("ら" . "ラ")) ("ry" . ("りゃ" . "リャ"))
    ("s" . ("さ" . "サ")) ("sh" . ("しゃ" . "シャ"))
    ("sy" . ("しゃ" . "シャ"))
    ("t" . ("た" . "タ")) ("th" . ("てぁ" . "テァ"))
    ("ty" . ("ちゃ" . "チャ"))
    ("v" . ("う゛ぁ" . "ヴァ")) ("w" . ("わ" . "ワ"))
    ("x" . ("ぁ" . "ァ")) ("xk" . ("か" . "ヵ"))
    ("xw" . ("ゎ" . "ヮ")) ("xy" . ("ゃ" . "ャ"))
    ("y" . ("や" . "ヤ"))
    ("z" . ("ざ" . "ザ")) ("zy" . ("じゃ" . "ジャ"))))

(defconst skk-roma-kana-i
  '(("" . ("い" . "イ"))
    ("b" . ("び" . "ビ")) ("by" . ("びぃ" . "ビィ"))
    ("ch" . ("ち" . "チ")) ("cy" . ("ちぃ" . "チィ"))
    ("d" . ("ぢ" . "ヂ")) ("dh" . ("でぃ" . "ディ"))
    ("dy" . ("ぢぃ" . "ヂィ"))
    ("f" . ("ふぃ" . "フィ")) ("fy" . ("ふぃ" . "フィ"))
    ("g" . ("ぎ" . "ギ")) ("gy" . ("ぎぃ" . "ギィ"))
    ("h" . ("ひ" . "ヒ")) ("hy" . ("ひぃ" . "ヒィ"))
    ("j" . ("じ" . "ジ")) ("jy" . ("じぃ" . "ジィ"))
    ("k" . ("き" . "キ")) ("ky" . ("きぃ" . "キィ"))
    ("m" . ("み" . "ミ")) ("my" . ("みぃ" . "ミィ"))
    ("n" . ("に" . "ニ")) ("ny" . ("にぃ" . "ニィ"))
    ("p" . ("ぴ" . "ピ")) ("py" . ("ぴぃ" . "ピィ"))
    ("r" . ("り" . "リ")) ("ry" . ("りぃ" . "リィ"))
    ("s" . ("し" . "シ")) ("sh" . ("し" . "シ"))
    ("sy" . ("しぃ" . "シィ"))
    ("t" . ("ち" . "チ")) ("th" . ("てぃ" . "ティ"))
    ("ty" . ("ちぃ" . "チィ"))
    ("v" . ("う゛ぃ" . "ヴィ")) ("w" . ("うぃ" . "ウィ"))
    ("x" . ("ぃ" . "ィ")) ("xw" . ("ゐ" . "ヰ"))
    ("z" . ("じ" . "ジ")) ("zy" . ("じぃ" . "ジィ"))))

(defconst skk-roma-kana-u
  '(("" . ("う" . "ウ"))
    ("b" . ("ぶ" . "ブ")) ("by" . ("びゅ" . "ビュ"))
    ("ch" . ("ちゅ" . "チュ")) ("cy" . ("ちゅ" . "チュ"))
    ("d" . ("づ" . "ヅ")) ("dh" . ("でゅ" . "デュ"))
    ("dy" . ("ぢゅ" . "ヂュ"))
    ("f" . ("ふ" . "フ")) ("fy" . ("ふゅ" . "フュ"))
    ("g" . ("ぐ" . "グ")) ("gy" . ("ぎゅ" . "ギュ"))
    ("h" . ("ふ" . "フ")) ("hy" . ("ひゅ" . "ヒュ"))
    ("j" . ("じゅ" . "ジュ")) ("jy" . ("じゅ" . "ジュ"))
    ("k" . ("く" . "ク")) ("ky" . ("きゅ" . "キュ"))
    ("m" . ("む" . "ム")) ("my" . ("みゅ" . "ミュ"))
    ("n" . ("ぬ" . "ヌ")) ("ny" . ("にゅ" . "ニュ"))
    ("p" . ("ぷ" . "プ")) ("py" . ("ぴゅ" . "ピュ"))
    ("r" . ("る" . "ル")) ("ry" . ("りゅ" . "リュ"))
    ("s" . ("す" . "ス")) ("sh" . ("しゅ" . "シュ"))
    ("sy" . ("しゅ" . "シュ"))
    ("t" . ("つ" . "ツ")) ("th" . ("てゅ" . "テュ"))
    ("ts" . ("つ" . "ツ")) ("ty" . ("ちゅ" . "チュ"))
    ("v" . ("う゛" . "ヴ")) ("w" . ("う" . "ウ"))
    ("x" . ("ぅ" . "ゥ")) ("xt" . ("っ" . "ッ"))
    ("xts" . ("っ" . "ッ")) ("xy" . ("ゅ" . "ュ"))
    ("y" . ("ゆ" . "ユ"))
    ("z" . ("ず" . "ズ")) ("zy" . ("じゅ" . "ジュ"))))

(defconst skk-roma-kana-e
  '(("" . ("え" . "エ"))
    ("b" . ("べ" . "ベ")) ("by" . ("びぇ" . "ビェ"))
    ("ch" . ("ちぇ" . "チェ")) ("cy" . ("ちぇ" . "チェ"))
    ("d" . ("で" . "デ")) ("dh" . ("でぇ" . "デェ"))
    ("dy" . ("ぢぇ" . "ヂェ"))
    ("f" . ("ふぇ" . "フェ")) ("fy" . ("ふぇ" . "フェ"))
    ("g" . ("げ" . "ゲ")) ("gy" . ("ぎぇ" . "ギェ"))
    ("h" . ("へ" . "ヘ")) ("hy" . ("ひぇ" . "ヒェ"))
    ("j" . ("じぇ" . "ジェ")) ("jy" . ("じぇ" . "ジェ"))
    ("k" . ("け" . "ケ")) ("ky" . ("きぇ" . "キェ"))
    ("m" . ("め" . "メ")) ("my" . ("みぇ" . "ミェ"))
    ("n" . ("ね" . "ネ")) ("ny" . ("にぇ" . "ニェ"))
    ("p" . ("ぺ" . "ペ")) ("py" . ("ぴぇ" . "ピェ"))
    ("r" . ("れ" . "レ")) ("ry" . ("りぇ" . "リェ"))
    ("s" . ("せ" . "セ")) ("sh" . ("しぇ" . "シェ"))
    ("sy" . ("しぇ" . "シェ"))
    ("t" . ("て" . "テ")) ("th" . ("てぇ" . "テェ"))
    ("ty" . ("ちぇ" . "チェ"))
    ("v" . ("う゛ぇ" . "ヴェ")) ("w" . ("うぇ" . "ウェ"))
    ("x" . ("ぇ" . "ェ")) ("xk" . ("け" . "ヶ"))
    ("xw" . ("ゑ" . "ヱ"))
    ("y" . ("いぇ" . "イェ"))
    ("z" . ("ぜ" . "ゼ")) ("zy" . ("じぇ" . "ジェ"))))

(defconst skk-roma-kana-o
  '(("" . ("お" . "オ"))
    ("b" . ("ぼ" . "ボ")) ("by" . ("びょ" . "ビョ"))
    ("ch" . ("ちょ" . "チョ")) ("cy" . ("ちょ" . "チョ"))
    ("d" . ("ど" . "ド")) ("dh" . ("でょ" . "デョ"))
    ("dy" . ("ぢょ" . "ヂョ"))
    ("f" . ("ふぉ" . "フォ")) ("fy" . ("ふょ" . "フョ"))
    ("g" . ("ご" . "ゴ")) ("gy" . ("ぎょ" . "ギョ"))
    ("h" . ("ほ" . "ホ")) ("hy" . ("ひょ" . "ヒョ"))
    ("j" . ("じょ" . "ジョ")) ("jy" . ("じょ" . "ジョ"))
    ("k" . ("こ" . "コ")) ("ky" . ("きょ" . "キョ"))
    ("m" . ("も" . "モ")) ("my" . ("みょ" . "ミョ"))
    ("n" . ("の" . "ノ")) ("ny" . ("にょ" . "ニョ"))
    ("p" . ("ぽ" . "ポ")) ("py" . ("ぴょ" . "ピョ"))
    ("r" . ("ろ" . "ロ")) ("ry" . ("りょ" . "リョ"))
    ("s" . ("そ" . "ソ")) ("sh" . ("しょ" . "ショ"))
    ("sy" . ("しょ" . "ショ"))
    ("t" . ("と" . "ト")) ("th" . ("てょ" . "テョ"))
    ("ty" . ("ちょ" . "チョ"))
    ("v" . ("う゛ぉ" . "ヴォ")) ("w" . ("を" . "ヲ"))
    ("x" . ("ぉ" . "ォ")) ("xy" . ("ょ" . "ョ"))
    ("y" . ("よ" . "ヨ"))
    ("z" . ("ぞ" . "ゾ")) ("zy" . ("じょ" . "ジョ"))))

(defconst skk-input-vector
  [nil  nil  nil  nil  nil  nil  nil  nil
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  "！" nil  nil  nil  nil  nil  nil
   nil  nil  nil  nil  "、" "ー" "。" nil
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  "：" "；" nil  nil  nil  "？"
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  "「" nil  "」" nil  nil
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil]
  "*Translation table for j-self inserting characters.")

(defconst skk-zenkaku-vector
  [nil  nil  nil  nil  nil  nil  nil  nil
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   nil  nil  nil  nil  nil  nil  nil  nil 
   "　"  "！" "”" "＃" "＄" "％" "＆" "’"
   "（" "）" "＊" "＋" "，" "−" "．" "／"
   "０" "１" "２" "３" "４" "５" "６" "７"
   "８" "９" "：" "；" "＜" "＝" "＞" "？"
   "＠" "Ａ" "Ｂ" "Ｃ" "Ｄ" "Ｅ" "Ｆ" "Ｇ"
   "Ｈ" "Ｉ" "Ｊ" "Ｋ" "Ｌ" "Ｍ" "Ｎ" "Ｏ"
   "Ｐ" "Ｑ" "Ｒ" "Ｓ" "Ｔ" "Ｕ" "Ｖ" "Ｗ"
   "Ｘ" "Ｙ" "Ｚ" "［" "＼" "］" "＾" "＿"
   "‘" "ａ" "ｂ" "ｃ" "ｄ" "ｅ" "ｆ" "ｇ"
   "ｈ" "ｉ" "ｊ" "ｋ" "ｌ" "ｍ" "ｎ" "ｏ"
   "ｐ" "ｑ" "ｒ" "ｓ" "ｔ" "ｕ" "ｖ" "ｗ"
   "ｘ" "ｙ" "ｚ" "｛" "｜" "｝" "〜" nil])

;; utilities

;; modified by Mikio Nakajima, 1995.4.10
(if (fboundp 'member)
    (fset 'j-member 'member)
  (defun j-member (x l)
    "check if X is a member of L, where string= is used to compare elements
of L against X"
    (catch 'found
      (while l
        (if (string= x (car l))
            (throw 'found t)
          (setq l (cdr l)) )))))

;; modified by Mikio Nakajima, 1995.4.10
(if (fboundp 'assoc)
    (defun j-assoc (key a-list)
      (cdr (assoc key a-list)) )
  (defun j-assoc (key a-list)
    (let ((list a-list) (cont t) (val nil))
      (while cont
	(if (null list)
	    (setq cont nil)
	  (let ((key2 (car (car list))))
	    (if (string= key key2)
		(setq cont nil
		      val (cdr (car list)))
	      (setq list (cdr list))))))
      val)))

;; added by Kiyotak Sakai, 1994.11.8.
(cond (skk-emacs19
       (fset 'j-read-char 'read-char))
      (t
       (fset 'j-read-char 'read-char)))

(defmacro skk-move-marker (marker position &optional buffer)
  ;; バッファローカル値である skk-henkan-start-point, skk-henkan-end-point,
  ;; skk-kana-start-point, あるいは skk-okurigana-start-point が nil だったら、
  ;; 新規マーカーを作って代入する。
  (list 'progn
        (list 'if (list 'not marker)
              (list 'setq marker (list 'make-marker)) )
        (list 'set-marker marker position buffer) ))

(defun j-change-mode-line (string)
  (setq j-mode-line-skk string)
  (set-buffer-modified-p (buffer-modified-p)))

(defun j-today ()
  "Insert current date at point in Kanji."
  (interactive)
  (insert (j-date)))

;; modified by Koichi Mori, 1991.1.17

(defun j-date (&optional date-ad number-style)
  (let* ((skk-date-ad (or date-ad skk-date-ad))
	 (skk-number-style (or number-style skk-number-style))
	 (str (current-time-string))
	 (y (- (string-to-int (substring str 20 24)) 1988))
	 (year (if skk-date-ad
		   (j-num (substring str 20 24))
		 (if (= y 1) "元" (j-num (int-to-string y)))))
	 (mon (substring str 4 7))
	 (month
	  (j-num
	   (cdr (assoc mon
		       '(("Jan" . "1") ("Feb" . "2") ("Mar" . "3")
			 ("Apr" . "4") ("May" . "5") ("Jun" . "6")
			 ("Jul" . "7") ("Aug" . "8") ("Sep" . "9")
			 ("Oct" . "10") ("Nov" . "11") ("Dec" . "12"))))))
	 (day (j-num (substring str 8 10)))
	 (dw (substring str 0 3))
	 (day-of-week
	  (cdr (assoc dw
		      '(("Sun" . "日") ("Mon" . "月") ("Tue" . "火")
			("Wed" . "水") ("Thu" . "木") ("Fri" . "金")
			("Sat" . "土")))))
	 )
    (concat (if skk-date-ad "" "平成") year "年"
	    month "月" day "日" "\(" day-of-week "\)")))

;; modified by Masakazu Takahashi, 1991.3.27
;; modified by Koichi Mori, 1991.1.17

(defun j-num (str)
  "convert a number string to other style according to SKK-NUMBER-STYLE"
  (mapconcat (function j-num1) str ""))

(defun j-num1 (c)
  "convert a number character to other style according to SKK-NUMBER-STYLE"
  (cond ((or (null skk-number-style) (eq skk-number-style 0))
	 (cdr (assq c
		    '((?0 . "0") (?1 . "1") (?2 . "2") (?3 . "3")
		      (?4 . "4") (?5 . "5") (?6 . "6") (?7 . "7")
		      (?8 . "8") (?9 . "9") (?  . "")))))
	((or (eq skk-number-style t) (eq skk-number-style 1))
	 (cdr (assq c
		    '((?0 . "０") (?1 . "１") (?2 . "２") (?3 . "３")
		      (?4 . "４") (?5 . "５") (?6 . "６") (?7 . "７")
		      (?8 . "８") (?9 . "９") (?  . "")))))
	(t
	 (cdr (assq c
		    '((?0 . "〇") (?1 . "一") (?2 . "二") (?3 . "三")
		      (?4 . "四") (?5 . "五") (?6 . "六") (?7 . "七")
		      (?8 . "八") (?9 . "九") (?  . "")))))))

;; modified by Kazuo Hirokawa, 1991.11.18.
;; modified by Kiyotaka Sakai, 1994.1.10.

(defun j-convert-to-vector (map)
  "convert a map in list form to a map in vector form."
  (if (not (or (vectorp map) skk-emacs19))
      (let ((new-map (make-keymap)) (l (cdr map)) def)
	(while l
	  (setq def (cdr (car l)))
	  (aset new-map (car (car l)) (if (keymapp def)
                      (copy-keymap def)
		      def))
	  (setq l (cdr l)))
	new-map)
    ;; modified by Tsugutomo Enami, 1990.7.9
    (copy-keymap map)))

;; the following function was introduced at the suggestion of
;; Tsugutomo Enami, 1993.4.7.

(defun j-in-minibuffer ()
  "check if the minibuffer is currently selected."
  (eq (selected-window) (minibuffer-window)))

;; modified by Tsugutomo Enami, 1994.7.9.

(defun j-do-auto-fill ()
  (if skk-emacs19
      ;; this is enough emacs19 do-auto-fill.
      (and auto-fill-function (funcall auto-fill-function))
    (and auto-fill-hook
	 (let* ((c (current-column)) (cont (> c fill-column)))
	   (while cont
	     (run-hooks 'auto-fill-hook)
	     ;; if current-column doesn't change after do-auto-fill,
	     ;; we exit from the while loop by setting cont to be nil.
	     ;; also, it is necessary that current-column >
	     ;; fill-column to continue the loop.
	     (setq cont (and (< (current-column) c)
			     (> (current-column) fill-column)))
	     (setq c (current-column)))))))

(defun skk-auto-fill-mode (arg)
  (interactive "P")
  (let ((auto-fill
	 ;; modified by Tsugutomo Enami, 1994.7.9.
	 (cond ((null arg) (not (if skk-emacs19
				    auto-fill-function
				  auto-fill-hook)))
	       ((> (prefix-numeric-value arg) 0) t)
	       (t nil))))
    (auto-fill-mode (if auto-fill 1 -1))
    (or skk-mode (skk-mode 1))
    (run-hooks 'skk-auto-fill-mode-hook)))

;; kana inserting functions

(defun j-insert (table)
  (let ((char (assoc j-prefix table)) str)
    (if (null char)
	;; j-prefix not found in the table
	(setq j-prefix ""
	      unread-command-char last-command-event)
      (if (and j-kakutei-early j-henkan-active) (j-kakutei))
      (setq str (if j-katakana (cdr (cdr char)) (car (cdr char))))
      (j-insert-str str)
      (if j-okurigana
	  (j-set-okurigana)
	(setq j-prefix ""))
      ;; Modified at the suggestion of Kazuo Hirokawa, 1992.3.9.
      ;; modified by Tsugutomo Enami, 1994.7.9.
      (if (not j-henkan-on) (j-do-auto-fill)))))

;; the following function relies on the dynamic variable vip-ovwrt-limit
;; used in vip version 4.
;; this style of coding should be avoided if possible.

(defun j-ovwrt-len (len)
  (if (and skk-use-vip (boundp 'vip-ovwrt-limit))
      (min (- vip-ovwrt-limit (point))
	   (- (save-excursion (end-of-line) (point)) (point))
	   len)
    ;; modified by Kiyotaka Sakai, 1994.6.14.
    (min (string-width
	  (buffer-substring (point) (save-excursion (end-of-line) (point))))
	 len)))

(defun j-insert-str (str)
  "Insert STR and, if necessary, call self-insert-after-hook, and take care of
overwrite-mode"
  (insert str)
  (or j-henkan-on
      (progn
	(if self-insert-after-hook
	    (funcall self-insert-after-hook (- (point) (length str)) (point)))
	;; (boundp 'vip-ovwrt-limit) means that this function is within the
	;; dynamic scope of vip-overwrite-execute
	(if (or overwrite-mode (boundp 'vip-ovwrt-limit))
	    ;; modified by Kiyotaka Sakai, 1994.6.14.
	    (j-del-char-with-pad (j-ovwrt-len (string-width str)))))))

(defun j-del-char-with-pad (length)
  "Delete exactly LENGTH width, by inserting a space at the end,
if necessary, for adjustment."
  ;; modified by Kiyotaka Sakai, 1994.6.14.
  (let ((p (point)) (len 0))
    (while (< len length)
      (forward-char 1)
      (setq len (string-width (buffer-substring (point) p))))
    (delete-region p (point))
    (or (= length len)
	(progn
	  (insert " ")
	  (backward-char 1)))))

(defun j-set-okurigana ()
  (let (w-head)
    (skk-move-marker j-henkan-end-point j-okurigana-start-point)
    (save-excursion
      ;; just in case
      (goto-char j-okurigana-start-point)
      (or (looking-at "\\*") (insert "*")))
    (setq w-head (buffer-substring
		  j-henkan-start-point
		  j-henkan-end-point))
    (setq j-henkan-key2
	  (concat w-head
		  "*"
		  (setq j-henkan-okurigana
			(buffer-substring
			 (1+ j-okurigana-start-point)
			 (point)))))
    (setq j-henkan-key (concat w-head j-okuri-char))
    (setq j-prefix ""
	  j-okuri-char "")
    (delete-region
     j-okurigana-start-point (1+ j-okurigana-start-point))
    (j-henkan)
    (setq j-okurigana nil)))

(defun j-insert-a ()
  (interactive)
  (j-insert skk-roma-kana-a))

(defun j-insert-i ()
  (interactive)
  (j-insert skk-roma-kana-i))

(defun j-insert-u ()
  (interactive)
  (j-insert skk-roma-kana-u))

(defun j-insert-e ()
  (interactive)
  (j-insert skk-roma-kana-e))

(defun j-insert-o ()
  (j-insert skk-roma-kana-o))

(defun j-erase-prefix ()
  "erase j-prefix characters if SKK-ECHO is on."
  (if skk-echo
      (delete-region j-kana-start-point (point))))

(defun j-insert-prefix (&optional char)
  "insert j-prefix if SKK-ECHO is on"
  (if skk-echo (insert (or char j-prefix))))

;; other inserting functions

(defun j-insert-comma (count)
  (interactive "p")
  (if (eq last-command 'j-completion)
      (j-previous-completion)
    (j-self-insert count)))

(defun j-insert-period (count)
  (interactive "p")
  (if (eq last-command 'j-completion)
      (progn
	(setq this-command 'j-completion)
	(j-completion nil))
    (j-self-insert count)))

;; kana input by romaji to kana conversion
(defun safe-aref (array idx)
  (condition-case nil
      (aref array idx)
    (error nil)))

(defun j-kana-input ()
  "Start romaji-to-kana conversion.  The character `o' calls this function in
order to treat `ohta' etc."
  (interactive)
  (if (and j-kakutei-early j-henkan-active) (j-kakutei))
  (let ((char (char-to-string last-command-event))
	;; don't echo key strokes in the minibuffer
	(echo-keystrokes 0)
	(cont t))
    (if skk-isearch-message (j-isearch-message))
    ;; modified by Kiyotaka Sakai, 1993.8.19
    ;; modified by Chikanobu Toyofuku, 1993.8.23
    (if (and (= last-command-event ?o)
	     (null (j-assoc-rule (concat j-prefix char))))
	(progn
	  (j-insert-o)
	  (if skk-isearch-message
	      (progn
		(j-isearch-message)
		(setq cont nil)
		;; thus you must type `oota' instead of `ohta' when inputting
		;; isearch string
		)
	    (setq j-prefix char)
	    (skk-move-marker j-kana-start-point (point))))
      (setq j-prefix char)
      (skk-move-marker j-kana-start-point (point))
      (j-insert-prefix))
    (condition-case conditions
	(while cont
	  ;; modified by Kiyotaka Sakai, 1994.11.8.
	  (let* ((r-char (j-read-char))
		 (r-char (if (= r-char ?\C-g)
			     (signal 'quit nil)
			   (if (and j-henkan-on
				    (not j-henkan-active)
				    ;; we must distinguish the two cases where
				    ;; SKK-ECHO is on and off
;;	added by Takashi SAKAMOTO because ``YoRu'' doesn't work...
				    (= j-kana-start-point j-henkan-start-point)
;;
				    (= j-henkan-start-point
				       (if skk-echo (1- (point)) (point)))
				    (< 64 r-char) (< r-char 91))
			       ;; this case takes care of the rare case where
			       ;; one types two characters in upper case
			       ;; consequtively.  For example, one sometimes
			       ;; types "TE" when one should type "Te"
			       (+ 32 r-char)
;;			       (progn (princ j-prefix) (+ 32 r-char))
			     r-char)))
		 (input (char-to-string r-char))
		 (prefix (concat j-prefix input))
		 (next (j-assoc-rule prefix)))
	    (if skk-isearch-message (j-isearch-message))
	    (cond (next
		   (let ((newprefix (car next))
			 (output (car (cdr next))))
		     (j-erase-prefix)
		     (if output
			 (progn
			   (j-insert-str
			    (if j-katakana (car output) (cdr output)))
			   (if j-okurigana (j-set-okurigana))))
		     (if newprefix
			 (progn
			   (skk-move-marker j-kana-start-point (point))
			   ;; modified by Naoki HAMADA, 1993.7.4.
			   (j-insert-prefix newprefix)
			   (setq j-prefix newprefix))
		       (setq cont nil)
		       (setq j-prefix ""))))
		  ((string= j-prefix "n")
		   (cond ((eq (safe-aref skk-char-type-vector r-char) 3) ;; vowel
			  (j-erase-prefix)
			  (setq cont nil)
			  (setq unread-command-char r-char))
			 ((= r-char ?y)
			  (setq j-prefix prefix)
			  (j-insert-prefix ?y))
			 ((and j-okurigana (= r-char 32))
			  (setq unread-command-char ?n))
			 (t
			  (j-erase-prefix)
			  (j-insert-str (if j-katakana "ン" "ん"))
			  (skk-move-marker j-kana-start-point (point))
			  (setq j-prefix "")
			  (setq cont nil)
			  (setq unread-command-char r-char))))
		  ((string= j-prefix "o")
		   (if (= r-char ?h)
		       (progn
			 (setq j-prefix prefix)
			 (j-insert-prefix "h"))
		     ;; the following line was added
		     ;; by Chikanobu Toyofuku, 1993.8.23
		     (j-erase-prefix)
		     (setq cont nil
			   j-prefix ""
			   unread-command-char r-char)))
		  ((string= j-prefix "oh")
		   (if (eq (safe-aref skk-char-type-vector r-char) 3)
		       ;; vowel
		       (progn
			 (setq cont nil)
			 (j-erase-prefix)
			 (setq j-prefix "h")
			 (setq unread-command-char r-char))
		     (j-erase-prefix)
		     (j-insert-str (if j-katakana "オ" "お"))
		     (setq cont nil
			   j-prefix ""
			   unread-command-char r-char)))
		  ((and (string= input j-prefix)
			(eq (safe-aref skk-char-type-vector r-char) 1))
		   (j-erase-prefix)
		   (j-insert-str (if j-katakana "ッ" "っ"))
		   (skk-move-marker j-kana-start-point (point))
		   (j-insert-prefix r-char))
		  ((j-member prefix skk-prefix-list)
		   (setq j-prefix prefix)
		   (j-insert-prefix input))
		  ((eq (safe-aref skk-char-type-vector r-char) 3) ;; vowel
		   (setq cont nil)
		   (j-erase-prefix)
		   (setq unread-command-char r-char))
		  ((eq (safe-aref skk-char-type-vector r-char) 4)
		   ;; j-set-henkan-point
		   (let ((last-command-event r-char))
		     (j-erase-prefix)
		     (j-set-henkan-point)))
		  ((eq (safe-aref skk-char-type-vector r-char) 5) ;; delete prefix
		   (setq cont nil)
		   (if (and j-okurigana
			    (= (char-after (+ j-okurigana-start-point 0)) ?*))
		       (progn
			 (delete-region j-okurigana-start-point
					(1+ j-okurigana-start-point))
			 (skk-move-marker j-kana-start-point
				     (+ j-okurigana-start-point 0))
			 (setq j-okurigana nil)))
		   (or (string= j-prefix "")
		       (if skk-echo
			   (j-erase-prefix)
			 (message "Deleted prefix \"%s\"." j-prefix)))
		   (setq j-prefix ""))
		  (t
		   (setq cont nil)
		   (j-erase-prefix)
		   (skk-move-marker j-kana-start-point nil)
		   (setq j-prefix "")
		   (setq unread-command-char r-char)))))
      (quit
       (if (string= j-prefix "o")
	   ;; moified by Kazuo Hirokawa, 1992.7.10.
	   (j-keyboard-quit)
	 (setq j-prefix "")
	 (j-erase-prefix)
	 (skk-move-marker j-kana-start-point nil)
	 (ding))))))

;; convert skk-rom-kana-rule-list to skk-rom-kana-rule-tree.
;; The rule tree follows the following syntax:
;; <tree> ::= ((<char> . <tree>) . <tree>) | nil
;; <item> ::= (<char> . <tree>)

(defun j-compile-rule-list (l)
  "compile rom-kana-rule-list into a tree form."
  (let ((tree nil))
    (while l
      (setq rule (car l))
      (setq l (cdr l))
      (setq tree (j-add-rule rule tree)))
    tree))

(defun j-add-rule (rule tree)
  "destructivley add RULE to TREE."
  (let* ((str (car rule))
	 (char (string-to-char str))
	 (rest (substring str 1))
	 (rule-body (cdr rule))
	 (root tree))
    (j-add-rule-main char rest rule-body tree)
    root))

(defun j-add-rule-main (char rest body tree)
  (let ((item (j-search-tree char tree)) (cont t))
    (if item
	(if (string= rest "")
	    (setcdr item (cons (cons 0 body) (cdr item)))
	  (j-add-rule-main
	   (string-to-char rest) (substring rest 1) body (cdr item)))
      ;; key not found, so add rule to the end of the tree
      (if (null root)
	  (setq root (j-make-rule-tree char rest body))
	(while (and cont tree)
	  (if (null (cdr tree))
	      (progn
		(setcdr tree (j-make-rule-tree char rest body))
		(setq cont nil))
	    (setq tree (cdr tree))))))))

(defun j-make-rule-tree (char rest body)
  (if (string= rest "")
      (list (cons char (list (cons 0 body))))
    (list
     (cons char
	   (j-make-rule-tree
	    (string-to-char rest) (substring rest 1) body)))))

(defun j-search-tree (char tree)
  (let ((cont t) (v nil))
    (while (and cont tree)
      (if (= char (car (car tree)))
	  (setq v (car tree)
		cont nil)
	(setq tree (cdr tree))))
    v))

(defun j-assoc-rule (key)
  (if skk-rom-kana-rule-tree
      (j-assoc-tree key skk-rom-kana-rule-tree)
    (j-assoc key skk-rom-kana-rule-list)))

(defun j-assoc-tree (key tree)
  (let ((char (string-to-char key)) (rest (substring key 1))
	(cont t) (v nil))
    (while (and tree cont)
      (if (= char (car (car tree)))
	  (if (string= rest "")
	      (setq v (if (= 0 (car (car (cdr (car tree)))))
			  (cdr (car (cdr (car tree)))))
		    cont nil)
	    (setq v (j-assoc-tree rest (cdr (car tree)))
		  cont nil))
	(setq tree (cdr tree))))
    v))

;; mode setup

(defun skk-mode (&optional arg)
  "SKK mode enables input of Japanese texts without affecting the
functionality of the original mode. With negative ARG, exits from SKK mode."
  (interactive "P")
  (setq skk-mode
	(if j-mode-line-format
	    (cond ((null arg) (not skk-mode))
		  ((> (prefix-numeric-value arg) 0) t)
		  (t nil))
	  ;; if skk-mode has not been called in this buffer, always
	  ;; enter skk-mode
	  t))
  (if (and (j-in-minibuffer) (boundp 'vip-current-mode))
      (setq vip-read-string-hook
	    '(lambda ()
	       (define-key minibuffer-local-map skk-kakutei-key 'j-kakutei)
	       (define-key minibuffer-local-map "\C-m" 'j-newline))))
  (if (not skk-mode)
      ;; exit skk-mode
      (progn
	(if skk-use-vip (vip-change-mode-to-insert))
	;; Tsugutomo Enami added the following line, 1990.7.13
	(let ((skk-mode t)) (j-kakutei))
	;; the following line modified by Tsugutomo Enami, 1990.7.13
	(setq mode-line-format j-mode-line-format)
	(use-local-map j-current-local-map)
	(set-buffer-modified-p (buffer-modified-p)))
    ;; enter skk-mode
    (if (not j-skk-mode-invoked)
	;; enter skk-mode for the first time in this session
	(progn
	  (setq j-skk-mode-invoked t)
	  ;; modified by Tsugutomo Enami, 1990.8.26
	  ;; modified by Masahiko Suzuki, 1992.7.13
	  (load skk-init-file t)
	  (setq j-kakutei-early
		(and skk-kakutei-early (not skk-process-okuri-early)))
	  (if skk-keep-record
	      (j-create-file
	       skk-record-file
	       "I have created an SKK record file for you."))
	  (or (file-exists-p skkinput-jisyo)
	      (j-create-file
	       skkinput-jisyo
	       "I have created an empty Jisyo file for you."))
	  (j-get-file-buffer skkinput-jisyo t)
	  (setq j-jisyo-buffer-modified nil)
	  (if (file-exists-p skk-jisyo)
	      (j-get-file-buffer skk-jisyo t)
	    (setq skk-jisyo-jisyo nil))
	  ;; added by Kiyotaka Sakai, 1994.6.14.
	  (or (fboundp 'string-width)
	      (fset 'string-width (symbol-function 'length)))
	  (if skk-use-vip
	      (progn
		;; we should be able to use (require 'vip) eventually.
		(if (not (boundp 'vip-current-mode)) (load "vip"))
		;; check vip's version.  this modification will not be
		;; necessary for vip4.x.
		(if (string= (vip-version)
			     "VIP version 3.5 of September 15, 1987")
		    (progn
		      (message "")
		      (fset 'vip-change-mode 'vip-ch-mode)))))))
    (if (or (not j-mode-line-format) (j-in-minibuffer))
	;; enter skk-mode for the first time in this buffer or the buffer
	;; is the minibuffer
	(let (map)
	  (if (and skk-use-vip (not (j-in-minibuffer)))
	      (let ((skk-mode nil)) (vip-change-mode-to-insert)))
	  (setq map
		(if (j-in-minibuffer)
		    minibuffer-local-map
		  (current-local-map)))
	  ;; save current mode
	  ;; modified by Tsugutomo Enami, 1990.7.13.
	  (setq j-mode-line-format mode-line-format
		j-current-local-map (if map (copy-keymap map) nil))
	  ;; modified at the suggestion of Masakazu Takahashi, 1990.7.8
	  (setq j-emacs-local-map
		(if map (copy-keymap map) (make-sparse-keymap)))
	  (define-key j-emacs-local-map skk-kakutei-key 'j-kakutei)
	  (j-setup-skk-map)
	  (j-setup-skk-zenkaku-map)
	  (j-setup-skk-abbrev-map)
	  (run-hooks 'skk-mode-hook))
      (if (and skk-use-vip (not (j-in-minibuffer)))
	  (let ((skk-mode nil)) (vip-change-mode-to-insert))))
    (setq j-mode t
	  j-katakana nil)
    (use-local-map skk-map)
    (define-key minibuffer-local-map
      (default-value 'skk-kakutei-key) 'j-kakutei)
    (define-key minibuffer-local-map "\C-m" 'j-newline)
    (define-key minibuffer-local-completion-map
      (default-value 'skk-kakutei-key) 'j-kakutei)
    (define-key minibuffer-local-completion-map "\C-m" 'j-newline)
    (define-key minibuffer-local-ns-map
      (default-value 'skk-kakutei-key) 'j-kakutei)
    (define-key minibuffer-local-ns-map "\C-m" 'j-newline)
    (setq mode-line-format
	  (cons "" (cons 'j-mode-line-skk (cdr j-mode-line-format))))
    (j-change-mode-line skk-hirakana-mode-string)))

;; The following function is contributed by Tsugutomo Enami, 1992.5.6.
;; modified by Kiyotaka Sakai, 1993.7.9
;; modified by Kiyotaka Sakai, 1993.7.28

(defun skk-set-jisyo-code (code)
  (cond ((stringp code)
	 (if skk-mule
	     (set-file-coding-system
	      (cdr (assoc code '(("euc" . *euc-japan*) ("ujis" . *euc-japan*)
				 ("sjis". *sjis*) ("jis" . *junet*)))))
	   (setq kanji-fileio-code
		 (cdr (assoc code '(("euc"  . 0) ("ujis"  . 0)
				    ("sjis" . 1) ("jis"  . 2)))))))
	(code (if skk-mule
		  (set-file-coding-system code)
		(setq kanji-fileio-code code)))))

(defun j-setup-skk-map ()
  (setq skk-map (j-convert-to-vector j-emacs-local-map))
  (j-define-skk-map skk-map))

(defun j-setup-skk-minibuff-map ()
  (setq skk-minibuff-map (j-convert-to-vector minibuffer-local-map))
  (j-define-skk-map skk-minibuff-map t))

(defun j-define-skk-map (map &optional minibuff)
  "Setup skk key bindings for the keymap MAP.  If the optional argument
MINIBUFF is t, the map is used in the minibuffer."
  (define-key map "\C-g" 'j-keyboard-quit)
  (define-key map
    (if minibuff (default-value 'skk-kakutei-key) skk-kakutei-key)
    'j-kakutei)
  (define-key map "\C-h" 'j-delete-backward-char)
  (define-key map "\C-m" 'j-newline)
  (define-key map "\t" 'j-try-completion)
  (define-key map "\ " 'j-start-henkan)
  (define-key map "!" 'j-self-insert)
  (define-key map "\"" 'j-self-insert)
  (define-key map "#" 'j-self-insert)
  (define-key map "$" 'j-display-code-for-char-at-point)
  (define-key map "%" 'j-self-insert)
  (define-key map "&" 'j-self-insert)
  (define-key map "'" 'j-self-insert)
  (define-key map "\(" 'j-self-insert)
  (define-key map "\)" 'j-self-insert)
  (define-key map "*" 'j-self-insert)
  (define-key map "+" 'j-self-insert)
  (define-key map "," 'j-insert-comma)
  (define-key map "-" 'j-self-insert)
  (define-key map "." 'j-insert-period)
  (define-key map "/" 'j-abbrev-input)
  (define-key map "0" 'j-self-insert)
  (define-key map "1" 'j-self-insert)
  (define-key map "2" 'j-self-insert)
  (define-key map "3" 'j-self-insert)
  (define-key map "4" 'j-self-insert)
  (define-key map "5" 'j-self-insert)
  (define-key map "6" 'j-self-insert)
  (define-key map "7" 'j-self-insert)
  (define-key map "8" 'j-self-insert)
  (define-key map "9" 'j-self-insert)
  (define-key map ":" 'j-self-insert)
  (define-key map ";" 'j-self-insert)
  (define-key map "<" 'j-set-henkan-point)
  (define-key map "=" 'j-self-insert)
  (define-key map ">" 'j-set-henkan-point)
  (define-key map "?" 'j-set-henkan-point)
  (define-key map "@" 'j-today)
  (define-key map "A" 'j-set-henkan-point)
  (define-key map "B" 'j-set-henkan-point)
  (define-key map "C" 'j-set-henkan-point)
  (define-key map "D" 'j-set-henkan-point)
  (define-key map "E" 'j-set-henkan-point)
  (define-key map "F" 'j-set-henkan-point)
  (define-key map "G" 'j-set-henkan-point)
  (define-key map "H" 'j-set-henkan-point)
  (define-key map "I" 'j-set-henkan-point)
  (define-key map "J" 'j-set-henkan-point)
  (define-key map "K" 'j-set-henkan-point)
  (define-key map "L" 'j-zenkaku-eiji)
  (define-key map "M" 'j-set-henkan-point)
  (define-key map "N" 'j-set-henkan-point)
  (define-key map "O" 'j-set-henkan-point)
  (define-key map "P" 'j-set-henkan-point)
  (define-key map "Q" 'j-set-henkan-point-subr)
  (define-key map "R" 'j-set-henkan-point)
  (define-key map "S" 'j-set-henkan-point)
  (define-key map "T" 'j-set-henkan-point)
  (define-key map "U" 'j-set-henkan-point)
  (define-key map "V" 'j-set-henkan-point)
  (define-key map "W" 'j-set-henkan-point)
  (define-key map "X" 'j-purge-from-jisyo)
  (define-key map "Y" 'j-set-henkan-point)
  (define-key map "Z" 'j-set-henkan-point)
  (define-key map "\[" 'j-self-insert) 
  (define-key map "\\" 'j-input-by-code-or-menu)
  (define-key map "\]" 'j-self-insert)
  (define-key map "^" 'j-self-insert)
  (define-key map "_" 'j-self-insert)
  (define-key map "`" 'j-self-insert)
  (define-key map "a" 'j-insert-a)
  (define-key map "b" 'j-kana-input)
  (define-key map "c" 'j-kana-input)
  (define-key map "d" 'j-kana-input)
  (define-key map "e" 'j-insert-e)
  (define-key map "f" 'j-kana-input)
  (define-key map "g" 'j-kana-input)
  (define-key map "h" 'j-kana-input)
  (define-key map "i" 'j-insert-i)
  (define-key map "j" 'j-kana-input)
  (define-key map "k" 'j-kana-input)
  (define-key map "l" (if minibuff 'j-mode-off-in-minibuff 'j-mode-off))
  (define-key map "m" 'j-kana-input)
  (define-key map "n" 'j-kana-input)
  (define-key map "o" 'j-kana-input)
  (define-key map "p" 'j-kana-input)
  (define-key map "q" 'j-toggle-kana)
  (define-key map "r" 'j-kana-input)
  (define-key map "s" 'j-kana-input)
  (define-key map "t" 'j-kana-input)
  (define-key map "u" 'j-insert-u)
  (define-key map "v" 'j-kana-input)
  (define-key map "w" 'j-kana-input)
  (define-key map "x" 'j-previous-candidate)
  (define-key map "y" 'j-kana-input)
  (define-key map "z" 'j-kana-input)
  (define-key map "\{" 'j-self-insert)
  (define-key map "|" 'j-self-insert)
  (define-key map "\}" 'j-self-insert)
  (define-key map "~" 'j-self-insert)
  (define-key map "\177" 'j-delete-backward-char)
  ;;(define-key map "\M-k" 'j-katakana-henkan)
  ;;(define-key map "\M-h" 'j-hiragana-henkan)
  ;;(define-key map "\M-z" 'j-zenkaku-henkan)
  )

;; modified by Masahiko Sato, 1991.4.6
;; modified by Masakazu Takahashi, 1990.5.11

(defun j-setup-skk-zenkaku-map ()
  (setq skk-zenkaku-map (j-convert-to-vector j-emacs-local-map))
  (let ((i 0))
    (while (< i 128)
      (if (aref skk-zenkaku-vector i)
	  (define-key skk-zenkaku-map (char-to-string i) 'j-zenkaku-insert) )
      (setq i (1+ i)))))

(defun j-setup-skk-abbrev-map ()
  (setq skk-abbrev-map (j-convert-to-vector j-emacs-local-map))
  (define-key skk-abbrev-map "\C-g" 'j-keyboard-quit)
  (define-key skk-abbrev-map skk-kakutei-key 'j-kakutei)
  (define-key skk-abbrev-map "\t" 'j-try-completion)
  (define-key skk-abbrev-map "\C-h" 'j-delete-backward-char)
  (define-key skk-abbrev-map "\C-m" 'j-newline)
  (define-key skk-abbrev-map "\C-q" 'j-zenkaku-henkan)
  (define-key skk-abbrev-map "." 'j-abbrev-period)
  (define-key skk-abbrev-map "," 'j-abbrev-comma)
  (define-key skk-abbrev-map "\ " 'j-start-henkan)
  (define-key skk-abbrev-map "\177" 'j-delete-backward-char)
  ;;(define-key skk-abbrev-map "\M-z" 'j-zenkaku-henkan)
  )

;; modified by Kazuo Hirokawa, 1991.11.18.

(defun j-self-insert (arg)
  (interactive "P")
  (let ((str (aref skk-input-vector last-command-event)))
    (if str
	(let ((count (prefix-numeric-value arg)))
	  (while (> count 0)
	    (j-insert-str str)
	    (setq count (1- count))))
      (j-emulate-original-map arg))
    (if j-henkan-active (j-kakutei))))

(defun j-zenkaku-insert (count)
  (interactive "p")
  (let* ((str (aref skk-zenkaku-vector last-command-event))
	 (len (length str)))
    (while (> count 0)
      (j-insert-str str)
      (setq count (1- count)))))

(defun j-zenkaku-self-insert (count)
  (interactive "p")
  (while (> count 0)
    ;; modified by Kazuo Hirokawa, 1993.7.7
    (j-insert-str (j-char-to-string 163 (+ last-command-event 128)))
    (setq count (1- count))))

(defun j-mode-off ()
  "return to old ascii mode."
  (interactive)
  (j-kakutei)
  (setq j-mode nil
	j-prefix ""
	j-zenkaku nil)
  (use-local-map j-emacs-local-map)
  (j-change-mode-line skk-mode-string))

(defun j-mode-off-in-minibuff ()
  "return to old ascii mode in the minibuffer."
  (interactive)
  (j-kakutei)
  (setq j-mode nil
	j-prefix ""
	j-zenkaku nil)
  (use-local-map minibuffer-local-map))

(defun j-zenkaku-eiji ()
  "zenkaku-eiji input"
  (interactive)
  (j-kakutei)
  (setq j-mode nil
	j-prefix ""
	j-zenkaku t)
  (use-local-map skk-zenkaku-map)
  (j-change-mode-line skk-zenei-mode-string))

(defun j-abbrev-input ()
  (interactive)
  (if (and j-henkan-on (not j-henkan-active)) (error ""))
  (j-kakutei)
  (j-set-henkan-point-subr)
  (use-local-map skk-abbrev-map)
  (setq j-abbrev t))

;; vip related functions

(defun vip-ch-mode (new-mode)
  "(NEW-MODE)  Change mode to NEW-MODE.  NEW-MODE is either emacs-mode,
vi-mode, or insert-mode."
  (if (j-in-minibuffer)
      (error "Can't change mode in minibuffer!")
    (or (eq new-mode vip-current-mode)
	(progn
	  (cond ((eq new-mode 'vi-mode)
		 (if (eq vip-current-mode 'insert-mode)
		     (progn
		       (if (and skk-mode j-mode) (j-kakutei))
		       (vip-copy-region-as-kill (point) vip-insert-point)
		       (vip-repeat-insert-command))
		   (setq vip-emacs-local-map (current-local-map)
			 vip-emacs-mode-line-buffer-identification
			 mode-line-buffer-identification
			 vip-insert-local-map (vip-copy-keymap
					       (current-local-map))))
		 (vip-change-mode-line "Vi:   ")
		 (if skk-mode (j-change-mode-line skk-mode-string))
		 (use-local-map vip-mode-map))
		((eq new-mode 'insert-mode)
		 (skk-move-marker vip-insert-point (point))
		 (if (eq vip-current-mode 'emacs-mode)
		     (setq vip-emacs-local-map (current-local-map)
			   vip-emacs-mode-line-buffer-identification
			   mode-line-buffer-identification
			   vip-insert-local-map (vip-copy-keymap
						 (current-local-map))))
		 (vip-change-mode-line "Insert")
		 (if skk-mode
		     (j-change-mode-line
		      (if j-mode (if j-katakana skk-katakana-mode-string
				   skk-hirakana-mode-string)
			(if j-zenkaku skk-zenei-mode-string skk-mode-string))))
		 (if skk-mode
		     (if j-mode
			 (use-local-map skk-map)
		       (if j-zenkaku
			   (use-local-map skk-zenkaku-map)
			 (use-local-map vip-insert-local-map)
			 (local-set-key skk-kakutei-key 'j-kakutei)))
		   (use-local-map vip-insert-local-map))
		 (local-set-key "\e" 'vip-change-mode-to-vi)
		 (local-set-key "\C-z" 'vip-ESC)
		 (local-set-key "\C-h"
				(if vip-help-in-insert-mode 'help-command
				  'j-delete-backward-char))
		 (local-set-key "\C-w"
				'vip-delete-backward-word))
		((eq new-mode 'emacs-mode) 
		 (vip-change-mode-line "Emacs:")
		 (if skk-mode (j-change-mode-line skk-mode-string))
		 (use-local-map vip-emacs-local-map)))
	  (setq vip-current-mode new-mode)
	  (vip-refresh-mode-line)))))

;(if (not (fboundp 'j-save-buffers-kill-emacs))
;    (fset 'j-save-buffers-kill-emacs
;	  (symbol-function 'save-buffers-kill-emacs)))

(defun save-buffers-kill-emacs (&optional query)
  "Save SKK jisyo buffer, offer to save each buffer, then kill this Emacs fork.
With prefix arg, silently save all file-visiting buffers, then kill."
  (interactive "P")
  (skk-save-jisyo)
  ;; modified at the suggestion of Masahiko Suzuki to check the value of
  ;; SKK-SERVER-HOST, 1992.7.13.
  ;; modified by Mikio Nakajima, 1995.4.15 
  (or (eq system-type 'ms-dos)
      (if (and skk-server-host (process-status "skkservd"))
	  (process-send-string "skkservd" "0")) ;; disconnect server
      ;; modified at the suggestion of Tsugutomo Enami, 1995.2.3
      (accept-process-output (get-process "skkservd")) )
  (j-save-buffers-kill-emacs query))

(defun skk-kill-emacs-without-saving-jisyo (&optional query)
  "Kill Emacs without saving jisyo."
  (interactive "P")
  (if (yes-or-no-p "Do you really wish to kill emacs without saving Jisyo? ")
      (progn
	(let ((buff (get-file-buffer skkinput-jisyo)))
	  (if buff (kill-buffer buff)))
	;; modified at the suggestion of Masahiko Suzuki to check the value of
	;; skk-server-host, 1992.7.13.
        ;; modified by Mikio Nakajima, 1995.4.9
        (or (eq system-type 'ms-dos)
	    (if (and skk-server-host (process-status "skkservd"))
		(process-send-string "skkservd" "0")) ;; disconnect server
	    ;; modified at the suggestion of Tsugutomo Enami, 1995.2.3
            (accept-process-output (get-process "skkservd")) )
	(j-save-buffers-kill-emacs query))))

(defun skk-save-jisyo ()
  "Save jisyo buffer into jisyo file."
  (interactive)
  (if (not j-jisyo-buffer-modified)
      (message "No need to save Jisyo.")
    ;; check if the header lines for the two jisyo buffers are ok.
    ;; error corrected by Masakazu Takahashi, 1992.1.26.
    (save-excursion
      (set-buffer (get-file-buffer skkinput-jisyo))
      ;; modified by Tsugutomo Enami, 1992.5.6
      ;; set kanji-fileio-code appropriately
;     (skk-set-jisyo-code skkinput-jisyo-code)
      (goto-char (point-min))
      (or (string=
	   (buffer-substring
	    (point)
	    (progn (end-of-line) (point)))
	   ";; okuri-ari entries.")
	  (search-forward "\n;; okuri-ari entries." nil t)
	  (error "Header line for okuri-ari entries is missing!"))
      (or (search-forward "\n;; okuri-nasi entries." nil t)
	  (error "Header line for okuri-nasi entries is missing!")))
    (message "Saving Jisyo...")
    (get-buffer-create " *record*")
    (let* ((inhibit-quit t)
	   lines
	   (skkinput-jisyo (expand-file-name skkinput-jisyo))
	   (skk-record-file (expand-file-name skk-record-file))
	   (file-modes (file-modes skkinput-jisyo)))
;      (save-window-excursion
      (save-excursion
	;; Originally, call-process was used to execute the Unix mv command.
	;; Masakazu Takahashi modified it as follows on 1991.10.1.
	(if skkinput-backup-jisyo (rename-file skkinput-jisyo (expand-file-name skkinput-backup-jisyo) t))
	;; modified at the suggestion of Kiyotaka Sakai, 1992.9.16
	(delete-file skkinput-jisyo)
	(j-create-file skkinput-jisyo)
	(set-file-modes skkinput-jisyo file-modes)
	(set-buffer (get-file-buffer skkinput-jisyo))
	(setq lines (count-lines (point-min) (point-max)))
	(mutual-eval skk-jisyo-mutex '(j-save-jisyo))
	(message "Saving Jisyo...done.")
	(if (and skk-keep-record (> j-count-kakutei 0))
	    (progn
	      (set-buffer " *record*")
	      (erase-buffer)
	      ;; modified by Yosiaki Iida, 1994.8.23.
	      (insert-file-contents skk-record-file)
	      (goto-char (point-min))
	      (insert
	       (format "%s  登録: %3d  確定: %4d  確定率: %3d%%  語数: %6d\n"
		       (current-time-string)
		       j-count-touroku
		       j-count-kakutei
		       (/ (* 100 (- j-count-kakutei j-count-touroku))
			  j-count-kakutei)
		       lines))
	      (write-region (point-min) (point-max) skk-record-file nil 'nomsg)
	      (set-buffer-modified-p nil)
	      ))
	;; modified by Masakazu Takahashi, 1991.3.27
	(setq j-count-touroku 0
	      j-count-kakutei 0)
	;; reset j-jisyo-buffer-modified
	(setq j-jisyo-buffer-modified nil)))))

(defun j-save-jisyo ()
  (let ((go-on t))
    (goto-char (point-min))
    (while go-on
      (set-mark (point))
      (goto-char (+ 50000 (point)))
      (end-of-line)
      (write-region (mark) (point) skkinput-jisyo t 'nomsg)
      (if (eobp) (setq go-on nil)))))

;; input functions

;; modified by Wataru Matsui, 1991.8.19
;; modified by Masahiko Sato, 1990.3.19
;; modified by Masakazu Takahashi, 1989.8.10

(defun j-newline (arg)
  (interactive "p")
  (let ((no-nl (and skk-egg-like-newline j-henkan-on)))
    (if (j-in-minibuffer)
	(progn
	  (j-kakutei)
	  (if no-nl
	      nil
	    (setq j-mode nil)
	    (exit-minibuffer)))
      (if (j-kakutei) (setq arg (1- arg)))
      (if no-nl
	  nil
	(j-emulate-original-map arg)))))

;; modified by Masakazu Takahashi, 1991.11.17
;; modified by Kazuo Hirokawa, 1991.11.18.

(defun j-delete-backward-char (count)
  (interactive "P")
  (if j-okurigana
      (progn
	(setq j-okurigana nil)
	(if (and (char-after (+ j-okurigana-start-point 0))
		 (= (char-after (+ j-okurigana-start-point 0)) ?*))
	    (delete-region j-okurigana-start-point
			   (1+ j-okurigana-start-point)))))
  (if (and j-henkan-on (= (point) j-henkan-start-point))
      (progn
	(setq j-henkan-count 0)
	(j-kakutei))
    ;; modified by Tsugutomo Enami, 1991.10.2
    (if j-henkan-active 
	;; modified by Shuji Ashizawa, 1993.8.17
	(let ((p (+ j-henkan-end-point 0)))
	  (if (and (not skk-delete-implies-kakutei) (= p (point)))
	      (j-previous-candidate)
           (delete-backward-char (prefix-numeric-value count) count)
           (if (< (point) p) (j-kakutei))))
      (if (j-in-minibuffer)
	  (delete-backward-char (prefix-numeric-value count))
	;; we should not emulate original map if skk-use-vip is t and
	;; vip-current-mode's value is insert-mode
	(if (and skk-use-vip (eq vip-current-mode 'insert-mode))
	    (delete-backward-char (prefix-numeric-value count))
	  (j-emulate-original-map count))))))

;; input by EUC/JIS code or by menu

;; The function j-input-by-code, which was used until version 4.20,
;; is now replaced by the following new function.  The code for this
;; function was contributed by nakamura@pluto.ai.kyutech.ac.jp

;; modified by Masahiko Sato, 1991.4.4
;; modified by Jun-ichi Nakamura, 1991.3.29

(defun j-input-by-code-or-menu ()
  "This function lets the user input a JIS character either by its code or
by following the menu provided by the system."
  (interactive)
  (if (interactive-p)
      (progn 
	(insert (j-input-by-code-or-menu))
	(message ""))	; I'm wondering why I need this line...

;      (insert (j-input-by-code-or-menu))	; original code

    (let* ((str (read-string "JIS or EUC code (00nn or CR for Jump Menu): "))
	   (n1 (if (string= str "") 128
		 (+ (* 16 (j-jis-string-to-hex (substring str 0 1)))
		    (j-string-to-hex (substring str 1 2)))))
	   (n2 (if (string= str "") 128
		 (+ (* 16 (j-jis-string-to-hex (substring str 2 3)))
		    (j-string-to-hex (substring str 3 4)))))
	   ;; added by Takeshi Ohtani, 1994.6.14.
	   (enable-recursive-mini-buffer t))
      (if (> n1 160) (j-char-to-string n1 n2)
	(j-input-by-code-or-menu-0 n1 n2)))))

(defun j-string-to-hex (str)
  (let ((num (string-to-char str)))
  (cond ((> num 96) (- num 87)) ;; a-f
	((> num 64) (- num 55)) ;; A-F
	((> num 47) (- num 48)) ;; 0-9
	(t (error "")))))

(defun j-jis-string-to-hex (str)
  (let ((num (string-to-char str)))
  (cond ((> num 96) (- num 87)) ;; a-f
	((> num 64) (- num 55)) ;; A-F
	((> num 47) (- num 40)) ;; 0-9
	(t (error "")))))

(defun j-char-to-string (n1 n2)
  (if skk-mule
      (char-to-string (make-character lc-jp n1 n2))
    (concat (char-to-string n1) (char-to-string n2))))

(defun j-next-n2-code (n)
  (if (<= (setq n (1+ n)) j-code-n2-max) n j-code-n2-min))

(defun j-previous-n2-code (n)
  (if (<= j-code-n2-min (setq n (1- n))) n j-code-n2-max))

(defun j-next-n1-code (n)
  (if (<= (setq n (1+ n)) j-code-n1-max) n j-code-n1-min))

(defun j-previous-n1-code (n)
  (if (<= j-code-n1-min (setq n (1- n))) n j-code-n1-max))

(defun j-input-by-code-or-menu-0 (n1 n2)
  (if (= n1 j-code-null)
      (j-input-by-code-or-menu-jump n2)
    (j-input-by-code-or-menu-1 n1 n2)))

(defun j-input-by-code-or-menu-jump (n)
  (let ((kanji-char nil))
    (if (< n j-code-n1-min) (setq n j-input-by-code-or-menu-jump-default))
    (while (not kanji-char)
      (let* ((n-org n)
	     (chars
	      (list
	       (list (j-char-to-string n j-code-n1-min) n j-code-n1-min)
	       (list (j-char-to-string n 177) n 177)
	       (list (j-char-to-string n 193) n 193)
	       (list (j-char-to-string n 209) n 209)
	       (list (j-char-to-string n 225) n 225)
	       (list (j-char-to-string n 241) n 241)
	       (progn
		 (setq n (j-next-n1-code n))
		 (list (j-char-to-string n j-code-n1-min) n j-code-n1-min))
	       (list (j-char-to-string n 177) n 177)
	       (list (j-char-to-string n 193) n 193)
	       (list (j-char-to-string n 209) n 209)
	       (list (j-char-to-string n 225) n 225)
	       (list (j-char-to-string n 241) n 241))))
	(save-excursion
	  (let ((i 0) (str ""))
	    (while (< i 12)
	      (setq str
		    (concat
		     str
		     (char-to-string (upcase
				      (nth i j-input-by-code-menu-keys1)))
		     (car (nth i chars))
		     "  "))
	      (setq i (1+ i)))
	    (message str))

	  ;; modified by Kiyotaka Sakai, 1994.11.8.
	  (let* ((char (j-read-char))
		 ;; modified by Kiyotaka Sakai, 1994.7.5.
		 (rest (memq char j-input-by-code-menu-keys1))
		 (ch (if rest
			 (nth
			  (- (length j-input-by-code-menu-keys1) (length rest))
			  chars)
		       nil)))
	    (setq kanji-char
		  (cond
		   (ch ch)
		   ((= char ?x)
		    (if (< (setq n (- n-org 2)) j-code-n1-min)
			(setq n j-code-n1-max))
		    nil)
		   ((= char 32)  ;;; space
		      (setq n (j-next-n1-code n))
		      nil)
		   ((= char 63)  ;;; ?
		    (message
		     "『%s』  EUC: %2x%2x (%3d, %3d), JIS: %2x%2x (%3d, %3d)  [Hit any key to continue.]"
		     (car (car chars))
		     n-org j-code-n1-min n-org j-code-n1-min
		     (- n-org 128) (- j-code-n1-min 128)
		     (- n-org 128) (- j-code-n1-min 128))
		    ;; modified by Kiyotaka Sakai, 1994.11.8.
		    (j-read-char)
		    (setq n n-org)
		    nil)
		   ((= char ?\C-g) (signal 'quit nil))
		   (t
		    (message
		     (format "`%c' is not valid here!" char))
		    (sit-for 1)
		    (setq n n-org)
		    nil)))))))
    (setq j-input-by-code-or-menu-jump-default (car (cdr kanji-char)))
    (j-input-by-code-or-menu-1
     (car (cdr kanji-char)) (car (cdr (cdr kanji-char))))))

(defun j-input-by-code-or-menu-1 (n1 n2)
  (let ((kanji-char nil))
    (while (not kanji-char)
      (let* ((n1-org n1) (n2-org n2) (i 0)
	     (chars (list (j-char-to-string n1 n2))))
	(while (< i 16)
	  ;; modified by Kiyotaka Sakai, 19947.5.
	  (nconc chars (list
			(progn (setq n2 (j-next-n2-code n2))
			       (if (= n2 j-code-n2-min)
				   (setq n1 (j-next-n1-code n1)))
			       (j-char-to-string n1 n2))))
	  (setq i (1+ i)))
	(save-excursion
	  (let ((i 0) (str ""))
	    (while (< i 16)
	      (setq str
		    (concat
		     str
		     (char-to-string (upcase
				      (nth i j-input-by-code-menu-keys2)))
		     (nth i chars)
		     " "))
	      (setq i (1+ i)))
	    (message str))
	  ;; modified by Kiyotaka Sakai, 1994.11.8.
	  (let* ((char (j-read-char))
		 ;; modified by Kiyotaka Sakai, 1994.7.5.
		 (rest (memq char j-input-by-code-menu-keys2))
		 (ch (if rest
			 (nth
			  (- (length j-input-by-code-menu-keys2) (length rest))
			  chars)
		       nil)))
	    (setq kanji-char
		  (cond
		   (ch ch)
		   ((= char ?x)
		    (if (< (setq n2 (- n2 31)) j-code-n2-min)
			(progn (setq n2 (+ n2 94)
				     n1 (j-previous-n1-code n1))))
		    nil)
		   ((= char 32)  ;;; space
		    (if (= (setq n2 (j-next-n2-code n2))
			   j-code-n2-min)
			(setq n1 (j-next-n1-code n1)))
		    nil)
		   ((= char 63)  ;;; ?
		    (message
		      "『%s』  EUC: %2x%2x (%3d, %3d), JIS: %2x%2x (%3d, %3d)  [Hit any key to continue.]"
		      (car chars) n1-org n2-org n1-org n2-org
		      (- n1-org 128) (- n2-org 128)
		      (- n1-org 128) (- n2-org 128))
		    ;; modified by Kiyotaka Sakai, 1994.11.8.
		    (j-read-char)
		    (setq n1 n1-org n2 n2-org)
		    nil)
		   ((= char 62)  ;;; >
		    (if (= (setq n2 (j-next-n2-code n2-org))
			   j-code-n2-min)
			(setq n1 (j-next-n1-code n1-org))
		      (setq n1 n1-org))
		    nil)
		   ((= char 60) ;;; < 
		    (if (= (setq n2 (j-previous-n2-code n2-org))
			   j-code-n2-max)
			(setq n1 (j-previous-n1-code n1-org))
		      (setq n1 n1-org))
		    nil)
		   ((= char ?\C-g) (signal 'quit nil))
		   (t
		    (message "`%c' is not valid here!" char)
		    (sit-for 1)
		    (setq n1 n1-org n2 n2-org)
		    nil)))))))
    kanji-char))

(defun j-display-code-for-char-at-point ()
  "Displays the code for the charater at the current point."
  (interactive)
  (if (eobp) (error "Cursor is at the end of the buffer."))
  (let* ((str
	  ;; modified by Kazuo Hirokawa, 1992.2.26.
	  (buffer-substring
	   (point)
	   (save-excursion (forward-char 1) (point))))
	 (char-list (mapcar '+ str)))
    (let* ((char1   (car char-list))
	   (charset (char-charset char1))
	   char1-s char1-e char2-e char1-j char2-j)
      (cond ((or (eq charset 'ascii)
		 (eq charset 'japanese-jisx0201-1976))
	     (setq char1 (mod char1 256))
	     (message "`%c'  %2x (%3d)" char1 char1 char1))
	    ((or (eq charset 'japanese-jisx0208-1978)
		 (eq charset 'japanese-jisx0208-1983)
		 (eq charset 'japanese-jisx0212-1990))
	     (setq char1-s (mod char1 65536))
	     (setq char1-j (/   char1-s 256))
	     (setq char2-j (mod char1-s 256))
	     (setq char1-e (+ char1-j 128))
	     (setq char2-e (+ char2-j 128))
	     (message "『%c』  EUC: %2x%2x (%3d, %3d), JIS: %2x%2x (%3d, %3d)"
		      char1 char1-e char2-e char1-e char2-e char1-j char2-j char1-j char2-j))
	    (t 
	     (error "I don't understand this character."))))))

;; henkan routines

(defun j-toggle-kana (arg)
  (interactive "P")
  (if (and j-henkan-on (not j-henkan-active))
      (j-katakana-henkan arg)
    (j-kakutei)
    (setq j-katakana (not j-katakana))
    (j-change-mode-line (if j-katakana skk-katakana-mode-string
			  skk-hirakana-mode-string))))

;; Hisao Kuroda suggested to make the argument of the following function
;; to be an optional argument, 1993.6.1.

(defun j-set-henkan-point (&optional arg)
  (interactive "P")
  (let* ((normal (and (<= ?A last-command-event) (<= last-command-event ?Z)))
	 (last-char (if normal (+ 32 last-command-event) last-command-event))
	 (sokuon (and (string= j-prefix (char-to-string last-char))
		      (/= last-char ?o)))
	 (henkan-active j-henkan-active))
    (if (or (not j-henkan-on) j-henkan-active)
	(if normal
	    (j-set-henkan-point-subr)
	  (if j-henkan-on
	      (j-set-henkan-point-subr))
	  ;; modified by Kazuo Hirokawa, 1993.6.3.
	  (if henkan-active
	      (j-emulate-original-map arg)
	    (j-self-insert arg)))
      (if normal
	  ;; prepare for the processing of okurigana if not j-okurigana and
	  ;; the preceding character is not a numeric character.
	  ;; if the previous char is a special midashi char or a
	  ;; numeric character, we assume that the user intended to type the
	  ;; last-command-char in lower case.
	  (if (and (not j-okurigana)
		   (not
		    (and (not (= j-henkan-start-point (point)))
			 (let ((p1 (char-after (1- (point)))))
			   (or
			    ;; previous char is a special midashi char
			    (memq p1 j-special-midashi-char-list)
			    ;; previous char is an ascii numeric char
			    (and (<= ?0 p1) (<= p1 ?9))
			    ;; previous char is a jis numeric char
			    (and (<= ?０ p1) (<= p1 ?９)))))))
	      (if skk-process-okuri-early
		  (progn
		    (skk-move-marker j-henkan-end-point (point))
		    (setq j-henkan-key
			  (concat (buffer-substring j-henkan-start-point
						    (if sokuon
							j-kana-start-point
						      (point)))
				  (if sokuon
				      (if j-katakana "ッ" "っ")
				    "")
				  (char-to-string last-char)))
		    (if sokuon (j-erase-prefix))
		    (insert (if sokuon
				(if j-katakana "ッ" "っ")
			      "")
			    " ")
		    (setq j-prefix "")
		    (j-henkan)
		    (delete-backward-char (if sokuon 2 1))
		    ;; we set j-kana-start-point here, since the marker may
		    ;; no longer point at the correct position after j-henkan.
		    (skk-move-marker j-kana-start-point (point)))
		;; modified by Wataru Matsui, 1991.8.16
		(if (= j-henkan-start-point (point))
		    nil
		  (if sokuon
		      (progn
			(j-erase-prefix)
			(insert (if j-katakana "ッ" "っ"))
			(setq j-prefix "")))
		  (skk-move-marker j-okurigana-start-point (point))
		  (insert "*")
		  (skk-move-marker j-kana-start-point (point))
		  (setq j-okuri-char (char-to-string last-char))
		  (setq j-okurigana t))))
	;; process special char
	(insert last-char)
	(skk-move-marker j-henkan-end-point (point))
	(setq j-henkan-key (buffer-substring j-henkan-start-point (point)))
	(setq j-search-key j-henkan-key)
	(setq j-prefix "")
	;;(insert " ")
	(j-henkan)
	;;(delete-backward-char 1)
	))
    (if normal (setq unread-command-char last-char))))

;; The following two functions, j-katakana-region and j-katakana-henkan,
;; were contributed by Wataru Matsui on 1991.8.27.

;; j-katakana-region: modified by Wataru Matsui, 199l.11.19.
;;                    modified by Wataru Matsui, 1992. 1.21.
;;                    modified by Tsugutomo Enami, 1992.9.18.
;;    Arguments can be markers as well as numbers.
;;    Cf. katakana-region in wnn-egg.el, arguments to which 
;;    should not be markers.
;;    If vcontract is non-nil, "う゛" is converted to "ヴ".
;;    The idea for this function comes from katakana-region in wnn-egg.el.

(defun j-katakana-region (start end &optional vcontract)
  "Convert hiragana\'s in the region between START and END to katakana\'s.
Arguments start and end can be markers as well as numbers.
If vcontract is non-nil, \"う゛\" is converted to \"ヴ\"."
  (interactive "r\nP")
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (let (ch2 (diff (if skk-mule (- ?ア ?あ))))
	(while (re-search-forward  "[ぁ-ん]" nil t)
	  (if skk-mule
	      (progn
		(setq ch2 (+ (preceding-char) diff))
		(forward-char -1)
		(insert ch2)
		(delete-char 1))
	    (setq ch2 (preceding-char))
	    (forward-char -2)
	    (insert ?\245 ch2)
	    (delete-char 2))))
      (if vcontract
	  (progn
	    (goto-char (point-min))
	    (while (re-search-forward  "ウ゛" nil t)
	      (if skk-mule
		  (progn
		    (forward-char -2)
		    (insert "ヴ")
		    (delete-char 2))
		(forward-char -4)
		(insert "ヴ")
		(delete-char 4))))))))

;; j-hiragana-region: contributed by Wataru Matsui, 1991.11.19.
;;                       modified by Wataru Matsui, 1992. 1.21.
;;                       modified by Tsugutomo Enami, 1992.9.18.
;;    Arguments can be markers as well as numbers.
;;    Cf. hiragana-region in wnn-egg.el, arguments to which 
;;    should not be markers.
;;    "ヵ" and "ヶ" are not regarded as katakana's, since
;;    they don't have corresponding hiragana's.  If optional
;;    argument vexpand is non-nil, "ヴ" is converted to "う゛".
;;    The idea for this function comes from hiragana-region in wnn-egg.el.

(defun j-hiragana-region (start end &optional vexpand)
  "Convert katakana\'s in the region between START and END to hiragana\'s.
Arguments start and end can be markers as well as numbers.
If vexpand is non-nil, \"ヴ\" is converted to \"う゛\".
\"ヵ\" and \"ヶ\" are left unchanged."
  (interactive "r\nP")
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (let (ch2 (diff (if skk-mule (- ?ア ?あ))))
	(while (re-search-forward  "[ァ-ン]" nil t)
	  (if skk-mule
	      (progn
		(setq ch2 (- (preceding-char) diff))
		(forward-char -1)
		(insert ch2)
		(delete-char 1))
	    (setq ch2 (preceding-char))
	    (forward-char -2)
	    (insert ?\244 ch2)
	    (delete-char 2))))
      (if vexpand
	  (progn
	    (goto-char (point-min))
	    (while (re-search-forward  "ヴ" nil t)
	      (if skk-mule
		  (progn
		    (forward-char -1)
		    (insert "う゛")
		    (delete-char 1))
		(forward-char -2)
		(insert "う゛")
		(delete-char 2))))))))

(defun j-zenkaku-region (start end)
  "Convert ascii characters in the region between START and END to the
corresponding zenkaku characters."
  (interactive "r")
  (let ((diff (if skk-mule (- ?Ａ ?A))))
    (save-excursion
      (save-restriction
	(narrow-to-region start end)
	(goto-char (point-min))
	(while (re-search-forward "[ -~]" nil t)
	  (let ((ch (preceding-char)))
	    (if (and (<= ?  ch) (<= ch ?~))
		(progn
		  (forward-char -1)
		  (let ((zen (cdr (assq ch j-zenkaku-alist))))
		    (if zen (insert zen)
		      (if skk-mule
			  (insert (+ ch diff))
			(insert ?\243 (+ ?\200 ch)))))
		  (delete-char 1)))))))))

;; modified by Kazuo Hirokawa, 1991.11.21.

(defun j-katakana-henkan (arg)
  "Convert hiragana\'s between henkan start point and
henkan end point into katakana\'s.  Valid only in ▽ mode."
  (interactive "P")
  (if j-henkan-on
      (if (or j-henkan-active j-katakana)
	  nil
        (setq j-mode t)
	(or (string= j-prefix "") (error ""))
	(if (< (point) j-henkan-start-point)
	    (error "Henkan end point must be after henkan start point."))
	(save-excursion
	  (beginning-of-line)
	  (if (> (point) j-henkan-start-point)
	      (error "Henkan key may not contain a new line character.")))
	(skk-move-marker j-henkan-end-point (point))
	(j-katakana-region j-henkan-start-point j-henkan-end-point t)
	(or arg (j-kakutei))
	)
    (j-emulate-original-map arg)
    ))

;; contributed by Kazuo Hirokawa, 1991.11.21.

(defun j-hiragana-henkan (arg)
"Convert katakana\'s between henkan start point and
henkan end point into hiragana\'s.  Valid only in ▽ mode."
  (interactive "P")
  (if j-henkan-on
      (if (or j-henkan-active (not j-katakana))
	  nil
	(setq j-mode t)
	(or (string= j-prefix "") (error ""))
	(if (< (point) j-henkan-start-point)
	    (error "Henkan end point must be after henkan start point."))
	(save-excursion
	  (beginning-of-line)
	  (if (> (point) j-henkan-start-point)
	      (error "Henkan key may not contain a new line character.")))
	(skk-move-marker j-henkan-end-point (point))
	(j-hiragana-region j-henkan-start-point j-henkan-end-point t)
	(or arg (j-kakutei))
	)
    (j-emulate-original-map arg)
    ))

;; contributed by Kazuo Hirokawa, 1991.11.21.

(defun j-zenkaku-henkan (arg)
  "Convert hankaku\'s between henkan start point and
henkan end point into zenkaku\'s.  Valid only in ▽ mode."
  (interactive "P")
  (if j-henkan-on
      (if j-henkan-active
	  nil
        (setq j-mode t)
	(or (string= j-prefix "") (error ""))
	(if (< (point) j-henkan-start-point)
	    (error "Henkan end point must be after henkan start point."))
	(save-excursion
	  (beginning-of-line)
	  (if (> (point) j-henkan-start-point)
	      (error "Henkan key may not contain a new line character.")))
	(skk-move-marker j-henkan-end-point (point))
	(j-zenkaku-region j-henkan-start-point j-henkan-end-point)
	(or arg (j-kakutei))
	)
    (j-emulate-original-map arg)
    ))

(defun j-start-henkan (arg)
  (interactive "p")
  (if j-henkan-on
      (progn
	(setq j-mode t)
	(if j-henkan-active (j-next-candidate)
	  (or (string= j-prefix "") (error ""))
	  (if (< (point) j-henkan-start-point)
	      (error "Henkan end point must be after henkan start point."))
	  (save-excursion
	    (beginning-of-line)
	    (if (> (point) j-henkan-start-point)
		(error "Henkan key may not contain a new line character.")))
	  (skk-move-marker j-henkan-end-point (point))
	  ;; modified by Takeshi OHTANI, 1995.1.17.
	  (setq j-henkan-key
		(let ((key (buffer-substring j-henkan-start-point
					     j-henkan-end-point)))
		  (substring key 0 (string-match " " key)))
		j-henkan-vector (vector))
	  ;;(insert " ")
	  (setq j-search-key (j-compute-numeric-henkan-key))
;for debugging
;	  (princ "j-search-key")
;	  (princ j-search-key)
;
	  (j-henkan)
	  ;;(delete-backward-char 1)
	  (if (and j-abbrev j-henkan-active) (use-local-map skk-map))))
    (j-self-insert arg)))

(defun j-set-henkan-point-subr ()
  (interactive)
  (if j-henkan-on (j-kakutei))
  (or (string= j-prefix "") (j-erase-prefix))
  (insert "▽")
  (or (string= j-prefix "")
      (progn
	(skk-move-marker j-kana-start-point (point))
	(insert j-prefix)))
  (setq j-henkan-on t)
  (skk-move-marker j-henkan-start-point (point)))

(defun j-change-marker ()
  (save-excursion
    (goto-char (- j-henkan-start-point j-kanji-len))
    (if (looking-at "▽")
	(progn
	  (insert "▼")
	  (delete-char 1))
      (j-kakutei)
      (error "It seems that you have deleted ▽."))))

(defun j-change-marker-to-white ()
  (save-excursion
    (goto-char (- j-henkan-start-point j-kanji-len))
    (if (looking-at "▼")
	(progn
	  (insert "▽")
	  (delete-char 1))
      (goto-char j-henkan-start-point)
      (insert "▽")
      (skk-move-marker j-henkan-start-point (point))
      (message "It seems that you have deleted ▼."))))

;; functions for handling numeric arguments in henkan key.

(defun j-compute-numeric-henkan-key ()
  "return the modified version of j-henkan-key where any consecutive
substring consisting of numeric chars like \"12\" or \"０９\" is
replaced by a #."
  (let (p (list nil) (val nil) (key j-henkan-key))
    (if skk-use-numeric-conversion
	(progn
	  (save-excursion
	    (set-buffer (get-buffer-create " *skk-work*"))
	    (erase-buffer)
	    (insert key)
	    (goto-char (point-min))
;	    (while (re-search-forward "\\([0-9]\\|[０-９]\\)" nil t)
	    (while (re-search-forward "([0-9]|[０-９])" nil t)
	      (let (num)
		(goto-char (match-beginning 1))
		(setq p (point))
		(while (looking-at "([0-9]|[０-９])")
;		(while (looking-at "\\([0-9]\\|[０-９]\\)")
		  (if (looking-at "[０-９]")
		      (progn
			;; modified by Kazuo Hirokawa, 1993.7.7
			(insert (- (following-char) (- ?０ ?0)))
;      			(if skk-mule
;			    (insert
;			     (- (char-component (following-char) 2) 128))
;			  (insert (- (char-after (1+ (point))) 128)))
			(delete-char 1))
		    (forward-char 1)))
		(setq num (buffer-substring p (point)))
		(delete-region p (point))
		(insert "#")
                ;; modified by Mikio Nakajima, 1995.4.15
                (setq list (nconc list (list num)))))
	    (setq val (buffer-string)))
	  (setq j-num-list list)
	  val)
      key)))

(defun j-num-exp (num type)
  "convert the integer string NUM into a string according to TYPE."
  (let ((fun (cdr (assq type skk-num-type-list))))
    (if fun (apply fun (list num))
      num)))

(defun j-zenkaku-num-str (num)
  "convert NUM to the string representing it in zenkaku numerals."
  (if (> (length num) 0)
      ;; modified by Masahiro Doteguchi, 1993.6.25.
      (concat (j-zenkaku-num (aref num 0))
	      (j-zenkaku-num-str (substring num 1)))
    ""))

(defun j-zenkaku-num (num)
  (cdr (assq num
	     '((?0 . "０") (?1 . "１") (?2 . "２") (?3 . "３")
	       (?4 . "４") (?5 . "５") (?6 . "６") (?7 . "７")
	       (?8 . "８") (?9 . "９")))))

(defun j-kanji-num-str (num)
  "convert NUM to the string representing it in zenkaku kanji numerals."
  (if (> (length num) 0)
      (concat (j-kanji-num (aref num 0))
	      (j-kanji-num-str (substring num 1)))
    ""))

(defun j-kanji-num (num)
  (cdr (assq num
	     '((?0 . "〇") (?1 . "一") (?2 . "二") (?3 . "三")
	       (?4 . "四") (?5 . "五") (?6 . "六") (?7 . "七")
	       (?8 . "八") (?9 . "九")))))

(defun j-kanji-num-str2 (num)
  "convert NUM to the string representing it in kanji.  e.g, 1021 will be
converted to \"千二十一\""
  (let ((str (j-kanji-num-str2-subr num)))
    (if (string= "" str) "〇" str)))

(defun j-kanji-num-str2-subr (num &optional silent0)
  "If the optional argument SILENT0 is t, the initial 0 of NUM string
will be supressed."
  (let* ((len (length num))
	 (l (substring num 0 1))
	 (r (substring num 1))
	 (c (string-to-char l)))
    (if (string= "" r)
	(if (= c ?0) "" (j-kanji-num c))
      (or (string= l "0") (setq silent0 nil))
      (concat
       (if (or (= c ?0) (and (string= l "1") (not (= (mod len 4) 1))))
	   ""
	 (j-kanji-num c))
       (if (and (string= l "0") (or silent0 (not (= (mod len 4) 1))))
	   ""
	 (cond ((= (mod len 4) 2) "十")
	       ((= (mod len 4) 3) "百")
	       ((= (mod len 4) 0) "千")
	       ((= len 5) (setq silent0 t) "万")
	       ((= len 9) (setq silent0 t) "億")
	       ((= len 13) (setq silent0 t) "兆")
	       ((= len 17) (setq silent0 t) "京")
	       (t (error "Too big num!"))))
       (j-kanji-num-str2-subr r silent0)))))

(defun j-shogi-num-str (num)
  "convert NUM to the representation used in Shogi.  e.g., 34 will be
converted to \"３四\"."
  (concat
   (j-zenkaku-num (string-to-char num))
   (j-kanji-num (string-to-char (substring num 1 2)))))

(defun j-compute-henkan-vectors ()
  (let ((cont t) (stage 1)
	(v1 (vector)) (v2 (vector)) (v3 (vector)) (v4 (vector)))
    (while (and cont (not (eolp)))
      (let ((item (buffer-substring
		   (point)
		   (progn
		     (search-forward "/")
		     (1- (point))))))
	;; modified by Kiyotaka Sakai, 1994.4.1.
	(cond ((not okuri-ari)
	       (if (and skk-process-okuri-early (= (aref item 0) ?\[))
		   (setq cont nil)
		 (setq v1 (vconcat v1 (list item)))))
	      ((and (= (aref item 0) ?\[) (<= stage 2))
	       (if (string= item
			    (concat "\[" okurigana))
		   (progn
		     (setq stage 3)
		     (setq v2 (vconcat v2 (vector item))))
		 (setq stage 2)
		 (setq v2 (vconcat v2 (vector item)))))
	      ((and (= (aref item 0) ?\]) (= stage 3))
	       (setq stage 4)
	       (setq v4 (vconcat v4 (vector item))))
	      ((= stage 1)
	       (setq v1 (vconcat v1 (vector item))))
	      ((= stage 2)
	       (setq v2 (vconcat v2 (vector item))))
	      ((= stage 3)
	       (setq v3 (vconcat v3 (vector item))))
	      ((= stage 4)
	       (setq v4 (vconcat v4 (vector item)))))))
    (list v1 v2 v3 v4)))

;; the following function was added by Kiyotaka Sakai, 1994.4.1.
;; modified by Motohiko Mouri, 1994.4.4.
;; modified by Tsugutomo Enami, 1994.4.4.

(defun j-quote-char (word)
  "If WORD contains characters that are normally not part of dictionary
entries, then convert it into a lisp code that will return the word when
it is evaluated."
  (if (and (string-match "[/\n\r\"]" word)
	   ;; we should not quote WORD if it is a symbolic expression
	   (let ((l (length word)))
	     (not
	      (and (> l 2)
		   (= (aref word 0) ?\()
		   (< (aref word 1) 128)
		   (= (aref word (1- l)) ?\))))))
      (concat "(concat \""
	      (mapconcat (function (lambda (c)
				     (cond ((eq c ?/) "\\057")
					   ((eq c ?\n) "\\n")
					   ((eq c ?\r) "\\r")
					   ((eq c ?\") "\\\"")
					   ((eq c ?\\) "\\\\")
					   (t (char-to-string c)))))
			 (append word nil) "")
	      "\")")
    word))

(defun j-update-jisyo (file word &optional purge)
  "update jisyo buffer associated to FILE so that WORD will become the first
candidate next time.  If PURGE is t, the word is removed from the jisyo entry."
  ;; if (get-file-buffer file) is nil, we have nothing to do
;  (princ "j-update-jisyo") for debugging
  (if (get-file-buffer file)
      (let ((vector1 [])
	    (vector2 [])
	    (vector3 [])
	    (vector4 [])
	    (len (length j-henkan-vector))
	    (count (1- j-henkan-count))
	    okuri-ari
	    okuri-info
	    min
	    max
	    (okurigana j-henkan-okurigana)
	    key
	    entry-point
	    (inhibit-quit t)
	    (new-entry t))
	;; we don't have to auto-process okuri if j-num-list is non-nil
	;; or the first character of j-henkan-key is an ascii character.
	(if (and skk-auto-okuri-process
		 (not j-num-list)
		 (> (aref j-henkan-key 0) 127)
		 (or (> j-henkan-count len)
		     (and (< j-okuri-index-min j-henkan-count)
			  (<= j-henkan-count j-okuri-index-max))))
	    (j-remove-common))
	;; we must re-compute okuri-ari, since j-henkan-key might have been
	;; changed by j-remove-common
	(setq okuri-ari ;; used in j-compute-henkan-vectors
	      (let ((char (aref j-henkan-key (1- (length j-henkan-key)))))
		(and (> (aref j-henkan-key 0) 127)
		     (<= ?a char)
		     (<= char ?z))))
	(setq key (concat (if okuri-ari j-henkan-key j-search-key) " /"))
	(save-excursion
	  (set-buffer (get-file-buffer file))
	  (setq okuri-info (assoc (expand-file-name file) j-jisyo-okuri-info))
	  (setq min (if okuri-ari (nth 1 okuri-info) (nth 3 okuri-info)))
	  (setq max (if okuri-ari (nth 2 okuri-info) (point-max)))
	  ;; we have to backup one character so that we can find key correctly
	  ;; even if it is the first entry in the region bounded by min and max
	  (goto-char (1- min))
	  ;; delete old entry
	  (if (search-forward (concat "\n" key) max t)
	      (progn
		(let ((l (j-compute-henkan-vectors)))
		  (setq vector1 (nth 0 l)
			vector2 (nth 1 l)
			vector3 (nth 2 l)
			vector4 (nth 3 l)))
		(setq new-entry nil)
		(delete-region
		 (progn (beginning-of-line) (point))
		 (progn (end-of-line) (forward-char 1) (point)))))
	  ;; insert new entry
	  (if okuri-ari
	      (if new-entry
		  (let (p)
		    (goto-char min)
		    (setq p (point))
		    ;; modified by Kazuo Hirokawa, 1991.6.10
		    (while (and (not (= (point) max))
				(string< key
					 (progn
					   (search-forward " /")
					   (buffer-substring p (point)))))
		      (forward-line 1)
		      (setq p (point)))))
	    (goto-char min))
	  (beginning-of-line)
	  (setq entry-point (point))
	  (insert key
		  (if purge
		      ""
		    (concat
		     (if (and (not new-entry)
			      skk-use-numeric-conversion
			      j-num-list
			      (< count (length vector1)))
			 (setq word (aref vector1 count))
		       (j-quote-char word))
		     "/")))
	  (let ((index 0) (len (length vector1)))
	    (while (< index len)
	      (let ((w (aref vector1 index)))
		(or (string= word w) (insert (j-quote-char w) "/"))
		(setq index (1+ index)))))
	  (if (and okuri-ari (not skk-process-okuri-early))
	      (progn
		(let ((index 0) (len (length vector2)))
		  (while (< index len)
		    (insert (aref vector2 index) "/")
		    (setq index (1+ index))))
		(if (equal vector3 [])
		    (or purge (insert "\[" okurigana "/" word "/\]/"))
		  (let ((index 0) (len (length vector3)))
		    (or purge (insert word "/"))
		    (while (< index len)
		      (let ((w (aref vector3 index)))
			(or (string= word w)
			    (insert w "/"))
			(setq index (1+ index))))))
		(let ((index 0) (len (length vector4)))
		  (if (> len 0)
		      (let ((p (point)))
			(save-excursion
			  (search-backward "/" nil nil 2)
			  (if (looking-at  "/\\[")
			      (progn
				(delete-region (1+ (point)) p)
				(setq index 1))))))
		  (while (< index len)
		    (insert (aref vector4 index) "/")
		    (setq index (1+ index))))))
	  (if purge
	      (let ((uniq t) (index 0) (l2 (length vector2))
		    (l4 (length vector4)))
		(while (and uniq (< index l2))
		  (if (string= word (aref vector2 index))
		      (setq uniq nil)
		    (setq index (1+ index))))
		(setq index 0)
		(while (and uniq (< index l4))
		  (if (string= word (aref vector4 index))
		      (setq uniq nil)
		    (setq index (1+ index))))
		(if uniq
		    ;; the WORD is not in vector2 nor in vector4, so purge it
		    ;; also from vector1 (if any)
		    (save-excursion
		      (let ((q (point)))
			(goto-char entry-point)
			(search-forward " ")
			(if (search-forward (concat "/" word "/") q t)
			    (delete-region (1+ (match-beginning 0))
					   (match-end 0))))))))
	  (insert "\n")
	  (forward-line -1)
	  (search-forward " /")
	  (if (eolp)
	      ;; the key has no words for it so delete everything
	      (delete-region (save-excursion (beginning-of-line) (point))
			     (1+ (point))))
	  (if okuri-ari
	      ;; in this case, we need to reset j-okuri-ari-max and
	      ;; j-okuri-nasi-min
	      (progn
		(goto-char min)
		(search-forward "\n;; okuri-nasi")
		(beginning-of-line)
		(setcar (nthcdr 2 okuri-info) (point))
;;		(setq j-okuri-ari-max (point))
		(forward-line 1)
		(setcar (nthcdr 3 okuri-info) (point))
;;		(setq j-okuri-nasi-min (point))
		))
	  (setq j-jisyo-buffer-modified
		(or j-jisyo-buffer-modified
		    (buffer-modified-p)))
	  (set-buffer-modified-p nil)
	  ))))

(defun j-remove-common ()
  "remove trailing common kana ending parts both from midasi and word.
For instance, (もってきた 持ってきた) -> key := \"もt /\",
okurigana := \"って\", word := \"持\""
  (let* ((midasi j-henkan-key)
	 (midasi-len (length midasi))
	 (word-len (length word))
	 ;; the following two variables were introduced by
	 ;; GUNJI Takao, 1993.9.27
	 (kanji-len2 (* 2 j-kanji-len))
	 char pos2)
    (if (and (>= midasi-len kanji-len2) (>= word-len kanji-len2))
	(progn
	  ;; check if both midasi and word end with the same ascii char.
	  (if (and (string= (substring midasi -1) (substring word -1))
		   (< (string-to-char (substring midasi -1)) 128))
	      ;; if so chop off the char from midasi and word
	      (setq midasi (substring midasi 0 -1)
		    midasi-len (1- midasi-len)
		    word (substring word 0 -1)
		    word-len (1- word-len)))
	  (let ((midasi-tail
		 (substring midasi (- midasi-len j-kanji-len) midasi-len))
		(word-tail (substring word (- word-len j-kanji-len) word-len)))
	    (if (and (string= midasi-tail word-tail)
		     (or
		      (and
		       (j-string<= "ぁ" midasi-tail)
		       (j-string<= midasi-tail "ん"))
		      (string= "、" midasi-tail)
		      (string= "。" midasi-tail)
		      (string= "，" midasi-tail)
		      (string= "．" midasi-tail)))
		(let ((pos (- word-len j-kanji-len))
		      (cont t)
		      new-word new-j-henkan-key)
		  (while (and cont (> pos 0))
		    (setq char (substring word (- pos j-kanji-len) pos))
		    (if (and (j-string<= "亜" char) (j-string<= char "瑤"))
			;; char is the right-most Kanji
			(setq cont nil)
		      (setq pos (- pos j-kanji-len))))
		  (setq pos2 (- midasi-len (- word-len pos)))
		  ;; check if midasi and word has the same tail of length
		  ;; (- word-len pos)
		  (if (string= (substring midasi pos2 midasi-len)
			       (substring word pos word-len))
		      (let ((okuri-first
			     (substring word pos (+ pos j-kanji-len))))
			(setq okurigana
			      (if (and (string= okuri-first "っ")
				       (<= (+ pos kanji-len2) word-len))
				  ;; in this case okuriga consits of two
				  ;; characters, e.g., 「残った」
				  (substring word pos (+ pos kanji-len2))
				okuri-first))
			(setq new-word (substring word 0 pos))
			(setq new-j-henkan-key
			      (concat
			       (substring midasi 0 pos2)
			       (if (string= okuri-first "ん")
				   "n"
				 (if (string= okuri-first "っ")
				     (aref skk-kana-rom-vector
					   (- (string-to-char
					       (substring
						okurigana
						(1- kanji-len2) kanji-len2))
					      161))
				   (aref skk-kana-rom-vector
					 (- (string-to-char
					     (substring
					      okurigana
					      (1- j-kanji-len) j-kanji-len))
					    161))))))
			(if (> j-henkan-count len)
			    ;; ask if register as okuri-ari word.
			    (let (;; allow keyboard quit
				  (inhibit-quit nil))
			      (if (y-or-n-p
				   (format
				    "Shall I register this as okuri-ari entry: %s /%s/ ? "
				    new-j-henkan-key new-word))
				  (setq word new-word
					j-henkan-key new-j-henkan-key))
			      (message ""))
			  (setq word new-word
				j-henkan-key new-j-henkan-key)))))))))))

(defun j-string<= (str1 str2)
  (or (string< str1 str2) (string= str1 str2)))

(defun j-henkan ()
  "The main kana-to-kanji conversion routine."
  (let ((eobp (eobp)) ; modified by Mikio Nakajima, 1995.5.10
	;; we use mark to go back to the correct position after henkan
	(mark (make-marker))
	new-word-entered)
    (or eobp
	(forward-char 1)
	(skk-move-marker mark (point)))
    (save-excursion
      (or j-henkan-active
	  (j-change-marker)
	  (setq j-henkan-active t
		j-search-prog-list skk-search-prog-list))
      (if (string= j-henkan-key "")
	  (j-kakutei)
	(let (new-word
	      (found nil) (kakutei nil) (quit nil)
	      (cont t) (l1 0) (l2 0))
	  (if (= j-henkan-count 0)
	      (progn
                ;; modified by Mikio Nakajima, 1995.4.15
		(if (equal j-henkan-vector [])
		    (progn
		      (if (eq last-command 'j-undo-kakutei)
			  ;; in this case, we should not search kakutei jisyo.
			  (setq j-search-prog-list (cdr skk-search-prog-list)))
		      (setq j-okuri-ari
			    (let ((char
				   (aref j-henkan-key
					 (1- (length j-henkan-key)))))
			      (and (> (aref j-henkan-key 0) 127)
				   (<= ?a char)
				   (<= char ?z)))
			    j-henkan-vector (j-search))))
		;; modified by Mikio Nakajima, 1995.4.15
		;; modified by Mikio Nakajima, 1995.5.10
		(if (not (equal j-henkan-vector []))
		    (setq found t
			  j-henkan-count 1
			  new-word (aref j-henkan-vector 0))))
	    (if (< j-henkan-count (length j-henkan-vector))
		(setq new-word (aref j-henkan-vector j-henkan-count)
		      found t)
	      ;; call j-search repeateldly, until we find new candidates
	      ;; or until j-search-prog-list becomes empty
	      (while (and j-search-prog-list (= l1 l2))
		(setq l1 (length j-henkan-vector))
		(setq j-henkan-vector
		      (j-vector-add j-henkan-vector (j-search)))
		(setq l2 (length j-henkan-vector)))
	      (if (< j-henkan-count (length j-henkan-vector))
		  (setq new-word (aref j-henkan-vector j-henkan-count)
			found t)))
	    (if (< j-henkan-count 4)
		(if found (setq j-henkan-count (1+ j-henkan-count)))
	      (if found
		  ;; show candidates in minibuffer
		  (j-henkan-show-candidates))))
	  (or quit
	      (if found
		  (progn
		    (delete-region j-henkan-start-point j-henkan-end-point)
		    (goto-char j-henkan-start-point)
		    (j-insert-word new-word)
		    (skk-move-marker j-henkan-end-point (point))
		    (if kakutei
			(let ((j-prefix j-prefix))
			  ;; save and restore j-prefix after j-kakutei
			  (j-kakutei new-word))))
		;; use recursive minibuffer
		(let ((save-start (copy-marker j-henkan-start-point))
		      (save-end (copy-marker j-henkan-end-point))
		      ;; added by IIDA Yosiaki, 1994.3.18.
		      (enable-recursive-minibuffers t) ; Added by IIDA
		      ;; inhibit isearch message while doing henkan
		      (skk-isearch-message nil))
		  (setq new-word-entered (j-henkan-in-minibuff))
		  (skk-move-marker j-henkan-start-point save-start)
		  (skk-move-marker j-henkan-end-point save-end)
		  (if new-word-entered
		      (progn
			(delete-region j-henkan-start-point
				       j-henkan-end-point)
			(goto-char j-henkan-start-point)
			(j-insert-word new-word)
			(skk-move-marker j-henkan-end-point (point))
			(if kakutei
			    (let ((j-prefix j-prefix))
			      ;; save and restore j-prefix after
			      ;; j-kakutei
			      (j-kakutei new-word)))))))))))
    (if eobp
	(goto-char (point-max))
      (goto-char mark)
      (or (and overwrite-mode new-word-entered) (backward-char 1))
      )))

(defun j-insert-word (word)
  "Insert WORD at point.  If SKK-USE-NUMERIC-CONVERSION is t, WORD will
be modified using j-num-list, and the the modified word will be inserted."
  (if (and skk-use-numeric-conversion j-num-list)
      (setq word (j-numeric-convert word)))
;  (if (string-match "^(.*)$" word)
  (if (string-match "^\\(.*\\)$" word)
      (condition-case conditions
	  (insert (eval (car (read-from-string word))))
	(quit (insert word))
	(error (insert word)))
    (insert word)))

;; modified by Mikio Nakajima, 1995.4.11
(defun j-search ()
  "search j-henkan-key using the programs in the list j-search-prog-list."
  (let ((v []))
    (while (and (equal v []) j-search-prog-list)
      (setq v (eval (car j-search-prog-list))
            j-search-prog-list (cdr j-search-prog-list) ))
    v ))

;;	複数の辞書ファイルを検索して、検索結果を merge して返す。
;;	これは skkinput-jisyo 及び skk-jisyo を一度の検索で終えるため
;;	に利用している。 
;;
(defun j-merge-search-jisyo-file (&rest files)
  (let (ari-min	ari-max	nasi-min result file okuri-info (retval []))
    (while files
      (setq file (car files))
;      (princ file)	; for debugging
      (if file
	  (progn
	    (j-get-file-buffer file t)
	    (save-excursion
	      (set-buffer (get-file-buffer file))
	      (setq okuri-info (assoc (expand-file-name file) j-jisyo-okuri-info))
;	      (princ okuri-info) ;	for debugging
	      (setq ari-min  (nth 1 okuri-info)
		    ari-max  (nth 2 okuri-info)
		    nasi-min (nth 3 okuri-info)))
	    (setq result
		  (j-search-sorted-buffer
		   (if j-okuri-ari j-henkan-key j-search-key)
		   (get-file-buffer file)
		   0
		   (if j-okuri-ari ari-min nasi-min)
		   (if j-okuri-ari ari-max nil)
		   (if j-okuri-ari t nil))))
	(setq result []))
;      (princ result)	; for debugging
      (setq retval (j-vector-add retval result))
      (setq files (cdr files)))
;    (princ retval) ; for debugging
    retval))

;; introduced at the suggestion of Katuya Tomioka, 92.4.20
(defun j-search-jisyo-file (file limit &optional nomsg)
  "search henkan-key in skk format jisyo file FILE.  binary search is
performed until the search region becomes less than LIMIT, and then
switch to linear search.  if LIMIT is 0, only linear search is done.
if the jisyo file is not sorted, you should set LIMT to be 0.  optional
argument NOMSG, if t, supresses the message."
  (let (ari-min ari-max nasi-min okuri-info)
    (if file
	(progn
	  (j-get-file-buffer file nomsg)
	  (save-excursion
	    (set-buffer (get-file-buffer file))
	    (setq okuri-info (assoc (expand-file-name file) j-jisyo-okuri-info))
	    (setq ari-min  (nth 1 okuri-info)
		  ari-max  (nth 2 okuri-info)
		  nasi-min (nth 3 okuri-info)))
	  (j-search-sorted-buffer
	   (if j-okuri-ari j-henkan-key j-search-key)
	   (get-file-buffer file)
	   limit
	   (if j-okuri-ari ari-min nasi-min)
	   (if j-okuri-ari ari-max nil)
	   (if j-okuri-ari t nil)))
      [])))

(defun j-get-file-buffer (file &optional nomsg)
  "Create a unique buffer for skk formated FILE and initialize some
local variables."
  (or (get-file-buffer file)
      (save-excursion
	(setq file (expand-file-name file))
	(set-buffer
	 (generate-new-buffer
	  (concat " *" (file-name-nondirectory file) "*")))
	(setq buffer-file-name file)
	;; suggested by Masakazu Takahashi, 1992.1.26.
	(setq case-fold-search nil)
;	(buffer-flush-undo (current-buffer))
	(or nomsg
	    (message "Inserting contents of %s ..."
		     (file-name-nondirectory file)))
	(insert-file-contents file)
	(or nomsg
	    (message "Inserting contents of %s ...done"
		     (file-name-nondirectory file)))
	(set-buffer-modified-p nil)
	(if (= (point-min) (point-max))
	    ;; if the file is empty, we make it a minimal well
	    ;; formed skk jisyo
	    (insert ";; okuri-ari entries.\n"
		    ";; okuri-nasi entries.\n"))
	(goto-char (point-min))
	(if (search-forward ";; okuri-ari entries.\n" nil t)
	    (let ((j-okuri-ari-min 0)
		  (j-okuri-ari-max 0)
		  (j-okuri-nasi-min 0) j-new-entry)
	      (setq j-okuri-ari-min (point))
	      ;; modified at the suggestion of MIYOSHI Tsutomu, 1992.9.30
	      (backward-char 1)
	      (if (search-forward "\n;; okuri-nasi entries." nil t)
		  (progn
		    (beginning-of-line)
		    (setq j-okuri-ari-max (point))
		    (end-of-line)
		    (setq j-okuri-nasi-min (1+ (point))))
		(error "%s is not well formed!" file))
	      (setq j-jisyo-okuri-info 
		    (cons (list file j-okuri-ari-min j-okuri-ari-max j-okuri-nasi-min)
			  j-jisyo-okuri-info)))
	  (error "%s is not well formed!" file))
;
;	(princ j-jisyo-okuri-info)
;
	(current-buffer))))

(defun j-search-kakutei-jisyo-file (file limit &optional nomsg)
  "search jisyo file, and return the first candidate as a string.  if no
candidates are found, return an empty vector."
  (let ((v (j-search-jisyo-file file limit nomsg)))
    (if (equal v [])
	[]
      (aref v 0))))

(defun j-search-sorted-buffer (key buffer limit &optional min max reverse)
  "search KEY in BUFFER which is assumed to be sorted. try binary
search first until the size of the search region becomes less than LIMIT.
If LIMIT is 0, only linear seach is done.  optional arguments MIN and MAX
bounds the search region.  if the optional argument REVERSE is t,
comparison will be done by reversed order."
  (let ((okurigana j-henkan-okurigana) ;; used in j-compute-henkan-vectors
	(okuri-ari j-okuri-ari) ;; used in j-compute-henkan-vectors
	;; when merge-all-entry is nil, only the entry with strcitly
	;; matched okurigana is returned.
	(merge-all-entry (or (not j-okuri-ari) (not j-henkan-okuri-strictly)))
	size p l)
    (save-excursion
      (set-buffer buffer)
      (setq min (or min (point-min))
	    max (or max (point-max))
	    size (- max min))
      ;; modified by Mikio Nakajima, 1995.4.19
      (if (> limit 0)
          (while (> size limit)
	    (goto-char (+ min (/ size 2)))
	    (beginning-of-line)
	    (setq p (point))
	    (if (if reverse
		    (string<
		     (buffer-substring
                      p                 ; modified by Mikio Nakajima, 1995.5.10
		      (progn (search-forward " ") (1- (point))))
		     key)
		  (string<
		   key
		   (buffer-substring
                    p                   ; modified by Mikio Nakajima, 1995.5.10
		    (progn (search-forward " ") (1- (point))))))
		(setq max p)
	      (setq min p))
            (setq size (- max min)) ))
      (goto-char min)
      ;; backup one character so that we can find the key correctly even
      ;; if the key is at the beginning of the search region.
      (or (bobp) (backward-char 1))
      ;; modified by Mikio Nakajima, 1995.5.10
      (let ((w (concat "\n" key " /"))
	    (kanji-flag nil)
            (mc-flag nil)               ; added by Mikio Nakajima, 1995.4.18
	    (case-fold-search nil))
	;; kanji-flag must be set nil for efficiency.
        ;; modified by Mikio Nakajima, 1995.5.10
        (setq l (if (search-forward w max t)
		    (j-compute-henkan-vectors)
                  '([] [] [] []) )))
      ;; added by Tsugutomo Enami, 1994.5.30.
      (if merge-all-entry
	  (j-vector-add (nth 2 l) (nth 0 l))
	(nth 2 l) ))))

(defun j-merge-okuri-search (&rest files)
  (let ((v []) skkinput-jisyo file)
    (if (and
	 ;; modified by Takeshi Ohtani, 1995.4.25
	 (not j-abbrev)
	 skk-auto-okuri-process
	 (not skk-process-okuri-early)
	 (not j-okuri-ari)
	 ;; we don't do auto-okuri-process if henkan key
	 ;; contains numerals
	 (not j-num-list)
	 ;; suggested by Kazuo Hirokawa, 1991.10.30.
	 (> (length j-henkan-key) 1))
	(progn
	  (setq j-okuri-index-min (length j-henkan-vector))
	  (while files
	    (if (setq skkinput-jisyo (car files))
		(setq v (j-vector-add v (j-okuri-search-subr))))
	    (setq files (cdr files)))
	  (setq j-okuri-index-max (+ j-okuri-index-min (length v)))
	  v)
      [])))

(defun j-okuri-search ()
  (let (v)
    (if (and
	 ;; modified by Takeshi Ohtani, 1995.4.25
	 (not j-abbrev)
	 skk-auto-okuri-process
	 (not skk-process-okuri-early)
	 (not j-okuri-ari)
	 ;; we don't do auto-okuri-process if henkan key
	 ;; contains numerals
	 (not j-num-list)
	 ;; suggested by Kazuo Hirokawa, 1991.10.30.
	 (> (length j-henkan-key) 1))
	(progn
	  (setq j-okuri-index-min (length j-henkan-vector))
	  (setq v (j-okuri-search-subr))
	  (setq j-okuri-index-max (+ j-okuri-index-min (length v)))
	  v)
      [])))

(defun j-okuri-search-subr ()
  (let* ((henkan-key j-henkan-key)
	 ;; modified by GUNJI Takao, 1993.11.1
	 (key (substring henkan-key 0 (if skk-mule 3 2)))
	 (len (length henkan-key))
	 (key1 (concat "\n" key))
	 key2 len2
	 key3 len3 okuri3
	 (kanji-flag nil)
         (mc-flag nil) ; added by Mikio Nakajima, 1995.4.18
	 (inhibit-quit t)
	 p q r s
	 (v (vector))
	 j-okuri-info j-okuri-ari-min j-okuri-ari-max
	 )
    (save-excursion
      (set-buffer (get-file-buffer skkinput-jisyo))
      (setq j-okuri-info (assoc (expand-file-name skkinput-jisyo) j-jisyo-okuri-info))
      (setq j-okuri-ari-min (nth 1 j-okuri-info)
	    j-okuri-ari-max (nth 2 j-okuri-info))
      (goto-char (1- j-okuri-ari-min))
      (while (search-forward key1 j-okuri-ari-max t)
	(setq p (point))
	(search-forward " ")
	(setq key2 (concat key (buffer-substring p (- (point) 2)))
	      len2 (length key2))
	(if (and
	     (<= len2 len)
             ;; modified by Mikio Nakajima,  1995.4.18
	     (string= key2 (substring henkan-key 0 len2)) )
	    (let ((cont t))
	      (save-excursion
		(end-of-line)
		(setq q (point)))
	      (while (and cont
			  (search-forward "/[" q t))
		(setq r (point))
		(search-forward "/")
		(setq okuri3 (buffer-substring r (1- (point)))
		      key3 (concat key2 okuri3)
		      len3 (length key3))
		(if (and
		     (<= len3 len)
                     ;; modified by Mikio Nakajima, 1995.4.18
		     (string= key3 (substring henkan-key 0 len3)) )
		    ;; finally found a candidate!
		    (let ((okuri
			   (concat okuri3
				   (substring henkan-key len3 len))))
		      (while (not (looking-at "\]"))
			(setq s (point))
			(search-forward "/" j-okuri-ari-max t)
			(setq v (vconcat v
					 (vector
					  (concat
					   (buffer-substring s (1- (point)))
					   okuri)))))
		      ;; it is not necessary to seach for "\[" on this line
		      ;; any more
		      (setq cont nil)))))))
      v)))

(defun j-numeric-convert (word)
  "If j-num-list is non-nil, convert WORD by substituting appropriate strings
for the occurrences of # in the WORD."
  (let ((list j-num-list) num)
    (if list
	(save-excursion
	  (set-buffer (get-buffer-create " *skk-work*"))
	  (erase-buffer)
	  (insert word)
	  (goto-char (point-min))
	  (while (and list (search-forward "#" nil t))
	    (setq num (car list))
	    (let ((char (following-char)))
	      (delete-region (1- (point)) (1+ (point)))
	      (insert (j-num-exp num char))
	      (setq list (cdr list))))
	  (buffer-string))
      word)))

(defun j-henkan-show-candidates (&optional h-start)
  "Show candidates in the minibuffer."
  (let ((cont t) (count 1) (l (length j-henkan-vector)))
    (or h-start (setq h-start 4))
    (setq found t)
    (delete-region j-henkan-start-point j-henkan-end-point)
    (let ((h-count j-henkan-count) (unread nil)
	  ;; Modified by Masakazu Takahashi, 1991.11.18
	  ;; Added following to enable interruption while executing
	  ;; skk-isearch.
	  (inhibit-quit nil))
      (save-excursion
	(while (and j-search-prog-list (< (- l h-count) 7))
	  (setq j-henkan-vector (j-vector-add j-henkan-vector (j-search))
		l (length j-henkan-vector)))
	(if (= h-count l)
	    (setq cont nil found nil))
	(while cont
	  (while (and j-search-prog-list (< (- l h-count) 7))
	    (setq j-henkan-vector (j-vector-add j-henkan-vector (j-search))
		  l (length j-henkan-vector)))
	  (if (= h-count l)
	      (setq cont nil)
	    (let ((i 1) str)
	      (setq str
		    (concat
		     (char-to-string (upcase
				      (nth 0 j-henkan-show-candidates-keys)))
		     ":"
		     (j-aref j-henkan-vector h-count)))
	      (while (and (< (+ h-count i) l) (< i 7))
		(setq str
		      (concat
		       str
		       "  "
		       (char-to-string (upcase
					(nth i j-henkan-show-candidates-keys)))
		       ":"
		       (j-aref j-henkan-vector (+ h-count i))))
		(setq i (1+ i)))
	      (setq str
		    (concat
		     str
		     (format "  [残り %d%s]"
			     (1+ (- l (+ h-count
					 (setq count
					       (min 8 (1+ (- l h-count)))))))
			     (make-string (length j-search-prog-list) ?+))))
;	      (princ str)
	      (message str)
	      )
	    (setq h-count (+ h-count (1- count)))
	    (condition-case conditions
		;; modified by Kiyotaka Sakai, 1994.11.8.
		(let* ((char (j-read-char))
		       (nth -1)
		       (char-val-pair
			(assq char
			      (mapcar
			       (function
				(lambda (x) (setq nth (1+ nth)) (cons x nth)))
				j-henkan-show-candidates-keys))))
		  (cond (char-val-pair
			 (let ((c (cdr char-val-pair)))
			   (if (> (+ c 2) count)
			       (progn
				 (message "`%c' is not valid here!" char)
				 (sit-for 1)
				 (setq h-count
				       (- h-count (1- count))))
			     ;; modified by Kazuo Hirokawa, 1992.5.15
			     (setq h-count
				   (+ (- h-count count) c 2))
			     (setq new-word
				   (aref j-henkan-vector (1- h-count)))
;;	modified by Tatari SAKAMOTO, 2003.10.16
			     (message nil)
;
			     (setq kakutei t cont nil))))
			((= char ?x)
			 (let* ((a (/ (- h-count (1+ h-start)) 7))
				(b (- h-count (+ h-start (* 7 a)))))
			   (if (= a 0)
			       (setq h-count (- h-count (1- b))
				     cont nil unread t)
			     (setq h-count (- (- h-count b) 7)))))
			((= char 32)
			 (if (and (= h-count l) (null j-search-prog-list))
			     ;; no more candidates
			     (setq cont nil found nil)))
			((= char ?\C-g) (signal 'quit nil))
			(t
			 (message "`%c' is not valid here!" char)
			 (sit-for 1)
			 (setq h-count (- h-count (1- count))))))
	      (quit
	       (setq h-count 1 cont nil unread t))))))
      (if unread (setq unread-command-char ?x quit t))
      (setq j-henkan-count h-count))))

(defun j-henkan-in-minibuff ()
  (setq new-word
	(let (r-word (h-count j-henkan-count))
	  (condition-case conditions
	      (setq r-word
		    (read-from-minibuffer
		     (concat
		      (if j-num-list
			  j-search-key
			(or j-henkan-key2 j-henkan-key))
		      " ")
		     nil
		     (progn
		       (j-setup-skk-minibuff-map)
		       skk-minibuff-map)))
	    (quit
	     (setq r-word "")))
	  (setq j-henkan-count h-count)
	  r-word))
  (if (string= new-word "")
      (progn
	(cond ((> j-henkan-count 4)
	       (let* ((a (/ (- j-henkan-count 5) 7))
		      (b (- j-henkan-count (+ 4 (* 7 a)))))
		 (setq j-henkan-count (- j-henkan-count b))
		 (j-henkan)))
	      ((= j-henkan-count 0)
	       (setq j-henkan-active nil
		     j-henkan-key2 nil)
	       (let ((j-henkan-start-point save-start))
		 (j-change-marker-to-white)))
	      (t nil)))
    (setq kakutei t)
    (setq j-count-touroku (1+ j-count-touroku))
    (setq j-henkan-count (1+ j-henkan-count)))
  (not (string= new-word "")))

(defun j-aref (vector index)
  "Get the element of VECTOR at index INDEX.  If SKK-USE-NUMERIC-CONVERSION
is t, modify the result appropriately using j-num-list."
  (let ((word (aref vector index)))
    (if (and skk-use-numeric-conversion j-num-list)
	(j-numeric-convert word)
      word)))

(defun j-next-candidate ()
  "Show next henkan candidate."
  (if j-henkan-active
      (progn
	;;(insert " ")
	(j-henkan)
	;;(delete-backward-char 1)
	)))

(defun j-previous-candidate ()
  "Show previous henkan candidate."
  (interactive)
  (if (and j-henkan-active (not (string= j-henkan-key "")))
      (progn
	(insert " ")
	(let ((word (concat j-henkan-key " ")) new-word
	      (found nil) p q)
	  (save-excursion
	    (cond ((= j-henkan-count 1)
		   (setq j-henkan-active nil
			 j-henkan-count 0
			 j-okuri-index-min 0
			 j-okuri-index-max 0
			 j-henkan-vector []
			 j-okurigana nil
			 j-henkan-okurigana nil
			 j-henkan-key2 nil
			 j-num-list nil)
		   (setq q (point-marker))
		   (delete-region j-henkan-start-point j-henkan-end-point)
		   (goto-char j-henkan-end-point)
		   (insert j-henkan-key)
		   (if (> (length j-prefix) 0)
		       (skk-move-marker j-kana-start-point (point)))
		   (setq p (point-marker))
		   (goto-char j-henkan-start-point)
		   (if (> (following-char) 127)
		       (progn
			 ;; roman prefix for okurigana is removed
			 (while (and (< (point) p) (> (following-char) 127))
			   (forward-char 1))
			 (if (and (<= ?a (following-char))
				  (<= (following-char) ?z))
			     (delete-region (point) p)))
		     (goto-char p))
		   (j-change-marker-to-white))
		  ((<= j-henkan-count 7)
		   (setq word (aref j-henkan-vector (- j-henkan-count 2)))
		   (delete-region j-henkan-start-point j-henkan-end-point)
		   (goto-char j-henkan-end-point)
		   (j-insert-word word)
		   (skk-move-marker j-henkan-end-point (point))
		   (setq j-henkan-count (1- j-henkan-count)))
		  ((< 7 j-henkan-count)
		   (setq j-henkan-count (- j-henkan-count 8))
		   (setq unread-command-char 32) ;; 32 is space char
		   )))
	  (if (and (> (point) 1) (= (char-after (1- (point))) 32))
	      (delete-backward-char 1))
	  (if (= j-henkan-count 0)
	      (progn
		(if skk-auto-okuri-process (goto-char q) (goto-char p))
		(if j-abbrev (use-local-map skk-abbrev-map))))))
    (if (eq last-command 'j-kakutei-henkan)
	;; restore the state just before the last kakutei henkan.
	(progn
	  (delete-region j-henkan-start-point (point))
	  (j-set-henkan-point-subr)
	  (insert j-kakutei-key)
	  (setq this-command 'j-undo-kakutei))
      (j-kana-input))))

(defun j-keyboard-quit ()
  "If j-henkan-active, abort showing henkan candidates and return to the
j-henkan-on status; if j-henkan-on, delete region between current point and
j-henkan-start-point; otherwise same as keyboard-quit"
  (interactive)
  (if (string= j-henkan-key "")
      (if (j-in-minibuffer) (abort-recursive-edit) (keyboard-quit)))
  (if j-henkan-active
      (progn
	(if (and skk-delete-okuri-when-quit j-okuri-ari)
	    (let ((p (point-marker)))
	      (setq j-henkan-count 1)
	      (j-previous-candidate)
	      (delete-region p (point)))
	  (setq j-henkan-count 1)
	  (j-previous-candidate)))
    (if j-henkan-on
	;; modified by Kiyotaka Sakai, 1994.7.5.
	(progn
	  (if (> (point) j-henkan-start-point)
	      (delete-region (point) j-henkan-start-point))
	  (j-kakutei))
      (if (j-in-minibuffer) (abort-recursive-edit) (keyboard-quit)))))

(defun j-kakutei (&optional word)
  "This function does what it says. If WORD is given, it is used as the new
word for jisyo update."
  (interactive)
  (let ((inhibit-quit t))
    (if skk-mode
	(progn
	  (j-change-mode-line (if j-katakana skk-katakana-mode-string
				skk-hirakana-mode-string))
	  (use-local-map skk-map))
      ;; if skk-mode has not been called in this buffer, call it now.
      (skk-mode 1))
    (setq j-mode t
	  j-prefix "")
    (if j-henkan-on
	(progn
	  (if (and j-henkan-active (> j-henkan-count 0))
	      (progn
		(mutual-eval
		 skk-jisyo-mutex
		 '(j-update-jisyo
		   skkinput-jisyo
		   (or word (aref j-henkan-vector (1- j-henkan-count)))))
		(setq j-count-kakutei (1+ j-count-kakutei))))
	  (save-excursion
	    (goto-char (- j-henkan-start-point j-kanji-len))
	    (if j-henkan-active
		(if (looking-at "▼")
		    (delete-char 1)
		  (message "It seems that you have deleted ▼."))
	      (if (looking-at "▽")
		  (delete-char 1)
		(message "It seems that you have deleted ▽.")))
	    (if j-okurigana
		(progn
		  (goto-char j-okurigana-start-point)
		  (if (looking-at "\\*") (delete-char 1))
		  (setq j-okurigana nil))))
	  (if self-insert-after-hook
	      (funcall self-insert-after-hook j-henkan-start-point (point)))
	  (if (or overwrite-mode (boundp 'vip-ovwrt-limit))
	      (j-del-char-with-pad
	       (j-ovwrt-len
		;; modified by Kiyotaka Sakai, 1994.6.14.
		(string-width
		 (buffer-substring j-henkan-start-point (point))))))
	  (setq j-abbrev nil)))
    (setq j-henkan-active nil
	  j-henkan-on nil
	  j-okurigana nil
	  j-okuri-char ""
	  j-henkan-key nil
	  j-henkan-key2 nil
	  j-henkan-okurigana nil
	  j-henkan-vector []
	  j-henkan-count 0
	  j-search-key nil
	  j-okuri-index-min 0
	  j-okuri-index-max 0
	  j-num-list nil)
    ;; modified by Masakazu Takahashi, 1989.8.9
    ;; modified at the suggestion of Kazuo Hirokawa, 1992.3.9.
    ;; modified by Tsugutomo Enami, 1994.7.9.
    (j-do-auto-fill)))

;; completion

;; modified by Kiyotaka Sakai, 1994.10.5.

(defun j-completion (first)
;  (princ j-jisyo-okuri-info)
  (let (c-word (cont t) p)
    (if first
	(progn
	  (setq j-completion-word
		(buffer-substring j-henkan-start-point (point)))
	  (if (string= j-completion-word "")
	      (error "Cannot complete an empty string!"))))
    (catch 'found
      (let ((inhibit-quit t)
	    ;; completion word is assumed to be a JIS Kanji word if it begins
	    ;; with a JIS character
	    (jis-completion-word (> (aref j-completion-word 0) 127))
	    j-okuri-info j-okuri-nasi-min)
	(save-excursion
	  (set-buffer (get-file-buffer skkinput-jisyo))
	  (setq j-okuri-info (assoc (expand-file-name skkinput-jisyo) j-jisyo-okuri-info))
	  (setq j-okuri-nasi-min (nth 3 j-okuri-info))
	  (if first (goto-char j-okuri-nasi-min))
	  (let ((kanji-flag nil)
		(mc-flag nil))
	    ;; kanji-flag/mc-flag must be set nil for efficiency.
	    (while (re-search-forward
		    (concat "^" (regexp-quote j-completion-word))
		    (point-max) t)
	      (if (looking-at " /")
		  nil
		(setq p (point))
		(search-forward " /")
		(setq c-word (concat j-completion-word
				     (buffer-substring p (- (point) 2))))
		;; if the c-word begins with a JIS character, we must check
		;; if it ends with an ascii character.  if it indeed ends
		;; with an ascii character we should ignore it.
		(and jis-completion-word
		     (<= (aref c-word (1- (length c-word))) 127)
		     (setq c-word nil))
		(if c-word
		    (throw 'found c-word)))))))
      (message "No %scompletions for \"%s\""
	       (if first "" "more ") j-completion-word)
      (ding))
    (if c-word
	(progn
	  (delete-region j-henkan-start-point (point))
	  (insert c-word)))))

;; modified by Kazuo Hirokawa, 1991.11.18.

(defun j-try-completion (arg)
  (interactive "P")
  (if (and j-henkan-on (not j-henkan-active))
      (progn
	(setq this-command 'j-completion)
	(j-completion
	 ;; modified at the suggestion of Kazushi Marukawa, 1992.7.22.
	 (not
	  (and skk-dabbrev-like-completion (eq last-command 'j-completion)))))
    (j-emulate-original-map arg)))

;; modified by Kazuo Hirokawa, 1991.11.18.

(defun j-abbrev-period (arg)
  (interactive "P")
  (if (eq last-command 'j-completion)
      (progn
	(setq this-command 'j-completion)
	(j-completion nil))
    (j-emulate-original-map arg)))

;; modified by Kazuo Hirokawa, 1991.11.18.

(defun j-abbrev-comma (arg)
  (interactive "P")
  (if (eq last-command 'j-completion)
      (j-previous-completion)
    (j-emulate-original-map arg)))

;; added by Tsugutomo Enami, 1994.1.10.

(defun j-command-key-sequence (key command)
  "Remove initial sequence of universal arguments from KEY and return
the real key sequence that invoked COMMAND.  If COMMAND is invoked by
`execute-extended-command', nil is returned."
  (while (not (or (zerop (length key))
		  (eq command (j-key-binding key))))
    (setq key (substring key 1)))
  (and (not (zerop (length key))) key))

;; modified by Kazuo Hirokawa, 1991.11.18.
;; modified by Tsugutomo Enami, 1994.1.10.
;; modified by Kiyotaka Sakai, 1994.10.7.
;; modified by Tsugutomo Enami and Kiyotaka Sakai, 1994.10.17.

(defun j-emulate-original-map (arg)
  (let ((prefix-arg arg)
	(local-map (current-local-map))
	(keys (j-command-key-sequence (this-command-keys) this-command))
	(buf (current-buffer)))
    (if (null keys)
	;; no alternative commands.  may be invoked by M-x.
	nil
      (unwind-protect
	  (progn
	    (use-local-map j-emacs-local-map)
	    (let ((command (j-key-binding keys)))
	      (if (eq command this-command)
		  ;; avoid recursive calling of j-emulate-original-map.
		  nil
		;; if no bindings are found, call `undefined'.  it's
		;; original behaviour.
		(setq this-command (or command (function undefined)))
		(command-execute this-command)
;		(command-execute (or command (function undefined)))
		)))
	;; restore skk keymap.
	(save-excursion
	  (set-buffer buf)
	  (use-local-map local-map))))))

(defun j-previous-completion ()
  (let ((inhibit-quit t)
	;; completion word is assumed to be a JIS Kanji word if it begins
	;; with a JIS character
	(jis-completion-word (> (aref j-completion-word 0) 127))
	(c-word nil) p)
    (save-excursion
      (set-buffer (get-file-buffer skkinput-jisyo))
      (beginning-of-line)
      (let ((kanji-flag nil)
            (mc-flag nil) ; added by Mikio Nakajima, 1995.4.18
            (cont t))
	;; kanji-flag must be set nil for efficiency.
	(while (and cont
		    (not (bobp))
		    ;; modifed by Haru Mizuno, 1994.10.6.
		    (or (re-search-backward (concat "^" j-completion-word)
					    (nthcdr 3 okuri-info)
;;					    j-okuri-nasi-min
					    t)
			(progn
			  (goto-char (point-min))
			  (looking-at (regexp-quote j-completion-word)))))
	  (search-forward j-completion-word)
	  (if (not (looking-at " /"))
	      (progn
		(setq p (point))
		(search-forward " /")
		(setq c-word (concat j-completion-word
				     (buffer-substring p (- (point) 2))))
		;; if the c-word begins with a JIS character, we must check
		;; if it ends with an ascii character.  if it indeed ends
		;; with an ascii character we should ignore it.
		(if jis-completion-word
		    (if (> (aref c-word (1- (length c-word))) 127)
			(setq cont nil)
		      (setq c-word nil)
		      (beginning-of-line))
		  (setq cont nil)))
	    (beginning-of-line)))))
    (delete-region j-henkan-start-point (point))
    (if c-word
	(insert c-word)
      (insert j-completion-word)
      (message "No more previous completions.")
      (ding))
    (setq this-command 'j-completion)))

(defun j-purge-from-jisyo ()
  "Purge wrong words from jisyo buffer."
  (interactive)
  (if (and j-henkan-active (not (string= j-henkan-key ""))
	   (yes-or-no-p "Really purge? "))
      (progn
	(mutual-eval
	 skk-jisyo-mutex
	 '(j-update-jisyo skkinput-jisyo (aref j-henkan-vector (1- j-henkan-count)) t))
	(delete-region j-henkan-start-point j-henkan-end-point)
	(j-change-marker-to-white)
	(setq j-henkan-active nil)
	(j-kakutei))))

;; skk server related functions
;; modified by Kiyotaka Sakai to handle multiple skk servers, 1993.7.28

(defun j-open-server ()
  "Establish connection with skk server."
  (or (get-process "skkservd")
      (let ((succ nil))
	(if (null skk-server-list)
	    (setq skk-server-list (list (cons skk-server-host skk-serv))))
	(while (and (null succ) skk-server-list)
	  (setq skk-server-host (car (car skk-server-list))
		skk-serv (cdr (car skk-server-list))
		skk-server-list (cdr skk-server-list))
	  (get-buffer-create " *skkserv*")
	  (if (j-open-server-subr)
	      (setq succ t)
	    (progn
	      (let ((count 7))
		(while (> count 0)
		  (message "SKK SERVER on %s is not active, I will activate it%s"
			   skk-server-host (make-string count ?.))
		  (if (string= skk-server-host (system-name))
		      ;; server host is local machine
		      (call-process skk-serv nil 0 nil)
		    (call-process
		     j-remote-shell-program nil 0 nil skk-server-host skk-serv))
		  (sit-for 3)
		  (if (j-open-server-subr)
		      (setq succ t
			    count 0)
		    (setq count (1- count))))))
	    (if succ
		(progn
		  (message "SKK SERVER on %s is active now." skk-server-host)
		  (sit-for 1)))))
	(if succ
	    (save-excursion
	      (if skk-mule
		  ;; this is for Mule
		  (set-process-coding-system
		   (get-process "skkservd") *euc-japan* *euc-japan*)
		;; this is for Nemacs
		;; If your Nemacs is an old one, it may not have the function
		;; set-process-kanji-code.
		(if (fboundp 'set-process-kanji-code)
		    (set-process-kanji-code (get-process "skkservd") 0))
		(set-buffer " *skkserv*")
		(setq kanji-fileio-code 0) ;; for old Nemacs
		))
	  (message "Could not activate SKK SERVER on %s." skk-server-host)
	  (sit-for 1)
	  ;; reset SKK-SERVER-HOST so as not to use server in this session
	  (setq skk-server-host nil)
	  (ding)))))

(defun j-open-server-subr ()
  (condition-case nil
      (open-network-stream
       "skkservd" " *skkserv*" skk-server-host (or skk-portnum "skkserv"))
    (error
     nil)))

;(defun j-search-server (file limit &optional nomsg)
;  "seach for henkan-key through skkserver. if server is not up, FILE is
;used instead."
;  ;; modified by Kiyotaka Sakai, 1993.7.28
;  (if (or skk-server-list skk-server-host)
;      (j-search-server-subr file limit)
;    (j-search-jisyo-file file limit nomsg)))

;(defun j-search-server-subr (file limit)
;  "search for henkan-key through skkserver and create the vector of
;candidates.  if server is not available, search FILE instead."
;  (let ((key (if j-okuri-ari j-henkan-key j-search-key))
;	(okurigana j-henkan-okurigana) ;; passed to j-compute-henkan-vectors
;	(okuri-ari j-okuri-ari) ;; used in j-compute-henkan-vectors
;	;; when merge-all-entry is nil, only the entry with strcitly
;	;; matched okurigana is returned.
;	(merge-all-entry (or (not j-okuri-ari) (not j-henkan-okuri-strictly)))
;	(v (vector)))
;    (save-excursion
;      (or (process-status "skkservd") (j-open-server))
;      (if (process-status "skkservd")
;	  (let ((cont t) (count 0))
;	    (set-buffer " *skkserv*")
;	    (erase-buffer)
;	    (process-send-string "skkservd" (concat "1" key " "))
;	    (while (and cont (memq (process-status "skkservd") '(open run)))
;	      (accept-process-output)
;	      (setq count (1+ count))
;	      (if (> (buffer-size) 0)
;		  (progn
;		    (if (= ?1 (char-after 1))
;			;; found key successfully, so check if a whole line
;			;; is received.
;			(if (= ?\n (char-after (1- (point-max))))
;			    (setq cont nil))
;		      ;; not found or error, so exit
;		      (setq cont nil)))))
;	    (goto-char (point-min))
;	    (if skk-report-server-response
;		(message "waited for server response %d times." count))
;	    (if (looking-at "1")
;		(progn
;		  (forward-char 2)
;		  (let ((l (j-compute-henkan-vectors)))
;		    (if merge-all-entry
;			;; added by Tsugutomo Enami, 1994.5.30.
;			(j-vector-add (nth 0 l) (nth 2 l))
;		      (nth 2 l) )))
;	      ;; not found or error
;	      []))
;	;; server is not active, so search file instead
;	(j-search-jisyo-file file limit)))))

(defun j-vector-add (u v)
  "Concatenate U and elements of V not in U."
    (let ((w u) (lv (length v)) (i 0))
      (while (< i lv)
	(let ((e (aref v i)))
	  (or (j-vector-mem e u)
	      (setq w (vconcat w (vector e))))
	  (setq i (1+ i))))
      w))

(defun j-vector-mem (e v)
  "Test if the string E is a member of the vector V."
  (let ((l (length v)) (i 0) (cont t))
    (while (and cont (< i l))
      (if (string= e (aref v i)) (setq cont nil) (setq i (1+ i))))
    (not cont)))

(defun j-create-file (file &optional message)
  "Create an empty file named FILE if the file FILE does not exist already."
  (let ((file (expand-file-name file)))
    (or (file-exists-p file)
	(progn
	  (write-region (point-min) (point-min) file nil 0)
	  (if message
	      (progn
		(message message)
		(sit-for 3)))))))

;; patch for old Nemacs (v2)
;; suggested by Masakazu Takahashi, 1992.4.12.
;; this modification is necessary since the variable
;; self-insert-after-hook is unbound in Nemacs v2 

(if skk-nemacs-v2 (setq self-insert-after-hook nil))

;; end of patch for old Nemacs (v2)

(provide 'skk)
