git.fiddlerwoaroof.com
Browse code

(init)

Edward authored on 14/03/2021 23:31:24
Showing 6 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+;;; Directory Local Variables
2
+;;; For more information see (info "(emacs) Directory Variables")
3
+
4
+((nil . ((fwoar::*package-prefix* . "aion"))))
0 5
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+*~
2
+*.*f?sl*
0 3
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; Package: ASDF-USER -*-
2
+(in-package :asdf-user)
3
+
4
+(defsystem :aion
5
+  :description ""
6
+  :author "Ed L <edward@elangley.org>"
7
+  :license "MIT"
8
+  :depends-on (:alexandria
9
+               :uiop
10
+               :serapeum
11
+               :fwoar-lisputils)
12
+  :serial t
13
+  :components ((:file "packages")
14
+               (:file "parser")
15
+               (:file "build-tree")))
0 16
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+(in-package :aion.build-tree)
2
+
3
+(fw.lu:defclass+ build-tree ()
4
+  ((%history :accessor history :initform ())))
5
+
6
+(defmethod handle-begin ((client build-tree) block)
7
+  (push (list block) (history client)))
8
+(defmethod handle-end ((client build-tree) block)
9
+  (progn (when (cdr (history client))
10
+           (let ((last (pop (history client))))
11
+             (push (nreverse last)
12
+                   (car (history client)))))))
13
+(defmethod handle-property ((client build-tree) tag params content)
14
+  (push (list tag params content)
15
+        (car (history client))))
16
+
17
+(defun ics->tree (data)
18
+  (let ((client (build-tree)))
19
+    (process-ics client data)
20
+    (nreverse (car (history client)))))
0 21
new file mode 100644
... ...
@@ -0,0 +1,22 @@
1
+(defpackage :aion.packages
2
+  (:use :cl )
3
+  (:export ))
4
+(in-package :aion.packages)
5
+
6
+(defpackage :aion.parser
7
+  (:use :cl)
8
+  (:export #:handle-begin
9
+           #:handle-end
10
+           #:handle-property))
11
+
12
+(defpackage :aion.build-tree
13
+  (:use :cl)
14
+  (:import-from #:aion.parser #:handle-begin #:handle-end
15
+                #:handle-property #:process-ics)
16
+  (:export #:ics->tree))
17
+
18
+(uiop:define-package :aion
19
+    (:use)
20
+  (:import-from :aion.parser #:handle-begin #:handle-end #:handle-property)
21
+  (:import-from :aion.build-tree #:ics->tree)
22
+  (:reexport :aion.build-tree :aion.parser))
0 23
new file mode 100644
... ...
@@ -0,0 +1,85 @@
1
+(in-package :aion.parser)
2
+
3
+(defgeneric handle-begin (client block)
4
+  (:documentation "handle the beginning of a new block in the iCalendar data"))
5
+(defgeneric handle-end (client block)
6
+  (:documentation "handle the ending of a block in the iCalendar data"))
7
+(defgeneric handle-property (client tag params content)
8
+  (:documentation "handle a property for the current iCalendar block"))
9
+
10
+(defun get-line (stream)
11
+  (loop for line = (read-line stream nil)
12
+        while line
13
+        collect line into results
14
+        while (eql #\space (peek-char nil stream nil))
15
+        finally (return (when results
16
+                          (string-right-trim
17
+                           '(#\newline #\return)
18
+                           (serapeum:string-replace-all
19
+                            #1=#.(coerce (list #\return #\space)
20
+                                         'string)
21
+                            (serapeum:string-join results "")
22
+                            ""))))))
23
+
24
+(defmacro with-temporary-keywords ((intern) &body body)
25
+  (alexandria:with-gensyms (kw-list)
26
+    `(let ((,kw-list '()))
27
+       (unwind-protect
28
+            (flet ((,intern (inp)
29
+                     (multiple-value-bind (kw existing?)
30
+                         (alexandria:make-keyword (string-upcase inp))
31
+                       (prog1 kw
32
+                         (unless existing?
33
+                           (push kw ,kw-list))))))
34
+              ,@body)
35
+         (mapc 'unintern ,kw-list)))))
36
+
37
+(defgeneric as-stream (it)
38
+  (:method ((it string))
39
+    (make-string-input-stream it))
40
+  (:method ((it pathname))
41
+    (open it))
42
+  (:method ((it stream))
43
+    it))
44
+
45
+(defun process-ics (client file)
46
+  (let ((states '()))
47
+    (with-temporary-keywords (normalize)
48
+      (labels ((%handle-block-delimiter (tag type)
49
+                 (push type states)
50
+                 (ecase tag
51
+                   ((:begin) (handle-begin client type))
52
+                   ((:end) (handle-end client type))))
53
+               (parse-params (inp)
54
+                 (destructuring-bind (head params) (fwoar.string-utils:partition #\; inp)
55
+                   (values head
56
+                           (when params
57
+                             (map 'list
58
+                                  (data-lens:• (data-lens:transform-head #'normalize)
59
+                                               (serapeum:op
60
+                                                 (fwoar.string-utils:partition #\= _)))
61
+                                  (fwoar.string-utils:split #\; params))))))
62
+               (parse-property (it)
63
+                 (destructuring-bind (s e) (fwoar.string-utils:partition #\: it)
64
+                   (multiple-value-bind (head params) (parse-params s)
65
+                     (list (normalize head)
66
+                           params
67
+                           e))))
68
+               (%handle-property (it)
69
+                 (apply 'handle-property client it))
70
+               (handle-line (tag tagged line)
71
+                 (case tag
72
+                   ((:begin)
73
+                    (%handle-block-delimiter tag (normalize tagged)))
74
+                   ((:end)
75
+                    (%handle-block-delimiter tag (normalize tagged)))
76
+                   (t (%handle-property (parse-property line))))))
77
+        (with-open-stream (s (as-stream file))
78
+          (loop for line = (get-line s)
79
+                for (tag tagged) = (if line
80
+                                       (fwoar.string-utils:partition #\: line)
81
+                                       '(nil nil))
82
+                while line
83
+                do (handle-line (fw.lu:may (normalize tag))
84
+                                tagged
85
+                                line)))))))