Shammer's Philosophy

My private adversaria

HTMLのカレンダー

ちょっとしたお遊び。Lisp で HTML の簡易カレンダーを出力するプログラム。

(defparameter *weeks* 1)
(defparameter *month* 1)
(defparameter *date* 1)
(defparameter *is-leap-year* nil)
(with-open-file (f "calendar.html" :direction :output :if-exists :supersede)
  (format f "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
  (format f "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">")
  (format f "<html>")
  (format f "<head>")
  (format f "<title>Calendar</title>")
  (format f "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>")
  (format f "</head>")
  (format f "<body>")
  (format f "<table border=\"1\">")
  (format f "<caption></caption>")
  (format f "<tbody>")
  (format f "<tr>")
  (format t "How many weeks?:")
  (do ((weeks (read) (read)))
      ((and (numberp weeks) (< 0 weeks))
       (setf *weeks* weeks))
    (format t "Invalid answer, How many weeks would you like to generate?"))
  (format t "From Month(1-12):")
  (do ((month (read) (read)))
      ((and (numberp month)
	    (and (< 0 month) (<= month 12)))
       (setf *month* month))
    (format t "Invalid input, try again(1-12):"))
  (format t "From Date(1-31):")
  (do ((date (read) (read)))
      ((and (numberp date)
	    (cond ((member *month* '(1 3 5 7 8 10 12))
		   (and (< 0 date) (<= date 31)))
		  ((member *month* '(4 6 9 11))
		   (and (< 0 date) (<= date 30)))
		  (t ; Febrary
		   (format t "Leap year(y/n)?:")
		   (do ((answer (read-line) (read-line)))
		       ()
		     (cond ((string= "y" answer)
			    (setf *is-leap-year* t)
			    (return (and (< 0 date) (<= date 29))))
			   ((string= "n" answer)
			    (return (and (< 0 date) (<= date 28))))
			   (t
			    (format t "Invalid answer, y or n with case sensitive:")))))))
       (setf *date* date))
    (format t "Invalid date, try again:"))
  (dotimes (i *weeks*)
    (dotimes (j 7)
      (format f "<th align=\"center\" width=\"200\">~A/~A(~A)</th>"
	      (write-to-string *month*)
	      (write-to-string *date*)
	      (nth j '("日" "月" "火" "水" "木" "金" "土")))
      (setf *date* (+ 1 *date*))
      (cond ((and (eql *date* 29)
		  (eql *month* 2))
	     (unless *is-leap-year*
	       (setf *date* 1)
	       (setf *month* 3)))
	    ((and (eql *date* 30)
		  (eql *month* 2)
		  *is-leap-year*)
	     (setf *month* 3)
	     (setf *date* 1))
	    ((eql *date* 31)
	     (when (member *month* '(4 6 9 11))
	       (setf *date* 1)
	       (setf *month* (+ 1 *month*))))
	    ((eql *date* 32)
	     (when (member *month* '(1 3 5 7 8 10 12))
	       (setf *date* 1)
	       (setf *month* (mod (+ 1 *month*) 12))))))
    (format f "</tr>")
    (format f "<tr>")
    (format f "<th align=\"center\" height=\"175\"></th>")
    (dotimes (j 6)
      (format f "<td align=\"center\"></td>"))
    (format f "</tr>"))
  (format f "</tbody></table></body></html>"))
(quit)