[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/vcard f5df1907bb 02/13: *** empty log message ***
From: |
Stefan Monnier |
Subject: |
[elpa] externals/vcard f5df1907bb 02/13: *** empty log message *** |
Date: |
Tue, 12 Jul 2022 00:17:01 -0400 (EDT) |
branch: externals/vcard
commit f5df1907bbed20c5e46ec89348e033570161aeba
Author: Noah Friedman <friedman@splode.com>
Commit: Noah Friedman <friedman@splode.com>
*** empty log message ***
---
vcard.el | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 177 insertions(+), 12 deletions(-)
diff --git a/vcard.el b/vcard.el
index 876866c14c..0d02e0bcbb 100644
--- a/vcard.el
+++ b/vcard.el
@@ -1,13 +1,13 @@
-;;; vcard.el --- vcard parsing and formatting routines
+;;; vcard.el --- vcard parsing and display routines
;; Copyright (C) 1997 Noah S. Friedman
-;; Author: Noah Friedman <friedman@prep.ai.mit.edu>
-;; Maintainer: friedman@prep.ai.mit.edu
+;; Author: Noah Friedman <friedman@splode.com>
+;; Maintainer: friedman@splode.com
;; Keywords: extensions
;; Created: 1997-09-27
-;; $Id: vcard.el,v 1.1 1997/10/01 11:55:52 friedman Exp $
+;; $Id: vcard.el,v 1.2 1997/10/14 19:38:18 friedman Exp $
;; 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
@@ -25,18 +25,52 @@
;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
;;; Commentary:
+
+;; The display routines here are just an example. The primitives in the
+;; first section can be used to construct other vcard formatters.
+
;;; Code:
-(defun vcard-parse-string (raw)
+(defvar vcard-standard-filters '(vcard-filter-html)
+ "*Standard list of filters to apply to parsed vcard data.
+These filters are applied sequentially to vcard data records when
+the function `vcard-standard-filter' is supplied as the second argument to
+`vcard-parse-string'.")
+
+(defun vcard-parse-string (raw &optional filter)
+ "Parse RAW vcard data as a string, and return an alist representing data.
+
+If the optional function FILTER is specified, apply that filter to the
+data record of each key before splitting fields. Filters should accept
+two arguments: the key and the data. They are expected to operate on
+\(and return\) a modified data value.
+
+Vcard data is normally in the form
+
+ begin: vcard
+ key1: field
+ key2;subkey1: field
+ key2;subkey2: field1;field2;field3
+ end: vcard
+
+If supplied to this function an alist of the form
+
+ ((\"key1\" \"field\")
+ (\"key2\"
+ (\"subkey2\" \"field1\" \"field2\" \"field3\")
+ (\"subkey1\" \"field\")))
+
+would be returned."
(save-match-data
(let ((raw-pos 0)
(vcard-data nil)
key data)
- (string-match "^begin:[ \t]*vcard[ \t]*[\r\n]+" raw raw-pos)
+ (string-match "^[ \t]*begin:[ \t]*vcard[ \t]*[\r\n]+" raw raw-pos)
(setq raw-pos (match-end 0))
(while (and (< raw-pos (length raw))
- (string-match "^\\([^:]+\\):[ \t]+\\(.*\\)[ \t]*[\n\r]+"
- raw raw-pos))
+ (string-match
+ "^[ \t]*\\([^:]+\\):[ \t]+\\(.*\\)[ \t]*[\n\r]+"
+ raw raw-pos))
(setq key (vcard-matching-substring 1 raw))
(setq data (vcard-matching-substring 2 raw))
(setq raw-pos (match-end 0))
@@ -44,6 +78,8 @@
((string= key "end")
(setq raw-pos (length raw)))
(t
+ (and filter
+ (setq data (funcall filter key data)))
(setq vcard-data
(vcard-set-alist-slot vcard-data
(vcard-split-string key ";")
@@ -51,22 +87,64 @@
(nreverse vcard-data))))
(defun vcard-ref (key vcard-data)
+ "Return the vcard data associated with KEY in VCARD-DATA.
+Key may be a list of nested keys or a single string of colon-separated
+keys."
(cond ((listp key)
- (vcard-nested-alist-assoc key vcard-data))
+ (vcard-alist-assoc key vcard-data))
((and (stringp key)
(save-match-data
(string-match ";" key)))
- (vcard-nested-alist-assoc (vcard-split-string key ";") vcard-data))
+ (vcard-alist-assoc (vcard-split-string key ";") vcard-data))
((stringp key)
(cdr (assoc key vcard-data)))))
-(defun vcard-nested-alist-assoc (keys alist)
+;;; Vcard data filters.
+
+;; These receive both the key and data, but are expected to operate on (and
+;; return) just the data.
+;;
+;; There is probably no overwhelming need for this, except that some lusers
+;; put HTML in their vcards under the misguided notion that it's a standard
+;; feature of vcards just because Netscape supports this feature. (Or
+;; perhaps those lusers just don't care that their vcards look like shit in
+;; every other MUA).
+;;
+;; On the other hand, perhaps someone will devise some other use for these
+;; filters, such as noticing common phone number formats and re-formatting
+;; them to fit personal preferences.
+
+(defun vcard-filter-apply-filter-list (filter-list key data)
+ (while filter-list
+ (setq data (funcall (car filter-list) key data))
+ (setq filter-list (cdr filter-list)))
+ data)
+
+(defun vcard-standard-filter (key data)
+ (vcard-filter-apply-filter-list vcard-standard-filters key data))
+
+(defun vcard-filter-html (key data)
+ (save-match-data
+ (while (string-match "<[^<>\n]+>" data)
+ (setq data (concat (substring data 0 (match-beginning 0))
+ (substring data (match-end 0)))))
+ data))
+
+
+;;; Utility routines.
+
+;; This does most of the dirty work of key lookup for vcard-ref.
+(defun vcard-alist-assoc (keys alist)
(while (and keys alist)
(setq alist (cdr (assoc (car keys) alist)))
(setq keys (cdr keys)))
alist)
+;; In ALIST, set KEY-LIST's value to VALUE, and return new value of ALIST.
+;; KEY-LIST should be a list of nested keys, if ALIST is an alist of alists.
+;; If any key is not present in an alist, the key and value pair will be
+;; inserted into the parent alist.
(defun vcard-set-alist-slot (alist key-list value)
(let* ((key (car key-list))
(elt (assoc key alist)))
@@ -92,7 +170,6 @@
(setcar alist new))))))
alist))
-
;; Return substring matched by last search.
;; N specifies which match data pair to use
;; Value is nil if there is no Nth match.
@@ -115,6 +192,94 @@
(setq pos (match-end 0)))
(nreverse (cons (substring string pos) list)))))
+(defun vcard-flatten (l)
+ (if (consp l)
+ (apply 'nconc (mapcar 'vcard-flatten l))
+ (list l)))
+
+
+;;; Sample formatting routines.
+
+(defun vcard-display-string (vcard-data)
+ "Format VCARD-DATA into a string suitable for presentation.
+VCARD-DATA should be a parsed vcard alist. The result is a string
+with formatted vcard information which can be inserted into a mime
+presentation buffer."
+ (let* ((name (vcard-display-get-name vcard-data))
+ (title (vcard-display-ref "title" vcard-data))
+ (org (vcard-display-ref "org" vcard-data))
+ (addr (vcard-display-get-address vcard-data))
+ (tel (vcard-display-get-telephone vcard-data))
+ (lines (delete nil (vcard-flatten (list name title org addr))))
+ (col-template (format "%%-%ds%%s"
+ (vcard-display-offset lines tel)))
+ (l lines))
+ (while tel
+ (setcar l (format col-template (car l) (car tel)))
+ (setq l (cdr l))
+ (setq tel (cdr tel)))
+ (mapconcat 'identity lines "\n")))
+
+(defun vcard-display-get-name (vcard-data)
+ (let ((name (vcard-display-ref "fn" vcard-data))
+ (email (or (vcard-display-ref '("email" "internet") vcard-data)
+ (vcard-display-ref "email" vcard-data))))
+ (if email
+ (format "%s <%s>" name email)
+ name)))
+
+(defun vcard-display-get-address (vcard-data)
+ (let* ((addr (or (vcard-display-ref '("adr" "dom") vcard-data)
+ (vcard-display-ref "adr" vcard-data)))
+ (street (delete "" (list (nth 0 addr) (nth 1 addr) (nth 2 addr))))
+ (city-list (delete "" (nthcdr 3 addr)))
+ (city (cond ((null (car city-list)) nil)
+ ((cdr city-list)
+ (format "%s, %s"
+ (car city-list)
+ (mapconcat 'identity (cdr city-list) " ")))
+ (t (car city-list)))))
+ (delete nil
+ (if city
+ (append street (list city))
+ street))))
+
+(defun vcard-display-get-telephone (vcard-data)
+ (delete nil
+ (mapcar (function (lambda (x)
+ (let ((result (vcard-display-ref (car x)
+ vcard-data)))
+ (and result
+ (concat (cdr x) result)))))
+ '((("tel" "work") . "Work: ")
+ (("tel" "home") . "Home: ")
+ (("tel" "fax") . "Fax: ")))))
+
+(defun vcard-display-ref (key vcard-data)
+ (setq key (vcard-ref key vcard-data))
+ (or (cdr key)
+ (setq key (car key)))
+ (and (stringp key)
+ (string= key "")
+ (setq key nil))
+ key)
+
+(defun vcard-display-offset (row1 row2 &optional maxwidth)
+ (or maxwidth (setq maxwidth (frame-width)))
+ (let ((max1 (vcard-display-max-length row1))
+ (max2 (vcard-display-max-length row2)))
+ (+ max1 (min 5 (max 1 (- maxwidth (+ max1 max2)))))))
+
+(defun vcard-display-max-length (strings)
+ (let ((maxlen 0)
+ (len 0))
+ (while strings
+ (setq len (length (car strings)))
+ (setq strings (cdr strings))
+ (and (> len maxlen)
+ (setq maxlen len)))
+ maxlen))
+
(provide 'vcard)
;;; vcard.el ends here.
- [elpa] externals/vcard updated (a85359ee83 -> 0200b96343), Stefan Monnier, 2022/07/12
- [elpa] externals/vcard ec3986a43a 03/13: *** empty log message ***, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard f5df1907bb 02/13: *** empty log message ***,
Stefan Monnier <=
- [elpa] externals/vcard ef82e79ac7 01/13: *** empty log message ***, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard d0ec40a5c6 08/13: Complete rewrite., Stefan Monnier, 2022/07/12
- [elpa] externals/vcard a50b9e4395 04/13: (vcard-format-lines): Handle case where 2nd column has more lines than, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 4bf38d79fc 05/13: (vcard-parse-string): Handle "key:field" type entries, i.e. no whitespace, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 0200b96343 13/13: Adjust package to the new `vcard.el` file, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 49301aa94d 12/13: Merge branch 'vcard-friedman' into externals/vcard, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 6283103cc6 11/13: (vcard-hexstring-to-ascii): New macro., Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 1399f2b8cb 06/13: (vcard-format-box): Return empty string if no data to present; don't, Stefan Monnier, 2022/07/12
- [elpa] externals/vcard 5f5af1f780 07/13: (vcard-parse-string): Bind case-fold-search to t., Stefan Monnier, 2022/07/12
- [elpa] externals/vcard a3e60e2883 09/13: (vcard-parse-region-value): Do not use `new-marker';, Stefan Monnier, 2022/07/12