summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJoe <joe@joelightning.com>2011-11-10 11:31:23 +0000
committerJoe <joe@joelightning.com>2011-11-10 11:31:23 +0000
commitc40170cb03e41bd1efe775bbd430a50da6cdeea4 (patch)
tree0cc4c0f5cc41c502a0dff8fdca124cab2bd0dab5 /tools
First commit, pbot-ng already works.
Diffstat (limited to 'tools')
-rw-r--r--tools/bashdoc/ChangeLog22
-rwxr-xr-xtools/bashdoc/bashdoc.sh726
-rwxr-xr-xtools/build_numerics.sh102
-rw-r--r--tools/numerics.txt215
4 files changed, 1065 insertions, 0 deletions
diff --git a/tools/bashdoc/ChangeLog b/tools/bashdoc/ChangeLog
new file mode 100644
index 0000000..5fcf8cb
--- /dev/null
+++ b/tools/bashdoc/ChangeLog
@@ -0,0 +1,22 @@
+Sun Oct 14 17:24:19 CEST 2007; Arvid Norlander
+ The last two days I have changed so much on bashdoc that I lost count of it
+ Some nice things:
+ Cleaned up code.
+ XHTML and CSS.
+ Made bashdoc able to document variables.
+ Fix many bugs.
+
+Sun Aug 13 13:08:12 PDT 2006; Unknown
+ Fix bug which caused either extra garbage around function links in src or
+ skipped some interlinks.
+ Release bashdoc-0.1.8
+
+Sun Jan 22 16:22:45 EST 2006; Unknown
+ ChangeLog: Started
+ src2html: changed sed to fix the weird invalid range end erors
+ Changes suggested by Jaka Kranjc
+ generate-smgl-docs: Add handy example doc generation
+ script, written by and for SourceMage
+ generate-smgl-docs: Patch by Jaka Kranjc
+ generate-smgl-docs: Add -q to bashdoc call to limit useless output
+ Release: bashdoc-0.1.7
diff --git a/tools/bashdoc/bashdoc.sh b/tools/bashdoc/bashdoc.sh
new file mode 100755
index 0000000..821f9b3
--- /dev/null
+++ b/tools/bashdoc/bashdoc.sh
@@ -0,0 +1,726 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+#--------------------------
+## @Synopsis Reads specialy formated shell scripts and creates docs
+## @Copyright Copyright 2003, Paul Mahon
+## @Copyright Copyright 2007, Arvid Norlander
+## @License GPL v2
+## Parses comments between lines of '#---'
+## Lines to be parsed start with ##. All tags start with @.
+## Lines without a tag are considered simple description of the section.
+## If the line following the comment block doesn't start with 'function'
+## the it's assumed that the comment is for the whole file. Only the first
+## non-function comment block will be used, the other will be ignored.
+## <p>
+## Multiple identical tags are allowed, the contents are appended and separated
+## with a space. @param tags are treated specials and are assumed to be in order.
+## <p>
+## There is an additional &lt;@function FUNCTION_NAME&gt; tag that can be embeded
+## in any bashdoc comment. It will be transformed into a link to that function.
+## Note, this will only work for functions that are defined in the same script.
+## <p><pre>
+## Usage: [OPTIONS] [--] script [ script ...]
+## -p, --project project Name of the project
+## -o, --output directory Specifies the directory you want the resulting html to go into
+## -c, --nocss Do not write default CSS file.
+## -e, --exclusive tag Only output if the block has this tag
+## -q, --quiet Quiet the output
+## -h, --help Display this help and exit
+## -V, --version Output version information and exit
+## -- No more arguments, only scripts
+## script The script you want documented
+##</pre>
+##
+#--------------------------
+
+# Make env sane
+unset LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY
+unset LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS
+unset LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION
+export LC_ALL=C
+export LANG=C
+
+# Check bash version. We need at least 3.2.x
+# Lets not use anything like =~ here because
+# that may not work on old bash versions.
+if [[ "$(awk -F. '{print $1 $2}' <<< $BASH_VERSION)" -lt 32 ]]; then
+ echo "Sorry your bash version is too old!"
+ echo "You need at least version 3.2 of bash"
+ echo "Please install a newer version:"
+ echo " * Either use your distro's packages"
+ echo " * Or see http://www.gnu.org/software/bash/"
+ exit 2
+fi
+
+# To make set -x more usable
+export PS4='(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]} : '
+
+VERSION="0.1.8"
+HEADERS="<!-- Generated by bashdoc version $VERSION, on $(date +'%Y-%m-%d'). -->
+<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\" />
+<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
+
+GOOD=$'\e[32;01m'
+WARN=$'\e[33;01m'
+BAD=$'\e[31;01m'
+NORMAL=$'\e[0m'
+
+#--------------------------
+## Output error message
+## @param Message
+## @Stderr Formated message
+#--------------------------
+print_error () {
+ echo -e " ${BAD}*${NORMAL} $*" >&2
+}
+#--------------------------
+## Output warning message
+## @param Message
+## @Stderr Formated message
+#--------------------------
+print_warn () {
+ echo -e " ${WARN}*${NORMAL} $*" >&2
+}
+#--------------------------
+## Output info message
+## @param Message
+## @Stderr Formated message
+#--------------------------
+print_info () {
+ echo -e " ${GOOD}*${NORMAL} $*" >&2
+}
+#--------------------------
+## Output debug message
+## @param Message
+## @Stderr Formated message
+#--------------------------
+print_debug () {
+ echo -e " $*" >&2
+}
+
+#--------------------------
+## @Arguments -r: recursive, -o [directory]: output html
+## Parses arguments for this script
+## @Gobals RECURSIVE, OUT_DIR
+#--------------------------
+function args()
+{
+ local retVal=0
+ QUIET=0
+ while true ; do
+ case $1 in
+ -p|--project)
+ PROJECT="$2"
+ (( retVal+=2 ))
+ shift 2
+ ;;
+ -o|--output)
+ OUT_DIR="$2"
+ (( retVal+=2 ))
+ shift 2
+ ;;
+ -c|--nocss)
+ NOCSS="1"
+ (( retVal+=2 ))
+ shift 1
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -V|--version)
+ version
+ exit 0
+ ;;
+ -e|--exclusive)
+ EXCLUSIVE="${2%%=*}"
+ EXCLUSIVE_VAL="${2#*=}"
+ (( retVal+=2 ))
+ shift 2
+ ;;
+ -q|--quiet)
+ (( QUIET+=1 ))
+ (( retVal+=1 ))
+ shift 1
+ ;;
+ --)
+ (( retVal++ ))
+ return $retVal
+ ;;
+ -*)
+ usage
+ exit 0
+ ;;
+ *)
+ [[ -e $1 ]] && return $retVal
+ echo "$1 doesn't exist."
+ usage
+ exit 1
+ ;;
+ esac
+ done
+}
+
+#-------------------------
+## Version for this script
+## @Stdout Version information
+#-------------------------
+function version()
+{
+ echo "bashdoc $VERSION - Generate HTML documentation from bash scripts"
+ echo ''
+ echo 'Copyright (C) 2003 Paul Mahon'
+ echo 'Copyright (C) 2007 Arvid Norlander'
+ echo 'This is free software; see the source for copying conditions. There is NO'
+ echo 'warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'
+ echo ''
+ echo 'Written by Paul Mahon and modified by Arvid Norlander'
+}
+
+#-------------------------
+## Usage for this script
+## @Stdout Usage information
+#-------------------------
+function usage()
+{
+cat <<- EOF
+bashdoc generates HTML documentation from bash scripts.
+
+Usage: $(basename $0) [OPTIONS] [--] script [script ...]
+
+Options:
+ -p, --project project Name of the project
+ -o, --output directory Specifies the directory you want the resulting html to go into
+ -c, --nocss Do not write default CSS file.
+ -e, --exclusive tag Only output if the block has this tag
+ -q, --quiet Quiet the output
+ -h, --help Display this help and exit
+ -V, --version Output version information and exit
+ -- No more arguments, only scripts
+ script The script you want documented
+
+Examples:
+ bashdoc.sh -p bashdoc -o docs/ bashdoc.sh Generate documentation for this program.
+ bashdoc.sh -p appname -o docs/ -e Type=API someapp.sh Generate documentation for someapp.sh,
+ exclude items that do not include the tag
+ @Type API
+EOF
+}
+
+
+#--------------------------
+## Reads until it has read an entire comment block. A block starts with
+## <br><pre>#---</pre></br>
+## Alone on a line, and continues until the next
+## <br><pre>#---</pre></br>
+## All comment lines inside should have ## at the start or they
+## will be ignored.
+##
+## @return 0 Possibly more blocks
+## @return 1 Unexpected end of file
+## @return 2 Expected end of file, no more blocks
+## @Stdin Reads a chunk
+## @Stdout Block with starting '##' removed
+## @Globals paramDesc, retDesc, desc, block, split, out_comment_block
+#--------------------------
+function get_comment_block()
+{
+ local inComment commentBlock lastLine=""
+ commentBlock=""
+ while read LINE ; do
+ (( srcLine++ ))
+ if [[ ${LINE:0:4} == '#---' ]] ; then
+ if [[ $inComment ]] ; then
+ out_comment_block="$commentBlock"
+ # I'm not sure why this is needed but it fixes incorrect line number
+ (( srcLine++ ))
+ return 0
+ else
+ inComment=yes
+ fi
+ elif [[ ${LINE:0:2} != '##' ]] && [[ $inComment ]] ; then
+ [[ $QUIET -lt 1 ]] && print_warn "Line $srcLine of $FILE isn't a doc comment! Ignoring."
+ [[ $QUIET -lt 1 ]] && print_warn "Line in question is: $LINE"
+ elif [[ $inComment ]] ; then
+ commentBlock="$commentBlock"$'\n'${LINE####}
+ fi
+ done
+ #If we make it out here, we hit the end of the file
+ if [[ $commentBlock ]] ; then
+ #If there is a comment block started, then it never ended
+ [[ $QUIET -lt 2 ]] && print_error "Unfinished comment block:"
+ [[ $QUIET -lt 2 ]] && print_error "$commentBlock"
+ return 1
+ else
+ return 2
+ fi
+}
+
+
+#-----------------------
+## Parses the comments from stdin. Also reads the (non-commented)
+## function name. Mostly uses <@function parse_block> and
+## <@function output_parsed_block> to do the read work.
+## @Stdin Reads line after comment block
+## @Globals paramDesc, retDesc, desc, block, split, out_comment_block
+#-----------------------
+function parse_comments()
+{
+
+ #We use a lot of $( echo ... ) in here to trim the blanks
+
+ local funcLine funcName
+ paramDesc=()
+ retDesc=()
+ local FIRST_BLOCK="yes"
+ local skipRead
+ local outBlock=""
+ local lastOutBlock=""
+ srcLine=0
+ # 1 = function
+ # 2 = variable
+ itemtype=0
+ while true ; do
+ paramNames=()
+ paramDesc=()
+ split=()
+ retDesc=()
+ desc=""
+ itemtype=0
+ unset out_comment_block
+ get_comment_block
+ [[ $? -gt 0 ]] && break
+ block="$out_comment_block"
+
+ if [[ $skipRead ]] ; then
+ skipRead=""
+ else
+ funcLine=""
+ funcName=""
+ read funcLine
+ fi
+ # Is it a (global) variable?
+ # Check before function to catch arrays.
+ if [[ ${funcLine} =~ ^(declare -r +)?([a-zA-Z_][a-zA-Z0-9_]*)=.+$ ]]; then
+ varName="${BASH_REMATCH[@]: -1}"
+ itemtype=2
+ # Is it a function?
+ elif [[ ${funcLine%%[[:blank:]]*} == function ]] || [[ ${funcLine} =~ ^[^\ ]+\ *\(\)\ *\{?$ ]]; then
+ funcName=$( echo ${funcLine#function} )
+ funcName=$( echo ${funcName%%()*} )
+ itemtype=1
+ fi
+ if [[ $funcName ]] || [[ $varName ]] || [[ $FIRST_BLOCK ]] ; then
+ # Only bother with this block if it is a function block or
+ # the first script block
+
+ #This fills in paramDesc[*], tag_*, retDesc
+ parse_block
+ lastOutBlock="$outBlock"
+ outBlock=$(output_parsed_block)
+
+ if [[ $FIRST_BLOCK ]] && [[ ! $funcName ]] && [[ ! $varName ]]; then
+ FIRST_BLOCK=""
+ fi
+
+ if [[ $EXCLUSIVE ]] ; then
+ # If this is first block, include it anyway.
+ if [[ $funcName ]] || [[ $varName ]]; then
+ local i="tag_${EXCLUSIVE}"
+ if [[ ${!i} != $EXCLUSIVE_VAL ]] ; then
+ if [[ $itemtype = 2 ]]; then
+ funcName="$varName"
+ fi
+ print_debug "$funcName block ignored, no $EXCLUSIVE=$EXCLUSIVE_VAL tag."
+ # Code duplication but hard to avoid
+ for i in ${!tag_*} ; do
+ unset $i
+ done
+ continue
+ fi
+ fi
+ fi
+
+ for i in ${!tag_*} ; do
+ unset $i
+ done
+
+ if [[ $funcName ]]; then
+ FUNC_LIST="$FUNC_LIST $funcName"
+ elif [[ $varName ]]; then
+ VAR_LIST="$VAR_LIST $varName"
+ fi
+ unset funcName varName
+ echo "$outBlock"
+
+ else
+ [[ $QUIET -lt 2 ]] && print_warn "Ignoring non-first non-function/variable comment block"
+ [[ $QUIET -lt 1 ]] && print_warn "$block"
+ fi
+ done
+}
+
+#---------------------
+## Create HTML from the non-special tags
+## @param var or func (is this for a variable or function)
+## @Stdout HTMLized tags
+#---------------------
+function output_parsed_tags() {
+ local i
+ for i in ${!tag_*} ; do
+ # Convert _ in tags to space. Looks better.
+ echo " <h3 class=\"othertag ${1}othertag ${i/tag_/tag-}\">$(sed 's/_/ /g' <<< "${i#tag_}")</h3>"
+ # This may be fun, allow special formatting by tag.
+ echo " <p class=\"othertag ${1}othertag ${i/tag_/tag-}\">"
+ echo " ${!i}"
+ echo " </p>"
+ unset $i
+ done
+}
+
+#---------------------
+## Outputs the parsed information in a nice pretty format.
+## @Stdout formated documentation
+## @Globals paramDesc, retDesc, desc, block, split
+#---------------------
+function output_parsed_block()
+{
+ echo "<hr />"
+ if [[ $itemtype -eq 1 ]] && [[ $funcName ]]; then
+ echo "<!-- Block for $funcName -->"
+ echo " <h2 id=\"$funcName\" class=\"function\">function <strong>$funcName</strong>()</h2>"
+ echo " <h3>Parameters:</h3>"
+ echo " <ul class=\"paramerters\">"
+ if [[ ${#paramDesc[*]} -gt 0 ]] ; then
+ for(( i=0; i<"${#paramDesc[@]}"; i++ )) ; do
+ echo " <li class=\"paramerters\">\$$[i+1]: ${paramDesc[i]}</li>"
+ done
+ else
+ echo "<li>None</li>"
+ fi
+ echo " </ul>"
+ if [[ ${#retDesc[*]} -gt 0 ]] ; then
+ echo " <h3>Returns:</h3>"
+ echo " <ul class=\"returns\">"
+ for(( i=0; i<"${#retDesc[@]}"; i++ )) ; do
+ echo " <li class=\"returns\">${retDesc[i]}</li>"
+ done
+ echo " </ul>"
+ fi
+
+ output_parsed_tags func
+ [[ $desc ]] && echo "<h3>Description</h3><p class=\"description funcdescription\">$desc</p>"
+ elif [[ $itemtype -eq 2 ]]; then
+ echo "<!-- Block for $varName -->"
+ echo " <h2 id=\"$varName\" class=\"variable\">variable <strong>$varName</strong></h2>"
+ output_parsed_tags var
+ [[ $desc ]] && echo "<h3>Description</h3><p class=\"description vardescription\">$desc</p>"
+ else
+ echo '<!-- Header for whole script -->'
+ echo "<h1>$FILE</h1>"
+ echo " <p class=\"filedescription\">$desc</p>"
+ echo "$desc" >> $SCRIPT_DESC
+
+ for i in ${!tag_*} ; do
+ echo " <h3 class=\"fileothertag ${i/tag_/tag-}\">${i#tag_}</h3>"
+ echo " <p class=\"fileothertag ${i/tag_/tag-}\">${!i}</p>"
+ unset $i
+ done
+ fi
+
+}
+
+#---------------
+## Does the real work of the parsing. Tags start with @. Special
+## tags are @return and @param. Doc lines without a tag are
+## considered description.
+## @Globals paramDesc, retDesc, desc, block, split
+#---------------
+function parse_block()
+{
+ local tag
+ local backIFS="$IFS"
+ IFS=$'\n'
+ for LINE in $block; do
+ IFS="$backIFS"
+ LINE=$( echo $LINE )
+ if [[ ${LINE:0:1} == '@' ]] ; then
+ split_tag split $LINE
+ case ${split} in
+ @param)
+ #paramNames[${#paramNames[*]}]=${split[1]}
+ paramDesc=( "${paramDesc[@]}" "${split[1]}" )
+ ;;
+ @return)
+ retDesc=( "${retDesc[@]}" "${split[1]}" )
+ ;;
+ @*)
+ tag=${split[0]#@}
+ local i="tag_${tag}"
+ if [[ ${!i} ]] ; then
+ local varname="tag_${tag}"
+ eval "tag_${tag}=\"\${!varname}"$'\n'"\${split[1]}\""
+ else
+ eval "tag_${tag}=\"\${split[1]}\""
+ fi
+ ;;
+ *)
+ print_error "We shouldn't get here... it was a tag, but not a tag?"
+ ;;
+ esac
+ else
+ desc="$desc"$'\n'"$LINE"
+ fi
+ done
+ IFS="$backIFS"
+}
+
+#----------------
+## Splits a line that starts with a tag into tag and data.
+## @param Variable you want the result put into. Array is format is ( tag, data ).
+## @param Tag
+## @param Data
+## @Globals The variable in $1 will get the results
+#----------------
+function split_tag()
+{
+ local out="${1}" ; shift
+ local tag=$( echo ${1} ) ; shift
+# local key=$( echo ${1} ) ; shift
+ local value=$( echo $* )
+ eval "$out=( \"\$tag\" \"\${value}\" )"
+}
+
+#--------------------
+## Outputs a header for script pages
+## @Stdout html header
+## @param Script name
+#--------------------
+function script_header()
+{
+cat <<- EOF > $OUT_FILE
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ $HEADERS
+ <title>$1 - $PROJECT</title>
+ </head>
+ <body>
+ <p class="right">
+ <a href="script_list.html">Script Index</a>
+ </p>
+EOF
+}
+
+# Initialise project variables
+OUT_DIR=$( dirname $0 )
+NOCSS=0
+args "$@"
+shift $?
+[[ $OUT_DIR ]] || OUT_DIR="."
+
+# Create output directory in case it doesn't exist
+mkdir -p "$OUT_DIR" || {
+ print_error "Failed to create output directory."
+ exit 1
+}
+
+if [[ $NOCSS = 0 ]]; then
+ print_info "Writing CSS"
+ # Copy stylesheet to output directory.
+ cat <<- EOF > "${OUT_DIR}/style.css"
+ /* Based on Trac CSS */
+ body {
+ background: #fff;
+ color: #000;
+ margin: 10px;
+ padding: 0;
+ }
+ body, th, td {
+ font: normal 13px verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;
+ }
+ h1, h2, h3, h4 {
+ font-family: arial,verdana,'Bitstream Vera Sans',helvetica,sans-serif;
+ font-weight: bold;
+ letter-spacing: -0.018em;
+ }
+ h1 { font-size: 19px; margin: .15em 1em 0 0 }
+ h2 { font-size: 16px; font-weight: normal; }
+ h3 { font-size: 14px }
+ hr { border: none; border-top: 1px solid #ccb; margin: 2em 0 }
+ address { font-style: normal }
+ img { border: none }
+ tt { white-space: pre }
+ :link, :visited {
+ text-decoration: none;
+ color: #b00;
+ border-bottom: 1px dotted #bbb;
+ }
+ :link:hover, :visited:hover {
+ background-color: #eee;
+ color: #555;
+ }
+ h1 :link, h1 :visited ,h2 :link, h2 :visited, h3 :link, h3 :visited,
+ h4 :link, h4 :visited, h5 :link, h5 :visited, h6 :link, h6 :visited {
+ color: inherit;
+ }
+ /* Partly own stuff: */
+ .nav body {
+ margin: 0;
+ padding: 0;
+ background: inherit;
+ color: inherit;
+ }
+ .nav ul { font-size: 11px; list-style: none; margin: 0; padding: 0; text-align: left }
+ .nav li {
+ display: block;
+ padding: 0;
+ margin: 0;
+ white-space: nowrap;
+ }
+ /* Own stuff */
+ .nav-header {
+ font-weight: bold;
+ }
+ .right { text-align: right }
+ .tag-Deprecated { color: #e00; }
+ EOF
+else
+ print_warn "Not writing a stylesheet. You will need to add your own by hand afterwards."
+fi
+
+while [[ $# -gt 0 ]] ; do
+
+ #Initialise vars for this src
+ FILE=$1
+ [[ ! -f $FILE ]] || [[ ! -r $FILE ]] && {
+ print_error "$FILE is not a file or is not readable, skipping."
+ shift
+ continue
+ }
+ print_info "Parsing $FILE"
+ shift
+ OUT_FILE=${FILE#/} #Remove leading /
+ OUT_FILE="$OUT_DIR/${OUT_FILE//\//.}.html"
+ FUNC_FILE="${OUT_FILE%.html}.funcs"
+ VAR_FILE="${OUT_FILE%.html}.vars"
+ SCRIPT_DESC="${OUT_FILE%.html}.desc"
+ # Store real name (reuse in script list)
+ REAL_NAME_FILE="${OUT_FILE%.html}.name"
+ echo -n "${FILE#/}" > "$REAL_NAME_FILE"
+
+ FUNC_LIST=""
+ VAR_LIST=""
+
+ #Start this src's html file
+ script_header "$FILE"
+
+ # Parse and write out function list
+ {
+ parse_comments < $FILE
+ echo "$FUNC_LIST" > $FUNC_FILE
+ echo "$VAR_LIST" > $VAR_FILE
+ # Convert references like <@function file,functioname> into links
+ } | sed -e 's!<@[[:blank:]]*function \([^,>]*\)[[:blank:]]*>!<a href="#\1">\1</a>!g' \
+ -e 's!<@[[:blank:]]*function \([^,>]*\),[[:blank:]]*\([^>]*\)[[:blank:]]*>!<a href="\1#\2">\1</a>!g' >> $OUT_FILE
+ #Close off the html for this src
+ cat <<- EOF >> $OUT_FILE
+ </body>
+ </html>
+ EOF
+
+done #Go on to next src
+
+#Now for tying the scripts all together
+pushd $OUT_DIR >/dev/null
+
+print_info "Writing function list"
+# Start page that will have all the function calls
+cat <<- EOF > function_list.html
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ $HEADERS
+ <title>Functions of $PROJECT</title>
+ </head>
+ <body class="nav">
+ <ul class="nav">
+EOF
+
+echo "<li class=\"nav nav-header\">Functions</li>" >> function_list.html
+# Merge function lists of all sources, sort by function name
+for i in *.funcs ; do
+ for f in $( cat $i ) ; do
+ echo "$f <li class=\"nav nav-function\"><a href=\"${i%.funcs}.html#$f\" target=\"main\">$f</a></li>"
+ done
+done | sort | cut -d' ' -f2- >> function_list.html
+
+echo "<li class=\"nav nav-header\">Variables</li>" >> function_list.html
+for i in *.vars ; do
+ for v in $( cat $i ) ; do
+ echo "$v <li class=\"nav nav-variable\"><a href=\"${i%.vars}.html#$v\" target=\"main\">$v</a></li>"
+ done
+done | sort | cut -d' ' -f2- >> function_list.html
+
+# Close off the html for the global function list
+cat <<- EOF >> function_list.html
+ </ul>
+ </body>
+</html>
+EOF
+
+print_info "Writing script list"
+# Start the list of scripts
+TITLE="Scripts"
+[[ $PROJECT ]] && TITLE="$PROJECT Script Documentation"
+cat <<- EOF > script_list.html
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ $HEADERS
+ <title>Scripts of $PROJECT</title>
+ </head>
+ <body>
+ <h1>$TITLE</h1>
+ <hr />
+ <dl>
+EOF
+
+# List all the sources + descriptions, sort by script dir/name
+for i in *.name ; do
+ name=${i%.name}
+ echo "${name} $(cat "$i")"
+done | sort | while read LINE realname; do
+ echo "<dt><a href=\"${LINE}.html\">$realname</a></dt>"
+ echo "<dd>"
+ cat ${LINE}.desc 2>/dev/null || { [[ $QUIET -lt 2 ]] && print_warn "$LINE has no description."; }
+ echo "</dd>"
+done >> script_list.html
+
+# Close off the html for the global script list
+cat <<- EOF >> script_list.html
+ </dl>
+ </body>
+</html>
+EOF
+
+print_info "Writing index file"
+# Create the index file for the whole shbang
+cat <<- EOF > index.html
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ $HEADERS
+ <title>BashDoc - $PROJECT</title>
+ </head>
+ <frameset cols="25%,*">
+ <frame src="function_list.html" name="function_list" />
+ <frame src="script_list.html" name="main" />
+ </frameset>
+</html>
+EOF
+
+# Remove the temporary .desc and .name files, leave the .func and .vars files, someone may want them later.
+rm *.desc
+rm *.name
+popd >/dev/null
diff --git a/tools/build_numerics.sh b/tools/build_numerics.sh
new file mode 100755
index 0000000..cb225a7
--- /dev/null
+++ b/tools/build_numerics.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an IRC bot in bash #
+# Copyright (C) 2007-2008 Arvid Norlander #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Generate list of numerics from the numerics.txt<br />
+## Output to STDOUT.<br />
+## Run this using make numerics in the main directory.
+#---------------------------------------------------------------------
+
+# Clean up env, just in case.
+unset LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY
+unset LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS
+unset LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION
+export LC_ALL=C
+export LANG=C
+
+cat << EOF
+#!/bin/bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an IRC bot in bash #
+# Copyright (C) 2007-2008 Arvid Norlander #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+# #
+###########################################################################
+
+###########################################################################
+# #
+# WARNING THIS FILE IS AUTOGENERATED. ANY CHANGES WILL BE OVERWRITTEN! #
+# See the source in tools/numerics.txt for comments about some numerics #
+# This file was generated with tools/build_numerics.sh #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Auto-generated list of numerics from tools/numerics.txt<br />
+## This file contains a list of numerics that we currently use.
+## It is therefore incomplete.<br />
+## Because the list of variables in this file is so long, please see
+## it's source for more details.
+#---------------------------------------------------------------------
+
+##########################
+# Name -> number mapping #
+##########################
+
+EOF
+# The numerics above are special case, otherwise bash strips leading 0.
+
+# Yes a bash file with .txt..
+source tools/numerics.txt || { echo 'Failed to source.' >&2; exit 1; }
+
+for index in ${!numeric[*]}; do
+ printf "numeric_%s='%03i'\n" "${numeric[$index]}" "$index"
+done
+
+# Same special case as above.
+cat << EOF
+
+##########################
+# Number -> name mapping #
+##########################
+
+EOF
+for index in ${!numeric[*]}; do
+ echo "numerics[$index]='${numeric[$index]}'"
+done
+
+cat << EOF
+
+# End of generated file.
+EOF
diff --git a/tools/numerics.txt b/tools/numerics.txt
new file mode 100644
index 0000000..1835bf6
--- /dev/null
+++ b/tools/numerics.txt
@@ -0,0 +1,215 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an irc bot in bash #
+# Copyright (C) 2007-2008 Arvid Norlander #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+# #
+###########################################################################
+# This file contains a list of numerics that we *currently use*.
+# It is therefore incomplete.
+
+# Sources:
+# RFC 1459
+# RFC 2812
+# http://www.alien.net.au/irc/irc2numerics.html
+# http://www.inspircd.org/wiki/List_Of_Numerics
+
+# These are from RFC 1459, if not mentioned otherwise
+
+##########################
+# Number -> name mapping #
+##########################
+
+# During connect, these are sent. They are NOT part of RFC 1459.
+# For some format of the parameters varies between servers.
+numeric[1]=RPL_WELCOME # "Welcome to <network>"
+numeric[2]=RPL_YOURHOST # "Your host is <servername>, running version <ver>"
+numeric[3]=RPL_CREATED
+numeric[4]=RPL_MYINFO # "<servername> <version> <available user modes> <available channel modes>"
+numeric[5]=RPL_ISUPPORT # Not in any RFC. See http://www.irc.org/tech_docs/005.html for incomplete list.
+
+numeric[6]=RPL_MAP # Not from any RFC
+numeric[7]=RPL_MAPEND # Not from any RFC
+numeric[8]=RPL_SNOMASK # Not from any RFC, used on Unreal
+
+# Command replies.
+numeric[205]=RPL_TRACEUSER
+numeric[213]=RPL_STATSCLINE
+numeric[219]=RPL_ENDOFSTATS
+numeric[221]=RPL_UMODEIS
+numeric[223]=RPL_STATSELINE # Not from any RFC. Conflicting use on different IRCds.
+numeric[232]=RPL_RULES # Unreal usage. Conflicting use on different IRCds.
+numeric[242]=RPL_STATSUPTIME
+numeric[250]=RPL_STATSCONN # Not from any RFC. Conflicting use on different IRCds.
+numeric[251]=RPL_LUSERCLIENT
+numeric[252]=RPL_LUSEROP
+numeric[253]=RPL_LUSERUNKNOWN
+numeric[254]=RPL_LUSERCHANNELS
+numeric[255]=RPL_LUSERME
+numeric[256]=RPL_ADMINME
+numeric[257]=RPL_ADMINLOC1
+numeric[258]=RPL_ADMINLOC2
+numeric[259]=RPL_ADMINEMAIL
+numeric[263]=RPL_TRYAGAIN
+numeric[265]=RPL_LOCALUSERS # Not from any RFC.
+numeric[266]=RPL_GLOBALUSERS # Not from any RFC.
+numeric[271]=RPL_SILELIST # Not from any RFC
+numeric[272]=RPL_ENDOFSILELIST # Not from any RFC
+
+numeric[301]=RPL_AWAY
+numeric[302]=RPL_USERHOST
+numeric[303]=RPL_ISON
+numeric[304]=RPL_TEXT # Not from any RFC I think. And on InspIRCd this is used for syntax hints.
+numeric[305]=RPL_UNAWAY
+numeric[306]=RPL_UNAWAY
+numeric[307]=RPL_WHOISREGNICK # Not from any RFC. Used on Unreal.
+numeric[308]=RPL_RULESSTART # Unreal usage. Conflicting use on different IRCds.
+numeric[309]=RPL_ENDOFRULES # Unreal usage. Conflicting use on different IRCds.
+numeric[310]=RPL_WHOISHELPOP # Unreal usage. Conflicting use on different IRCds.
+numeric[311]=RPL_WHOISUSER
+numeric[312]=RPL_WHOISSERVER
+numeric[313]=RPL_WHOISOPERATOR
+numeric[314]=RPL_WHOWASUSER
+numeric[315]=RPL_ENDOFWHO
+numeric[317]=RPL_WHOISIDLE
+numeric[318]=RPL_ENDOFWHOIS
+numeric[319]=RPL_WHOISCHANNELS
+numeric[320]=RPL_WHOISSPECIAL # Not from any RFC. Numeric called other things on other ircds.
+ # RPL_WHOISSPECIAL is what it is called on Unreal.
+ # Used for "connecting using ssl" on InspIRCd. Also used for SWHOIS.
+ # On hyperion used for "is identified to services".
+numeric[321]=RPL_LISTSTART
+numeric[322]=RPL_LIST
+numeric[323]=RPL_LISTEND
+numeric[324]=RPL_CHANNELMODEIS
+numeric[329]=RPL_CREATIONTIME # Not from any RFC. Used on InspIRCd at least.
+numeric[330]=RPL_WHOISACCOUNT # Not from any RFC. This is how it is used on InspIRCd with m_services_account.
+numeric[331]=RPL_NOTOPIC
+numeric[332]=RPL_TOPIC
+numeric[333]=RPL_TOPICWHOTIME # Not from any RFC.
+numeric[340]=RPL_USERIP # Not from any RFC.
+numeric[341]=RPL_INVITING
+numeric[346]=RPL_INVITELIST
+numeric[347]=RPL_ENDOFINVITELIST
+numeric[348]=RPL_EXCEPTLIST
+numeric[349]=RPL_ENDOFEXCEPTLIST
+numeric[351]=RPL_VERSION
+numeric[352]=RPL_WHOREPLY
+numeric[353]=RPL_NAMREPLY
+numeric[364]=RPL_LINKS
+numeric[365]=RPL_ENDOFLINKS
+numeric[366]=RPL_ENDOFNAMES
+numeric[367]=RPL_BANLIST
+numeric[368]=RPL_ENDOFBANLIST
+numeric[369]=RPL_ENDOFWHOWAS
+numeric[371]=RPL_INFO
+numeric[372]=RPL_MOTD
+numeric[374]=RPL_ENDOFINFO
+numeric[375]=RPL_MOTDSTART
+numeric[376]=RPL_ENDOFMOTD
+numeric[378]=RPL_WHOISHOST
+numeric[381]=RPL_YOUREOPER
+numeric[382]=RPL_REHASHING
+numeric[391]=RPL_TIME
+numeric[396]=RPL_HOSTHIDDEN # Not from any RFC.
+
+
+# Errors
+numeric[401]=ERR_NOSUCHNICK
+numeric[402]=ERR_NOSUCHSERVER
+numeric[403]=ERR_NOSUCHCHANNEL
+numeric[404]=ERR_CANNOTSENDTOCHAN
+numeric[405]=ERR_TOOMANYCHANNELS
+numeric[406]=ERR_WASNOSUCHNICK
+numeric[407]=ERR_TOOMANYTARGETS
+numeric[412]=ERR_NOTEXTTOSEND
+numeric[416]=ERR_TOOMANYMATCHES # Not from any RFC.
+numeric[421]=ERR_UNKNOWNCOMMAND
+numeric[422]=ERR_NOMOTD
+numeric[432]=ERR_ERRONEUSNICKNAME # Bad/forbidden nickname
+numeric[433]=ERR_NICKNAMEINUSE # Nick in use
+numeric[438]=ERR_NICKTOOFAST # Not from any RFC. Used on ircu and Unreal (at least).
+numeric[441]=ERR_USERNOTINCHANNEL
+numeric[442]=ERR_NOTONCHANNEL
+numeric[443]=ERR_USERONCHANNEL
+numeric[445]=ERR_SUMMONDISABLED # Yep, most (all?) do nowdays :)
+numeric[446]=ERR_USERSDISABLED # Yep, most (all?) do nowdays :)
+numeric[447]=ERR_NONICKCHANGE # Not from any RFC.
+numeric[460]=ERR_NOTFORHALFOPS # Not from any RFC. Unreal got this at least.
+numeric[461]=ERR_NEEDMOREPARAMS
+numeric[462]=ERR_ALREADYREGISTERED
+numeric[468]=ERR_ONLYSERVERSCANCHANGE # Not from any RFC.
+numeric[470]=ERR_LINKCHANNEL # Not from any RFC.
+ # InspIRCd example: :#channel has become full, so you are automatically being transferred to the linked channel #otherchannel
+numeric[471]=ERR_CHANNELISFULL
+numeric[472]=ERR_UNKNOWNMODE
+numeric[473]=ERR_INVITEONLYCHAN
+numeric[474]=ERR_BANNEDFROMCHAN
+numeric[475]=ERR_BADCHANNELKEY
+numeric[477]=ERR_NEEDREGGEDNICK # Not from any RFC.
+numeric[478]=ERR_BANLISTFULL
+numeric[480]=ERR_CANNOTKNOCK # Not from any RFC.
+numeric[481]=ERR_NOPRIVILEGES
+numeric[482]=ERR_CHANOPRIVSNEEDED
+numeric[484]=ERR_ATTACKDENY # Name on Unreal. No idea use on Unreal.
+ # InspIRCd: 484 <nick> <channel> :Can't kick user <nick> from channel (+Q set)
+numeric[489]=ERR_SECUREONLYCHAN # Not from any RFC. Used on Unreal and InspIRCd at least.
+numeric[490]=ERR_ALLMUSTUSESSL # InspIRCd specific numeric. I made up this name, I don't know correct name.
+ # 490 <nick> <channel> :all members of the channel must be connected via SSL
+numeric[491]=ERR_NOOPERHOST
+numeric[495]=ERR_NOREJOINONKICK # InspIRCd specific numeric. I made up this name, I don't know correct name.
+ # 495 <nick> <channel> :You cannot rejoin this channel yet after being kicked (+J)
+numeric[499]=ERR_CHANOWNPRIVNEEDED # Not from any RFC. Unreal got this at least.
+
+numeric[501]=ERR_UMODEUNKNOWNFLAG # Some send this for unknown umodes. not all.
+numeric[502]=ERR_USERSDONTMATCH # Trying to change mode for other user.
+
+# Others. Not from any RFC but semi standard.
+numeric[600]=RPL_LOGON # Unreal, InspIRCd and more
+numeric[601]=RPL_LOGOFF # Unreal, InspIRCd and more
+numeric[602]=RPL_WATCHOFF # Unreal, InspIRCd and more
+numeric[604]=RPL_NOWON # Unreal, InspIRCd and more
+numeric[605]=RPL_NOWOFF # Unreal, InspIRCd and more
+numeric[606]=RPL_WATCHLIST # Unreal, InspIRCd and more
+numeric[607]=RPL_ENDOFWATCHLIST # Unreal, InspIRCd and more
+
+numeric[671]=RPL_WHOISSECURE # Used on Unreal for ssl clients.
+
+
+# IRCd specific, these are InspIRCd ones unless said otherwise.
+# As we can't include more than one meaning for every numeric conflicting
+# ones may be added as comments. Modules depending on 9xx numerics should use the raw value.
+# As I mainly use InspIRCd I prioritize those. ;)
+numeric[900]=RPL_MODULES
+numeric[901]=RPL_ENDOFMODULES
+numeric[902]=RPL_COMMANDS # 902 <nick> :<command> <module name> <minimum parameters>
+numeric[903]=RPL_ENDOFCOMMANDS # 903 <nick> :End of COMMANDS list
+numeric[936]=ERR_CENSORED # 936 <nick> <channel> <word> :Your message contained a censored word, and was blocked
+numeric[937]=ERR_ALREDYCENSORED # 937 <nick> <channel> :The word %s is already on the spamfilter list
+numeric[938]=ERR_NOTCENSORED # 938 <nick> <channel> :No such spamfilter word is set
+numeric[939]=ERR_SPAMFILTERLISTFULL # 939 <nick> <channel> :Channel spamfilter list is full
+numeric[940]=RPL_ENDOFSPAMFILTER # 940 <nick> <channel> :End of channel spamfilter list
+numeric[941]=RPL_SPAMFILTER # 941 <nick> <channel> <spamfilter>
+numeric[942]=ERR_INVALIDNICK # 942 <nick> <nick> :Invalid user specified.
+numeric[950]=RPL_SILENCEREMOVED # 950 <nick> <nick> :Removed <nick>!*@* from silence list
+numeric[951]=RPL_SILENCEADDED # 951 <nick> <nick> :Added <nick>!*@* to silence list
+numeric[952]=ERR_ALREADYSILENCE # 952 <nick> <nick> :<nick> is already on your silence list
+numeric[972]=ERR_CANNOTDOCOMMAND # Unreal uses 972 (ERR_CANNOTDOCOMMAND) for umode +q, and other failed kicks.
+ # According to http://www.alien.net.au/irc/irc2numerics.html:
+ # "Works similarly to all of KineIRCd's CANNOT* numerics. This one indicates that a
+ # command could not be performed for an arbitrary reason. For example, a halfop trying to kick an op."
+numeric[974]=ERR_CANNOTCHANGECHANMODE # Unreal uses 974 (ERR_CANNOTCHANGECHANMODE ?) for ERR_ALLMUSTUSESSL.