;;; cpio-entry-contents-mode.el --- minor mode for editing a cpio-entry's contents. -*- coding: utf-8 -*-
;; COPYRIGHT
;;
;; Copyright © 2019 Free Software Foundation, Inc.
;; All rights reserved.
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see .
;; Author: Douglas Lewan
;; Maintainer: Douglas Lewan
;; Created: 2017 Dec 06
;; yVersion: 0.17
;; Keywords: files
;;; Commentary:
;; This file contains code for editing and saving
;; the contents of entries in a cpio-archive.
;;; Documentation:
;;; Code:
;;
;; Hacks
;;
(defun entry-setup (arg &optional name depth)
"Set up buffers and windows for working on entry NAME.
If NAME is not given, then use 'aa'."
(interactive "P")
(if (and (called-interactively-p 'interactive)
arg)
(setq name (read-string "Name? ")))
(unless name (setq name "aa"))
(unless depth (setq depth 0))
(let* ((fname "entry-setup")
(short-archive-name "alphabet_small.crc.cpio")
(archive-name (if (string-match "alphabet/" default-directory)
(concat default-directory short-archive-name)
(concat default-directory "test_data/alphabet/" short-archive-name)))
(cpio-archive-buffer)
(cpio-dired-buffer)
(cpio-entry-contents-buffer)
(cpio-dired-contents-mode-buffer))
;; Make sure we have a clean copy of the archive.
(with-current-buffer (find-file-noselect archive-name)
(shell-command "make crc" nil nil)
(kill-buffer))
(with-current-buffer (setq cpio-archive-buffer (find-file-noselect archive-name))
(cpio-mode)
(setq cpio-dired-buffer (current-buffer)))
(unless (with-current-buffer cpio-archive-buffer (cpio-entry-exists-p name))
(if (> depth 1)
(error "%s(): Going too deep." fname)
(entry-setup nil name (1+ depth)))
(setq cpio-dired-buffer (current-buffer)))
;; Get the entry
(switch-to-buffer cpio-dired-buffer)
(cpio-dired-goto-entry name)
(cpio-dired-find-entry)
(setq cpio-entry-contents-buffer (current-buffer))
(switch-to-buffer cpio-dired-buffer)
;; Set up windows.
(delete-other-windows)
(split-window-right)
(split-window)
(other-window 1)
(switch-to-buffer cpio-archive-buffer)
(other-window 1)
(split-window)
(switch-to-buffer cpio-entry-contents-buffer)
(other-window 1)
(setq cpio-dired-contents-mode-buffer (switch-to-buffer "cpio-entry-contents-mode.el"))
(other-window 2)))
;;
;; Dependencies
;;
;;;;;;;;;;;;;;;;
;; Things to make the byte compiler happy.
(defvar cpio-entry-name)
(defvar *cpio-catalog-entry-contents-start-idx*)
(declare-function cpio-contents-start "cpio-mode.el")
(declare-function cpio-delete-archive-entry "cpio-mode.el")
(declare-function cpio-dired-find-entry "cpio-dired.el")
(declare-function cpio-dired-goto-entry "cpio-dired.el")
(declare-function cpio-entry "cpio-mode.el")
(declare-function cpio-entry-attrs "cpio-mode.el")
(declare-function cpio-entry-exists-p "cpio-mode.el")
(declare-function cpio-entry-header-start "cpio-mode.el")
(declare-function cpio-insert-padded-contents "cpio-mode.el")
(declare-function cpio-make-header-string "cpio-mode.el")
(declare-function cpio-mode "cpio-mode.el")
(declare-function cpio-present-ala-dired "cpio-dired.el")
(declare-function cpio-set-entry-modified "cpio-mode.el")
(declare-function cpio-set-entry-size "cpio-mode.el")
(declare-function cpio-entry-exists-p "cpio-mode.el")
(declare-function cpio-dired-goto-entry "cpio-dired.el")
(declare-function cpio-dired-find-entry "cpio-dired.el")
;; EO things for the byte compiler.
;;;;;;;;;;;;;;;;
;;
;; Vars
;;
;;
;; Library
;;
;;
;; Commands
;;
(defun cpio-entry-contents-save ()
"Save the contents of the current buffer in it's cpio archive."
(interactive)
(let ((fname "cpio-entry-contents-save")
(name cpio-entry-name)
(entry (cpio-entry cpio-entry-name))
(attrs (cpio-entry-attrs cpio-entry-name))
(header-string)
(size (buffer-size))
(new-contents (buffer-string))
(dired-buffer-name))
(unless (cpio-entry-contents-buffer-p)
(error "%s(): You're not in a cpio entry contents buffer." fname))
(with-current-buffer *cab-parent*
;; 1. Delete the entry's head and contents (plus padding) in the parent buffer.
(cpio-delete-archive-entry entry)
;; 2. Update the entry size in the entry.
(cpio-set-entry-size attrs size)
;; 3. Write the new contents in the archive buffer (plus padding).
(goto-char (cpio-contents-start name))
(cpio-insert-padded-contents new-contents)
;; 4. Build the entry header.
(setq header-string (cpio-make-header-string attrs))
;; 5. Write the header in the archive buffer (plus padding).
(goto-char (cpio-entry-header-start entry))
(with-writable-buffer
(insert header-string))
(aset entry *cpio-catalog-entry-contents-start-idx* (point-marker))
(setq dired-buffer-name (cpio-dired-buffer-name (buffer-file-name))))
;; 6. Mark the contents buffer as unmodified.
(set-buffer-modified-p nil)
;; 6a. But mark the entry in the archive modified.
(cpio-set-entry-modified entry)
;; 7. Update the dired-like interface.
(with-current-buffer dired-buffer-name
(save-excursion
(cpio-dired-goto-entry name)
(with-writable-buffer
(delete-region (line-beginning-position) (line-end-position))
(insert (cpio-dired-format-entry attrs)))))
(message "Saved into cpio archive buffer `%s'. Be sure to save that buffer!"
(file-name-nondirectory (buffer-file-name *cab-parent*)))))
(defun cpio-entry-contents-buffer-p ()
"Return non-NIL if the current buffer is an entry contents buffer."
(let ((fname "cpio-entry-contents-buffer-p"))
(member 'cpio-entry-contents-mode (current-minor-modes))))
(defun cpio-entry-contents-kill (&optional buffer-or-name)
"Kill the buffer specified by BUFFER-OR-NAME.
A name denotes the name of an entry in the cpio archive."
(interactive "P")
(unless buffer-or-name (setq buffer-or-name (current-buffer)))
(let ((fname "cpio-entry-contents-kill")
(buffer (if (bufferp buffer-or-name)
buffer-or-name
(get-buffer-create buffer-or-name))))
(if (and (buffer-modified-p buffer)
(yes-or-no-p "Buffer is modified. Really kill? "))
(kill-buffer buffer))))
(defun cpio-entry-contents-revert-buffer ()
"Discard any changes to the current CPIO archive entry and
reload the [current] entry contents."
(interactive)
(let ((fname "cpio-entry-contents-revert-buffer"))
(unless (cpio-entry-contents-buffer-p)
(error "%s(): You're not in an entry contetnts buffer." fname))
(with-writable-buffer
(erase-buffer)
(cpio-find-entry cpio-entry-name)
(set-auto-mode 'keep-mode-if-same))))
;;
;; Mode definition
;;
(defvar *cpio-entry-contents-mode-map* (make-sparse-keymap)
"Keymap for cpio-entry-contents-mode.")
(setq *cpio-entry-contents-mode-map* (make-sparse-keymap))
(defun cpio-entry-contents-make-keymap ()
"Define the keys that cpio-entry-contents-mode must override."
(let ((fname "cpio-entry-contents-make-keymap"))
(define-key *cpio-entry-contents-mode-map* "\C-x\C-s" 'cpio-entry-contents-save)
(define-key *cpio-entry-contents-mode-map* "\C-x\C-k" 'cpio-entry-contents-kill)
;; HEREHERE Does the following make sense any more?
(define-key *cpio-entry-contents-mode-map* "\M-," 'cpio-tags-loop-continue)))
(define-minor-mode cpio-entry-contents-mode
"Minor mode for working with an entry's contents from a cpio archive.
This mode is automatically invoked when the contents of a cpio entry are
prepared for editing."
nil
" entry contents"
:keymap *cpio-entry-contents-mode-map*
:global nil
:lighter "(cpio entry)"
;; Major modes kill local variables.
;; Keep the ones we need for cpio entry contents.
(let ((cab-parent *cab-parent*)
(entry-name cpio-entry-name)
(attrs (cpio-entry-attrs cpio-entry-name))
(local-buffer-file-name buffer-file-name))
;; For some reason (decode-coding-region) seems to need a writable buffer.
;; (with-writable-buffer
;; (decode-coding-region (cpio-entry-contents-start (cpio-entry entry-name))
;; (cpio-entry-contents-end (cpio-entry entry-name))
;; nil)))
;; (point-min) (point-max) nil)
;; (set-buffer-file-coding-system last-coding-system-used t)
;; (normal-mode)
(set-auto-mode 'keep-mode-if-same)
(setq *cab-parent* cab-parent)
(setq cpio-entry-name entry-name)
;; Why was I doing this?
;; (setq buffer-file-name local-buffer-file-name)
(setq cpio-entry-contents-mode t)))
(cpio-entry-contents-make-keymap)
(provide 'cpio-entry-contents-mode)
;;; cpio-entry-contents-mode.el ends here