1 ;;; tinylibb.el --- Library of (b)ackward compatible functions.
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1998-2007 Jari Aalto
8 ;; Keywords: extensions
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinylibb-version.
13 ;; Look at the code with folding.el
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
37 ;; ........................................................ &t-install ...
38 ;; DO NOT LOAD THIS FILE, but load the central library "m". It loads this
39 ;; file and autoload library "a"
41 ;; (require 'tinylibm)
46 ;; ..................................................... &t-commentary ...
52 ;; This is lisp function library, package itself does nothing.
53 ;; This library defines new [X]Emacs release functions for older
58 ;; You must not autoload this package; but always include
60 ;; (require 'tinylibm)
62 ;; Yes, there is no typo, you load "m" lib. It will handle arranging
63 ;; everything for you. This library is included by "m" library
64 ;; automatically. Repeat: you DO NOT PUT any of these in your
68 ;; (require 'tinyliba)
69 ;; (require 'tinylibb)
70 ;; (require 'tinylibo)
71 ;; (require 'tinyliby)
73 ;; A single statement will arrange everything:
75 ;; (require 'tinylibm)
79 ;; 2000-09-12 <ttn@revel.glug.org> in gnu.emacs.sources
80 ;; http://www.glug.org/people/ttn/software/ttn-pers-elisp/ reported that:
81 ;; New file core/veneration.el allows GNU Emacs 19 support.
82 ;; In this file some functions are available
83 ;; in GNU Emacs 20, but not in GNU Emacs 19: `compose-mail' and
84 ;; minimal supporting functions (see mail-n-news/compose-mail.el),
85 ;; `shell-command-to-string', and `char-before'. We also redefine
86 ;; `match-data' to handle arguments.
88 ;; 1998-10 SEMI's poe*el libraries also emulate various Emacs
97 ;;; .......................................................... provide ...
102 ;;{{{ code: Emacs compatibility, aliases, byteCompiler
105 (defvar temporary-file-directory)
106 (autoload 'ti::replace-match "tinylibm"))
108 ;;; ....................................................... &emulation ...
110 (defun-maybe force-mode-line-update ()
111 ;; XEmacs, labels this obsolete
112 ;; In older Emacs it does not exist
113 (set-buffer-modified-p (buffer-modified-p)))
115 (defun-maybe eval-after-load (arg1 form) ;; XEmacs 19.14 doesn't have this
116 ;; "A simple emulation. Eval FORM immediately."
120 ;; Some XEmacs doesn't have 'buffer-flush-undo
121 (defalias-maybe 'buffer-disable-undo 'buffer-flush-undo)
123 (defalias-maybe 'number-to-string 'int-to-string)
125 (defalias-maybe 'set-text-properties 'ignore)
127 (defalias-maybe 'string-to-number 'string-to-int)
129 ;; Doesn't exist in Emacs
130 (defalias-maybe 'read-directory-name 'read-file-name)
132 (and (fboundp 'insert-file-contents-literally)
133 ;; Emacs includes `insert-file-literally'.
134 (defalias-maybe 'insert-file-literally 'insert-file-contents-literally))
136 (defun-maybe make-local-hook (hook) ;; Exists in 19.30+
137 ;; "Make HOOK local to buffer."
138 ;; - I need locals so many times it make sme cry, e.g. post-command-hook
139 ;; - And why doesn't the add-hook accepts list by default ??
141 ;; - This aapplies to 19.29.1 and newer
142 ;; (add-hook HOOK FUNCTION &optional APPEND LOCAL)
143 ;; Do not use `make-local-variable' to make a hook
144 ;; variable buffer-local. Use `make-local-hook'
147 ;; the variable may be local already, but we do not do
149 (make-local-variable hook)
150 ;; Copy this because add-hook modifies the list structure.
151 (set hook (copy-sequence (eval hook))))
153 (defun-maybe find-buffer-visiting (file) ;not in XEmacs 19.14
154 ;; "Find buffer for FILE."
155 ;; file-truename dies if there is no directory part in the name
157 (or (and (string-match "^/" file)
158 (get-file-buffer (file-truename file)))
159 (get-file-buffer file)))
161 (defun-maybe backward-line (&optional arg)
162 (forward-line (if (integerp arg)
167 ;; "Absolute value of X."
172 (defun-maybe int-to-float (nbr)
173 "Convert integer NBR to float."
174 (read (concat (int-to-string nbr) ".0")))
176 (defun-maybe logtest (x y)
177 "Tinylibm: True if any bits set in X are also set in Y.
178 Just like the Common Lisp function of the same name."
179 (not (zerop (logand x y))))
181 (defun-maybe bin-string-to-int (8bit-string)
182 "Convert 8BIT-STRING string to integer."
183 (let* ((list '(128 64 32 16 8 4 2 1))
187 (if (not (string= "0" (substring 8bit-string i (1+ i))))
188 (setq int (+ int (nth i list) )))
192 (defun-maybe int-to-bin-string (n &optional length)
193 "Convert integer N to bit string (LENGTH, default 8)."
196 (s (make-string len ?0)))
198 (if (not (zerop (logand n (ash 1 i))))
199 (aset s (- len (1+ i)) ?1))
203 (defun-maybe int-to-hex-string (n &optional separator pad)
204 "Convert integer N to hex string. SEPARATOR between hunks is \"\".
205 PAD says to padd hex string with leading zeroes."
209 (function (lambda (x)
210 (setq x (format "%X" (logand x 255)))
219 (defun-maybe int-to-oct-string (n &optional separator)
220 "Convert integer N into Octal. SEPARATOR between hunks is \"\"."
224 (function (lambda (x)
225 (setq x (format "%o" (logand x 511)))
226 (if (= 1 (length x)) (concat "00" x)
227 (if (= 2 (length x)) (concat "0" x) x))))
228 (list (ash n -27) (ash n -18) (ash n -9) n)
231 (defun radix (str base)
232 "Convert STR according to BASE."
233 (let ((chars "0123456789abcdefghijklmnopqrstuvwxyz")
238 (setq i (string-match (make-string 1 c) chars))
239 (if (>= (or i 65536) base)
240 (error "%c illegal in base %d" c base))
241 (setq n (+ (* n base) i)))
245 (defun-maybe bin-to-int (str)
246 "Convert STR into binary."
249 (defun-maybe oct-to-int (str)
250 "Convert STR into octal."
253 (defun hex-to-int (str)
254 "Convert STR into hex."
255 (if (string-match "\\`0x" str)
256 (setq str (substring str 2)))
259 (defun-maybe int-to-net (float)
260 "Decode packed FLOAT 32 bit IP addresses."
261 (format "%d.%d.%d.%d"
262 (truncate (% float 256))
263 (truncate (% (/ float 256.0) 256))
264 (truncate (% (/ float (* 256.0 256.0)) 256))
265 (truncate (% (/ float (* 256.0 256.0 256.0)) 256))))
267 (defun-maybe rmac (string)
268 "Decode STRING x-mac-creator and x-mac-type numbers."
270 (setq string (format "%X" string)))
273 (while (< i (length string))
278 ;; EWas call to 'rhex'
279 (hex-to-int (concat (make-string 1 (aref string i))
280 (make-string 1 (aref string (1+ i)))))))
284 (defun-maybe ctime (time)
285 "Print a time_t TIME."
286 (if (and (stringp time) (string-match "\\`[0-9]+\\'" time))
287 (setq time (string-to-number (concat time ".0"))))
288 (let* ((top (floor (/ time (ash 1 16))))
289 ;; (bot (floor (mod time (1- (ash 1 16)))))
290 (bot (floor (- time (* (ash 1 16) (float top))))))
291 (current-time-string (cons top bot))))
294 "Random number in [0 .. N]."
299 (abs (% (random) n)))))
301 (defsubst-maybe rand1 (n)
302 "Random number [1 .. N]."
305 (defun-maybe randij (i j)
306 "Random number [I .. J]."
308 ((< i j) (+ i (rand0 (1+ (- j i)))))
310 ((> i j) (+ j (rand0 (1+ (- i j)))))
311 (t (error "randij wierdness %s %s"
313 (ti::string-value j)))))
315 ;;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... split ..
317 (unless (fboundp 'split-sting)
319 (defun ti::split-string (string &optional regexp level cont-level)
320 "Do not use this function. Call `split-string' instead.
321 This function exists, because current Emacs did not define `split-string' and
322 there is now alias which emulates the new Emacs behavior.
324 If called with only STRING, then split on white space.
329 REGEXP The delimiter in string, Default is '[\\f\\t\\n\\r\\v]+'
330 LEVEL The sub match in REGEXP to end reading substring.
332 CONT-LEVEL The sub match end to continue reading the STRING.
333 Default is 0 (REGEXP match's end point)
337 (split-string \"-I/dir1 -I/dir2\" \" *-I\")
338 --> '(\"/dir1\" \"/dir2\")"
343 (setq regexp "[ \f\t\n\r\v]+"))
349 ;; If no match, return as is '(string)
351 (if (null (string-match regexp string ))
352 (setq ret (list string))
353 (while (string-match regexp string start)
354 (setq str (substring string start (match-beginning level)))
355 (setq start (match-end cont-level))
356 ;; Ignore BOL matches. There is no string for us.
357 (if (> (match-beginning level) 0)
359 ;; Try with " test" --> '("test")
361 (< start (length string)))
362 (push (substring string start) ret)))
365 (defun-maybe split-string (string &optional separators)
366 ;; (split-string STRING &optional SEPARATORS)
367 ;; in XEmacs 19.14 subr.el
368 ;; "Split string on whitespace."
369 (ti::split-string string separators))
371 ;;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. higher Emacs . .
372 ;;: Features found from new emacs only 20.xx
374 ;; In simple.el, old Emacs does not have this.
375 (and (fboundp 'delete-indentation)
376 (defalias-maybe 'join-lines 'delete-indentation))
378 (defun-maybe replace-char-in-string (ch1 ch2 string)
379 ;; "Search CH1, change it with CH2 in STRING."
380 (nsubstitute ch1 ch2 string))
382 (defun-maybe string-prefix-p (s1 s2)
383 ;; "True if string S1 is a prefix of S2 (i.e. S2 starts with S1)"
384 (equal 0 (string-match (regexp-quote s1) s2)))
386 (put 'with-temp-buffer 'lisp-indent-function 0)
387 (put 'with-temp-buffer 'edebug-form-spec '(body))
388 (defmacro-maybe with-temp-buffer (&rest forms)
389 "Create a temporary buffer, and evaluate FORMS there like `progn'."
390 (let ((temp-buffer (make-symbol "temp-buffer")))
392 (let (((, temp-buffer)
393 (get-buffer-create (generate-new-buffer-name " *temp*"))))
396 (set-buffer (, temp-buffer))
398 (and (buffer-name (, temp-buffer))
399 (kill-buffer (, temp-buffer))) )))))
401 (defun-maybe byte-compiling-files-p ()
402 "Return t if currently byte-compiling files."
403 (string= (buffer-name) " *Compiler Input*"))
405 ;; #todo: This already exists in some XEmacs
407 (put 'with-output-to-string 'edebug-form-spec '(body))
408 (defmacro-maybe with-output-to-string (&rest body) ;XEmacs has this
409 "Please use `shell-command-to-string'. Execute BODY and return string."
412 (set-buffer (get-buffer-create " *string-output*"))
413 (setq buffer-read-only nil)
414 (buffer-disable-undo (current-buffer))
416 (let ((standard-output (current-buffer)))
420 ;;; ----------------------------------------------------------------------
422 (unless (fboundp 'with-buffer-unmodified)
423 ;; Appeared in Emacs 21.2
424 (put 'with-buffer-modified 'lisp-indent-function 0)
425 (put 'with-buffer-modified 'edebug-form-spec '(body))
426 (defmacro with-buffer-modified (&rest body)
427 "This FORM saves modified state during execution of body.
428 Suppose buffer is _not_ modified when you do something in the BODY,
429 e.g. set face properties: changing face also signifies
430 to Emacs that buffer has been modified. But the result is that when
431 BODY finishes; the original buffer modified state is restored.
433 This form will also make the buffer writable for the execution of body,
434 but at the end of form it will restore the possible read-only state as
435 seen my `buffer-read-only'
437 \(with-buffer-modified
438 (set-text-properties 1 10 '(face highlight)))
441 (` (let* ((Buffer-Modified (buffer-modified-p))
442 (Buffer-Read-Only buffer-read-only))
445 (setq buffer-read-only nil)
448 (set-buffer-modified-p t)
449 (set-buffer-modified-p nil))
451 (setq buffer-read-only t)
452 (setq buffer-read-only nil))))))
454 ;; `save-excursion' is expensive; use `save-current-buffer' instead
455 (put 'save-current-buffer 'edebug-form-spec '(body))
456 (defmacro-maybe save-current-buffer (&rest body)
457 "Save the current buffer; execute BODY; restore the current buffer.
458 Executes BODY just like `progn'."
459 (` (save-excursion (,@ body))))
461 (put 'with-current-buffer 'lisp-indent-function 1)
462 (put 'with-current-buffer 'edebug-form-spec '(body))
463 (defmacro-maybe with-current-buffer (buffer &rest body)
465 Execute the forms in BODY with BUFFER as the current buffer.
466 The value returned is the value of the last form in BODY.
467 See also `with-current-buffer'."
470 (set-buffer (, buffer))
473 (defmacro-maybe with-output-to-file (file &rest body)
474 "Open FILE and run BODY.
475 \(with-output-to-file \"foo\"
476 (print '(bar baz)))."
477 `(with-temp-file ,file
478 (let ((standard-output (current-buffer)))
481 ;; Emacs 19.30 and below don't have this
483 (defun-maybe match-string (level &optional string)
484 ;; "Read match from buffer at sub match LEVEL. Optionally from STRING.
485 ;;Return nil, if match at LEVEL doesn't exist.
487 ;;You have to call `looking-at' etc. before using this function.
488 ;;You can use use `ti::buffer-match' or `ti::string-match' directly too."
489 (if (match-end level)
493 (match-beginning level) (match-end level))
495 (match-beginning level) (match-end level)))))
497 ;; (replace-regexp-in-string
498 ;; REGEXP REP STRING &optional FIXEDCASE LITERAL SUBEXP START)
500 ;; (string regexp rep &optional subexp count)
502 (defun-maybe replace-regexp-in-string
503 (regexp rep string &optional fixedcase literal subexp start)
507 (while (string-match regexp string)
508 (if (> (incf i) 5000)
509 (error "Substituted string causes circular match. Loop never ends.")
510 (inline (setq string (ti::replace-match subexp rep string)))))
513 (defun-maybe buffer-substring-no-properties (beg end)
514 (ti::remove-properties (buffer-substring beg end)))
516 ;; Here's the pre-Emacs 20.3 definition. Note the optional arg.
518 (defun-maybe match-string-no-properties (num &optional string)
519 ;; "Return string of text matched by last search, without text properties.
520 ;; NUM specifies which parenthesized expression in the last regexp.
521 ;; Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
522 ;; Zero means the entire text matched by the whole regexp or whole string.
523 ;; STRING should be given if the last search was by `string-match' on STRING."
524 (if (match-beginning num)
527 (substring string (match-beginning num) (match-end num))))
528 (set-text-properties 0 (length result) nil result)
530 (buffer-substring-no-properties (match-beginning num)
533 ;; This is from pcvs.el
534 (defun-maybe file-to-string (file &optional oneline args)
535 "Read the content of FILE and return it as a string.
536 If ONELINE is t, only the first line (no \\n) will be returned.
537 If ARGS is non-nil, the file will be executed with ARGS as its
538 arguments. If ARGS is not a list, no argument will be passed."
544 file nil t nil (when (listp args) args))
545 (insert-file-contents file))
546 (buffer-substring (point-min)
548 (progn (goto-char (point-min))
554 (defun-maybe file-name-extension (filename)
555 (ti::file-get-extension filename))
557 (defun-maybe file-name-sans-extension (filename)
558 ;; "Return FILENAME without extension."
559 (replace-regexp-in-string "\\.[^.]+$" "" filename))
561 ;; Emacs 20.3 invented its own function names `line-beginning-position'
562 ;; `line-end-position' while XEmacs already had had point-* function
563 ;; names since 1996: `point-at-eol' and `point-at-bol'.
565 (defsubst-maybe line-beginning-position (&optional n)
566 "Return begin position of line forward N."
570 (beginning-of-line) (point)))
572 (defsubst-maybe line-end-position (&optional n)
573 "Return end position of line forward N."
577 (end-of-line) (point)))
579 (defsubst-maybe insert-file-literally (file) ;; XEmacs 21.4 does not have this
580 "Insert contents of file FILENAME into buffer after point with no conversion."
581 (let (find-file-hooks
588 (if (locate-library "executable") ;; 20.4 defines this
589 (autoload 'executable-find "executable")
590 (defun-maybe executable-find (program-name)
591 ;; "Find PROGRAM-NAME along `exec-path'."
592 (ti::file-get-load-path program-name exec-path))))
594 (defun-maybe executable-find-in-system (program-name) ;Handle Win32 case too.
595 ;; "Find PROGRAM-NAME along `exec-path'.
596 ;; The PROGRAM-NAME should not contain system dependent prefixes; an
597 ;; .exe is added automatically on PC."
599 (or (executable-find (concat program-name ".exe"))
600 (executable-find (concat program-name ".com"))
601 (executable-find (concat program-name ".bat"))
602 (executable-find (concat program-name ".cmd")))
603 (executable-find program-name)))
605 ;;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. XEmacs20 char . .
607 (defmacro ti::compat-character-define-macro (function1 function2)
608 "Define XEmacs compatible character FUNCTION2 as an alias for FUNCTION1."
610 (when (or (not (fboundp (, function1)))
612 (fboundp (, function1))
613 (or (not (equal (symbol-function (, function1))
615 ;; If the definition is 'ignore, reassign correct
617 (equal (symbol-function (, function1))
619 (defalias (, function1) (, function2)))))
621 (defun ti::compat-char-int-p (ch) ;Not in Emacs (in XEmacs20 MULE)
623 (> ch -1) ;valid range 0-255
626 (defun ti::compat-define-compatibility-defalias ()
627 "Emacs and XEmacs compatibility.
628 Define XEmacs character functions to work in Emacs.
629 Function mappings are:
634 chars-in-string length
636 char-int-p ti::compat-char-int-p
638 ;; - In Emacs the characters are treated as integers
639 ;; - In XEmacs charactersa are their own data type
640 (dolist (elt '((int-to-char identity)
642 ;; Not in Emacs (exist in XEmacs 20)
643 (char-to-int identity)
644 ;; Emacs 20.2/20.3 change
645 (chars-in-string length)
646 ;; exists only in XEmacs
647 (characterp integerp)
648 (char-int-p ti::compat-char-int-p)
649 (char-int identity)))
650 (multiple-value-bind (original alias) elt
651 (ti::compat-character-define-macro original alias))))
653 (ti::compat-define-compatibility-defalias)
655 (defun-maybe char= (ch1 ch2 &optional ignored-arg) ;exists in XEmacs 20.1
656 (let* (case-fold-search) ;case sensitive
657 (char-equal ch1 ch2)))
659 ;; eshell-mode.el fix
660 (eval-after-load "eshell-mode"
661 '(progn (ti::compat-define-compatibility-defalias)))
663 ;; eshell-2.4.1/esh-mode.el mistakenly defines characterp
664 ;; as alias to `ignore' => breaks many things
665 (eval-after-load "esh-mode"
666 '(progn (ti::compat-define-compatibility-defalias)))
668 ;; Gnus MIME handling also behaves wrong
669 (eval-after-load "mm-decode"
670 '(progn (ti::compat-define-compatibility-defalias)))
673 (defun-maybe count-char-in-string (c s)
674 "Count CHARACTER in STRING."
677 (while (< pos (length s))
678 (if (char= (aref s pos) c)
683 (defun-maybe count-char-in-region (beg end char)
684 "In region BEG END, count all CHAR occurrences.
685 E.g. to have real line count in buffer that
686 is running folding.el or outline, you should not call
687 count-lines function , but (count-char-in-region ?\\n)"
688 (interactive "r\ncChar: ")
690 (setq end (max beg end)
691 char (char-to-string char))
693 (goto-char (min beg end))
694 (while (search-forward char end t)
697 (message "%d hits in region." i))
700 (defun-maybe char-assq (ch alist)
701 "If CH can be found in ALIST, return entry. If CH is nil, do nothing."
702 (let (case-fold-search
704 (while (and ch alist)
705 (setq ret (car alist))
706 (if (char= ch (car ret))
708 (setq alist (cdr alist)
712 ;; XEmacs : replace-in-string
714 (defun-maybe subst-char-in-string (fromchar tochar string &optional inplace)
715 "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
717 (let ((len (length string))
718 (ret (copy-sequence string))) ;because 'aset' is destructive
720 (if (char= (aref string (1- len)) fromchar)
721 (aset ret (1- len) tochar))
725 (defun-maybe subst-char-with-string (string &optional char to-string)
726 "In STRING, convert CHAR with TO-STRING.
727 Default is to convert all tabs in STRING with spaces."
728 (let* ((len (length string))
733 ((not (and char to-string))
736 (untabify (point-min) (point-max))
737 (setq ret (buffer-string))))
740 (setq elt (char-to-string (aref string i)))
741 (if (char= char (aref string i))
742 (setq elt to-string))
743 (setq ret (concat ret elt))
748 (when (or (featurep 'xemacs)
749 (boundp 'xemacs-logo))
750 ;; Just a forward declaration, because byte-compiler cannot see through
751 ;; defun-maybe. If this function already exists, this autoload
752 ;; definition is no-op.
753 (autoload 'subst-char-in-string "tinylibb.el")))
755 ;; Emacs and XEmacs differ here. Convert Emacs function --> XEmacs name
758 ((and (fboundp 'exec-to-string)
759 (not (fboundp 'shell-command-to-string)))
760 (defalias-maybe 'shell-command-to-string 'exec-to-string))
761 ((not (fboundp 'shell-command-to-string))
762 (defun-maybe shell-command-to-string (command)
763 "Returns shell COMMAND's ouput as string. Tinylibm."
765 (shell-command command (current-buffer))
768 ;;; XEmacs ilisp.el :: describe-symbol-find-file
769 (defun-maybe describe-symbol-find-file (symbol) ;; XEmacs
770 "Find SYMBOL defined in file."
771 (loop for (file . load-data) in load-history
772 do (when (memq symbol load-data)
775 ;; shell.el, term.el, terminal.el
777 (unless (boundp 'explicit-shell-file-name)
778 (defvar explicit-shell-file-name nil))
780 (unless (boundp 'shell-command-output-buffer)
781 (defvar shell-command-output-buffer "*Shell Command Output*"))
783 (when (or (not (boundp 'temporary-file-directory))
784 (not (stringp temporary-file-directory))
785 (not (file-directory-p temporary-file-directory)))
786 (let* ((temp (or (getenv "TEMP")
789 (defvar temporary-file-directory ;Emacs 20.3
792 ((file-directory-p "/tmp") "/tmp")
793 ((file-directory-p "~/tmp") "~/tmp")
794 ((file-directory-p "C:/temp") "C:/temp")
795 ;; don't know what to do, maybe this exists.
797 "*Tinylib: XEmacs and Emacs compatibility.")))
799 ;;; ........................................................... &other ...
801 ;; Emacs 20.7 - 21.2 does not have this
802 (defun-maybe turn-off-font-lock ()
803 "Turn off font lock."
806 ;; Emacs 21.3 includes `turn-on-font-lock'
807 (defun-maybe turn-on-font-lock-mode ()
811 (defun-maybe turn-on-auto-fill-mode ()
812 "Turn on Auto Fill mode."
815 (defun font-lock-mode-maybe (&optional mode check-global)
816 "Pass MODE to function `font-lock-mode' only on color display.
817 If CHECK-GLOBAL is non-nil, the `global-font-lock-mode' flag must also
818 be non-nil before calling.
820 Usually there is no point of turning on `font-lock-mode' if Emacs
821 can't display colors, so this is is the umbrella function to
823 (when (and (featurep 'font-lock)
824 (ti::colors-supported-p)
825 (or (null check-global)
826 (and (boundp 'global-font-lock-mode)
827 (symbol-value 'global-font-lock-mode))))
828 (font-lock-mode mode)
831 (defun turn-on-font-lock-mode-maybe ()
832 "Call `font-lock-mode-maybe' with argument 1."
833 (font-lock-mode-maybe 1))
835 (defalias-maybe 'compose-mail 'mail)
837 (defun-maybe region-active-p () ;XEmacs function
838 "Return `mark' if mark (region) is active."
841 (boundp 'zmacs-regions))
842 (let* ((zmacs-regions t)) ;XEmacs
844 ((boundp 'mark-active) ;Emacs
845 (and (symbol-value 'mark-active)
846 ;; used to return (mark-marker)
849 ;; Newer advice "2.15" uses this call, make sure it exist.
850 (defalias-maybe 'byte-code-function-p 'ignore)
852 (defun-maybe add-to-list (list-var element)
853 ;; "Add to symbol LIST-VAR ELEMENT."
854 (or (member element (symbol-value list-var)) ;; copy from 19.34
855 (set list-var (cons element (symbol-value list-var)))))
857 (defun-maybe run-hook-with-args-until-success
858 (hook-sym &optional &rest args)
859 ;; "Run all functions in HOOK-SYM. Stop when first one return non-nil.
863 ;; HOOK-SYM hook symbol, or list of functions.
864 ;; ARGS arguments to functions. if NIL, functions
865 ;; are called without arguments."
866 (let* ((val (symbol-value hook-sym))
867 (list (if (listp val) val (list val))) ;Make list maybe
870 (while (and (null ret) list)
871 (setq func (car list) list (cdr list))
872 (setq ret (apply func args)))
875 (defun-maybe buffer-live-p (buffer)
876 ;; "Check if BUFFER exist."
878 ((not (bufferp buffer))
879 (error "must be pointer"))
883 (buffer-name buffer))))
886 ;; don't show "obsolete function warning", because we know what
887 ;; we're doing below.
888 (put 'frame-parameters 'byte-compile nil))
890 (when (not (fboundp 'frame-parameter)) ;Emacs 19.35
891 (if (fboundp 'frame-property)
892 (defalias 'frame-parameter 'frame-property) ; XEmacs.
893 (defun frame-parameter (frame property &optional default)
894 "Return FRAME's value for property PROPERTY."
895 (or (cdr (assq property (frame-parameters frame)))
898 (unless (and (fboundp 'find-file-binary) ;; Emacs function --> XEmacs
899 (boundp 'buffer-file-coding-system))
900 (defun find-file-binary (file)
901 "Read FILE without conversiosn."
902 (let* ((buffer-file-coding-system 'binary))
903 (unless buffer-file-coding-system
904 (setq buffer-file-coding-system nil)) ;Quiet Bytecompiler "unused var".
910 ;;; ........................................... &compatibility-special ...
911 ;;; These need emacs-p xemacs-p tests
913 ;; not known function in 19.14
916 (autoload 'read-kbd-macro "edmacro")
918 (or (fboundp 'kbd) ;Std in Emacs 20.x
919 (defmacro kbd (keys) ;(kbd "C-<delete>")
920 "Convert KEYS to the internal Emacs key representation.
921 KEYS should be a string constant in the format used for
922 saving keyboard macros (see `insert-kbd-macro')."
923 (let ((f 'read-kbd-macro))
924 (funcall f keys))))))
927 ;;{{{ code: function test
929 ;;; ...................................................... &func-tests ...
930 ;;; We define these here because they are used lated in this library
931 ;;; "define before using"
935 ;;; ----------------------------------------------------------------------
937 (defun-maybe functionp (obj) ;; Emacs 20.3+ XEmacs 20.x
939 (byte-code-function-p obj)
943 (eq (car obj) 'lambda))))
945 ;;; ----------------------------------------------------------------------
947 (defun ti::function-args-p (symbol)
948 "Return function SYMBOL's argument list as string or nil.
949 Works for byte compiled functions too.
952 if function is alias, the real function behind it is examined.
953 if function is in autoload state, \"(autoload-args)\" is returned."
954 (let* ((args-re-xemacs ;; arguments: (&optional BUFFER)
955 "arguments: +(\\([^)]+\\))")
956 (args-re ;; (buffer-size &optional BUFFER)
957 "([^(]+\\([^)]+)\\)")
962 (if (ti::autoload-p symbol)
963 ;; We can't know the args. And we don't want to find out,
964 ;; since it would load the package unnecessarily
965 (setq ret "(autoload-args)")
966 (if (setq sym (ti::defalias-p symbol))
968 (setq sym-func (symbol-function symbol))
970 (setq str (documentation sym-func))
971 (setq str (prin1-to-string sym-func)))
972 ;; "$ad-doc: mouse-yank-at-click$" (interactive "e\nP")
973 (when (and (string-match "ad-doc:" str)
977 (symbol-name symbol)))))
978 (setq str (prin1-to-string (symbol-function symbol))))
983 ((string-match "^#\\[(\\([^)]+\\)" str)
984 (setq ret (match-string 1 str)))
985 ((or (string-match "^(lambda[ \t]+nil" str)
986 (string-match "^#\\[nil" str))
988 ((string-match args-re str)
989 (setq ret (match-string 1 str))
994 ;; XEmacs has different Byte compilation format
995 ;; #<compiled-function (from "custom.elc") nil "...(7)
998 (concat "compiled-function +\(from.*\) +" args-re) str)
999 (setq ret (match-string 2)))
1000 ((string-match "^(lambda +nil" str)) ;bypass
1001 ((string-match args-re-xemacs str)
1002 (setq ret (match-string 1 str)))
1003 ((string-match args-re str)
1004 (setq ret (match-string 1 str)))))))
1007 ;;; --++-- --++-- --++-- --++-- --++-- --++-- --++-- eval-and-compile --
1010 ;;{{{ code: Cygwin support
1012 ;;; ........................................................... cygwin ...
1014 ;;; Patch for these functions has been submitted to Emacs 21.2
1017 (defvar w32-cygwin-mount-table nil
1018 "Cygwin mount.exe mapping. See `w32-cygwin-mount-table'.")
1020 ;;; ----------------------------------------------------------------------
1022 (put 'w32-cygwin-mount-table-dolist 'lisp-indent-function 0)
1023 (put 'w32-cygwin-mount-table-dolist 'edebug-form-spec '(body)) ;;#todo: not working
1024 (defmacro w32-cygwin-mount-table-dolist (&rest body)
1025 "Run DOLIST for Cygwin mount table.
1026 `mount' is complete mount element (cygwin . dos).
1027 Variables `cygwin' and `dos' are bound respectively."
1029 (dolist (mount w32-cygwin-mount-table)
1030 ;; mount => ("/tmp" . "c:\\temp")
1031 (let* ((cygwin (car mount))
1035 ;;; ----------------------------------------------------------------------
1037 (put 'w32-cygwin-shell-environment 'lisp-indent-function 0)
1038 (put 'w32-cygwin-shell-environment 'edebug-form-spec '(body))
1039 (defmacro w32-cygwin-shell-environment (&rest body)
1040 "Run BODY under Cygwin shell environment.
1041 For example, you you want to call program ´zgrep' which is not an
1042 .exe, but a shell program, you have to switch to the Cygwin context.
1044 (when (and (ti::win32-p)
1045 (ti::win32-cygwin-p))
1046 (w32-cygwin-shell-environment
1049 Variable ´shell-file-name' is locally bound during call."
1051 (let ((shell-file-name (format "%s/bin/hash.exe"
1052 (ti::win32-cygwin-p 'use-cache))))
1055 ;;; ----------------------------------------------------------------------
1057 (defun w32-cygwin-mount-table-parse ()
1058 ;; "Parse cygwin mount table from current point forward."
1060 ;; Search lines with backslash
1061 ;; f:\\u\\bin /usr/bin user binmode
1063 ;; Cygwin 1.3.3 changed format, it is now
1065 ;; f:\\u\\bin on /usr/bin type user (binmode)
1068 ;; \\network\path\this
1073 (if (re-search-forward "^\\([a-z]:\\|[\\][\\]\\).* on " nil t)
1075 "^\\([a-zA-Z]:[\\][^ \t\r\n]*"
1077 "\\|[\\][\\][^ \t\r\n]+"
1080 "\\(/[^ \t\r\n]*\\)")
1082 "^\\([a-zA-Z]:[\\][^ \t\r\n]*"
1084 "\\|[\\][\\][^ \t\r\n]+"
1087 "\\(/[^ \t\r\n]*\\)")))))
1088 (while (re-search-forward regexp nil t)
1089 (let ((dos (match-string 2))
1090 (cygwin (match-string 1)))
1091 (push (cons dos cygwin)
1094 ;; sort the entries so that the longest mounts come first and
1095 ;; last the shortest. This makes a difference when Cygwin paths are
1096 ;; converted back to dos:
1098 ;; /tmp/other mapping must be handled before /tmp
1106 (length (car b))))))))
1108 ;;; ----------------------------------------------------------------------
1110 (defun w32-cygwin-convert (path &optional flag)
1111 "Run `cygpath' to find out PATH.
1114 The default concersion is CYGWIN => DOS
1116 If `flag' is set, then the conversion is
1118 (let* ((cmd (executable-find "cygpath"))
1119 (option "--windows")
1123 (setq option "--unix"))
1132 (goto-char (point-min))
1133 (when (looking-at "^.*") ;; Filter newlines
1134 (setq ret (match-string 0)))))
1137 ;;; ----------------------------------------------------------------------
1139 (defun w32-cygwin-mount-table ()
1140 ;; "Return Cygwin mount table '((CYGWIN . DOS) ..) using `mount' command."
1141 (when ;; (memq system-type '(ms-dos windows-nt))
1143 ;; specifically request the .exe which must be along PATH
1144 ;; if we used only `mount', that could call user's "mount.bat" or
1146 (let ((cmd (executable-find "mount.exe")))
1149 (call-process cmd nil (current-buffer))
1150 (goto-char (point-min))
1152 ;; It's a serious error if "mount" does not say where
1153 ;; the ROOT "/" is. Should we do something?
1155 (goto-char (point-min))
1156 (let ((ret (w32-cygwin-mount-table-parse)))
1158 (error "Cygwin mount.exe output parse failed:\n[%s]"
1162 ;;; ----------------------------------------------------------------------
1164 (defun w32-cygwin-mount-point-to-dos (path)
1165 "Convert Cygwin mount filenames like /tmp to DOS paths."
1168 (dolist (cygwin w32-cygwin-mount-table)
1169 (when (string-match (concat "^" (car cygwin) "\\(.*\\)")
1172 ;; expand will ensure that slashes are after glue
1173 ;; to the same direction
1175 (concat (file-name-as-directory (cdr cygwin) )
1176 (match-string 1 path))))
1177 ;; It is difficult to expand the file name correctly because
1178 ;; user can make any mount points. That's what we compare which
1179 ;; mount point gives the longest match and return it.
1181 ;; E.g. the root / will always match, but it is not necessarily
1182 ;; the final answer given path /tmp/something where there is
1183 ;; separate mount point for longer match /tmp
1185 (if (null last-choice)
1186 (setq last-choice (cons (car cygwin) try))
1187 (if (length (> (car cygwin) (car last-choice)))
1188 (setq last-choice (cons (car cygwin) try))))))
1189 (if (null last-choice)
1191 (cdr last-choice))))
1193 ;;; ----------------------------------------------------------------------
1195 (defun w32-cygwin-mount-table-set ()
1196 ;; "Run mount.exe and set internal variable `w32-cygwin-mount-table'.
1197 ;; You should run this function after you have made a change to
1198 ;; cygwin mount points."
1200 (if (ti::win32-p) ;; (memq system-type '(ms-dos windows-nt))
1201 (setq w32-cygwin-mount-table
1202 (w32-cygwin-mount-table))))
1204 ;;; ----------------------------------------------------------------------
1206 (defun w32-cygwin-mount-table-path-to-dos (path)
1207 "Convert PATH to dos using cygwin mount table.
1208 You should not call this function, use `w32-cygwin-path-to-dos'."
1209 ;; Convert Cygwin /usr/local to DOS path. LOCATION/usr/local.
1210 ;; This relies on the fact that the longest paths are first
1211 ;; in the mount table.
1213 (w32-cygwin-mount-table-dolist
1214 ;; mount => ("/tmp" . "c:\\temp")
1215 ;; variables `cygwin' and `dos' are part of the macro
1216 (when (string-match (concat "^" (regexp-quote cygwin)
1219 (unless (string= cygwin "/")
1220 (setq dos (concat dos (match-string 1 path))))
1221 ;; Convert to forward slashes
1222 (setq final-path (subst-char-in-string ?\\ ?/ dos))
1225 ;; None matched, so this path is under cygwin root dir.
1226 (let ((root (ti::win32-cygwin-p)))
1227 (setq final-path (concat root path))))
1230 ;;; ----------------------------------------------------------------------
1232 (defun w32-cygwin-path-to-dos (path)
1233 "Convert cygwin like //c/temp or /cygdrive/c/temp path to
1234 dos notation c:/temp."
1235 ;; NOTE for cygwin and bash shell prompt
1236 ;; We can't require a slash after the drive letter, because
1237 ;; //c and /cygdrive/c are all top level roots.
1239 ;; The bash shell's PS1 setting \w (The current working directory)
1240 ;; Does not add trailing slash.
1242 ((or (string-match "^//\\([a-z]\\)/?$" path)
1243 (string-match "^/cygdrive/\\([a-z]\\)/?$" path))
1244 (concat (match-string 1 path) ":/"))
1245 ((or (string-match "^//\\([a-z]\\)\\(/.*\\)" path)
1246 (string-match "^/cygdrive/\\([a-z]\\)\\(/.*\\)" path))
1247 (concat (match-string 1 path) ":" (match-string 2 path)))
1248 ((string-match "^(/cygdrive/./\\|//" path)
1249 ;; if previous regexps couldn't handle it, this is severe error.
1250 (error "Invalid path format for cygwin %s" path))
1251 ((string-match "[\\]" path)
1252 (error "Invalid backslash path %s" path))
1253 ((string-match "^/" path)
1254 (w32-cygwin-mount-table-path-to-dos path))
1258 ;;; ----------------------------------------------------------------------
1260 (defun w32-cygwin-dos-path-to-cygwin (path)
1261 "Convert dos PATH to cygwin path.
1262 Be sure to call `expand-file-name' before you pass PATH to the function."
1264 ((string-match "\\([a-z]\\):[\\/]\\(.*\\)" path)
1265 (let ((drive (format "/cygdrive/%s/" (match-string 1 path)))
1266 (rest-path (match-string 2 path)))
1269 (w32-cygwin-mount-table-dolist
1270 ;; mount => ("/tmp" . "c:\\temp")
1271 ;; variables `cygwin' and `dos' are part of the macro
1272 (when (or (string-match (concat "^" dos "\\(.*\\)") path)
1273 (string-match (concat "^"
1274 ;; Convert to / slashes
1275 (expand-file-name dos)
1277 (when (match-string 1 path)
1278 (setq path (match-string 1 path))
1279 (setq cygwin (concat cygwin path)))
1280 ;; Convert to forward slashes
1281 (return (subst-char-in-string ?\\ ?/ cygwin)))))))
1283 (error "Cannot convert to cygwin. path is not absolute %s" path))))
1285 ;; Make it defconst, so that rereading tinylibb.el will always update
1286 ;; the value. If Cygwin is changed, reloading this library.
1288 (setq w32-cygwin-mount-table
1289 (if (ti::win32-p) ;; (memq system-type '(ms-dos windows-nt))
1290 (w32-cygwin-mount-table)))
1292 (defsubst w32-expand-file-name-for-cygwin (path)
1293 "Expand PATH to Cygwin notation if Cygwin is present."
1294 (when (and (string-match "^[A-Za-z]:" path)
1295 (ti::win32-cygwin-p))
1296 (setq path (w32-cygwin-dos-path-to-cygwin path)))
1299 (defsubst w32-expand-file-name-for-emacs (path)
1300 "Expand PATH to DOS Emacs notation if PATH is in Cygwin notation."
1302 ((and (ti::emacs-type-win32-p)
1303 (string-match "^/cygdrive" path))
1304 (setq path (w32-cygwin-path-to-dos path)))
1305 ((and (ti::emacs-type-cygwin-p)
1306 (string-match "^[a-zA-Z]:" path))
1307 (setq path (w32-cygwin-dos-path-to-cygwin path))))
1312 ;;; ########################################################## &custom ###
1317 ;;; - This code is beginning to be obsolete now when Newest Emacs is 21.2
1319 ;;; - This code does nothing if custom.el is present, so let it be here.
1323 ((string-match "2[0-9]\\." (emacs-version))
1324 (require 'custom)) ;Out of the box
1325 (t ;Well, this is old Emacs - lot of work
1326 (let* ((list load-path)
1331 ;; ..................................................... no custom ...
1332 ;; The reason why newest custom.el does not work in prior releases is the
1333 ;; new bacquote macro syntax it uses. It needs new emacs lisp parser to
1336 ((or (and (ti::emacs-p)
1337 (< emacs-minor-version 34))
1338 (and (eq 19 (ti::xemacs-p))
1339 (< emacs-minor-version 15)))
1340 ;; This emacs is too old for new custom. Emulate it.
1341 (defmacro defgroup (&rest args) nil)
1342 (defmacro defcustom (var value doc &rest args)
1343 (` (defvar (, var) (, value) (, doc)))))
1344 ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. custom maybe . .
1346 ;; Explanation: When I say (require 'custom) in -batch byte
1347 ;; compile; and the load-path HAD my private ~/elisp at front,
1348 ;; but it still loaded old custom.elc from XEmacs 19.14 distribution.
1350 ;; Why? Don't know. That's why we load it manually here.
1351 (while (and (null path) ;Where it is?
1352 (setq dir (car list)))
1354 (if (string-match "/$" dir)
1355 (concat dir "custom.el")
1356 (concat dir "/custom.el")))
1357 (when (file-exists-p try)
1358 ;;; (message (format "tinylibm: ** Using custom from [%s]" try))
1359 (setq path (file-name-directory try)))
1360 (setq list (cdr list)))
1361 ;; ............................................... load new custom ...
1364 ;; The new custom won't work in .el format, it must be
1365 ;; loaded in .elc format.
1366 (unless (featurep 'custom)
1367 (load (concat path "custom.elc"))))
1369 (message "tinylibm: ** Couldn't find custom.elc [compiled version]")))
1370 ;; Check few things, what this custom.elc provided.
1371 ;; This is internal information to debug things
1373 (message "tinylibm: ** internal info: Custom [%s] declare [%s]"
1374 (if (featurep 'custom)
1377 (if (fboundp 'custom-declare-variable)
1381 ((and (featurep 'custom)
1382 (fboundp 'custom-declare-variable))
1383 ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . case 1 ..
1384 ;; 19.14 includes a very old custom.el, and it shouldn't be used
1387 ;; custom-XE19.14 : custom.el::customize()
1388 ;; custom-1.96 : cus-edit.el::(defun customize (symbol)
1389 ;; custom-1.9956 : cus-edit.el:::customize()
1390 ;; cus-edit.el::customize-group (group)
1392 ((and (null (ti::function-args-p 'customize))
1393 (not (fboundp 'customize-group)))
1395 tinylibm.el: ** [Ignore, Compilation is still going fine...]
1396 ** Hm, loading custom didn't go quite right. Reasons:
1397 ** a. You have too old custom.el library, because I can't
1398 ** see `customize' function to take ONE argument.
1399 ** Be sure to have newest custom.el and cus-edit.el
1400 ** b. Your load-path is set so that the old custom.el
1403 ;; The new 1.9956 Custom.el produces warning for defcustom
1404 ;; variables not beeing defined. This code is only for
1405 ;; 19.34 and won't work anywhere else.
1408 "19.2[0-9]\\|19.3[0-3]\\|19.1[0-4]"
1411 ** ...But you don't have [X]Emacs 19.34, 19.15, or 20+
1412 ** That's why you see lot of undefined variables.
1413 ** It's a byte compiler issue, nothing to worry about.")
1414 ;; This is part of bytecomp.el in 20.1:
1416 (put 'custom-declare-variable 'byte-hunk-handler
1417 'byte-compile-file-form-custom-declare-variable)
1418 (defun byte-compile-file-form-custom-declare-variable (form)
1419 (if (memq 'free-vars byte-compile-warnings)
1420 (setq byte-compile-bound-variables
1421 (cons (nth 1 (nth 1 form))
1422 byte-compile-bound-variables))) form))))
1425 ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . case 2 ..
1427 (unless (string-match "19.2[0-9]\\|19.3[0-3]\\|19.1[0-4]"
1430 tinylibm.el: ** Too old custom.el; You should upgrade your Emacs."))
1431 ;; We have the old custom-library, hack around it.
1432 (defmacro defgroup (&rest args) nil)
1433 (defmacro defcustom (var value doc &rest args)
1434 (` (defvar (, var) (, value) (, doc))))))))))))
1438 ;;; ################################################### &byte-optimize ###
1442 (when (and nil ;Disabled now
1443 (null (get 'concat 'byte-optimizer)))
1444 (put 'concat 'byte-optimizer 'tinylibb-byte-optimize-concat)
1446 ;; Like `concat', but this macro expands to optimized form.
1447 ;; Many times you want to divide complex regexps on separate lines like
1449 ;; (looking-at (concat
1456 ;; This is perfectly good way, but won't be optimized in any way:
1457 ;; The compiled version contains `concat' command and separate strings.
1459 ;; This optimized `concat' macro will expand the ARGS to single string
1460 ;; "regexp-1regexp-2\ if they all are strings.
1461 ;; In other cases it expands to normal `concat' call.
1463 ;; (defmacro concat-macro (&rest args)
1464 ;; (if (every 'stringp args)
1465 ;; (apply 'concat args)
1466 ;; (cons 'concat args)))
1469 (defun tinylibb-byte-optimize-concat (form)
1470 (let ((args (cdr form))
1472 (while (and args constant)
1473 (or (byte-compile-constp (car args))
1475 (setq constant nil))
1476 (setq args (cdr args)))
1485 ;;; ......................................................... &version ...
1487 (defconst tinylibb-version
1488 (substring "$Revision: 2.73 $" 11 15)
1489 "Latest version number.")
1491 (defconst tinylibb-version-id
1492 "$Id: tinylibb.el,v 2.73 2007/05/01 17:20:45 jaalto Exp $"
1493 "Latest modification time and version number.")
1495 ;;; ----------------------------------------------------------------------
1497 (defun tinylibb-version (&optional arg)
1498 "Show version information. ARG will instruct to print message to echo area."
1500 (ti::package-version-info "tinylibb.el" arg))
1502 ;;; ----------------------------------------------------------------------
1504 (defun tinylibb-submit-bug-report ()
1505 "Submit bug report."
1507 (ti::package-submit-bug-report
1510 '(tinylibb-version-id)))
1514 ;;; tinylibb.el ends here