Glue is a simple formatting language.

A Glue Expression is either standalone (e.g. in lqquery) or
can be embedded in a string using ${...}.

The result of a Glue Expression is always a Gluon.

Glue Expressions are always evaluated with respect to a hierarchy
of Name Spaces.

(A Name Space is a set of bindings between C variables or functions
and strings.)

Within a Glue Expression,
    "..." surrounds a literal string
    '...' surrounds a shell-style string in which \ is not special.
	Note that there is no way to include ' in this kind of Glue string.

    $[...] represents a Smart String.

    Within a Smart String, ${....} and $[...] are recognised.
    Within a literal string, \ is recognised as in C.
	TODO: be explicit

    Variable   interpolates a reference to the given variable
    NameSpace.Variable refers to Variable in the given NameSpace.

    You can aply a filter to a variable:
    Variable -> filter
    Variable -> filter(param1, param2, param3)

    filters include
	reverse
	reverse(bycharacter)
	    hello world -> dlrow olleh
	reverse(byword)
	    hello world -> olleh dlrow
	reverse(byword) -> reverse(bycharacter)
	    hello world -> world hello
	An optional string parameter is a string containing
	whitespace to use for the reversal:
	reverse(byword, "/-")
	    /usr/dict/word-list -> /rsu/tcid/drow-tsil
	reverse(byword, "/")
	    /usr/dict/word-list -> /rsu/tcid/tsil-drow

	transliterate("abc", "def")
	tr("abc", "def")
	    to turn a into d, b into e, c into f
	
	case(toupper)
	    hello world -> HELLO WORLD
	case(tolower)
	    hello world -> hello world
	    HELLO WORLD -> hello world
	case(invert)
	    hello world -> HELLO WORLD
	    Hello World -> hELLO wORLD
	case(initialcaps)
	    hello world -> Hello World
	case(initialcaps, "/")
	    hello world -> Hello world
	    /usr/dict/words -> /Usr/Dict/Words
	
	baseconv(16)
	    converts wholly numeric tokens
	    hello world -> hello world
	    I need 25 boys -> I need 19 boys
		(i.e. converted the number to hexadecimal)
	The full format is:
	baseconv([fromspec] [tospec])
	    fromspec is from: followed by arguments
	    tospec is to: followed by arguments
	Optional parameters include
	    a number -- the base concerned
	    C (use C-style format conventions, with hex in upper case)
	    c (use C-style format conventions, but in lower case)
	    a string, used to delimt words
	    a format (these are described in more detail below);
	    you should not use both C and a format.
	Example:
	    baseconv(from: 8, " ,"; to: 16, C, ", ")
		Here, we are converting from octal to hexadecimal,
		using C hexadecimal constant format (0xFF), and
		separating the output tokens with ", ".
		The input tokens are separated with any combination
		of space and comma.

		Hello 0377, 12 6 zx81 8V -> Hello, 0xFF, 0xC, 6, zx81, 8V
	    
	Note: you can use , instead of : and ; in the example:
	    baseconv(from, 8, " ,", to, 16, C, ", ")
	but this may look odd.


	justify
	    [padleft | padright | centre | center]
	    nn - fieldwidth

	    ${"<" fby "hello" -> justify(padleft, 10) fby ">"}
		<     hello>
	    ${"<" fby "hello" -> justify(padright, 10) fby ">"}
		<hello     >
	    ${"<" fby "hello" -> justify(centre, 10) fby ">"}
		<  hello   >
	    Some implementations may allow units:
	    ${"<" fby "hello" -> justify(centre, 2 cm) fby ">"}
		<  hello   >


	truncate([flags] width)
	    remove characters.
	    flags can be any of
		left, right, outside, middle
		specifying whence to remove charcters
	    characters, words
		unit of removal
	    ellipsis [=value]
		(default is ...)
		what to insert in the middle if truncation happens.
		The insertion of the ellipsis will cause extra truncation
		rather than making the string too long.
		It is an error to make width be less than the width
		of an ellipsis
	    addwidth
		add the width of the ellipsis to the field width
	    "word-separators"
		what constitutes a string
		If not given, ReadWord is used
	    width is how much to retain

	    truncate(words, 1)
		hello world -> hello
	    truncate(words, right, 1)
		hello world -> world
	    truncate(middle, 4)
		hello world -> held
	    truncate(middle, ellipsis, 7)
		hello world -> he...ld
	    truncate(middle, ellipsis, 4)
		hello world -> h...
	    truncate(middle, ellipsis, addwidth, 4)
		hello world -> he...ld
	    truncate(middle, ellipsis="//", 4)
		hello world -> he//ld
	    truncate(outside, 5)
		hello world -> lo wo
	    

	substitute(/pattern/, "replacement" [, flags])
	    Match the stream against the given regular expression;
	    if it matches, change whatever matched with the replacement.
	    Inside the replacement, \ is treated as for any other string;
	    you can use 'shell-style strings' if you prefer.

	    flag parameters are
		each (the default)
		    substitute over the entire stream
		byword
		    substitute for each word
		byline
		    substitute for each line of text
		    (this is unusual, since Glue expressions only
		    rarely generate nwelines; you may need an explicit
		    \n somewhere to make this do what you expect)
		global
		    do all matches
		ic
		ignorecase
		    case insensitive
		hc
		halfcase
		    Upper Case Letters only match upper case;
		    lower case matches either
		    (just as in lq-text Heuristic Phrase Matching)
		
		You can also give
		    skip=n
		    count=n
		so, for exmple,
		    substitute(/\<boy\>/, "Simon", skip=1, count=3)
		replaces the second, third and fourth boy-word with Simon.

		In the replacement, \1..\9 and & work as per ed.
		I don't know if \u \U \l \L etc. work.

		How about this?
		    substitute(
			/\(boy \)\([^ ]*\)/,
			"\1" fby "\2"-> case(initialcaps) fby "!"
		    )

		    boy wonder -> boy Wonder!
		Hmm, don't know if it's worth implementing that.
		
	    
	You can join two expressions with the fby operator:

	Date.Month.Name fby " " fby Date.Year

	Another way to do this is to use a Smart String:

	$[${Date.Month.Name} ${Date.Year}]

	${...} contains any subexpression.

	For example,
	${FileName -> reverse(byword, "/")} -> case(toupper) -> tr("/", "\\")


Formats
    Any glue subexpression or Smart String can contain a format specification.

    You can specify left, right and centred justification,
    truncation by characters, words, or field-with,
    and numeric and string formatting.

    This can be with the above filters, or it can be done with
    the printf filter, as in C printf:
	stream -> printf("%03d")

