GUIDE to the SAM Distribution

# GUIDE
# Copyright (C) 2025 Joseph Rosevear, San Diego CA, USA.

# This file is part of a distribution SAM.

# SAM 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.

# SAM 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/>.



1.  Information about SAM that is online.

2.  Informative files in this distribution.

3.  What is this?

4.  Some terminology.

5.  Installing SAM.

6.  Running SAM.

7.  Using SAM.

8. SAM menus.

9. The SAM prompt.

10.  File menu.dat and the menu command.

11. Using libraries.

12. Using $init with libraries.

13. Weird uses of bound.

14. Nested invocations of begin, bree and breekit.

15. Quoted tasks.

16.  Special variables.

17.  There is a nuisance you may encounter.

18. SAM's temporary and scratch directories.

19. Shells used.

20. SAM's synthetic shell.

21. Batch mode.

22. Bugs in SAM.

23. SAM limits.

24. SAM.tool.

25.  Good SAM coding practice.

25.1 Prefixed definitions. 

25.2 Use of "bye" and "pop".

26.  About code comments, junk directories, and changlog.txt files.

***


1.  Information about SAM that is online.

See the website:

   https://rosevearsoftware.com/products/sam


2.  Informative files in this distribution.

$sam_root
---------
CONTENTS
COPYING
GUIDE
TIPS
kernel/data/copyr.dat

$sam_root is the root of the installation.


3.  What is this?

This is a distribution of SAM.  It was written by me, Joseph Rosevear. 
See file COPYING in this distribution for a statement of the license
agreement.


4.  Some terminology.  I distribute SAM as a tarball.  A "tarball" is a
directory tree compressed into a single file by use of tar.

I have in the past referred to SAM as "SAM Kernel and Application", "An
Application of SAM for GNU/Linux Slackware, or "SAM-GLS".  These are
all the same project, although it has changed over time in content,
structure and function.


5.  Installing SAM.

Please see the information that is available online:

   https://rosevearsoftware.com/products/sam/get


6.  Running SAM.

I have provided instructions for running SAM online at:

   https://rosevearsoftware.com/products/sam/get

These instructions (above) explain how to use begin to run SAM.  Please
refer to these instructions.

The section below gives additional information about the use of begin
and explains also the use of the other executables found in $sam_root.

These executable scripts in $sam_root participate in running SAM:

   begin
   bgen
   bits
   bree
   breekit
   buser
   bxadd
   bxauth

You should use the full path when invoking these scripts.  I'm not sure
if this is necessary for all of them, but it is for at least a few, and
this therefore will avoid confusion.  Also, all but bxadd and bxauth
can be run as an ordinary user or as root, although the purpose of bree
and breekit is to become root, so you wouldn't ordinarily run these as
root.  Scripts bxadd and bxauth run xauth which belongs to X.  X
doesn't like root, so don't run them as root.

Here are explanations these scripts:


   begin          Runs SAM for ordinary users and root.  Nested
                  invocations (running SAM from inside SAM) are
                  allowed.  The resulting shell (nested or ordinary
                  invocation) inherits all exported variables plus
                  non-SAM exported functions.

   bgen           You should make symlinks to bgen in /mnt/your_root
                  directory.  Give these symlinks the names of any
                  script in $sam_root that you wish to use in dual
                  mode, but only symlinks "begin", "bree" and "breekit"
                  are necessary.  You can invoke the other scripts
                  directly.

                  Use the resulting symlinks in the same way that you
                  would use the corresponding scripts in $sam_root.

   bits           This script first sets variable bits to "".  Then it
                  outputs the value of bits after first setting it to
                  64 if apppropriate.  It is apppropriate if the
                  processor has 64 bits.  This is used by SAM to get
                  the right executable.

   bree           Runs SAM again from an environment in which it is
                  already running.  The new instance becomes root and
                  inherits all exported variables plus functions that
                  were defined by SAM.  If there are any non-SAM
                  exported functions, these will be inherited also.

   breekit        Uses begin to run SAM, and then bree to run SAM
                  again, recursively, as root.  It inherits variables
                  and functions in the same way as begin.

                  Like begin, this script allows nested invocations,
                  however I can think of no reason you would want to do
                  this.

   buser          This script starts the login using su for user $1. 
                  Any user may run this script, and it is normally run
                  when not in SAM.

                  If you do run it in SAM, you will notice one or two
                  things: (1) This script dumps you out of SAM somewhat
                  ungracefully.  This will be obvious.  (2) Your PATH
                  will be the ordinary PATH, not what it was in SAM,
                  but the shell will inherit the current SAM functions. 
                  You may not notice this.

                  Neither of the above are problems, if you are aware
                  of them, but the second one can be avoided--don't do
                  it!  Run buser when not in SAM.  Or just follow the
                  use of buser by begin or breekit.  This will reset
                  the functions as needed.

                  Actually, following with the use of begin is what I
                  normally do.  I wrote buser specifically to prepare
                  an xterm to use SAM commands dog and wolf in
                  $lib/tool to start the web browser in a remote X
                  session.  (This involves the use of SAM's bxauth and
                  bxadd.)

                  Note that buser won't run when you are not in X.

   bxadd          Run this script in a remote X session after
                  first running bxauth in the local X session.  It will
                  give you a local xterm which belongs to the remote
                  session.

                  Use $1 to provide the value of DISPLAY, less ":", for
                  the local session.  

   bxauth         See notes for bxadd.


