mhc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/COPYRIGHT +28 -0
  6. data/Gemfile +8 -0
  7. data/README.org +209 -0
  8. data/Rakefile +13 -0
  9. data/bin/mhc +312 -0
  10. data/emacs/Cask +25 -0
  11. data/emacs/Makefile +58 -0
  12. data/emacs/mhc-calendar.el +1723 -0
  13. data/emacs/mhc-calfw.el +135 -0
  14. data/emacs/mhc-compat.el +90 -0
  15. data/emacs/mhc-date.el +642 -0
  16. data/emacs/mhc-day.el +149 -0
  17. data/emacs/mhc-db.el +158 -0
  18. data/emacs/mhc-draft.el +211 -0
  19. data/emacs/mhc-e21.el +167 -0
  20. data/emacs/mhc-face.el +236 -0
  21. data/emacs/mhc-file.el +224 -0
  22. data/emacs/mhc-guess.el +648 -0
  23. data/emacs/mhc-header.el +176 -0
  24. data/emacs/mhc-logic.el +563 -0
  25. data/emacs/mhc-message.el +130 -0
  26. data/emacs/mhc-minibuf.el +466 -0
  27. data/emacs/mhc-misc.el +248 -0
  28. data/emacs/mhc-mua.el +260 -0
  29. data/emacs/mhc-parse.el +286 -0
  30. data/emacs/mhc-process.el +35 -0
  31. data/emacs/mhc-ps.el +1174 -0
  32. data/emacs/mhc-record.el +201 -0
  33. data/emacs/mhc-schedule.el +202 -0
  34. data/emacs/mhc-summary.el +763 -0
  35. data/emacs/mhc-sync.el +158 -0
  36. data/emacs/mhc-vars.el +149 -0
  37. data/emacs/mhc.el +1114 -0
  38. data/icons/Anniversary.xbm +6 -0
  39. data/icons/Anniversary.xpm +27 -0
  40. data/icons/Birthday.xbm +6 -0
  41. data/icons/Birthday.xpm +25 -0
  42. data/icons/Business.xbm +6 -0
  43. data/icons/Business.xpm +24 -0
  44. data/icons/CheckBox.xbm +6 -0
  45. data/icons/CheckBox.xpm +24 -0
  46. data/icons/CheckedBox.xbm +6 -0
  47. data/icons/CheckedBox.xpm +25 -0
  48. data/icons/Conflict.xbm +6 -0
  49. data/icons/Conflict.xpm +22 -0
  50. data/icons/Date.xbm +6 -0
  51. data/icons/Date.xpm +29 -0
  52. data/icons/Holiday.xbm +6 -0
  53. data/icons/Holiday.xpm +25 -0
  54. data/icons/Link.xbm +6 -0
  55. data/icons/Link.xpm +25 -0
  56. data/icons/Other.xbm +6 -0
  57. data/icons/Other.xpm +28 -0
  58. data/icons/Party.xbm +6 -0
  59. data/icons/Party.xpm +23 -0
  60. data/icons/Private.xbm +6 -0
  61. data/icons/Private.xpm +26 -0
  62. data/icons/Recurrence.xbm +6 -0
  63. data/icons/Recurrence.xpm +98 -0
  64. data/icons/Vacation.xbm +6 -0
  65. data/icons/Vacation.xpm +26 -0
  66. data/lib/mhc.rb +45 -0
  67. data/lib/mhc/builder.rb +64 -0
  68. data/lib/mhc/caldav.rb +304 -0
  69. data/lib/mhc/calendar.rb +106 -0
  70. data/lib/mhc/command.rb +13 -0
  71. data/lib/mhc/command/cache.rb +14 -0
  72. data/lib/mhc/command/completions.rb +108 -0
  73. data/lib/mhc/command/init.rb +133 -0
  74. data/lib/mhc/command/scan.rb +33 -0
  75. data/lib/mhc/command/sync.rb +22 -0
  76. data/lib/mhc/config.rb +229 -0
  77. data/lib/mhc/converter.rb +330 -0
  78. data/lib/mhc/datastore.rb +164 -0
  79. data/lib/mhc/date_enumerator.rb +274 -0
  80. data/lib/mhc/date_frame.rb +124 -0
  81. data/lib/mhc/date_helper.rb +49 -0
  82. data/lib/mhc/etag.rb +68 -0
  83. data/lib/mhc/event.rb +396 -0
  84. data/lib/mhc/formatter.rb +312 -0
  85. data/lib/mhc/logger.rb +94 -0
  86. data/lib/mhc/modifier.rb +149 -0
  87. data/lib/mhc/occurrence.rb +94 -0
  88. data/lib/mhc/occurrence_enumerator.rb +113 -0
  89. data/lib/mhc/property_value.rb +33 -0
  90. data/lib/mhc/property_value/date.rb +190 -0
  91. data/lib/mhc/property_value/integer.rb +15 -0
  92. data/lib/mhc/property_value/list.rb +41 -0
  93. data/lib/mhc/property_value/period.rb +49 -0
  94. data/lib/mhc/property_value/range.rb +100 -0
  95. data/lib/mhc/property_value/recurrence_condition.rb +272 -0
  96. data/lib/mhc/property_value/text.rb +11 -0
  97. data/lib/mhc/property_value/time.rb +45 -0
  98. data/lib/mhc/query.rb +210 -0
  99. data/lib/mhc/sync.rb +46 -0
  100. data/lib/mhc/sync/driver.rb +108 -0
  101. data/lib/mhc/sync/status.rb +70 -0
  102. data/lib/mhc/sync/status_manager.rb +142 -0
  103. data/lib/mhc/sync/strategy.rb +233 -0
  104. data/lib/mhc/sync/syncinfo.rb +98 -0
  105. data/lib/mhc/templates/config.yml.erb +142 -0
  106. data/lib/mhc/version.rb +4 -0
  107. data/lib/mhc/webdav.rb +319 -0
  108. data/mhc.gemspec +24 -0
  109. data/samples/DOT.mhc-config.yml +116 -0
  110. data/samples/japanese-holidays.mhcc +153 -0
  111. data/samples/mhc-completions.zsh +11 -0
  112. data/spec/mhc_spec.rb +682 -0
  113. data/spec/spec_helper.rb +9 -0
  114. data/xpm/close.xpm +18 -0
  115. data/xpm/delete.xpm +19 -0
  116. data/xpm/exit.xpm +18 -0
  117. data/xpm/month.xpm +18 -0
  118. data/xpm/next.xpm +18 -0
  119. data/xpm/next2.xpm +18 -0
  120. data/xpm/next_year.xpm +18 -0
  121. data/xpm/open.xpm +19 -0
  122. data/xpm/prev.xpm +18 -0
  123. data/xpm/prev2.xpm +18 -0
  124. data/xpm/prev_year.xpm +18 -0
  125. data/xpm/save.xpm +19 -0
  126. data/xpm/today.xpm +18 -0
  127. metadata +214 -0
