• To understand recursion, you first need to understand recursion (and Jo

    From Rainer Weikusat@21:1/5 to All on Mon Feb 5 15:37:48 2024
    Debian (and derived distros) use a system called Debconf for prompting
    users for configuration information during package installation. In the advanced section, the manpage suggests that config scripts should support moving backwards through multiple question so that users can fix mistakes
    and then states

    There are several ways to write the control structures of your
    program so it can jump back to previous questions when
    necessary. You can write goto-laden spaghetti code. Or you can
    create several functions and use recursion. But perhaps the
    cleanest and easiest way is to construct a state machine. Here is
    a skeleton of a state machine that you can fill out and expand.

    This is followed by a 40 line code example using case (Bourne shell) to implement a form of computed goto in a loop with lots of explicit state handling and switching code.

    Considering the problem, there's a set of questions which needs to be
    asked in order. If a user OKs an answer, the next question should be
    asked, if he cancels it, the previous question should be asked
    again. This absolutely cries for a recursive solution and there's a
    really simple and general one which needs much less code than the
    example in the manpage.

    First, define a helper function for actually asking a question:

    ask()
    {
    db_input high "$PREFIX/$1"
    db_go
    }

    Given that, a function for asking a set of question which can back up to
    the previous one can be written as

    ask_all()
    ( # run in forked subshell so that variables are local

    # termination condition: called w/ no argumnets,
    # ergo, nothing to do, return success
    test "$1" || return 0

    # remove our question from argument list
    q="$1"
    shift

    while true;
    do
    # ask question, return failure on failure (2 arbitrary)
    ask "$q" || return 2

    # invoke ask_all again to ask remaining question, return success on success
    ask_all "$@" && return 0
    done
    )

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Geoff Clare@21:1/5 to Rainer Weikusat on Tue Feb 6 13:47:17 2024
    Rainer Weikusat wrote:

    # termination condition: called w/ no argumnets,
    # ergo, nothing to do, return success
    test "$1" || return 0

    Nit-pick: the comment doesn't match the code. Should be either:

    # termination condition: called w/ no arguments,
    # ergo, nothing to do, return success
    test "$#" -eq 0 || return 0

    or:

    # termination condition: called w/ no arguments or with an
    # empty first argument, ergo, nothing to do, return success
    test "$1" || return 0

    In the latter case I would also usually use test -n "$1" just in
    case it ever gets run with a version of test that doesn't follow
    the POSIX single-argument rule correctly. (I believe pre-POSIX
    Bourne shells when given test "!" would produce an error complaining
    of a missing argument.)

    --
    Geoff Clare <netnews@gclare.org.uk>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Geoff Clare@21:1/5 to Geoff Clare on Tue Feb 6 14:28:51 2024
    Geoff Clare wrote:

    # termination condition: called w/ no arguments,
    # ergo, nothing to do, return success
    test "$#" -eq 0 || return 0

    What's that law about posts pointing out mistakes always containing
    a mistake?

    I failed to notice the new test has the logic the other way round
    from test "$1". So it should be:

    test "$#" -eq 0 && return 0

    or:

    test "$#" -ne 0 || return 0

    --
    Geoff Clare <netnews@gclare.org.uk>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Geoff Clare on Tue Feb 6 16:41:38 2024
    Geoff Clare <geoff@clare.See-My-Signature.invalid> writes:
    Rainer Weikusat wrote:

    # termination condition: called w/ no argumnets,
    # ergo, nothing to do, return success
    test "$1" || return 0

    Nit-pick: the comment doesn't match the code. Should be either:

    # termination condition: called w/ no arguments,
    # ergo, nothing to do, return success
    test "$#" -eq 0 || return 0

    or:

    # termination condition: called w/ no arguments or with an
    # empty first argument, ergo, nothing to do, return success
    test "$1" || return 0

    In theory, that's correct. In practice, passing empty arguments to this functions serves no useful purpose, hence, that's something the calling
    code isn't supposed to do. I've also just inserted the comments to
    explain the example, they're not in the actual code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)