7.  Using SAM.

After invoking SAM you will see that the prompt has been changed.  It
will look something like this:

   sam 1::)1
   student@220506aa1:/mnt/joe_root)

There is a lot of information in the two-line prompt, but I won't
describe it yet.  If you get a prompt that looks something like the
above, then you are in SAM.

The first command to learn is "menu".  Invoke the menu command.  You
should get a screen that begins like this:

   added:
   
   /mnt/SAM_root/lib/tool
   /mnt/SAM_root/main
   /mnt/SAM_root/kernel
   
   ::
   
    COMMAND       DESCRIPTION
   
   SAM is a flexible, text-based menuing system.
 
The menu name is normally displayed after the ":" above, but as there
is no menu currently defined the prompt shows "::".

Even though there is no menu, you can still try it out.  Scroll up and
down with the up and down arrows.  (You are actually using the "less"
command.) Pressing "q" returns you to the command prompt.  Enter "menu"
to display the menu again.

One way to use SAM is to enter commands from the current menu to do the
things described by the menu.  This works, because the commands of the
current menu are added by SAM to the PATH.

This is the quintessential use of SAM.  The menu shows shows you what
the current commands are.  You may not remember them otherwise.  The
menu also describes how to use the commands.  This allows use of
commands that take multiple arguments: the text of the menu is a handy
reference that defines the use of $1, $2 and so on.  With such a
reference readily available you can write and use code that is more
powerful than what you could manage otherwise.

SAM, however, makes many commands available, not just the commands of
the current menu.  Every use of the menu command, whether there is a
currently defined menu or not, will show a list of added paths.  These
are paths that have been added by SAM to the current command set.  They
are listed below "added:"

You can see above that there are currently three paths added.  The menu
shows their full names, but these names are equally valid:
"$sam_root/lib/tool", "$sam_root/main" and "$sam_root/kernel".  SAM
plays by its own rules.  It couldn't do the things it needed to do
without having the commands of "$sam_root/kernel" available.  Some of
these commands are handy for your own use as well.

There is no magic in the menu command, and very little code.  All it
does is display file $level/menu.dat.  However, that is just what is
needed.  I wrote a menu.dat file for the kernel.  You can see it, or
any menu, even when it is not current by this use of the menu command:

   menu $sam_root/kernel

This, instead of showing the current menu, displays a named menu.  Try
it and you will see that the menu command itself is listed and
described:

       menu       If $1 is "", displays current menu.  Otherwise
                  displays menu for $1.

Other commands of the kernel that you will surely use are "bound",
"bye" and "library".  These you may also find useful: "hello",
"library" and "shoparts".

Remember always to press "q" to leave a menu before entering a command.

Use "exit" to leave SAM.  This is not a SAM command.  It works by
exiting the shell that is keeping SAM open.  It is like pulling the
stopper from the bath tub--the water goes down the drain.

Use "bye" to leave a menu and return to the previous one.  When there is no
previous menu "bye" will take you all the way out of SAM.

Use ";" to separate commands on one line.  This is a feature of Bash,
not of SAM, but it works well in SAM.


8. SAM menus.

Menus are introduced in the online documentation at
https://rosevearsoftware.com/products/sam.  They are also described in
the brief SAM tutorial which appears when you use the "menu" command. 
Please refer to the descriptions at these locations.


