# $Id: HACKING 777 2010-05-17 02:17:25Z slakmagik $
# vim:set ft=:

We welcome contributions to sbopkg.  If you have a bug report or a feature
request, please go to the project's Google Code site and use the 'Issue
Tracker' so your bug report/feature request does not get lost:
http://code.google.com/p/sbopkg/issues/list.  If you cannot post to the Issue
Tracker, please consider joining the sbopkg mailing list and post your bug
report or feature request there:
http://sbopkg.org/mailman/listinfo/sbopkg-users

As far as hacking on the code, the best thing to do is to checkout the
latest version from subversion (see http://www.sbopkg.org/devel.php) and then
contribute patches with something like 'diff -Naurp' or 'svn diff -x -p'.
Please try to make each patch do one thing and do it well.  Also, please do
not combine whitespace or other non-functional changes with functional changes
in the same patch (unless the same lines contain both types of changes).
Basically, just use common sense -- a one line functional change and a typo
correction can be a single patch, rather than two one-line patches.

Please make sure your patches conform to these stylistic points:

* Code in Bash.

* Wrap lines at 78 columns.

* Expand tabs to spaces.

* Indent with four spaces at all levels.

* Use '[[' wherever possible, vs. '['.

* Negate tests like '[[ ! foo ]]' instead of '! [[ foo ]]'.

* write functions in the form:

      my_func() {
          # comments here

          stuff
      }

* In general, variables do not need to be quoted except in cases where the
  variable may contain spaces.  If unsure, quote the variable just to be safe.

* Use variable names in the form:  MYVARNAME except when MYVARNAME is
  ambiguous or made of more than two or three components.  In that case, use
  MY_VAR_NAME.

* If you are going to need a bit of data repeatedly, try to grab it once and
  assign it to a variable rather than re-obtaining it.

* If you are going to use a combination of several concatenated variables
  multiple times, consider creating a new variable like:
  'NEWVAR=$OLDVAR1-$OLDVAR2-$OLDVAR3'.

* Prefer the style:

      if [[ foo ]]; then
          bar
      fi

  instead of:

      if [[ foo ]]
      then
          bar
      fi

  (same goes with 'for' and 'while' loops).

* The spacing in numeric 'for' loops is:

      for ((i=0; i<=10; i++)); do

* Prefer shell redirection to piping 'echo' or 'cat'.

* Prefer bash variable substitutions to 'tr', 'sed', 'cut', ..., when
  possible.

* Error messages should go to standard error:

      echo "Things have gone nuts" >&2

* Make return codes meaningful (i.e. if you redirect to stderr try
  to return or exit 1 at the same time).

* When both 'foo' is simple and 'bar' is a one-liner, the conditional form:

      [[ foo ]] && bar

  can be used instead of:

      if [[ foo ]]; then
          bar
      fi

  However, do not use the following form:

      if [[ foo ]]; then bar; fi

* Use:

      [[ foo ]] || bar

  only when 'bar' is simple and supposed to be executed on error conditions
  (i.e. almost never)

* Multiple conditionals can be done either as:

  if [[ $CHOICE == 1 ]] || [[ $CHOICE == 0 && -z $CUSTOMOPTS ]]; then

  or

  if [[ $CHOICE == 1 || ( $CHOICE == 0 && -z $CUSTOMOPTS ) ]]; then

  but not:

  if [ $CHOICE = 1 ] || [ $CHOICE = 0 -a "$CUSTOMOPTS" = "" ]; then

  The reasons the third example is not as good as the first two are that it
  uses single brackets instead of double brackets and uses '-a' instead of
  '&&'.

* 'case' statements should be indented as:

    case $FOO in
        bar ) # Comment goes here
            commands
            ;;
        baz* ) # Comment goes here
            commands
            ;;
    esac

  unless the statements can be short one-liners, in which case the form

    case $FOO in
        bar ) short_simple_command ;;
        baz* ) simple_short_command; exit ;;
    esac

  is preferred.

* Avoid chaining commands with ';' (with the above exceptions).

* Declare local variables as such at the function start.

* Positional parameters to functions should be assigned to local variables,
  one per 'local' statement, before declaring the other local variables (which
  can share a single 'local' statement):

    local FILE="$1"
    local DIR="$2"
    local FOO BAR BAZ

* In general, when wrapping long lines, the part going on the next line should
  be indented with 8 spaces if there is ambiguity so as to distinguish the
  wrap from other lines before and after it.  The same would be true for line
  wraps in conditions.  For example:

    if ASD ||
            FGH; then
        echo "Success"
    fi

  as opposed to:

    if ASD ||
        FGH; then
        echo "Success"
    fi

  In the latter case, having 'FGH; then' at the same indent level as the echo
  is ambiguous.  On the other hand:

    APP=$(grep foo \
        really/long/path/to/file)
    if foo; then
        echo "Success"
    fi

  is ok since there really is no ambiguity.

* Prefer 'foo | bar' over 'foo |bar' or 'foo|bar'.  However, if the line
  barely goes over 78 columns, then removing spaces is OK to keep it on a
  single line.  In other words:

    foo |bar |baz

  is better than

    foo | bar |
            baz

* When wrapping between two piped commands, the pipe should be the last
  character of the former line.  For example, prefer:

    some stuff here foo |
        bar

  instead of:

    some stuff here foo \
        | bar

  when possible.

* Always use $( ... ) instead of ` ... `.

* 'Break' and 'continue' should never be used to influence a loop outside of
  the function they belong to.

* Avoid indirect recursion (A calls B that calls A).

* [[ -z "$VAR" ]] vs. [[ ! "$VAR" ]] and [[ "$VAR" ]] vs. [[ -n "$VAR" ]]:
  -n/-z should be used when $VAR contains a computational result and the other
  form should be used where $VAR is a functional flag.  For example:

    VAR=$(grep "^something=" <$SBOPKG_RENAMES)
    if [[ -z $VAR ]]; then

    and

    if [[ $DIAG ]]; then

* For indices, use FILE and DIR instead of 'f' and 'd'.  However, 'i' is OK as
  a counter since that is fairly universal.

* When deciding whether or not to use the =~ operator in [[ commands, make
  sure that they work across bash 3.1, 3.2, and 4.0. This means the regexes
  must be unquoted for bash >=3.2 and still work in bash 3.1 (i.e., no
  'foo|bar' expressions).