@@ -0,0 +1,135 @@
1
+ ;;; calfw-mhc.el --- calfw calendar view for mhc
2
+
3
+ ;; Author: Yoshinari Nomura <nom@quickhack.net>
4
+
5
+ ;;; Commentary:
6
+
7
+ ;; setting example:
8
+ ;;
9
+ ;; (require 'calfw)
10
+ ;; (require 'calfw-mhc)
11
+ ;; (require 'calfw-org)
12
+ ;;
13
+ ;; (defun open-calendar ()
14
+ ;; (interactive)
15
+ ;; (cfw:open-calendar-buffer
16
+ ;; :view 'month
17
+ ;; :contents-sources
18
+ ;; (list
19
+ ;; (cfw:org-create-source "Seagreen4")
20
+ ;; (cfw:mhc-create-source "all" "black" "!(Holiday || Birthday)")
21
+ ;; (cfw:mhc-create-source "birthday" "yellow" "Birthday")
22
+ ;; (cfw:mhc-create-source "holiday" "red" "Holiday"))))
23
+
24
+ ;;; Code:
25
+
26
+ (require 'mhc)
27
+ (require 'calfw)
28
+
29
+ (defvar cfw:mhc-text-keymap
30
+ (let ((map (make-sparse-keymap)))
31
+ (define-key map [mouse-1] 'cfw:mhc-open-article)
32
+ (define-key map (kbd "<return>") 'cfw:mhc-open-article)
33
+ map)
34
+ "key map on the calendar item text.")
35
+
36
+ (defvar cfw:mhc-schedule-map
37
+ (cfw:define-keymap
38
+ '(
39
+ ("q" . cfw:mhc-close-article)
40
+ ("SPC" . cfw:mhc-open-article)
41
+ ))
42
+ "Key map for the mhc calendar mode.")
43
+
44
+ (defun cfw:mhc-schedule-cache-clear ())
45
+
46
+ (defun cfw:to-mhc-date (date)
47
+ (mhc-date-new (nth 2 date) (nth 0 date) (nth 1 date)))
48
+
49
+ (defun cfw:mhc-to-calfw-date (mhc-date)
50
+ (mhc-day-let mhc-date
51
+ (list month day-of-month year)))
52
+
53
+ (defun cfw:mhc-make-one-day-entry (day-info &optional category-predicate)
54
+ (cons
55
+ (cfw:mhc-to-calfw-date
56
+ (mhc-day-date day-info))
57
+ (delq nil
58
+ (mapcar
59
+ (lambda (sch)
60
+ (if (funcall category-predicate sch)
61
+ (cfw:mhc-make-summary-string sch) nil))
62
+ (mhc-day-schedules day-info)))))
63
+
64
+ (defun blank-p (s)
65
+ (not (and s (not (string= s "")))))
66
+
67
+ ;;
68
+ ;; Although mhc has its own formatting functions for this purpose,
69
+ ;; they seems to require some modification to get along with calfw.
70
+ ;; I'm in the mood for fixing the functions in mhc for the
71
+ ;; first time almost in a decade :-)
72
+ ;;
73
+ (defun cfw:mhc-make-summary-string (schedule)
74
+ (let ((line
75
+ (format "%s %s %s"
76
+ (mhc-schedule-time-as-string schedule)
77
+ (mhc-schedule-subject-as-string schedule)
78
+ (if (blank-p (mhc-schedule-location schedule))
79
+ ""
80
+ (format "[%s]" (mhc-schedule-location schedule))))))
81
+ (propertize
82
+ line
83
+ 'keymap cfw:mhc-text-keymap
84
+ 'mhc-schedule schedule)))
85
+
86
+ (defun cfw:mhc-schedule-period-to-calendar (begin end &optional category)
87
+ (let ((category-predicate (mhc-expr-compile category)))
88
+ (mapcar
89
+ (lambda (day-info)
90
+ (cfw:mhc-make-one-day-entry day-info category-predicate))
91
+ (mhc-db-scan
92
+ (cfw:to-mhc-date begin)
93
+ (cfw:to-mhc-date end)
94
+ 'nosort))))
95
+
96
+ (defun cfw:mhc-create-source (name &optional color category)
97
+ (lexical-let ((category category))
98
+ (make-cfw:source
99
+ :name (concat "mhc:" name)
100
+ :color (or color "SteelBlue")
101
+ :update 'cfw:mhc-schedule-cache-clear
102
+ :data (lambda (begin end) (cfw:mhc-schedule-period-to-calendar begin end category)))))
103
+
104
+ (defun cfw:mhc-close-article ()
105
+ (interactive)
106
+ (mhc-window-pop)
107
+ (kill-buffer))
108
+
109
+ (defun cfw:mhc-open-article ()
110
+ (interactive)
111
+ (mhc-window-push)
112
+ (let ((schedule (get-text-property (point) 'mhc-schedule)))
113
+ (if schedule
114
+ (cfw:details-popup
115
+ (with-temp-buffer
116
+ (insert-file-contents
117
+ (mhc-record-name (mhc-schedule-record schedule)))
118
+ (mhc-calendar/view-file-decode-header)
119
+ (buffer-string)
120
+ ))
121
+ (message "mhc schedule not found"))))
122
+
123
+ (defun cfw:open-mhc-calendar ()
124
+ (interactive)
125
+ (cfw:open-calendar-buffer
126
+ :view 'month
127
+ :contents-sources
128
+ (list
129
+ (cfw:mhc-create-source "all" "black" "!(Holiday | Birthday)")
130
+ (cfw:mhc-create-source "birthday" "brown" "Birthday")
131
+ (cfw:mhc-create-source "holiday" "red" "Holiday"))))
132
+
133
+ (provide 'mhc-calfw)
134
+
135
+ ;;; mhc-calfw.el ends here
@@ -0,0 +1,90 @@
1
+ ;;; -*- mode: Emacs-Lisp; coding: utf-8 -*-
2
+
3
+ ;; Author: Yoshinari Nomura <nom@quickhack.net>,
4
+ ;; TSUCHIYA Masatoshi <tsuchiya@namazu.org>
5
+ ;; Created: 2000/05/01
6
+ ;; Revised: $Date$
7
+
8
+
9
+ ;;; Commentary:
10
+
11
+ ;; This file is a part of MHC, and includes definitions to absorb
12
+ ;; incompatibilities between emacsen.
13
+
14
+
15
+ ;;; Code:
16
+
17
+ (if (fboundp 'insert-file-contents-as-coding-system)
18
+ (defalias 'mhc-insert-file-contents-as-coding-system
19
+ 'insert-file-contents-as-coding-system)
20
+ (defun mhc-insert-file-contents-as-coding-system
21
+ (coding-system filename &optional visit beg end replace)
22
+ "Like `insert-file-contents', q.v., but CODING-SYSTEM the first arg will
23
+ be applied to `coding-system-for-read'."
24
+ (let ((coding-system-for-read coding-system)
25
+ (file-coding-system-for-read coding-system))
26
+ (insert-file-contents filename visit beg end replace))))
27
+
28
+
29
+ (if (fboundp 'write-region-as-coding-system)
30
+ (defalias 'mhc-write-region-as-coding-system
31
+ 'write-region-as-coding-system)
32
+ (defun mhc-write-region-as-coding-system
33
+ (coding-system start end filename &optional append visit lockname)
34
+ "Like `write-region', q.v., but CODING-SYSTEM the first arg will be
35
+ applied to `coding-system-for-write'."
36
+ (let ((coding-system-for-write coding-system)
37
+ (file-coding-system coding-system))
38
+ (write-region start end filename append visit))))
39
+
40
+ (if (and (fboundp 'regexp-opt)
41
+ (not (featurep 'xemacs)))
42
+ (defalias 'mhc-regexp-opt 'regexp-opt)
43
+ (defun mhc-regexp-opt (strings &optional paren)
44
+ "Return a regexp to match a string in STRINGS.
45
+ Each string should be unique in STRINGS and should not contain any regexps,
46
+ quoted or not. If optional PAREN is non-nil, ensure that the returned regexp
47
+ is enclosed by at least one regexp grouping construct."
48
+ (let ((open-paren (if paren "\\(" "")) (close-paren (if paren "\\)" "")))
49
+ (concat open-paren (mapconcat 'regexp-quote strings "\\|") close-paren))))
50
+
51
+
52
+ (if (fboundp 'string-to-char-list)
53
+ (defalias 'mhc-string-to-char-list 'string-to-char-list)
54
+ (defun mhc-string-to-char-list (string)
55
+ (string-to-list string)))
56
+
57
+ (provide 'mhc-compat)
58
+
59
+ ;;; Copyright Notice:
60
+
61
+ ;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
62
+ ;; Copyright (C) 2000 MHC developing team. All rights reserved.
63
+
64
+ ;; Redistribution and use in source and binary forms, with or without
65
+ ;; modification, are permitted provided that the following conditions
66
+ ;; are met:
67
+ ;;
68
+ ;; 1. Redistributions of source code must retain the above copyright
69
+ ;; notice, this list of conditions and the following disclaimer.
70
+ ;; 2. Redistributions in binary form must reproduce the above copyright
71
+ ;; notice, this list of conditions and the following disclaimer in the
72
+ ;; documentation and/or other materials provided with the distribution.
73
+ ;; 3. Neither the name of the team nor the names of its contributors
74
+ ;; may be used to endorse or promote products derived from this software
75
+ ;; without specific prior written permission.
76
+ ;;
77
+ ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
78
+ ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
79
+ ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
80
+ ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
81
+ ;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
82
+ ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
83
+ ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
84
+ ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85
+ ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
86
+ ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
87
+ ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
88
+ ;; OF THE POSSIBILITY OF SUCH DAMAGE.
89
+
90
+ ;;; mhc-compat.el ends here
data/emacs/mhc-date.el ADDED
@@ -0,0 +1,642 @@
1
+ ;;; mhc-date.el -- Digit style Date Calculation Lib.
2
+
3
+ ;; Author: Yoshinari Nomura <nom@quickhack.net>,
4
+ ;; TSUCHIYA Masatoshi <tsuchiya@namazu.org>
5
+ ;;
6
+ ;; Created: 2000/06/14
7
+ ;; Revised: $Date: 2004/05/06 16:35:13 $
8
+
9
+ ;;;
10
+ ;;; Commentary:
11
+ ;;;
12
+
13
+ ;;
14
+ ;; mhc-date format is simple. It expresses a date by
15
+ ;; days from 1970/1/1
16
+ ;;
17
+ ;; for example:
18
+ ;;
19
+ ;; (mhc-date-new 1970 1 1) -> 0
20
+ ;; (mhc-date-new 2000 6 14) -> 11122
21
+ ;;
22
+ ;; mhc-time is also simple. It expresses a time by minits from midnight.
23
+
24
+ ;;;
25
+ ;;; Code:
26
+ ;;;
27
+
28
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29
+ ;;; mhc-time
30
+
31
+ (defsubst mhc-time/check (HH MM)
32
+ (and (integerp HH) (>= HH 0) (<= HH 99)
33
+ (integerp MM) (>= MM 0) (<= MM 59)))
34
+
35
+ (defmacro mhc-time-HH (time)
36
+ `(/ ,time 60))
37
+
38
+ (defmacro mhc-time-MM (time)
39
+ `(% ,time 60))
40
+
41
+ ;; All constructors emit error signal if args are illegal.
42
+ ;; In case called with noerror is t, return nil quietly.
43
+
44
+ (defsubst mhc-time-new (HH MM &optional noerror)
45
+ (if (mhc-time/check HH MM)
46
+ (+ (* HH 60) MM)
47
+ (if noerror
48
+ nil
49
+ (error "mhc-time-new: arg error (%s,%s)" HH MM))))
50
+
51
+ (defsubst mhc-time-new-from-string (str &optional noerror regexp)
52
+ (let (ret (match (match-data)))
53
+ (if (string-match (or regexp "^\\([0-9][0-9]\\):\\([0-9][0-9]\\)$") str)
54
+ (setq ret (mhc-time-new (mhc-date/substring-to-int str 1)
55
+ (mhc-date/substring-to-int str 2)
56
+ t)))
57
+ (store-match-data match)
58
+ (if (or noerror ret)
59
+ ret
60
+ (error "mhc-time-new-from-string: format error (%s)" str))))
61
+
62
+ (defsubst mhc-time-now ()
63
+ (let* ((now (decode-time (current-time)))
64
+ (HH (nth 2 now))
65
+ (MM (nth 1 now)))
66
+ (mhc-time-new HH MM)))
67
+
68
+ ;; xxx: use defmacro for speed !!
69
+ (defalias 'mhc-time-max 'max)
70
+ (defalias 'mhc-time-min 'min)
71
+ (defalias 'mhc-time< '<)
72
+ (defalias 'mhc-time= '=)
73
+ (defalias 'mhc-time<= '<=)
74
+ (defalias 'mhc-time> '>)
75
+ (defalias 'mhc-time>= '>=)
76
+
77
+ (defun mhc-time-sort (time-list)
78
+ (sort time-list (function mhc-time<)))
79
+
80
+ (defmacro mhc-time-let (time &rest form)
81
+ (let ((tempvar (make-symbol "tempvar")))
82
+ `(let* ((,tempvar ,time)
83
+ (hh (mhc-time-HH ,tempvar))
84
+ (mm (mhc-time-MM ,tempvar)))
85
+ ,@form)))
86
+ (put 'mhc-time-let 'lisp-indent-function 1)
87
+ (put 'mhc-time-let 'edebug-form-spec '(form body))
88
+
89
+ (defmacro mhc-time-to-string (time)
90
+ `(mhc-time-let ,time (format "%02d:%02d" hh mm)))
91
+
92
+ (defsubst mhc-time-to-list (time)
93
+ (list (mhc-time-HH time)
94
+ (mhc-time-MM time)))
95
+
96
+ (defalias 'mhc-time+ '+)
97
+ (defalias 'mhc-time- '-)
98
+
99
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100
+ ;;; mhc-date
101
+
102
+ ;;
103
+ ;; special form.
104
+ ;;
105
+
106
+ (defmacro mhc-date-let (date &rest form) "\
107
+ This special form converts DATE, as the number of days since
108
+ 1970/01/01, to following local variables, and evaluates FORM.
109
+
110
+ yy The year, an integer typically greater than 1900.
111
+ mm The month of the year, as an integer between 1 and 12.
112
+ dd The day of the month, as an integer between 1 and 31.
113
+ ww The day of week, as an integer between 0 and 6, where 0
114
+ stands for Sunday.
115
+ "
116
+ (let ((tempvar (make-symbol "tempvar")))
117
+ `(let* ((,tempvar (mhc-date-to-list ,date))
118
+ (yy (nth 0 ,tempvar))
119
+ (mm (nth 1 ,tempvar))
120
+ (dd (nth 2 ,tempvar))
121
+ (ww (nth 3 ,tempvar)))
122
+ ,@form)))
123
+ (put 'mhc-date-let 'lisp-indent-function 1)
124
+ (put 'mhc-date-let 'edebug-form-spec '(form body))
125
+
126
+
127
+ (defmacro mhc-date-let-for-month (date &rest form) "\
128
+ This special form converts DATE, as the number of days since
129
+ 1970/01/01, to following local variables, and evaluates FORM.
130
+
131
+ yy The year, an integer typically greater than 1900.
132
+ mm The month of the year, as an integer between 1 and 12.
133
+ dd The day of the month, as an integer between 1 and 31.
134
+ ww The day of week, as an integer between 0 and 6, where 0
135
+ stands for Sunday.
136
+ oo The order of week, as an integer between 0 and 4.
137
+ last-p Predicate to check if the dd is in the last week.
138
+ "
139
+ (let ((tempvar (make-symbol "tempvar")))
140
+ `(let* ((,tempvar (mhc-date-to-list ,date))
141
+ (yy (nth 0 ,tempvar))
142
+ (mm (nth 1 ,tempvar))
143
+ (dd 1)
144
+ (ww (nth 3 ,tempvar))
145
+ (end (mhc-date/last-day-of-month yy mm))
146
+ (days ,date)
147
+ (last-p nil))
148
+ (while (<= dd end)
149
+ ,@form
150
+ (setq days (mhc-date++ days)
151
+ dd (1+ dd)
152
+ oo (/ (1- dd) 7)
153
+ ww (% (1+ ww) 7)
154
+ last-p (< (- end 7) dd))))))
155
+ (put 'mhc-date-let-for-month 'lisp-indent-function 1)
156
+ (put 'mhc-date-let-for-month 'edebug-form-spec '(form body))
157
+
158
+
159
+ ;;
160
+ ;; private
161
+ ;;
162
+
163
+ (defsubst mhc-date/leap-year-p (yy)
164
+ (and (zerop (% yy 4))
165
+ (or (not (zerop (% yy 100)))
166
+ (zerop (% yy 400)))))
167
+
168
+ (defsubst mhc-date/last-day-of-month (yy mm)
169
+ (if (and (= mm 2) (mhc-date/leap-year-p yy))
170
+ 29
171
+ (aref '[0 31 28 31 30 31 30 31 31 30 31 30 31] mm)))
172
+
173
+ (defsubst mhc-date/check (yy mm dd)
174
+ (and (integerp yy) (>= yy 1000)
175
+ (integerp mm) (>= mm 1) (<= mm 12)
176
+ (integerp dd) (>= dd 1) (<= dd (mhc-date/last-day-of-month yy mm))
177
+ t))
178
+
179
+ (defmacro mhc-date/day-number (yy mm dd)
180
+ `(if (mhc-date/leap-year-p ,yy)
181
+ (+ (aref '[0 0 31 60 91 121 152 182 213 244 274 305 335] ,mm) ,dd)
182
+ (+ (aref '[0 0 31 59 90 120 151 181 212 243 273 304 334] ,mm) ,dd)))
183
+
184
+ (defsubst mhc-date/absolute-from-epoch (yy mm dd)
185
+ (let ((xx (1- yy)))
186
+ (+ (mhc-date/day-number yy mm dd)
187
+ (* xx 365)
188
+ (/ xx 4)
189
+ (/ xx -100)
190
+ (/ xx 400)
191
+ -719163)))
192
+
193
+ (defsubst mhc-date/iso-week-days (yday wday)
194
+ (- yday -3 (% (- yday wday -382) 7)))
195
+
196
+ (defmacro mhc-date/substring-to-int (str pos)
197
+ `(string-to-number
198
+ (substring ,str (match-beginning ,pos) (match-end ,pos))))
199
+
200
+ ;; according to our current time zone,
201
+ ;; convert timezone string into offset minutes
202
+ ;;
203
+ ;; for example, if current time zone is in Japan,
204
+ ;; convert "GMT" or "+0000" into 540.
205
+ (defun mhc-date/string-to-timezone-offset (timezone)
206
+ (let ((tz (or (cdr (assoc timezone
207
+ '(("PST" . "-0800") ("PDT" . "-0700")
208
+ ("MST" . "-0700") ("MDT" . "-0600")
209
+ ("CST" . "-0600") ("CDT" . "-0500")
210
+ ("EST" . "-0500") ("EDT" . "-0400")
211
+ ("AST" . "-0400") ("NST" . "-0300")
212
+ ("UT" . "+0000") ("GMT" . "+0000")
213
+ ("BST" . "+0100") ("MET" . "+0100")
214
+ ("EET" . "+0200") ("JST" . "+0900"))))
215
+ timezone))
216
+ min
217
+ offset)
218
+ (if (string-match "\\([-+]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" tz)
219
+ (progn
220
+ (setq min (* (+ (* 60 (mhc-date/substring-to-int tz 2))
221
+ (mhc-date/substring-to-int tz 3))
222
+ (if (string= "+"
223
+ (substring tz
224
+ (match-beginning 1)
225
+ (match-end 1)))
226
+ 1 -1))
227
+ offset (- (/ (car (current-time-zone)) 60) min))))))
228
+
229
+ ;;
230
+ ;; conversion.
231
+ ;;
232
+
233
+ (defsubst mhc-date-to-second (date)
234
+ ;; It has workaround in case of 28 bit integer.
235
+ (let (high low)
236
+ (setq low (* (+ date (if (< (nth 0 (current-time-zone)) 0) 1 0)) 240)
237
+ high (/ low 65536)
238
+ low (* (% low 65536) 360)
239
+ high (+ (* high 360) (/ low 65536))
240
+ low (% low 65536))
241
+ (list high low 0)))
242
+
243
+
244
+ (defsubst mhc-date/to-list1 (date)
245
+ (let ((lst (decode-time (mhc-date-to-second date))))
246
+ (list (nth 5 lst)
247
+ (nth 4 lst)
248
+ (nth 3 lst)
249
+ (nth 6 lst))))
250
+
251
+ (defsubst mhc-date/to-list2 (date)
252
+ (let (x b c d e w dom)
253
+ (setq w (% (+ date 25568) 7)
254
+ date (+ date 2440588)
255
+ x (floor (/ (- date 1867216.25) 36524.25))
256
+ b (- (+ date 1525 x) (floor (/ x 4.0)))
257
+ c (floor (/ (- b 122.1) 365.25))
258
+ d (floor (* 365.25 c))
259
+ e (floor (/ (- b d) 30.6001))
260
+ dom (- b d (floor (* 30.6001 e))))
261
+ (if (<= e 13)
262
+ (list (- c 4716) (1- e) dom w)
263
+ (list (- c 4715) (- e 13) dom w))))
264
+
265
+ (defsubst mhc-date-to-list (date)
266
+ (if (and (<= 0 date) (<= date 24837))
267
+ (mhc-date/to-list1 date)
268
+ (mhc-date/to-list2 date)))
269
+
270
+ ;;
271
+ ;; constructor.
272
+ ;;
273
+
274
+ ;; All constructors emit error signal if args are illegal.
275
+ ;; In case called with noerror is t, return nil quietly.
276
+
277
+ ;; new from 3 digits.
278
+ (defsubst mhc-date-new (yy mm dd &optional noerror)
279
+ (if (mhc-date/check yy mm dd)
280
+ (mhc-date/absolute-from-epoch yy mm dd)
281
+ (if noerror
282
+ nil
283
+ (error "mhc-date-new: arg error (%s,%s,%s)" yy mm dd))))
284
+
285
+
286
+ ;; new from emacs style time such as (14654 3252 689999).
287
+ (defsubst mhc-date-new-from-second (&optional second)
288
+ (let ((now (decode-time (or second (current-time)))))
289
+ (mhc-date/absolute-from-epoch
290
+ (nth 5 now)
291
+ (nth 4 now)
292
+ (nth 3 now))))
293
+
294
+ ;; new from current time.
295
+ (defalias 'mhc-date-now 'mhc-date-new-from-second)
296
+
297
+ ;; new from string. 19990101
298
+ (defsubst mhc-date-new-from-string (str &optional noerror)
299
+ (let (ret (match (match-data)))
300
+ (if (string-match
301
+ "^\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)$" str)
302
+ (setq ret (mhc-date-new (mhc-date/substring-to-int str 1)
303
+ (mhc-date/substring-to-int str 2)
304
+ (mhc-date/substring-to-int str 3)
305
+ t)))
306
+ (store-match-data match)
307
+ (if (or noerror ret)
308
+ ret
309
+ (error "mhc-date-new-from-string: format error (%s)" str))))
310
+
311
+ ;; new from string. [[yyyy/]mm]/dd
312
+ (defsubst mhc-date-new-from-string2 (str &optional base-date noerror)
313
+ (mhc-date-let (or base-date (mhc-date-now))
314
+ (let ((match (match-data)) fail ret)
315
+ (cond
316
+ ((string-match
317
+ "^\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)$" str)
318
+ (setq yy (mhc-date/substring-to-int str 1)
319
+ mm (mhc-date/substring-to-int str 2)
320
+ dd (mhc-date/substring-to-int str 3)))
321
+ ((string-match "^\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)$" str)
322
+ (setq yy (mhc-date/substring-to-int str 1)
323
+ mm (mhc-date/substring-to-int str 2)
324
+ dd (mhc-date/substring-to-int str 3)))
325
+ ((string-match "^\\([0-9]+\\)/\\([0-9]+\\)$" str)
326
+ (setq mm (mhc-date/substring-to-int str 1)
327
+ dd (mhc-date/substring-to-int str 2)))
328
+ ((string-match "^\\([0-9]+\\)$" str)
329
+ (setq dd (mhc-date/substring-to-int str 1)))
330
+ (t
331
+ (setq fail t)))
332
+ (store-match-data match)
333
+ (if (not fail) (setq ret (mhc-date-new yy mm dd t)))
334
+ (if (or noerror ret)
335
+ ret
336
+ (error "mhc-date-new-from-string2: format error (%s)" str)))))
337
+
338
+ ;; regexp for rfc822 Date: field.
339
+ (defconst mhc-date/rfc822-date-regex
340
+ ;; assuming ``Tue, 9 May 2000 12:15:12 -0700 (PDT)''
341
+ (concat
342
+ "\\([0-9]+\\)[ \t]+" ;; day
343
+ "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|" ;;
344
+ "Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ \t]+" ;; month
345
+ "\\([0-9]+\\)[ \t]+" ;; year
346
+ "\\([0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?[ \t]*" ;; hh:mm(:ss)?
347
+ "\\([A-Z][A-Z][A-Z]\\|[-+][0-9][0-9][0-9][0-9]\\)" ;; JST or +0900
348
+ ))
349
+
350
+ ;; new from rfc822 Date: field.
351
+ (defun mhc-date-new-from-string3 (string)
352
+ (if (and (stringp string) (string-match mhc-date/rfc822-date-regex string))
353
+ (let ((dd (mhc-date/substring-to-int string 1))
354
+ (mm nil)
355
+ (mon (substring string (match-beginning 2) (match-end 2)))
356
+ (yy (mhc-date/substring-to-int string 3))
357
+ (MM (+ (* 60 (mhc-date/substring-to-int string 4))
358
+ (mhc-date/substring-to-int string 5)))
359
+ (tz (substring string (match-beginning 8) (match-end 8)))
360
+ tz-offset)
361
+ (setq
362
+ yy (cond
363
+ ((< yy 50) (+ yy 2000))
364
+ ((< yy 100) (+ yy 1900))
365
+ (t yy))
366
+ mm (1+ (/ (string-match mon
367
+ "JanFebMarAprMayJunJulAugSepOctNovDec") 3))
368
+ tz-offset (mhc-date/string-to-timezone-offset tz)
369
+ MM (+ MM tz-offset))
370
+ (car
371
+ (cond
372
+ ((< MM 0)
373
+ (setq MM (+ MM 1440))
374
+ (list (mhc-date-- (mhc-date-new yy mm dd))
375
+ (mhc-time-new (/ MM 60) (% MM 60))
376
+ tz-offset))
377
+ ((>= MM 1440)
378
+ (setq MM (- MM 1440))
379
+ (list (mhc-date++ (mhc-date-new yy mm dd))
380
+ (mhc-time-new (/ MM 60) (% MM 60))
381
+ tz-offset))
382
+ (t
383
+ (list (mhc-date-new yy mm dd)
384
+ (mhc-time-new (/ MM 60) (% MM 60))
385
+ tz-offset)))))))
386
+
387
+ ;;
388
+ ;; manipulate yy, mm, dd.
389
+ ;;
390
+
391
+ (defmacro mhc-date-yy (date)
392
+ `(nth 0 (mhc-date-to-list ,date)))
393
+
394
+ (defmacro mhc-date-mm (date)
395
+ `(nth 1 (mhc-date-to-list ,date)))
396
+
397
+ (defmacro mhc-date-dd (date)
398
+ `(nth 2 (mhc-date-to-list ,date)))
399
+
400
+ (defmacro mhc-date-ww (date)
401
+ `(nth 3 (mhc-date-to-list ,date)))
402
+
403
+ (defmacro mhc-date-oo (date)
404
+ `(/ (1- (mhc-date-dd ,date)) 7))
405
+
406
+ (defsubst mhc-date-cw (date)
407
+ (mhc-date-let date
408
+ (let* ((yday (mhc-date/day-number yy mm dd))
409
+ (days (mhc-date/iso-week-days yday ww))
410
+ (d))
411
+ (if (< days 0)
412
+ (setq days (mhc-date/iso-week-days
413
+ (+ yday 365 (if (mhc-date/leap-year-p (1- yy)) 1 0)) ww))
414
+ (setq d (mhc-date/iso-week-days
415
+ (- yday 365 (if (mhc-date/leap-year-p yy) 1 0)) ww))
416
+ (if (<= 0 d) (setq days d)))
417
+ (1+ (/ days 7)))))
418
+
419
+ ;;
420
+ ;; compare.
421
+ ;;
422
+
423
+ (defalias 'mhc-date= '= )
424
+ (defalias 'mhc-date< '< )
425
+ (defalias 'mhc-date<= '<= )
426
+ (defalias 'mhc-date> '> )
427
+ (defalias 'mhc-date>= '>= )
428
+
429
+ (defalias 'mhc-date-max 'max)
430
+ (defalias 'mhc-date-min 'min)
431
+ (defmacro mhc-date-sort (date-list)
432
+ `(sort ,date-list (function mhc-date<)))
433
+
434
+ (defsubst mhc-date-yy= (d1 d2) (= (mhc-date-yy d1) (mhc-date-yy d2)))
435
+ (defsubst mhc-date-yy< (d1 d2) (< (mhc-date-yy d1) (mhc-date-yy d2)))
436
+ (defsubst mhc-date-yy<= (d1 d2) (<= (mhc-date-yy d1) (mhc-date-yy d2)))
437
+ (defsubst mhc-date-yy> (d1 d2) (mhc-date-yy< d2 d1))
438
+ (defsubst mhc-date-yy>= (d1 d2) (mhc-date-yy<= d2 d1))
439
+
440
+ (defsubst mhc-date-yymm= (d1 d2)
441
+ (and (mhc-date-yy= d1 d2)
442
+ (= (mhc-date-mm d1) (mhc-date-mm d2))))
443
+
444
+ (defsubst mhc-date-yymm< (d1 d2)
445
+ (or (mhc-date-yy< d1 d2)
446
+ (and (mhc-date-yy= d1 d2)
447
+ (< (mhc-date-mm d1) (mhc-date-mm d2)))))
448
+
449
+ (defmacro mhc-date-yymm> (d1 d2) `(mhc-date-yymm< ,d2 ,d1))
450
+ (defmacro mhc-date-yymm<= (d1 d2) `(not (mhc-date-yymm> ,d1 ,d2)))
451
+ (defmacro mhc-date-yymm>= (d1 d2) `(mhc-date-yymm<= ,d2 ,d1))
452
+
453
+ ;;
454
+ ;; increment, decrement.
455
+ ;;
456
+
457
+ (defalias 'mhc-date+ '+ )
458
+ (defalias 'mhc-date- '- )
459
+ (defalias 'mhc-date++ '1+)
460
+ (defalias 'mhc-date-- '1-)
461
+
462
+ (defsubst mhc-date-mm+ (date c)
463
+ (mhc-date-let date
464
+ (let (xx pp)
465
+ (setq xx (+ mm c))
466
+ (setq pp (if (< 0 xx ) (/ (- xx 1) 12) (/ (- xx 12) 12)))
467
+ (setq yy (+ yy pp) mm (- xx (* 12 pp)))
468
+ (if (mhc-date/check yy mm dd)
469
+ (mhc-date-new yy mm dd)
470
+ (mhc-date-new yy mm (mhc-date/last-day-of-month yy mm))))))
471
+
472
+ (defmacro mhc-date-mm- (date c) `(mhc-date-mm+ ,date (- ,c)))
473
+ (defmacro mhc-date-mm++ (date) `(mhc-date-mm+ ,date 1))
474
+ (defmacro mhc-date-mm-- (date) `(mhc-date-mm- ,date 1))
475
+
476
+ (defsubst mhc-date-yy+ (date c)
477
+ (mhc-date-let date
478
+ (setq yy (+ yy c))
479
+ (if (mhc-date/check yy mm dd)
480
+ (mhc-date-new yy mm dd)
481
+ (mhc-date-new yy mm (mhc-date/last-day-of-month yy mm)))))
482
+
483
+ (defmacro mhc-date-yy- (date c) `(mhc-date-yy+ ,date (- ,c)))
484
+ (defmacro mhc-date-yy++ (date) `(mhc-date-yy+ ,date 1))
485
+ (defmacro mhc-date-yy-- (date) `(mhc-date-yy- ,date 1))
486
+
487
+ ;;
488
+ ;; get meaninful date.
489
+ ;;
490
+ (defmacro mhc-date-mm-first (date)
491
+ "Return the number of days since 1970/01/01 to the first day of month, DATE."
492
+ `(mhc-date-let ,date
493
+ (mhc-date-new yy mm 1 t)))
494
+
495
+ (defmacro mhc-date-mm-last (date)
496
+ "Return the number of days since 1970/01/01 to the last day of month, DATE."
497
+ `(mhc-date-let ,date
498
+ (mhc-date-new yy mm (mhc-date/last-day-of-month yy mm) t)))
499
+
500
+ (defun mhc-date-ww-first (date &optional wkst)
501
+ "Return the first day of week immediate before DATE.
502
+ WKST specifies start day of week (0:Sunday...6:Saturday).
503
+ If WKST is not specified, 0 (Sunday) is used."
504
+ (setq wkst (or wkst 0))
505
+ (mhc-date- date (mod (- (mhc-date-ww date) wkst) 7)))
506
+
507
+ (defun mhc-date-ww-last (date &optional wkst)
508
+ "Return the last day of week immediate after DATE.
509
+ WKST specifies start day of week (0:Sunday...6:Saturday).
510
+ If WKST is not specified, 0 (Sunday) is used."
511
+ (mhc-date+ (mhc-date-ww-first date wkst) 6))
512
+
513
+ ;;
514
+ ;; predicate
515
+ ;;
516
+
517
+ ;; check if the date is in the last week of a month.
518
+ (defsubst mhc-date-oo-last-p (date)
519
+ (< (- (mhc-date/last-day-of-month
520
+ (mhc-date-yy date)
521
+ (mhc-date-mm date)) 7) (mhc-date-dd date)))
522
+
523
+
524
+ (defalias 'mhc-date-p 'integerp)
525
+
526
+
527
+ ;;
528
+ ;; miscellaneous.
529
+ ;;
530
+
531
+ (defmacro mhc-end-day-of-week ()
532
+ `(nth mhc-start-day-of-week '(6 0 1 2 3 4 5)))
533
+
534
+ ;;
535
+ ;; to string.
536
+ ;;
537
+
538
+ ;; (mhc-date-format date "%04d%02d%02d" yy mm dd)
539
+ (defmacro mhc-date-format (date format &rest vars)
540
+ `(mhc-date-let ,date
541
+ (format ,format ,@vars)))
542
+
543
+ (defun mhc-date-digit-to-mm-string (mm &optional long)
544
+ (if long
545
+ (aref
546
+ '[nil "January" "February" "March" "April" "May" "June"
547
+ "July" "August" "September" "October" "November" "December"]
548
+ mm)
549
+ (aref
550
+ [nil "Jan" "Feb" "Mar" "Apr" "May" "Jun"
551
+ "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"]
552
+ mm)))
553
+
554
+ (defun mhc-date-digit-to-ww-string (ww &optional long)
555
+ (if long
556
+ (aref ["Sunday" "Monday" "Tuesday" "Wednesday"
557
+ "Thursday" "Friday" "Saturday"] ww)
558
+ (aref ["Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat"] ww)))
559
+
560
+ (defun mhc-date-digit-to-ww-japanese-string (ww &optional long)
561
+ (if long
562
+ (aref ["日曜日" "月曜日" "火曜日" "水曜日"
563
+ "木曜日" "金曜日" "土曜日"] ww)
564
+ (aref ["日" "月" "火" "水" "木" "金" "土"] ww)))
565
+
566
+ (defun mhc-date-digit-to-oo-string (oo &optional long)
567
+ (aref ["1st" "2nd" "3rd" "4th" "5th"] oo))
568
+
569
+ ;; format-time-string subset (but has enough spec)
570
+ (defun mhc-date-format-time-string (format date)
571
+ (mhc-date-let date
572
+ (let (head match (ret "") char)
573
+ (while (string-match "%." format)
574
+ (setq head (substring format 0 (match-beginning 0))
575
+ match (match-string 0 format)
576
+ format (substring format (match-end 0))
577
+ char (aref match 1))
578
+ (cond
579
+ ((eq char ?Y) ;; 100年単位の年
580
+ (setq match (format "%d" yy)))
581
+
582
+ ((eq char ?y) ;; 年の下2桁 (00-99)
583
+ (setq match (format "%02d" (% yy 100))))
584
+
585
+ ((or (eq char ?b) (eq char ?h)) ;; 月 略称
586
+ (setq match (mhc-date-digit-to-mm-string mm)))
587
+
588
+ ((eq char ?B) ;; 月 名称
589
+ (setq match (mhc-date-digit-to-mm-string mm t)))
590
+
591
+ ((eq char ?m) ;; 月 (01-12)
592
+ (setq match (format "%02d" mm)))
593
+
594
+ ((eq char ?d) ;; 日 (ゼロ padding)
595
+ (setq match (format "%02d" dd)))
596
+
597
+ ((eq char ?e) ;; 日 (空白 padding)
598
+ (setq match (format "%2d" dd)))
599
+
600
+ ((eq char ?a) ;; 曜日 略称
601
+ (setq match (mhc-date-digit-to-ww-string ww)))
602
+
603
+ ((eq char ?A) ;; 曜日 名称
604
+ (setq match (mhc-date-digit-to-ww-string ww t))))
605
+
606
+ (setq ret (concat ret head match)))
607
+ (concat ret format))))
608
+
609
+ (provide 'mhc-date)
610
+
611
+ ;;; Copyright Notice:
612
+
613
+ ;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
614
+ ;; Copyright (C) 2000 MHC developing team. All rights reserved.
615
+
616
+ ;; Redistribution and use in source and binary forms, with or without
617
+ ;; modification, are permitted provided that the following conditions
618
+ ;; are met:
619
+ ;;
620
+ ;; 1. Redistributions of source code must retain the above copyright
621
+ ;; notice, this list of conditions and the following disclaimer.
622
+ ;; 2. Redistributions in binary form must reproduce the above copyright
623
+ ;; notice, this list of conditions and the following disclaimer in the
624
+ ;; documentation and/or other materials provided with the distribution.
625
+ ;; 3. Neither the name of the team nor the names of its contributors
626
+ ;; may be used to endorse or promote products derived from this software
627
+ ;; without specific prior written permission.
628
+ ;;
629
+ ;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
630
+ ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
631
+ ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
632
+ ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
633
+ ;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
634
+ ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
635
+ ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
636
+ ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
637
+ ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
638
+ ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
639
+ ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
640
+ ;; OF THE POSSIBILITY OF SUCH DAMAGE.
641
+
642
+ ;;; mhc-date.el ends here.