From bf77e060f17055a5efa6941be7a94cb278d3935c Mon Sep 17 00:00:00 2001
From: Ryan Kavanagh <rak@rak.ac>
Date: Thu, 9 Feb 2023 18:07:36 -0500
Subject: Squashed 'dot_emacs.d/local/dictem/' content from commit 078e608

git-subtree-dir: dot_emacs.d/local/dictem
git-subtree-split: 078e60824eb97ac4e9f0a3033b2f592219a81523
---
 AUTHORS              |    2 +
 COPYING              |    3 +
 NEWS                 |  252 +++++++
 README               |  558 ++++++++++++++
 TODO                 |    6 +
 dictem-elisp.el      |  102 +++
 dictem-lingvo-dsl.el |   67 ++
 dictem.el            | 2028 ++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 3018 insertions(+)
 create mode 100644 AUTHORS
 create mode 100644 COPYING
 create mode 100644 NEWS
 create mode 100644 README
 create mode 100644 TODO
 create mode 100644 dictem-elisp.el
 create mode 100644 dictem-lingvo-dsl.el
 create mode 100644 dictem.el

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b4dd7b6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Mon, 20 Oct 2003 20:40:46 +0300
+DictEm was written by Aleksey Cheusov <vle@gmx.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..bacce4d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,3 @@
+GNU GPL 2.0
+http://www.gnu.org/licenses/gpl-2.0.html
+http://opensource.org/licenses/gpl-2.0.php
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..46f946b
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,252 @@
+Version 1.0.4, Sat, 25 Aug 2012 23:23:24 +0300
+
+  - Flag (interactive) was removed from the following functions:
+     dictem-select-strategy, dictem-select-database, dictem-read-query
+     and dictem-run. This fixes Debian bug #564251.
+
+Version 1.0.3, Sun, 22 Jul 2012 13:12:00 +0300
+
+  - fix: "dictem-get-matches" function returns dictionary names
+    without ":" in the end.
+
+  - fix.  insertion of text produced by "dict" client of by user's
+    database is always made IN THE END of dictem buffer. This fixes
+    the problems with hightlighting in match/define mixed results.
+
+  - Fix failure when dictem-use-user-databases-only is t.  The problem
+    was that dictem-last-database variable was initialized
+    incorrectly.
+
+Version 1.0.2, Sun, 22 Mar 2009 17:20:12 +0200
+
+  Another fix in dictem-postprocess-definition-remove-header.
+
+Version 1.0.1, Fri, 20 Mar 2009 12:43:15 +0200
+
+  - fix in dictem-postprocess-definition-remove-header.
+    It wrongly deleted extra line
+
+Version 1.0.0, Sat, 11 Oct 2008 18:59:15 +0300
+
+   - Running dictem-initialize everytime your network/internet is up
+     (if case you have no permanent connection to Internet,
+     e.g. dial-up, adsl etc.) is a bit annoying. To avoid this dictem
+     is (re)initialized (if needed) automatically from
+     dictem-select-strategy and dictem-select-database functions.  As
+     a result, running dictem-initialize in .emacs becomes unnecessary
+
+   - New function (dictem-reinitialize-err) added
+
+   - Minor fix in dictem-initialize-databases-alist function.  Now it
+     returns error data in case of failure, not nil.
+     (just like dictem-initialize-strategies-alist)
+
+Version 0.82, Mon, 28 Jan 2008 22:59:07 +0200
+
+  - FIX for emacs-22 (insert-string is replaced with insert)
+  - Minor fixes in README
+
+Version 0.81, Sat, 22 Jul 2006 15:45:53 +0300
+
+  - dictem-server variable can be equal to nil, in this case
+    'dict' command line tool will be called without -h option, i.e.
+    default _list of servers_ specified in .dictrc (or dict.conf)
+    will be used.
+
+    dict:///dictionary_name (in dictem-user-databases-alist) also means
+    that default server list will be used, see Ex.4 for the sample of use.
+
+  - dictem-server variable now defaults to nil, old value was "dict.org".
+    dictem-strategy-alist and dictem-database-alist also defaults to nil.
+
+Version 0.8, Mon,  Sun, 28 May 2006 00:23:43 +0300
+
+  - removed: ./configure / make / make install
+    See installation section in README if you are in trouble
+
+  - added: dictem-exclude-databases variable to disable some databases
+    from autocompletion menu, see example 15 in README file.
+
+    example for those who uses dict://dict.org:
+
+        (setq dictem-exclude-databases
+         '("tur-" "afr-" "ara-" "cro-" "cze-" "dan-" "hin-" "hun-"
+           "iri-" "ita-" "kha-" "lat-" "nld-" "por-" "sco-" "scr-"
+           "slo-" "swa-" "swe-" "tur-" "rom-" "wel-"
+
+           "-tur" "-afr" "-ara" "-cro" "-cze" "-dan" "-hin" "-hun"
+           "-iri" "-ita" "-kha" "-lat" "-nld" "-por" "-sco" "-scr"
+           "-slo" "-swa" "-swe" "-tur" "-rom" "-wel"))
+
+  - errors messages obtained from 'dict' command are printed
+     in case initialization failure but the constant string.
+
+Version 0.7, Mon,  3 Apr 2006 15:11:57 +0300
+
+  - DICTEM can handle dictionaries defined by user.
+    This allows to use dictem not only for accessing DICT servers,
+    but also for accesing user's databases.
+    See Ex.14 in README file for a simple example.
+
+  - added: dictem-client-prog-args-list variable
+    that keeps a list of additional
+    arguments to the command line 'dict' client.
+    This may be helpful in case you use 'dict' wrappers (having additional
+    options) or new versions of 'dict' program.
+
+  - added: dictem-option-mime variable.
+    If `t' the OPTION MIME command (see RFC-2229 for details)
+    will be sent to the DICT server. i.e. 'dict' program
+    will be run with '-M' option.
+    As a result server's response will be prepanded with MIME header
+    followed by a blank line.
+    Because of bugs in dict -M (dict version < 1.10.3),
+    dict-1.10.3 or later is STRONGLY recommended.
+
+    MIME-ized content can be postprocessed by functions called from
+    dictem-postprocess-xxxx hooks. Because the current version of dictem
+    doesn't contain such kind of functions, this variable should be used
+    by those who program in Emacs.
+    Suggestions and code are welcomed as always.
+    Have a lot of fun ;-)
+
+  - added: dictem-run-show-strategies function,
+    similar to dictem-run-show-databases.
+
+  - more complete dictem-mode's help string (documentation for dictem mode)
+
+  - new examples of dictem usage in Ex.9 section
+
+  - minor fixes in documentation and README
+
+Version 0.0.5, Wed,  8 Jun 2005 19:56:56 +0300
+
+  - new examples in README file: Ex.12-13
+
+  - `dictem-postprocess-collect-hyperlinks' function
+    (when added to `dictem-postprocess-definition-hook',
+     `dictem-postprocess-show-info-hook' or
+     `dictem-postprocess-show-server-hook' hooks) collects hyperlinks
+     in the variable `dictem-hyperlinks-alist'.
+     This variable is used by the function `dictem-hyperlinks-menu'
+     which implements
+     the autocompletion-based menu the same way `Info-menu' does.
+
+    "e" is assigned to call the function `dictem-hyperlinks-menu'.
+    The variable `dictem-hyperlinks-alist' is local to buffer.
+
+  - If `dictem-use-existing-buffer' variable is `t'
+    and dictem-use-content-history is not nil,
+    the entire buffer content and (point)
+    is stored in `dictem-content-history' variable when you click
+    on hyperlink and thus you can easily return to the previous
+    buffer by pressing "l" (`dictem-last' function).
+
+    "l" is assigned to function `dictem-last'.
+    It works just like the button <BACK> in the WEB browsers.
+
+  - added: `dictem-postprocess-definition-remove-header',
+      function for postprocessing DEFINE buffer.
+      It is intended to remove header `XXX definition[s] found'
+      at the beginning of dict's output
+      and can be added to the hook `dictem-postprocess-definition-hook'.
+
+  - fixes:
+    `dictem-kill-all-buffers' has been reimplemented for using
+    `dolist' macros instead of recursion.
+    Recursion-bases implementation causes dictem to fail
+    when lots of buffers exist.
+    Thanks to Juri Linkov for bug reports and lots of suggestions.
+
+  - String that begins hyperlink
+      is stored in the variable `dictem-hyperlink-beginning', defaults to "{"
+    String that ends hyperlink
+      is stored in the variable `dictem-hyperlink-end, defaults to "}"
+    Function that is called when hyperlink "define" is activated
+      is stored in the variable `dictem-hyperlink-define-func',
+      defaults to `dictem-base-define'
+
+    All this stuff may be useful for more complex buffer postprocessing.
+    Hyperlinks are not always enclosed in '{' and '}' braces.
+
+Version 0.0.4, Thu, 24 Feb 2005 19:40:24 +0200
+
+  dictem-default-database (dictem-default-strategy) variables override
+  value of dictem-last-database (dictem-last-strategy) variable,
+  i.e. when dictem-default-xxx is set to non-nil
+  this database (strategy) is always used by default,
+  otherwise the last used database (strategy) is used.
+
+  All examples in README file are know numbered.
+
+  New examples #10 and #11 in README file.
+
+  By default dictem uses the default query as an initial
+  input, this may be very useful.
+  To disable this behaviour set `dictem-empty-initial-input' to `t'.
+  See (describe-variable 'dictem-empty-initial-input)
+  and REAME example #11.
+
+  FIXED: `dictem-last-database' keeps "low-level" database name
+  but the user's virtual one. As a result virtual dictionary
+  could not be the default one (kept in dictem-last-database or
+  dictem-default-database variable ).
+
+Version 0.0.3, Tue, 14 Dec 2004 20:43:34 +0200
+
+  DictEm has been ported to XEmacs
+
+  Virtual dictionaries can access databases from different DICT servers
+
+    (setq dictem-user-databases-alist
+      '(("_translate" . ("dict://mova.org/mueller7"
+                         "dict://dict.org:2628/web1913"))
+        ("_ru-ru" . ("beslov" "dict://mova.org:2628/religion"))
+        ))
+
+    See README file for more information.
+
+  The following commands can be run non-interactively.
+     `dictem-run-show-info', `dictem-run-search' and
+     `dictem-run-define' 
+
+  `dictem-next-link' and `dictem-previous-link' skip hyperlinks on
+    database names.
+
+  Renamed: `dictem-url'       to `dictem-make-url'
+           `link-create-link' to `dictem-create-link'
+
+  DictEm's prompt looks like this: `<string> [<default>]:'
+
+  New default faces
+
+  Lots of README updates.
+
+  A few fixes
+
+Version 0.0.2, Tue, 30 Nov 2004 16:40:00 +0200
+
+  added: new function `dictem-kill-all-buffers' killing all dictem buffers.
+      The key "x" press in dictem buffer use it.
+
+  dictem-postprocess-definition-hyperlinks function:
+     When a substring {foo|bar} is encountered in a definition,
+     `foo' is used for highlighting and `bar' is used for subsearch.
+
+  new functions: `dictem-next-link' and `dictem-previous-link' which
+     set pointer to the next (or previous) hyper link
+  \M-n and \M-p key
+     are assigned to `dictem-next-link' and `dictem-previous-link'
+  When pressing RET (C-m) key on hyper link, subsearch
+     DICT server is sent a DEFINE command
+
+  added: new customizable variable: `dictem-use-existing-buffer'
+      which can be used
+      to use existing dictem buffer instead of creating a new one
+      for subsearches. This variable is local to buffer.
+
+  Documentation update
+
+Version 0.0.1, Thu, 08 Jul 2004 13:58:59 +0300
+
+  first publicly available release
diff --git a/README b/README
new file mode 100644
index 0000000..c1d6e78
--- /dev/null
+++ b/README
@@ -0,0 +1,558 @@
+DictEm is a Dictionary protocol client for GNU Emacs.
+
+It uses a console dict client (http://sf.net/projects/dict) and
+implements all functions of the client part of DICT protocol
+(RFC-2229, www.dict.org), i.e. looking up words and definitions,
+obtaining information about available strategies, provided databases,
+information about DICT server etc.
+
+Unlike dictionary.el
+(http://www.myrkr.in-berlin.de/dictionary/index.html) DictEm widely
+uses autocompletion that is used for selecting dictionary and search
+strategy.  Moreover, DictEm provides several hooks which may be used
+for buffer postprocessing. For example, inbuilt hyperlinking and
+highlighting mechanisms are based on this possibility.  Another example
+is that information obtained from DICT server that is in HTML, ROFF or
+INFO format can be easily viewed by Emacs+DictEm if the user supplies
+appropriate conversion functions.  Of course DictEm can be differently
+configured for different Emacs modes (major, minor or buffer
+oriented), that allows modularized access to all data serviced by DICT
+servers. This makes it ideal tool for translating articles between a
+series of foreign languages, browsing manuals and other tasks
+depending on Emacs mode user currently works with.
+
+Additionally DictEm supports accessing so called virtual dictionaries (a set
+of dictionaries provided by DICT server that user prefers to treat as
+a single one).
+
+Yet another feature DictEm provides is a set of useful functions with
+a help of which user can extend DictEm functionality such as to define
+new search strategies or even provide new functionality such as to use
+another sources of data other than DICT servers.
+
+See below for a set of example configuration and extensions.
+
+Also DictEm uses customization mechanism provided by Emacs that helps
+Emacs users to easily configure DictEm.
+
+COPYING
+============
+
+See the file COPYING
+
+DOWNLOAD
+========
+
+Latest sources can be downloaded from
+http://sourceforge.net/projects/dictem
+or
+http://freshmeat.net/projects/dictem
+
+INSTALLATION
+============
+
+* In order to uncompress dictem tarball run the following.
+
+  tar xfv dictem-x.y.z.tar.gz
+
+  If you read this file, you probably have already done this.
+
+* Change your current directory to dictem.
+
+  cd dictem-x.y.z
+
+* Copy *.el file to the directory you want.
+
+  cp *.el /path/to/emacs/el/files
+
+* Make sure that DICT client named dict
+  (available at http://sf.net/projects/dict)
+  is installed on your system.
+  Console dict client is used by DictEm for accessing the DICT server.
+  dict-1.9.14 or later is strongly recommended.
+  If you'll set dictem-option-mime variable to t (read below),
+  dict-1.10.3 or later MUST be used.
+
+REPORTING BUGS
+==============
+
+    Please send all bug reports and suggestions directly to
+    Aleksey Cheusov <vle@gmx.net>.
+    Reporting bugs at sf.net is also good.
+
+    Also note that there exists dict-beta@dict.org mailing list (low
+    traffic) where you can ask questions about DICT protocol and
+    software.
+
+CONFIGURING
+=============
+
+Customization group
+-------------------
+
+Take note, that DictEm defines customization group "dictem".
+So, it may be easier for you to customize DictEm by running
+M-x customize-group <RET> dictem <RET>
+
+Manual Configuration
+--------------------
+
+Ex.1
+
+The easiest configuration of dictem may look like this
+
+; Add to load-path variable a new directory with files of dictem
+(add-to-list 'load-path "/path/you/installed/dictem/to")
+
+; Loading dictem functions
+(require 'dictem)
+
+; Setting the dictionary server hostname.
+; This part is optional, if dictem-server is nil (the default value)
+; "dict" command line utility will use its ows config file
+; ~/.dictrc or PREFIX/etc/dict.conf.
+; Keeping dictem-server variable unset is recomended because
+; this allows to try _list of_ servers until connection is made,
+; see dict(1) for details.
+;(setq dictem-server "localhost")
+;(setq dictem-server "dict.org")
+
+
+; Setting the dictionary server port.
+; Setting dictem-port is usually not necessary because
+; most DICT servers use the default port 2628.
+;(setq dictem-port   "2628")
+
+; Code necessary to obtain database and strategy list from DICT
+; server. As of version 0.90, dictem runs this function from
+; dictem-select-database and dictem-select-strategy if an
+; initialization was not completed or failed previously, that is
+; running dictem-initialize is optional
+(dictem-initialize)
+
+; Assigning hot keys for accessing DICT server
+
+; SEARCH = MATCH + DEFINE
+; Ask for word, database and search strategy
+; and show definitions found
+(global-set-key "\C-cs" 'dictem-run-search)
+
+; MATCH
+; Ask for word, database and search strategy
+; and show matches found
+(global-set-key "\C-cm" 'dictem-run-match)
+
+; DEFINE
+; Ask for word and database name
+; and show definitions found
+(global-set-key "\C-cd" 'dictem-run-define)
+
+; SHOW SERVER
+; Show information about DICT server
+(global-set-key "\C-c\M-r" 'dictem-run-show-server)
+
+; SHOW INFO
+; Show information about the database
+(global-set-key "\C-c\M-i" 'dictem-run-show-info)
+
+; SHOW DB
+; Show a list of databases provided by DICT server
+(global-set-key "\C-c\M-b" 'dictem-run-show-databases)
+
+-------
+Ex.2
+
+There are a few functions that can make dictem look
+a bit nicer and be more functional. They should
+be added to special hooks like the following.
+
+; For creating hyperlinks on database names
+; and found matches.
+; Click on them with mouse-2
+(add-hook 'dictem-postprocess-match-hook
+	  'dictem-postprocess-match)
+
+; For highlighting the separator between the definitions found.
+; This also creates hyperlink on database names.
+(add-hook 'dictem-postprocess-definition-hook 
+	  'dictem-postprocess-definition-separator)
+
+; For creating hyperlinks in dictem buffer
+; that contains definitions.
+(add-hook 'dictem-postprocess-definition-hook 
+	  'dictem-postprocess-definition-hyperlinks)
+
+; For creating hyperlinks in dictem buffer
+; that contains information about a database.
+(add-hook 'dictem-postprocess-show-info-hook
+	  'dictem-postprocess-definition-hyperlinks)
+
+-------
+Ex.3
+
+If you want to combine some databases in you own "virtual" dictionary,
+create them like this
+
+(setq dictem-user-databases-alist
+   '(("_en-ru"  . ("mueller7" "korolew_en-ru"))
+     ("_en-en"  . ("foldoc" "gcide" "wn"))
+     ("_ru-ru"  . ("beslov" "ushakov" "ozhegov" "brok_and_efr"))
+     ("_unidoc" . ("susv3" "man" "info" "howto" "rfc"))
+     ))
+
+As a result four new special database collections will be created
+and new names will appear when
+dictem-run function will ask you about database name.
+
+-------
+Ex.4
+
+You can even create virtual dictionaries which consist of
+databases from different DICT server.
+The dict url form dict:///religion means 'dict' command line tool
+will be called without -h option, i.e. a list of dictionary servers
+from .dictrc (or dict.conf) will be used.
+
+(setq dictem-user-databases-alist
+   '(("_en-ru" . ("dict://mova.org/mueller7"
+                  "dict://dict.org:2628/web1913"))
+     ("_ru-ru" . ("beslov" "dict:///religion"))
+     ))
+
+another example:
+
+(setq dictem-user-databases-alist
+      `(("en-en" . ("dict://dict.org:2628/english"))
+        ("en-ru" . ("dict:///en-ru"
+                    "dict://dict.org:2628/eng-rus"
+                    ))
+        ))
+
+-------
+Ex.5
+
+If your DICT server provides too many databases and most of which
+are of no interest for you, you can disable them
+and use only those specified in dictem-user-databases-alist variable. 
+
+(setq dictem-use-user-databases-only t)
+
+-------
+Ex.6
+
+Of course, you can assign your own key bindings in dictem buffer
+
+(define-key dictem-mode-map [tab] 'dictem-next-link)
+(define-key dictem-mode-map [(backtab)] 'dictem-previous-link)
+
+-------
+Ex.7
+
+You are not limited to the default DICT server only.
+The following code will allow you to access any server you want.
+You'll be asked for host and port.
+
+; DEFINE
+(global-set-key
+ "\C-c\M-d"
+ '(lambda ()
+    (interactive)
+    (save-dictem
+     (let* ((dictem-server (read-string "server: "
+					dictem-server nil "dict.org"))
+	    (dictem-port (read-string "port: "
+				      (dictem-get-port) nil "2628")))
+       (dictem-initialize)
+       (call-interactively 'dictem-run-define)))))
+
+; MATCH
+(global-set-key
+ "\C-c\M-m"
+ '(lambda ()
+    (interactive)
+    (save-dictem
+     (let* ((dictem-server (read-string "server: "
+					dictem-server nil "dict.org"))
+	    (dictem-port (read-string "port: "
+				      (dictem-get-port) nil "2628")))
+       (dictem-initialize)
+       (call-interactively 'dictem-run-match)))))
+
+; SEARCH = MATCH+DEFINE
+(global-set-key
+ "\C-c\M-s"
+ '(lambda ()
+    (interactive)
+    (save-dictem
+     (let* ((dictem-server (read-string "server: "
+					dictem-server nil "dict.org"))
+	    (dictem-port (read-string "port: "
+				      (dictem-get-port) nil "2628")))
+       (dictem-initialize)
+       (call-interactively 'dictem-run-search)))))
+
+; SHOW INFO
+(global-set-key
+ "\C-c\M-i"
+ '(lambda ()
+    (interactive)
+    (save-dictem
+     (let* ((dictem-server (read-string "server: "
+					dictem-server nil "dict.org"))
+	    (dictem-port (read-string "port: "
+				      (dictem-get-port) nil "2628")))
+       (dictem-initialize)
+       (call-interactively 'dictem-run-show-info)))))
+
+; SHOW SERVER
+(global-set-key
+ "\C-c\M-r"
+ '(lambda ()
+    (interactive)
+    (save-dictem
+     (let* ((dictem-server (read-string "server: "
+					dictem-server nil "dict.org"))
+	    (dictem-port (read-string "port: "
+				      (dictem-get-port) nil "2628")))
+       (dictem-initialize)
+       (call-interactively 'dictem-run-show-server)))))
+
+-------
+Ex.8
+
+Some databases may have specially formatted definitions,
+for example, HTML, MIME, DICF or ROFF formats.
+It is easy to postprocess them.
+
+; All functions from dictem-postprocess-each-definition-hook
+; will be run for each definition which in turn will be narrowed.
+; Current database name is kept in dictem-current-dbname variable.
+; The following code demonstrates how to highlight SUSV3 and ROFF
+; definitions.
+(add-hook 'dictem-postprocess-definition-hook
+	  'dictem-postprocess-each-definition)
+
+; Function for highlighting definition from the database "susv3".
+(defun dictem-highlight-susv3-definition ()
+  (cond ((string= "susv3" dictem-current-dbname)
+	 (goto-char (point-min))
+	 (while (search-forward-regexp
+		 "^ *[QWERTYUIOPASDFGHJKLZXCVBNM ]+$" nil t)
+	   (put-text-property
+	    (match-beginning 0) (match-end 0) 'face 'bold)
+	   ))))
+
+; Function to show roff-formatted text from the database "man".
+(require 'woman)
+(defun dictem-highlight-man-definition ()
+  (cond ((string= "man" dictem-current-dbname)
+	 (goto-char (point-min))
+	 (while (search-forward-regexp "^  " nil t)
+	   (replace-match ""))
+	 (goto-char (point-min))
+	 (forward-line 2)
+	 (woman-decode-region (point) (point-max))
+	 )))
+
+(add-hook 'dictem-postprocess-each-definition-hook 
+	  'dictem-highlight-susv3-definition)
+(add-hook 'dictem-postprocess-each-definition-hook 
+	  'dictem-highlight-man-definition)
+
+-------
+Ex.9
+
+; The dictem's top level function is 'dictem-run'.
+; By using it more advanced ELISP programmers
+; can create their own search scenaria. Look at this code.
+
+(dictem-run
+  'dictem-base-search
+  "gcide" "apple" "lev")
+
+(dictem-run
+  'dictem-base-match
+  "dict://mova.org/mueller7" "apple" "exact")
+
+(dictem-run
+  'dictem-base-define
+  '("dict://mova.org/mueller7" "dict://dict.org/gcide")
+   "apple" "exact")
+
+(dictem-run 'dictem-base-show-info "dict://dict.org/gcide")
+
+(let ((dictem-server "localhost"))
+  (dictem-run
+   '(lambda (a b c)
+      (dictem-base-show-strategies nil nil nil)
+      (dictem-base-show-databases nil nil nil)
+      (dictem-base-show-server nil nil nil)
+      )))
+
+(dictem-run
+  '(lambda (a b c)
+     (dictem-base-define
+      '("man" "susv3")
+      (dictem-read-query (thing-at-point 'word))
+      nil ))
+  nil nil)
+
+(let ((query (dictem-read-query (thing-at-point 'word))))
+  (dictem-run
+   `((lambda (a b c)
+       (dictem-base-match
+	'("gcide" "wn")
+	,query "exact"))
+     (lambda (a b c)
+       (dictem-base-search
+	'("mueller7" "korolew_en-ru")
+	,query "word")))))
+
+-------
+Ex.10
+
+By default dictem remembers the database name and strategy that
+was used last time.
+The  dictem-select-database and dictem-select-strategy functions
+will use these values as a default in the minibuffer.
+If you dislike this behaviour, set variables
+dictem-default-database and/or dictem-default-strategy.
+
+(add-hook 'c-mode-common-hook
+	  '(lambda ()
+	     (interactive)
+	     (make-local-variable 'dictem-default-database)
+	     (setq dictem-default-database "man")
+	     ))
+
+The example above sets default database to "man"
+in C buffers.
+
+-------
+Ex.11
+
+As of dictem-0.0.4 dictem-empty-initial-input customizable variable
+tells dictem-read-query whether to leave initial input empty or not.
+It is `nil' by default.
+For emulating behaviour of older releases, set it to `t'.
+
+(setq dictem-empty-initial-input t)
+
+-------
+Ex. 12
+
+By default dictem-postprocess-definition-hyperlinks function
+assumes that hyperlinks have the following form: {foo} or {foo|bar}.
+Sometimes "{" and "}" characters are general characters
+in definitions. The following code changes "{" and "}" for
+"{link-beg " and " link-end" respectively
+inside definitions obtained from the databases "^infopage-..."
+
+; new function is used for creating hyperlinks
+; which works differently depending on database name
+(defun my-dictem-postprocess-definition-hyperlinks ()
+  "Creating hyperlinks according to database name"
+  (interactive)
+  (cond (
+	((string-match "^infopage-" dictem-current-dbname)
+	 (let ((dictem-hyperlink-beginning "{link-beg ")
+	       (dictem-hyperlink-end       " link-end}")
+	       )
+	   (dictem-postprocess-definition-hyperlinks)))
+	(t (dictem-postprocess-definition-hyperlinks)))))
+
+; definitions from each database are processed separately
+(add-hook 'dictem-postprocess-definition-hook
+	  'dictem-postprocess-each-definition)
+(add-hook 'dictem-postprocess-each-definition-hook
+	  'my-dictem-postprocess-definition-hyperlinks)
+
+-------
+Ex. 13
+
+You may want to remove "XXX definition[s] found" header
+from the DEFINE buffers.
+It may be done with a help of
+dictem-postprocess-definition-remove-header function.
+
+(add-hook 'dictem-postprocess-definition-hook
+	  'dictem-postprocess-definition-remove-header)
+
+-------
+Ex. 14
+
+As of version 0.7 dictem can handle dictionaries defined by user.
+This allows to use dictem not only for accessing DICT servers,
+but also for accesing users' databases.
+
+; DEFINE function for the database "mysuperdb"
+(defun dictem-mysuperdb-DEFINE (query)
+  (cond
+   ((string= query "apple")  '("Apples grow on the trees"
+			       "Apple may be green, yellow or red"))
+   ((string= query "potato") '("Potato is a vegetable"
+			       "Potato is a traditional Belarusian food"))
+   (t (dictem-make-error
+       20 (format "No definitions for %s" query)))
+  ))
+
+; MATCH function for the database "mysuperdb"
+(defun dictem-mysuperdb-MATCH (query strategy)
+  ; the name of strategy is ignored
+  (let ((apple  (string-match query "apple"))
+	(potato (string-match query "potato")))
+    (cond
+     ((and (string= strategy "exact") (string= query "apple"))
+      '("apple"))
+     ((and (string= strategy "exact") (string= query "potato"))
+      '("potato"))
+     ((and apple potato)
+      '("apple" "potato"))
+     (apple
+      '("apple"))
+     (potato
+      '("potato"))
+     (t (dictem-make-error
+	 20 (format "No matches for %s/%s" query strategy)))
+     )))
+
+; Initializing a list of user-defined databases
+(setq dictem-user-databases-alist
+      `(("_en-en"  . ("foldoc" "gcide" "wn"))
+	("_ru-ru"  . ("beslov" "ushakov" "ozhegov" "brok_and_efr"))
+	,(dictem-make-userdb
+          ; the name of the database
+	  "mysuperdb"
+          ; short description
+          "My super database"
+          ; MATCH function
+	  (symbol-function 'dictem-mysuperdb-MATCH)
+          ; DEFINE function
+	  (symbol-function 'dictem-mysuperdb-DEFINE))
+	))
+
+-------
+Ex. 15
+
+Last years many dictionary servers provide too many bilingual dictionaries,
+most of which may be not very interesting for you.
+DictEm allows to exclude such dictionaries from an autocompletion menu
+by setting a list of regular expressions in dictem-exclude-databases
+variable.
+If, for example, you don't speak french and german and use
+dict://dict.org server, your config may look like this
+
+(setq dictem-server "dict.org")
+(setq dictem-exclude-databases '("ger-" "-ger" "fra-" "-fra"))
+(dictem-initialize)
+
+Note that, (dictem-initialize) is placed after initializing
+dictem-exclude-databases variable.
+
+-------
+If you have read to this point and all the examples above seem easy,
+you are probably a ELISP Guru.
+So, I have nothing more to tell you ;-)
+Feel free to inspect the code, and I hope you'll find DictEm useful.
+
+Dict'em All! ;-)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..38b7ccf
--- /dev/null
+++ b/TODO
@@ -0,0 +1,6 @@
+- "er" dictionary + geek
+- antonym for "l". "n" and "p"?
+- keep p/n history in buffers with numbers.
+- does dictem-use-existing-buffer work properly?
+
+Do you have ideas, want new features, see bugs? Let me know ;-)
diff --git a/dictem-elisp.el b/dictem-elisp.el
new file mode 100644
index 0000000..7ee6cbc
--- /dev/null
+++ b/dictem-elisp.el
@@ -0,0 +1,102 @@
+(require 'dictem)
+
+(defun dictem-elisp-variable-documentation (func)
+  (let* ((help-buffer "*Help*")
+	 (temp-buffer-show-function (lambda (b) ()))
+	 )
+    (if (boundp func)
+	(save-excursion
+	  (describe-variable func)
+	  (set-buffer help-buffer)
+	  (prog1
+	      (buffer-substring (point-min) (point-max))
+	    (kill-this-buffer help-buffer))
+	  )
+      nil)))
+
+(defun dictem-elisp-function-documentation (func)
+  (let* ((help-buffer "*Help*")
+	 (temp-buffer-show-function (lambda (b) ()))
+	 )
+    (if (functionp func)
+	(save-excursion
+	  (describe-function func)
+	  (set-buffer help-buffer)
+	  (prog1
+	      (buffer-substring (point-min) (point-max))
+	    (kill-this-buffer))
+	  )
+      nil)))
+
+(defun dictem-elisp-DEFINE (query)
+  (let ((sym (intern-soft query))
+	(doc nil))
+;         (ret (if (and sym (functionp sym))
+;		  (documentation sym)
+;		nil)))
+    (cond ((null sym)
+	   (dictem-make-error
+	    20 (format "SYmbol '%s is not defined" query)))
+	  ((functionp sym)
+	   (setq doc (dictem-elisp-function-documentation sym))
+	   (if doc doc
+	     (dictem-make-error
+	      20 (format "'%s is not documented as a function" query))))
+	  (t
+	   (setq doc (dictem-elisp-function-documentation sym))
+	   (if doc doc
+	     (dictem-make-error
+	      20 (format "'%s is documented as neither function not variable" query)))
+	   ))))
+;	   (documentation sym))
+;          (t (dictem-make-error
+;              20 (format "There is no function '%s" query))))))
+
+(defun dictem-string-match-prefix (pattern string)
+  (eq 0 (string-match (regexp-quote pattern) string)))
+(defun dictem-string-match-substring (pattern string)
+  (string-match (regexp-quote pattern) string))
+(defun dictem-string-match-suffix (pattern string)
+  (string-match (regexp-quote pattern) string)
+  (= (length string) (match-end 0)))
+(defun dictem-string-match-word (pattern string)
+  (string-match (concat "\\b\\(" (regexp-quote pattern) "\\)\\b")
+		string))
+
+(defun dictem-elisp-MATCH-UNI (query fun)
+  (let ((i    0)
+	(l    nil)
+;	(re   (regexp-quote query))
+	(item nil))
+    (while (< i (length obarray))
+      (progn
+	(setq item (symbol-name (elt obarray i)))
+	(if (funcall fun (regexp-quote query) item)
+	    (setq l (cons item l)))
+	(setq i (+ i 1))))
+    l))
+
+(defun dictem-elisp-MATCH (query strategy)
+  (let ((l (dictem-elisp-MATCH-UNI
+	    query
+	    (cond ((string= strategy "exact")
+		   (symbol-function 'string=))
+		  ((string= strategy "word")
+		   (symbol-function 'dictem-string-match-word))
+		  ((string= strategy "prefix")
+		   (symbol-function 'dictem-string-match-prefix))
+		  ((string= strategy "suffix")
+		   (symbol-function 'dictem-string-match-suffix))
+		  ((string= strategy "substring")
+		   (symbol-function 'dictem-string-match-substring))))))
+    (if l l
+      (dictem-make-error
+       20 (format "No matches for %s/%s" query strategy)))))
+
+;(dictem-elisp-MATCH "at"     "word")
+;(dictem-elisp-MATCH "file"   "suffix")
+;(dictem-elisp-MATCH "dictem" "prefix")
+;(dictem-elisp-MATCH "s-s"    "substring")
+;(dictem-elisp-MATCH "pike"   "substring")
+
+(provide 'dictem-elisp)
diff --git a/dictem-lingvo-dsl.el b/dictem-lingvo-dsl.el
new file mode 100644
index 0000000..35f92d5
--- /dev/null
+++ b/dictem-lingvo-dsl.el
@@ -0,0 +1,67 @@
+;; -*- coding: utf-8; -*- 
+
+(require 'dictem)
+
+(defun dictem-lingvo-dsl-highlight ()
+  ; trn/ex/com/*
+  (goto-char (point-min))
+  (while (search-forward-regexp "\\[/?trn\\]\\|\\[/?p\\]\\|\\[/?c\\]\\|\\[/?com\\]\\|\\[/?[*]\\]\\|\\[/?b\\]\\|\\[/?i\\]\\|\\[/?m[0-9]?\\]\\|\\[/?ex\\]" nil t)
+    (replace-match "" t t))
+
+  ; [ex] [/ex]
+;  (goto-char (point-min))
+;  (while (search-forward-regexp "\\[ex\\]\\([][]*\\)\\[/ex\\]" nil t)
+;    (add-text-properties (match-beginning 0) (match-end 0)
+;			 '(face dictem-lingvo-dsl-example-face))
+;    (let* ((beg (match-beginning 1))
+;	   (end (match-end 1))
+;	   (repl (buffer-substring beg end)))
+;      (replace-match repl 1 1)))
+
+  ; <<>>
+  (goto-char (point-min))
+  (while (search-forward-regexp "\\(<<\\|\\[ref\\]\\)\\([^\n]*\\)\\(>>\\|\\[/ref\\]\\)" nil t)
+    (let* ((beg (match-beginning 2))
+	   (end (match-end 2))
+	   (repl (buffer-substring beg end)))
+      (replace-match (concat "{" repl "}") t t)))
+
+  ; hyperlinks
+  (dictem-postprocess-definition-hyperlinks)
+  )
+
+(progn
+  (set-buffer "*dsl-buffer*")
+  (dictem-lingvo-dsl-highlight))
+
+(defface dictem-lingvo-dsl-italic-face
+  '((((background light)) (:italic true))
+    (((background dark))  (:italic true)))
+  "Face for italic"
+  )
+
+(defface dictem-lingvo-dsl-color-face
+  '((((background light)) (:italic true))
+    (((background dark))  (:italic true)))
+  "Face for color"
+  )
+
+(defface dictem-lingvo-dsl-example-face
+  '((((background light)) (:italic true))
+    (((background dark))  (:italic true)))
+  "Face for color"
+  )
+
+(defface dictem-lingvo-dsl-bold-face
+  '((((background light)) (:bold true))
+    (((background dark))  (:bold true)))
+  "Face for bold"
+  )
+
+(defface dictem-lingvo-dsl-trn-face
+  '((((background light)) (:bold true :italic true))
+    (((background dark))  (:bold true :italic true)))
+  "Face for trn"
+  )
+
+(provide 'dictem-lingvo-dsl)
diff --git a/dictem.el b/dictem.el
new file mode 100644
index 0000000..8602ca3
--- /dev/null
+++ b/dictem.el
@@ -0,0 +1,2028 @@
+;;; dictem.el --- DICT protocol client (rfc-2229) for [X]Emacs
+
+;; This code was initially based on
+;; dictionary.el written by Torsten Hilbrich <Torsten.Hilbrich@gmx.net>
+;; but now probably doesn't contain original code.
+;; Most of the code has been written
+;; from scratch by Aleksey Cheusov <vle@gmx.net>, 2004-2008.
+;;
+;; DictEm 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 version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; DictEm 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 this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA
+
+;;; Commentary:
+
+;; DICT protocol client (rfc-2229) for [X]Emacs
+
+;; NOTE! Documentation is in README file.
+;;
+;; Latest information about dictem project and sources
+;; are available at
+;;
+;; http://freshmeat.net/projects/dictem
+;; http://sourceforge.net/projects/dictem
+;; http://mova.org/~cheusov/pub/dictem
+
+;;; Code:
+
+(require 'cl)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;         Custom Things        ;;;;;
+
+(defgroup dictem nil
+  "Client for accessing the DICT server."
+  :tag "DictEm"
+  :group 'help
+  :group 'hypermedia)
+
+(defgroup dictem-faces nil
+  "Face options for dictem DICT client."
+  :tag "DictEm faces"
+  :group 'dictem
+  :group 'faces)
+
+(defcustom dictem-server nil
+  "The DICT server"
+  :group 'dictem
+  :type '(restricted-sexp :match-alternatives (stringp 'nil)))
+
+(defcustom dictem-port 2628
+  "The port of the DICT server"
+  :group 'dictem
+  :type 'number)
+
+(defcustom dictem-client-prog "dict"
+  "The command line DICT client.
+dictem accesses DICT server through this executable.
+dict-1.9.14 or later (or compatible) is strongly recomented."
+  :group 'dictem
+  :type 'string)
+
+(defcustom dictem-client-prog-args-list nil
+  "A list of additional arguments (strings) passed to dict client.
+For example '(\"--some-option\")."
+  :group 'dictem
+  :type  'list)
+
+(defcustom dictem-option-mime nil
+  "If `t' the OPTION MIME command (see RFC-2229 for details)
+will be sent to the DICT server. i.e. \"dict\" program
+will be run with \"-M\" option.
+As a result server's response will be prepanded with MIME header
+followed by a blank line.
+Because of bugs in dict -M (version < 1.10.3) utility,
+dict-1.10.3 or later is strongly recommended
+"
+  :group 'dictem
+  :type  'boolean)
+
+(defcustom dictem-default-strategy nil
+  "The default search strategy."
+  :group 'dictem
+  :type  'string)
+
+(defcustom dictem-default-database nil
+  "The default database name."
+  :group 'dictem
+  :type  'string)
+
+(defcustom dictem-user-databases-alist
+  nil
+  "ALIST of user's \"virtual\"databases.
+Valid value looks like this:
+'((\"en-ru\" .  (\"mueller7\" \"korolew_en-ru\"))
+  ((\"en-en\" . (\"foldoc\" \"gcide\" \"wn\")))
+  ((\"gazetteer\" . \"gaz\")))
+"
+  :group 'dictem
+  :type '(alist :key-type string))
+
+(defcustom dictem-exclude-databases
+  nil
+  "ALIST of regexps for databases
+that will not appear in autocompletion list.
+"
+  :group 'dictem
+  :type '(alist :key-type string))
+
+(defcustom dictem-use-user-databases-only
+  nil
+  "If `t', only user's dictionaries from dictem-user-databases-alist
+will be used by dictem-select-database"
+  :group 'dictem
+  :type 'boolean)
+
+(defcustom dictem-mode-hook
+  nil
+  "Hook run in dictem mode buffers."
+  :group 'dictem
+  :type 'hook)
+
+(defcustom dictem-use-existing-buffer
+  nil
+  "If `t' the `dictem-run' function will not create new *dictem* buffer.
+Instead, existing buffer will be erased and used to show results.
+"
+  :group 'dictem
+  :type 'boolean)
+
+(defcustom dictem-empty-initial-input
+  nil
+  "If `t' the `dictem-read-query' leave initial input empty"
+  :group 'dictem
+  :type 'boolean)
+
+(defcustom dictem-use-content-history t
+  "If not nil and dictem-use-existing-buffer is also not nil,
+buffer content and (point) is saved in dictem-content-history variable
+when DEFINE hyperlinks are accessed.
+It is restored by dictem-last function.
+On slow machines it may better to set this variable to nil"
+  :group 'dictem)
+
+;;;;;            Faces             ;;;;;
+
+(defface dictem-reference-definition-face
+  '((((background light)) (:foreground "blue"))
+    (((background dark))  (:foreground "cyan")))
+
+  "The face that is used for displaying a reference to
+a phrase in a DEFINE search."
+  :group 'dictem-faces)
+
+(defface dictem-reference-m1-face
+  '((((background light)) (:foreground "darkgreen"))
+    (((background dark))  (:foreground "lightblue")))
+
+  "The face that is used for displaying a reference to
+a phrase in a MATCH search."
+  :group 'dictem-faces)
+
+(defface dictem-reference-m2-face
+  '((((background light)) (:foreground "blue"))
+    (((background dark))  (:bold true :foreground "gray")))
+
+  "The face that is used for displaying a reference to
+a single word in a MATCH search."
+  :group 'dictem-faces)
+
+(defface dictem-reference-dbname-face
+  '((((background light)) (:foreground "darkgreen"))
+    (((background dark))  (:bold t :foreground "white")))
+
+  "The face that is used for displaying a reference to database"
+  :group 'dictem-faces)
+
+(defface dictem-database-description-face
+  '((((background light)) (:bold t :foreground "darkblue"))
+    (((background dark))  (:bold t :foreground "white")))
+
+  "The face that is used for displaying a database description"
+  :group 'dictem-faces)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;           Variables          ;;;;;
+
+(defconst dictem-version "1.0.4"
+  "DictEm version information.")
+
+(defvar dictem-strategy-alist
+  nil
+  "ALIST of search strategies")
+
+(defvar dictem-database-alist
+  nil
+  "ALIST of databases")
+
+(defvar dictem-strategy-history
+  nil
+  "List of strategies entered from minibuffer")
+
+(defvar dictem-database-history
+  nil
+  "List of database names entered from minibuffer")
+
+(defvar dictem-query-history
+  nil
+  "List of queries entered from minibuffer")
+
+(defvar dictem-last-database
+  "*"
+  "Last used database name")
+
+(defvar dictem-last-strategy
+  "."
+  "Last used strategy name")
+
+(defvar dictem-mode-map
+  nil
+  "Keymap for dictem mode")
+
+(defvar dictem-temp-buffer-name
+  "*dict-temp*"
+  "Temporary dictem buffer name")
+
+(defvar dictem-current-dbname
+  nil
+  "This variable keeps a database name of the definition
+currently processed
+by functions run from dictem-postprocess-each-definition-hook.")
+
+(defvar dictem-error-messages
+  nil
+  "A list of error messages collected by dictem-run")
+
+(defvar dictem-hyperlinks-alist
+  nil
+  "ALIST of hyperlinks collected from dictem buffer by
+the function dictem-postprocess-collect-hyperlinks
+(add this function to the hook dictem-postprocess-definition-hook).
+This variable is local to buffer")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-prepand-special-strats (l)
+  (cons '(".") l))
+
+(defun dictem-prepand-special-dbs (l)
+  (cons '("*") (cons '("!") l)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;        Functions         ;;;;;;
+
+(defmacro save-dictem (&rest funs)
+  `(let ((dictem-port                    2628)
+	 (dictem-server                  nil)
+	 (dictem-database-alist          nil)
+	 (dictem-strategy-alist          nil)
+	 (dictem-use-user-databases-only nil)
+	 (dictem-user-databases-alist    nil)
+	 )
+     (progn ,@funs)
+     ))
+
+(defun dictem-client-text ()
+  "Returns a portion of text sent to the server for identifying a client"
+  (concat "dictem " dictem-version ", DICT client for emacs"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;     Functions related to userdb    ;;
+
+(defun dictem-make-userdb (name short-name match define)
+  "Make user database object"
+  (list name 'dictem-userdb
+	short-name match define))
+
+(defun dictem-userdb-p (obj)
+  "Returns t if obj is the dictem error object"
+  (and obj (listp obj) (cdr obj) (listp (cdr obj))
+       (eq (cadr obj) 'dictem-userdb)))
+
+(defun dictem-userdb-member (obj name)
+  "Extract member from userdb object by its name"
+  (cond ((dictem-userdb-p obj)
+	 (nth (cdr (assoc name
+			  '(("name"   . 0) ("short-name" . 2)
+			    ("match"  . 3) ("define"     . 4))))
+	      obj))
+	(t (error "Invalid type of argument"))))
+
+(defun dictem-userdb-DEFINE (buffer db query host port)
+  (let* ((fun   (dictem-userdb-member db "define"))
+	 (name  (dictem-userdb-member db "name"))
+	 (sname (dictem-userdb-member db "short-name"))
+	 (ret (save-excursion (funcall fun query)))
+	 (buf (dictem-get-buffer buffer)))
+    (save-excursion
+      (set-buffer buf)
+      (cond ((dictem-error-p ret)
+;	     (insert "From " sname " [" name "]:\n\n"
+;		     (dictem-error-message ret) "\n\n")
+;	     (insert (dictem-error-message ret) "\n")
+	     (insert (dictem-error-message ret) "\n")
+	     (dictem-error-status ret))
+	    ((null ret)
+	     (insert "No matches found" "\n")
+	     20)
+	    ((listp ret)
+	     (dolist (definition ret)
+	       (insert "From " sname " [" name "]:\n\n"
+		       (dictem-indent-string definition) "\n\n"))
+	     0)
+	    ((stringp ret)
+	     (insert "From " sname " [" name "]:\n\n"
+		     (dictem-indent-string ret) "\n\n")
+	     0)
+	    (t
+	     (error "Invalid type of returned value1"))))))
+
+(defun dictem-userdb-MATCH (buffer db query strat host port)
+  (let* ((fun   (dictem-userdb-member db "match"))
+	 (name  (dictem-userdb-member db "name"))
+	 (ret (save-excursion (funcall fun query strat)))
+	 (buf (dictem-get-buffer buffer)))
+    (save-excursion
+      (set-buffer buf)
+      (cond ((dictem-error-p ret)
+	     (insert (dictem-error-message ret) "\n")
+	     (dictem-error-status ret))
+	    ((listp ret)
+	     (insert (concat name ":\n"))
+	     (dolist (match ret); (insert (car db) ":\n" ))
+	       (progn
+		 (insert "  " match "\n"))
+		 )
+	     0)
+	    (t
+	     (error "Invalid type of returned value2"))))))
+
+(defun dictem-userdb-SEARCH (buffer db query strat host port)
+  (let* ((funm  (dictem-userdb-member db "match"))
+	 (name  (dictem-userdb-member db "name"))
+	 (sname (dictem-userdb-member db "short-name"))
+	 (sname nil)
+	 (ret   (funcall funm query strat))
+	 (buf   (dictem-get-buffer buffer)))
+    (save-excursion
+      (set-buffer buf)
+      (cond ((dictem-error-p ret)
+	     (insert (dictem-error-message ret) "\n")
+	     (dictem-error-status ret))
+	    ((listp ret)
+	     (dolist (match ret)
+	       (dictem-userdb-DEFINE buffer db
+				     match host port))
+	     0)
+	    (t
+	     (error "Something strange happened"))
+	    ))))
+
+(defun dictem-userdb-SHOW-INFO (buffer db host port)
+  (let ((sname (dictem-userdb-member db "short-name"))
+	(buf   (dictem-get-buffer buffer)))
+    (save-excursion
+      (set-buffer buf)
+      (cond ((dictem-error-p sname)
+	     (insert (dictem-error-message sname) "\n")
+	     (dictem-error-status sname))
+	    ((stringp sname)
+	     (insert sname)
+	     0)
+	    (t
+	     (error "Something strange happened"))
+	    ))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions related to error object  ;;
+
+(defun dictem-make-error (error_status &optional buffer-or-string)
+  "Creates dictem error object"
+  (cond
+   ((stringp buffer-or-string)
+    (list 'dictem-error error_status buffer-or-string))
+   ((bufferp buffer-or-string)
+    (dictem-make-error
+     error_status
+     (save-excursion
+       (set-buffer buffer-or-string)
+       (goto-char (point-min))
+       (dictem-get-line)
+       )))
+   ((eq nil buffer-or-string)
+    (list 'dictem-error error_status buffer-or-string))
+   (t
+    (error "Invalid type of argument"))
+   ))
+
+(defun dictem-error-p (OBJECT)
+  "Returns t if OBJECT is the dictem error object"
+  (and
+   (not (null OBJECT))
+   (listp OBJECT)
+   (eq (car OBJECT) 'dictem-error)
+   ))
+
+(defun dictem-error-message (err)
+  "Extract error message from dictem error object"
+  (cond
+   ((dictem-error-p err)
+    (nth 2 err))
+   (t
+    (error "Invalid type of argument"))
+   ))
+
+(defun dictem-error-status (err)
+  "Extract error status from dictem error object"
+  (cond
+   ((dictem-error-p err)
+    (nth 1 err))
+   (t
+    (error "Invalid type of argument"))
+   ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-collect-matches ()
+  ; nreverse, setcar and nconc are used to reduce a number of cons
+  (goto-char (point-min))
+  (let ((dictem-temp nil))
+    (loop
+     (let ((line (dictem-get-line)))
+       (if (string-match "^[^ ]+:" line)
+	   (progn
+	     (if (consp dictem-temp)
+		 (setcar (cdar dictem-temp)
+			 (nreverse (cadar dictem-temp))))
+	     (setq
+	      dictem-temp
+	      (cons
+	       (list
+		(substring line (match-beginning 0) (- (match-end 0) 1))
+		(nreverse 
+		 (dictem-tokenize (substring line (match-end 0)))))
+	       dictem-temp)))
+	 (if (consp dictem-temp)
+	     (setcar (cdar dictem-temp)
+		     (nconc (nreverse (dictem-tokenize line))
+			    (cadar dictem-temp))
+		     ))
+	 ))
+     (if (or (> (forward-line 1) 0)
+	     (> (current-column) 0))
+	 (return (nreverse dictem-temp)))
+     )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-get-buffer (buf)
+  (cond
+   ((bufferp buf) buf)
+   (buf (current-buffer))
+   (t (get-buffer-create dictem-temp-buffer-name))
+   ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;             call-process functions
+
+(defun dictem-local-dict-basic-option (host port option-mime)
+  (let ((server-host (if host host (dictem-get-server))))
+    (append
+     (list "-P" "-")
+     (if server-host
+	 (list "-h" server-host "-p" (dictem-get-port port)))
+     (if option-mime '("-M"))
+     dictem-client-prog-args-list
+     )))
+
+(defun dictem-call-process (buffer host port args)
+  (let (coding-system
+	coding-system-for-read
+	coding-system-for-write)
+    (if (and (functionp 'coding-system-list)
+	     (member 'utf-8 (coding-system-list)))
+	(setq coding-system 'utf-8))
+    (setq coding-system-for-read coding-system)
+    (setq coding-system-for-write coding-system)
+    (apply 'call-process
+	   `(,dictem-client-prog
+	     nil
+	     ,(dictem-get-buffer buffer)
+	     nil
+	     ,@(dictem-local-dict-basic-option host port nil)
+	     ,@args
+	     ))))
+
+(defun dictem-call-process-SHOW-SERVER (buffer host port)
+  (dictem-call-process buffer host port '("-I")))
+
+(defun dictem-call-process-SHOW-INFO (buffer db host port)
+  (dictem-call-process buffer host port (list "-i" db)))
+
+(defun dictem-call-process-SHOW-STRAT (buffer host port)
+  (dictem-call-process buffer host port '("-S")))
+
+(defun dictem-call-process-SHOW-DB (buffer host port)
+  (dictem-call-process buffer host port '("-D")))
+
+(defun dictem-call-process-MATCH (buffer db query strat host port)
+  (dictem-call-process
+   buffer host port
+   (list "-m"
+	 "-d" (if db db "*")
+	 "-s" (if strat strat ".")
+	 query)))
+
+(defun dictem-call-process-DEFINE (buffer db query host port)
+  (dictem-call-process
+   buffer host port
+   (list "-d" (if db db "*") query)))
+
+(defun dictem-call-process-SEARCH (buffer db query strat host port)
+  (dictem-call-process
+   buffer host port
+   (list "-d" (if db db "*")
+	 "-s" (if strat strat ".")
+	 query)))
+
+;;;;;        GET Functions         ;;;;;
+
+(defun dictem-get-matches (query &optional database strategy server port)
+  "Returns ALIST of matches"
+  (let ((exit_status
+	 (dictem-call-process-MATCH nil database query strategy server port)
+	 ))
+    (cond
+     ((= exit_status 20) ;20 means "no matches found", See dict(1)
+      (kill-buffer dictem-temp-buffer-name)
+      nil)
+     ((= exit_status 0)
+      (progn
+	(save-excursion
+	  (set-buffer dictem-temp-buffer-name)
+	  (let ((matches (dictem-collect-matches)))
+	    (kill-buffer dictem-temp-buffer-name)
+	    matches))))
+     (t
+      (let
+	  ((err (dictem-make-error exit_status
+				   (get-buffer dictem-temp-buffer-name))))
+	(kill-buffer dictem-temp-buffer-name)
+	err))
+     )))
+
+(defun dictem-get-strategies (&optional server port)
+  "Obtains strategy ALIST from a DICT server
+and returns alist containing strategies and their descriptions"
+  (let ((exit_status
+	 (dictem-call-process-SHOW-STRAT nil server port)
+	 ))
+    (cond
+     ((= exit_status 0)
+      (save-excursion
+	(set-buffer dictem-temp-buffer-name)
+	(goto-char (point-min))
+	(let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$")
+	      (l nil))
+	  (while (search-forward-regexp regexp nil t)
+	    (setq l (cons
+		     (list
+		      (buffer-substring-no-properties
+		       (match-beginning 1) (match-end 1))
+		      (buffer-substring-no-properties
+		       (match-beginning 2) (match-end 2)))
+		     l)))
+	  (kill-buffer dictem-temp-buffer-name)
+	  l)))
+     (t
+      (let
+	  ((err (dictem-make-error exit_status
+				   (get-buffer dictem-temp-buffer-name))))
+	(kill-buffer dictem-temp-buffer-name)
+	err))
+    )))
+
+(defun dictem-get-databases (&optional server port)
+  "Obtains database ALIST from a DICT server
+and returns alist containing database names and descriptions"
+  (let ((exit_status
+	 (dictem-call-process-SHOW-DB nil server port)
+	 ))
+    (cond
+     ((= exit_status 0)
+      (save-excursion
+	(set-buffer dictem-temp-buffer-name)
+	(goto-char (point-min))
+	(let ((regexp "^ \\([^ ]+\\) +\\(.*\\)$")
+	      (l nil))
+	  (while (search-forward-regexp regexp nil t)
+	    (let ((dbname (buffer-substring-no-properties
+			   (match-beginning 1) (match-end 1)))
+		  (dbdescr (buffer-substring-no-properties
+			    (match-beginning 2) (match-end 2))))
+	      (if (not (string= "--exit--" dbname))
+		  (setq l (cons (list dbname dbdescr) l)))))
+	  (kill-buffer dictem-temp-buffer-name)
+	  l)))
+     (t
+      (let
+	  ((err (dictem-make-error exit_status
+				   (get-buffer dictem-temp-buffer-name))))
+	(kill-buffer dictem-temp-buffer-name)
+	err))
+     )))
+
+(defun dictem-get-default-strategy (&optional def-strat)
+  "Gets the default search strategy"
+  (if def-strat
+      def-strat
+    (if dictem-default-strategy
+	dictem-default-strategy
+      (if dictem-last-strategy
+	  dictem-last-strategy
+	"."))))
+
+(defun dictem-extract-dbname (database)
+  (cond
+   ((consp database) (dictem-extract-dbname (car database)))
+   ((stringp database) database)
+   (t (error "The database should be either stringp or consp"))
+   ))
+
+(defun dictem-get-default-database (&optional def-db)
+  "Returns the default database"
+
+  (if def-db
+      (dictem-extract-dbname def-db)
+    (if dictem-default-database
+	(dictem-extract-dbname dictem-default-database)
+      (if dictem-last-database
+	  (dictem-extract-dbname dictem-last-database)
+	"*"))))
+
+;;;;;      Low Level Functions     ;;;;;
+
+(defun dictem-db-should-be-excluded (dbname)
+  "Returns t if a dbname should is not interesting for user.
+See dictem-exclude-databases variable"
+  (let ((ret nil))
+    (dolist (re dictem-exclude-databases)
+      (if (string-match re dbname)
+	  (setq ret t)))
+    ret))
+
+(defun dictem-delete-alist-predicate (l pred)
+  "makes a copy of l with no items for which (pred item) is true"
+  (let ((ret nil))
+    (dolist (item l)
+      (if (not (funcall pred (car item)))
+	  (setq ret (cons item ret))))
+    ret))
+
+(defun dictem-get-line ()
+  "Replacement for (thing-at-point 'line)"
+  (save-excursion
+    (buffer-substring-no-properties
+     (progn (beginning-of-line) (point))
+     (progn (end-of-line) (point)))))
+
+(defun dictem-list2alist (l)
+  (cond
+   ((null l) nil)
+   (t (cons
+       (list (car l) nil)
+       (dictem-list2alist (cdr l))))))
+
+(defun dictem-indent-string (str)
+  (let ((start 0))
+    (while (string-match "\n" str start)
+      (progn
+	(setq start ( + 2 (match-end 0)))
+	(setq str (replace-match "\n  " t t str)))))
+  (concat "  " str))
+
+(defun dictem-replace-spaces (str)
+  (while (string-match "[ \n][ \n]+" str)
+    (setq str (replace-match " " t t str)))
+  (if (string-match "^ +" str)
+      (setq str (replace-match "" t t str)))
+  (if (string-match " +$" str)
+      (setq str (replace-match "" t t str)))
+  str)
+
+(defun dictem-remove-value-from-alist (l)
+  (let ((ret nil))
+    (dolist (i l)
+      (setq ret (cons (list (car i)) ret)))
+    (reverse ret)
+    ))
+;(defun dictem-remove-value-from-alist (l)
+;  (cond
+;   ((symbolp l) l)
+;   (t (cons (list (caar l))
+;	    (dictem-remove-value-from-alist (cdr l))))))
+
+(defun dictem-select (prompt alist default history)
+  (let*
+      ((completion-ignore-case t)
+       (str (completing-read
+	     (concat prompt " [" default "]: ")
+	     alist nil t nil history default))
+       (str-cons (assoc str alist)))
+    (cond
+     ((and str-cons (consp str-cons) (cdr str-cons))
+      str-cons)
+     ((and str-cons (consp str-cons))
+      (car str-cons))
+     (t nil))))
+
+(defun dictem-tokenize (s)
+  (if (string-match "\"[^\"]+\"\\|[^ \"]+" s )
+;	(substring s (match-beginning 0) (match-end 0))
+      (cons (substring s (match-beginning 0) (match-end 0))
+	    (dictem-tokenize (substring s (match-end 0))))
+    nil))
+
+;(defun dictem-search-forward-regexp-cs (REGEXP &optional BOUND NOERROR COUNT)
+;  "Case-sensitive variant for search-forward-regexp"
+;  (let ((case-replace nil)
+;	(case-fold-search nil))
+;    (search-forward-regexp REGEXP BOUND NOERROR COUNT)))
+
+;(defun dictem-replace-match-cs (NEWTEXT &optional FIXEDCASE LITERAL STRING SUBEXP)
+;  "Case-sensitive variant for replace-match"
+;  (let ((case-replace nil)
+;	(case-fold-search nil))
+;    (replace-match NEWTEXT FIXEDCASE LITERAL STRING SUBEXP)))
+
+(defun dictem-get-port (&optional port)
+  (let ((p (if port port dictem-port)))
+    (cond
+     ((and (stringp p) (string= "" p)) 2628)
+     ((null p) 2628)
+     ((stringp p) p)
+     ((numberp p) (number-to-string p))
+     (t (error "The value of dictem-port variable should be \
+either a string or a number"))
+     )))
+
+(defun dictem-get-server ()
+  (cond
+   ((and (stringp dictem-server) (string= "" dictem-server)) nil)
+   ((stringp dictem-server) dictem-server)
+   ((null dictem-server) nil)
+   (t (error "The value of dictem-server variable should be \
+either a string or a nil"))
+   ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;        Main Functions        ;;;;;
+
+;;;;;; Functions for Initializing ;;;;;;
+
+(defun dictem-initialize-strategies-alist (&optional server port)
+  "Obtain strategy ALIST from a DICT server
+and sets dictem-strategy-alist variable."
+  (interactive)
+  (setq dictem-strategy-alist (dictem-get-strategies
+			       server
+			       (dictem-get-port port))))
+
+(defun dictem-initialize-databases-alist (&optional server port)
+  "Obtain database ALIST from a DICT server
+and sets dictem-database-alist variable."
+  (interactive)
+  (setq dictem-database-alist
+	(dictem-get-databases server (dictem-get-port port)))
+  (if (dictem-error-p dictem-database-alist)
+      dictem-database-alist
+    (setq dictem-database-alist
+	  (dictem-delete-alist-predicate
+	   dictem-database-alist
+	   'dictem-db-should-be-excluded))))
+
+(defun dictem-initialize ()
+  "Initializes dictem, i.e. obtains
+a list of available databases and strategiss from DICT server
+and makes other tasks."
+  (interactive)
+  (let ((dbs (dictem-initialize-databases-alist))
+	(strats (dictem-initialize-strategies-alist)))
+    (if (dictem-error-p dbs)
+	dbs strats)))
+
+(defun dictem-reinitialize-err ()
+  "Initializes dictem if it is not initialized yet
+and run (error ...) if an initialization fails"
+  (interactive)
+  (if (or (dictem-error-p dictem-database-alist)
+	  (null dictem-database-alist))
+      (if (dictem-error-p (dictem-initialize))
+	  (error (dictem-error-message dictem-database-alist)))))
+
+;;; Functions related to Minibuffer ;;;;
+
+(defun dictem-select-strategy (&optional default-strat)
+  "Switches to minibuffer and asks the user
+to enter a search strategy."
+  (dictem-reinitialize-err)
+  (dictem-select
+   "strategy"
+   (dictem-prepand-special-strats
+    (dictem-remove-value-from-alist dictem-strategy-alist))
+   (dictem-get-default-strategy default-strat)
+   'dictem-strategy-history))
+
+(defun dictem-select-database (spec-dbs user-dbs &optional default-db)
+  "Switches to minibuffer and asks user
+to enter a database name."
+  (dictem-reinitialize-err)
+  (let* ((dbs (dictem-remove-value-from-alist dictem-database-alist))
+	 (dbs2 (if user-dbs
+		   (if dictem-use-user-databases-only
+		       dictem-user-databases-alist
+		     (append dictem-user-databases-alist dbs)
+		     )
+		 dbs)))
+    (dictem-select
+     "db"
+     (if spec-dbs (dictem-prepand-special-dbs dbs2) dbs2)
+     (dictem-get-default-database default-db)
+     'dictem-database-history)))
+
+(defun dictem-read-query (&optional default-query)
+  "Switches to minibuffer and asks user to enter a query."
+  (if (featurep 'xemacs)
+      (read-string
+       (concat "query [" default-query "]: ")
+       nil 'dictem-query-history default-query)
+    (read-string
+     (concat "query [" default-query "]: ")
+     (if dictem-empty-initial-input nil default-query)
+     'dictem-query-history default-query t)))
+
+
+;;;;;;;;           Hooks        ;;;;;;;;
+
+(defcustom dictem-postprocess-definition-hook
+  nil
+  "Hook run in dictem mode buffers containing DEFINE result."
+  :group 'dictem
+  :type 'hook
+  :options '(dictem-postprocess-definition-separator
+	     dictem-postprocess-definition-hyperlinks
+	     dictem-postprocess-each-definition
+	     dictem-postprocess-definition-remove-header
+	     dictem-postprocess-collect-hyperlinks))
+
+(defcustom dictem-postprocess-match-hook
+  nil
+  "Hook run in dictem mode buffers containing MATCH result."
+  :group 'dictem
+  :type 'hook
+  :options '(dictem-postprocess-match))
+
+(defcustom dictem-postprocess-show-info-hook
+  nil
+  "Hook run in dictem mode buffers containing SHOW INFO result."
+  :group 'dictem
+  :type 'hook
+  :options '(dictem-postprocess-definition-hyperlinks
+	     dictem-postprocess-collect-hyperlinks))
+
+(defcustom dictem-postprocess-show-server-hook
+  nil
+  "Hook run in dictem mode buffers containing SHOW SERVER result."
+  :group 'dictem
+  :type 'hook)
+
+;;;;;;;;    Search Functions     ;;;;;;;
+
+(defun dictem-call-dict-internal (fun databases)
+  (let ((exit-status -1))
+    (cond
+     ((null databases) 0)
+     ((stringp databases)
+      (dictem-call-dict-internal fun (list databases)))
+     ((listp databases)
+      (dolist (db databases)
+	(let ((ex_st (funcall fun db)))
+	  (cond
+	   ((= ex_st 0)
+	    (setq exit-status 0))
+	   (t (if (/= 0 exit-status)
+		  (setq exit-status ex_st)))
+	   )))
+      (if (= exit-status -1) 0 exit-status)
+      )
+     (t (error "wrong type of argument"))
+     )
+    ))
+
+;(defun dictem-call-dict-internal (fun databases)
+;  (dolist (db databases)
+;    (funcall fun db)))
+;  (funcall fun databases))
+
+(defun dictem-make-url (host port database cmd_sign query &optional strategy)
+  "Returns dict:// URL"
+  (concat
+   "dict://" host ":"
+   (dictem-get-port (if port port "2628"))
+   "/" cmd_sign ":" query ":" database
+   (if strategy (concat ":" (if strategy strategy ".")))
+   ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-base-do-selector (cmd hook &optional database &rest args)
+  (let* ((splitted-url nil)
+	 (databases    nil)
+	 (user-db      (assoc database dictem-user-databases-alist))
+	 )
+    (goto-char (point-max))
+    (cond ((dictem-userdb-p database)
+	   (apply 'dictem-base-do-default-server
+		  (append (list cmd hook database) args)))
+
+	  ((and database (listp database))
+	   (dictem-call-dict-internal
+	    `(lambda (db)
+	       (apply 'dictem-base-do-selector 
+		      (append (list ,cmd hook db) args)))
+	    (cdr database))
+	   (setq dictem-last-database (car database)))
+
+	  ((and database (stringp database)
+		(setq splitted-url (dictem-parse-url database)))
+	   (apply 'dictem-base-do-foreign-server
+		  (append
+		   (list cmd hook
+			 (nth 1 splitted-url)
+			 (dictem-get-port (nth 2 splitted-url))
+			 (nth 3 splitted-url))
+		   args)))
+
+	  (user-db
+	   (let ((exit_status
+		  (apply 'dictem-base-do-selector
+			 (append
+			  (list cmd hook user-db) args))))
+	     (progn
+	       (setq dictem-last-database database)
+	       exit_status)
+	     ))
+
+	  (t
+	   (apply 'dictem-base-do-default-server
+		  (append (list cmd hook database) args)))
+	  )))
+
+(defun dictem-base-do-foreign-server (cmd hook server port database &rest args)
+  (let ((dictem-last-database nil)
+	(dictem-last-strategy nil))
+    (save-dictem (setq dictem-server server)
+		 (setq dictem-port   port)
+		 (setq database      database)
+		 (dictem-initialize)
+		 (apply 'dictem-base-do-default-server
+			(append (list cmd hook database) args))
+		 )))
+
+(defun dictem-base-do-default-server (cmd hook
+					  &optional database query strategy)
+  (let* ((beg (point))
+	 (fun (if (dictem-userdb-p database)
+		  (dictem-cmd2userdb cmd)
+		(dictem-cmd2function cmd)))
+
+	 (exit_status
+	  (save-excursion (apply fun (append (list t)
+			     (if database (list database))
+			     (if query (list query))
+			     (if strategy (list strategy))
+			     (list nil) (list nil))))
+	  ))
+
+    (cond ((= 0 exit_status)
+	   (save-excursion
+	     (narrow-to-region beg (point-max))
+	     (run-hooks hook)
+	     (widen)))
+	  ((= 21 exit_status)
+	   (save-excursion
+	     (narrow-to-region beg (point-max))
+	     (run-hooks 'dictem-postprocess-match-hook)
+	     (widen)))
+	  (t
+	   (if (/= beg (point))
+	       (setq dictem-error-messages
+		     (append
+		      (list
+		       (dictem-make-url (dictem-get-server)
+					(dictem-get-port) database "?" query)
+		       (buffer-substring-no-properties beg (point)))
+		      dictem-error-messages)))
+	   (kill-region beg (point))))
+
+    (if database (setq dictem-last-database database))
+    (if strategy (setq dictem-last-strategy strategy))
+    exit_status
+    ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-base-search (databases query strategy)
+  "MATCH + DEFINE commands"
+
+  (dictem-base-do-selector
+   "search"
+   'dictem-postprocess-definition-hook
+   databases query strategy))
+
+(defun dictem-base-define (databases query c)
+  "DEFINE command"
+
+  (dictem-base-do-selector
+   "define"
+   'dictem-postprocess-definition-hook
+   databases query))
+
+(defun dictem-base-match (databases query strategy)
+  "MATCH command"
+
+  (dictem-base-do-selector
+   "match"
+   'dictem-postprocess-match-hook
+   databases query strategy))
+
+(defun dictem-base-show-databases (a b c)
+  "SHOW DB command"
+
+  (dictem-base-do-selector
+   "show-db"
+   nil))
+
+(defun dictem-base-show-strategies (a b c)
+  "SHOW STRAT command"
+
+  (dictem-base-do-selector
+   "show-strat"
+   nil))
+
+(defun dictem-base-show-info (databases b c)
+  "SHOW INFO command"
+
+  (dictem-base-do-selector
+   "show-info"
+   'dictem-postprocess-show-info-hook
+   databases))
+
+(defun dictem-base-show-server (a b c)
+  "SHOW SERVER command"
+
+  (dictem-base-do-selector
+   "show-server"
+   'dictem-postprocess-show-server-hook))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-get-error-message (exit_status)
+  (cond
+   ((= exit_status 0) "All is fine")
+   ((= exit_status 20) "No matches found")
+   ((= exit_status 21) "Approximate matches found")
+   ((= exit_status 22) "No databases available")
+   ((= exit_status 23) "No strategies available")
+
+   ((= exit_status 30) "Unexpected response code from server")
+   ((= exit_status 31) "Server is temporarily unavailable")
+   ((= exit_status 32) "Server is shutting down")
+   ((= exit_status 33) "Syntax error, command not recognized")
+   ((= exit_status 34) "Syntax error, illegal parameters")
+   ((= exit_status 35) "Command not implemented")
+   ((= exit_status 36) "Command parameter not implemented")
+   ((= exit_status 37) "Access denied")
+   ((= exit_status 38) "Authentication failed")
+   ((= exit_status 39) "Invalid database name")
+   ((= exit_status 40) "Invalid strategy name")
+   ((= exit_status 41) "Connection to server failed")
+   (t                  (concat "Ooops!" (number-to-string exit_status)))
+   ))
+
+(defun dictem-local-internal (err-msgs exit_status)
+  (if err-msgs
+      (concat (car err-msgs) "\n"
+	      (cadr err-msgs)
+	      "\n"
+	      (dictem-local-internal
+	       (cddr err-msgs)
+	       nil)
+	      )
+    (if exit_status
+	(dictem-get-error-message exit_status)
+      nil)))
+
+(defun dictem-generate-full-error-message (exit_status)
+
+  (concat "Error messages:\n\n"
+	  (dictem-local-internal dictem-error-messages exit_status)))
+
+(defun dictem-run (search-fun &optional database query strategy)
+  "Creates new *dictem* buffer and run search-fun"
+
+  (let ((ex_status -1))
+
+    (defun dictem-local-run-functions (funs database query strategy)
+      (cond
+       ((functionp funs)
+	(let ((ex_st (funcall funs database query strategy)))
+	  (if (/= ex_status 0)
+	      (setq ex_status ex_st))))
+       ((and (consp funs) (functionp (car funs)))
+	(dictem-local-run-functions (car funs) database query strategy)
+	(dictem-local-run-functions (cdr funs) database query strategy))
+       ((null funs)
+	nil)
+       (t (error "wrong argument type"))
+       )
+      ex_status)
+
+    (let ((selected-window (frame-selected-window))
+	    ; here we remember values of variables local to buffer
+	  (server           dictem-server)
+	  (port             dictem-port)
+	  (dbs              dictem-database-alist)
+	  (strats           dictem-strategy-alist)
+	  (user-dbs         dictem-user-databases-alist)
+	  (user-only        dictem-use-user-databases-only)
+	  (use-existing-buf dictem-use-existing-buffer)
+;	    (option-mime      dictem-option-mime)
+	  (dict-buf         nil)
+	  )
+      (cond
+       ((eq dictem-use-existing-buffer 'always)
+	(dictem-ensure-buffer))
+       ((eq dictem-use-existing-buffer t)
+	(dictem-ensure-buffer))
+       (t
+	(dictem))
+       0)
+      (setq dict-buf (buffer-name))
+;	(set-buffer-file-coding-system coding-system)
+      (make-local-variable 'dictem-default-strategy)
+      (make-local-variable 'dictem-default-database)
+      (make-local-variable 'case-replace)
+      (make-local-variable 'case-fold-search)
+
+	; the following lines are to inherit values local to buffer
+      (set (make-local-variable 'dictem-server) server)
+      (set (make-local-variable 'dictem-port)   port)
+      (set (make-local-variable 'dictem-database-alist) dbs)
+      (set (make-local-variable 'dictem-strategy-alist) strats)
+      (set (make-local-variable 'dictem-user-databases-alist) user-dbs)
+      (set (make-local-variable 'dictem-use-user-databases-only) user-only)
+      (set (make-local-variable 'dictem-use-existing-buffer) use-existing-buf)
+
+;	(set (make-local-variable 'dictem-option-mime) option-mime)
+
+      (set (make-local-variable 'dictem-hyperlinks-alist) nil)
+
+	;;;;;;;;;;;;;;
+      (setq case-replace nil)
+      (setq case-fold-search nil)
+      (setq dictem-error-messages nil)
+      (dictem-local-run-functions search-fun database query strategy)
+      (switch-to-buffer dict-buf)
+      (if (and (not (equal ex_status 0)) (= (point-min) (point-max)))
+	  (insert (dictem-generate-full-error-message ex_status)))
+      (goto-char (point-min))
+      (setq buffer-read-only t)
+      ex_status
+      )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun dictem-next-section ()
+  "Move point to the next definition"
+  (interactive)
+  (forward-char)
+  (if (search-forward-regexp "^From " nil t)
+      (beginning-of-line)
+    (goto-char (point-max))))
+
+(defun dictem-previous-section ()
+  "Move point to the previous definition"
+  (interactive)
+  (backward-char)
+  (if (search-backward-regexp "^From " nil t)
+      (beginning-of-line)
+    (goto-char (point-min))))
+
+(defun dictem-hyperlinks-menu ()
+  "Hyperlinks menu with autocompletion"
+  (interactive)
+  (let ((link (completing-read "Go to:" dictem-hyperlinks-alist)))
+    (if (and link (setq link (assoc link dictem-hyperlinks-alist)))
+	(dictem-run-define
+	 (cadr link)
+	 dictem-last-database))
+    ))
+
+(defun dictem-next-link ()
+  "Move point to the next hyperlink"
+  (interactive)
+  (let ((pt nil)
+	(limit (point-max)))
+    (if (and (setq pt (next-single-property-change
+		       (point) 'link nil limit))
+	     (/= limit pt))
+	(if (get-char-property pt 'link)
+	    (goto-char pt)
+	  (goto-char (next-single-property-change pt 'link nil limit))))
+    ))
+
+(defun dictem-previous-link ()
+  "Move point to the previous hyperlink"
+  (interactive)
+  (let ((pt nil)
+	(limit (point-min)))
+    (if (and (setq pt (previous-single-property-change
+		       (point) 'link nil limit))
+	     (/= limit pt))
+	(if (get-char-property pt 'link)
+	    (goto-char pt)
+	  (goto-char (previous-single-property-change pt 'link nil limit))))
+      ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun dictem-help ()
+  "Display a dictem help"
+  (interactive)
+  (describe-function 'dictem-mode))
+
+(defun dictem-mode ()
+  "This is a mode for dict client implementing
+the protocol defined in RFC 2229.
+
+The following basic commands are available in the buffer.
+
+  \\[dictem-help]         display the help information
+
+  \\[dictem-kill]         kill the dictem buffer
+  \\[dictem-kill-all-buffers]         kill all dictem buffers
+  \\[dictem-quit]         bury the dictem buffer
+
+  \\[dictem-last]         restore content of the previously visited dictem buffer
+
+  \\[dictem-run-search]         make a new SEARCH, i.e. ask for a database, strategy and query
+            and show definitions
+  \\[dictem-run-match]         make a new MATCH, i.e. ask for database, strategy and query
+            and show matches
+  \\[dictem-run-define]         make a new DEFINE, i.e. ask for a database and query
+            and show definitions
+  \\[dictem-run-show-server]         show information about DICT server
+  \\[dictem-run-show-info]         ask for a database and show information about it
+  \\[dictem-run-show-databases]         show databases DICT server provides
+  \\[dictem-run-show-strategies]         show search strategies DICT server provides
+
+  \\[dictem-next-section]         move point to the next definition
+  \\[dictem-previous-section]         move point to the previous definition
+  \\[dictem-next-link]       move point to the next hyper link
+  \\[dictem-previous-link]       move point to the previous hyper link
+
+  \\[dictem-hyperlinks-menu]         display the menu with hyperlinks
+
+  \\[scroll-up]                 scroll dictem buffer up
+  \\[scroll-down]                 scroll dictem buffer down
+  \\[dictem-define-on-click] or \\[dictem-define-on-press]    visit a link (DEFINE using all dictionaries)
+
+
+Also some advanced commands are available.
+
+  \\[dictem-initialize] Initializes dictem, i.e. obtains
+a list of available databases and strategiss from DICT server
+and makes other tasks
+  \\[dictem-initialize-strategies-alist] Obtain strategy ALIST from a DICT server and sets dictem-strategy-alist variable
+  \\[dictem-initialize-databases-alist] Obtain database ALIST from a DICT server and sets dictem-database-alist variable
+
+
+The following key bindings are currently in effect in the buffer:
+\\{dictem-mode-map}
+"
+
+  (interactive)
+
+  (kill-all-local-variables)
+  (buffer-disable-undo)
+  (use-local-map dictem-mode-map)
+  (setq major-mode 'dictem-mode)
+  (setq mode-name "dictem")
+
+  (add-hook 'kill-buffer-hook 'dictem-kill t t)
+  (run-hooks 'dictem-mode-hook)
+  )
+
+(defvar dictem-window-configuration
+  nil
+  "The window configuration to be restored upon closing the buffer")
+
+(defvar dictem-selected-window
+  nil
+  "The currently selected window")
+
+(defvar dictem-content-history
+  nil
+  "A list of lists (buffer_content point)")
+
+(defconst dictem-buffer-name
+  "*dictem buffer*")
+
+(defconst dictem-url-regexp
+  "^\\(dict\\)://\\([^/:]*\\)\\(:\\([0-9]+\\)\\)?/\\(.*\\)$")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst dictem-cmd2function-alist
+  '(("show-server" dictem-call-process-SHOW-SERVER)
+    ("show-info"   dictem-call-process-SHOW-INFO)
+    ("show-strat"  dictem-call-process-SHOW-STRAT)
+    ("show-db"     dictem-call-process-SHOW-DB)
+    ("match"       dictem-call-process-MATCH)
+    ("define"      dictem-call-process-DEFINE)
+    ("search"      dictem-call-process-SEARCH)
+    ))
+
+(defconst dictem-cmd2userdb-alist
+  '(("match"       dictem-userdb-MATCH)
+    ("define"      dictem-userdb-DEFINE)
+    ("search"      dictem-userdb-SEARCH)
+    ("show-info"   dictem-userdb-SHOW-INFO)
+    ))
+
+(defun dictem-cmd2xxx (cmd alist)
+  (let ((fun (assoc cmd alist)))
+    (if fun
+	(symbol-function (cadr fun))
+      (error "Unknown command \"%s\"" cmd)
+      )
+    ))
+
+(defun dictem-cmd2function (cmd)
+  (dictem-cmd2xxx cmd dictem-cmd2function-alist))
+(defun dictem-cmd2userdb (cmd)
+  (dictem-cmd2xxx cmd dictem-cmd2userdb-alist))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun dictem-parse-url (url)
+  "Parses string like dict://dict.org:2628/foldoc
+and returns a list containing protocol, server, port and path on nil if fails"
+  (if (string-match dictem-url-regexp url)
+      (list
+       (match-string 1 url) ; protocol
+       (match-string 2 url) ; host
+       (match-string 4 url) ; port
+       (match-string 5 url) ; path (database name for dict://)
+       )
+    nil))
+
+(defun dictem ()
+  "Create a new dictem buffer and install dictem-mode"
+  (interactive)
+
+  (let (
+	(buffer (generate-new-buffer dictem-buffer-name))
+	(window-configuration (current-window-configuration))
+	(selected-window (frame-selected-window)))
+    (switch-to-buffer-other-window buffer)
+    (dictem-mode)
+
+    (make-local-variable 'dictem-window-configuration)
+    (make-local-variable 'dictem-selected-window)
+    (make-local-variable 'dictem-content-history)
+    (setq dictem-window-configuration window-configuration)
+    (setq dictem-selected-window selected-window)
+    ))
+
+;(unless dictem-mode-map
+(setq dictem-mode-map (make-sparse-keymap))
+(suppress-keymap dictem-mode-map)
+
+; Kill the buffer
+(define-key dictem-mode-map "k" 'dictem-kill)
+
+; Kill all dictem buffers
+(define-key dictem-mode-map "x" 'dictem-kill-all-buffers)
+
+; Bury the buffer
+(define-key dictem-mode-map "q" 'dictem-quit)
+
+; LAST, works like in Info-mode
+(define-key dictem-mode-map "l" 'dictem-last)
+
+; Show help message
+(define-key dictem-mode-map "h" 'dictem-help)
+
+; SEARCH = MATCH + DEFINE
+(define-key dictem-mode-map "s" 'dictem-run-search)
+
+; MATCH
+(define-key dictem-mode-map "m" 'dictem-run-match)
+
+; DEFINE
+(define-key dictem-mode-map "d" 'dictem-run-define)
+
+; SHOW SERVER
+(define-key dictem-mode-map "r" 'dictem-run-show-server)
+
+; SHOW INFO
+(define-key dictem-mode-map "i" 'dictem-run-show-info)
+
+; Move point to the next DEFINITION
+(define-key dictem-mode-map "n" 'dictem-next-section)
+
+; Move point to the previous DEFINITION
+(define-key dictem-mode-map "p" 'dictem-previous-section)
+
+; Move point to the next HYPER LINK
+(define-key dictem-mode-map "\M-n" 'dictem-next-link)
+
+; Move point to the previous HYPER LINK
+(define-key dictem-mode-map "\M-p" 'dictem-previous-link)
+
+; Hyperlinks menu
+(define-key dictem-mode-map "e" 'dictem-hyperlinks-menu)
+
+; Scroll up dictem buffer
+(define-key dictem-mode-map " " 'scroll-up)
+
+; Scroll down dictem buffer
+(define-key dictem-mode-map "\177" 'scroll-down)
+
+; Define on click
+(if (featurep 'xemacs)
+    (define-key dictem-mode-map [button2]
+      'dictem-define-on-click)
+  (define-key dictem-mode-map [mouse-2]
+    'dictem-define-on-click))
+
+(define-key dictem-mode-map "\C-m"
+  'dictem-define-on-press)
+
+(defun dictem-mode-p ()
+  "Return non-nil if current buffer has dictem-mode"
+  (eq major-mode 'dictem-mode))
+
+(defun dictem-ensure-buffer ()
+  "If current buffer is not a dictem buffer, create a new one."
+  (if (dictem-mode-p)
+      (progn
+	(if dictem-use-content-history
+	    (setq dictem-content-history
+		  (cons (list (buffer-substring
+			       (point-min) (point-max))
+			      (point)) dictem-content-history)))
+	(setq buffer-read-only nil)
+	(erase-buffer))
+    (dictem)))
+
+(defun dictem-quit ()
+  "Bury the current dictem buffer."
+  (interactive)
+  (if (featurep 'xemacs)
+      (bury-buffer)
+    (quit-window)))
+
+(defun dictem-kill ()
+  "Kill the current dictem buffer."
+  (interactive)
+
+  (if (eq major-mode 'dictem-mode)
+      (progn
+	(setq major-mode nil)
+	(let ((configuration dictem-window-configuration)
+	      (selected-window dictem-selected-window))
+	  (kill-buffer (current-buffer))
+	  (if (window-live-p selected-window)
+	      (progn
+		(select-window selected-window)
+		(set-window-configuration configuration)))))))
+
+(defun dictem-last ()
+  "Go back to the last buffer visited visited."
+  (interactive)
+  (if (eq major-mode 'dictem-mode)
+      (if dictem-content-history
+	  (progn
+	    (setq buffer-read-only nil)
+	    (delete-region (point-min) (point-max))
+	    (insert (car (car dictem-content-history)))
+	    (goto-char (cadr (car dictem-content-history)))
+	    (setq dictem-content-history (cdr dictem-content-history))
+	    )
+	  )
+    ))
+
+(defun dictem-kill-all-buffers ()
+  "Kill all dictem buffers."
+  (interactive)
+  (dolist (buffer (buffer-list))
+    (let ((buf-name (buffer-name buffer)))
+      (if (and (<= (length dictem-buffer-name) (length buf-name))
+	       (string= dictem-buffer-name
+			(substring buf-name 0 (length dictem-buffer-name))))
+	  (kill-buffer buf-name))
+      )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;     Top-level Functions     ;;;;;;
+
+(defun dictem-run-match (query database strat)
+  "Asks a user about database name, search strategy and query,
+creates new *dictem* buffer and
+shows matches in it."
+  (interactive
+   (list 
+    (dictem-read-query (thing-at-point 'word))
+    (dictem-select-database t t (dictem-get-default-database))
+    (dictem-select-strategy (dictem-get-default-strategy))))
+  (dictem-run 'dictem-base-match database query strat))
+
+(defun dictem-run-define (query database)
+  "Asks a user about database name and query,
+creates new *dictem* buffer and
+shows definitions in it."
+  (interactive
+   (list
+    (dictem-read-query (thing-at-point 'word))
+    (dictem-select-database t t (dictem-get-default-database))))
+  (dictem-run 'dictem-base-define database query nil))
+
+(defun dictem-run-search (query database strat)
+  "Asks a user about database name, search strategy and query,
+creates new *dictem* buffer and
+shows definitions in it."
+  (interactive
+   (list
+    (dictem-read-query (thing-at-point 'word))
+    (dictem-select-database t t (dictem-get-default-database))
+    (dictem-select-strategy (dictem-get-default-strategy))))
+  (dictem-run 'dictem-base-search database query strat))
+
+(defun dictem-run-show-info (database)
+  "Asks a user about database name
+creates new *dictem* buffer and
+shows information about it."
+  (interactive (list
+		(dictem-select-database
+		 nil nil
+		 (dictem-get-default-database))))
+  (dictem-run 'dictem-base-show-info database))
+
+(defun dictem-run-show-server ()
+  "Creates new *dictem* buffer and
+shows information about DICT server in it."
+  (interactive)
+  (dictem-run 'dictem-base-show-server))
+
+(defun dictem-run-show-databases ()
+  "Creates new *dictem* buffer and
+shows a list of databases provided by DICT."
+  (interactive)
+  (dictem-run 'dictem-base-show-databases))
+
+(defun dictem-run-show-strategies ()
+  "Creates new *dictem* buffer and
+shows a list of search stratgeies provided by DICT."
+  (interactive)
+  (dictem-run 'dictem-base-show-strategies))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(easy-menu-define
+ dictem-menu
+ dictem-mode-map
+ "DictEm Menu"
+ `("DictEm"
+   ["DictEm..." dictem-help t]
+   "--"
+   ["Next Section"     dictem-next-section t]
+   ["Previous Section" dictem-previous-section t]
+   "--"
+   ["Match"            dictem-run-match t]
+   ["Definition"       dictem-run-define t]
+   ["Search"           dictem-run-search t]
+   "--"
+   ["Information about server"   dictem-run-show-server t]
+   ["Information about database" dictem-run-show-info t]
+   ["A list of available databases" dictem-run-show-databases t]
+   "--"
+   ["Bury Dictem Buffer" dictem-quit t]
+   ["Kill Dictem Buffer" dictem-kill t]
+   ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;      Optional Features       ;;;;;
+(defun dictem-create-link (start end face function &optional data add-props)
+  "Create a link in the current buffer starting from `start' going to `end'.
+The `face' is used for displaying, the `data' are stored together with the
+link.  Upon clicking the `function' is called with `data' as argument."
+  (let ((properties
+	 (append (list 'face face
+		       'mouse-face 'highlight
+		       'link-data data
+		       'link-function function
+		       'dictem-server dictem-server
+		       'dictem-port   dictem-port)
+	 add-props)))
+    (remove-text-properties start end properties)
+    (add-text-properties start end properties)))
+
+;;;;;;;   Postprocessing Functions     ;;;;;;;
+
+(defun dictem-postprocess-definition-separator ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp "^\\(From\\)\\( [^\n]+\\)\\(\\[[^\n]+\\]\\)"))
+
+      (while (search-forward-regexp regexp nil t)
+	(let ((beg (match-beginning 1))
+	      (end (match-end 1))
+	      (beg-dbdescr (match-beginning 2))
+	      (end-dbdescr (match-end 2))
+	      (beg-dbname (match-beginning 3))
+	      (end-dbname (match-end 3))
+	      )
+	  (put-text-property beg end
+			     'face 'dictem-database-description-face)
+	  (put-text-property beg-dbdescr end-dbdescr
+			     'face 'dictem-database-description-face)
+	  (setq dictem-current-dbname
+		(dictem-replace-spaces
+		 (buffer-substring-no-properties
+		  (+ beg-dbname 1) (- end-dbname 1))))
+	  (dictem-create-link
+	   beg-dbname end-dbname
+	   'dictem-reference-dbname-face
+	   'dictem-base-show-info
+	   (list (cons 'dbname dictem-current-dbname))))
+	))))
+
+(defvar dictem-hyperlink-beginning
+  "{"
+  "String that begins hyperlink.
+This variable is used by
+the function 'dictem-postprocess-definition-hyperlinks'")
+
+(defvar dictem-hyperlink-end
+  "}"
+  "String that ends hyperlink.
+This variable is used by
+the function 'dictem-postprocess-definition-hyperlinks'")
+
+(defvar dictem-hyperlink-define-func
+  'dictem-base-define
+  "Function called when user clicks on hyperlinks inside the definition.
+This variable is used by
+the function 'dictem-postprocess-definition-hyperlinks'")
+
+(defun dictem-postprocess-collect-hyperlinks ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp (concat "\\(" dictem-hyperlink-beginning "\\([^{}|]+\\)"
+		  dictem-hyperlink-end
+		  "\\|\\(" dictem-hyperlink-beginning
+		  "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)" dictem-hyperlink-end
+		  "\\)\\)")))
+
+      (while (search-forward-regexp regexp nil t)
+	(cond ((match-beginning 2)
+	       (let* ((word (dictem-replace-spaces
+			     (buffer-substring-no-properties
+			      (match-beginning 2)
+			      (match-end 2)))))
+		 (setq dictem-hyperlinks-alist
+		       (cons (list word word) dictem-hyperlinks-alist))
+		 ))
+	      ((match-beginning 3)
+	       (let* ((word-beg (match-beginning 4))
+		      (word-end (match-end 4))
+		      (link-beg (match-beginning 5))
+		      (link-end (match-end 5))
+		      (word (dictem-replace-spaces
+			     (buffer-substring-no-properties
+			      word-beg word-end)))
+		      (link (dictem-replace-spaces
+			     (buffer-substring-no-properties
+			      link-beg link-end)))
+		      )
+		 (setq dictem-hyperlinks-alist
+		       (cons (list word link) dictem-hyperlinks-alist))
+		 )))))
+    ))
+
+(defun dictem-find-brackets (re-beg re-end)
+  (let ((beg-beg (make-marker))
+	(beg-end (make-marker))
+	(end-beg (make-marker))
+	(end-end (make-marker)))
+    (if (search-forward-regexp re-beg nil t)
+	(progn
+	  (set-marker beg-beg (match-beginning 0))
+	  (set-marker beg-end (match-end 0))
+	  (if (search-forward-regexp re-end nil t)
+	      (progn
+		(set-marker end-beg (match-beginning 0))
+		(set-marker end-end (match-end 0))
+		(list beg-beg beg-end end-beg end-end))
+	    nil))
+      nil)))
+
+(defun dictem-postprocess-definition-hyperlinks-cyrlybr1 ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp) (pos) (beg1) (beg2) (beg3) (end) (word))
+
+      (while (setq pos (dictem-find-brackets dictem-hyperlink-beginning
+					     dictem-hyperlink-end))
+	(delete-region (nth 0 pos) (nth 1 pos))
+	(delete-region (nth 2 pos) (nth 3 pos))
+	(setq word (buffer-substring-no-properties (nth 1 pos) (nth 2 pos)))
+	(dictem-create-link
+	 (nth 1 pos) (nth 2 pos)
+	 'dictem-reference-definition-face
+	 dictem-hyperlink-define-func
+	 (list (cons 'word (dictem-replace-spaces word))
+	       (cons 'dbname dictem-current-dbname))
+	 '(link t))))))
+
+(defun dictem-postprocess-definition-hyperlinks-curlybr2 ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp
+	   (concat dictem-hyperlink-beginning "\\([^{}|\n]+\\)|\\([^{}|\n]+\\)"
+		   dictem-hyperlink-end)))
+
+      (while (search-forward-regexp regexp nil t)
+	(let* ((beg (match-beginning 5))
+	       (end (match-end 5))
+	       (match-beg (match-beginning 3))
+	       (repl-beg (match-beginning 4))
+	       (repl-end (match-end 4))
+	       (repl (buffer-substring-no-properties repl-beg repl-end))
+	       (word (buffer-substring-no-properties beg end)))
+	  (replace-match repl t t)
+	  (dictem-create-link
+	   match-beg (+ match-beg (length repl))
+	   'dictem-reference-definition-face
+	   dictem-hyperlink-define-func
+	   (list (cons 'word (dictem-replace-spaces word))
+		 (cons 'dbname dictem-current-dbname))
+	   '(link t)))))))
+
+(defun dictem-postprocess-definition-hyperlinks ()
+  (dictem-postprocess-definition-hyperlinks-cyrlybr1)
+  (dictem-postprocess-definition-hyperlinks-curlybr2)
+;  (dictem-postprocess-definition-hyperlinks-curlybr2)
+  )
+
+(defun dictem-postprocess-match ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((last-database dictem-last-database)
+	  (regexp "\\(\"[^\"\n]+\"\\)\\|\\([^ \"\n]+\\)"))
+
+      (while (search-forward-regexp regexp nil t)
+	(let* ((beg (match-beginning 0))
+	       (end (match-end 0))
+	       (first-char (buffer-substring-no-properties beg beg)))
+	  (cond
+	   ((save-excursion (goto-char beg) (= 0 (current-column)))
+	    (setq last-database
+		  (dictem-replace-spaces
+		   (buffer-substring-no-properties beg (- end 1))))
+	    (dictem-create-link
+	     beg (- end 1)
+	     'dictem-reference-dbname-face 'dictem-base-show-info
+	     (list (cons 'dbname last-database))))
+	   ((match-beginning 1)
+	    (dictem-create-link
+	     beg end
+	     'dictem-reference-m1-face 'dictem-base-define
+	     (list (cons 'word
+			 (dictem-replace-spaces
+			  (buffer-substring-no-properties
+			   (+ beg 1) (- end 1))))
+		   (cons 'dbname last-database))))
+	   (t
+	    (dictem-create-link
+	     beg end
+	     'dictem-reference-m2-face 'dictem-base-define
+	     (list (cons 'word
+			 (dictem-replace-spaces
+			  (buffer-substring-no-properties
+			   beg end )))
+		   (cons 'dbname last-database))))
+	   ))))))
+
+(defun dictem-postprocess-definition-remove-header ()
+  (save-excursion
+    (goto-char (point-min))
+    (end-of-line)
+    (let (eol (point))
+      (goto-char (point-min))
+      (if (search-forward-regexp "[0-9] definitions? found" eol t)
+	  (progn
+	    (goto-char (point-min))
+	    (let ((kill-whole-line t))
+	      (kill-line 1))
+	    )))))
+
+(defun dictem-add-text-face-properties (start end face-add-props
+					      &optional object)
+  (let (face-props)
+    (while (<= start end)
+      (progn
+	(setq face-props (get-text-property start 'face object))
+	(if (facep face-props)
+	    (progn
+	      (setq face-props nil)
+	      (add-text-properties
+	       start (+ 1 start)
+	       (list 'face nil)
+	       object)))
+	(add-text-properties
+	 start (+ 1 start)
+	 (list 'face (append face-props face-add-props))
+	 object)
+	(setq start (+ start 1))))))
+
+(defun dictem-add-begendre-face-propertires (re-beg re-end face-properties)
+  (let ((bold-beg-beg (make-marker))
+	(bold-beg-end (make-marker))
+	(bold-end-beg (make-marker))
+	(bold-end-end (make-marker)))
+    (while (search-forward-regexp re-beg nil t)
+      (progn
+	(set-marker bold-beg-beg (match-beginning 0))
+	(set-marker bold-beg-end (match-end 0))
+	(if (search-forward-regexp re-end nil t)
+	    (progn
+	      (set-marker bold-end-beg (match-beginning 0))
+	      (set-marker bold-end-end (match-end 0))
+	      (dictem-add-text-face-properties
+	       bold-beg-end (- bold-end-beg 1) face-properties)
+	      (delete-region bold-beg-beg bold-beg-end)
+	      (delete-region bold-end-beg bold-end-end)
+	      ))))))
+
+(defun dictem-postprocess-stardict-definition ()
+  (interactive)
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<b>" "</b>" '(:weight bold))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<k>" "</k>" '(:height 1.2 :foreground "white" :weight bold))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<abr>" "</abr>" '(:weight bold :foreground "green"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<dtrn>" "</dtrn>" '())
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<c c=\"green\">" "</c>" '(:foreground "green"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<c c=\"brown\">" "</c>" '(:foreground "brown"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<c>" "</c>" '(:foreground "green"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<ex>" "</ex>" '(:foreground "BurlyWood"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<i>" "</i>" '(:slant "oblique"))
+
+  (goto-char (point-min))
+  (dictem-add-begendre-face-propertires
+   "<c c=\"blueviolet\">" "</c>" '(:foreground "lightblue"))
+
+  ; replaceing <tr> with [
+  (goto-char (point-min))
+  (while (search-forward-regexp "<tr>" nil t)
+    (replace-match "[" t t))
+
+  ; replaceing </tr> with ]
+  (goto-char (point-min))
+  (while (search-forward-regexp "</tr>" nil t)
+    (replace-match "]" t t))
+
+  ; replaceing <co> with (
+  (goto-char (point-min))
+  (while (search-forward-regexp "<co>" nil t)
+    (replace-match "" t t))
+
+  ; replaceing </co> with (
+  (goto-char (point-min))
+  (while (search-forward-regexp "</co>" nil t)
+    (replace-match "" t t))
+
+  (let ((dictem-hyperlink-beginning "<kref>")
+	(dictem-hyperlink-end "</kref>"))
+    (dictem-postprocess-definition-hyperlinks-cyrlybr1))
+
+  )
+
+;;;;;       On-Click Functions     ;;;;;
+(defun dictem-define-on-press ()
+  "Is called upon pressing Enter."
+  (interactive)
+
+  (let* (
+	 (properties (text-properties-at (point)))
+	 (data (plist-get properties 'link-data))
+	 (fun  (plist-get properties 'link-function))
+	 (dictem-server (plist-get properties 'dictem-server))
+	 (dictem-port   (plist-get properties 'dictem-port))
+	 (word   (assq 'word data))
+	 (dbname (assq 'dbname data))
+	 )
+    (if (or word dbname)
+	(dictem-run fun
+		    (if dbname (cdr dbname) dictem-last-database)
+		    (if word (cdr word) nil)
+		    nil))))
+
+(defun dictem-define-on-click (event)
+  "Is called upon clicking the link."
+  (interactive "@e")
+
+  (mouse-set-point event)
+  (dictem-define-on-press))
+
+;(defun dictem-define-with-db-on-click (event)
+;  "Is called upon clicking the link."
+;  (interactive "@e")
+;
+;  (mouse-set-point event)
+;  (let* (
+;	 (properties (text-properties-at (point)))
+;	 (word (plist-get properties 'link-data)))
+;    (if word
+;	(dictem-run 'dictem-base-define (dictem-select-database) word nil))))
+
+;(define-key dictem-mode-map [C-down-mouse-2]
+;  'dictem-define-with-db-on-click)
+
+
+;;;     Function for "narrowing" definitions ;;;;;
+
+(defcustom dictem-postprocess-each-definition-hook
+  nil
+  "Hook run in dictem mode buffers containing SHOW SERVER result."
+  :group 'dictem
+  :type 'hook
+  :options '(dictem-postprocess-definition-separator
+	     dictem-postprocess-definition-hyperlinks))
+
+(defun dictem-postprocess-each-definition ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp-from-dbname "^From [^\n]+\\[\\([^\n]+\\)\\]")
+	  (beg nil)
+	  (end (make-marker))
+	  (dbname nil))
+      (if (search-forward-regexp regexp-from-dbname nil t)
+	  (let ((dictem-current-dbname
+		 (buffer-substring-no-properties
+		  (match-beginning 1) (match-end 1))))
+	    (setq beg (match-beginning 0))
+	    (while (search-forward-regexp regexp-from-dbname nil t)
+	      (set-marker end (match-beginning 0))
+;	    (set-marker marker (match-end 0))
+	      (setq dbname
+		    (buffer-substring-no-properties
+		     (match-beginning 1) (match-end 1)))
+
+	      (save-excursion
+		(narrow-to-region beg (marker-position end))
+		(run-hooks 'dictem-postprocess-each-definition-hook)
+		(widen))
+
+	      (setq dictem-current-dbname dbname)
+	      (goto-char end)
+	      (forward-char)
+	      (setq beg (marker-position end))
+	      )
+	    (save-excursion
+	      (narrow-to-region beg (point-max))
+	      (run-hooks 'dictem-postprocess-each-definition-hook)
+	      (widen))
+	    )))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(provide 'dictem)
-- 
cgit v1.2.3