1 ;;; punycode.el --- An ASCII compatible Unicode encoding format. -*- coding: iso-8859-1 -*-
3 ;; Copyright (C) 2003-2013 Simon Josefsson
4 ;; Keywords: punycode, idna, idn, unicode, encoding
6 ;; This file is part of GNU Libidn.
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.
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.
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/>.
23 ;; A simple wrapper around the command line "idn" utility in GNU
24 ;; Libidn to make punycode operations available in Emacs.
28 ;; (punycode-encode "räksmörgås")
29 ;; => "rksmrgs-5wao1o"
31 ;; (punycode-encode "foo")
34 ;; (punycode-decode "rksmrgs-5wao1o")
37 ;; (punycode-decode "foo-")
40 ;; This package is useless unless your emacs has at least partial
41 ;; support for the UTF-8 coding system.
43 ;; Report bugs to bug-libidn@gnu.org.
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")))
51 (defgroup punycode nil
52 "Punycode: An ASCII compatible Unicode encoding format.")
54 (defcustom punycode-program "idn"
55 "Name of the GNU Libidn \"idn\" application."
59 (defcustom punycode-environment '("CHARSET=UTF-8")
60 "List of environment variable definitions prepended to `process-environment'."
61 :type '(repeat string)
64 (defcustom punycode-encode-parameters '("--quiet" "--punycode-encode")
65 "Parameters passed to `punycode-program' to invoke punycode encoding mode."
66 :type '(repeat string)
69 (defcustom punycode-decode-parameters '("--quiet" "--punycode-decode")
70 "Parameters passed to `punycode-program' to invoke punycode decoding mode."
71 :type '(repeat string)
74 ;; Internal process handling:
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.")
81 (defun punycode-encode-response-clear ()
82 (setq punycode-encode-response nil))
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)
90 (defun punycode-encode-filter (process string)
91 (setq punycode-encode-response (concat punycode-encode-response string)))
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
99 (kill-process punycode-encode-process)
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))
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.")
116 (defun punycode-decode-response-clear ()
117 (setq punycode-decode-response nil))
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)
125 (defun punycode-decode-filter (process string)
126 (setq punycode-decode-response (concat punycode-decode-response string)))
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
134 (kill-process punycode-decode-process)
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))
146 ;; Punycode Elisp API:
148 (defun punycode-encode (str)
149 "Returns a Punycode encoding of STR."
150 (let ((proc (punycode-encode-process))
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)))
161 (defun punycode-decode (str)
162 "Returns a possibly multibyte string which is the punycode decoding of STR."
163 (let ((proc (punycode-decode-process))
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)))
174 (defun punycode-shutdown ()
175 "Kill the punycode related process."
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)))
186 ;;; punycode.el ends here