1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
;;; url-parse.el --- Uniform Resource Locator parser
;; Copyright (C) 1996, 1997, 1998, 1999, 2004,
;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Keywords: comm, data, processes
;; This file is part of GNU Emacs.
;;
;; GNU Emacs 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.
;; 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.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'url-vars)
(eval-when-compile (require 'cl))
(autoload 'url-scheme-get-property "url-methods")
(defstruct (url
(:constructor nil)
(:constructor url-parse-make-urlobj
(&optional type user password host portspec filename
target attributes fullness))
(:copier nil))
type user password host portspec filename target attributes fullness)
(defsubst url-port (urlobj)
(or (url-portspec urlobj)
(if (url-fullness urlobj)
(url-scheme-get-property (url-type urlobj) 'default-port))))
(defsetf url-port (urlobj) (port) `(setf (url-portspec ,urlobj) ,port))
;;;###autoload
(defun url-recreate-url (urlobj)
"Recreate a URL string from the parsed URLOBJ."
(concat (url-type urlobj) ":" (if (url-host urlobj) "//" "")
(if (url-user urlobj)
(concat (url-user urlobj)
(if (url-password urlobj)
(concat ":" (url-password urlobj)))
"@"))
(url-host urlobj)
(if (and (url-port urlobj)
(not (equal (url-port urlobj)
(url-scheme-get-property (url-type urlobj) 'default-port))))
(format ":%d" (url-port urlobj)))
(or (url-filename urlobj) "/")
(url-recreate-url-attributes urlobj)
(if (url-target urlobj)
(concat "#" (url-target urlobj)))))
(defun url-recreate-url-attributes (urlobj)
"Recreate the attributes of an URL string from the parsed URLOBJ."
(when (url-attributes urlobj)
(concat ";"
(mapconcat (lambda (x)
(if (cdr x)
(concat (car x) "=" (cdr x))
(car x)))
(url-attributes urlobj) ";"))))
;;;###autoload
(defun url-generic-parse-url (url)
"Return an URL-struct of the parts of URL.
The CL-style struct contains the following fields:
TYPE USER PASSWORD HOST PORTSPEC FILENAME TARGET ATTRIBUTES FULLNESS."
;; See RFC 3986.
(cond
((null url)
(url-parse-make-urlobj))
((or (not (string-match url-nonrelative-link url))
(= ?/ (string-to-char url)))
;; This isn't correct, as a relative URL can be a fragment link
;; (e.g. "#foo") and many other things (see section 4.2).
;; However, let's not fix something that isn't broken, especially
;; when close to a release.
(url-parse-make-urlobj nil nil nil nil nil url))
(t
(with-temp-buffer
;; Don't let those temp-buffer modifications accidentally
;; deactivate the mark of the current-buffer.
(let ((deactivate-mark nil))
(set-syntax-table url-parse-syntax-table)
(let ((save-pos nil)
(prot nil)
(user nil)
(pass nil)
(host nil)
(port nil)
(file nil)
(refs nil)
(attr nil)
(full nil)
(inhibit-read-only t))
(erase-buffer)
(insert url)
(goto-char (point-min))
(setq save-pos (point))
;; 3.1. Scheme
(unless (looking-at "//")
(skip-chars-forward "a-zA-Z+.\\-")
(downcase-region save-pos (point))
(setq prot (buffer-substring save-pos (point)))
(skip-chars-forward ":")
(setq save-pos (point)))
;; 3.2. Authority
(when (looking-at "//")
(setq full t)
(forward-char 2)
(setq save-pos (point))
(skip-chars-forward "^/")
(setq host (buffer-substring save-pos (point)))
(if (string-match "^\\([^@]+\\)@" host)
(setq user (match-string 1 host)
host (substring host (match-end 0) nil)))
(if (and user (string-match "\\([^:]+\\):\\(.*\\)" user))
(setq pass (match-string 2 user)
user (match-string 1 user)))
;; This gives wrong results for IPv6 literal addresses.
(if (string-match ":\\([0-9+]+\\)" host)
(setq port (string-to-number (match-string 1 host))
host (substring host 0 (match-beginning 0))))
(if (string-match ":$" host)
(setq host (substring host 0 (match-beginning 0))))
(setq host (downcase host)
save-pos (point)))
(if (not port)
(setq port (url-scheme-get-property prot 'default-port)))
;; 3.3. Path
;; Gross hack to preserve ';' in data URLs
(setq save-pos (point))
;; 3.4. Query
(if (string= "data" prot)
(goto-char (point-max))
;; Now check for references
(skip-chars-forward "^#")
(if (eobp)
nil
(delete-region
(point)
(progn
(skip-chars-forward "#")
(setq refs (buffer-substring (point) (point-max)))
(point-max))))
(goto-char save-pos)
(skip-chars-forward "^;")
(unless (eobp)
(setq attr (url-parse-args (buffer-substring (point) (point-max))
t)
attr (nreverse attr))))
(setq file (buffer-substring save-pos (point)))
(if (and host (string-match "%[0-9][0-9]" host))
(setq host (url-unhex-string host)))
(url-parse-make-urlobj
prot user pass host port file refs attr full)))))))
(provide 'url-parse)
;; arch-tag: f338325f-71ab-4bee-93cc-78fb9a03d403
;;; url-parse.el ends here
|