9. The SAM prompt.

Here is a breakdown of the parts of the prompt:

   \n$sam_file:${level}${sam_symbol}${sam_env_num}$sam_env_num
   \n\u@\h:\w${sam_symbol} 

   The first line of the prompt has these parts:

      sam <instance>:${level}${sam_symbol}${sam_env_num}

         <instance>   SAM can be started a number of times by each
         user.  Theses "instances" of SAM are counted, and the current
         value of the count is displayed in the prompt.

         $level        This is the path which the user selected to
                       represent the current menu.

         $sam_symbol   This is defined by script $sam_root/go/sam where
                       it is defined as ")" and exported.

         $sam_env_num  Each instance of SAM uses a stack of
                       environments.  $sam_env_num is the current
                       position in the stack.

      Note: Internally, SAM represents the instance together with the
      name of the file ($sam_root/go/sam) which was used to start SAM. 
      This combination is referenced in SAM as "$sam_file".  Therefore
      $sam_file is

         sam <instance>

   The second line of the prompt is:

      \u@\h:\w${sam_symbol}

         \u            user

         \h            hostname

         \w            working directory

         $sam_symbol   <See above.>

   Except for the use of $sam_symbol at the end, this is probably
   familiar to you.

I apologize if you have grown accustomed to having the final character
be "#" for user root.  I chose not to implement that behavior, because
SAM allows you to become root in a number of different ways which vary
somewhat in their nature.  Note that, in my experience, \u shows the
same value as `whoami`.  Therefore, if you see "root" in the prompt, it
is probably safe to assume that you are root.  That's what I do.  I
have not found this documented anywhere.

Here is a table which summarizes the different ways to become root in
SAM.  See the Key and Note below also:

     `whoami`/$LOGNAME/$USER in console
   ---------------------------------------
   before       after     after
   starting     begin     begin, then bree
   --------     -----     ----------------
   O/O/O        O/O/O     R/O/O
   R/R/R        R/R/R     R/R/R

        `whoami`/$LOGNAME/$USER in X
   ---------------------------------------
   before       after     after
   starting     begin     begin, then bree
   --------     -----     ----------------
   O/O/O        O/O/O     R/R/O
   R/R/R        R/R/R     R/R/R

   Key: O=Ordinary user, R=Root user.

   Note:  Use of breekit gives the same results as "begin, then bree".


10.  File menu.dat and the menu command.

Menus displayed by SAM are defined by files named "menu.dat".  Make one
and put it in a directory, and it will be displayed by the use of the
command

   menu

when it is the current menu.  To make a menu current use the "bound"
command.

I will illustrate with an example, but first I need to mention my use
of the term "current".  Hopefully you are familiar with "current" as it
applies to directories.  I have given the term "current" a new use by
applying it also to menus.  When a menu is "current" that means that
variable level has been given the value of the path to the directory. 
SAM then knows to treat it in a special way.

A directory is current when you are in it.  You go into a directory by
using "cd".  That is nothing new.  A menu is "current" when you "bound"
to the path that defines it.

Here is an example:

   /mnt/SAM_root/begin
   echo test > /tmp/menu.dat
   bound /tmp
   menu
   bye
 
This example makes the menu at /tmp current ("bound /tmp" does this). 
The "menu" command causes the menu to be displayed, and "bye" will exit
SAM.


11. Using libraries.

A library is a menu, and a menu is a directory.  To avoid being
trivial, the directory needs to contain executable files and/or
qualified function definitions.  You *may*, however use an empty
directory as a library, if you choose to do so.

