|
|
1.1 ! root 1: ;; Info support functions package for Emacs ! 2: ;; Copyright (C) 1986 Free Software Foundation, Inc. ! 3: ! 4: ;; This file is part of GNU Emacs. ! 5: ! 6: ;; GNU Emacs is distributed in the hope that it will be useful, ! 7: ;; but WITHOUT ANY WARRANTY. No author or distributor ! 8: ;; accepts responsibility to anyone for the consequences of using it ! 9: ;; or for whether it serves any particular purpose or works at all, ! 10: ;; unless he says so in writing. Refer to the GNU Emacs General Public ! 11: ;; License for full details. ! 12: ! 13: ;; Everyone is granted permission to copy, modify and redistribute ! 14: ;; GNU Emacs, but only under the conditions described in the ! 15: ;; GNU Emacs General Public License. A copy of this license is ! 16: ;; supposed to have been given to you along with GNU Emacs so you ! 17: ;; can know your rights and responsibilities. It should be in a ! 18: ;; file named COPYING. Among other things, the copyright notice ! 19: ;; and this notice must be preserved on all copies. ! 20: ! 21: (require 'info) ! 22: ! 23: (defun Info-tagify () ! 24: "Create or update Info-file tag table in current buffer." ! 25: (interactive) ! 26: ;; Save and restore point and restrictions. ! 27: ;; save-restrictions would not work ! 28: ;; because it records the old max relative to the end. ! 29: ;; We record it relative to the beginning. ! 30: (let ((omin (point-min)) ! 31: (omax (point-max)) ! 32: (nomax (= (point-max) (1+ (buffer-size)))) ! 33: (opoint (point))) ! 34: (unwind-protect ! 35: (progn ! 36: (widen) ! 37: (goto-char (point-min)) ! 38: (if (search-forward "\^_\nIndirect:\n" nil t) ! 39: (message "Cannot tagify split info file") ! 40: (let ((regexp "Node:[ \t]*\\([^,\n\t]\\)*[,\t\n]") ! 41: (case-fold-search t) ! 42: list) ! 43: (while (search-forward "\n\^_" nil t) ! 44: (forward-line 1) ! 45: (let ((beg (point))) ! 46: (forward-line 1) ! 47: (if (re-search-backward regexp beg t) ! 48: (setq list ! 49: (cons (list (buffer-substring ! 50: (match-beginning 1) ! 51: (match-end 1)) ! 52: beg) ! 53: list))))) ! 54: (goto-char (point-max)) ! 55: (forward-line -8) ! 56: (let ((buffer-read-only nil)) ! 57: (if (search-forward "\^_\nEnd tag table\n" nil t) ! 58: (let ((end (point))) ! 59: (search-backward "\nTag table:\n") ! 60: (beginning-of-line) ! 61: (delete-region (point) end))) ! 62: (goto-char (point-max)) ! 63: (insert "\^_\f\nTag table:\n") ! 64: (move-marker Info-tag-table-marker (point)) ! 65: (setq list (nreverse list)) ! 66: (while list ! 67: (insert "Node: " (car (car list)) ?\177) ! 68: (princ (car (cdr (car list))) (current-buffer)) ! 69: (insert ?\n) ! 70: (setq list (cdr list))) ! 71: (insert "\^_\nEnd tag table\n"))))) ! 72: (goto-char opoint) ! 73: (narrow-to-region omin (if nomax (1+ (buffer-size)) ! 74: (min omax (point-max))))))) ! 75: ! 76: (defun Info-split () ! 77: "Split an info file into an indirect file plus bounded-size subfiles. ! 78: Each subfile will be up to 50000 characters plus one node. ! 79: ! 80: To use this command, first visit a large Info file that has a tag table. ! 81: The buffer is modified into a (small) indirect info file ! 82: which should be saved in place of the original visited file. ! 83: ! 84: The subfiles are written in the same directory the original file is in, ! 85: with names generated by appending `-' and a number to the original file name. ! 86: ! 87: The indirect file still functions as an Info file, but it contains ! 88: just the tag table and a directory of subfiles." ! 89: (interactive) ! 90: (if (< (buffer-size) 70000) ! 91: (error "This is too small to be worth splitting")) ! 92: (goto-char (point-min)) ! 93: (search-forward "\^_") ! 94: (forward-char -1) ! 95: (let ((start (point)) ! 96: (chars-deleted 0) ! 97: subfiles ! 98: (subfile-number 1) ! 99: (case-fold-search t) ! 100: (filename (file-name-sans-versions buffer-file-name))) ! 101: (goto-char (point-max)) ! 102: (forward-line -8) ! 103: (setq buffer-read-only nil) ! 104: (or (search-forward "\^_\nEnd tag table\n" nil t) ! 105: (error "Tag table required; use M-x Info-tagify")) ! 106: (search-backward "\nTag table:\n") ! 107: (if (looking-at "\nTag table:\n\^_") ! 108: (error "Tag table is just a skeleton; use M-x Info-tagify")) ! 109: (beginning-of-line) ! 110: (forward-char 1) ! 111: (save-restriction ! 112: (narrow-to-region (point-min) (point)) ! 113: (goto-char (point-min)) ! 114: (while (< (1+ (point)) (point-max)) ! 115: (goto-char (min (+ (point) 50000) (point-max))) ! 116: (search-forward "\^_" nil 'move) ! 117: (setq subfiles ! 118: (cons (list (+ start chars-deleted) ! 119: (concat (file-name-nondirectory filename) ! 120: (format "-%d" subfile-number))) ! 121: subfiles)) ! 122: ;; Put a newline at end of split file, to make Unix happier. ! 123: (insert "\n") ! 124: (write-region (point-min) (point) ! 125: (concat filename (format "-%d" subfile-number))) ! 126: (delete-region (1- (point)) (point)) ! 127: ;; Back up over the final ^_. ! 128: (forward-char -1) ! 129: (setq chars-deleted (+ chars-deleted (- (point) start))) ! 130: (delete-region start (point)) ! 131: (setq subfile-number (1+ subfile-number)))) ! 132: (while subfiles ! 133: (goto-char start) ! 134: (insert (nth 1 (car subfiles)) ! 135: (format ": %d" (car (car subfiles))) ! 136: "\n") ! 137: (setq subfiles (cdr subfiles))) ! 138: (goto-char start) ! 139: (insert "\^_\nIndirect:\n") ! 140: (search-forward "\nTag Table:\n") ! 141: (insert "(Indirect)\n"))) ! 142: ! 143: (defun Info-validate () ! 144: "Check current buffer for validity as an Info file. ! 145: Check that every node pointer points to an existing node." ! 146: (interactive) ! 147: (save-excursion ! 148: (save-restriction ! 149: (widen) ! 150: (goto-char (point-min)) ! 151: (if (search-forward "\nTag table:\n(Indirect)\n" nil t) ! 152: (error "Don't yet know how to validate indirect info files: \"%s\"" ! 153: (buffer-name (current-buffer)))) ! 154: (goto-char (point-min)) ! 155: (let ((allnodes '(("*"))) ! 156: (regexp "Node:[ \t]*\\([^,\n\t]*\\)[,\t\n]") ! 157: (case-fold-search t) ! 158: (tags-losing nil) ! 159: (lossages ())) ! 160: (while (search-forward "\n\^_" nil t) ! 161: (forward-line 1) ! 162: (let ((beg (point))) ! 163: (forward-line 1) ! 164: (if (re-search-backward regexp beg t) ! 165: (let ((name (downcase ! 166: (buffer-substring ! 167: (match-beginning 1) ! 168: (progn ! 169: (goto-char (match-end 1)) ! 170: (skip-chars-backward " \t") ! 171: (point)))))) ! 172: (if (assoc name allnodes) ! 173: (setq lossages ! 174: (cons (list name "Duplicate node-name" nil) ! 175: lossages)) ! 176: (setq allnodes ! 177: (cons (list name ! 178: (progn ! 179: (end-of-line) ! 180: (and (re-search-backward ! 181: "prev[ious]*:" beg t) ! 182: (progn ! 183: (goto-char (match-end 0)) ! 184: (downcase ! 185: (Info-following-node-name))))) ! 186: beg) ! 187: allnodes))))))) ! 188: (goto-char (point-min)) ! 189: (while (search-forward "\n\^_" nil t) ! 190: (forward-line 1) ! 191: (let ((beg (point)) ! 192: thisnode next) ! 193: (forward-line 1) ! 194: (if (re-search-backward regexp beg t) ! 195: (save-restriction ! 196: (search-forward "\n\^_" nil 'move) ! 197: (narrow-to-region beg (point)) ! 198: (setq thisnode (downcase ! 199: (buffer-substring ! 200: (match-beginning 1) ! 201: (progn ! 202: (goto-char (match-end 1)) ! 203: (skip-chars-backward " \t") ! 204: (point))))) ! 205: (end-of-line) ! 206: (and (search-backward "next:" nil t) ! 207: (setq next (Info-validate-node-name "invalid Next")) ! 208: (assoc next allnodes) ! 209: (if (equal (car (cdr (assoc next allnodes))) ! 210: thisnode) ! 211: ;; allow multiple `next' pointers to one node ! 212: (let ((tem lossages)) ! 213: (while tem ! 214: (if (and (equal (car (cdr (car tem))) ! 215: "should have Previous") ! 216: (equal (car (car tem)) ! 217: next)) ! 218: (setq lossages (delq (car tem) lossages))) ! 219: (setq tem (cdr tem)))) ! 220: (setq lossages ! 221: (cons (list next ! 222: "should have Previous" ! 223: thisnode) ! 224: lossages)))) ! 225: (end-of-line) ! 226: (if (re-search-backward "prev[ious]*:" nil t) ! 227: (Info-validate-node-name "invalid Previous")) ! 228: (end-of-line) ! 229: (if (search-backward "up:" nil t) ! 230: (Info-validate-node-name "invalid Up")) ! 231: (if (re-search-forward "\n* Menu:" nil t) ! 232: (while (re-search-forward "\n\\* " nil t) ! 233: (Info-validate-node-name ! 234: (concat "invalid menu item " ! 235: (buffer-substring (point) ! 236: (save-excursion ! 237: (skip-chars-forward "^:") ! 238: (point)))) ! 239: (Info-extract-menu-node-name)))) ! 240: (goto-char (point-min)) ! 241: (while (re-search-forward "\\*note[ \n]*[^:\t]*:" nil t) ! 242: (goto-char (+ (match-beginning 0) 5)) ! 243: (skip-chars-forward " \n") ! 244: (Info-validate-node-name ! 245: (concat "invalid reference " ! 246: (buffer-substring (point) ! 247: (save-excursion ! 248: (skip-chars-forward "^:") ! 249: (point)))) ! 250: (Info-extract-menu-node-name "Bad format cross-reference"))))))) ! 251: (setq tags-losing (not (Info-validate-tags-table))) ! 252: (if (or lossages tags-losing) ! 253: (with-output-to-temp-buffer " *problems in info file*" ! 254: (while lossages ! 255: (princ "In node \"") ! 256: (princ (car (car lossages))) ! 257: (princ "\", ") ! 258: (let ((tem (nth 1 (car lossages)))) ! 259: (cond ((string-match "\n" tem) ! 260: (princ (substring tem 0 (match-beginning 0))) ! 261: (princ "...")) ! 262: (t ! 263: (princ tem)))) ! 264: (if (nth 2 (car lossages)) ! 265: (progn ! 266: (princ ": ") ! 267: (let ((tem (nth 2 (car lossages)))) ! 268: (cond ((string-match "\n" tem) ! 269: (princ (substring tem 0 (match-beginning 0))) ! 270: (princ "...")) ! 271: (t ! 272: (princ tem)))))) ! 273: (terpri) ! 274: (setq lossages (cdr lossages))) ! 275: (if tags-losing (princ "\nTags table must be recomputed\n"))) ! 276: ;; Here if info file is valid. ! 277: ;; If we already made a list of problems, clear it out. ! 278: (save-excursion ! 279: (if (get-buffer " *problems in info file*") ! 280: (progn ! 281: (set-buffer " *problems in info file*") ! 282: (kill-buffer (current-buffer))))) ! 283: (message "File appears valid")))))) ! 284: ! 285: (defun Info-validate-node-name (kind &optional name) ! 286: (if name ! 287: nil ! 288: (goto-char (match-end 0)) ! 289: (skip-chars-forward " \t") ! 290: (if (= (following-char) ?\() ! 291: nil ! 292: (setq name ! 293: (buffer-substring ! 294: (point) ! 295: (progn ! 296: (skip-chars-forward "^,\t\n") ! 297: (skip-chars-backward " ") ! 298: (point)))))) ! 299: (if (null name) ! 300: nil ! 301: (setq name (downcase name)) ! 302: (or (and (> (length name) 0) (= (aref name 0) ?\()) ! 303: (assoc name allnodes) ! 304: (setq lossages ! 305: (cons (list thisnode kind name) lossages)))) ! 306: name) ! 307: ! 308: (defun Info-validate-tags-table () ! 309: (goto-char (point-min)) ! 310: (if (not (search-forward "\^_\nEnd tag table\n" nil t)) ! 311: t ! 312: (not (catch 'losing ! 313: (let* ((end (match-beginning 0)) ! 314: (start (progn (search-backward "\nTag table:\n") ! 315: (1- (match-end 0)))) ! 316: tem) ! 317: (setq tem allnodes) ! 318: (while tem ! 319: (goto-char start) ! 320: (or (equal (car (car tem)) "*") ! 321: (search-forward (concat "Node: " ! 322: (car (car tem)) ! 323: "\177") ! 324: end t) ! 325: (throw 'losing 'x)) ! 326: (setq tem (cdr tem))) ! 327: (goto-char (1+ start)) ! 328: (while (looking-at ".*Node: \\(.*\\)\177\\([0-9]+\\)$") ! 329: (setq tem (downcase (buffer-substring ! 330: (match-beginning 1) ! 331: (match-end 1)))) ! 332: (setq tem (assoc tem allnodes)) ! 333: (if (or (not tem) ! 334: (< 1000 (progn ! 335: (goto-char (match-beginning 2)) ! 336: (setq tem (- (car (cdr (cdr tem))) ! 337: (read (current-buffer)))) ! 338: (if (> tem 0) tem (- tem))))) ! 339: (throw 'losing 'y))) ! 340: (forward-line 1)) ! 341: (or (looking-at "End tag table\n") ! 342: (throw 'losing 'z)) ! 343: nil)))) ! 344: ! 345: (defun batch-info-validate () ! 346: "Runs Info-validate on the files remaining on the command line. ! 347: Must be used only with -batch, and kills emacs on completion. ! 348: Each file will be processed even if an error occurred previously. ! 349: For example, invoke \"emacs -batch -f batch-info-validate $info/ ~/*.info\"" ! 350: (if (not noninteractive) ! 351: (error "batch-info-validate may only be used -batch.")) ! 352: (let ((version-control t) ! 353: (auto-save-default nil) ! 354: (find-file-run-dired nil) ! 355: (kept-old-versions 259259) ! 356: (kept-new-versions 259259)) ! 357: (let ((error 0) ! 358: file ! 359: (files ())) ! 360: (while command-line-args-left ! 361: (setq file (expand-file-name (car command-line-args-left))) ! 362: (cond ((not (file-exists-p file)) ! 363: (message ">> %s does not exist!" file) ! 364: (setq error 1 ! 365: command-line-args-left (cdr command-line-args-left))) ! 366: ((file-directory-p file) ! 367: (setq command-line-args-left (nconc (directory-files file) ! 368: (cdr command-line-args-left)))) ! 369: (t ! 370: (setq files (cons file files) ! 371: command-line-args-left (cdr command-line-args-left))))) ! 372: (while files ! 373: (setq file (car files) ! 374: files (cdr files)) ! 375: (let ((lose nil)) ! 376: (condition-case err ! 377: (progn ! 378: (if buffer-file-name (kill-buffer (current-buffer))) ! 379: (find-file file) ! 380: (buffer-flush-undo (current-buffer)) ! 381: (set-buffer-modified-p nil) ! 382: (fundamental-mode) ! 383: (let ((case-fold-search nil)) ! 384: (goto-char (point-max)) ! 385: (cond ((search-backward "\n\^_\^L\nTag table:\n" nil t) ! 386: (message "%s already tagified" file)) ! 387: ((< (point-max) 30000) ! 388: (message "%s too small to bother tagifying" file)) ! 389: (t ! 390: (message "Tagifying %s..." file) ! 391: (Info-tagify) ! 392: (message "Tagifying %s...done" file)))) ! 393: (let ((loss-name " *problems in info file*")) ! 394: (message "Checking validity of info file %s..." file) ! 395: (if (get-buffer loss-name) ! 396: (kill-buffer loss-name)) ! 397: (Info-validate) ! 398: (if (not (get-buffer loss-name)) ! 399: nil ;(message "Checking validity of info file %s... OK" file) ! 400: (message "----------------------------------------------------------------------") ! 401: (message ">> PROBLEMS IN INFO FILE %s" file) ! 402: (save-excursion ! 403: (set-buffer loss-name) ! 404: (princ (buffer-substring (point-min) (point-max)))) ! 405: (message "----------------------------------------------------------------------") ! 406: (setq error 1 lose t))) ! 407: (if (and (buffer-modified-p) ! 408: (not lose)) ! 409: (progn (message "Saving modified %s" file) ! 410: (save-buffer)))) ! 411: (error (message ">> Error: %s" (prin1-to-string err)))))) ! 412: (kill-emacs error))))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.