Initial Commit
[packages] / xemacs-packages / net-utils / punycode.el
1 ;;; punycode.el --- An ASCII compatible Unicode encoding format. -*- coding: iso-8859-1 -*-
2
3 ;; Copyright (C) 2003-2013 Simon Josefsson
4 ;; Keywords: punycode, idna, idn, unicode, encoding
5
6 ;; This file is part of GNU Libidn.
7
8 ;; This program is free software: you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
12
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;; A simple wrapper around the command line "idn" utility in GNU
24 ;; Libidn to make punycode operations available in Emacs.
25
26 ;; Example:
27 ;;
28 ;; (punycode-encode "räksmörgås")
29 ;; => "rksmrgs-5wao1o"
30 ;;
31 ;; (punycode-encode "foo")
32 ;; => "foo-"
33 ;;
34 ;; (punycode-decode "rksmrgs-5wao1o")
35 ;; => "räksmörgås"
36 ;;
37 ;; (punycode-decode "foo-")
38 ;; => "foo"
39
40 ;; This package is useless unless your emacs has at least partial
41 ;; support for the UTF-8 coding system.
42
43 ;; Report bugs to bug-libidn@gnu.org.
44
45 ;;; Code:
46
47 (eval-when (load eval)
48   (unless (find-coding-system 'utf-8)
49     (error 'invalid-operation "`punycode.el' requires support for the utf-8 coding system")))
50
51 (defgroup punycode nil
52   "Punycode: An ASCII compatible Unicode encoding format.")
53
54 (defcustom punycode-program "idn"
55   "Name of the GNU Libidn \"idn\" application."
56   :type 'string
57   :group 'punycode)
58
59 (defcustom punycode-environment '("CHARSET=UTF-8")
60   "List of environment variable definitions prepended to `process-environment'."
61   :type '(repeat string)
62   :group 'punycode)
63
64 (defcustom punycode-encode-parameters '("--quiet" "--punycode-encode")
65   "Parameters passed to `punycode-program' to invoke punycode encoding mode."
66   :type '(repeat string)
67   :group 'punycode)
68
69 (defcustom punycode-decode-parameters '("--quiet" "--punycode-decode")
70   "Parameters passed to `punycode-program' to invoke punycode decoding mode."
71   :type '(repeat string)
72   :group 'punycode)
73
74 ;; Internal process handling:
75
76 (defvar punycode-encode-process nil
77   "Internal variable holding process for punycode encoding.")
78 (defvar punycode-encode-response nil
79   "Internal variable holding response data received from punycode process.")
80
81 (defun punycode-encode-response-clear ()
82   (setq punycode-encode-response nil))
83
84 (defun punycode-encode-response ()
85   (while (and (eq (process-status punycode-encode-process) 'run)
86               (null punycode-encode-response))
87     (accept-process-output punycode-encode-process 1))
88   punycode-encode-response)
89
90 (defun punycode-encode-filter (process string)
91   (setq punycode-encode-response (concat punycode-encode-response string)))
92
93 (defun punycode-encode-process ()
94   (if (and punycode-encode-process
95            (eq (process-status punycode-encode-process) 'run))
96       punycode-encode-process
97     (if punycode-encode-process
98         (condition-case ()
99             (kill-process punycode-encode-process)
100           (error)))
101     (when (setq punycode-encode-process
102                 (let ((process-environment (append punycode-environment
103                                                    process-environment)))
104                   (apply 'start-process "punycode" nil punycode-program
105                          punycode-encode-parameters)))
106       (set-process-filter punycode-encode-process 'punycode-encode-filter)
107       (set-process-coding-system punycode-encode-process 'utf-8 'utf-8)
108       (process-kill-without-query punycode-encode-process))
109     punycode-encode-process))
110
111 (defvar punycode-decode-process nil
112   "Internal variable holding process for punycode encoding.")
113 (defvar punycode-decode-response nil
114   "Internal variable holding response data received from punycode process.")
115
116 (defun punycode-decode-response-clear ()
117   (setq punycode-decode-response nil))
118
119 (defun punycode-decode-response ()
120   (while (and (eq (process-status punycode-decode-process) 'run)
121               (null punycode-decode-response))
122     (accept-process-output punycode-decode-process 1))
123   punycode-decode-response)
124
125 (defun punycode-decode-filter (process string)
126   (setq punycode-decode-response (concat punycode-decode-response string)))
127
128 (defun punycode-decode-process ()
129   (if (and punycode-decode-process
130            (eq (process-status punycode-decode-process) 'run))
131       punycode-decode-process
132     (if punycode-decode-process
133         (condition-case ()
134             (kill-process punycode-decode-process)
135           (error)))
136     (when (setq punycode-decode-process
137                 (let ((process-environment (append punycode-environment
138                                                    process-environment)))
139                   (apply 'start-process "punycode" nil punycode-program
140                          punycode-decode-parameters)))
141       (set-process-filter punycode-decode-process 'punycode-decode-filter)
142       (set-process-coding-system punycode-decode-process 'utf-8 'utf-8)
143       (process-kill-without-query punycode-decode-process))
144     punycode-decode-process))
145
146 ;; Punycode Elisp API:
147
148 (defun punycode-encode (str)
149   "Returns a Punycode encoding of STR."
150   (let ((proc (punycode-encode-process))
151         string)
152     (if (null proc)
153         (error "Cannot start idn application")
154       (punycode-encode-response-clear)
155       (process-send-string proc (concat str "\n"))
156       (setq string (punycode-encode-response))
157       (if (and string (string= (substring string (1- (length string))) "\n"))
158           (substring string 0 (1- (length string)))
159         string))))
160
161 (defun punycode-decode (str)
162   "Returns a possibly multibyte string which is the punycode decoding of STR."
163   (let ((proc (punycode-decode-process))
164         string)
165     (if (null proc)
166         (error "Cannot start idn application")
167       (punycode-decode-response-clear)
168       (process-send-string proc (concat str "\n"))
169       (setq string (punycode-decode-response))
170       (if (and string (string= (substring string (1- (length string))) "\n"))
171           (substring string 0 (1- (length string)))
172         string))))
173
174 (defun punycode-shutdown ()
175   "Kill the punycode related process."
176   (interactive)
177   (if (and punycode-decode-process
178            (eq (process-status punycode-decode-process) 'run))
179       (kill-process punycode-decode-process))
180   (if (and punycode-encode-process
181            (eq (process-status punycode-encode-process) 'run))
182       (kill-process punycode-encode-process)))
183
184 (provide 'punycode)
185
186 ;;; punycode.el ends here