mirror of
https://github.com/boostorg/build.git
synced 2026-02-13 12:22:17 +00:00
466 lines
14 KiB
Plaintext
466 lines
14 KiB
Plaintext
# (C) Copyright Rene Rivera, 2002-2003.
|
|
#
|
|
# See accompanying license for terms and conditions of use.
|
|
#
|
|
|
|
# Utilities for generating format independent output. Using these
|
|
# will help in generation of documentation in at minimum plain/console
|
|
# and html.
|
|
|
|
import modules ;
|
|
import numbers ;
|
|
import string ;
|
|
import regex ;
|
|
|
|
# The current output target. Defaults to console.
|
|
output-target = console ;
|
|
|
|
# The current output type. Defaults to plain.
|
|
output-type = plain ;
|
|
|
|
# Whitespace.
|
|
.whitespace = [ string.whitespace ] ;
|
|
|
|
# Set the target and type of output to generate. This sets both
|
|
# the destination output and the type of docs to generate to that
|
|
# output. The target can be either a file or "console" for echoing
|
|
# to the console. If the type of output is not specified it defaults
|
|
# to plain text.
|
|
#
|
|
rule output (
|
|
target # The target file or device; file or "console".
|
|
type ? # The type of output; "plain", or "html".
|
|
)
|
|
{
|
|
type ?= plain ;
|
|
if $(output-target) != $(target)
|
|
{
|
|
output-target = $(target) ;
|
|
output-type = $(type) ;
|
|
if $(output-type) = html
|
|
{
|
|
text
|
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"
|
|
"<html>"
|
|
"<head>"
|
|
"</head>"
|
|
"<body link=\"#0000ff\" vlink=\"#800080\">"
|
|
: true
|
|
: prefix ;
|
|
text
|
|
"</body>"
|
|
"</html>"
|
|
:
|
|
: suffix ;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate a section with a description. The type of output can be
|
|
# controlled by the value of the 'output-type' variable. If not set
|
|
# it defaults to 'console' indicating immediate display to the console.
|
|
# Other possible values are: 'html-file'.
|
|
#
|
|
rule section (
|
|
name # The name of the section.
|
|
description * # A number of description lines.
|
|
)
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
lines [ split-at-words $(name): ] ;
|
|
lines ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
name = [ escape-html $(name) ] ;
|
|
text <h3>$(name)</h3> <p> ;
|
|
}
|
|
local pre = ;
|
|
while $(description)
|
|
{
|
|
local paragraph = ;
|
|
while $(description) && [ string.is-whitespace $(description[1]) ] { description = $(description[2-]) ; }
|
|
if $(pre)
|
|
{
|
|
while $(description) && (
|
|
$(pre) = " $(description[1])" ||
|
|
( $(pre) < [ string.chars [ MATCH "^([$(.whitespace)]*)" : " $(description[1])" ] ] )
|
|
)
|
|
{ paragraph += $(description[1]) ; description = $(description[2-]) ; }
|
|
while [ string.is-whitespace $(paragraph[-1]) ] { paragraph = $(paragraph[1--2]) ; }
|
|
pre = ;
|
|
if $(output-type) = plain
|
|
{
|
|
lines $(paragraph) "" : " " " " ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text <blockquote> ;
|
|
lines $(paragraph) ;
|
|
text </blockquote> ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while $(description) && ! [ string.is-whitespace $(description[1]) ]
|
|
{ paragraph += $(description[1]) ; description = $(description[2-]) ; }
|
|
if $(paragraph[1]) = :: && ! $(paragraph[2])
|
|
{
|
|
pre = " " ;
|
|
}
|
|
if $(paragraph[1]) = ::
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
lines $(paragraph[2-]) "" : " " " " ;
|
|
lines ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text <blockquote> ;
|
|
lines $(paragraph[2-]) ;
|
|
text </blockquote> ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
local p = [ MATCH "(.*)(::)$" : $(paragraph[-1]) ] ;
|
|
local pws = [ MATCH "([ ]*)$" : $(p[1]) ] ;
|
|
p = [ MATCH "(.*)($(pws))($(p[2]))$" : $(paragraph[-1]) ] ;
|
|
if $(p[3]) = ::
|
|
{
|
|
pre = [ string.chars [ MATCH "^([$(.whitespace)]*)" : " $(p[1])" ] ] ;
|
|
if ! $(p[2]) || $(p[2]) = "" { paragraph = $(paragraph[1--2]) $(p[1]): ; }
|
|
else { paragraph = $(paragraph[1--2]) $(p[1]) ; }
|
|
if $(output-type) = plain
|
|
{
|
|
lines [ split-at-words " " $(paragraph) ] : " " " " ;
|
|
lines ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text </p> <p> [ escape-html $(paragraph) ] ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
lines [ split-at-words " " $(paragraph) ] : " " " " ;
|
|
lines ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text </p> <p> [ escape-html $(paragraph) ] ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if $(output-type) = html
|
|
{
|
|
text </p> ;
|
|
}
|
|
}
|
|
|
|
# Generate the start of a list of items. The type of output can be
|
|
# controlled by the value of the 'output-type' variable. If not set
|
|
# it defaults to 'console' indicating immediate display to the console.
|
|
# Other possible values are: 'html-file'.
|
|
#
|
|
rule list-start ( )
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text <ul> ;
|
|
}
|
|
}
|
|
|
|
# Generate an item in a list. The type of output can be
|
|
# controlled by the value of the 'output-type' variable. If not set
|
|
# it defaults to 'console' indicating immediate display to the console.
|
|
# Other possible values are: 'html-file'.
|
|
#
|
|
rule list-item (
|
|
item + # The item to list.
|
|
)
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
lines [ split-at-words "*" $(item) ] : " " ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text <li> [ escape-html $(item) ] </li> ;
|
|
}
|
|
}
|
|
|
|
# Generate the end of a list of items. The type of output can be
|
|
# controlled by the value of the 'output-type' variable. If not set
|
|
# it defaults to 'console' indicating immediate display to the console.
|
|
# Other possible values are: 'html-file'.
|
|
#
|
|
rule list-end ( )
|
|
{
|
|
if $(output-type) = plain
|
|
{
|
|
lines ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
text </ul> ;
|
|
}
|
|
}
|
|
|
|
# Split the given text into separate lines, word-wrapping to a margin.
|
|
# The default margin is 78 characters.
|
|
#
|
|
rule split-at-words (
|
|
text + # The text to split.
|
|
: margin ? # An optional margin, default is 78.
|
|
)
|
|
{
|
|
local lines = ;
|
|
text = [ string.words $(text:J=" ") ] ;
|
|
text = $(text:J=" ") ;
|
|
margin ?= 78 ;
|
|
local char-match-1 = ".?" ;
|
|
local char-match = "" ;
|
|
while $(margin) != 0
|
|
{
|
|
char-match = $(char-match)$(char-match-1) ;
|
|
margin = [ numbers.decrement $(margin) ] ;
|
|
}
|
|
while $(text)
|
|
{
|
|
local s = "" ;
|
|
local t = "" ;
|
|
# divide s into the first X characters and the rest
|
|
s = [ MATCH "^($(char-match))(.*)" : $(text) ] ;
|
|
|
|
if $(s[2])
|
|
{
|
|
# split the first half at a space
|
|
t = [ MATCH "^(.*)[\\ ]([^\\ ]*)$" : $(s[1]) ] ;
|
|
}
|
|
else
|
|
{
|
|
t = $(s) ;
|
|
}
|
|
|
|
if ! $(t[2])
|
|
{
|
|
t += "" ;
|
|
}
|
|
|
|
text = $(t[2])$(s[2]) ;
|
|
lines += $(t[1]) ;
|
|
}
|
|
return $(lines) ;
|
|
}
|
|
|
|
# Generate a set of fixed lines. Each single item passed in is
|
|
# output on a separate line. For console this just echos each line,
|
|
# but for html this will split them with <br>.
|
|
#
|
|
rule lines (
|
|
text * # The lines of text.
|
|
: indent ? # Optional indentation prepended to each line after the first one.
|
|
outdent ? # Optional indentation to prepend to the first line.
|
|
)
|
|
{
|
|
text ?= "" ;
|
|
indent ?= "" ;
|
|
outdent ?= "" ;
|
|
if $(output-type) = plain
|
|
{
|
|
text $(outdent)$(text[1]) $(indent)$(text[2-]) ;
|
|
}
|
|
else if $(output-type) = html
|
|
{
|
|
local indent-chars = [ string.chars $(indent) ] ;
|
|
indent = "" ;
|
|
for local c in $(indent-chars)
|
|
{
|
|
if $(c) = " " { c = ; }
|
|
else if $(c) = " " { c = ; }
|
|
indent = $(indent)$(c) ;
|
|
}
|
|
local html-text = [ escape-html $(text) : ] ;
|
|
text $(html-text[1])<br> $(indent)$(html-text[2-])<br> ;
|
|
}
|
|
}
|
|
|
|
# Output text directly to the current target. When doing output
|
|
# to a file, one can indicate if the text should be output to
|
|
# "prefix" it, as the "body" (default), or "suffix" of the file. This is
|
|
# independant of the actual execution order of the text rule. This rule
|
|
# invokes a singular action, one action only once, which does the
|
|
# build of the file. Therefore actions on the target outside of this
|
|
# rule will happen entirely before and/or after all output using this rule.
|
|
#
|
|
rule text (
|
|
strings * # The strings of text to output.
|
|
: overwrite ? # true to overwrite the output (if it is a file)
|
|
: prefix-body-suffix ? # Indication to output prefix, body, or suffix (for a file).
|
|
)
|
|
{
|
|
prefix-body-suffix ?= body ;
|
|
if $(output-target) = console
|
|
{
|
|
if ! $(strings)
|
|
{
|
|
ECHO ;
|
|
}
|
|
else
|
|
{
|
|
while $(strings)
|
|
{
|
|
ECHO $(strings[1]) ;
|
|
strings = $(strings[2-]) ;
|
|
}
|
|
}
|
|
}
|
|
# We ignore empty output because the Windows ECHO command is
|
|
# braindamaged. It doesn't have any facility for echoing a blank line.
|
|
else if $(output-target)
|
|
{
|
|
if ! $($(output-target).did-action)
|
|
{
|
|
$(output-target).did-action = yes ;
|
|
_ on $(output-target) = " " ;
|
|
nl on $(output-target) = "
|
|
" ;
|
|
text-redirect-0 on $(output-target) = ">>" ;
|
|
text-redirect-n on $(output-target) = ">>" ;
|
|
text-front on $(output-target) = ;
|
|
text-prefix on $(output-target) = ;
|
|
text-body on $(output-target) = ;
|
|
text-suffix on $(output-target) = ;
|
|
text-action $(output-target) ;
|
|
text-front-section.$(soutput-target) = ;
|
|
}
|
|
if $(overwrite)
|
|
{
|
|
text-redirect-0 on $(output-target) = ">" ;
|
|
}
|
|
if ! $(text-front-section.$(output-target))
|
|
{
|
|
text-front on $(output-target) = [ echo-cmd $(strings[1]) ] ;
|
|
text-front-section.$(output-target) = $(prefix-body-suffix) ;
|
|
strings = $(strings[2-]) ;
|
|
}
|
|
if $(strings)
|
|
{
|
|
if ( $(prefix-body-suffix) = prefix &&
|
|
$(text-front-section.$(output-target)) != prefix ) ||
|
|
( $(prefix-body-suffix) = body &&
|
|
$(text-front-section.$(output-target)) = suffix )
|
|
{
|
|
text-$(text-front-section.$(output-target)) on $(output-target) =
|
|
[ on $(output-target) return $(text-front) ]
|
|
[ on $(output-target) return $(text-$(text-front-section.$(output-target))) ] ;
|
|
text-front on $(output-target) = [ echo-cmd $(strings[1]) ] ;
|
|
text-front-section.$(output-target) = $(prefix-body-suffix) ;
|
|
strings = $(strings[2-]) ;
|
|
}
|
|
while $(strings)
|
|
{
|
|
text-$(prefix-body-suffix) on $(output-target) += [ echo-cmd $(strings[1]) ] ;
|
|
strings = $(strings[2-]) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Outputs the text to the current targets, after word-wrapping it.
|
|
rule wrapped-text ( text + )
|
|
{
|
|
local lines = [ split-at-words $(text) ] ;
|
|
text $(lines) ;
|
|
}
|
|
|
|
# Escapes text into html/xml printable equivalents.
|
|
# Does not know about tags and therefore tags fed into
|
|
# this will also be escaped. Currently escapes space, "<", ">", and "&".
|
|
#
|
|
rule escape-html (
|
|
text + # The text to escape.
|
|
: space ? # What to replace spaces with, defaults to " ".
|
|
)
|
|
{
|
|
local html-text = ;
|
|
while $(text)
|
|
{
|
|
local html = $(text[1]) ;
|
|
text = $(text[2-]) ;
|
|
html = [ regex.replace $(html) "&" "&" ] ;
|
|
html = [ regex.replace $(html) "<" "<" ] ;
|
|
html = [ regex.replace $(html) ">" ">" ] ;
|
|
if $(space)
|
|
{
|
|
html = [ regex.replace $(html) " " "$(space)" ] ;
|
|
}
|
|
html-text += $(html) ;
|
|
}
|
|
return $(html-text) ;
|
|
}
|
|
|
|
# Outputs the text strings collected by the text rule to the output
|
|
# file.
|
|
#
|
|
actions quietly text-action
|
|
{
|
|
$(text-front)$(_)$(text-redirect-0)$(_)"$(<)"
|
|
$(text-prefix)$(_)$(text-redirect-n)$(_)"$(<)"$(nl)
|
|
$(text-body)$(_)$(text-redirect-n)$(_)"$(<)"$(nl)
|
|
$(text-suffix)$(_)$(text-redirect-n)$(_)"$(<)"$(nl)
|
|
}
|
|
|
|
if [ modules.peek : NT ]
|
|
{
|
|
rule echo-cmd ( string ? )
|
|
{
|
|
if $(string) || $(string) != ""
|
|
{
|
|
local escaped = [ regex.escape $(string) : "&|()<>^" : "^" ] ;
|
|
return "echo $(escaped)" ;
|
|
}
|
|
else
|
|
{
|
|
return "echo." ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rule echo-cmd ( string ? )
|
|
{
|
|
if $(string) || $(string) != ""
|
|
{
|
|
local escaped = [ regex.escape $(string) : "\\\"" : "\\" ] ;
|
|
return "echo \"$(escaped)\"" ;
|
|
}
|
|
else
|
|
{
|
|
return "echo" ;
|
|
}
|
|
}
|
|
}
|
|
|
|
local rule __test__ ( )
|
|
{
|
|
import assert ;
|
|
|
|
assert.result one two three : split-at-words one two three : 5 ;
|
|
assert.result "one two" three : split-at-words one two three : 8 ;
|
|
assert.result "one two" three : split-at-words one two three : 9 ;
|
|
assert.result "one two three" : split-at-words one two three ;
|
|
assert.result "one two three" "&<>" :
|
|
escape-html "one two three" "&<>" ;
|
|
}
|