emacs/lisp/url/url-util.el

633 lines
21 KiB
EmacsLisp
Raw Normal View History

;;; url-util.el --- Miscellaneous helper routines for URL library -*- lexical-binding: t -*-
2004-04-16 22:05:32 +00:00
;; Copyright (C) 1996-1999, 2001, 2004-2018 Free Software Foundation,
;; Inc.
2004-04-16 22:05:32 +00:00
2004-04-04 01:21:46 +00:00
;; Author: Bill Perry <wmperry@gnu.org>
;; Maintainer: emacs-devel@gnu.org
2004-04-04 01:21:46 +00:00
;; Keywords: comm, data, processes
2004-04-16 22:05:32 +00:00
;; This file is part of GNU Emacs.
;;
;; GNU Emacs is free software: you can redistribute it and/or modify
2004-04-16 22:05:32 +00:00
;; 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.
2004-04-16 22:05:32 +00:00
;; GNU Emacs 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.
2004-04-16 22:05:32 +00:00
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
2004-04-16 22:05:32 +00:00
;;; Commentary:
;;; Code:
2004-04-04 01:21:46 +00:00
(require 'url-parse)
(require 'url-vars)
2004-04-04 01:21:46 +00:00
(autoload 'timezone-parse-date "timezone")
(autoload 'timezone-make-date-arpa-standard "timezone")
(autoload 'mail-header-extract "mailheader")
2004-04-04 01:21:46 +00:00
(defvar url-parse-args-syntax-table
(copy-syntax-table emacs-lisp-mode-syntax-table)
"A syntax table for parsing sgml attributes.")
(modify-syntax-entry ?' "\"" url-parse-args-syntax-table)
(modify-syntax-entry ?` "\"" url-parse-args-syntax-table)
(modify-syntax-entry ?{ "(" url-parse-args-syntax-table)
(modify-syntax-entry ?} ")" url-parse-args-syntax-table)
;;;###autoload
(defcustom url-debug nil
"What types of debug messages from the URL library to show.
2004-04-04 01:21:46 +00:00
Debug messages are logged to the *URL-DEBUG* buffer.
If t, all messages will be logged.
If a number, all messages will be logged, as well shown via `message'.
If a list, it is a list of the types of messages to be logged."
:type '(choice (const :tag "none" nil)
(const :tag "all" t)
(checklist :tag "custom"
(const :tag "HTTP" :value http)
(const :tag "DAV" :value dav)
(const :tag "General" :value retrieval)
(const :tag "Filename handlers" :value handlers)
(symbol :tag "Other")))
:group 'url-hairy)
;;;###autoload
(defun url-debug (tag &rest args)
(if quit-flag
(error "Interrupted!"))
(if (or (eq url-debug t)
(numberp url-debug)
(and (listp url-debug) (memq tag url-debug)))
2004-04-16 22:05:32 +00:00
(with-current-buffer (get-buffer-create "*URL-DEBUG*")
2004-04-04 01:21:46 +00:00
(goto-char (point-max))
(insert (symbol-name tag) " -> " (apply 'format args) "\n")
(if (numberp url-debug)
(apply 'message args)))))
;;;###autoload
(defun url-parse-args (str &optional nodowncase)
;; Return an assoc list of attribute/value pairs from an RFC822-type string
(let (
name ; From name=
value ; its value
results ; Assoc list of results
name-pos ; Start of XXXX= position
val-pos ; Start of value position
st
nd
)
(save-excursion
(save-restriction
(set-buffer (get-buffer-create " *urlparse-temp*"))
(set-syntax-table url-parse-args-syntax-table)
(erase-buffer)
(insert str)
(setq st (point-min)
nd (point-max))
(set-syntax-table url-parse-args-syntax-table)
(narrow-to-region st nd)
(goto-char (point-min))
(while (not (eobp))
(skip-chars-forward "; \n\t")
(setq name-pos (point))
(skip-chars-forward "^ \n\t=;")
(if (not nodowncase)
(downcase-region name-pos (point)))
(setq name (buffer-substring name-pos (point)))
(skip-chars-forward " \t\n")
(if (/= (or (char-after (point)) 0) ?=) ; There is no value
(setq value nil)
(skip-chars-forward " \t\n=")
(setq val-pos (point)
value
(cond
((or (= (or (char-after val-pos) 0) ?\")
(= (or (char-after val-pos) 0) ?'))
(buffer-substring (1+ val-pos)
(condition-case ()
(prog2
(forward-sexp 1)
(1- (point))
(skip-chars-forward "\""))
(error
(skip-chars-forward "^ \t\n")
(point)))))
(t
(buffer-substring val-pos
(progn
(skip-chars-forward "^;")
(skip-chars-backward " \t")
(point)))))))
(setq results (cons (cons name value) results))
(skip-chars-forward "; \n\t"))
results))))
;;;###autoload
(defun url-insert-entities-in-string (string)
"Convert HTML markup-start characters to entity references in STRING.
Also replaces the \" character, so that the result may be safely used as
2012-09-29 22:45:44 +02:00
an attribute value in a tag. Returns a new string with the result of the
conversion. Replaces these characters as follows:
2004-04-04 01:21:46 +00:00
& ==> &amp;
< ==> &lt;
> ==> &gt;
\" ==> &quot;"
(if (string-match "[&<>\"]" string)
* url-util.el (url-insert-entities-in-string): * url-nfs.el (url-nfs-unescape): * url-ldap.el (url-ldap): * url-imap.el (url-imap): * url-cid.el (url-cid-gnus, url-cid): Use with-current-buffer. * erc.el (erc-display-line-1, erc-process-away): * erc-truncate.el (erc-truncate-buffer-to-size): Use with-current-buffer. * term/ns-win.el (ns-scroll-bar-move, ns-face-at-pos): * play/mpuz.el (mpuz-create-buffer): * play/landmark.el (lm-prompt-for-move, lm-print-wts, lm-print-smell) (lm-print-y,s,noise, lm-print-w0, lm-init): * play/gomoku.el (gomoku-prompt-for-move): * play/fortune.el (fortune-in-buffer): * play/dissociate.el (dissociated-press): * play/decipher.el (decipher-adjacency-list, decipher-display-regexp) (decipher-analyze-buffer, decipher-stats-buffer,decipher-stats-buffer): * mail/supercite.el (sc-eref-show): * mail/smtpmail.el (smtpmail-send-it): * mail/rmailsum.el (rmail-summary-next-labeled-message) (rmail-summary-previous-labeled-message, rmail-summary-wipe) (rmail-summary-undelete-many, rmail-summary-rmail-update) (rmail-summary-goto-msg, rmail-summary-expunge) (rmail-summary-get-new-mail, rmail-summary-search-backward) (rmail-summary-add-label, rmail-summary-output-menu) (rmail-summary-output-body): * mail/rfc822.el (rfc822-addresses): * mail/reporter.el (reporter-dump-variable, reporter-dump-state): * mail/mailpost.el (post-mail-send-it): * mail/hashcash.el (hashcash-generate-payment): * mail/feedmail.el (feedmail-run-the-queue) (feedmail-queue-send-edit-prompt-help-first) (feedmail-send-it-immediately, feedmail-give-it-to-buffer-eater) (feedmail-deduce-address-list): * eshell/esh-ext.el (eshell-remote-command): * eshell/em-unix.el (eshell-occur-mode-mouse-goto): * emulation/viper-util.el (viper-glob-unix-files, viper-save-setting) (viper-wildcard-to-regexp, viper-glob-mswindows-files) (viper-save-string-in-file, viper-valid-marker): * emulation/viper-keym.el (viper-toggle-key): * emulation/viper-ex.el (ex-expand-filsyms, viper-get-ex-file) (ex-edit, ex-global, ex-mark, ex-next-related-buffer, ex-quit) (ex-get-inline-cmd-args, ex-tag, ex-command, ex-compile): * emulation/viper-cmd.el (viper-exec-form-in-vi) (viper-exec-form-in-emacs, viper-brac-function): * emulation/viper.el (viper-delocalize-var): * emulation/vip.el (vip-mode, vip-get-ex-token, vip-ex, vip-get-ex-pat) (vip-get-ex-command, vip-get-ex-opt-gc, vip-get-ex-buffer) (vip-get-ex-count, vip-get-ex-file, ex-edit, ex-global, ex-mark) (ex-map, ex-unmap, ex-quit, ex-read, ex-tag, ex-command): * emulation/vi.el (vi-switch-mode, vi-ex-cmd): * emulation/edt.el (edt-electric-helpify): * emulation/cua-rect.el (cua--rectangle-aux-replace): * emulation/cua-gmrk.el (cua--insert-at-global-mark) (cua--delete-at-global-mark, cua--copy-rectangle-to-global-mark) (cua-indent-to-global-mark-column): * calendar/diary-lib.el (calendar-mark-1): * calendar/cal-hebrew.el (calendar-hebrew-mark-date-pattern): Use with-current-buffer. * emulation/viper.el (viper-delocalize-var): Use dolist.
2009-11-03 02:04:29 +00:00
(with-current-buffer (get-buffer-create " *entity*")
2004-04-04 01:21:46 +00:00
(erase-buffer)
(buffer-disable-undo (current-buffer))
(insert string)
(goto-char (point-min))
(while (progn
(skip-chars-forward "^&<>\"")
(not (eobp)))
(insert (cdr (assq (char-after (point))
'((?\" . "&quot;")
(?& . "&amp;")
(?< . "&lt;")
(?> . "&gt;")))))
(delete-char 1))
(buffer-string))
string))
;;;###autoload
(defun url-normalize-url (url)
"Return a \"normalized\" version of URL.
2004-04-04 01:21:46 +00:00
Strips out default port numbers, etc."
(let (type data retval)
2004-04-04 01:21:46 +00:00
(setq data (url-generic-parse-url url)
type (url-type data))
(if (member type '("www" "about" "mailto" "info"))
(setq retval url)
2008-09-25 07:41:32 +00:00
;; FIXME all this does, and all this function seems to do in
;; most cases, is remove any trailing "#anchor" part of a url.
(setf (url-target data) nil)
2004-04-04 01:21:46 +00:00
(setq retval (url-recreate-url data)))
retval))
;;;###autoload
(defun url-lazy-message (&rest args)
"Just like `message', but is a no-op if called more than once a second.
2004-04-16 22:05:32 +00:00
Will not do anything if `url-show-status' is nil."
(if (or (and url-current-object
(url-silent url-current-object))
(null url-show-status)
2004-04-04 01:21:46 +00:00
(active-minibuffer-window)
(= url-lazy-message-time
(setq url-lazy-message-time (nth 1 (current-time)))))
nil
(apply 'message args)))
;;;###autoload
(defun url-get-normalized-date (&optional specified-time)
"Return a date string that most HTTP servers can understand."
(let ((system-time-locale "C"))
Simplify use of current-time and friends. * doc/misc/org.texi (Dynamic blocks): * lisp/allout-widgets.el (allout-widgets-hook-error-handler): * lisp/calendar/appt.el (appt-display-message): * lisp/calendar/icalendar.el (icalendar--convert-float-to-ical): * lisp/calendar/timeclock.el (timeclock-in, timeclock-when-to-leave) (timeclock-last-period, timeclock-day-base): * lisp/eshell/em-ls.el (eshell-ls-file): * lisp/eshell/esh-util.el (eshell-parse-ange-ls): * lisp/generic-x.el (named-database-print-serial): * lisp/net/newst-backend.el (newsticker--get-news-by-url-callback) (newsticker-get-news, newsticker--sentinel-work) (newsticker--image-get, newsticker--image-sentinel): * lisp/net/tramp-sh.el (tramp-get-remote-touch): * lisp/progmodes/opascal.el (opascal-debug-log): * lisp/textmodes/remember.el (remember-mail-date) (remember-store-in-files): * lisp/vc/vc-annotate.el (vc-annotate-display-autoscale) (vc-default-annotate-current-time): * lisp/vc/vc-bzr.el (vc-bzr-shelve-snapshot): * lisp/vc/vc-cvs.el (vc-cvs-annotate-current-time): * lisp/vc/vc-rcs.el (vc-rcs-annotate-current-time): * lisp/url/url-util.el (url-get-normalized-date): * lisp/erc/erc-backend.el (TOPIC): * lisp/gnus/gnus-delay.el (gnus-delay-article): * lisp/gnus/gnus-sum.el (gnus-summary-read-document): * lisp/gnus/gnus-util.el (gnus-seconds-today, gnus-seconds-month): * lisp/gnus/message.el (message-make-expires-date): * lisp/org/org-archive.el (org-archive-subtree) (org-archive-to-archive-sibling): * lisp/org/org-clock.el (org-resolve-clocks, org-clock-get-sum-start) (org-clock-special-range): * lisp/org/org-timer.el (org-timer-seconds): * lisp/org/org.el (org-read-date-analyze, org-get-cursor-date): * lisp/org/ox-html.el (org-html-format-spec): * lisp/org/ox-icalendar.el (org-icalendar--vtodo): Omit unnecessary call to current-time. * lisp/calendar/time-date.el (time-to-seconds) [!float-time]: * lisp/calendar/timeclock.el (timeclock-time-to-date): * lisp/vc/vc-annotate.el (vc-annotate-convert-time): Use current time if arg is nil, to be compatible with float-time. (time-date--day-in-year): New function, with most of the guts of the old time-to-day-in-year. (time-to-day-in-year): Use it. (time-to-days): Use it, to avoid decoding the same time stamp twice. * lisp/calendar/timeclock.el (timeclock-update-mode-line): * lisp/cedet/srecode/args.el (srecode-semantic-handle-:time): * lisp/gnus/gnus-util.el (gnus-seconds-year): * lisp/org/org.el (org-get-cursor-date): Don't call current-time twice to get the current time stamp, as this can lead to inconsistent results. * lisp/completion.el (cmpl-hours-since-origin): * lisp/erc/erc.el (erc-emacs-time-to-erc-time): * lisp/ido.el (ido-time-stamp): * lisp/vc/vc-annotate.el (vc-annotate-convert-time): Simplify by using float-time. * lisp/completion.el (save-completions-to-file): * lisp/url/url-cache.el (url-cache-prune-cache): Rename local var to avoid confusion. * lisp/gnus/gnus-util.el (gnus-float-time): * lisp/net/rcirc.el (rcirc-float-time): * lisp/org/org-compat.el (org-float-time): Simplify to an alias because time-to-seconds now behaves like float-time with respect to nil arg. * lisp/subr.el (progress-reporter-do-update): Don't call float-time unless needed. * lisp/erc/erc.el (erc-current-time): Simplify by using erc-emacs-time-to-erc-time. * lisp/org/org-clock.el (org-clock-get-table-data): Omit unnecessary, lossy conversion from floating point to Emacs time and back. (org-resolve-clocks): Prefer two-argument floor.
2014-10-28 18:42:51 -07:00
(format-time-string "%a, %d %b %Y %T GMT" specified-time t)))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-eat-trailing-space (x)
"Remove spaces/tabs at the end of a string."
(let ((y (1- (length x)))
(skip-chars (list ? ?\t ?\n)))
(while (and (>= y 0) (memq (aref x y) skip-chars))
(setq y (1- y)))
(substring x 0 (1+ y))))
;;;###autoload
(defun url-strip-leading-spaces (x)
"Remove spaces at the front of a string."
(let ((y (1- (length x)))
(z 0)
(skip-chars (list ? ?\t ?\n)))
(while (and (<= z y) (memq (aref x z) skip-chars))
(setq z (1+ z)))
(substring x z nil)))
(define-obsolete-function-alias 'url-pretty-length
'file-size-human-readable "24.4")
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-display-percentage (fmt perc &rest args)
(when (and url-show-status
(or (null url-current-object)
(not (url-silent url-current-object))))
(if (null fmt)
(if (fboundp 'clear-progress-display)
(clear-progress-display))
(if (and (fboundp 'progress-display) perc)
(apply 'progress-display fmt perc args)
(apply 'message fmt args)))))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-percentage (x y)
(if (fboundp 'float)
(round (* 100 (/ x (float y))))
(/ (* x 100) y)))
;;;###autoload
(defalias 'url-basepath 'url-file-directory)
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-file-directory (file)
"Return the directory part of FILE, for a URL."
2004-04-04 01:21:46 +00:00
(cond
((null file) "")
((string-match "\\?" file)
(url-file-directory (substring file 0 (match-beginning 0))))
((string-match "\\(.*\\(/\\|%2[fF]\\)\\)" file)
(match-string 1 file))))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-file-nondirectory (file)
"Return the nondirectory part of FILE, for a URL."
(cond
((null file) "")
((string-match "\\?" file)
(url-file-nondirectory (substring file 0 (match-beginning 0))))
((string-match ".*\\(?:/\\|%2[fF]\\)\\(.*\\)" file)
(match-string 1 file))
(t file)))
2004-04-04 01:21:46 +00:00
;;;###autoload
2005-09-01 16:38:39 +00:00
(defun url-parse-query-string (query &optional downcase allow-newlines)
2004-04-04 01:21:46 +00:00
(let (retval pairs cur key val)
(setq pairs (split-string query "[;&]"))
2004-04-04 01:21:46 +00:00
(while pairs
(setq cur (car pairs)
pairs (cdr pairs))
(unless (string-match "=" cur)
(setq cur (concat cur "=")))
(when (string-match "=" cur)
(setq key (url-unhex-string (substring cur 0 (match-beginning 0))
allow-newlines))
(setq val (url-unhex-string (substring cur (match-end 0) nil)
allow-newlines))
(if downcase
(setq key (downcase key)))
(setq cur (assoc key retval))
(if cur
(setcdr cur (cons val (cdr cur)))
(setq retval (cons (list key val) retval)))))
2004-04-04 01:21:46 +00:00
retval))
;;;###autoload
(defun url-build-query-string (query &optional semicolons keep-empty)
"Build a query-string.
Given a QUERY in the form:
((key1 val1)
(key2 val2)
(key3 val1 val2)
(key4)
2012-09-29 22:45:44 +02:00
(key5 \"\"))
\(This is the same format as produced by `url-parse-query-string')
This will return a string
\"key1=val1&key2=val2&key3=val1&key3=val2&key4&key5\". Keys may
be strings or symbols; if they are symbols, the symbol name will
be used.
When SEMICOLONS is given, the separator will be \";\".
When KEEP-EMPTY is given, empty values will show as \"key=\"
instead of just \"key\" as in the example above."
(mapconcat
(lambda (key-vals)
(let ((escaped
(mapcar (lambda (sym)
(url-hexify-string (format "%s" sym))) key-vals)))
(mapconcat (lambda (val)
(let ((vprint (format "%s" val))
(eprint (format "%s" (car escaped))))
(concat eprint
(if (or keep-empty
(and val (not (zerop (length vprint)))))
"="
"")
vprint)))
(or (cdr escaped) '("")) (if semicolons ";" "&"))))
query (if semicolons ";" "&")))
2004-04-04 01:21:46 +00:00
(defun url-unhex (x)
(if (> x ?9)
(if (>= x ?a)
(+ 10 (- x ?a))
(+ 10 (- x ?A)))
(- x ?0)))
;; Fixme: Is this definition better, and does it ever matter?
;; (defun url-unhex-string (str &optional allow-newlines)
;; "Remove %XX, embedded spaces, etc in a url.
;; If optional second argument ALLOW-NEWLINES is non-nil, then allow the
;; decoding of carriage returns and line feeds in the string, which is normally
;; forbidden in URL encoding."
;; (setq str (or str ""))
;; (setq str (replace-regexp-in-string "%[[:xdigit:]]\\{2\\}"
;; (lambda (match)
;; (string (string-to-number
;; (substring match 1) 16)))
;; str t t))
;; (if allow-newlines
;; (replace-regexp-in-string "[\n\r]" (lambda (match)
;; (format "%%%.2X" (aref match 0)))
;; str t t)
;; str))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-unhex-string (str &optional allow-newlines)
"Remove %XX embedded spaces, etc in a URL.
2004-04-04 01:21:46 +00:00
If optional second argument ALLOW-NEWLINES is non-nil, then allow the
decoding of carriage returns and line feeds in the string, which is normally
forbidden in URL encoding."
2004-04-04 01:21:46 +00:00
(setq str (or str ""))
(let ((tmp "")
(case-fold-search t))
(while (string-match "%[0-9a-f][0-9a-f]" str)
(let* ((start (match-beginning 0))
(ch1 (url-unhex (elt str (+ start 1))))
(code (+ (* 16 ch1)
(url-unhex (elt str (+ start 2))))))
(setq tmp (concat
tmp (substring str 0 start)
(cond
(allow-newlines
(byte-to-string code))
2004-04-04 01:21:46 +00:00
((or (= code ?\n) (= code ?\r))
" ")
(t (byte-to-string code))))
2004-04-04 01:21:46 +00:00
str (substring str (match-end 0)))))
2012-04-10 19:03:34 +02:00
(concat tmp str)))
2004-04-04 01:21:46 +00:00
(defconst url-unreserved-chars
'(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
2004-04-04 01:21:46 +00:00
?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
?- ?_ ?. ?~)
"List of characters that are unreserved in the URL spec.
This is taken from RFC 3986 (section 2.3).")
(defconst url-encoding-table
(let ((vec (make-vector 256 nil)))
(dotimes (byte 256)
;; RFC 3986 (Section 2.1): For consistency, URI producers and
;; normalizers should use uppercase hexadecimal digits for all
;; percent-encodings.
(aset vec byte (format "%%%02X" byte)))
vec)
"Vector translating bytes to URI-encoded %-sequences.")
(defun url--allowed-chars (char-list)
"Return an \"allowed character\" mask (a 256-slot vector).
The Nth element is non-nil if character N is in CHAR-LIST. The
result can be passed as the second arg to `url-hexify-string'."
(let ((vec (make-vector 256 nil)))
(dolist (byte char-list)
(ignore-errors (aset vec byte t)))
vec))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-hexify-string (string &optional allowed-chars)
"URI-encode STRING and return the result.
If STRING is multibyte, it is first converted to a utf-8 byte
string. Each byte corresponding to an allowed character is left
as-is, while all other bytes are converted to a three-character
string: \"%\" followed by two upper-case hex digits.
The allowed characters are specified by ALLOWED-CHARS. If this
argument is nil, the list `url-unreserved-chars' determines the
allowed characters. Otherwise, ALLOWED-CHARS should be a vector
whose Nth element is non-nil if character N is allowed."
(unless allowed-chars
(setq allowed-chars (url--allowed-chars url-unreserved-chars)))
(mapconcat (lambda (byte)
(if (aref allowed-chars byte)
(char-to-string byte)
(aref url-encoding-table byte)))
(if (multibyte-string-p string)
(encode-coding-string string 'utf-8)
string)
""))
(defconst url-host-allowed-chars
;; Allow % to avoid re-encoding %-encoded sequences.
(url--allowed-chars (append '(?% ?! ?$ ?& ?' ?\( ?\) ?* ?+ ?, ?\; ?=)
url-unreserved-chars))
"Allowed-character byte mask for the host segment of a URI.
These characters are specified in RFC 3986, Appendix A.")
(defconst url-path-allowed-chars
(let ((vec (copy-sequence url-host-allowed-chars)))
(aset vec ?/ t)
(aset vec ?: t)
(aset vec ?@ t)
vec)
"Allowed-character byte mask for the path segment of a URI.
These characters are specified in RFC 3986, Appendix A.")
(defconst url-query-allowed-chars
(let ((vec (copy-sequence url-path-allowed-chars)))
(aset vec ?? t)
vec)
"Allowed-character byte mask for the query segment of a URI.
These characters are specified in RFC 3986, Appendix A.")
;;;###autoload
(defun url-encode-url (url)
"Return a properly URI-encoded version of URL.
This function also performs URI normalization, e.g. converting
the scheme to lowercase if it is uppercase. Apart from
normalization, if URL is already URI-encoded, this function
should return it unchanged."
(let* ((obj (url-generic-parse-url url))
(user (url-user obj))
(pass (url-password obj))
(path-and-query (url-path-and-query obj))
(path (car path-and-query))
(query (cdr path-and-query))
(frag (url-target obj)))
(if user
(setf (url-user obj) (url-hexify-string user)))
(if pass
(setf (url-password obj) (url-hexify-string pass)))
(if path
(setq path (url-hexify-string path url-path-allowed-chars)))
(if query
(setq query (url-hexify-string query url-query-allowed-chars)))
(setf (url-filename obj) (if query (concat path "?" query) path))
(if frag
(setf (url-target obj)
(url-hexify-string frag url-query-allowed-chars)))
(url-recreate-url obj)))
2004-04-04 01:21:46 +00:00
;;;###autoload
(defun url-file-extension (fname &optional x)
"Return the filename extension of FNAME.
If optional argument X is t, then return the basename
of the file with the extension stripped off."
2004-04-04 01:21:46 +00:00
(if (and fname
(setq fname (url-file-nondirectory fname))
2004-04-04 01:21:46 +00:00
(string-match "\\.[^./]+$" fname))
(if x (substring fname 0 (match-beginning 0))
(substring fname (match-beginning 0) nil))
;;
;; If fname has no extension, and x then return fname itself instead of
;; nothing. When caching it allows the correct .hdr file to be produced
;; for filenames without extension.
;;
(if x
fname
"")))
;;;###autoload
(defun url-truncate-url-for-viewing (url &optional width)
"Return a shortened version of URL that is WIDTH characters wide or less.
2004-04-04 01:21:46 +00:00
WIDTH defaults to the current frame width."
(let* ((fr-width (or width (frame-width)))
(str-width (length url))
(fname nil)
(modified 0)
(urlobj nil))
;; The first thing that can go are the search strings
(if (and (>= str-width fr-width)
(string-match "?" url))
(setq url (concat (substring url 0 (match-beginning 0)) "?...")
str-width (length url)))
2004-04-04 01:21:46 +00:00
(if (< str-width fr-width)
nil ; Hey, we are done!
(setq urlobj (url-generic-parse-url url)
fname (url-filename urlobj)
fr-width (- fr-width 4))
(while (and (>= str-width fr-width)
(string-match "/" fname))
(setq fname (substring fname (match-end 0) nil)
modified (1+ modified))
(setf (url-filename urlobj) fname)
2004-04-04 01:21:46 +00:00
(setq url (url-recreate-url urlobj)
str-width (length url)))
(if (> modified 1)
(setq fname (concat "/.../" fname))
(setq fname (concat "/" fname)))
(setf (url-filename urlobj) fname)
2004-04-04 01:21:46 +00:00
(setq url (url-recreate-url urlobj)))
url))
;;;###autoload
(defun url-view-url (&optional no-show)
"View the current document's URL.
Optional argument NO-SHOW means just return the URL, don't show it in
the minibuffer.
This uses `url-current-object', set locally to the buffer."
(interactive)
(if (not url-current-object)
nil
(if no-show
(url-recreate-url url-current-object)
(message "%s" (url-recreate-url url-current-object)))))
(defvar url-get-url-filename-chars "-%.?@a-zA-Z0-9()_/:~=&"
"Valid characters in a URL.")
2004-04-04 01:21:46 +00:00
(defun url-get-url-at-point (&optional pt)
"Get the URL closest to point, but don't change position.
Has a preference for looking backward when not directly on a symbol."
;; Not at all perfect - point must be right in the name.
(save-excursion
(if pt (goto-char pt))
(let (start url)
(save-excursion
;; first see if you're just past a filename
(if (not (eobp))
(if (looking-at "[] \t\n[{}()]") ; whitespace or some parens
(progn
(skip-chars-backward " \n\t\r({[]})")
(if (not (bobp))
(backward-char 1)))))
(if (and (char-after (point))
(string-match (concat "[" url-get-url-filename-chars "]")
2004-04-04 01:21:46 +00:00
(char-to-string (char-after (point)))))
(progn
(skip-chars-backward url-get-url-filename-chars)
(setq start (point))
(skip-chars-forward url-get-url-filename-chars))
(setq start (point)))
(setq url (buffer-substring-no-properties start (point))))
(if (and url (string-match "^(\\(.*\\))\\.?$" url))
2004-04-04 01:21:46 +00:00
(setq url (match-string 1 url)))
(if (and url (string-match "^URL:" url))
(setq url (substring url 4 nil)))
(if (and url (string-match "\\.$" url))
(setq url (substring url 0 -1)))
(if (and url (string-match "^www\\." url))
(setq url (concat "http://" url)))
(if (and url (not (string-match url-nonrelative-link url)))
(setq url nil))
url)))
(defun url-generate-unique-filename (&optional fmt)
"Generate a unique filename in `url-temporary-directory'."
Use declare forms, where possible, to mark obsolete functions. * lisp/allout.el (allout-passphrase-hint-string): Likewise. (allout-init): Use a declare form to mark obsolete. * lisp/calendar/calendar.el (calendar-version): * lisp/calendar/icalendar.el (icalendar-extract-ical-from-buffer) (icalendar-convert-diary-to-ical): * lisp/cus-edit.el (custom-mode): * lisp/ansi-color.el (ansi-color-unfontify-region): * lisp/international/latin1-disp.el (latin1-char-displayable-p): * lisp/progmodes/cwarn.el (turn-on-cwarn-mode): * lisp/progmodes/which-func.el (which-func-update-1): Use define-obsolete-function-alias. * lisp/bookmark.el (bookmark-jump-noselect): Use a declare form to mark this function obsolete. * lisp/calendar/cal-x.el (calendar-two-frame-setup) (calendar-only-one-frame-setup, calendar-one-frame-setup): * lisp/calendar/calendar.el (american-calendar, european-calendar) (calendar-for-loop): * lisp/comint.el (comint-dynamic-simple-complete) (comint-dynamic-complete-as-filename, comint-unquote-filename): * lisp/desktop.el (desktop-load-default): * lisp/dired-x.el (dired-omit-here-always) (dired-hack-local-variables, dired-default-directory): * lisp/emacs-lisp/derived.el (derived-mode-class): * lisp/emacs-lisp/timer.el (timer-set-time-with-usecs): * lisp/emacs-lock.el (toggle-emacs-lock): * lisp/epa.el (epa-display-verify-result): * lisp/epg.el (epg-sign-keys, epg-start-sign-keys) (epg-passphrase-callback-function): * lisp/eshell/esh-util.el (eshell-for): * lisp/eshell/eshell.el (eshell-remove-from-window-buffer-names) (eshell-add-to-window-buffer-names): * lisp/files.el (locate-file-completion): * lisp/imenu.el (imenu-example--create-c-index) (imenu-example--create-lisp-index) (imenu-example--lisp-extract-index-name) (imenu-example--name-and-position): * lisp/international/mule-cmds.el (princ-list): * lisp/international/mule-diag.el (decode-codepage-char): * lisp/international/mule-util.el (detect-coding-with-priority): * lisp/iswitchb.el (iswitchb-read-buffer): * lisp/mail/mailalias.el (mail-complete): * lisp/mail/sendmail.el (mail-sent-via): * lisp/mouse.el (mouse-popup-menubar-stuff, mouse-popup-menubar) (mouse-major-mode-menu): * lisp/password-cache.el (password-read-and-add): * lisp/pcomplete.el (pcomplete-parse-comint-arguments): * lisp/progmodes/sh-script.el (sh-maybe-here-document): * lisp/replace.el (query-replace-regexp-eval): * lisp/savehist.el (savehist-load): * lisp/simple.el (choose-completion-delete-max-match): * lisp/term.el (term-dynamic-simple-complete): * lisp/vc/ediff-init.el (ediff-check-version): * lisp/vc/ediff-wind.el (ediff-choose-window-setup-function-automatically): * lisp/vc/vc.el (vc-diff-switches-list): * lisp/view.el (view-return-to-alist-update): Likewise. * lisp/iswitchb.el (iswitchb-read-buffer): Move code of iswitchb-define-mode-map here, and delete that obsolete function. * lisp/subr.el (eval-next-after-load, makehash, insert-string) (assoc-ignore-representation, assoc-ignore-case): Use declare to mark obsolete. (mode-line-inverse-video): Variable deleted. * lisp/emacs-lisp/byte-run.el (make-obsolete): Doc fix; emphasize that this applies to functions. * lisp/erc/erc.el (erc-send-command): Use define-obsolete-function-alias. * lisp/international/mule-util.el (string-to-sequence): Remove. * lisp/net/newst-backend.el (newsticker-cache-filename): * lisp/net/newst-treeview.el (newsticker-groups-filename): Fix incorrect obsolescence declaration. * lisp/net/snmp-mode.el (snmp-font-lock-keywords-3): Don't use obsolete font-lock-reference-face. * lisp/url/url-parse.el (url-recreate-url-attributes): * lisp/url/url-util.el (url-generate-unique-filename): Use declare to mark obsolete. * src/xdisp.c (mode_line_inverse_video): Delete obsolete variable.
2012-09-25 12:13:02 +08:00
(declare (obsolete make-temp-file "23.1"))
;; This variable is obsolete, but so is this function.
(let ((tempdir (with-no-warnings url-temporary-directory)))
(if (not fmt)
(let ((base (format "url-tmp.%d" (user-real-uid)))
(fname "")
(x 0))
(setq fname (format "%s%d" base x))
(while (file-exists-p
(expand-file-name fname tempdir))
(setq x (1+ x)
fname (concat base (int-to-string x))))
(expand-file-name fname tempdir))
(let ((base (concat "url" (int-to-string (user-real-uid))))
2004-04-04 01:21:46 +00:00
(fname "")
(x 0))
(setq fname (format fmt (concat base (int-to-string x))))
2004-04-04 01:21:46 +00:00
(while (file-exists-p
(expand-file-name fname tempdir))
2004-04-04 01:21:46 +00:00
(setq x (1+ x)
fname (format fmt (concat base (int-to-string x)))))
(expand-file-name fname tempdir)))))
2004-04-04 01:21:46 +00:00
(defun url-extract-mime-headers ()
"Set `url-current-mime-headers' in current buffer."
(save-excursion
(goto-char (point-min))
(unless url-current-mime-headers
(set (make-local-variable 'url-current-mime-headers)
(mail-header-extract)))))
2007-12-11 05:48:40 +00:00
(defun url-make-private-file (file)
"Make FILE only readable and writable by the current user.
Creates FILE and its parent directories if they do not exist."
(let ((dir (file-name-directory file)))
(when dir
;; For historical reasons.
(make-directory dir t)))
;; Based on doc-view-make-safe-dir.
(condition-case nil
(with-file-modes #o0600
(with-temp-buffer
(write-region (point-min) (point-max) file nil 'silent nil 'excl)))
2007-12-11 05:48:40 +00:00
(file-already-exists
(if (file-symlink-p file)
(error "Danger: `%s' is a symbolic link" file))
(set-file-modes file #o0600))))
2004-04-04 01:21:46 +00:00
(provide 'url-util)
2004-04-04 04:44:10 +00:00
2004-04-16 22:05:32 +00:00
;;; url-util.el ends here