":"; exec emacs -script $0 "$@" # -*-emacs-lisp-*-
;;; make-html
;; Copyright (C) 2010 Thien-Thi Nguyen
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see .
;;; Commentary:
;; Usage: ./make-html --git-urls [OUTPUT-FILESTEM]
;;
;; OUTPUT-FILESTEM defaults to MODULES-NEW if omitted.
;; Write two files: OUTPUT-FILESTEM.html, OUTPUT-FILESTEM-FANOUT.html.
;;; Code:
(let ((tool "gnulib-tool"))
(unless (and (file-exists-p tool)
(= #o500 (logand #o500 (file-modes tool))))
(error "ERROR: make-html must be %s\n\t(where executable %s resides)"
"invoked in the gnulib top-level directory"
tool)))
(require 'cl)
(defvar VENERABLE (with-current-buffer (get-buffer-create "VENERABLE")
(insert-file-contents "MODULES.html.sh")
;; We ‘read’ a lot, so chuck the bad hash.
(while (re-search-forward "#.*$" nil t)
(delete-region (match-beginning 0) (match-end 0)))
(goto-char (point-min))
(current-buffer)))
(defun venerable (method name)
(with-current-buffer VENERABLE
(let ((buf (current-buffer))
acc)
(case method
((symbols)
(re-search-forward (concat "^" name "=.*"))
(while (not (= ?' (char-after (1+ (point)))))
(push (read buf) acc)))
((funcalls)
(search-forward (concat "func_section_wrap " name))
(search-forward "func_begin_table")
(while (eq 'func_module (read buf))
(push (read buf) acc))))
(nreverse acc))))
(defvar SEEN-MODULES nil)
(defvar SEEN-FILES nil)
(setq debug-on-error t
vc-handled-backends nil
case-fold-search nil)
(defconst POSIX2001-URL "http://www.opengroup.org/susv3")
(defconst POSIX2008-URL "http://www.opengroup.org/onlinepubs/9699919799")
(defconst REPO-URL-PREFIX
(cond ((equal "--git-urls" (car command-line-args-left))
(pop command-line-args-left)
"http://git.sv.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=")
(t "")))
(defconst REPO-URL-SUFFIX "")
(defconst OUTPUT-FILESTEM (or (car command-line-args-left)
"MODULES-NEW"))
(defconst POSIX-HEADERS (venerable 'symbols "POSIX_HEADERS"))
(defconst POSIX2001-HEADERS (venerable 'symbols "posix2001_headers"))
(defconst POSIX-FUNCTIONS (venerable 'symbols "posix_functions"))
(defconst POSIX2001-FUNCTIONS (venerable 'symbols "posix2001_functions"))
(defvar FUNCTIONS (make-hash-table :test 'eq))
(defun jam-functions! (ls url-prefix-1 url-prefix-2)
(let ((anchor-lhs (concat "")
(indent))
(defun end (tag)
(unindent)
(echo "" tag ">"))
(defun wrap (tag s)
(format "<%s>%s%s>"
tag s (if (string-match " " tag)
(substring tag 0 (match-beginning 0))
tag)))
(defvar TAGS (make-hash-table :test 'equal))
(defvar IN-TOC nil)
(defun section (h tag title)
(echo (wrap h (wrap (format "A %s=%S" (if IN-TOC
'HREF
'NAME)
(if IN-TOC
(concat "#" tag)
tag))
title))))
(defun begin-table ()
(begin "TABLE")
(cond (IN-TOC
;; (begin "TR")
;; (echo "")
;; (echo "")
;; (end "TR")
)
(t
(begin "TR" "VALIGN=\"TOP\"")
(echo "
modules/")
(echo " | lib/")
(echo " | lib/")
(echo " | m4/")
(echo " | ")
(end "TR")
(begin "TR")
(echo " | Module")
(echo " | Header")
(echo " | Implementation")
(echo " | Autoconf macro")
(echo " | Depends on")
(end "TR"))))
(defconst AMBIGUOUS (concat " what??"
" If you mean a function, please say so."))
(defun extract-insert (part module)
(erase-buffer)
(insert (or (module-part module part) ""))
(goto-char (point-min))
(flush-lines "^$"))
(defvar WORK-BUFFER (let ((buf (get-buffer-create "WORK")))
(with-current-buffer buf
(buffer-disable-undo))
buf))
(defmacro working (&rest body)
`(with-current-buffer WORK-BUFFER
(erase-buffer)
,@body))
(defun gsr (rx to literal)
(goto-char (point-min))
(while (re-search-forward rx nil t)
(replace-match to 'fixedcase literal)))
(defun gsr-angle-brackets ()
(gsr "<" "<" t)
(gsr ">" ">" t)
(goto-char (point-min)))
(defconst TD " | ")
(defun td/width (percent)
(format " | " percent))
(defconst TD-20 TD)
(defconst TD-80 TD)
(defun repo-file (cut filename)
(format "%s"
REPO-URL-PREFIX filename
REPO-URL-SUFFIX (substring filename cut)))
(defun BR-sep (lines &optional func)
(mapconcat (or func 'identity) lines " "))
(defun module (module)
(message "%smodule: %s" (if IN-TOC "toc-" "") module)
(begin "TR" "VALIGN=\"TOP\"")
(cond
(IN-TOC
(echo TD-20
(format "%s" module module)
TD-80
(working
;; Rendering the description:
;; - Change the symbol() syntax as suitable for documentation,
;; removing the parentheses (as per GCS, section "GNU Manuals").
;; - Flag the remaining symbol() constructs as errors.
;; - Change 'xxx' to xxx .
(extract-insert 'Description module)
(gsr-angle-brackets)
(while (not (eobp))
(while (re-search-forward "\\([a-zA-Z0-9_]+\\)()"
(line-end-position) t)
(let* ((beg (match-beginning 1))
(end (- (match-end 1) 2))
(name (match-string 1))
(type (when (looking-at " \\(function\\|macro\\)")
(setq end (match-end 0))
(match-string 1)))
(anchor-lhs (gethash (intern name) FUNCTIONS)))
(delete-char -2)
(when anchor-lhs
(insert ""))
(unless type
(insert AMBIGUOUS)
(setq end (point)))
(when anchor-lhs
(goto-char beg)
(insert anchor-lhs name ".html\">"))
(goto-char end)))
(beginning-of-line)
(while (re-search-forward "'\\([-a-zA-Z0-9_ ]*\\)'"
(line-end-position) t)
(replace-match "\\1 " t))
(forward-line 1))
(buffer-string))))
(t
;; module name
(echo TD
(format "%s"
module
REPO-URL-PREFIX module REPO-URL-SUFFIX
module))
;; header
(let ((files (module-part module 'Files))
redundant includes inc anchor-lhs beg end)
(echo TD
(working
(extract-insert 'Include module)
(gsr-angle-brackets)
(while (not (eobp))
(when (looking-at "# *i\\(nclude\\)* ")
(delete-region (point) (match-end 0))
(cond ((looking-at "\"\\(.+\\)\"")
(push (match-string 1) redundant)
(replace-match
(concat "\"\\1\"")
t))
((and (looking-at "<\\(.+\\).h>")
(setq inc (match-string 1)
anchor-lhs (gethash (intern inc) HEADERS)))
(setq beg (match-beginning 1)
end (+ 2 (match-end 1))) ; +2 for ".h"
(setq inc (concat inc ".h"))
(goto-char end)
(insert ".html\">" inc "")
(goto-char end)
(while (search-backward "/" beg 1)
(replace-match "_" t t))
(insert anchor-lhs))))
(end-of-line)
(unless (eobp)
(insert " "))
(forward-line 1))
(if (zerop (buffer-size))
"---"
(buffer-string))))
;; implementation
(echo TD
(let ((impl (mapcar (lambda (filename)
(when (string-match "^lib/" filename)
(unless (member (substring filename 4)
redundant)
filename)))
files)))
(if (setq impl (delq nil impl))
(BR-sep impl (lambda (filename)
(repo-file 4 filename)))
"---")))
;; autoconf macro
(echo TD
(let ((m4 (mapcar (lambda (filename)
(when (string-match "^m4/" filename)
filename))
files))
(ac (module-part module 'AC)))
(if (append (setq m4 (delq nil m4))
(setq ac (when ac (split-string ac "\n"))))
(BR-sep (append (mapcar (lambda (filename)
(repo-file 3 filename))
m4)
ac))
"---")))
;; upstream
(echo TD
(let ((up (module-part module 'Depends-on)))
(if up
(BR-sep up (lambda (module)
(format "%s"
module module)))
"---")))
(push module SEEN-MODULES)
(setq SEEN-FILES (nconc SEEN-FILES files)))))
(end "TR"))
(defun end-table ()
(end "TABLE"))
(defun sec+tab (h tag title)
(section h tag title)
(begin-table)
(mapc 'module (or (gethash tag TAGS)
(puthash tag (venerable 'funcalls tag) TAGS)))
(end-table))
(defun all-modules (segment)
(setq IN-TOC (eq 'toc segment))
(sec+tab "H2" "ansic_sup_obsolete"
"Support for obsolete systems lacking ANSI C 89")
(echo "These modules are not listed among dependencies below, for simplicity.")
(echo "If your package requires portability to old, obsolete systems,
you need to list these modules explicitly among the modules
to import through gnulib-tool.")
(sec+tab "H2" "ansic_sup"
"Support for systems lacking ANSI C 89")
(section "H2" "ansic_enh"
"Enhancements for ANSI C 89 functions")
(sec+tab "H3" "ansic_enh_assert_diagnostics"
"Diagnostics <assert.h>")
(sec+tab "H3" "ansic_enh_math"
"Mathematics <math.h>")
(sec+tab "H3" "ansic_enh_stdio"
"Input/output <stdio.h>")
(sec+tab "H3" "ansic_enh_stdlib_memory"
"Memory management functions <stdlib.h>")
(sec+tab "H3" "ansic_enh_stdlib_sorting"
"Sorting functions <stdlib.h>")
(sec+tab "H3" "ansic_enh_time_datetime"
"Date and time <time.h>")
(section "H2" "ansic_ext"
"Extra functions based on ANSI C 89")
(sec+tab "H3" "ansic_ext_stdlib_memory"
"Memory management functions <stdlib.h>")
(sec+tab "H3" "ansic_ext_stdlib_arith"
"Integer arithmetic functions <stdlib.h>")
(sec+tab "H3" "ansic_ext_stdlib_env"
"Environment variables <stdlib.h>")
(sec+tab "H3" "ansic_ext_ctype"
"Character handling <ctype.h>")
(sec+tab "H3" "ansic_ext_string"
"String handling <string.h>")
(sec+tab "H3" "ansic_ext_math"
"Mathematics <math.h>")
(sec+tab "H3" "ansic_ext_stdlib_conv"
"Numeric conversion functions <stdlib.h>")
(sec+tab "H3" "ansic_ext_time_datetime"
"Date and time <time.h>")
(sec+tab "H3" "ansic_ext_stdio"
"Input/Output <stdio.h>")
(sec+tab "H3" "ansic_ext_signal"
"Signal handling <signal.h>")
(sec+tab "H3" "ansic_ext_argv"
"Command-line arguments")
(sec+tab "H3" "ansic_ext_container"
"Container data structures")
(sec+tab "H3" "ansic_ext_crypto"
"Cryptographic computations (low-level)")
(sec+tab "H3" "ansic_ext_crypto2"
"Cryptographic computations (high-level)")
(sec+tab "H3" "ansic_ext_compwarn"
"Compiler warning management")
(sec+tab "H3" "ansic_ext_misc"
"Misc")
(section "H2" "isoc_sup"
"Support for systems lacking ISO C 99")
(sec+tab "H3" "isoc_core_properties"
"Core language properties")
(sec+tab "H3" "isoc_sup_limits"
"Sizes of integer types <limits.h>")
(sec+tab "H3" "isoc_sup_stdarg"
"Variable arguments <stdarg.h>")
(sec+tab "H3" "isoc_sup_stdbool"
"Boolean type and values <stdbool.h>")
(sec+tab "H3" "isoc_sup_stddef"
"Basic types <stddef.h>")
(sec+tab "H3" "isoc_sup_stdint"
"Integer types and values <stdint.h>")
(sec+tab "H3" "isoc_sup_stdio"
"Input/output <stdio.h>")
(sec+tab "H3" "isoc_sup_stdlib_procconv"
"Process control, Numeric conversion functions <stdlib.h>")
(sec+tab "H3" "isoc_sup_ctype"
"Unibyte characters <ctype.h>")
(sec+tab "H3" "isoc_sup_inttypes"
"Functions for greatest-width integer types <inttypes.h>")
(sec+tab "H3" "isoc_sup_string"
"String handling <string.h>")
(sec+tab "H3" "isoc_sup_wchar"
"Extended multibyte and wide character utilities <wchar.h>")
(sec+tab "H3" "isoc_sup_wctype"
"Wide character classification and mapping utilities <wctype.h>")
(sec+tab "H3" "isoc_sup_float"
"Characteristics of floating types <float.h>")
(sec+tab "H3" "isoc_sup_math"
"Mathematics <math.h>")
(section "H2" "isoc_enh"
"Enhancements for ISO C 99 functions")
(sec+tab "H3" "isoc_enh_stdio"
"Input/output <stdio.h>")
(section "H2" "isoc_ext"
"Extra functions based on ISO C 99")
(sec+tab "H3" "isoc_ext_math"
"Mathematics <math.h>")
(sec+tab "H3" "isoc_ext_stdlib_conv"
"Numeric conversion functions <stdlib.h>")
(sec+tab "H3" "isoc_ext_wchar_mb"
"Extended multibyte and wide character utilities <wchar.h>")
(sec+tab "H2" "posix_sup_obsolete"
"Support for obsolete systems lacking POSIX:2008")
(echo "These modules are not listed among dependencies below, for simplicity.")
(echo "If your package requires portability to old, obsolete systems,
you need to list these modules explicitly among the modules
to import through gnulib-tool.")
(sec+tab "H2" "posix_sup"
"Support for systems lacking POSIX:2008")
(sec+tab "H2" "posix_compat"
"Compatibility checks for POSIX:2008 functions")
(sec+tab "H2" "posix_enh"
"Enhancements for POSIX:2008 functions")
(section "H2" "posix_ext"
"Extra functions based on POSIX:2008")
(sec+tab "H3" "posix_ext_stdio"
"Input/output")
(sec+tab "H3" "posix_ext_conv"
"Numeric conversion functions")
(sec+tab "H3" "posix_ext_filesys"
"File system functions")
(sec+tab "H3" "posix_ext_inodeset"
"File system as inode set")
(sec+tab "H3" "posix_ext_filedesc"
"File descriptor based Input/Output")
(sec+tab "H3" "posix_ext_filestream"
"File stream based Input/Output")
(sec+tab "H3" "posix_ext_uidgid"
"Users and groups")
(sec+tab "H3" "posix_ext_security"
"Security")
(sec+tab "H3" "posix_ext_datetime"
"Date and time")
(sec+tab "H3" "posix_ext_net"
"Networking functions")
(sec+tab "H3" "posix_ext_thread"
"Multithreading")
(sec+tab "H3" "posix_ext_signal"
"Signal handling")
(sec+tab "H3" "posix_ext_i18n"
"Internationalization functions")
(sec+tab "H3" "posix_ext_unicode"
"Unicode string functions")
(sec+tab "H3" "posix_ext_exec"
"Executing programs")
(sec+tab "H3" "posix_ext_java"
"Java")
(sec+tab "H3" "posix_ext_csharp"
"C#")
(sec+tab "H3" "posix_ext_misc"
"Misc")
(sec+tab "H2" "build_lib"
"Support for building libraries and executables")
(sec+tab "H2" "build_doc"
"Support for building documentation")
(sec+tab "H2" "maintain"
"Support for maintaining and releasing projects")
(sec+tab "H2" "misc"
"Misc"))
;; First, write the main documentation.
(erase-buffer)
(insert "\n")
(begin "HTML")
(begin "HEAD")
(echo (wrap "TITLE" "Gnulib Module List"))
(echo (concat ""))
(end "HEAD")
(begin "BODY")
(echo (wrap "H1" "Gnulib Module List"))
(echo "This is a list of the modules which make up gnulib, with dependencies.")
(all-modules 'toc)
(all-modules 'body)
(let ((missing (set-difference MODULES-ACCORDING-TO-GNULIB-TOOL
SEEN-MODULES
:test 'eq)))
(when missing
(setq missing (mapcar 'symbol-name missing)
missing (sort missing 'string<)
missing (mapcar 'intern missing))
(section "H2" "missing-modules"
"Unclassified modules - please update make-html")
(begin-table)
(while missing
(module (pop missing)))
(end-table)))
(let* ((all (working
(flet ((under (dir) (call-process
"find" nil t nil
dir "-type" "f" "-print")))
(under "lib")
(under "m4"))
(goto-char (point-min))
(mapc 'flush-lines '("/\\."
"CVS"
"README"
"ChangeLog"
"Makefile"
"TODO"
"tags$"
"TAGS$"
"~$"))
(split-string (buffer-string))))
(missing (set-difference all SEEN-FILES :test 'string=)))
(when missing
(setq missing (delete "m4/onceonly.m4" (sort missing 'string<)))
(section "H2" "lone-files"
"Lone files - please create new modules containing them")
(while missing
(let ((filename (pop missing)))
(echo (format "%s "
REPO-URL-PREFIX
filename
REPO-URL-SUFFIX
(wrap "TT" filename)))))))
(echo (wrap "H2" "Future developments"))
(echo "Ideally a module could consist of:")
(begin "UL")
(let* ((var-m (wrap "VAR" "module"))
(f "files")
(meta (mapconcat 'identity '("configure.ac fragment"
"Makefile.am fragment"
"dependency list")
", "))
(ls `(("A header file: lib/%s.h" ,var-m)
("One or more implementation %s: lib/%s.c et al." ,f ,var-m)
("One or more autoconf macro %s: m4/%s.m4 et al." ,f ,var-m)
("A %s: modules/%s" ,meta ,var-m)
("A testsuite: source %s %s (a %s) in modules/%s-tests"
,f "in tests/ and metainformation" ,meta ,var-m)
("Some documentation")
("A POT file and some PO %s" ,f)))
fmt)
(while ls
(echo (wrap "LI" (apply 'format (pop ls))))))
(end "UL")
(echo " ")
(echo "Generated from " (wrap "CODE" "make-html") " on "
(format-time-string "%Y-%m-%d") ".")
(end "BODY")
(end "HTML")
(let ((backup-inhibited t))
(write-file (format "%s.html" OUTPUT-FILESTEM)))
;; Now write fanout documentation.
(defun mref (m)
(format "%s"
OUTPUT-FILESTEM m m))
(setq indent "")
(erase-buffer)
(insert "\n")
(begin "HTML")
(begin "HEAD")
(echo (wrap "TITLE" "Gnulib Module Fanout"))
(echo (concat ""))
(end "HEAD")
(begin "BODY")
(echo (wrap "H1" "Gnulib Module Fanout"))
(echo "This is a table of each module's fanout, i.e., the list of"
" modules directly depending on a particular module."
" Heading links refer to the"
" " (format "main module list"
OUTPUT-FILESTEM)
" (a separate document)."
" Other links are internal.")
(mapc (lambda (m)
(let ((ls (sort (mapcar 'symbol-name (gethash m FANOUT))
'string<)))
(echo (wrap "H2"
(format "%s (%d)"
m OUTPUT-FILESTEM m m (length ls))))
(echo (mapconcat (lambda (m)
(format "%s"
m m))
ls ", ")
"\n")))
MODULES-ACCORDING-TO-GNULIB-TOOL)
(end "BODY")
(end "HTML")
(let ((backup-inhibited t))
(write-file (format "%s-FANOUT.html" OUTPUT-FILESTEM)))
;;; make-html ends here
|