######################################################
### framework.sh

Framework is the main library of shell functions and run-time and environment variables needed by many of the scripts in the bgscripts and bgscripts-core packages.

Only functions that provide external value will be described in this document.

#### BEHAVIOR

 --fcheck
Outputs the version number of framework and exits.

#### FUNCTIONS

##### getval
Getval is used during the parameter parsing to grab the next positional parameter.
Examples:
case ${flag} in
   "c" | "conf" | "conffile" | "config" ) getval; conffile="${tempval}";;
esac
This snippet is from the parseFlag() section of the template. If you call the template script with a -c flag:
./ftemplate.sh -c /etc/special.conf
The /etc/special.conf will be read by getval, and here it will be assigned to $conffile.

##### debuglev
Debuglev returns true if the debug level is equal to or higher than the called number.

If your script was called with:
./myscript.sh -d 5
Then the debug level is set to 5. You could write an expression:
debuglev 4 && echo "Debug level is 4 or higher."
This command would then execute, and the same is true for ./myscript.sh -d 4.
It will skip the echo if you called ./myscript.sh -d 3.

You can use the logical NOT operator, the exclamation mark ! to invert the operation.
If your script was called with:
./myscript.sh -d 6
And your logic includes:
! debuglev 6 && echo "Debugging is set to level 5 or below."
It will not display the message.

##### fisnum
Framework, is number.
Call fisnum:
fisnum $1 && echo "$1 is a number!"

The logic was shared on Stack Overflow years ago. Basically if anything in the string is not a numeral from 0 to 9, then the function returns false.

Examples:
a=fish
fisnum $a && echo "Can do addition with $a."
! fisnum $a && echo "How do you expect to perform arithmetic with ${a}?" && exit 1

b=5
fisnum $b && echo "Thank you for providing a number for variable ${b}."

##### Fistruthy
Framework; is truthy.

If a variable contains a 'yes,' '1,' 'y,' 'true,' or 'always,' then return true. Otherwise, return false.

Comparing a given variable to a truthy value is needed all the time in writing scripts. Unifying the logic into a single function reduces the need to rewrite code.

Examples:
a=7.5
fistruthy "${a}" && echo "This will not appear because 7.5 does not fit in the bounds of a 'true' value, for the purposes of the function."

b=True
fistruthy "${b}" && echo "This will appear."

##### setval
   # call: setval 0 value1 value2 value3 ... <<EOFOPTIONS
   # /bin/foo1 --optforfoo1
   # /usr/bin/foo2 --optforfoo2
   # EOFOPTIONS
   #              ^ 0 = soft fail, 1 = critical-fail

Use setval to search for a file and set any extra options based on which file it finds.

Examples:
setval 0 backupscript bup_option1 bup_option2 bup_option3 <<EOFOPTIONS
/usr/bin/backupscript.sh -l -t -f
/usr/bin/oldbup.sh --long --title
/usr/bin/rsync -avz --ignore-missing
EOFOPTIONS
If it finds /usr/bin/backupscript.sh, then it will set $backupscript to /usr/bin/backupscript.sh, bup_option1 to "-l," bup_option2 to "-t" et al.
The 0 means it will set the value of $backupscript to "fail" if it cannot find any of the listed items. If the value is a 1, then the $backupscript will be set to "critical-fail." It is expected that the script will check for these values and respond accordingly.

##### flecho
Framework log echo.
This version attempts to combine the lecho (log echo) and plecho (pipe log echo) options into one shell function.
It tries to read stdin and if it finds any, it will apply the log echo function to the stream.
It also takes any parameters and adds those to the output.

Examples:
cat file1 | flecho "this string is prepended"

##### convert_to_seq
Convert to sequence.
Takes parameters and converts comma-separated numbers and sets of numbers and turns it all into space-delimited sequence.

Examples:
convert_to_seq '1,4-7,55'
1 4 5 6 7 55
convert_to_seq '25,8,15-20'
25 8 15 16 17 18 19 20

