(insert-file-contents-as-raw-text): Return value.
[elisp/apel.git] / emu-mule.el
1 ;;; emu-mule.el --- emu module for Mule 1.* and Mule 2.*
2
3 ;; Copyright (C) 1995,1996,1997,1998 MORIOKA Tomohiko
4
5 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;;         Katsumi Yamaoka <yamaoka@jpl.org>
7 ;; Keywords: emulation, compatibility, Mule
8
9 ;; This file is part of emu.
10
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; This program is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Code:
27
28 ;;; @ version specific features
29 ;;;
30
31 (cond (running-emacs-19
32        (require 'emu-e19)
33        
34        ;; Suggested by SASAKI Osamu <osamu@shuugr.bekkoame.or.jp>
35        ;; (cf. [os2-emacs-ja:78])
36        (defun fontset-pixel-size (fontset)
37          (let* ((font (get-font-info
38                        (aref (cdr (get-fontset-info fontset)) 0)))
39                 (open (aref font 4)))
40            (if (= open 1)
41                (aref font 5)
42              (if (= open 0)
43                  (let ((pat (aref font 1)))
44                    (if (string-match "-[0-9]+-" pat)
45                        (string-to-number
46                         (substring
47                          pat (1+ (match-beginning 0)) (1- (match-end 0))))
48                      0))
49                ))))
50        )
51       (running-emacs-18
52        (require 'emu-18)
53        (defun make-overlay (beg end &optional buffer type))
54        (defun overlay-put (overlay prop value))
55        ))
56
57
58 ;;; @ character set
59 ;;;
60
61 (defalias 'make-char 'make-character)
62
63 (defalias 'find-non-ascii-charset-string 'find-charset-string)
64 (defalias 'find-non-ascii-charset-region 'find-charset-region)
65
66 (defalias 'charset-bytes        'char-bytes)
67 (defalias 'charset-description  'char-description)
68 (defalias 'charset-registry     'char-registry)
69 (defalias 'charset-columns      'char-width)
70 (defalias 'charset-direction    'char-direction)
71
72 (defun charset-chars (charset)
73   "Return the number of characters per dimension of CHARSET."
74   (if (= (logand (nth 2 (character-set charset)) 1) 1)
75       96
76     94))
77
78
79 ;;; @ coding system
80 ;;;
81
82 (defun encode-coding-region (start end coding-system)
83   "Encode the text between START and END to CODING-SYSTEM.
84 \[EMACS 20 emulating function]"
85   ;; If `coding-system' is nil, do nothing.
86   (code-convert-region start end *internal* coding-system))
87
88 (defun decode-coding-region (start end coding-system)
89   "Decode the text between START and END which is encoded in CODING-SYSTEM.
90 \[EMACS 20 emulating function]"
91   ;; If `coding-system' is nil, do nothing.
92   (code-convert-region start end coding-system *internal*))
93
94 ;; XXX: Should we support optional NOCOPY argument? (only in Emacs 20.x)
95 (defun encode-coding-string (str coding-system)
96   "Encode the STRING to CODING-SYSTEM.
97 \[EMACS 20 emulating function]"
98   (if coding-system
99       (code-convert-string str *internal* coding-system)
100     ;;(code-convert-string str *internal* nil) returns nil instead of str.
101     str)
102
103 ;; XXX: Should we support optional NOCOPY argument? (only in Emacs 20.x)
104 (defun decode-coding-string (str coding-system)
105   "Decode the string STR which is encoded in CODING-SYSTEM.
106 \[EMACS 20 emulating function]"
107   (if coding-system
108       (let ((len (length str))
109             ret)
110         (while (and (< 0 len)
111                     (null (setq ret
112                                 (code-convert-string
113                                  (substring str 0 len)
114                                  coding-system *internal*))))
115           (setq len (1- len)))
116         (concat ret (substring str len)))
117     str)
118
119 (defalias 'detect-coding-region 'code-detect-region)
120
121 (defalias 'set-buffer-file-coding-system 'set-file-coding-system)
122
123 (defmacro as-binary-process (&rest body)
124   (` (let (selective-display    ; Disable ^M to nl translation.
125            ;; Mule
126            mc-flag      
127            (default-process-coding-system (cons *noconv* *noconv*))
128            program-coding-system-alist)
129        (,@ body))))
130
131 (defmacro as-binary-input-file (&rest body)
132   (` (let (mc-flag
133            (file-coding-system-for-read *noconv*)
134            )
135        (,@ body))))
136
137 (defmacro as-binary-output-file (&rest body)
138   (` (let (mc-flag
139            (file-coding-system *noconv*)
140            )
141        (,@ body))))
142
143 (defalias 'set-process-input-coding-system 'set-process-coding-system)
144
145
146 ;;; @ binary access
147 ;;;
148
149 (defun insert-file-contents-as-binary (filename
150                                        &optional visit beg end replace)
151   "Like `insert-file-contents', q.v., but don't code and format conversion.
152 Like `insert-file-contents-literary', but it allows find-file-hooks,
153 automatic uncompression, etc.
154
155 Namely this function ensures that only format decoding and character
156 code conversion will not take place."
157   (as-binary-input-file
158    ;; Returns list absolute file name and length of data inserted.
159    (insert-file-contents filename visit beg end replace)))
160
161 (defalias 'insert-binary-file-contents 'insert-file-contents-as-binary)
162 (make-obsolete 'insert-binary-file-contents 'insert-file-contents-as-binary)
163
164 (defun insert-file-contents-as-raw-text (filename
165                                          &optional visit beg end replace)
166   "Like `insert-file-contents', q.v., but don't code and format conversion.
167 Like `insert-file-contents-literary', but it allows find-file-hooks,
168 automatic uncompression, etc.
169 Like `insert-file-contents-as-binary', but it converts line-break
170 code."
171   (save-excursion
172     (save-restriction
173       (narrow-to-region (point)(point))
174       (let ((return-val
175              ;; Returns list absolute file name and length of data inserted.
176              (insert-file-contents-as-binary filename visit beg end replace)))
177         (goto-char (point-min))
178         (while (re-search-forward "\r$" nil t)
179           (replace-match ""))
180         (list (car return-val) (buffer-size))))))
181
182 (defun insert-binary-file-contents-literally (filename
183                                               &optional visit beg end replace)
184   "Like `insert-file-contents-literally', q.v., but don't code conversion.
185 A buffer may be modified in several ways after reading into the buffer due
186 to advanced Emacs features, such as file-name-handlers, format decoding,
187 find-file-hooks, etc.
188   This function ensures that none of these modifications will take place."
189   (as-binary-input-file
190    ;; Returns list absolute file name and length of data inserted.
191    (insert-file-contents-literally filename visit beg end replace)))
192
193 (cond
194  (running-emacs-19_29-or-later
195   ;; for MULE 2.3 based on Emacs 19.34.
196   (defun write-region-as-binary (start end filename
197                                        &optional append visit lockname)
198     "Like `write-region', q.v., but don't code conversion."
199     (as-binary-output-file
200      (write-region start end filename append visit lockname)))
201
202   (defun write-region-as-raw-text-CRLF (start end filename
203                                               &optional append visit lockname)
204     "Like `write-region', q.v., but don't code conversion."
205     (let ((the-buf (current-buffer)))
206       (with-temp-buffer
207         (insert-buffer-substring the-buf start end)
208         (goto-char (point-min))
209         (while (re-search-forward "\\(\\=\\|[^\r]\\)\n" nil t)
210           (replace-match "\\1\r\n"))
211         (write-region-as-binary (point-min)(point-max)
212                                 filename append visit lockname))))
213   )
214  (t
215   ;; for MULE 2.3 based on Emacs 19.28.
216   (defun write-region-as-binary (start end filename
217                                        &optional append visit lockname)
218     "Like `write-region', q.v., but don't code conversion."
219     (as-binary-output-file
220      (write-region start end filename append visit)))
221
222   (defun write-region-as-raw-text-CRLF (start end filename
223                                               &optional append visit lockname)
224     "Like `write-region', q.v., but don't code conversion."
225     (let ((the-buf (current-buffer)))
226       (with-temp-buffer
227         (insert-buffer-substring the-buf start end)
228         (goto-char (point-min))
229         (while (re-search-forward "\\(\\=\\|[^\r]\\)\n" nil t)
230           (replace-match "\\1\r\n"))
231         (write-region-as-binary (point-min)(point-max)
232                                 filename append visit))))
233   ))
234
235
236 ;;; @ MIME charset
237 ;;;
238
239 (defun encode-mime-charset-region (start end charset)
240   "Encode the text between START and END as MIME CHARSET."
241   (let ((cs (mime-charset-to-coding-system charset)))
242     (if cs
243         (code-convert start end *internal* cs)
244       )))
245
246 (defun decode-mime-charset-region (start end charset &optional lbt)
247   "Decode the text between START and END as MIME CHARSET."
248   (let ((cs (mime-charset-to-coding-system charset lbt)))
249     (if cs
250         (code-convert start end cs *internal*)
251       )))
252
253 (defun encode-mime-charset-string (string charset)
254   "Encode the STRING as MIME CHARSET."
255   (let ((cs (mime-charset-to-coding-system charset)))
256     (if cs
257         (code-convert-string string *internal* cs)
258       string)))
259
260 (defun decode-mime-charset-string (string charset &optional lbt)
261   "Decode the STRING which is encoded in MIME CHARSET."
262   (let ((cs (mime-charset-to-coding-system charset lbt)))
263     (if cs
264         (decode-coding-string string cs)
265       string)))
266
267 (cond
268  (running-emacs-19_29-or-later
269   ;; for MULE 2.3 based on Emacs 19.34.
270   (defun write-region-as-mime-charset (charset start end filename
271                                                &optional append visit lockname)
272     "Like `write-region', q.v., but code-convert by MIME CHARSET."
273     (let ((file-coding-system
274            (or (mime-charset-to-coding-system charset)
275                *noconv*)))
276       (write-region start end filename append visit lockname)))
277   )
278  (t
279   ;; for MULE 2.3 based on Emacs 19.28.
280   (defun write-region-as-mime-charset (charset start end filename
281                                                &optional append visit lockname)
282     "Like `write-region', q.v., but code-convert by MIME CHARSET."
283     (let ((file-coding-system
284            (or (mime-charset-to-coding-system charset)
285                *noconv*)))
286       (write-region start end filename append visit)))
287   ))
288
289
290 ;;; @@ to coding-system
291 ;;;
292
293 (defvar mime-charset-coding-system-alist
294   '((iso-8859-1      . *ctext*)
295     (x-ctext         . *ctext*)
296     (gb2312          . *euc-china*)
297     (koi8-r          . *koi8*)
298     (iso-2022-jp-2   . *iso-2022-ss2-7*)
299     (x-iso-2022-jp-2 . *iso-2022-ss2-7*)
300     (shift_jis       . *sjis*)
301     (x-shiftjis      . *sjis*)
302     ))
303
304 (defsubst mime-charset-to-coding-system (charset &optional lbt)
305   (if (stringp charset)
306       (setq charset (intern (downcase charset)))
307     )
308   (setq charset (or (cdr (assq charset mime-charset-coding-system-alist))
309                     (intern (concat "*" (symbol-name charset) "*"))))
310   (if lbt
311       (setq charset (intern (format "%s%s" charset
312                                     (cond ((eq lbt 'CRLF) 'dos)
313                                           ((eq lbt 'LF) 'unix)
314                                           ((eq lbt 'CR) 'mac)
315                                           (t lbt)))))
316     )
317   (if (coding-system-p charset)
318       charset
319     ))
320
321
322 ;;; @@ detection
323 ;;;
324
325 (defvar charsets-mime-charset-alist
326   (let ((alist
327          '(((lc-ascii)                                  . us-ascii)
328            ((lc-ascii lc-ltn1)                          . iso-8859-1)
329            ((lc-ascii lc-ltn2)                          . iso-8859-2)
330            ((lc-ascii lc-ltn3)                          . iso-8859-3)
331            ((lc-ascii lc-ltn4)                          . iso-8859-4)
332 ;;;        ((lc-ascii lc-crl)                           . iso-8859-5)
333            ((lc-ascii lc-crl)                           . koi8-r)
334            ((lc-ascii lc-arb)                           . iso-8859-6)
335            ((lc-ascii lc-grk)                           . iso-8859-7)
336            ((lc-ascii lc-hbw)                           . iso-8859-8)
337            ((lc-ascii lc-ltn5)                          . iso-8859-9)
338            ((lc-ascii lc-roman lc-jpold lc-jp)          . iso-2022-jp)
339            ((lc-ascii lc-kr)                            . euc-kr)
340            ((lc-ascii lc-cn)                            . gb2312)
341            ((lc-ascii lc-big5-1 lc-big5-2)              . big5)
342            ((lc-ascii lc-roman lc-ltn1 lc-grk
343                       lc-jpold lc-cn lc-jp lc-kr
344                       lc-jp2)                           . iso-2022-jp-2)
345            ((lc-ascii lc-roman lc-ltn1 lc-grk
346                       lc-jpold lc-cn lc-jp lc-kr lc-jp2
347                       lc-cns1 lc-cns2)                  . iso-2022-int-1)
348            ((lc-ascii lc-roman
349                       lc-ltn1 lc-ltn2 lc-crl lc-grk
350                       lc-jpold lc-cn lc-jp lc-kr lc-jp2
351                       lc-cns1 lc-cns2 lc-cns3 lc-cns4
352                       lc-cns5 lc-cns6 lc-cns7)          . iso-2022-int-1)
353            ))
354         dest)
355     (while alist
356       (catch 'not-found
357         (let ((pair (car alist)))
358           (setq dest
359                 (append dest
360                         (list
361                          (cons (mapcar (function
362                                         (lambda (cs)
363                                           (if (boundp cs)
364                                               (symbol-value cs)
365                                             (throw 'not-found nil)
366                                             )))
367                                        (car pair))
368                                (cdr pair)))))))
369       (setq alist (cdr alist)))
370     dest))
371
372 (defvar default-mime-charset 'x-ctext
373   "Default value of MIME-charset.
374 It is used when MIME-charset is not specified.
375 It must be symbol.")
376
377 (defun detect-mime-charset-region (start end)
378   "Return MIME charset for region between START and END."
379   (charsets-to-mime-charset
380    (cons lc-ascii (find-charset-region start end))))
381
382
383 ;;; @ buffer representation
384 ;;;
385
386 (defsubst-maybe set-buffer-multibyte (flag)
387   "Set the multibyte flag of the current buffer to FLAG.
388 If FLAG is t, this makes the buffer a multibyte buffer.
389 If FLAG is nil, this makes the buffer a single-byte buffer.
390 The buffer contents remain unchanged as a sequence of bytes
391 but the contents viewed as characters do change.
392 \[Emacs 20.3 emulating function]"
393   (setq mc-flag flag)
394   )
395
396
397 ;;; @ character
398 ;;;
399
400 (defalias 'char-charset 'char-leading-char)
401
402 (defun split-char (character)
403   "Return list of charset and one or two position-codes of CHARACTER."
404   (let ((p (1- (char-bytes character)))
405         dest)
406     (while (>= p 1)
407       (setq dest (cons (- (char-component character p) 128) dest)
408             p (1- p)))
409     (cons (char-charset character) dest)))
410
411 (defmacro char-next-index (char index)
412   "Return index of character succeeding CHAR whose index is INDEX."
413   (` (+ (, index) (char-bytes (, char)))))
414
415 ;;; @@ obsoleted aliases
416 ;;;
417 ;;; You should not use them.
418
419 (defalias 'char-length 'char-bytes)
420 ;;(defalias 'char-columns 'char-width)
421
422
423 ;;; @ string
424 ;;;
425
426 (defalias 'string-columns 'string-width)
427
428 (defalias 'string-to-int-list 'string-to-char-list)
429
430 (or (fboundp 'truncate-string)
431     ;; Imported from Mule-2.3
432     (defun truncate-string (str width &optional start-column)
433       "\
434 Truncate STR to fit in WIDTH columns.
435 Optional non-nil arg START-COLUMN specifies the starting column.
436 \[emu-mule.el; Mule 2.3 emulating function]"
437       (or start-column
438           (setq start-column 0))
439       (let ((max-width (string-width str))
440             (len (length str))
441             (from 0)
442             (column 0)
443             to-prev to ch)
444         (if (>= width max-width)
445             (setq width max-width))
446         (if (>= start-column width)
447             ""
448           (while (< column start-column)
449             (setq ch (aref str from)
450                   column (+ column (char-width ch))
451                   from (+ from (char-bytes ch))))
452           (if (< width max-width)
453               (progn
454                 (setq to from)
455                 (while (<= column width)
456                   (setq ch (aref str to)
457                         column (+ column (char-width ch))
458                         to-prev to
459                         to (+ to (char-bytes ch))))
460                 (setq to to-prev)))
461           (substring str from to))))
462     )
463
464 (defalias 'looking-at-as-unibyte 'looking-at)
465
466
467 ;;; @ regulation
468 ;;;
469
470 (defun regulate-latin-char (chr)
471   (cond ((and (<= ?\e$B#A\e(B chr)(<= chr ?\e$B#Z\e(B))
472          (+ (- chr ?\e$B#A\e(B) ?A))
473         ((and (<= ?\e$B#a\e(B chr)(<= chr ?\e$B#z\e(B))
474          (+ (- chr ?\e$B#a\e(B) ?a))
475         ((eq chr ?\e$B!%\e(B) ?.)
476         ((eq chr ?\e$B!$\e(B) ?,)
477         (t chr)))
478
479 (defun regulate-latin-string (str)
480   (let ((len (length str))
481         (i 0)
482         chr (dest ""))
483     (while (< i len)
484       (setq chr (sref str i))
485       (setq dest (concat dest
486                          (char-to-string (regulate-latin-char chr))))
487       (setq i (+ i (char-bytes chr))))
488     dest))
489
490
491 ;;; @ CCL
492 ;;;
493 (require 'ccl)
494
495 (defconst ccl-use-symbol-as-program nil
496   "t if CCL related builtins accept symbol as CCL program.
497 (20.2 with ExCCL, 20.3 or later)
498 Otherwise nil (20.2 without ExCCL or former).
499
500 Because emu provides functions accepting symbol as CCL program,
501 user programs should not refer this variable.")
502
503 (defun make-ccl-coding-system
504   (coding-system mnemonic doc-string decoder encoder)
505   "Define a new CODING-SYSTEM (symbol) by CCL programs
506 DECODER (symbol) and ENCODER (symbol)."
507   (setq decoder (symbol-value decoder)
508         encoder (symbol-value encoder))
509   (make-coding-system coding-system 4 mnemonic doc-string
510                       nil ; Mule takes one more optional argument: EOL-TYPE.
511                       (cons decoder encoder)))
512
513 (eval-when-compile
514   (define-ccl-program test-ccl-eof-block
515     '(1
516       (read r0)
517       (write "[EOF]")))
518
519   (make-ccl-coding-system
520    'test-ccl-eof-block-cs ?T "CCL_EOF_BLOCK tester"
521    'test-ccl-eof-block 'test-ccl-eof-block)
522   )
523
524 (defconst ccl-encoder-eof-block-is-broken
525   (eval-when-compile
526     (not (equal (encode-coding-string "" 'test-ccl-eof-block-cs)
527                 "[EOF]")))
528   "t if CCL_EOF_BLOCK is not executed when coding system encounts EOF on
529 encoding.")
530
531 (defconst ccl-decoder-eof-block-is-broken
532   (eval-when-compile
533     (not (equal (decode-coding-string "" 'test-ccl-eof-block-cs)
534                 "[EOF]")))
535   "t if CCL_EOF_BLOCK is not executed when coding system encounts EOF on
536 decoding.")
537
538 (defconst ccl-eof-block-is-broken
539   (or ccl-encoder-eof-block-is-broken
540       ccl-decoder-eof-block-is-broken))
541
542 (defun ccl-execute (ccl-prog reg)
543   "Execute CCL-PROG with registers initialized by REGISTERS.
544 If CCL-PROG is symbol, it is dereferenced.
545 \[Emacs 20.3 emulating function]"
546   (exec-ccl
547    (if (symbolp ccl-prog) (symbol-value ccl-prog) ccl-prog)
548    reg))
549
550 (defun ccl-execute-on-string (ccl-prog status string &optional contin)
551   "Execute CCL-PROG with initial STATUS on STRING.
552 If CCL-PROG is symbol, it is dereferenced.
553 \[Emacs 20.3 emulating function]"
554   (exec-ccl-string
555    (if (symbolp ccl-prog) (symbol-value ccl-prog) ccl-prog)
556    string status))
557
558
559 ;;; @ end
560 ;;;
561
562 (provide 'emu-mule)
563
564 ;;; emu-mule.el ends here