*** empty log message ***
[bpt/emacs.git] / lisp / arc-mode.el
index b6a969d..dc623e2 100644 (file)
@@ -1,6 +1,7 @@
 ;;; arc-mode.el --- simple editing of archives
 
-;; Copyright (C) 1995, 1997, 1998, 2003, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1997, 1998, 2001, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Morten Welinder <terra@gnu.org>
 ;; Keywords: archives msdog editing major-mode
@@ -20,8 +21,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
   (make-temp-name
    (expand-file-name (if (eq system-type 'ms-dos) "ar" "archive.tmp")
                     temporary-file-directory))
-  "Directory for temporary files made by arc-mode.el."
+  "Directory for temporary files made by `arc-mode.el'."
   :type 'directory
   :group 'archive)
 
@@ -224,8 +225,7 @@ Archive and member name will be added."
     '("unzip" "-qq" "-c"))
   "*Program and its options to run in order to extract a zip file member.
 Extraction should happen to standard output.  Archive and member name will
-be added.  If `archive-zip-use-pkzip' is non-nil then this program is
-expected to extract to a file junking the directory part of the name."
+be added."
   :type '(list (string :tag "Program")
                (repeat :tag "Options"
                        :inline t
@@ -464,10 +464,12 @@ Each descriptor is a vector of the form
 (defsubst archive-name (suffix)
   (intern (concat "archive-" (symbol-name archive-subtype) "-" suffix)))
 
-(defun archive-l-e (str &optional len)
-  "Convert little endian string/vector to integer.
-Alternatively, first argument may be a buffer position in the current buffer
-in which case a second argument, length, should be supplied."
+(defun archive-l-e (str &optional len float)
+  "Convert little endian string/vector STR to integer.
+Alternatively, STR may be a buffer position in the current buffer
+in which case a second argument, length LEN, should be supplied.
+FLOAT, if non-nil, means generate and return a float instead of an integer
+\(use this for numbers that can overflow the Emacs integer)."
   (if (stringp str)
       (setq len (length str))
     (setq str (buffer-substring str (+ str len))))
@@ -475,7 +477,8 @@ in which case a second argument, length, should be supplied."
         (i 0))
     (while (< i len)
       (setq i (1+ i)
-            result (+ (ash result 8) (aref str (- len i)))))
+            result (+ (if float (* result 256.0) (ash result 8))
+                     (aref str (- len i)))))
     result))
 
 (defun archive-int-to-mode (mode)
@@ -567,7 +570,7 @@ the mode is invalid.  If ERROR is nil then nil will be returned."
     (format "%02d:%02d:%02d" hour minute second)))
 
 (defun archive-unixdate (low high)
-  "Stringify unix (LOW HIGH) date."
+  "Stringify Unix (LOW HIGH) date."
   (let ((str (current-time-string (cons high low))))
     (format "%s-%s-%s"
            (substring str 8 10)
@@ -575,7 +578,7 @@ the mode is invalid.  If ERROR is nil then nil will be returned."
            (substring str 20 24))))
 
 (defun archive-unixtime (low high)
-  "Stringify unix (LOW HIGH) time."
+  "Stringify Unix (LOW HIGH) time."
   (let ((str (current-time-string (cons high low))))
     (substring str 11 19)))
 
@@ -587,7 +590,7 @@ the mode is invalid.  If ERROR is nil then nil will be returned."
 
 (defun archive-get-descr (&optional noerror)
   "Return the descriptor vector for file at point.
-Does not signal an error if optional second argument NOERROR is non-nil."
+Does not signal an error if optional argument NOERROR is non-nil."
   (let ((no (archive-get-lineno)))
     (if (and (>= (point) archive-file-list-start)
              (< no (length archive-files)))
@@ -761,7 +764,7 @@ when parsing the archive."
 
 (defun archive-alternate-display ()
   "Toggle alternative display.
-To avoid very long lines some archive mode don't show all information.
+To avoid very long lines archive mode does not show all information.
 This function changes the set of information shown for each files."
   (interactive)
   (setq archive-alternate-display (not archive-alternate-display))
@@ -800,17 +803,13 @@ using `make-temp-file', and the generated name is returned."
              (archive-name
               (or (and archive-subfile-mode (aref archive-subfile-mode 0))
                   archive)))
-         (make-directory archive-tmpdir t)
-         ;; If ARCHIVE includes leading directories, make sure they
-         ;; exist under archive-tmpdir.
-         (let ((arch-dir (file-name-directory archive)))
-           (if arch-dir
-               (make-directory (concat
-                                (file-name-as-directory archive-tmpdir)
-                                arch-dir)
-                               t)))
          (setq archive-local-name
                (archive-unique-fname archive-name archive-tmpdir))
+         ;; Maked sure all the leading directories in
+         ;; archive-local-name exist under archive-tmpdir, so that
+         ;; the directory structure recorded in the archive is
+         ;; reconstructed in the temporary directory.
+         (make-directory (file-name-directory archive-local-name) t)
          (save-restriction
            (widen)
            (write-region start (point-max) archive-local-name nil 'nomessage))
@@ -864,20 +863,26 @@ using `make-temp-file', and the generated name is returned."
   "Set the current buffer as if it were visiting FILENAME."
   (save-excursion
     (goto-char (point-min))
-    (let ((coding
+    (let ((buffer-undo-list t)
+         (coding
           (or coding-system-for-read
               (and set-auto-coding-function
                    (save-excursion
                      (funcall set-auto-coding-function
                               filename (- (point-max) (point-min)))))
-              ;; dos-w32.el defines find-operation-coding-system for
-              ;; DOS/Windows systems which preserves the coding-system
-              ;; of existing files.  We want it to act here as if the
-              ;; extracted file existed.
+              ;; dos-w32.el defines the function
+              ;; find-buffer-file-type-coding-system for DOS/Windows
+              ;; systems which preserves the coding-system of existing files.
+              ;; (That function is called via file-coding-system-alist.)
+              ;; Here, we want it to act as if the extracted file existed.
+              ;; The following let-binding of file-name-handler-alist forces
+              ;; find-file-not-found-set-buffer-file-coding-system to ignore
+              ;; the file's name (see dos-w32.el).
               (let ((file-name-handler-alist
                      '(("" . archive-file-name-handler))))
-                (car (find-operation-coding-system 'insert-file-contents
-                                                   filename t))))))
+                (car (find-operation-coding-system
+                      'insert-file-contents
+                      (cons filename (current-buffer)) t))))))
       (if (and (not coding-system-for-read)
               (not enable-multibyte-characters))
          (setq coding
@@ -895,7 +900,7 @@ using `make-temp-file', and the generated name is returned."
 (defun archive-extract (&optional other-window-p event)
   "In archive mode, extract this entry of the archive into its own buffer."
   (interactive (list nil last-input-event))
-  (if event (mouse-set-point event))
+  (if event (posn-set-point (event-end event)))
   (let* ((view-p (eq other-window-p 'view))
         (descr (archive-get-descr))
          (ename (aref descr 0))
@@ -911,16 +916,18 @@ using `make-temp-file', and the generated name is returned."
          (read-only-p (or archive-read-only
                          view-p
                          (string-match file-name-invalid-regexp ename)))
+        (arcfilename (expand-file-name (concat arcname ":" iname)))
          (buffer (get-buffer bufname))
          (just-created nil))
-      (if buffer
+      (if (and buffer
+              (string= (buffer-file-name buffer) arcfilename))
           nil
        (setq archive (archive-maybe-copy archive))
+       (setq bufname (generate-new-buffer-name bufname))
         (setq buffer (get-buffer-create bufname))
         (setq just-created t)
         (with-current-buffer buffer
-          (setq buffer-file-name
-                (expand-file-name (concat arcname ":" iname)))
+          (setq buffer-file-name arcfilename)
           (setq buffer-file-truename
                 (abbreviate-file-name buffer-file-name))
           ;; Set the default-directory to the dir of the superior buffer.
@@ -1159,13 +1166,13 @@ With a prefix argument, mark that many files."
   "In archive mode, un-mark this member if it is marked to be deleted.
 With a prefix argument, un-mark that many files forward."
   (interactive "p")
-  (archive-flag-deleted p ? ))
+  (archive-flag-deleted p ?\s))
 
 (defun archive-unflag-backwards (p)
   "In archive mode, un-mark this member if it is marked to be deleted.
 With a prefix argument, un-mark that many members backward."
   (interactive "p")
-  (archive-flag-deleted (- p) ? ))
+  (archive-flag-deleted (- p) ?\s))
 
 (defun archive-unmark-all-files ()
   "Remove all marks."
@@ -1175,8 +1182,8 @@ With a prefix argument, un-mark that many members backward."
     (save-excursion
       (goto-char archive-file-list-start)
       (while (< (point) archive-file-list-end)
-        (or (= (following-char) ? )
-            (progn (delete-char 1) (insert ? )))
+        (or (= (following-char) ?\s)
+            (progn (delete-char 1) (insert ?\s)))
         (forward-line 1)))
     (restore-buffer-modified-p modified)))
 
@@ -1214,7 +1221,7 @@ Use \\[archive-unmark-all-files] to remove all marks."
 (defun archive-chmod-entry (new-mode)
   "Change the protection bits associated with all marked or this member.
 The new protection bits can either be specified as an octal number or
-as a relative change like \"g+rw\" as for chmod(2)"
+as a relative change like \"g+rw\" as for chmod(2)."
   (interactive "sNew mode (octal or relative): ")
   (if archive-read-only (error "Archive is read-only"))
   (let ((func (archive-name "chmod-entry")))
@@ -1333,13 +1340,14 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
       (let* ((namefld (buffer-substring (+ p 2) (+ p 2 13)))
             (fnlen   (or (string-match "\0" namefld) 13))
             (efnname (substring namefld 0 fnlen))
-             (csize   (archive-l-e (+ p 15) 4))
+            ;; Convert to float to avoid overflow for very large files.
+             (csize   (archive-l-e (+ p 15) 4 'float))
              (moddate (archive-l-e (+ p 19) 2))
              (modtime (archive-l-e (+ p 21) 2))
-             (ucsize  (archive-l-e (+ p 25) 4))
+             (ucsize  (archive-l-e (+ p 25) 4 'float))
             (fiddle  (string= efnname (upcase efnname)))
              (ifnname (if fiddle (downcase efnname) efnname))
-             (text    (format "  %8d  %-11s  %-8s  %s"
+             (text    (format "  %8.0f  %-11s  %-8s  %s"
                               ucsize
                               (archive-dosdate moddate)
                               (archive-dostime modtime)
@@ -1352,7 +1360,11 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
                           visual)
              files (cons (vector efnname ifnname fiddle nil (1- p))
                           files)
-              p (+ p 29 csize))))
+             ;; p needs to stay an integer, since we use it in char-after
+             ;; above.  Passing through `round' limits the compressed size
+             ;; to most-positive-fixnum, but if the compressed size exceeds
+             ;; that, we cannot visit the archive anyway.
+              p (+ p 29 (round csize)))))
     (goto-char (point-min))
     (let ((dash (concat "- --------  -----------  --------  "
                        (make-string maxlen ?-)
@@ -1361,7 +1373,7 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
              dash)
       (archive-summarize-files (nreverse visual))
       (insert dash
-             (format "  %8d                         %d file%s"
+             (format "  %8.0f                         %d file%s"
                      totalsize
                      (length files)
                      (if (= 1 (length files)) "" "s"))
@@ -1395,9 +1407,10 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
     (while (progn (goto-char p)                ;beginning of a base header.
                  (looking-at "\\(.\\|\n\\)\\(.\\|\n\\)-l[hz][0-9ds]-"))
       (let* ((hsize   (char-after p))  ;size of the base header (level 0 and 1)
-            (csize   (archive-l-e (+ p 7) 4)) ;size of a compressed file to follow (level 0 and 2),
+            ;; Convert to float to avoid overflow for very large files.
+            (csize   (archive-l-e (+ p 7) 4 'float)) ;size of a compressed file to follow (level 0 and 2),
                                        ;size of extended headers + the compressed file to follow (level 1).
-             (ucsize  (archive-l-e (+ p 11) 4))        ;size of an uncompressed file.
+             (ucsize  (archive-l-e (+ p 11) 4 'float)) ;size of an uncompressed file.
             (time1   (archive-l-e (+ p 15) 2)) ;date/time (MSDOS format in level 0, 1 headers
             (time2   (archive-l-e (+ p 17) 2)) ;and UNIX format in level 2 header.)
             (hdrlvl  (char-after (+ p 20))) ;header level
@@ -1473,12 +1486,12 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
                          (archive-unixtime time1 time2)
                        (archive-dostime time1)))
        (setq text    (if archive-alternate-display
-                         (format "  %8d  %5S  %5S  %s"
+                         (format "  %8.0f  %5S  %5S  %s"
                                  ucsize
                                  (or uid "?")
                                  (or gid "?")
                                  ifnname)
-                       (format "  %10s  %8d  %-11s  %-8s  %s"
+                       (format "  %10s  %8.0f  %-11s  %-8s  %s"
                                modestr
                                ucsize
                                moddate
@@ -1493,9 +1506,13 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
              files (cons (vector prname ifnname fiddle mode (1- p))
                           files))
        (cond ((= hdrlvl 1)
-              (setq p (+ p hsize 2 csize)))
+              ;; p needs to stay an integer, since we use it in goto-char
+              ;; above.  Passing through `round' limits the compressed size
+              ;; to most-positive-fixnum, but if the compressed size exceeds
+              ;; that, we cannot visit the archive anyway.
+              (setq p (+ p hsize 2 (round csize))))
              ((or (= hdrlvl 2) (= hdrlvl 0))
-              (setq p (+ p thsize 2 csize))))
+              (setq p (+ p thsize 2 (round csize)))))
        ))
     (goto-char (point-min))
     (set-buffer-multibyte default-enable-multibyte-characters)
@@ -1508,8 +1525,8 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
                       "M   Length    Uid    Gid  File\n"
                    "M   Filemode    Length  Date         Time      File\n"))
          (sumline (if archive-alternate-display
-                      "  %8d                %d file%s"
-                    "              %8d                         %d file%s")))
+                      "  %8.0f                %d file%s"
+                    "              %8.0f                         %d file%s")))
       (insert header dash)
       (archive-summarize-files (nreverse visual))
       (insert dash
@@ -1605,7 +1622,8 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
             ;; (method  (archive-l-e (+ p 10) 2))
              (modtime (archive-l-e (+ p 12) 2))
              (moddate (archive-l-e (+ p 14) 2))
-             (ucsize  (archive-l-e (+ p 24) 4))
+            ;; Convert to float to avoid overflow for very large files.
+             (ucsize  (archive-l-e (+ p 24) 4 'float))
              (fnlen   (archive-l-e (+ p 28) 2))
              (exlen   (archive-l-e (+ p 30) 2))
              (fclen   (archive-l-e (+ p 32) 2))
@@ -1631,7 +1649,7 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
                           (string= (upcase efnname) efnname)))
              (ifnname (if fiddle (downcase efnname) efnname))
             (width (string-width ifnname))
-             (text    (format "  %10s  %8d  %-11s  %-8s  %s"
+             (text    (format "  %10s  %8.0f  %-11s  %-8s  %s"
                              modestr
                               ucsize
                               (archive-dosdate moddate)
@@ -1657,7 +1675,7 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
              dash)
       (archive-summarize-files (nreverse visual))
       (insert dash
-             (format "              %8d                         %d file%s"
+             (format "              %8.0f                         %d file%s"
                      totalsize
                      (length files)
                      (if (= 1 (length files)) "" "s"))
@@ -1711,7 +1729,8 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
       (let* ((next    (1+ (archive-l-e (+ p 6) 4)))
              (moddate (archive-l-e (+ p 14) 2))
              (modtime (archive-l-e (+ p 16) 2))
-             (ucsize  (archive-l-e (+ p 20) 4))
+            ;; Convert to float to avoid overflow for very large files.
+             (ucsize  (archive-l-e (+ p 20) 4 'float))
             (namefld (buffer-substring (+ p 38) (+ p 38 13)))
             (dirtype (char-after (+ p 4)))
             (lfnlen  (if (= dirtype 2) (char-after (+ p 56)) 0))
@@ -1735,7 +1754,7 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
             (fiddle  (and (= lfnlen 0) (string= efnname (upcase efnname))))
              (ifnname (if fiddle (downcase efnname) efnname))
             (width (string-width ifnname))
-             (text    (format "  %8d  %-11s  %-8s  %s"
+             (text    (format "  %8.0f  %-11s  %-8s  %s"
                               ucsize
                               (archive-dosdate moddate)
                               (archive-dostime modtime)
@@ -1757,7 +1776,7 @@ This doesn't recover lost files, it just undoes changes in the buffer itself."
              dash)
       (archive-summarize-files (nreverse visual))
       (insert dash
-             (format "  %8d                         %d file%s"
+             (format "  %8.0f                         %d file%s"
                      totalsize
                      (length files)
                      (if (= 1 (length files)) "" "s"))