So how is a library different from a menu?  The answer is that it isn't
different.  It is just another name for the same thing.  However, when
I use the term *library* I mean a directory of executables and/or
qualified function definitions which has been made into a tarball,
named in the manner of a library (see
https://rosevearsoftware.com/products/sam/names), and distributed as a
"library".

When you get a library as a tarball, you need to unpack it and put it
in a directory tree or on a flash drive somewhere that is convenient
for you. You have great latitude here.

When I make libraries they unpack into a single directory.  This is
helpful, because it takes care of naming the directory.  The name is
important, as other code may depend on your use of the intended name. 
Using a different name could cause trouble.

Let's say you have a library in the form of a tarball, and you unpack
it making directory "handy".  (There is a library that I have
distributed--or will distribute--that has that name.) There are
different things you can do with it, but all are essentially the same
at there basic level.  All use bound to add the commands of the library
to the command set.

This then is one of the things you can do--run bound on it.  For
example, this makes it the current menu:

   bound <path to handy>

And this adds it to the command set without changing the current menu:

   bound $level <path to handy>

The second of these is more library-like, since it has a minimal effect
on the current environment.  It pushes the stack and adds the commands
to the command set, but leaves variable *level* unchanged.  This allows
you continue the use of the current menu.

Both ways that I give above are valid, and you may find that sometimes
you need one and sometimes the other.

The thing about libraries, however, is that you need a convenient way
to reference the locations of the directories--such as handy--that you
have collected.  I have designed SAM to use the directory $lib as a
repository.  This use is simple, yet effective.  (See
https:/products/sam/get for the discussion of "Dual mode.)  It allows
you to put your upacked library directories, such as "handy" in $lib.
Or, and this is better, you can put symbolic links in $lib which point
to the locations for each library directory.

Having done the above, you can now refer to the library "handy" as
"$lib/handy".  You will find that this added level of abstraction is
essential.  Now you can do the above like this:

   bound $lib/handy

and

   bound $level $lib/handy


12. Using $init with libraries.

This, like $lib, is an expression that SAM manages.  It normally
defines a file which is an executable script, but you might, if you
wanted to, find other ways to get the same result.  What you want is
for $init to output parameters to be used by a bound invocation which
happens before (or at the same time) as the begin command is creating
the SAM shell.  In this way you can start SAM with a pre-defined
command set.  SAM always inherits the current PATH and functions that
are definined at the time begin is invoked, but with $init you can add
to that command set before your first use of SAM's shell.

Typically $init looks like this:

   $#/bin/sh

   echo : <path> final

You need to understand, however, that the three strings echoed by this
script are just parameters for a bound invocation.  See the kernel menu
for more information:

   menu $sam

The SAM distribution comes with "$lib/tool" for "<path>" ($2).  I hope
if you are reading and following along that this is a "light bulb"
moment for you.  Now you should see how libraries work.  There is a
fine point, however that I will show you.  These are all acceptable
strings for $2:

   $lib/tool

   $lib/handy

   $lib/handy:$lib/tool

The first two are exactly what you would expect, but the last one is
new.  In this way you can add two (or several) libraries to the command
set before your first use of the SAM shell.

About the "final" at the end.  That is normal use of the bound command,
although it is especially useful in the $init invocation.  It prevents
the "bye" command from popping the stack back to a state that is prior
to the initial state.  Actually, you can pop to a prior state if you
use "pop" instead of "bye".


13. Weird uses of bound.

SAM allows the use of as many ":" (colons) as you would like to use. 
If there are extra colons they are ignored, but a single colon for $1
means "null menu" and a single colon for $2 will be ignored.

Similarly multiple uses of the same directory are filtered out.  This,
for example, is a valid and will result in a PATH variable without repeated
directories:

   bound /tmp:/bob::/tmp $lib/handy:$lib/tool:$lib/handy

   
14. Nested invocations of begin, bree and breekit.

SAM will let you nest invocations of begin, bree and breekit either
individually or mixed up--if you do it right.  For single levels of
nesting all cases look the same, but beyond that you need to pay
attention to the different behaviors of begin, bree, and breekit.

First of all, use only double quotes.

Next you need to learn the normal progression of escapes.  It is:

   "2**n - 1"

which is another way of saying "one less than each of the powers of 2. 
The powers of 2 are: 1, 2, 4, 8, 16, etc.  So the escape sequence, using
the one less idea, is: 0, 1, 3, 7, 15, etc.

Straight nesting of begin follows the sequence.  For example this will
work as expected:

    $sam_root/begin "$sam_root/begin
    \"$sam_root/begin \\\"echo bob; echo mary\\\"\""

And with some imagination you will see how to continue this pattern to
arbitrary levels of nesting, although why you would *want* to do this
is another matter.

Straight nesting of bree follows a modified sequence.  I'm pretty sure
this results from the structure of the bree code, but I'll leave that
to you to verify.  The modified sequence I have found to be this:

   0, 3, 15, etc.

Simply, it starts with the first element of the normal sequence, and
skips taking every second element.  For example this will work as
expected.  Of course you need to do this after first having used begin
once, as bree only works in SAM:

    $sam_root/bree "$sam_root/bree
    \\\"$sam_root/bree
    \\\\\\\\\\\\\\\"echo bob; echo mary\\\\\\\\\\\\\\\"\\\""

OK, now for the big one, breekit.  It, having a different code
structure, uses the first, then ever third element of the normal
sequence:

   0, 7, 63, etc.

This is getting ridiculous.  I mean, 63 escapes?  This works:

   $sam_root/breekit "$sam_root/breekit
   \\\\\\\"$sam_root/breekit
   \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
   echo bob;
   echo mary\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
   \\\\\\\""

Now for the matter of combining begin, bree, and breekit.  I'll give
just one example.  The way to do this is to apply the applicable method
after each use of begin, bree or breekit while keeping track of where
you are in the sequence of escapes.  This works:

   $sam_root/breekit "$sam_root/begin
   \\\\\\\"$sam_root/begin
   \\\\\\\\\\\\\\\"echo bob; echo mary\\\\\\\\\\\\\\\"\\\\\\\""

These examples are extreme, but since I bothered to figure them out, I
wanted to share them with you.  Plus it is a comfort to know how to do
this just in case, and an incentive to confidence (in SAM) to know that
SAM can do it.


15. Quoted tasks.

Similar to nesting is the providing of a quoted set of tasks for begin,
bree or breekit.  I have found using bree this way is useful if I want
to write a script that has tasks that need root to run.  Here is a
simple example:

   #!/bin/sh
   
   $sam_root/bree "
   mount $1 /mnt/zip;
   mount | grep $1;
   pause;
   exit;
   "

This will prompt you to provide your root password, if you are not
root.  It then mounts $1 at /mnt/zip, gives a report, and pauses until
you press a key.  Then it exits from the shell script.

When doing something like this I will sometimes add a loop that pauses
and checks periodically for a successful mount.  This helps when the
mount doesn't happen quickly, as in such cases the report given by this
script may incorrectly show the drive has not been mounted.

I'll let you figure out how to write the code for the loop.


16.  Special variables.

These variables can be used to control the behavior of SAM.  Set them
anyplace and anytime:

   sam_batch

      Exporting sam_batch with value of batch (or anything) will cause
      SAM to be run in a batch mode.  In this mode it will not give you
      interactive behavior.  Sometimes interrupting a shell script
      results in an interactive shell opening at the point where the
      script stopped.  Often this is not desired.  Use this variable to
      prevent this behavior.

   sam_hosts

      The default number of SAM hosts for each user is 24, but you can
      override that default by exporting this variable when you run
      begin, bree, or breekit.

These variables also control the behavior of SAM:

   export sam_view=<alternate menu viewer>
   
      You would export this to change the viewer which is used by
      $sam_root/kernel/menu to display menus.
   
      The default viewer is "less".  A suggested alternate viewer is
      "cat".

   sam_flat

      A definition of this variable is prefixed to the su invocation by
      script $sam_root/buser.  The variable is used by
      $sam_root/go/sam1 to control its behavior.

      Please see the scripts buser and sam1 to learn more.

   type

      This variable is used by script $lib/tool/view_it.  You are
      encouraged to define it by prefixing a definition to the
      invocation of view_it.  Please see the menu for $lib/tool, and
      perhaps the script itself, for more information.
   
There are other variables that are important to SAM but are normally
dealt with by your $sam_root/bprofile.  Read about them in
$sam_root/TIPS.


17.  There is a nuisance you may encounter.

There is a nuisance you may encounter.  This happens when $sam_temp_dir
(which points to the current temp for SAM) gets files in it that cannot
be written to.  Say for example that you have a temp dir at ~/temp1,
but you get a file in it that belongs to root.

When this happens you will need to change to root, go to ~/temp1 (or
temp2, etc) and change the ownership of the files back to the user (not
root). Or you can leave SAM, clean out the $sam_temp_dir's, and try
again.


18.  SAM's temporary and scratch directories.

This tells the scheme for SAM's temporary and scratch directories:


$sam_temp_base    You can set sam_temp_base to anything you want, but
                  $sam_root/bprofile included with this distribution
                  sets it to:

                     /tmp/`whoami`

$sam_temp_dir     You can set sam_temp_dir to anything you want, but
                  $sam_root/go/sam included with this distribution sets
                  and exports it like this:

                     export sam_temp_dir=$sam_temp_base/temp${1}

temp<n>           temp1 - temp<n> are made by this line in
                  $sam/sam_core:

                     mkdir --parents $sam_temp_dir

                  Note that (in this distribution) this will also make
                  $sam_temp_base if it does not already exist.

$env_scratch      I believe (but I'm not sure) that you can set
                  env_scratch to anything you want, but
                  $sam_root/sam_env included with this distribution
                  sets and exports it like this:

                     export env_scratch=$sam_temp_base/scratch

scratch           Make scratch any way you like, but in this
                  distribution scratch is made by this line in
                  $sam_root/brc:

                     mkdir --parents $sam_temp_base/scratch

                  Note that this will also make $sam_temp_base if it
                  does not already exist.

Note that the number of temp<n> directories is limited mainly by the
way in which SAM is configured.  In the current distribution the
maximum number of directories is configured by the way in which
$sam_root/begin invokes $sam_distro/go/sam1.  In particular, the
maximum is $1.

temp<n> are known as $sam_temp_dir.


19.  Shells used.

SAM uses #!/bin/sh in all* scripts but one.  That script
($sam/sam_core) has code that writes code to open additional shells. 
The code it writes uses "/bin/bash".  I chose "/bin/bash" over
"/bin/sh", because I wanted to use the --rcfile option.  Using this
option let me write better code, so I did it.  SAM, with the features I
described above, worked when I tested it in Ubuntu (see below), but
functionality in Ubuntu was not the reason for the design choices.

Note that I spent some time trying out SAM in Ubuntu.  In Ubuntu
/bin/sh is a link to dash.  SAM should work OK in Ubuntu if you first
change that link to point instead to the (traditional) bash.  Also you
may need to have a real root account.  I found that there was a change
you could make in Ubuntu to do this, but that was many years ago.  Here
are my notes, for what they are worth--I don't know if this still
works:

   Do "sudo passwd root" to get a real root.  If you change your mind
   do "sudo passwd -l root" to lock root again.



20.  SAM's synthetic shell.

Besides the normal Bash shell, SAM uses an oddity that I call a
"synthetic" shell.  The synthetic shell is what allows SAM's command
sets to function.  See also the section above called "SAM menus".

I invented the synthetic shell to give SAM the behavior I desired.  It
is coupled with $sam_env_num in the same way that a normal shell is
coupled with $SHLVL.  To help the user I gave SAM a prompt that
displays $sam_env_num at the end of the first line of SAM's two-line
prompt.  SAM needs the synthetic shell for it's operation, but you may
interact with it as well.  It works by pushing *some* of the current
variables onto a stack--which is actually a set of files in
$sam_temp_dir--and incrementing the variable sam_env_num.  To "pop" it
decrements sam_env_num and unsets, sets, and exports as needed to
restore the previous environment.  It's actually just a bit more
complex than this.  Look at the source code in sam/source to learn
more.  In short, SAM's synthetic shell works by manipulating the
current environment.

Let me explain my use of the word *some* above.  SAM pushes variables
that begin with a lower case letter onto a stack.  And variables that
begin with some other characters too.  The C code that is operating
here (set_filt.exe) selects all variables (for pushing onto the stack)
that begin with a letter with an ACII value greater than 96.  If you
examine an ASCII table you will see that this includes a-z and some
unusual characters, but excludes A-Z.  The intention was to exclude
variables in all caps which are normally environment variables, but you
can see that by my lazy coding I excluded more than just these.


21. Batch mode.

SAM has a batch mode.  It is selected by exporting thusly:

   export sam_batch=batch

before invoking SAM.  In batch mode a shell will not stay open waiting
for a command line input.  This capability was added to SAM to allow me
to invoke it from crontab files.  It wouldn't work otherwise.

See $sam/sam_core for the details.


22. Bugs in SAM

recursion:

You can invoke SAM inside of SAM, but there is one peculiarity when
doing so.  The functions that were defined before the nested SAM was
invoked will be inherited by the nested SAM.  That is they will be
unless something is done before SAM is invoked.

This is either a feature of SAM or a bug.  It is something that you
should be aware of.

SAM is written so that you can easily remove the existing function
definitions.  This guide is not about the application of SAM, but you
can be sure that any application of SAM that I write will automatically
remove inherited function definitions.  Still, you should be aware of
this, and be careful.

lockfile and msdos file systems:

SAM uses the lockfile command to augment the protection given by the
use of the "in_use" file.  The in_use file protects against multiple
simultaneous uses of the same $sam_temp_dir, however it fails at this
when the user invokes SAM rapidly in succession.  That's where the
lockfile command comes in.  It almost fixes things.  The problem is
that I haven't been able to get lockfile to put a lock on a file in an
msdos file system (such as vfat or fat32).  There is no such trouble
with the native Linux ext2 file system, so maybe this is a non-issue.

SAM tries to put the lock file in sam_temp_dir.  So if you are using an
msdos file system for $sam_temp_dir, be aware that there is no
protection against rapid successive invocations of SAM causing multiple
simultaneous use of a $sam_temp_dir.  You will see a warning from
lockfile that it cannot do it's job--something about praying.  If you
avoid rapid successive invocations of SAM when using $sam_temp_dir in
an msdos file system you'll be OK.


23. SAM limits.

SAM has some limits that might be seen as bugs as follows:

Don't run instructional text files:

Be careful not to run instructional text files (such as this file). 
BAD things could happen.  Ordinarily such files cannot be run, because
they don't have execute permission.  However, if you run SAM from an
msdos file system, then you will not have this protection.  Or this
could also be the case if I (or someone) have given a text file execute
permission by mistake.

Beware commands and variables:

SAM has a few scripts and executables that you may not know about
unless you look.  They are not likely to do any harm, but it would be
smart for you to look and see what they are so you don't use them by
accident.  The documentation does not currently list all the scripts
and executables.

Similarly, SAM adds many variables to the environment.  It does this in
a shell, so your original environment is protected.  However, SAM
depends on these variables to do what it does.  You could have
difficulty if you alter one of them.  The documentation does not
currently list these variables.
  
cd `pwd`:

SAM does this (the above) in sam/pop.sam.  It is an odd thing to have
to do.  It is needed to make the prompt correct in certain situations,
but this isn't fully understood.

Disk space:

You can run out of disk space needed for SAM's $sam_temp_dir.  Although
this isn't likely, SAM does nothing to prevent it.  It would cause SAM
to fail.

Limited buffers:

A buffer in set_filt.c is of limited size and can cause failure.  The
code checks to prevent writing beyond the end of the buffer, but
unfortunately SAM cannot proceed if the buffer isn't big enough.  See
the source code for details, and be aware that this error message

   Buffer size exceeded.

means the buffer size limit has been encountered.  You are free to
change the buffer size and recompile.

Non existent local directories:

SAM doesn't care if you do this:  "bound /hey".  It works whether /hey
exists or not.  This is good, because SAM is a tool.  You may have a
reason to do this even if /hey doesn't exist.  Similarly, you can do
this: "bound hey".  The leading "/" has been removed.  Again you may
have a reason to do this.  In both cases if you aren't aware of what
you are doing, SAM may surprise you.

Mistakes of comprehension:

When writing SAM scripts you are really writing ordinary Bash shell
scripts.  Yet, there are mistakes of comprehension that can be made. 
It is easy to misunderstand what SAM does.  The methods of scripting
shown by the examples (that may have come with your distribution) work
well when each method is understood and followed.  If a method is not
followed, then it may not work correctly.  Similarly, if a method is
not understood, it may seem to not work correctly.  Both situations can
be frustrating, but such are not necessarily errors belonging to SAM.

Limitation in xargs:

SAM puts a lot of stuff in the environment.  In particular, it exports
a lot of variables and functions.  This is why I sometimes got an error
message which said "xargs: environment is too large for exec".  The
solution I found was to change xargs and recompile it, then replace the
original xargs with the corrected one.

Here's the piece of code I changed, before and after:

   Before:

      if (arg_max > 20 * 1024)
        arg_max = 20 * 1024;

   After:

    /* JHR 050813 I commented out and changed the two lines below */
    /*if (arg_max > 20 * 1024)
        arg_max = 20 * 1024; */
      if (arg_max > 40 * 1024)
        arg_max = 40 * 1024;

I learned that this was the needed fix by what I found when searching
in Google Groups "www.groups.google.com" on the quoted error message.

After doubling the limit (from 20K to 40K) I've had no trouble...yet.

Here's an update (today is 4-18-12):  The native xargs seems to work
fine now, so I removed the modifed xargs.  Perhaps the solution came
from a change that I made.  I added a filter called "slice" to the
kernel.  It is used by "push" and treats an odd runaway growth of the
environment (in particular, the variable TERMCAP).  Read the comments
in slice to learn more.


24.  SAM.tool.

Please see the description of SAM.tool which is online at:

   https://rosevearsoftware.com/products/sam/libraries

Here is a little more information:

Library SAM.tool can be found at $lib/tool.  The commnds of $lib/tool
are documented in its menu.  You can read the menu with this command:

   menu $lib/tool


25.  Good SAM coding practice.

When using SAM there are a few things that can happen that you probably
want to avoid, or at least be aware of.  You can avoid them by using
the coding practices I will describe below:

25.1 Prefixed definitions.

   Do not use prefixed parameter definitions in front of a qualified
   SAM function.

   Note:  A "qualified" function is one defined by a definition that
   has "OK SAM" in the first ten lines and has a name which is the same
   name as the basename of the defining file.  Such functions are
   "managed" by SAM as if belonging to the SAM menus.

Bash allows you to prefix a definition in front of a script or function
invocation.  For example:

   horse=black horsecolor

"horsecolor" can be a function or a script.

This works in Bash and is compatible with SAM as well.  However, I
propose that is is poor coding practice to do this when horsecolor is a
qualified function that contains SAM commands that perform stack
operations.  Here is an example that will cause a result that you might
in fact desire, but more likely will surprise you.  Let's say that you
made file horsecolor.sam and put it in /tmp:

   #OK SAM

   horsecolor() {

      bound /tmp/bob
      bye

      return
   }

Then you added it to the command set by use of "bound /tmp".

After invoking "horse=black horsecolor" you will find by use of "echo
$horse" that $horse is now "black".  Bash doesn't do this normally, but
it does when SAM is used in this and similar ways.  This happens
because bound pushes part of the environment, including variable
"horse" on to the stack.  "bye" then pops the stack, but in doing so it
adds the definition of horse to the environment.

It was there before, by virtue of the prefixed parameter definition,
but after "bound...; bye" it is there without the special protection
offered by Bash for prefixed parameter definitions.  The result is that
the value given to "horse" will persist in the current environment
after the invocation of function horsecolor.

As I said, you might want this behavior, but because it is a
potentially surprising behavior I propose that it be called "poor
coding practice", or if you prefer, "advanced coding practice". 
Whatever.  We won't call it "good".

This behavior was triggered above by "bound...; bye".  It will also
happen with "push; pop" and "hello; bye".  And it will be caused by
more complex but equivalent sequences of commands.

For more information about this feature of Bash enter "man bash" and
search on "augment".

25.2 Use of "bye" and "pop".

   Use "bye" or "pop" only in qualified SAM functions or at the command
   line, but not in scripts.

   Reminder: "bye" calls "pop".

These SAM commands pop the stack.  This is not a problem all by itself,
and it isn't a problem at all when done at the command line or in
functions.

In scripts, however, it is possible by use of these commands to "change
the past", so to speak.  What I mean is that the script can pop the
stack to go back to a level (as defined by $sam_env_num) that is below
the level from which the script was invoked.  Then at this level the
script can potentially make assignments which "change the past".  This
"changed past" will persist after the script exits.

This won't happen in a function or at the command line.  It won't
happen, because a function (or the command line)--operating on the
current environment--won't let you go below the level from which the
function was invoked (or the command line was created).  This might be
desirable for advanced users, but I propose that we exclude this from
"Good SAM coding practice".


26.  About code comments, junk directories, and changlog.txt files.

Often I will describe the changes I make to a code or other file in
comments at the top of the file.  I will also often save the current
version of the file to the current "junk" directory before making the
changes.  I will not include these junk directories in the regular
distributions.

When I do not describe the changes in comments at the top of the file
it is due either to haste or necessity.  For example, I do not describe
changes to this GUIDE in comments at the top of the file, as that would
spoil its readability.

Many, if not all, of the directories of this SAM distribution will
contain a file "changlog.txt" and often also "changlog.txt<n>".  These
are "change log" files.  I will normally record in the current
changlog.txt file the date and rough nature of any change I make to a
file in the current directory.  Sometimes, especially when the file
doesn't have a section at the top for comments, I will include details
of the changes made to the file in changlog.txt.  Files
"changlog.txt<n>" are made when changlog.txt becomes large.

When I "fork" the development of a file by restoring a previous
version from "junk", I will document this in the changlog.txt
file and perhaps also in "https://rosevearsoftware.com/products/sam",
but not in the comments at the top of the file.