##### fsudo
Framework sudo. Simply find and execute sudo with all parameters passed to it.

##### fwhich
Framework which.
Returns the fully qualified file path of the passed filename. It simply executes:

    readlink -f "$@"

##### ferror
Framework error
Print parameters to standard error. It simply executes:

    echo "$@" 1>&2

##### prepend
Prepends the parameters to the stream.
Example:
cat file | prepend "But first... "

##### append
Appends the parameters to the stream.
Example:
cat file | append " x 100!"

##### setdebug
Sets the debug level. This function integrates tightly with the parseFlag() section of the ftemplate file.

Setdebug should be used in the parseFlag() function like:
case ${flag} in
   "d" | "debug" | "DEBUG" | "dd" ) setdebug; ferror "debug level ${debug}";;
esac

##### isvalidip
Checks if the parameter is a valid IPv4 address.
# call: isvalidip ${input} && echo yes

##### getconf
Reads the file as a parameter and finds all variables in it that are not yet defined in the current environment and then evaluates them.
This function was designed to work with the Unix-like behaviors of using environment variables and simple config files.

Examples:
Take example.conf:
EXAMPLE_STRING="muffin"
EXAMPLE_PHRASE="flashy spreadsheets"

With a variable already defined of EXAMPLE_STRING=cheesesticks, the function:
get_conf example.conf
Will add to the environment the value EXAMPLE_PHRASE="flashy spreadsheets."

##### define_if_new
# call: define_if_new IFW_IN_LOG_FILE "/var/log/messages"
If the first parameter evaluates to null string, then define the first parameter with a value of the second parameter.

Examples:
define_if_new LOG_FILE=/var/log/application.log

##### fchmodref
# call: fchmodref "${oldfile}" "${newfile}"
FreeBSD does not provide chmod --reference 'oldfile' 'newfile', so this function wraps that feature into a function. On Linux, this function passes through to chmod --reference, albeit with no additional parameters.

#### VARIABLES
today
now
server
thistty
thisip
thisos
thisflavor
thisflavorversion
scriptdir
scriptfile
scripttrim
thisppid
cronpid
is_cronjob
stdin_piped
stdout_piped
stderr_piped
stdin_local
is_root

######################################################
### ftemplate.sh

#### BEHAVIOR

Ftemplate is the template file for a new shell script. It is copied and modified by the newscript.sh script.

This is a template. Feel free to modify/delete any portions to suit your needs. Use it to get your work done as you see fit. Do not feel bound by any limitations present in the template; just make it work the way you need it to.

It calls framework in a dynamic way:
# DETERMINE LOCATION OF FRAMEWORK
f_needed=20171111
while read flocation ; do if test -e ${flocation} ; then __thisfver="$( sh ${flocation} --fcheck 2>/dev/null )" ; if test ${__thisfver} -ge ${f_needed} ; then frameworkscript="${flocation}" ; break; else printf "Obsolete: %s %s\n" "${flocation}" "${__this_fver}" 1>&2 ; fi ; fi ; done <<EOFLOCATIONS
./framework.sh
${scriptdir}/framework.sh
$HOME/bin/bgscripts/framework.sh
$HOME/bin/framework.sh
$HOME/bgscripts/framework.sh
$HOME/framework.sh
/usr/local/bin/bgscripts/framework.sh
/usr/local/bin/framework.sh
/usr/bin/bgscripts/framework.sh
/usr/bin/framework.sh
/bin/bgscripts/framework.sh
/usr/local/share/bgscripts/framework.sh
/usr/share/bgscripts/framework.sh
/usr/libexec/bgscripts/framework.sh
EOFLOCATIONS
test -z "${frameworkscript}" && echo "$0: framework not found. Aborted." 1>&2 && exit 4

The provided list of filenames is what the script searches for. As soon as it finds an executable file, that returns a version number greater than or equal to the number specified, then it will assign that as the library location and exit the loop.

The list of filenames can be modified to suit your purpose. If framework is being embedded in a custom location or package, you can add its full path to this list.



######################################################
### newscriptsh
