[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/cpio-mode 6ef0296 11/61: Create cpio-generic.el
From: |
Stefan Monnier |
Subject: |
[elpa] externals/cpio-mode 6ef0296 11/61: Create cpio-generic.el |
Date: |
Fri, 11 Jan 2019 15:25:22 -0500 (EST) |
branch: externals/cpio-mode
commit 6ef0296dd9fc06a47c44b51fe7ca724dd7c42c17
Author: dlewan <address@hidden>
Commit: GitHub <address@hidden>
Create cpio-generic.el
Initial code from local CVS.
---
cpio-generic.el | 521 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 521 insertions(+)
diff --git a/cpio-generic.el b/cpio-generic.el
new file mode 100644
index 0000000..18aaf07
--- /dev/null
+++ b/cpio-generic.el
@@ -0,0 +1,521 @@
+;; -*- coding: utf-8 -*-
+;;; cpio-generic.el --- generically useful functions created in support of
CPIO mode.
+; $Id: cpio-generic.el,v 1.1.4.4.2.1 2018/03/08 06:22:09 doug Exp $
+
+;; COPYRIGHT
+;;
+;; Copyright © 2015, 2018 Douglas Lewan, address@hidden
+;; 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 <http://www.gnu.org/licenses/>.
+;;
+
+;; Author: Douglas Lewan (address@hidden)
+;; Maintainer: -- " --
+;; Created: 2015 Apr 23
+;; Version: 0.02
+;; Keywords: generically useful emacs lisp functions.
+
+;;; Commentary:
+
+;;
+;; This file contains useful generic functions,
+;; commands for managing debuggers
+;; and other temporarily useful hacks
+;; to help with the development of cpio-mode.
+;;
+;; A quick glance through it suggests
+;; that it has a lot of functional overlap with cpio-modes.el.
+;;
+
+;;; Documentation:
+
+;;; Code:
+
+;;
+;; Dependencies
+;;
+
+
+;;
+;; Vars
+;;
+(defvar *integer-size* nil)
+(setq *integer-size* nil)
+
+(defvar *integer-hex-digits* nil)
+
+
+(defvar *debugger-re* "^\\s-*(message \"%s(): \\([[:digit:]]+\\)\" fname)$"
+ "RE to match a debugger created by M-x insert-debugger.")
+(setq *debugger-re* "^\\s-*(message \"%s(): \\([[:digit:]]+\\)\" fname)")
+
+;;
+;; Bit definitions from sys/bits.h
+;; CAVEAT: According to the info on file attributes in the info for libc
+;; you can't depend on the bit values being portable to other OSes.
+;; Is there a reasonable way to autoconfiscate this?
+;;
+;; /* File types. */
+;; #define __S_IFDIR 0040000 /* Directory. */
+(defvar *cpio-directory-bits* (lsh #o4 12))
+;; #define __S_IFCHR 0020000 /* Character device. */
+(defvar *cpio-char-device-bits* (lsh #o2 12))
+;; #define __S_IFBLK 0060000 /* Block device. */
+(defvar *cpio-blk-device-bits* (lsh #o6 12))
+;; #define __S_IFREG 0100000 /* Regular file. */
+(defvar *cpio-regular-file-bits* (lsh #o1 15))
+;; #define __S_IFIFO 0010000 /* FIFO. */
+(defvar *cpio-fifo-bits* (lsh #o1 12))
+;; #define __S_IFLNK 0120000 /* Symbolic link. */
+(defvar *cpio-symlink-bits* (lsh #o12 12))
+;; #define __S_IFSOCK 0140000 /* Socket. */
+(defvar *cpio-socket-bits* (lsh #o14 12))
+;;
+;; MAINTENANCE The ls(1) info page mentions other file types:
+;; C - Contiguous data file
+;; D - Door (Solaris only?)
+;; M - Migrated file (Cray)
+;; ? - Some other type.
+;;
+;; /* Protection bits. */
+;;
+;; #define __S_ISUID 04000 /* Set user ID on execution. */
+(defvar *cpio-s-isuid-bits* #o40)
+;; #define __S_ISGID 02000 /* Set group ID on execution. */
+(defvar *cpio-s-isgid-bits* #o20)
+;; #define __S_ISVTX 01000 /* Save swapped text after use
(sticky). */
+(defvar *cpio-s-ivtx-bits* #o10)
+;; #define __S_IREAD 0400 /* Read by owner. */
+(defvar *cpio-s-iread-bits* #o4)
+;; #define __S_IWRITE 0200 /* Write by owner. */
+(defvar *cpio-s-iwrite-bits* #o2)
+;; #define __S_IEXEC 0100 /* Execute by owner. */
+(defvar *cpio-s-iexec-bits* #o1)
+;;
+
+(defvar *insert-after* nil
+ "Value used to define that a marker has type 'insert after'.")
+(defvar *insert-before* t
+ "Value used to define that a marker has type 'insert before'.")
+
+
+;;
+;; Library
+;;
+(defun integer-size ()
+ "Return the number of bits in an [unsigned] integer."
+ (let ((fname "integer-size")
+ (b 1)
+ (bit-ct 0))
+ (cond ((null *integer-size*)
+ (while (/= 0 (logand b most-positive-fixnum))
+ (setq bit-ct (1+ bit-ct))
+ (setq b (lsh b 1)))
+ (setq *integer-size* (1+ bit-ct)))
+ (t t))
+ *integer-size*))
+
+(defun integer-hex-digits ()
+ "Calculate the number of hex digits that are required to represent any
integer."
+ (let ((fname "integer-hex-digits")
+ (an-integer most-negative-fixnum)
+ (hex-digit-ct 0))
+ (unless *integer-hex-digits*
+ (while (/= 0 an-integer)
+ (setq an-integer (lsh an-integer -4))
+ (setq hex-digit-ct (1+ hex-digit-ct)))
+ (setq *integer-hex-digits* hex-digit-ct)))
+ *integer-hex-digits*)
+
+(defun lsh-pair (pair n)
+ "Bit shift the given PAIR, (high . low), left by N bits.
+This returns the resulting pair or integer
+depending on whether the high component is non-zero.
+PAIR is a cons of two integers."
+ ;; The concept of integer in emacs is, of course, very soft.
+ ;; It likely varies from installation to installation.
+ (let ((fname "lsh-pair")
+ (mask 0)
+ (cross-bits)
+ (high (car pair))
+ (low (cdr pair)))
+ (if (< n 0)
+ (setq mask (low-bits-mask n))
+ (setq mask (high-bits-mask n)))
+ (cond ((< n 0)
+ (setq cross-bits (logand high mask))
+ (setq high (lsh high n))
+ (setq low (lsh low n))
+ (setq low (logior low (lsh cross-bits (- (integer-size) n)))))
+ (t
+ (setq cross-bits (logand low mask))
+ (setq high (lsh high n))
+ (setq low (lsh low n))
+ (setq high (logior high cross-bits))))
+ (if (/= 0 high)
+ (cons high low)
+ low)))
+
+(defun lsh-with-carry (bits n)
+ "Shift the given BITS left by N using a pair or a triple as necessary."
+ ;; HEREHERE This is an obvious part of the lsh-* library here
+ ;; but probably not necessary for the current project.
+ (let ((fname "lsh-with-carry")
+ low middle high)
+ (error "%s is not yet implemented." fname)))
+
+(defun lsh-triplet ()
+ "DO THAT and update this docstring."
+ (let ((fname "lsh-triplet"))
+ (error "%s is not yet implemented." fname)))
+
+(defun low-bits-mask (n)
+ "Return a mask appropriate for picking up the right N bits of an integer.
+If N is zero, then an empty mask is returned.
+The value is a bit mask."
+ ;; See (lsh-pair) for a sample use.
+ (let ((fname "low-bits-mask")
+ (i 0)
+ (mask 0))
+ (while (< i n)
+ (setq mask (+ (lsh mask 1) 1))
+ (setq i (1+ i)))
+ mask))
+
+(defun high-bits-mask (n)
+ "Return a mask appropriate for picking up the left N bits of an integer.
+If N is zero, then an empty mask is returned.
+The value is a bit mask."
+ ;; See (lsh-pair) for a sample use.
+ (let ((fname "high-bits-mask")
+ (i 0)
+ (mask 0))
+ (while (< i n)
+ (setq mask (+ (lsh mask -1) most-negative-fixnum))
+ (setq i (1+ i)))
+ mask))
+(defun hex-format-pair (pair)
+ "Return a hex formatted representation of PAIR."
+ (let ((fname "hex-format-pair")
+ (hex-digit-count (integer-hex-digits))
+ (formatter))
+ (setq formatter (format "%%0%dx" hex-digit-count))
+ (setq formatter (concat formatter formatter))
+ (format formatter (car pair) (cdr pair))))
+
+(defun hex-format-triple (triple)
+ "Return a hex formatted representation of TRIPLE."
+ (let ((fname "hex-format-triple")
+ (hex-digit-count (integer-hex-digits))
+ (formatter))
+ (setq formatter (format "%%0%dx" hex-digit-count))
+ (setq formatter (concat formatter formatter formatter))
+ (format formatter (car triple) (cadr triple) (cddr triple))))
+
+
+(defun drwx-to-hex (mode-string)
+ "DO THAT and update this docstring."
+ (let ((fname "drwx-to-hex")
+ (user-offset 6)
+ (group-offset 3)
+ (other-offset 0)
+ (user-string (substring mode-string 1 4))
+ (user-value 0)
+ (group-string (substring mode-string 4 7))
+ (group-value 0)
+ (other-string (substring mode-string 7 10))
+ (other-value 0)
+ (file-type-string (substring mode-string 0 1))
+ (file-type-value 0)
+ (value))
+ (unless (string-match "\\`[-bcdlps]\\(?:[-r][-w][-xXst]\\)\\{3\\}\\'"
+ mode-string)
+ (error "%s bad mode string: [[%s]]" fname mode-string))
+ (setq file-type-value (drwx-to-file-type file-type-string))
+ (setq user-value (lsh (rwx-to-bits user-string) user-offset))
+ (if (string-match "..[Ss]" user-string)
+ (setq user-value (logior user-value (lsh *cpio-s-isuid-bits*
user-offset))))
+ (setq group-value (lsh (rwx-to-bits group-string) group-offset))
+ (if (string-match "..[Ss]" group-string)
+ (setq group-value (logior group-value (lsh *cpio-s-isgid-bits*
group-offset))))
+ (setq other-value (lsh (rwx-to-bits other-string) other-offset))
+ (if (string-match "..t" other-string)
+ (setq other-value (logior other-value (lsh *cpio-s-ivtx-bits*
user-offset))))
+ (setq value (logior file-type-value user-value group-value other-value))
+ (format "%08X" value)))
+
+(defun drwx-to-file-type (mode-string)
+ "Convert the given mode-string to the bits specifying its file type."
+ ;; -bcdlps
+ (let ((fname "drwx-to-file-type"))
+ (cond ((string-match "\\`-" mode-string)
+ *cpio-regular-file-bits*)
+ ((string-match "\\`b" mode-string)
+ *cpio-blk-device-bits*)
+ ((string-match "\\`c" mode-string)
+ *cpio-char-device-bits*)
+ ((string-match "\\`d" mode-string)
+ *cpio-directory-bits*)
+ ((string-match "\\`l" mode-string)
+ *cpio-symlink-bits*)
+ ((string-match "\\`p" mode-string)
+ *cpio-fifo-bits*)
+ ((string-match "\\`s" mode-string)
+ *cpio-socket-bits*)
+ (t
+ (error "%s(): bad string for file type [[%s]]" fname mode-string)))))
+
+(defun rwx-to-bits (mode-string)
+ "Convert a rwx type of mode string to corresponding bits.
+rwx = 7 and rw- = 6, for example."
+ (let ((fname "rwx-to-bits")
+ (ret 0))
+ (unless (string-match "\\`[-r][-w][-xXst]\\'" mode-string)
+ (error "%s bad mode string: [[%s]]" fname mode-string))
+ (if (string-match "r.." mode-string)
+ (setq ret (logior ret *cpio-s-iread-bits*)))
+ (if (string-match ".w." mode-string)
+ (setq ret (logior ret *cpio-s-iwrite-bits*)))
+ (if (string-match "..[xst]" mode-string)
+ (setq ret (logior ret *cpio-s-iexec-bits*)))
+ ;; Only the caller can know if this is user or group.
+ ;; He must deal with set U/GID bits.
+ ret))
+
+(defun round-up (number modulus)
+ "Round NUMBER up to the next multiple of MODULUS.
+CAVEAT: If NUMBER is negative, then the result may be surprising."
+ (let ((fname "round-up"))
+ (unless (and (integerp number) (integerp modulus))
+ (error "%s() takes integer arguments." fname))
+ (* modulus (/ (+ number modulus -1) modulus))))
+
+(defun pad-right (string width char)
+ "Pad STRING on the right with CHAR until it is WIDTH characters wide.
+CHAR is typically a character or a single character string, but may be any
string."
+ (let ((fname "pad-right"))
+ (if (characterp char) (setq char (char-to-string char)))
+ (while (< (length string) width)
+ (setq string (concat string char)))
+ string))
+
+;; MAINTENANCE We need a portable version of (cpio-look-up-uid).
+(defun UNUSED-cpio-look-up-uid (user-name)
+ "Look up the UID for the given USER-NAME and return the UID a an integer
string.
+If the given user does not exist, then return FFFFFFFF."
+ (let ((fname "cpio-look-up-uid"))
+ (with-temp-buffer
+ ;; MAINTENANCE The following is not portable to, e.g. Windows.
+ ;; It might not be portable to OSX.
+ (insert-file "/etc/passwd")
+ (goto-char (point-min))
+ (if (re-search-forward (concat "^" user-name
":[[:graph:]]+:\\([[:digit:]]+\\):") (point-max) t)
+ (format "%08X" (string-to-number (match-string 1)))
+ "FFFFFFFF"))))
+
+;; MAINTENANCE We need a portable (cpio-look-up-gid).
+(defun UNUSED-cpio-look-up-gid (group-name)
+ "Look up the GID for the given GROUP-NAME and return the GID a an integer
string.
+If the given user does not exist, then return 99 999 999."
+ (let ((fname "cpio-look-up-gid"))
+ (with-temp-buffer
+ ;; MAINTENANCE The following is not portable to, e.g. Windows.
+ ;; It might not be portable to OSX.
+ (insert-file "/etc/group")
+ (goto-char (point-min))
+ (if (re-search-forward (concat "^" user-name
":[[:graph:]]+:\\([[:digit:]]+\\):") (point-max) t)
+ (format "%08X" (string-to-number (match-string 1)))
+ "FFFFFFFF"))))
+
+(defun strip-right (re string &optional multiples)
+ "Strip the given RE from the right end of STRING.
+If the optional argument MULTIPLES is not NIL,
+then match as many copies of RE as are there."
+ (let ((fname "strip-right")
+ (inner-re (if multiples
+ (concat "\\(" re "\\)+\\'")
+ (concat re "\\'")))
+ (result string))
+ (if (string-match inner-re string)
+ (setq result (substring string 0 (match-beginning 0))))
+ result))
+
+(defun strip-left (re string &optional multiples)
+ "Strip the given RE from the left end of STRING.
+If the optional argument MULTIPLES is not NIL,
+then match as many copies of RE as are there."
+ (let ((fname "strip-left")
+ (inner-re (if multiples
+ (concat "\\`+\\(" re "\\)")
+ (concat "\\`" re)))
+
+ (result string))
+ (if (string-match inner-re string)
+ (setq result (substring string (match-end 0))))
+ result))
+
+(defun strip (re string &optional multiples)
+ "Remove the given RE from both ends of STRING.
+If the optional argument MULTIPLES is not NIL,
+then match as many copies of RE as are there."
+ (let ((fname "strip")
+ (result))
+ (strip-left re (strip-right re string multiples) multiples)))
+
+(defun cpio-padded (string modulus pad-char)
+ "Pad the given STRING."
+ (let* ((fname "cpio-padded")
+ (string-length (length string))
+ (desired-length (round-up string-length modulus)))
+ (pad-right string desired-length pad-char)))
+
+(defun cpio-point ()
+ "Return (point) as if it were 0-based and not 1-based.
+The intent here is to make calculating padding and locations easier."
+ ;; Would this be better as a macro?
+ (let ((fname "cpio-point"))
+ (1- (point))))
+
+(defun cpio-goto-char (where)
+ "Move point to WHERE, where WHERE is a 0-based point."
+ (let ((fname "cpio-goto-char"))
+ (if (< where 0)
+ (signal 'wrong-type-argument (list (format "%d" where))))
+ (goto-char (1+ where))))
+
+(defun cpio-point-min ()
+ "Return the minimum point given a 0-based point."
+ (let ((fname "cpio-point-min"))
+ (1- (point-min))))
+
+(defun cpio-point-max ()
+ "Return the maximum point given a 0-based point."
+ (let ((fname "cpio-point-max"))
+ (1- (point-max))))
+
+
+;;
+;; Commands
+;;
+
+(defun insert-debugger ()
+ "Insert a new debugger statement above the line containing point."
+ (interactive)
+ (let ((fname "insert-debugger"))
+ (beginning-of-line)
+ (open-line 1)
+ (insert (format "(message \"%%s(): %d\" fname)" (count-lines (point-min)
(point))))
+ (indent-according-to-mode)))
+(local-set-key "\M-\C-i" 'insert-debugger)
+
+(defun update-debuggers ()
+ "Update the line numbers in all the debuggers created by M-x
insert-debugger."
+ (interactive)
+ (let ((fname "update-debuggers"))
+ (save-excursion
+ (save-restriction
+ (goto-char (point-min))
+ (while (re-search-forward *debugger-re* (point-max) t)
+ (replace-match (format "%d" (count-lines (point-min) (point)))
+ nil nil nil 1))))
+ (save-buffer)))
+(local-set-key "\M-\C-u" 'update-debuggers)
+
+(defun remove-debugger ()
+ "Remove the next debugger.
+Return T if one was found
+and NIL otherwise.
+This function respects narrowing."
+ (interactive)
+ (let ((fname "remove-debugger"))
+ (cond ((re-search-forward *debugger-re* (point-max) t)
+ (delete-region (match-beginning 0) (match-end 0))
+ t)
+ (t nil))))
+
+(defun remove-some-debuggers (arg)
+ "Remove the next ARG debuggers.
+Return non-NIL if any were found and deleted.
+Return NIL if none were found.
+This function respects narrowing."
+ (interactive "p")
+ (let ((fname "remove-some-debuggers")
+ (ct 0))
+ (while (and (< 0 arg) (remove-debugger))
+ (setq ct (1+ ct))
+ (setq arg (1- arg)))
+ ct))
+
+(defun remove-all-debuggers ()
+ "Remove all debuggers created by (insert-debuggers).
+This function respects narrowing."
+ (interactive)
+ (let ((fname "remove-all-debuggers"))
+ (while (remove-debugger))))
+
+;;
+;; Hacks
+;;
+(defun aaa ()
+ "Create a general cpio-mode function set to the next cpio-newc function.
+Well, that's the intent, but, really, it's a hack."
+ (interactive)
+ (let ((fname "aaa")
+ (cpio-newc-function-name)
+ (cpio-function-definition)
+ (start -1)
+ (end -1)
+ (defun-end -1))
+
+ (cond ((re-search-forward " \\(cpio-newc\\(-[-[:alnum:]]+\\)\\)"
(point-max))
+ (setq cpio-newc-function-name (match-string-no-properties 1))
+ (setq cpio-function-definition
+ (format "(setq cpio%s-function %s)\n"
(match-string-no-properties 2)
+ cpio-newc-function-name))
+ (end-of-defun)
+ (insert cpio-function-definition))
+ (t nil))))
+
+(defun bbb-newc (header-string)
+ "Return a crudely parsed newc header from the given HEADER-STRING."
+ (let* ((fname "bbb-newc")
+ (lengths (list 6 8 8 8 8 8 8 8 8 8 8 8 8 8 8))
+ (stops (let ((i 0)
+ (j 0)
+ (n 0))
+ (mapcar (lambda (l)
+ (prog1
+ n
+ (setq n (+ n (nth i lengths)))
+ (setq i (1+ i))))
+ lengths)))
+ (i 0)
+ (j 1))
+ (setq header-string (strip-right "\0" header-string t))
+ (mapcar (lambda (s)
+ (prog1 (substring header-string (nth i stops) (nth j stops))
+ (setq i j)
+ (setq j (1+ j))))
+ stops)))
+
+
+;;
+;; Mode definition (IF APPROPRIATE)
+;;
+
+
+
+(provide 'cpio-generic)
+;;; cpio-generic.el ends here
- [elpa] branch externals/cpio-mode created (now 90f1236), Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 7626f39 01/61: Create README.md, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 8ef4a0e 05/61: Create cpio-bin.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 4d11b71 06/61: Create cpio-crc.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode c0d77ed 04/61: Create cpio-affiliated-buffers.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode e048c6f 02/61: Create configure.ac, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 8cfe789 03/61: Create COPYING, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 339dee9 10/61: Create cpio-entry-header.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 6ef0296 11/61: Create cpio-generic.el,
Stefan Monnier <=
- [elpa] externals/cpio-mode 25d2230 09/61: Create cpio-entry-contents-mode.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 92481ae 18/61: Create cpio-newc-test.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 2463890 14/61: Create cpio-hpodc.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 70755a2 21/61: Create cpio-tests.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 125c509 19/61: Create cpio-odc.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode adc2862 13/61: Create cpio-hpbin.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode e77f48e 16/61: Create cpio-modes-test.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 8011050 20/61: Create cpio-tar.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 12877b1 22/61: Create cpio-ustar.el, Stefan Monnier, 2019/01/11
- [elpa] externals/cpio-mode 0af3b11 15/61: Create cpio-modes.el, Stefan Monnier, 2019/01/11