buf2html-with-number
buf2html
ini2css-file
ini2css-buffer

  1. ;;; -*- Mode: Lisp -*-
  2. ;;;
  3. ;;; buf2html.l --- convert text of buffer to HTML
  4. ;;; Copyright (C) 2001 OHKUBO Hiroshi
  5. ;;; Author: OHKUBO Hiroshi <konata_o@hotmail.com>
  6. ;;; Version: 0.0.0.5
  7. ;;; Time-stamp: <2001/12/15 11:47:34 +0900>
  8. ;;; Xyzzy: 0.2.2.220
  9. ;;; buf2html:
  10. ;;;
  11. ;;;     なるべくバッファの表示を再現するような HTML を生成します。
  12. ;;;     キーワード、正規表現キーワード、text-attribute に対応していますが、
  13. ;;;     一行反転表示には対応していません。
  14. ;;;
  15. ;;;     勘で書いている部分があるのでおかしな変換があると思います。
  16. ;;;     気がついた点を知らせて頂けるとありがたいです。
  17. ;;;
  18. ;;; Install:
  19. ;;;
  20. ;;;     1. 解凍して buf2html.l を、~/site-lispにコピーします。
  21. ;;;
  22. ;;;     2. 必要ならばバイトコンパイルします。
  23. ;;;
  24. ;;;             M-x byte-compile-file
  25. ;;;
  26. ;;;     3. .xyzzy または siteinit.l に以下のコードを追加します。
  27. ;;;
  28. ;;;             (load-library "buf2html")
  29. ;;;
  30. ;;;     4. 上記の設定を反映させるために、xyzzyを再起動します。
  31. ;;;
  32. ;;; Usage:
  33. ;;;
  34. ;;;     1. M-x ini2css-file または M-x ini2css-buffer で xyzzy の
  35. ;;;        INI ファイル (標準では xyzzy.ini) からスタイルシートを生成し、
  36. ;;;        xyzzy.css というファイル名で保存。
  37. ;;;
  38. ;;;     2. 変換元のバッファで M-x buf2html または M-x buf2html-with-number し、
  39. ;;;        HTML の出力されたバッファを xyzzy.css を保存したフォルダに保存。
  40. ;;;
  41. ;;; Changes:
  42. ;;;     [Version 0.0.0.5]
  43. ;;;     Sat, 15 Dec 2001 11:19:03 +0900
  44. ;;;             ・ML で亀井さんに教えていただいたキーワード検索の方法に変更。
  45. ;;;               ・タグをハイライトするかどうかを html-highlight-mode の値で判定
  46. ;;;               ・syntax-symbol-prefix-p が non-nil の場合のハイライト
  47. ;;;               ・syntax-table の option に *syntax-option-c-preprocessor* が
  48. ;;;                 指定されていた場合の動作
  49. ;;;               上記 3 点について xyzzy と同様の動作になったと思います。
  50. ;;;
  51. ;;;     [Version 0.0.0.4]
  52. ;;;     Fri, 14 Dec 2001 18:25:03 +0900
  53. ;;;             ・tag のあるモードかどうかを syntax-table で判断するように。
  54. ;;;
  55. ;;;     Tue, 11 Dec 2001 10:30:34 +0900
  56. ;;;             ・Memo 修正。
  57. ;;;             ・<TITLE></TITLE> の間では半角スペースを &nbsp; に変換
  58. ;;;               しないように変更。
  59. ;;;
  60. ;;;     [Version 0.0.0.3]
  61. ;;;     Mon, 10 Dec 2001 17:58:20 +0900
  62. ;;;             ・context をパースする際の message の位置を変更。
  63. ;;;             ・行番号付き出力 buf2html-with-number 追加。
  64. ;;;             ・HTML 出力後バッファの modify flag を nil に。
  65. ;;;             ・その他修正。
  66. ;;;
  67. ;;;     [Version 0.0.0.2]
  68. ;;;     Fri, 07 Dec 2001 07:40:23 +0900
  69. ;;;             ・message の位置を修正。
  70. ;;;             ・bgr2rgb を buf2html-bgr2rgb に名称変更。
  71. ;;;             ・余分な HTML タグの削減。
  72. ;;;             ・キーワードが大文字小文字を区別するかの判定。
  73. ;;;             ・tag 文字 (syntax-open-tag-p, syntax-close-tag-p) を
  74. ;;;               キーワードより優先させるように修正。
  75. ;;;             ・その他修正。
  76. ;;;
  77. ;;;     [Version 0.0.0.1]
  78. ;;;     Fri, 07 Dec 2001 02:37:41 +0900
  79. ;;;             ・門田さんの mode2htm.l, ini2css.l を参考にして初版作成。
  80. ;;;
  81. ;;; Todo:
  82. ;;;     ・できれば行反転表示への対応
  83. ;;;     ・制御文字の表示
  84. ;;;     ・改行、タブ、EOF、全角スペース、半角スペースの表示
  85. ;;;     ・行間への対応
  86. ;;;     ・固定幅 bold 表示
  87. ;;;     ・lang や charset へのまともな対応
  88. ;;;     ・余分な HTML タグの削減
  89. ;;;     ・TAB 文字への対処
  90. ;;;     ・速度改善
  91. ;;;
  92. ;;; Memo:
  93. ;;;     ・正規表現キーワードよりもキーワードの方が優先される。
  94. ;;;       色が重ならないだけでなく、キーワード自体が重ならない。
  95. ;;;     ・キーワードの色よりもタグの開始・終了の色の方が優先される。
  96. ;;;       ただしタグの開始・終了文字の部分はキーワード構成部分となり得る。
  97. ;;;     ・html-highlight-mode が non-nil の場合は :tag の中でしか context は
  98. ;;;       切り替わらない。
  99. ;;;     ・context が nil 中での :string は 終了の " 自体までだが、
  100. ;;;       context が :tag 中での :string は終了の " の前まで。
  101. ;;;       "abcdefghijklmn"    "abcdefghijklmn"
  102. ;;;        ^^^^^^^^^^^^^^^ と  ^^^^^^^^^^^^^^ の違い。
  103. ;;;     ・正規表現キーワードは指定されたコンテキスト内であれば、隣接した
  104. ;;;       コンテキストをまたいでもよい。
  105. ;;;       単一のコンテキスト内でキーワードが完結する必要はない。
  106. ;;;       ("abc \"\" def" t (:color 1 0 :underline) (:string))
  107. ;;;       は 2 つの :string コンテキストによる「"abc "" def"」 をキーワードと
  108. ;;;       認識する。
  109. ;;;     ・正規表現キーワードにて個々の色設定がなされていても、begin end により除外
  110. ;;;       されている場合色はつかない。
  111. ;;;     ・("123\\(45\\(67\\)89\\)0" nil ((1 . (:color 1)) (2 . (:color 2))) t 1 1)
  112. ;;;       では、(:color 1) の色で 456789 に色がつくのではなく、67 には
  113. ;;;       (:color 2) の色で色がつく。
  114. ;;;       最後の begin end は色をつける point の範囲を group 番号で指定している。
  115. ;;;     ・text-attribute に (:underline nil) 等を指定しても、
  116. ;;;       (正規表現)キーワードで underline 等が指定されている場合は
  117. ;;;       それらは無効化されない。
  118. ;;;     ・color の nil と (:color nil) は異なる。
  119. ;;;     ・color に nil を指定するとその色指定は無視されるよう。
  120. ;;;
  121. ;;;
  122. ;;;     ・html-highlight-mode が non-nil の場合は基本的にキーワードは
  123. ;;;       タグ内部のみだが、0.2.2.207 で追加された記述方法で
  124. ;;;       nil context の中にもキーワード指定ができる。
  125. ;;;       keyword-hash-table をよくみていないがもしかしたら、キーワードファイル
  126. ;;;       自体を読んで parse しなければならない?
  127. ;;;     ・ed::regexp-keyword-list は必ず (compile-regexp-keyword-list) されている?
  128. ;;;     ・「正規表現のキーワード色分けの、グループごとの色指定」における
  129. ;;;       「colorがnilなら、同一範囲にマッチした若いグループ番号の色。tなら元の色。」
  130. ;;;       は具体的にどういうことなのか。「元の色」とは何か。
  131. ;;;       「元の色」は「地の色」(「文字色」「背景色」)であっているのか。
  132. ;;;       context は考慮する必要はないのか。
  133. ;;;
  134. ;;; Data structure:
  135. ;;;
  136. ;;;     <UNITS>  : (<UNIT>*)
  137. ;;;     <UNIT>   : (<TYPE> . <RANGE>)
  138. ;;;     <RANGES> : (<RANGE>*)
  139. ;;;     <RANGE>  : (<FROM> . <TO>)
  140. ;;;     <TYPE>   : (<keyword> . <INFO>)
  141. ;;;     <FROM>   : <POINT>
  142. ;;;     <TO>     : <POINT>
  143. ;;;     <POINT>  : <number>
  144. ;;;
  145. ;;;     <number> : /[0-9]+/
  146. ;;;     <keyword>: nil
  147. ;;;              | :string
  148. ;;;              | :comment
  149. ;;;              | :tag
  150. ;;;              | :buf2html-keyword
  151. ;;;              | :buf2html-regexp-keyword
  152. ;;;              | :buf2html-regexp-keyword-group
  153. ;;;              | :buf2html-text-attribute
  154. ;;;              | :buf2html-line-feed
  155. ;;;
  156. ;;;     <INFO>   : <TYPE> の <keyword> 毎に色々。
  157. ;;;
  158. ;;;       <keyword> == nil | :string | :comment | :tag
  159. ;;;              : nil
  160. ;;;
  161. ;;;       <keyword> == :buf2html-keyword
  162. ;;;              : compiled-color
  163. ;;;
  164. ;;;       <keyword> == :buf2html-regexp-keyword
  165. ;;;              : regexp-keyword-group-units
  166. ;;;
  167. ;;;       <keyword> == :buf2html-regexp-keyword-group
  168. ;;;              : compiled-color
  169. ;;;
  170. ;;;       <keyword> == :buf2html-text-attribute
  171. ;;;              : (btag . etag)
  172. ;;;
  173. ;;;       <keyword> == :buf2html-line-feed
  174. ;;;              : nil
  175. ;;;
  176. ;;;
  177. ;;;     ・<UNITS> を構成する <UNIT> は (<TYPE> . (<FROM> . <TO>)) の
  178. ;;;       <FROM> で昇順ソートされていなければならない。
  179. ;;;
  180. ;;;     ・<TO> は実際には範囲に含まれない。
  181. ;;;       <FROM>, <TO> は (buffer-substring <FROM> <TO>) となる値。
  182. ;;;
  183. ;;; Code:
  184. (provide "buf2html")
  185. (defconstant *buf2html-version* "0.0.0.5"
  186.   "buf2html: Version")
  187. (defvar *buf2html-color-context* t
  188.   "buf2html: context の解析を行う")
  189. (defvar *buf2html-color-keyword* t
  190.   "buf2html: キーワードの解析を行う")
  191. (defvar *buf2html-color-regexp-keyword* t
  192.   "buf2html: 正規表現キーワードの解析を行う")
  193. (defvar *buf2html-color-text-attribute* t
  194.   "buf2html: text-attribute の解析を行う")
  195. (defvar *buf2html-auto-mode-parameter-string* "Mode: html"
  196.   "buf2html: HTML 文書に含める xyzzy 用のモード指定")
  197. (defvar *buf2html-date-format* "%a, %d %b %Y %H:%M:%S %Z"
  198.   "buf2html: HTML 文書に含める日付書式")
  199. (defvar *buf2html-time-stamp-start* "Last updated: <"
  200.   "buf2html: 日付の前の文字列")
  201. (defvar *buf2html-time-stamp-end* ">"
  202.   "buf2html: 日付の後の文字列")
  203. (defvar *buf2html-buffer-tmp* "*buf2html: Tmp*"
  204.   "buf2html: 作業バッファ名")
  205. (defvar *buf2html-buffer-css* "*buf2html: CSS*"
  206.   "buf2html: スタイルシート出力バッファ名")
  207. (defvar *buf2html-buffer-html* "*buf2html: HTML*"
  208.   "buf2html: HTML 文書出力バッファ名")
  209. (defvar *buf2html-convert-half-space* nil
  210.   "buf2html: 半角スペースを必ず &nbsp; に変換")
  211. (defvar *buf2html-number-link* t
  212.   "buf2html: 行番号出力時、行番号の <A> タグを付加")
  213. (defvar *buf2html-string-encode-alist*
  214.   '(("&" . "&amp;")
  215.     ("<" . "&lt;")
  216.     (">" . "&gt;")
  217.     ( "\"" . "&quot;")
  218. ;   " " は状況に応じて変換
  219. ;   (" " . "&nbsp;")
  220.     )
  221.   "buf2html: 変換する文字参照リスト")
  222. (defvar *buf2html-char-code-limit* 128
  223.   "buf2html: syntax-table を調べる char-code の限界
  224. 全て調べる場合は lisp:char-code-limit を指定")
  225. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  226. ;; buf2html-with-number
  227. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. (defun buf2html-with-number ()
  229.   "buf2html: xyzzy の表示に従ってバッファを行番号つきで HTML に変換"
  230.   (interactive)
  231.   (buf2html t))
  232. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  233. ;; buf2html
  234. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  235. (defun buf2html (&optional line-number-p)
  236.   "buf2html: xyzzy の表示に従ってバッファを HTML に変換"
  237.   (interactive)
  238.   (let ((point-max (point-max))
  239.         (compiled-color-tag-table (make-hash-table))
  240.         all-units keyword-units regexp-keyword-units text-attribute-units
  241.         tag-char-units line-feed-units
  242.         opitimized-keyword-color-list line-feed-p
  243.         (source-buffer (selected-buffer)))
  244.     (long-operation
  245.       (save-excursion
  246.         (buf2html-set-buffer *buf2html-buffer-html*)
  247.         (with-output-to-buffer (*buf2html-buffer-html*)
  248.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  249.           ;; context
  250.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  251.           (if *buf2html-color-context*
  252.               (setq all-units (buf2html-get-units-context))
  253.             (setq all-units (cons nil (cons (point-min) (point-max)))))
  254.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  255.           ;; tag-char
  256.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  257.           (if html-highlight-mode
  258.               (setq tag-char-units
  259.                     (buf2html-get-units-tag-char
  260.                      (buf2html-get-ranges-if-context all-units '(:tag)))))
  261.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  262.           ;; keyword
  263.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  264.           (when (and *buf2html-color-context*
  265.                      *buf2html-color-keyword*
  266.                      (boundp 'ed::keyword-hash-table))
  267.             (setq keyword-units
  268.                   (buf2html-get-units-keyword
  269.                    (buf2html-range-concatenate
  270.                     (if html-highlight-mode
  271.                         (buf2html-get-ranges-if-context all-units '(:tag))
  272.                       (buf2html-get-ranges-if-not-context all-units '(:string :comment))))))
  273.             ;; keyword の compiled-color の値(数)にあった HTML タグの登録
  274.             (buf2html-add-compiled-color-tag-hash-table
  275.              compiled-color-tag-table (mapcar #'cdar keyword-units))
  276.             ;; keyword の範囲を適用
  277.             (message "Merge keyword range.")
  278.             (setq all-units (buf2html-unit-cover all-units keyword-units))
  279.             ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  280.             ;; c-preprocessor 用の特殊キーワード検索
  281.             (when (not (zerop (logand (get-syntax-option (syntax-table))
  282.                                       *syntax-option-c-preprocessor*)))
  283.               (setq keyword-units
  284.                     (buf2html-get-units-keyword-c-preprocessor
  285.                      (buf2html-range-concatenate
  286.                       (if html-highlight-mode
  287.                           (buf2html-get-ranges-if-context all-units '(:tag))
  288.                         (buf2html-get-ranges-if-not-context all-units '(:string :comment))))))
  289.               ;; keyword の compiled-color の値(数)にあった HTML タグの登録
  290.               (buf2html-add-compiled-color-tag-hash-table
  291.                compiled-color-tag-table (mapcar #'cdar keyword-units))
  292.               ;; keyword の範囲を適用
  293.               (message "Merge c preprocessor keyword range.")
  294.               (setq all-units (buf2html-unit-cover all-units keyword-units))
  295.               )
  296.             )
  297.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  298.           ;; regexp-keyword
  299.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  300.           (when (and *buf2html-color-context*
  301.                      *buf2html-color-regexp-keyword*
  302.                      (boundp 'ed::regexp-keyword-list))
  303.             ;; 正規表現キーワードの compiled-color の値にあった HTML タグの登録
  304.             (buf2html-add-compiled-color-tag-hash-table
  305.              compiled-color-tag-table
  306.              (buf2html-make-regexp-keyword-color-list ed::regexp-keyword-list))
  307.             (let (regexp colors compiled-context begin end (i 0)
  308.                   (regexp-keyword-list-length (length ed::regexp-keyword-list)))
  309.               (dolist (regexp-keyword ed::regexp-keyword-list)
  310.                 (incf i)
  311.                 (message "Parse regexp keyword: ~D/~D" i regexp-keyword-list-length)
  312. ;               (setq regexp (car regexp-keyword))
  313. ;               (setq colors (cadr regexp-keyword))
  314.                 (setq compiled-context (caddr regexp-keyword))
  315. ;               (setq begin (cadddr regexp-keyword))
  316. ;               (setq end (car (cddddr regexp-keyword)))
  317.                 (setq regexp-keyword-units
  318.                       (buf2html-get-units-regexp-keyword
  319.                        (buf2html-range-concatenate
  320.                         (buf2html-get-ranges-if-context
  321.                          all-units
  322.                          (buf2html-decode-compiled-context compiled-context)))
  323.                        regexp-keyword))
  324.                 ;; regexp-keyword の範囲を適用
  325.                 (message "Merge regexp keyword range: ~D/~D"
  326.                          i regexp-keyword-list-length)
  327.                 (setq all-units
  328.                       (buf2html-unit-cover all-units regexp-keyword-units))))
  329.             )
  330.           
  331.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  332.           ;; tag-char をキーワードよりも優先
  333.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  334.           (when html-highlight-mode
  335.             (message "Merge tag-char range.")
  336.             (setq all-units (buf2html-unit-cover all-units tag-char-units)))
  337.           
  338.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  339.           ;; 最適化
  340.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  341.           (setq all-units (buf2html-unit-concatenate all-units))
  342.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  343.           ;; 行分割 (line-feed)
  344.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  345.           (setq line-feed-p line-number-p)
  346.           (when line-feed-p
  347.             (setq line-feed-units (buf2html-get-units-line-feed))
  348.             (setq all-units (buf2html-unit-cover all-units line-feed-units)))
  349.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  350.           ;; text-attribute
  351.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  352.           (when *buf2html-color-text-attribute*
  353.             (message "Parse text attribute.")
  354.             (setq text-attribute-units (buf2html-get-units-text-attribute)))
  355.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  356.           ;; 出力
  357.           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  358.           (buf2html-print-header line-number-p)
  359.           (buf2html-print-body all-units compiled-color-tag-table
  360.                                text-attribute-units line-number-p)
  361.           (buf2html-print-footer line-number-p)
  362.           (message "Output HTML: done."))
  363.         (set-buffer-modified-p nil *buf2html-buffer-html*))
  364.       (pop-to-buffer *buf2html-buffer-html*)
  365.       (set-buffer-fileio-encoding (buffer-fileio-encoding source-buffer))
  366.       (set-buffer-eol-code (buffer-eol-code source-buffer))
  367.       (html-mode)
  368.       )))
  369. (defun buf2html-get-units-context (&key begin end nomsg)
  370.   "buf2html: context の範囲のリストを作成"
  371.   (let ((point-max (point-max)) rate pre-rate
  372.         all-units context pre-context from to range)
  373.     (save-excursion
  374.       (unless begin
  375.         (setq begin (point-min)))
  376.       (unless end
  377.         (setq end (point-max)))
  378.       (setq from begin)
  379.       (goto-char from)
  380.       (if (= begin 0)
  381.           (setq context nil)
  382.         (setq context (parse-point-syntax (1- (point)))))
  383.       (setq rate -1)
  384.       (while (and (<= (point) end) (not (eobp)))
  385.         (setq pre-context context)
  386.         (setq context (parse-point-syntax (point)))
  387.         (unless nomsg
  388.           (setq pre-rate rate)
  389.           (setq rate (floor (* 100 (/ (pointpoint-max))))
  390.           (if (/= pre-rate rate)
  391.               (message "Parse context: ~2D%" rate)))
  392.         (unless (eq pre-context context)
  393.           (do-events)
  394. ;         (unless nomsg
  395. ;           (message "Parse context: ~2D%" (floor (* 100 (/ (point) point-max)))))
  396.           ;; とりあえず 0.2.2.219 での context を元に適当にやってみる
  397.           (cond
  398.            ; nil から context が切り替わる際は一つ前から
  399.            ((eq pre-context nil)
  400.             (setq to (1- (point))))
  401.            ; nil に切り替わる際はそのまま
  402.            ((eq context nil)
  403.             (setq to (point)))
  404.            ;; :tag については html(+)-mode でしか試していないのであってないかも
  405.            ((eq pre-context :tag)
  406.             (setq to (1- (point))))
  407.            ((and (eq context :tag)
  408.                  (eq pre-context :string))
  409.             (setq to (1+ (point))))
  410.            (t
  411.             (setq to (point))))
  412.           (setq range (cons from to))
  413.           (when (< from to)
  414.             (push (cons (cons pre-context nil) range) all-units)
  415.             (setq from to))
  416. #|
  417.           ; こんな感じのことをすると少しは早くなるかも。でもバグの元かも。
  418.           (cond
  419.            ((eq context :string)
  420.             (skip-syntax-spec-forward "^\"")
  421.             (backward-char)))
  422. |#
  423.           )
  424.         (forward-char))
  425.       (setq range (cons from end))
  426.       (if (< from end)
  427.           (push (cons (cons pre-context nil) range) all-units)))
  428.     (unless nomsg
  429.       (message "Parse context: done."))
  430.     (nreverse all-units)))
  431. (defun buf2html-get-units-line-feed ()
  432.   "buf2html: 改行文字の範囲(位置)のリストを作成"
  433.   (let (line-feed-units point)
  434.     (goto-char (point-min))
  435.     (while (scan-buffer "\n" :tail t)
  436.       (setq point (1- (point)))
  437.       (push (cons (cons :buf2html-line-feed nil) (cons point (1+ point)))
  438.             line-feed-units))
  439.     (nreverse line-feed-units)))
  440. (defun buf2html-get-units-tag-char (ranges)
  441.   "buf2html: タグの開始、終了文字の範囲(位置)のリストを作成"
  442.   (let (tag-char-units from to c)
  443.     (dolist (range ranges)
  444.       (setq from (car range))
  445.       (setq to (cdr range))
  446.       (when (< from to)
  447.         (setq c (char (buffer-substring from (1+ from)) 0))
  448.         (if (or (syntax-open-tag-p c) (syntax-close-tag-p c))
  449.             (push (cons (cons :tag nil) (cons from (1+ from))) tag-char-units))
  450.         (when (< from (1- to))
  451.           (setq c (char (buffer-substring (1- to) to) 0))
  452.           (if (or (syntax-open-tag-p c) (syntax-close-tag-p c))
  453.               (push (cons (cons :tag nil) (cons (1- to) to)) tag-char-units)))))
  454.     (nreverse tag-char-units)))
  455. (defun buf2html-get-units-text-attribute ()
  456.   "buf2html: text-attribute の範囲のリストを作成"
  457.   (let (text-attribute-units btag etag range key value)
  458.     (dolist (text-attributes (list-text-attributes (point-min) (point-max)))
  459.       (setq range (cons (car text-attributes) (cadr text-attributes)))
  460.       (setq text-attributes (cdddr text-attributes))
  461.       (setq btag "")
  462.       (setq etag "")
  463.       (while text-attributes
  464.         (setq key (car text-attributes))
  465.         (setq value (cadr text-attributes))
  466.         (setq text-attributes (cddr text-attributes))
  467.         (case key
  468.           (:foreground
  469.            (setq btag (format nil "~A<SPAN class=\"fg~D\">" btag value))
  470.            (setq etag (format nil "</SPAN>~A" etag)))
  471.           (:background
  472.            (setq btag (format nil "~A<SPAN class=\"bg~D\">" btag value))
  473.            (setq etag (format nil "</SPAN>~A" etag)))
  474.           (:bold
  475.            (when value
  476.              (setq btag (concat btag "<SPAN class=\"bold\">"))
  477.              (setq etag (concat "</SPAN>" etag))))
  478.           (:underline
  479.            (when value
  480.              (setq btag (concat btag "<SPAN class=\"underline\">"))
  481.              (setq etag (concat "</SPAN>" etag))))
  482.           (:strike-out
  483.            (when value
  484.              (setq btag (concat btag "<SPAN class=\"strike-out\">"))
  485.              (setq etag (concat "</SPAN>" etag))))))
  486.       (push (cons (cons :buf2html-text-attribute (cons btag etag)) range)
  487.             text-attribute-units))
  488.     (nreverse text-attribute-units)))
  489. (defun buf2html-get-units-keyword (ranges)
  490.   "buf2html: キーワードの範囲のリストを作成"
  491.   (let ((point-max (point-max)) keyword-units from to regexp compiled-color
  492.         str begin end)
  493.     (dolist (range ranges)
  494.       (setq from (car range))
  495.       (setq to (cdr range))
  496.       (goto-char from)
  497.       (message "Parse keyword: ~2D%" (floor (* 100 (/ from point-max))))
  498.       (setq regexp (compile-regexp "\\(\\s@\\|\\s{\\|\\s\\\\)?\\(\\sw\\|\\s_\\)+"))
  499.       (while (scan-buffer regexp :limit to)
  500.         (setq str (match-string 0))
  501.         (setq begin (match-beginning 0))
  502.         (setq end (match-end 0))
  503.         (when (syntax-symbol-prefix-p (char str 0))
  504.           (setq str (substring 1 str))
  505.           (setq begin (1- begin)))
  506.         (multiple-value-bind (compiled-color init)
  507.             (gethash str ed::keyword-hash-table)
  508.           (when init
  509.             (push (cons (cons :buf2html-keyword compiled-color)
  510.                         (cons begin end)) keyword-units)))
  511.         (goto-char end)))
  512.     (message "Parse keyword: done.")
  513.     (nreverse keyword-units)))
  514. (defun buf2html-get-units-keyword-c-preprocessor (ranges)
  515.   "buf2html: C preprocessor 用キーワードの範囲のリストを作成"
  516.   (let ((point-max (point-max)) keyword-units from to regexp compiled-color
  517.         str begin end)
  518.     (dolist (range ranges)
  519.       (setq from (car range))
  520.       (setq to (cdr range))
  521.       (goto-char from)
  522.       (message "Parse c preprocessor keyword: ~2D%" (floor (* 100 (/ from point-max))))
  523.       (setq regexp (compile-regexp "#[ \t]*\\(\\(\\sw\\|\\s_\\)+\\)"))
  524.       (while (scan-buffer regexp :limit to)
  525.         (setq str (concat "#" (match-string 1)))
  526.         (setq begin (match-beginning 0))
  527.         (setq end (match-end 0))
  528.         (multiple-value-bind (compiled-color init)
  529.             (gethash str ed::keyword-hash-table)
  530.           (when init
  531.             (push (cons (cons :buf2html-keyword compiled-color)
  532.                         (cons begin end)) keyword-units)))
  533.         (goto-char end)))
  534.     (message "Parse c preprocessor keyword: done.")
  535.     (nreverse keyword-units)))
  536. (defun buf2html-get-units-regexp-keyword (ranges regexp-keyword)
  537.   "buf2html: 正規表現キーワードの範囲のリストを作成"
  538.   (let ((regexp (car regexp-keyword))
  539.         (colors (cadr regexp-keyword))
  540.         (compiled-context (caddr regexp-keyword))
  541.         (begin (cadddr regexp-keyword))
  542.         (end (car (cddddr regexp-keyword)))
  543.         regexp-keyword-units from to
  544.         (point-max (point-max))
  545.         whole-range enable-range regexp-keyword-group-units
  546.         group-number group-range compiled-color)
  547.     (dolist (range ranges)
  548.       (setq from (car range))
  549.       (setq to (cdr range))
  550.       (goto-char from)
  551.       (while (scan-buffer regexp :tail t :limit to)
  552.         (setq whole-range (cons (match-beginning 0) (match-end 0)))
  553.         (setq enable-range
  554.               (cons (if (minusp begin) (match-end (* -1 begin)) (match-beginning begin))
  555.                     (if (minusp end) (match-beginning (* -1 end)) (match-end end))))
  556.         (setq whole-range enable-range)
  557.         (setq regexp-keyword-group-units
  558.               (list (cons (cons :buf2html-regexp-keyword-group nil)
  559.                           (copy-list whole-range))))
  560.         (cond
  561.          ((not (consp colors))
  562.           (setq compiled-color colors)
  563.           (setq regexp-keyword-group-units
  564.                 (buf2html-unit-cover
  565.                  regexp-keyword-group-units
  566.                  (list (cons (cons :buf2html-regexp-keyword-group compiled-color)
  567.                              enable-range)))))
  568.          (t
  569.           (dolist (color (sort colors #'< :key #'car)); group 順にソート
  570.             (setq group-number (car color))
  571.             (setq compiled-color (cdr color))
  572.             (setq group-range (cons (match-beginning group-number)
  573.                                     (match-end group-number)))
  574.             
  575.             (when (and compiled-color                 ; compiled-color が nil でない
  576.                        (buf2html-in-range-p group-range enable-range))
  577.               (setq regexp-keyword-group-units
  578.                     (buf2html-unit-cover
  579.                      regexp-keyword-group-units
  580.                      (list (cons (cons :buf2html-regexp-keyword-group compiled-color)
  581.                                  group-range))))))))
  582.         (push (cons (cons :buf2html-regexp-keyword regexp-keyword-group-units) whole-range)
  583.               regexp-keyword-units)))
  584.     (nreverse regexp-keyword-units)))
  585. (defun buf2html-make-regexp-keyword-color-list (regexp-keyword-list)
  586.   "buf2html: regexp-keyword-list から color のリストを作成"
  587.   (let (compiled-color-list)
  588.     (when regexp-keyword-list
  589.       ;; nil は使うので必ずいれておく。
  590.       (pushnew nil compiled-color-list :test 'eql)
  591.       (dolist (compiled-colors (mapcar #'cadr regexp-keyword-list))
  592.         (cond
  593.          ((consp compiled-colors)
  594.           (dolist (compiled-color (mapcar #'cdr compiled-colors))
  595.             (pushnew compiled-color compiled-color-list :test 'eql)))
  596.          ((numberp compiled-colors)
  597.           (pushnew compiled-colors compiled-color-list :test 'eql))
  598.          (t
  599.           (pushnew compiled-colors compiled-color-list :test 'eql)))))
  600.     compiled-color-list))
  601. (defun buf2html-add-compiled-color-tag-hash-table (hash-table compiled-colors)
  602.   "buf2html: compiled-colors に対応する HTML タグを hash-table に登録"
  603.   (when (hash-table-p hash-table)
  604.     (dolist (compiled-color compiled-colors)
  605.       (multiple-value-bind (value init)
  606.           (gethash compiled-color hash-table)
  607.         (unless init
  608.           (setf (gethash compiled-color hash-table)
  609.                 (buf2html-make-compiled-color-tag compiled-color)))))
  610.     hash-table))
  611. ;; 正規表現キーワードのグループ毎の色指定での
  612. ;; color 部分が t の場合の動作がよくわからない。
  613. ;; nil のときは、compiled-color は nil
  614. ;; t   のときは、compiled-color は 0
  615. (defun buf2html-make-compiled-color-tag (compiled-color)
  616.   "buf2html: compiled-color に対応する HTML タグを作成"
  617.   (unless (numberp compiled-color)
  618.     (return-from buf2html-make-compiled-color-tag (cons "" "")))
  619.   (let ((fg-bg-p (= (logand compiled-color #x1) #x1))
  620.         (line-p (= (logand compiled-color #x2) #x2))
  621.         (bold-p (= (logand compiled-color #x200000) #x200000))
  622.         (underline-p (= (logand compiled-color #x800000) #x800000))
  623.         (strike-out-p (= (logand compiled-color #x1000000) #x1000000))
  624.         (color (logand compiled-color (lognot #x1)
  625.                        (lognot #x2) (lognot #x200000) (lognot #x800000) (lognot #x1000000)))
  626.         (btag "") (etag ""))
  627.     (cond
  628.      (fg-bg-p
  629.       (setq btag (format nil "<SPAN class=\"fg~D bg~D\">"
  630.                          (floor (logand color #x1f00) #x200)
  631.                          (floor (logand color #x1f0000) #x20000)))
  632.       (setq etag "</SPAN>"))
  633.      (t
  634.       (cond
  635.        ((= color 0)
  636.         (setq btag "" etag ""))
  637.        ((= color (gethash #\0 ed::*keyword-translate-hash-table*));keyword1
  638.         (setq btag "<SPAN class=\"keyword1\">" etag "</SPAN>"))
  639.        ((= color (gethash #\1 ed::*keyword-translate-hash-table*));keyword2
  640.         (setq btag "<SPAN class=\"keyword2\">" etag "</SPAN>"))
  641.        ((= color (gethash #\2 ed::*keyword-translate-hash-table*));keyword3
  642.         (setq btag "<SPAN class=\"keyword3\">" etag "</SPAN>"))
  643.        ((= color (gethash #\3 ed::*keyword-translate-hash-table*));keyword1 反転
  644.         (setq btag "<SPAN class=\"keyword1inverse\">" etag "</SPAN>"))
  645.        ((= color (gethash #\4 ed::*keyword-translate-hash-table*));keyword2 反転
  646.         (setq btag "<SPAN class=\"keyword2inverse\">" etag "</SPAN>"))
  647.        ((= color (gethash #\5 ed::*keyword-translate-hash-table*));keyword3 反転
  648.         (setq btag "<SPAN class=\"keyword3inverse\">" etag "</SPAN>"))
  649.        ((= color (gethash #\S ed::*keyword-translate-hash-table*));string
  650.         (setq btag "<SPAN class=\"string\">" etag "</SPAN>"))
  651.        ((= color (gethash #\T ed::*keyword-translate-hash-table*));tag
  652.         (setq btag "<SPAN class=\"tag\">" etag "</SPAN>"))
  653.        ((= color (gethash #\C ed::*keyword-translate-hash-table*));comment
  654.         (setq btag "<SPAN class=\"comment\">" etag "</SPAN>")))))
  655.     ;; bold
  656.     (when bold-p
  657.       (setq btag (concat btag "<SPAN class=\"bold\">"))
  658.       (setq etag (concat "</SPAN>" etag)))
  659.     ;; underline
  660.     (when underline-p
  661.       (setq btag (concat btag "<SPAN class=\"underline\">"))
  662.       (setq etag (concat "</SPAN>" etag)))
  663.     ;; strike-out
  664.     (when strike-out-p
  665.       (setq btag (concat btag "<SPAN class=\"strike-out\">"))
  666.       (setq etag (concat "</SPAN>" etag)))
  667.     ;; line (どうすればよい?)
  668.     (when line-p
  669.       t)
  670.     (cons btag etag)))
  671. (defun buf2html-decode-compiled-context (compiled-context)
  672.   "buf2html: compiled-context をデコードし context のリストを作成"
  673.   (let (context-list)
  674.     (if (= (logand compiled-context #x1) #x1)
  675.         (push nil context-list))
  676.     (if (= (logand compiled-context #x2) #x2)
  677.         (push :string context-list))
  678.     (if (= (logand compiled-context #x4) #x4)
  679.         (push :tag context-list))
  680.     (if (= (logand compiled-context #x8) #x8)
  681.         (push :comment context-list))
  682.     context-list))
  683. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  684. ;; range, unit 操作関連
  685. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  686. (defun buf2html-in-range-p (position_or_range range)
  687.   "buf2html: range に position_or_range が含まれるかどうか"
  688.   (if (null range)
  689.       nil
  690.     (cond
  691.      ((numberp position_or_range)
  692.       (if (and (<= (car range) position_or_range)
  693.                (<= position_or_range (cdr range)))
  694.           range
  695.         nil))
  696.      ((consp position_or_range)
  697.       (if (and (<= (car range) (car position_or_range))
  698.                (<= (cdr position_or_range) (cdr range)))
  699.           range
  700.         nil))
  701.      (t nil))))
  702. (defun buf2html-range-concatenate (ranges)
  703.   "buf2html: 隣接した range を連結"
  704.   (let (return-ranges work-range)
  705.     (unless ranges
  706.       (return-from buf2html-range-concatenate nil))
  707.     (setq work-range (car ranges))
  708.     (dolist (range (cdr ranges))
  709.       (cond
  710.        ((= (cdr work-range) (car range))
  711.         (setq work-range (cons (car work-range) (cdr range))))
  712.        (t
  713.         (push work-range return-ranges)
  714.         (setq work-range range))))
  715.     (push work-range return-ranges)
  716.     (nreverse return-ranges)))
  717. (defun buf2html-unit-concatenate (units)
  718.   "buf2html: 隣接した同じ type の unit を連結"
  719.   (let (return-units work-unit)
  720.     (unless units
  721.       (return-from buf2html-unit-concatenate nil))
  722.     (setq work-unit (car units))
  723.     (dolist (unit (cdr units))
  724.       (cond
  725.        ((and (equal (car work-unit) (car unit))
  726.              (= (cddr work-unit) (cadr unit)))
  727.         (setq work-unit (cons (car work-unit)
  728.                               (cons (cadr work-unit) (cddr unit)))))
  729.        (t
  730.         (push work-unit return-units)
  731.         (setq work-unit unit))))
  732.     (push work-unit return-units)
  733.     (nreverse return-units)))
  734. (defun buf2html-unit-cover (base-units priority-units)
  735.   "buf2html: base-units に priority-units をかぶせる"
  736.   (let (return-units base-type-range priority-type-range base-unit priority-unit start)
  737.     (setq start 0)
  738.     (setq base-unit (car base-units))
  739.     (setq base-units (cdr base-units))
  740.     (setq priority-unit (car priority-units))
  741.     (setq priority-units (cdr priority-units))
  742.     (while (and base-unit priority-unit)
  743.       (cond
  744.        ;; 重ならず base が前
  745.        ((<= (cddr base-unit) (cadr priority-unit))
  746.         (if (< (cadr base-unit) (cddr base-unit))
  747.             (push base-unit return-units))
  748.         (setq start (cddr base-unit)))
  749.        ;; 重ならず priority が前
  750.        ((<= (cddr priority-unit) (cadr base-unit))
  751.         (if (< (cadr priority-unit) (cddr priority-unit))
  752.             (push priority-unit return-units))
  753.         (setq start (cddr priority-unit))
  754.         (setq priority-unit nil))
  755.        ;; priority が base を含む
  756.        ((and (<= (cadr priority-unit) (cadr base-unit))
  757.              (<= (cddr base-unit) (cddr priority-unit)))
  758.         (if (< (cadr priority-unit) (cddr priority-unit))
  759.             (push priority-unit return-units))
  760.         (setq start (cddr priority-unit))
  761.         (setq priority-unit nil))
  762.        ;; base が priority を含む
  763.        ((and (<= (cadr base-unit) (cadr priority-unit))
  764.              (<= (cddr priority-unit) (cddr base-unit)))
  765.         (if (< (cadr base-unit) (cadr priority-unit))
  766.             (push (cons (car base-unit)
  767.                         (cons (cadr base-unit) (cadr priority-unit))) return-units))
  768.         (if (< (cadr priority-unit) (cddr priority-unit))
  769.             (push priority-unit return-units))
  770.         (setq start (cddr priority-unit))
  771.         (setq priority-unit nil))
  772.        ;; 重なり priority が前
  773.        ((<= (cadr priority-unit) (cadr base-unit))
  774.         (if (< (cadr priority-unit) (cddr priority-unit))
  775.             (push priority-unit return-units))
  776.         (setq start (cddr priority-unit))
  777.         (setq priority-unit nil))
  778.        ;; 重なり priority が後
  779.        (t
  780.         (if (< (cadr base-unit) (cadr priority-unit))
  781.             (push (cons (car base-unit)
  782.                         (cons (cadr base-unit) (cadr priority-unit))) return-units))
  783.         (if (< (cadr priority-unit) (cddr priority-unit))
  784.             (push priority-unit return-units))
  785.         (setq start (cddr priority-unit))
  786.         (setq priority-unit nil)))
  787.       (unless priority-unit
  788.         (setq priority-unit (car priority-units))
  789.         (setq priority-units (cdr priority-units)))
  790.       (while (and base-unit (<= (cddr base-unit) start))
  791.         (setq base-unit (car base-units))
  792.         (setq base-units (cdr base-units)))
  793.       (if (and base-unit (< (cadr base-unit) start))
  794.           (setq base-unit (cons (car base-unit) (cons start (cddr base-unit)))))
  795.       )
  796.     (cond
  797.      (base-unit
  798.       (while base-unit
  799.         (if (< (cadr base-unit) (cddr base-unit))
  800.             (push base-unit return-units))
  801.         (setq base-unit (car base-units))
  802.         (setq base-units (cdr base-units))))
  803.      (priority-unit
  804.       (while priority-unit
  805.         (if (< (cadr priority-unit) (cddr priority-unit))
  806.             (push priority-unit return-units))
  807.         (setq priority-unit (car priority-units))
  808.         (setq priority-units (cdr priority-units)))))
  809.     (nreverse return-units)))
  810. (defun buf2html-get-ranges-if-context (units contexts)
  811.   "buf2html: contexts に含まれる context である unit の range のリストを返す"
  812.   (mapcar #'cdr
  813.           (remove contexts units
  814.                   :test #'(lambda (contexts context)
  815.                             (not (position context contexts)))
  816.                   :key #'caar)))
  817. (defun buf2html-get-ranges-if-not-context (units contexts)
  818.   "buf2html: contexts に含まれない context である unit の range のリストを返す"
  819.   (mapcar #'cdr
  820.           (remove contexts units
  821.                   :test #'(lambda (contexts context)
  822.                             (position context contexts))
  823.                   :key #'caar)))
  824. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  825. ;; 出力関連
  826. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  827. (defun buf2html-protect-string (body &optional convert-half-space-p)
  828.   "buf2html: 文字参照を変換した文字列を返す"
  829.   (dolist (cell *buf2html-string-encode-alist*)
  830.     (setq body (substitute-string body (car cell) (cdr cell))))
  831.   (if convert-half-space-p
  832.       (setq body (substitute-string body " " "&nbsp;")))
  833.   body)
  834. (defun buf2html-print-header (&optional line-number-p)
  835.   "buf2html: HTML の開始部分を出力"
  836.   (let (lang title charset encoding-display-name)
  837.     (if (setq title (get-buffer-file-name))
  838.         (setq title (concat (pathname-name title)
  839.                             (if (pathname-type title)
  840.                                 (concat "." (pathname-type title)) "")))
  841.       (setq title (buffer-name (selected-buffer))))
  842.     (setq encoding-display-name (char-encoding-display-name (buffer-fileio-encoding)))
  843.     (cond
  844.      ((string-match "日本語" encoding-display-name)
  845.       (setq lang "ja"))
  846.      ((string-match "中国語" encoding-display-name)
  847.       nil)
  848.      ((string-match "韓国語" encoding-display-name)
  849.       nil)
  850.      (t
  851.       nil))
  852.     (cond
  853.      ((string-match "Shift_JIS" encoding-display-name)
  854.       (setq charset "Shift_JIS"))
  855.      ((string-match "EUC-JP" encoding-display-name)
  856.       (setq charset "EUC-JP"))
  857.      ((string-match "ISO-2022-JP" encoding-display-name)
  858.       (setq charset "ISO-2022-JP"))
  859.      ((string-match "UTF-8" encoding-display-name)
  860.       (setq charset "UTF-8"))
  861.      (t
  862.       nil))
  863.      
  864.     (format t "~A~%" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">")
  865.     (if (stringp *buf2html-auto-mode-parameter-string* )
  866.         (format t "~A~A~A~%" "<!-- -*- "
  867.                 *buf2html-auto-mode-parameter-string* " -*- -->"))
  868.     (if (and (stringp *buf2html-date-format*)
  869.              (stringp *buf2html-time-stamp-start*)
  870.              (stringp *buf2html-time-stamp-end*))
  871.         (format t "~A~A~A~A~A~%"
  872.                 "<!-- " *buf2html-time-stamp-start*
  873.                 (format-date-string *buf2html-date-format*)
  874.                 *buf2html-time-stamp-end* " -->"))
  875.     (format t "~A~A~A~%" "<!-- Created by buf2html-" *buf2html-version* " -->")
  876.     (if lang
  877.         (format t "~A~A~A~%" "<HTML lang=\"" lang "\">")
  878.       (format t "~A~%" "<HTML>"))
  879.     (format t "~A~%" "  <HEAD>")
  880.     (format t "~A~A~A~%" "    <META name=\"GENERATOR\" content=\"buf2html-"
  881.             *buf2html-version* "\">")
  882.     (if charset
  883.         (format t "~A~A~A~%" "    <META http-equiv=\"Content-Type\" content=\"text/html; charset=" charset "\">"))
  884.     (format t "~A~%" "    <LINK href=\"xyzzy.css\" rel=\"stylesheet\" type=\"text/css\">")
  885.     (format t "~A~A~A~%" "    <TITLE>" (buf2html-protect-string title) "</TITLE>")
  886.     (format t "~A~%" "  </HEAD>")
  887.     (format t "~A~%" "  <BODY class=\"bgcolor\">")
  888.     (if line-number-p
  889.         (if *buf2html-number-link*
  890.             (format t "~A" "<OL>\n<LI><CODE><A name=\"1\">")
  891.           (format t "~A" "<OL>\n<LI><CODE>"))
  892.       (format t "~A~%" "    <PRE>"))
  893.     ))
  894. (defun buf2html-print-footer (&optional line-number-p)
  895.   "buf2html: HTML の終了部分を出力"
  896.   (if line-number-p
  897.       (format t "~A~%" "</OL>")
  898.     (format t "~A~%" "</PRE>"))
  899.   (format t "~A~%" "  </BODY>")
  900.   (format t "~A~%" "</HTML>"))
  901. (defun buf2html-print-body (all-units compiled-color-tag-table text-attribute-units
  902.                             &optional line-number-p)
  903.   "buf2html: HTML のメイン部分を出力"
  904.   (let ((point-max (point-max)) btag etag
  905.         type range tags (line-number 1)
  906.         regexp-keyword-group-units regexp-keyword-group-range)
  907.     (flet ((print-range (range btag etag text-attribute-units)
  908.              (let (text-attribute-unit
  909.                    text-attribute-tags
  910.                    text-attribute-range
  911.                    (convert-half-space-p (or *buf2html-convert-half-space* line-number-p)))
  912. ;              ;; 念のため前の部分を除外
  913. ;              (while (and text-attribute-units
  914. ;                          (<= (cddar text-attribute-units) (car range)))
  915. ;                (setq text-attribute-units (cdr text-attribute-units)))
  916.                ;; text-attribute-units の先頭を取得(先頭には残したまま)
  917.                (when text-attribute-units
  918.                  (setq text-attribute-unit (car text-attribute-units))
  919.                  (setq text-attribute-tags (cdar text-attribute-unit))
  920.                  (setq text-attribute-range (cdr text-attribute-unit))
  921.                  (if (< (car text-attribute-range) (car range))
  922.                      (setq text-attribute-range
  923.                            (cons (car range) (cdr text-attribute-range)))))
  924.                
  925.                (while (< (car range) (cdr range))
  926.                  (cond
  927.                   ;; text-attribute-range と関係がない場合
  928.                   ((or (null text-attribute-range)
  929.                        (<= (cdr range) (car text-attribute-range)))
  930.                    (format t "~A~A~A"
  931.                            btag
  932.                            (buf2html-protect-string
  933.                             (buffer-substring (car range) (cdr range))
  934.                             convert-half-space-p)
  935.                            etag)
  936.                    (return))
  937.                   ;; text-attribute-range が range の終端以降まである場合
  938.                   ((< (cdr range) (cdr text-attribute-range))
  939.                    (format t "~A" btag)
  940.                    (if (< (car range) (car text-attribute-range))
  941.                        (format t "~A"
  942.                                (buf2html-protect-string
  943.                                 (buffer-substring (car range) (car text-attribute-range))
  944.                                 convert-half-space-p)))
  945.                    (format t "~A~A~A~A"
  946.                            (car text-attribute-tags)
  947.                            (buf2html-protect-string
  948.                             (buffer-substring (car text-attribute-range) (cdr range))
  949.                             convert-half-space-p)
  950.                            (cdr text-attribute-tags) etag)
  951.                    (return))
  952.                   ;; text-attribute-range が range に含まれる場合
  953.                   (t
  954.                    (format t "~A" btag)
  955.                    (if (< (car range) (car text-attribute-range))
  956.                        (format t "~A"
  957.                                (buf2html-protect-string
  958.                                 (buffer-substring (car range) (car text-attribute-range))
  959.                                 convert-half-space-p)))
  960.                    (format t "~A~A~A~A"
  961.                            (car text-attribute-tags)
  962.                            (buf2html-protect-string
  963.                             (buffer-substring (car text-attribute-range)
  964.                                               (cdr text-attribute-range))
  965.                             convert-half-space-p)
  966.                            (cdr text-attribute-tags)
  967.                            etag)
  968.                    (setq range (cons (cdr text-attribute-range) (cdr range)))
  969.                    ;; 使用済みの text-attribute-unit を先頭から除外
  970.                    (setq text-attribute-units (cdr text-attribute-units))
  971.                    (if text-attribute-units
  972.                        (progn
  973.                          (setq text-attribute-unit (car text-attribute-units))
  974.                          (setq text-attribute-tags (cdar text-attribute-unit))
  975.                          (setq text-attribute-range (cdr text-attribute-unit)))
  976.                      (progn
  977.                        (setq text-attribute-unit nil)
  978.                        (setq text-attribute-tags nil)
  979.                        (setq text-attribute-range nil)))))))
  980.              text-attribute-units))
  981.       
  982.       (dolist (all-unit all-units)
  983.         (setq type (car all-unit))
  984.         (setq range (cdr all-unit))
  985.         (message "Output HTML: ~2D%" (floor (* 100 (/ (car range) point-max))))
  986.         (case (car type)
  987.           ((nil)
  988.            (setq text-attribute-units
  989.                  (print-range range "" "" text-attribute-units)))
  990.           (:string
  991.            (setq text-attribute-units
  992.                  (print-range range "<SPAN class=\"string\">" "</SPAN>"
  993.                               text-attribute-units)))
  994.           (:comment
  995.            (setq text-attribute-units
  996.                  (print-range range "<SPAN class=\"comment\">" "</SPAN>"
  997.                               text-attribute-units)))
  998.           (:tag
  999.            (setq text-attribute-units
  1000.                  (print-range range "<SPAN class=\"tag\">" "</SPAN>"
  1001.                               text-attribute-units)))
  1002.           (:buf2html-keyword
  1003.            (setq tags (gethash (cdr type) compiled-color-tag-table))
  1004.            (setq text-attribute-units
  1005.                  (print-range range (car tags) (cdr tags) text-attribute-units)))
  1006.           (:buf2html-regexp-keyword
  1007.            (setq regexp-keyword-group-units (cdr type))
  1008.            (dolist (regexp-keyword-group-unit regexp-keyword-group-units)
  1009.              (setq tags (gethash (cdar regexp-keyword-group-unit)
  1010.                                  compiled-color-tag-table))
  1011.              (setq regexp-keyword-group-range (cdr regexp-keyword-group-unit))
  1012.              (if (< (car regexp-keyword-group-range) (car range))
  1013.                  (setq regexp-keyword-group-range
  1014.                        (cons (car range) (cdr regexp-keyword-group-range))))
  1015.              (if (< (cdr range) (cdr regexp-keyword-group-range))
  1016.                  (setq regexp-keyword-group-range
  1017.                        (cons (car regexp-keyword-group-range) (cdr range))))
  1018.              (if (< (car regexp-keyword-group-range) (cdr regexp-keyword-group-range))
  1019.                  (setq text-attribute-units
  1020.                        (print-range regexp-keyword-group-range (car tags) (cdr tags)
  1021.                                     text-attribute-units)))))
  1022.           (:buf2html-line-feed
  1023.            (cond
  1024.             ((not line-number-p)
  1025.              (setq text-attribute-units
  1026.                    (print-range range "" "" text-attribute-units)))
  1027.             ((= (cdr range) point-max)
  1028.              (if *buf2html-number-link*
  1029.                  (setq text-attribute-units
  1030.                        (print-range range "</A></CODE></LI>" ""
  1031.                                     text-attribute-units))
  1032.                (setq text-attribute-units
  1033.                      (print-range range "</CODE></LI>" ""
  1034.                                   text-attribute-units))))
  1035.             (t
  1036.              (incf line-number)
  1037.              (if *buf2html-number-link*
  1038.                  (setq text-attribute-units
  1039.                        (print-range range "</A></CODE></LI>"
  1040.                                     (format nil "<LI><CODE><A name=\"~D\">"
  1041.                                             line-number)
  1042.                                     text-attribute-units))
  1043.                (setq text-attribute-units
  1044.                      (print-range range "</CODE></LI>" "<LI><CODE>"
  1045.                                   text-attribute-units))))))
  1046.           (t
  1047.            (setq text-attribute-units
  1048.                  (print-range range "" "" text-attribute-units))))))))
  1049. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1050. ;; syntax-table 関連
  1051. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1052. ; 使用していない
  1053. (defun buf2html-syntax-table-check ()
  1054.   "buf2html: syntax-table を調べる"
  1055.   (let ((percent -1) pre-percent c
  1056.         open-tag-characters close-tag-characters
  1057.         start-comment-characters end-comment-characters
  1058.         start-multi-comment-1-characters start-multi-comment-2-characters
  1059.         end-multi-comment-1-characters end-multi-comment-2-characters)
  1060.     (dotimes (i *buf2html-char-code-limit*)
  1061.       (setq pre-percent percent)
  1062.       (setq percent (floor (* 100 (/ i *buf2html-char-code-limit*))))
  1063.       (if (/= pre-percent percent) (message "Check syntax table: ~2D%" percent))
  1064.       (setq c (code-char i))
  1065.       (if (syntax-open-tag-p c) (push c open-tag-characters))
  1066.       (if (syntax-close-tag-p c) (push c close-tag-characters))
  1067.       (if (syntax-start-comment-p c) (push c start-comment-characters))
  1068.       (if (syntax-end-comment-p c) (push c end-comment-characters))
  1069.       (if (syntax-start-multi-comment-1-p c) (push c start-multi-comment-1-characters))
  1070.       (if (syntax-start-multi-comment-2-p c) (push c start-multi-comment-2-characters))
  1071.       (if (syntax-end-multi-comment-1-p c) (push c end-multi-comment-1-characters))
  1072.       (if (syntax-end-multi-comment-2-p c) (push c end-multi-comment-2-characters))
  1073.       )
  1074.     (values open-tag-characters close-tag-characters
  1075.             start-comment-characters end-comment-characters
  1076.             start-multi-comment-1-characters start-multi-comment-2-characters
  1077.             end-multi-comment-1-characters end-multi-comment-2-characters)
  1078.     ))
  1079. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1080. ;; ini2css-file
  1081. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1082. (defun ini2css-file (ini-path)
  1083.   "buf2html: xyzzy の設定ファイルからスタイルシートを生成"
  1084.   (interactive "fFind ini file: "
  1085.     :title0 "Find ini file"
  1086.     :default0 (let ((path (concat (si:system-root) "usr/" (user-name"/"
  1087.                                   (case (os-platform)
  1088.                                     ('windows-95 "w95")
  1089.                                     ('windows-98 "w98")
  1090.                                     ('windows-wme "wme")
  1091.                                     ('windows-nt "wnt")
  1092.                                     ('windows-w2k "w2k"))
  1093.                                   "/xyzzy.ini")))
  1094.                 (if (file-exist-p path) path "")))
  1095.   (if (file-exist-p ini-path)
  1096.       (progn
  1097.         (save-excursion
  1098.           (buf2html-set-buffer *buf2html-buffer-tmp*)
  1099.           (with-output-to-buffer (*buf2html-buffer-tmp*)
  1100.             (with-open-file (fp ini-path)
  1101.               (let ((line nil))
  1102.                 (while (setq line (read-line fp nil nil nil))
  1103.                   (format t "~A~%" line)))))
  1104.           (set-buffer *buf2html-buffer-tmp*)
  1105.           (goto-char (point-min))
  1106.           (ini2css-buffer)
  1107.           (delete-buffer (find-buffer *buf2html-buffer-tmp*)))
  1108.         (pop-to-buffer *buf2html-buffer-css*))
  1109.     (message "ファイルが存在しません")))
  1110. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1111. ;; ini2css-buffer
  1112. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1113. (defun ini2css-buffer ()
  1114.   "buf2html: 現在のバッファからスタイルシートを生成"
  1115.   (interactive)
  1116.   (let (start-point end-point colors-alist)
  1117.     (save-excursion
  1118.       (goto-char (point-min))
  1119.       (when (scan-buffer "^\\[Colors\\]" :regexp t :case-fold t)
  1120.         (setq start-point (point))
  1121.         (setq end-point
  1122.               (if (scan-buffer "^\\[.+\\]" :regexp t :no-dup t) (point) (point-max)))
  1123.         (save-restriction
  1124.           (narrow-to-region start-point end-point)
  1125.           (goto-char (point-min))
  1126.           (while (scan-buffer "^\\([^=]+\\)=#\\([0-9a-f]+\\)"
  1127.                               :regexp t :case-fold t :no-dup t)
  1128.             (push (cons (match-string 1)
  1129.                         (buf2html-bgr2rgb (parse-integer (match-string 2) :radix 16)))
  1130.                   colors-alist)))))
  1131.     (buf2html-set-buffer *buf2html-buffer-css*)
  1132.     (with-output-to-buffer (*buf2html-buffer-css*)
  1133.       (flet ((format-selector (colors-alist selector fg-item &optional bg-item single-line)
  1134.                (let (fgcolor bgcolor)
  1135.                  (if (stringp fg-item)
  1136.                      (setq fgcolor (find fg-item colors-alist :key 'car :test 'string-equal)))
  1137.                  (if (stringp bg-item)
  1138.                      (setq bgcolor (find bg-item colors-alist :key 'car :test 'string-equal)))
  1139.                  (when (or fgcolor bgcolor)
  1140.                    (format t "~A {" selector)
  1141.                    (unless single-line (format t "~%"))
  1142.                    (when fgcolor
  1143.                      (format t "~A" (if single-line " " "\t"))
  1144.                      (format t "~A: #~6,'0x;" "color" (cdr fgcolor))
  1145.                      (unless single-line (format t "~%")))
  1146.                    (when bgcolor
  1147.                      (format t "~A" (if single-line " " "\t"))
  1148.                      (format t "~A: #~6,'0x;" "background-color" (cdr bgcolor))
  1149.                      (unless single-line (format t "~%")))
  1150.                    (if single-line (format t " "))
  1151.                    (cond
  1152.                     ((and fgcolor bgcolor)
  1153.                      (format t "} /* ~A, ~A */~%" fg-item bg-item))
  1154.                     (fgcolor
  1155.                      (format t "} /* ~A */~%" fg-item))
  1156.                     (bgcolor
  1157.                      (format t "} /* ~A */~%" bg-item))))
  1158.                  )))
  1159.         (format-selector colors-alist ".bgcolor" "textColor" "backColor")
  1160.         (format-selector colors-alist "SPAN.keyword1" "kwdColor1")
  1161.         (format-selector colors-alist "SPAN.keyword2" "kwdColor2")
  1162.         (format-selector colors-alist "SPAN.keyword3" "kwdColor3")
  1163.         (format-selector colors-alist "SPAN.keyword1inverse" "backColor" "kwdColor1")
  1164.         (format-selector colors-alist "SPAN.keyword2inverse" "backColor" "kwdColor2")
  1165.         (format-selector colors-alist "SPAN.keyword3inverse" "backColor" "kwdColor3")
  1166.         (format-selector colors-alist "SPAN.string" "stringColor")
  1167.         (format-selector colors-alist "SPAN.comment" "commentColor")
  1168.         (format-selector colors-alist "SPAN.tag" "tagColor")
  1169.         (format-selector colors-alist ".fg0" "textColor")
  1170.         (format-selector colors-alist ".bg0" nil "backColor")
  1171.         (do ((i 1 (1+ i)))
  1172.             ((> i 15))
  1173.           (format-selector colors-alist (format nil ".fg~D" i) (format nil "fg~D" i) nil t)
  1174.           (format-selector colors-alist (format nil ".bg~D" i) nil (format nil "bg~D" i) t))
  1175.         )
  1176.       ;; bold
  1177.       (format t "~A { ~A; }~%" ".bold" "font-weight: bold")
  1178.       ;; underline
  1179.       (format t "~A { ~A; }~%" ".underline" "text-decoration: underline")
  1180.       ;; strike-out
  1181.       (format t "~A { ~A; }~%" ".strike-out" "text-decoration: line-through")
  1182.       )
  1183.     (pop-to-buffer *buf2html-buffer-css*)
  1184.     (if (fboundp 'css-mode)
  1185.         (css-mode))
  1186.     (set-buffer-modified-p nil)
  1187.     ))
  1188. ;; #ffffff 以上の値はどんなフォーマット?
  1189. (defun buf2html-bgr2rgb (bgr)
  1190.   "buf2html: bgr の数値を rgb の数値に変換"
  1191.   (let ((b (floor (mod bgr #x1000000) #x10000))
  1192.         (g (floor (mod bgr #x10000) #x100))
  1193.         (r (mod bgr #x100)))
  1194.     (+ (* r #x10000) (* g #x100) b)))
  1195. (defun buf2html-set-buffer (buffer-name)
  1196.   "buf2html: 出力用バッファの準備"
  1197.   (save-excursion
  1198.     (get-buffer-create buffer-name)
  1199.     (erase-buffer buffer-name)
  1200.     (set-buffer buffer-name)
  1201.     (make-local-variable 'need-not-save)
  1202.     (setq need-not-save t)
  1203.     (make-local-variable 'need-not-save)
  1204.     (setq need-not-save t)))