Code content
============

Be aware of the `librelib(7)` library suite, which lives `src/lib`.
It is a suite of Bash libraries that will help you out.  Most of the
people looking at the libretools code are familiar with the `messages`
part of it, which actually contains a bunch of utility routines, not
just message printing.  There is also a library for dealing with
`blacklist.txt`, and one for loading configuration files and
PKGBUILDs.  These are common tasks, but are tricky to handle
consistently--the libraries are there to make things easier.  Take a
look at the man pages.

Message printing: All of the message printing routines, except for
`term_title` and `flag`,  take printf-type arguments.  Take advantage
of that; don't use string interpolation (don't do `"foo ${var}
bar"`).  The reason for this is that if you don't do string
interpolation, messages can be automatically internationalized.
(Internationalization is incomplete at the momement)

Message printing: The in `--help`/`-h` text, use `print` to print
lines that should not wrap, `echo` to print blank lines, `prose` to
print paragraphs, `bullet` to print bullet points, and `flag` to print
option flags.  The text should follow this general format:

    print "Usage: %s [OPTIONS] VARS_ARE_UNDERSCORE_AND_CAPITAL" "${program_name}"
	print "One line description of program, no period"
	echo
	prose "More details.  This is a paragraph."
	echo
	print "Options:"
	flag  "-h"         "Show this message"

In the "Usage:" line, use printf `%s` and the value `"${0##*/}"` to
determine the program name at runtime.

There used to be guidelines for how to align the option flags and
descriptions, but now the `flag` command exists takes care of it for
you.  Yay for things being easier!

When using `set -u`, `set -e`, or `trap`, you should also use `set -E`
to have the error handling be passed down to subshells.

Feel free to use `set -e` (fail on error), but be careful of the
caveats (there are a bunch of them); don't assume all errors are
checked because of it.

Use `set -u` if you can; it makes using an unset variable an error.
 - If a variable not being set is valid (perhaps a configuration
   option), use `${var:-}` when accessing it to suppress the error.
 - An empty array counts as unset, so if you have an array that may be
   empty, use `set +u` before accessing it.
   - The reason for this is that a normal string variable is basically
     an array with length=1; an unset variable looks like an array
     with length=0.  Weird stuff.

In the shebang, use `#!/usr/bin/env bash`.  This allows us to not
hardcode the location of bash (I'm not sure why this is useful for
something distro-dependent like libretools, but fauno seems to have a
use-case for it).

In the shebang, don't pass flags to bash, besides breaking `env`
(above), it means people will make mistakes when debugging, and
running things with `bash FILENAME`.  Instead, use `set` to adjust the
flags inside of the program.

Obey `$TMPDIR`.  It's usually as easy as passing `--tmpdir` to
`mktemp`.

Use `trap` to clean up your temporary files.  This way, even if your
program terminates early, things will be cleaned up.

Bash best practices
===================

Basically, know what you are doing, and be safe with it.  The problem
is that most people don't know about safe bash scripting.

A lot of people look at the "Advanced Bash Scripting" ebook--DO NOT do
that, it is trash... though it contains a "reference card" page that
may be useful and isn't trash.

Take a look at Gentoo's Bash guidelines
<http://devmanual.gentoo.org/tools-reference/bash/index.html>.
They're pretty good, and cover most of the "gotcha's" about Bash
syntax.  It mentions but discourages the use of Bash 3
features... why?  Who still uses Bash 2?  Feel free to use Bash 4
features!

I wrote an article on Bash arrays
<https://lukeshu.com/blog/bash-arrays.html>.  A lot of people think
they're tricky, but they're simple once you know how they work.  It's
short enough that you should read the whole thing.  Know the
difference between `"${array[@]}"` and `"${array[*]}"`.  And I'll say
it again here, ALWAYS wrap those in double quotes; there is no reason
I can think of that the unquoted behavior would ever be the correct
thing.

My brief rules of thumb:

 - Quote every variable.
   - That includes arrays: `"${array[@]}"` and `"${array[*]}"`.
   - In most (but not all!) cases inside of `[[ ... ]]` conditions,
     variables don't need to be quoted.  When in doubt, quote them.
   - When assigning one variable to another, you don't need quotes;
     you don't need quotes for `foo=$bar`
 - Try to avoid global variables; declare all variables in functions
   with `local`.
   - Or `declare`; inside of a function, unless you pass the `-g`
     flag, `declare` makes the variable local.
 - Use `local VAR` before a `for VAR in LIST` loop--the variable is created in the
   current scope, not the scope of the loop.
 - Feeding input to `while` loops is weird because of how subshells
   work:

	# Input from a file
	# BAD
	cat file | while read line; do
		...
	done
	# GOOD
	while read line; do
		...
	done <file

	# Input from a program
	# BAD
	prog | while read line; do
		...
	done
	# GOOD
	while read line; do
		...
	done < <(prog)