Mercurial > hg > xemacs-beta
comparison lisp/gnus/nnheader.el @ 98:0d2f883870bc r20-1b1
Import from CVS: tag r20-1b1
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:13:56 +0200 |
parents | 131b0175ea99 |
children | 360340f9fd5f |
comparison
equal
deleted
inserted
replaced
97:498bf5da1c90 | 98:0d2f883870bc |
---|---|
1 ;;; nnheader.el --- header access macros for Gnus and its backends | 1 ;;; nnheader.el --- header access macros for Gnus and its backends |
2 ;; Copyright (C) 1987,88,89,90,93,94,95,96 Free Software Foundation, Inc. | 2 ;; Copyright (C) 1987,88,89,90,93,94,95,96,97 Free Software Foundation, Inc. |
3 | 3 |
4 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> | 4 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> |
5 ;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no> | 5 ;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no> |
6 ;; Keywords: news | 6 ;; Keywords: news |
7 | 7 |
36 ;; uses it for xrefs.) | 36 ;; uses it for xrefs.) |
37 | 37 |
38 ;;; Code: | 38 ;;; Code: |
39 | 39 |
40 (require 'mail-utils) | 40 (require 'mail-utils) |
41 (eval-when-compile (require 'cl)) | |
42 | 41 |
43 (defvar nnheader-max-head-length 4096 | 42 (defvar nnheader-max-head-length 4096 |
44 "*Max length of the head of articles.") | 43 "*Max length of the head of articles.") |
44 | |
45 (defvar nnheader-head-chop-length 2048 | |
46 "*Length of each read operation when trying to fetch HEAD headers.") | |
45 | 47 |
46 (defvar nnheader-file-name-translation-alist nil | 48 (defvar nnheader-file-name-translation-alist nil |
47 "*Alist that says how to translate characters in file names. | 49 "*Alist that says how to translate characters in file names. |
48 For instance, if \":\" is illegal as a file character in file names | 50 For instance, if \":\" is illegal as a file character in file names |
49 on your system, you could say something like: | 51 on your system, you could say something like: |
50 | 52 |
51 \(setq nnheader-file-name-translation-alist '((?: . ?_)))") | 53 \(setq nnheader-file-name-translation-alist '((?: . ?_)))") |
52 | 54 |
55 (eval-and-compile | |
56 (autoload 'nnmail-message-id "nnmail") | |
57 (autoload 'mail-position-on-field "sendmail") | |
58 (autoload 'message-remove-header "message") | |
59 (autoload 'cancel-function-timers "timers")) | |
60 | |
53 ;;; Header access macros. | 61 ;;; Header access macros. |
54 | 62 |
55 (defmacro mail-header-number (header) | 63 (defmacro mail-header-number (header) |
56 "Return article number in HEADER." | 64 "Return article number in HEADER." |
57 `(aref ,header 0)) | 65 `(aref ,header 0)) |
128 | 136 |
129 (defun make-mail-header (&optional init) | 137 (defun make-mail-header (&optional init) |
130 "Create a new mail header structure initialized with INIT." | 138 "Create a new mail header structure initialized with INIT." |
131 (make-vector 9 init)) | 139 (make-vector 9 init)) |
132 | 140 |
141 (defun make-full-mail-header (&optional number subject from date id | |
142 references chars lines xref) | |
143 "Create a new mail header structure initialized with the parameters given." | |
144 (vector number subject from date id references chars lines xref)) | |
145 | |
146 ;; fake message-ids: generation and detection | |
147 | |
148 (defvar nnheader-fake-message-id 1) | |
149 | |
150 (defsubst nnheader-generate-fake-message-id () | |
151 (concat "fake+none+" (int-to-string (incf nnheader-fake-message-id)))) | |
152 | |
153 (defsubst nnheader-fake-message-id-p (id) | |
154 (save-match-data ; regular message-id's are <.*> | |
155 (string-match "\\`fake\\+none\\+[0-9]+\\'" id))) | |
156 | |
133 ;; Parsing headers and NOV lines. | 157 ;; Parsing headers and NOV lines. |
134 | 158 |
135 (defsubst nnheader-header-value () | 159 (defsubst nnheader-header-value () |
136 (buffer-substring (match-end 0) (gnus-point-at-eol))) | 160 (buffer-substring (match-end 0) (gnus-point-at-eol))) |
137 | |
138 (defvar nnheader-newsgroup-none-id 1) | |
139 | 161 |
140 (defun nnheader-parse-head (&optional naked) | 162 (defun nnheader-parse-head (&optional naked) |
141 (let ((case-fold-search t) | 163 (let ((case-fold-search t) |
142 (cur (current-buffer)) | 164 (cur (current-buffer)) |
143 (buffer-read-only nil) | 165 (buffer-read-only nil) |
144 end ref in-reply-to lines p) | 166 in-reply-to lines p) |
145 (goto-char (point-min)) | 167 (goto-char (point-min)) |
146 (when naked | 168 (when naked |
147 (insert "\n")) | 169 (insert "\n")) |
148 ;; Search to the beginning of the next header. Error messages | 170 ;; Search to the beginning of the next header. Error messages |
149 ;; do not begin with 2 or 3. | 171 ;; do not begin with 2 or 3. |
150 (prog1 | 172 (prog1 |
151 (when (or naked (re-search-forward "^[23][0-9]+ " nil t)) | 173 (when (or naked (re-search-forward "^[23][0-9]+ " nil t)) |
152 ;; This implementation of this function, with nine | 174 ;; This implementation of this function, with nine |
153 ;; search-forwards instead of the one re-search-forward and | 175 ;; search-forwards instead of the one re-search-forward and |
189 (goto-char p) | 211 (goto-char p) |
190 (if (search-forward "\nmessage-id: " nil t) | 212 (if (search-forward "\nmessage-id: " nil t) |
191 (nnheader-header-value) | 213 (nnheader-header-value) |
192 ;; If there was no message-id, we just fake one to make | 214 ;; If there was no message-id, we just fake one to make |
193 ;; subsequent routines simpler. | 215 ;; subsequent routines simpler. |
194 (concat "none+" | 216 (nnheader-generate-fake-message-id))) |
195 (int-to-string | |
196 (incf nnheader-newsgroup-none-id))))) | |
197 ;; References. | 217 ;; References. |
198 (progn | 218 (progn |
199 (goto-char p) | 219 (goto-char p) |
200 (if (search-forward "\nreferences: " nil t) | 220 (if (search-forward "\nreferences: " nil t) |
201 (nnheader-header-value) | 221 (nnheader-header-value) |
224 (nnheader-header-value))))) | 244 (nnheader-header-value))))) |
225 (when naked | 245 (when naked |
226 (goto-char (point-min)) | 246 (goto-char (point-min)) |
227 (delete-char 1))))) | 247 (delete-char 1))))) |
228 | 248 |
249 (defmacro nnheader-nov-skip-field () | |
250 '(search-forward "\t" eol 'move)) | |
251 | |
252 (defmacro nnheader-nov-field () | |
253 '(buffer-substring (point) (if (nnheader-nov-skip-field) (1- (point)) eol))) | |
254 | |
255 (defmacro nnheader-nov-read-integer () | |
256 '(prog1 | |
257 (if (= (following-char) ?\t) | |
258 0 | |
259 (let ((num (ignore-errors (read (current-buffer))))) | |
260 (if (numberp num) num 0))) | |
261 (or (eobp) (forward-char 1)))) | |
262 | |
263 ;; (defvar nnheader-none-counter 0) | |
264 | |
265 (defun nnheader-parse-nov () | |
266 (let ((eol (gnus-point-at-eol))) | |
267 (vector | |
268 (nnheader-nov-read-integer) ; number | |
269 (nnheader-nov-field) ; subject | |
270 (nnheader-nov-field) ; from | |
271 (nnheader-nov-field) ; date | |
272 (or (nnheader-nov-field) | |
273 (nnheader-generate-fake-message-id)) ; id | |
274 (nnheader-nov-field) ; refs | |
275 (nnheader-nov-read-integer) ; chars | |
276 (nnheader-nov-read-integer) ; lines | |
277 (if (= (following-char) ?\n) | |
278 nil | |
279 (nnheader-nov-field)) ; misc | |
280 ))) | |
281 | |
229 (defun nnheader-insert-nov (header) | 282 (defun nnheader-insert-nov (header) |
230 (princ (mail-header-number header) (current-buffer)) | 283 (princ (mail-header-number header) (current-buffer)) |
231 (insert | 284 (insert |
232 "\t" | 285 "\t" |
233 (or (mail-header-subject header) "(none)") "\t" | 286 (or (mail-header-subject header) "(none)") "\t" |
234 (or (mail-header-from header) "(nobody)") "\t" | 287 (or (mail-header-from header) "(nobody)") "\t" |
235 (or (mail-header-date header) "") "\t" | 288 (or (mail-header-date header) "") "\t" |
236 (or (mail-header-id header) | 289 (or (mail-header-id header) |
237 (nnmail-message-id)) "\t" | 290 (nnmail-message-id)) |
291 "\t" | |
238 (or (mail-header-references header) "") "\t") | 292 (or (mail-header-references header) "") "\t") |
239 (princ (or (mail-header-chars header) 0) (current-buffer)) | 293 (princ (or (mail-header-chars header) 0) (current-buffer)) |
240 (insert "\t") | 294 (insert "\t") |
241 (princ (or (mail-header-lines header) 0) (current-buffer)) | 295 (princ (or (mail-header-lines header) 0) (current-buffer)) |
242 (insert "\t") | 296 (insert "\t") |
243 (when (mail-header-xref header) | 297 (when (mail-header-xref header) |
244 (insert "Xref: " (mail-header-xref header) "\t")) | 298 (insert "Xref: " (mail-header-xref header) "\t")) |
245 (insert "\n")) | 299 (insert "\n")) |
246 | 300 |
247 (defun nnheader-insert-article-line (article) | 301 (defun nnheader-insert-article-line (article) |
248 (goto-char (point-min)) | 302 (goto-char (point-min)) |
252 (search-forward "\n\n" nil 'move) | 306 (search-forward "\n\n" nil 'move) |
253 (delete-region (point) (point-max)) | 307 (delete-region (point) (point-max)) |
254 (forward-char -1) | 308 (forward-char -1) |
255 (insert ".")) | 309 (insert ".")) |
256 | 310 |
311 (defun nnheader-nov-delete-outside-range (beg end) | |
312 "Delete all NOV lines that lie outside the BEG to END range." | |
313 ;; First we find the first wanted line. | |
314 (nnheader-find-nov-line beg) | |
315 (delete-region (point-min) (point)) | |
316 ;; Then we find the last wanted line. | |
317 (when (nnheader-find-nov-line end) | |
318 (forward-line 1)) | |
319 (delete-region (point) (point-max))) | |
320 | |
321 (defun nnheader-find-nov-line (article) | |
322 "Put point at the NOV line that start with ARTICLE. | |
323 If ARTICLE doesn't exist, put point where that line | |
324 would have been. The function will return non-nil if | |
325 the line could be found." | |
326 ;; This function basically does a binary search. | |
327 (let ((max (point-max)) | |
328 (min (goto-char (point-min))) | |
329 (cur (current-buffer)) | |
330 (prev (point-min)) | |
331 num found) | |
332 (while (not found) | |
333 (goto-char (/ (+ max min) 2)) | |
334 (beginning-of-line) | |
335 (if (or (= (point) prev) | |
336 (eobp)) | |
337 (setq found t) | |
338 (setq prev (point)) | |
339 (cond ((> (setq num (read cur)) article) | |
340 (setq max (point))) | |
341 ((< num article) | |
342 (setq min (point))) | |
343 (t | |
344 (setq found 'yes))))) | |
345 ;; We may be at the first line. | |
346 (when (and (not num) | |
347 (not (eobp))) | |
348 (setq num (read cur))) | |
349 ;; Now we may have found the article we're looking for, or we | |
350 ;; may be somewhere near it. | |
351 (when (and (not (eq found 'yes)) | |
352 (not (eq num article))) | |
353 (setq found (point)) | |
354 (while (and (< (point) max) | |
355 (or (not (numberp num)) | |
356 (< num article))) | |
357 (forward-line 1) | |
358 (setq found (point)) | |
359 (or (eobp) | |
360 (= (setq num (read cur)) article))) | |
361 (unless (eq num article) | |
362 (goto-char found))) | |
363 (beginning-of-line) | |
364 (eq num article))) | |
365 | |
257 ;; Various cruft the backends and Gnus need to communicate. | 366 ;; Various cruft the backends and Gnus need to communicate. |
258 | 367 |
259 (defvar nntp-server-buffer nil) | 368 (defvar nntp-server-buffer nil) |
260 (defvar gnus-verbose-backends 7 | 369 (defvar gnus-verbose-backends 7 |
261 "*A number that says how talkative the Gnus backends should be.") | 370 "*A number that says how talkative the Gnus backends should be.") |
267 (defvar nnheader-callback-function nil) | 376 (defvar nnheader-callback-function nil) |
268 | 377 |
269 (defun nnheader-init-server-buffer () | 378 (defun nnheader-init-server-buffer () |
270 "Initialize the Gnus-backend communication buffer." | 379 "Initialize the Gnus-backend communication buffer." |
271 (save-excursion | 380 (save-excursion |
272 (setq nntp-server-buffer (get-buffer-create " *nntpd*")) | 381 (unless (gnus-buffer-live-p nntp-server-buffer) |
382 (setq nntp-server-buffer (get-buffer-create " *nntpd*"))) | |
273 (set-buffer nntp-server-buffer) | 383 (set-buffer nntp-server-buffer) |
274 (buffer-disable-undo (current-buffer)) | 384 (buffer-disable-undo (current-buffer)) |
275 (erase-buffer) | 385 (erase-buffer) |
276 (kill-all-local-variables) | 386 (kill-all-local-variables) |
277 (setq case-fold-search t) ;Should ignore case. | 387 (setq case-fold-search t) ;Should ignore case. |
278 t)) | 388 t)) |
279 | |
280 | 389 |
281 ;;; Various functions the backends use. | 390 ;;; Various functions the backends use. |
282 | 391 |
283 (defun nnheader-file-error (file) | 392 (defun nnheader-file-error (file) |
284 "Return a string that says what is wrong with FILE." | 393 "Return a string that says what is wrong with FILE." |
295 (defun nnheader-insert-head (file) | 404 (defun nnheader-insert-head (file) |
296 "Insert the head of the article." | 405 "Insert the head of the article." |
297 (when (file-exists-p file) | 406 (when (file-exists-p file) |
298 (if (eq nnheader-max-head-length t) | 407 (if (eq nnheader-max-head-length t) |
299 ;; Just read the entire file. | 408 ;; Just read the entire file. |
300 (nnheader-insert-file-contents-literally file) | 409 (nnheader-insert-file-contents file) |
301 ;; Read 1K blocks until we find a separator. | 410 ;; Read 1K blocks until we find a separator. |
302 (let ((beg 0) | 411 (let ((beg 0) |
303 format-alist | 412 format-alist) |
304 (chop 1024)) | 413 (while (and (eq nnheader-head-chop-length |
305 (while (and (eq chop (nth 1 (insert-file-contents | 414 (nth 1 (nnheader-insert-file-contents |
306 file nil beg (incf beg chop)))) | 415 file nil beg |
307 (prog1 (not (search-forward "\n\n" nil t)) | 416 (incf beg nnheader-head-chop-length)))) |
417 (prog1 (not (search-forward "\n\n" nil t)) | |
308 (goto-char (point-max))) | 418 (goto-char (point-max))) |
309 (or (null nnheader-max-head-length) | 419 (or (null nnheader-max-head-length) |
310 (< beg nnheader-max-head-length)))))) | 420 (< beg nnheader-max-head-length)))))) |
311 t)) | 421 t)) |
312 | 422 |
319 (goto-char (point-min)) | 429 (goto-char (point-min)) |
320 (while (looking-at "[A-Z][^ \t]+:.*\n\\([ \t].*\n\\)*\\|From .*\n") | 430 (while (looking-at "[A-Z][^ \t]+:.*\n\\([ \t].*\n\\)*\\|From .*\n") |
321 (goto-char (match-end 0))) | 431 (goto-char (match-end 0))) |
322 (prog1 | 432 (prog1 |
323 (eobp) | 433 (eobp) |
324 (widen)))) | 434 (widen)))) |
325 | 435 |
326 (defun nnheader-insert-references (references message-id) | 436 (defun nnheader-insert-references (references message-id) |
327 "Insert a References header based on REFERENCES and MESSAGE-ID." | 437 "Insert a References header based on REFERENCES and MESSAGE-ID." |
328 (if (and (not references) (not message-id)) | 438 (if (and (not references) (not message-id)) |
329 () ; This is illegal, but not all articles have Message-IDs. | 439 () ; This is illegal, but not all articles have Message-IDs. |
330 (mail-position-on-field "References") | 440 (mail-position-on-field "References") |
331 (let ((begin (save-excursion (beginning-of-line) (point))) | 441 (let ((begin (save-excursion (beginning-of-line) (point))) |
332 (fill-column 78) | 442 (fill-column 78) |
333 (fill-prefix "\t")) | 443 (fill-prefix "\t")) |
334 (if references (insert references)) | 444 (when references |
335 (if (and references message-id) (insert " ")) | 445 (insert references)) |
336 (if message-id (insert message-id)) | 446 (when (and references message-id) |
447 (insert " ")) | |
448 (when message-id | |
449 (insert message-id)) | |
337 ;; Fold long References lines to conform to RFC1036 (sort of). | 450 ;; Fold long References lines to conform to RFC1036 (sort of). |
338 ;; The region must end with a newline to fill the region | 451 ;; The region must end with a newline to fill the region |
339 ;; without inserting extra newline. | 452 ;; without inserting extra newline. |
340 (fill-region-as-paragraph begin (1+ (point)))))) | 453 (fill-region-as-paragraph begin (1+ (point)))))) |
341 | 454 |
357 (if (search-forward "\n\n" nil t) | 470 (if (search-forward "\n\n" nil t) |
358 (1- (point)) | 471 (1- (point)) |
359 (point-max))) | 472 (point-max))) |
360 (goto-char (point-min))) | 473 (goto-char (point-min))) |
361 | 474 |
362 (defun nnheader-set-temp-buffer (name) | 475 (defun nnheader-set-temp-buffer (name &optional noerase) |
363 "Set-buffer to an empty (possibly new) buffer called NAME with undo disabled." | 476 "Set-buffer to an empty (possibly new) buffer called NAME with undo disabled." |
364 (set-buffer (get-buffer-create name)) | 477 (set-buffer (get-buffer-create name)) |
365 (buffer-disable-undo (current-buffer)) | 478 (buffer-disable-undo (current-buffer)) |
366 (erase-buffer) | 479 (unless noerase |
480 (erase-buffer)) | |
367 (current-buffer)) | 481 (current-buffer)) |
368 | 482 |
369 (defmacro nnheader-temp-write (file &rest forms) | 483 (defmacro nnheader-temp-write (file &rest forms) |
370 "Create a new buffer, evaluate FORM there, and write the buffer to FILE." | 484 "Create a new buffer, evaluate FORMS there, and write the buffer to FILE. |
371 `(save-excursion | 485 Return the value of FORMS. |
372 (let ((nnheader-temp-file ,file) | 486 If FILE is nil, just evaluate FORMS and don't save anything. |
373 (nnheader-temp-cur-buffer | 487 If FILE is t, return the buffer contents as a string." |
374 (nnheader-set-temp-buffer | 488 (let ((temp-file (make-symbol "temp-file")) |
375 (generate-new-buffer-name " *nnheader temp*")))) | 489 (temp-buffer (make-symbol "temp-buffer")) |
376 (when (and nnheader-temp-file | 490 (temp-results (make-symbol "temp-results"))) |
377 (not (file-directory-p (file-name-directory | 491 `(save-excursion |
378 nnheader-temp-file)))) | 492 (let* ((,temp-file ,file) |
379 (make-directory (file-name-directory nnheader-temp-file) t)) | 493 (default-major-mode 'fundamental-mode) |
380 (unwind-protect | 494 (,temp-buffer |
381 (prog1 | 495 (set-buffer |
382 (progn | 496 (get-buffer-create |
383 ,@forms) | 497 (generate-new-buffer-name " *nnheader temp*")))) |
384 (when nnheader-temp-file | 498 ,temp-results) |
385 (set-buffer nnheader-temp-cur-buffer) | 499 (unwind-protect |
386 (write-region (point-min) (point-max) | 500 (progn |
387 nnheader-temp-file nil 'nomesg))) | 501 (setq ,temp-results (progn ,@forms)) |
388 (when (buffer-name nnheader-temp-cur-buffer) | 502 (cond |
389 (kill-buffer nnheader-temp-cur-buffer)))))) | 503 ;; Don't save anything. |
504 ((null ,temp-file) | |
505 ,temp-results) | |
506 ;; Return the buffer contents. | |
507 ((eq ,temp-file t) | |
508 (set-buffer ,temp-buffer) | |
509 (buffer-string)) | |
510 ;; Save a file. | |
511 (t | |
512 (set-buffer ,temp-buffer) | |
513 ;; Make sure the directory where this file is | |
514 ;; to be saved exists. | |
515 (when (not (file-directory-p | |
516 (file-name-directory ,temp-file))) | |
517 (make-directory (file-name-directory ,temp-file) t)) | |
518 ;; Save the file. | |
519 (write-region (point-min) (point-max) | |
520 ,temp-file nil 'nomesg) | |
521 ,temp-results))) | |
522 ;; Kill the buffer. | |
523 (when (buffer-name ,temp-buffer) | |
524 (kill-buffer ,temp-buffer))))))) | |
390 | 525 |
391 (put 'nnheader-temp-write 'lisp-indent-function 1) | 526 (put 'nnheader-temp-write 'lisp-indent-function 1) |
392 (put 'nnheader-temp-write 'lisp-indent-hook 1) | |
393 (put 'nnheader-temp-write 'edebug-form-spec '(form body)) | 527 (put 'nnheader-temp-write 'edebug-form-spec '(form body)) |
394 | 528 |
395 (defvar jka-compr-compression-info-list) | 529 (defvar jka-compr-compression-info-list) |
396 (defvar nnheader-numerical-files | 530 (defvar nnheader-numerical-files |
397 (if (boundp 'jka-compr-compression-info-list) | 531 (if (boundp 'jka-compr-compression-info-list) |
438 (nnheader-directory-files-safe | 572 (nnheader-directory-files-safe |
439 dir nil nnheader-numerical-short-files t))) | 573 dir nil nnheader-numerical-short-files t))) |
440 | 574 |
441 (defun nnheader-fold-continuation-lines () | 575 (defun nnheader-fold-continuation-lines () |
442 "Fold continuation lines in the current buffer." | 576 "Fold continuation lines in the current buffer." |
443 (goto-char (point-min)) | 577 (nnheader-replace-regexp "\\(\r?\n[ \t]+\\)+" " ")) |
444 (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t) | |
445 (replace-match " " t t))) | |
446 | 578 |
447 (defun nnheader-translate-file-chars (file) | 579 (defun nnheader-translate-file-chars (file) |
448 (if (null nnheader-file-name-translation-alist) | 580 (if (null nnheader-file-name-translation-alist) |
449 ;; No translation is necessary. | 581 ;; No translation is necessary. |
450 file | 582 file |
475 (car args) | 607 (car args) |
476 (apply 'format args))) | 608 (apply 'format args))) |
477 nil) | 609 nil) |
478 | 610 |
479 (defun nnheader-get-report (backend) | 611 (defun nnheader-get-report (backend) |
480 (message "%s" (symbol-value (intern (format "%s-status-string" backend))))) | 612 "Get the most recent report from BACKEND." |
613 (condition-case () | |
614 (message "%s" (symbol-value (intern (format "%s-status-string" | |
615 backend)))) | |
616 (error (message "")))) | |
481 | 617 |
482 (defun nnheader-insert (format &rest args) | 618 (defun nnheader-insert (format &rest args) |
483 "Clear the communicaton buffer and insert FORMAT and ARGS into the buffer. | 619 "Clear the communication buffer and insert FORMAT and ARGS into the buffer. |
484 If FORMAT isn't a format string, it and all ARGS will be inserted | 620 If FORMAT isn't a format string, it and all ARGS will be inserted |
485 without formatting." | 621 without formatting." |
486 (save-excursion | 622 (save-excursion |
487 (set-buffer nntp-server-buffer) | 623 (set-buffer nntp-server-buffer) |
488 (erase-buffer) | 624 (erase-buffer) |
496 (when (and (file-exists-p file) | 632 (when (and (file-exists-p file) |
497 (file-readable-p file) | 633 (file-readable-p file) |
498 (file-regular-p file)) | 634 (file-regular-p file)) |
499 (save-excursion | 635 (save-excursion |
500 (nnheader-set-temp-buffer " *mail-file-mbox-p*") | 636 (nnheader-set-temp-buffer " *mail-file-mbox-p*") |
501 (nnheader-insert-file-contents-literally file) | 637 (nnheader-insert-file-contents file) |
502 (goto-char (point-min)) | 638 (goto-char (point-min)) |
503 (prog1 | 639 (prog1 |
504 (looking-at message-unix-mail-delimiter) | 640 (looking-at message-unix-mail-delimiter) |
505 (kill-buffer (current-buffer)))))) | 641 (kill-buffer (current-buffer)))))) |
506 | 642 |
509 (let ((string (substring string 0)) ;Copy string. | 645 (let ((string (substring string 0)) ;Copy string. |
510 (len (length string)) | 646 (len (length string)) |
511 (idx 0)) | 647 (idx 0)) |
512 ;; Replace all occurrences of FROM with TO. | 648 ;; Replace all occurrences of FROM with TO. |
513 (while (< idx len) | 649 (while (< idx len) |
514 (if (= (aref string idx) from) | 650 (when (= (aref string idx) from) |
515 (aset string idx to)) | 651 (aset string idx to)) |
516 (setq idx (1+ idx))) | 652 (setq idx (1+ idx))) |
517 string)) | 653 string)) |
518 | 654 |
519 (defun nnheader-file-to-group (file &optional top) | 655 (defun nnheader-file-to-group (file &optional top) |
520 "Return a group name based on FILE and TOP." | 656 "Return a group name based on FILE and TOP." |
557 (defun nnheader-functionp (form) | 693 (defun nnheader-functionp (form) |
558 "Return non-nil if FORM is funcallable." | 694 "Return non-nil if FORM is funcallable." |
559 (or (and (symbolp form) (fboundp form)) | 695 (or (and (symbolp form) (fboundp form)) |
560 (and (listp form) (eq (car form) 'lambda)))) | 696 (and (listp form) (eq (car form) 'lambda)))) |
561 | 697 |
562 (defun nnheader-concat (dir file) | 698 (defun nnheader-concat (dir &rest files) |
563 "Concat DIR as directory to FILE." | 699 "Concat DIR as directory to FILE." |
564 (concat (file-name-as-directory dir) file)) | 700 (apply 'concat (file-name-as-directory dir) files)) |
565 | 701 |
566 (defun nnheader-ms-strip-cr () | 702 (defun nnheader-ms-strip-cr () |
567 "Strip ^M from the end of all lines." | 703 "Strip ^M from the end of all lines." |
568 (save-excursion | 704 (save-excursion |
569 (goto-char (point-min)) | 705 (goto-char (point-min)) |
572 | 708 |
573 (defun nnheader-file-size (file) | 709 (defun nnheader-file-size (file) |
574 "Return the file size of FILE or 0." | 710 "Return the file size of FILE or 0." |
575 (or (nth 7 (file-attributes file)) 0)) | 711 (or (nth 7 (file-attributes file)) 0)) |
576 | 712 |
577 (defun nnheader-find-etc-directory (package) | 713 (defun nnheader-find-etc-directory (package &optional file) |
578 "Go through the path and find the \".../etc/PACKAGE\" directory." | 714 "Go through the path and find the \".../etc/PACKAGE\" directory. |
715 If FILE, find the \".../etc/PACKAGE\" file instead." | |
579 (let ((path load-path) | 716 (let ((path load-path) |
580 dir result) | 717 dir result) |
581 ;; We try to find the dir by looking at the load path, | 718 ;; We try to find the dir by looking at the load path, |
582 ;; stripping away the last component and adding "etc/". | 719 ;; stripping away the last component and adding "etc/". |
583 (while path | 720 (while path |
584 (if (and (car path) | 721 (if (and (car path) |
585 (file-exists-p | 722 (file-exists-p |
586 (setq dir (concat | 723 (setq dir (concat |
587 (file-name-directory | 724 (file-name-directory |
588 (directory-file-name (car path))) | 725 (directory-file-name (car path))) |
589 "etc/" package "/"))) | 726 "etc/" package |
590 (file-directory-p dir)) | 727 (if file "" "/")))) |
728 (or file (file-directory-p dir))) | |
591 (setq result dir | 729 (setq result dir |
592 path nil) | 730 path nil) |
593 (setq path (cdr path)))) | 731 (setq path (cdr path)))) |
594 result)) | 732 result)) |
595 | 733 |
596 (defvar ange-ftp-path-format) | 734 (defvar ange-ftp-path-format) |
597 (defvar efs-path-regexp) | 735 (defvar efs-path-regexp) |
598 (defun nnheader-re-read-dir (path) | 736 (defun nnheader-re-read-dir (path) |
599 "Re-read directory PATH if PATH is on a remote system." | 737 "Re-read directory PATH if PATH is on a remote system." |
600 (if (and (fboundp 'efs-re-read-dir) (boundp 'efs-path-regexp)) | 738 (if (and (fboundp 'efs-re-read-dir) (boundp 'efs-path-regexp)) |
601 (when (string-match efs-path-regexp path) | 739 (when (string-match efs-path-regexp path) |
602 (efs-re-read-dir path)) | 740 (efs-re-read-dir path)) |
603 (if (and (fboundp 'ange-ftp-re-read-dir) (boundp 'ange-ftp-path-format)) | 741 (when (and (fboundp 'ange-ftp-re-read-dir) (boundp 'ange-ftp-path-format)) |
604 (when (string-match (car ange-ftp-path-format) path) | 742 (when (string-match (car ange-ftp-path-format) path) |
605 (ange-ftp-re-read-dir path))))) | 743 (ange-ftp-re-read-dir path))))) |
606 | 744 |
745 (defun nnheader-insert-file-contents (filename &optional visit beg end replace) | |
746 "Like `insert-file-contents', q.v., but only reads in the file. | |
747 A buffer may be modified in several ways after reading into the buffer due | |
748 to advanced Emacs features, such as file-name-handlers, format decoding, | |
749 find-file-hooks, etc. | |
750 This function ensures that none of these modifications will take place." | |
751 (let ((format-alist nil) | |
752 (auto-mode-alist (nnheader-auto-mode-alist)) | |
753 (default-major-mode 'fundamental-mode) | |
754 (after-insert-file-functions nil)) | |
755 (insert-file-contents filename visit beg end replace))) | |
756 | |
757 (defun nnheader-find-file-noselect (&rest args) | |
758 (let ((format-alist nil) | |
759 (auto-mode-alist (nnheader-auto-mode-alist)) | |
760 (default-major-mode 'fundamental-mode) | |
761 (enable-local-variables nil) | |
762 (after-insert-file-functions nil)) | |
763 (apply 'find-file-noselect args))) | |
764 | |
765 (defun nnheader-auto-mode-alist () | |
766 "Return an `auto-mode-alist' with only the .gz (etc) thingies." | |
767 (let ((alist auto-mode-alist) | |
768 out) | |
769 (while alist | |
770 (when (listp (cdar alist)) | |
771 (push (car alist) out)) | |
772 (pop alist)) | |
773 (nreverse out))) | |
774 | |
775 (defun nnheader-directory-regular-files (dir) | |
776 "Return a list of all regular files in DIR." | |
777 (let ((files (directory-files dir t)) | |
778 out) | |
779 (while files | |
780 (when (file-regular-p (car files)) | |
781 (push (car files) out)) | |
782 (pop files)) | |
783 (nreverse out))) | |
784 | |
785 (defmacro nnheader-skeleton-replace (from &optional to regexp) | |
786 `(let ((new (generate-new-buffer " *nnheader replace*")) | |
787 (cur (current-buffer)) | |
788 (start (point-min))) | |
789 (set-buffer new) | |
790 (buffer-disable-undo (current-buffer)) | |
791 (set-buffer cur) | |
792 (goto-char (point-min)) | |
793 (while (,(if regexp 're-search-forward 'search-forward) | |
794 ,from nil t) | |
795 (insert-buffer-substring | |
796 cur start (prog1 (match-beginning 0) (set-buffer new))) | |
797 (goto-char (point-max)) | |
798 ,(when to `(insert ,to)) | |
799 (set-buffer cur) | |
800 (setq start (point))) | |
801 (insert-buffer-substring | |
802 cur start (prog1 (point-max) (set-buffer new))) | |
803 (copy-to-buffer cur (point-min) (point-max)) | |
804 (kill-buffer (current-buffer)) | |
805 (set-buffer cur))) | |
806 | |
807 (defun nnheader-replace-string (from to) | |
808 "Do a fast replacement of FROM to TO from point to point-max." | |
809 (nnheader-skeleton-replace from to)) | |
810 | |
811 (defun nnheader-replace-regexp (from to) | |
812 "Do a fast regexp replacement of FROM to TO from point to point-max." | |
813 (nnheader-skeleton-replace from to t)) | |
814 | |
815 (defun nnheader-strip-cr () | |
816 "Strip all \r's from the current buffer." | |
817 (nnheader-skeleton-replace "\r")) | |
818 | |
607 (fset 'nnheader-run-at-time 'run-at-time) | 819 (fset 'nnheader-run-at-time 'run-at-time) |
608 (fset 'nnheader-cancel-timer 'cancel-timer) | 820 (fset 'nnheader-cancel-timer 'cancel-timer) |
609 (fset 'nnheader-find-file-noselect 'find-file-noselect) | 821 (fset 'nnheader-cancel-function-timers 'cancel-function-timers) |
610 (fset 'nnheader-insert-file-contents-literally | |
611 'insert-file-contents-literally) | |
612 | 822 |
613 (when (string-match "XEmacs\\|Lucid" emacs-version) | 823 (when (string-match "XEmacs\\|Lucid" emacs-version) |
614 (require 'nnheaderxm)) | 824 (require 'nnheaderxm)) |
615 | 825 |
616 (run-hooks 'nnheader-load-hook) | 826 (run-hooks 'nnheader-load-hook) |