Profile Scheme
                               ______________
                                                                     24/6/82

The profile scheme provides a way for programs or packages to store and
retrieve small amounts of data separately for each user.  This information
would typically specify options chosen by the individual user.  For example,
if the program were the text editor ECCE, the information stored might be
whether letter case was to be ignored or not when searching for text
strings, initial macro definitions, and monitoring level.  It is stressed
that different users can each select different settings.

Along with the information there is stored a version number.  This relates
to the format of the profile information stored for the program, and
provides a mechanism for handling format changes in the information which
the program stores.  The details are given below.

The information is held for all programs using the profile scheme in a file
in the user's process called SS#PROFILE.

Two external routines are involved:

        external routine              string          name
        ________ _______ read profile(______(11) key, ____ info,
                                      integername
                                      ___________ version, flag)

        external routine               string          name
        ________ _______ write profile(______(11) key, ____ info,
                                       integername
                                       ___________ version, flag)

These require to be explicitly specified.

read profile reads the information stored under the specified keyword in
file SS#PROFILE if it exists, and copies it to the name
                                                   ____-type parameter.

write profile copies the contents of the name
                                         ____-type parameter to SS#PROFILE,
creating the latter if necessary.


read profile parameters
_______________________

The meanings of the parameters to read profile are as follows:

key        The keyword relating to the particular profile information;
           chosen by the program writer.  Every call of read profile must
           specify this (non-null) string.

info       A scalar variable (not
                              ___ an array) of any type; usually a record or
           a string.
           read profile copies the information from SS#PROFILE to info.  If
           the number of bytes held for the specified keyword in SS#PROFILE
           is greater than the size of info, then only as many bytes as info
           can hold are passed; truncation of the file information is from
           the right.  If the number of bytes held in SS#PROFILE is less
           than the size of info (this includes the case where no
           information is held for the specified keyword) then the rightmost
           bytes of info are cleared to 0.  See also flag, described below.

version    read profile returns the version number appropriate to the
           information currently stored in SS#PROFILE.  This is 0 if no
           information is stored for the given keyword (or if SS#PROFILE
           does not exist).

flag       Set by read profile as follows:
              0  Success.
              1  Info held in SS#PROFILE is larger than size of info
                 parameter passed.  Some rightmost bytes of file info not
                 transferred.
              2  Info held in SS#PROFILE is smaller than size of info
                 parameter passed.  Some rightmost bytes of info parameter
                 set to zero.
              3  SS#PROFILE does not exist.
              4  Keyword not found in SS#PROFILE.
              5  Failed to connect SS#PROFILE.  The attempts to connect
                 SS#PROFILE are as follows.  If the program is running in
                 background mode, the program will attempt to connect
                 SS#PROFILE a total of five times, with a delay of 20
                 seconds of cpu time between each attempt, before returning
                 this flag.  If the program is running in foreground mode,
                 up to 3 attempts will be made, with a delay of 1 second of
                 cpu time between each.
              6  File SS#PROFILE corrupt.
              7  Keyword is null.

              If flag=2 on return then the info parameter has been partially
              padded with zeros, as described above.  If flag>2 on return
              then the info parameter has been cleared to zeros and version
              has been set to 0.  Note that only flag values of 5 or more
              indicate a definite fault.


write profile parameters
________________________

The meanings of the parameters to write profile are as follows:

key        The keyword relating to the particular profile information;
           chosen by the program writer.  Every call of write profile must
           specify this (non-null) string.

info       A scalar variable (not
                              ___ an array) of any type; usually a record or
           a string.
           write profile copies the contents of info into SS#PROFILE,
           creating the file if necessary.  See also flag, described below.

version    write profile sets the version number attached to the information
           which it is writing into SS#PROFILE to the specified value of
           version.
           [Note that version is an integer name
                                    _______ ____ parameter although its
           value is never changed by write profile.  This is so that the
           formal parameter lists for read profile and write profile can be
           identical.]

flag       Set by write profile as follows:
           0  Success.
           1  SS#PROFILE was created.
           2  Failed to create SS#PROFILE.
           3  Failed to connect SS#PROFILE.  First an attempt to connect it
              in write mode is made; if this fails another attempt is made
              after a delay of 1 cpu second.  If this fails an attempt is
              made to connect it in read shared mode, and a flag of 3 is
              returned if this fails.  If it succeeds, a copy of SS#PROFILE
              is made, and changed, then a NEWGEN is attempted; if this
              fails, a flag of 4 (see below) is returned.
           4  Failed to create a copy of SS#PROFILE, or failed to NEWGEN it.
              A copy is made of SS#PROFILE if it can only be connected in
              read shared mode (see above) or needs to have its size
              altered.  This usually entails increasing the size, but wasted
              space can be recovered during the operation and this may
              actually enable the file to be reduced in size.
           5  SS#PROFILE already holds information for the maximum number of
              keywords permitted (ca. 500).  Should not occur.
           6  The info parameter is larger than 4060 bytes.  This is the
              largest amount which may be stored for any one keyword.
           7  Keyword is null.

           No information has been written to SS#PROFILE if flag>1 on
           return.


Using the profile scheme
________________________

Without being prescriptive, I would envisage the scheme being used by a
program as follows.  On entry the program would first establish, by calling
read profile, what information relevant to its operation was held.  It would
then respond accordingly, normally by setting up initial values for relevant
variables.  In addition, some means would be provided for the user to change
the information held in the profile file; this could either be done from
within the program itself or as a separate program.

One straighforward way of setting profile information from within the
program itself is to follow the INITPARMS approach in Subsystem command
OPTION: i.e. to provide a means for the user to specify that his defaults
are to be the current
              _______ settings of the relevant variables.  Thus, in the case
of ECCE, the user could set %L (case sensitive text location), %F (full
monitoring) and some appropriate values for the macros %W, %X, %Y, %Z.  Then
if he gave the command %P say (P for profile), ECCE would call write profile
to save %L, %F, and the current macro definitions.  When the user called
ECCE thereafter, this stored information would be read on entry and the
program variables set accordingly.

The version number is provided at the suggestion of Sandy Shaw, who has also
suggested an elegant use of it, as described below.

Suppose that a user used a program ZZZ three years ago, when version 2 of
ZZZ's profile information was in use.  Now, three years later, he starts
using ZZZ again.  His SS#PROFILE file contains information stored in the
version 2 format, but now version 4 (say) of ZZZ's profile information is in
use, which contains different information from that of version 2 and in a
different format.  The suggested approach is that when ZZZ makes its initial
call on read profile it first checks that the flag returned is satisfactory,
then uses the version number returned as a switch value and jumps to a piece
of code:

              vsn(0): ....
                     :
              vsn(1): ....
                     :
              vsn(2): ....
                     :
              vsn(3): ....
                     :
              vsn(4): ....
                     :


The code following switch label vsn(1):, for example, transforms profile
information held in the version 1 format into the version 2 format.  It is
assumed that a change in profile format will usually entail appending to the
previous format, e.g. appending subfields to a record, although existing
subfields could be ignored or reused.  The conversion code is added to the
program when version 2 of the profile format is introduced.  It can also
include an output message to the effect that a new version of the program
was put into service on such and such a date, contains the following goodies
..., etc.

In the case of our user of program ZZZ, after the program has read the
user's profile data a jump would be made to label vsn(2): and the code
following vsn(2): and vsn(3): would be executed.  By this time the
information returned by read profile would have been transformed into the
version 4 format (the latest version).  Thereafter, the program would call
write profile to write out the information in the latest (version 4) format
if what read profile returned earlier was not in the latest format.  Then
the run of ZZZ could proceed as per normal.  The next time the user calls
ZZZ, it will read a profile version number of 4, jump to vsn(4): and proceed
directly.  Thus the code following each switch label is only executed once
for each user.

This approach also provides a way of introducing the profile scheme into
existing programs.  When no information pertaining to a particular program
is held in SS#PROFILE (or perhaps SS#PROFILE does not even exist), a version
number of 0 is returned by read profile.  A jump to vsn(0): thus follows and
the code there can set up the profile information, as described above.  The
version number of the new profile information will be 1.  After the vsn(1):
code there will be a call of write profile, which will automatically create
SS#PROFILE if it does not already exist.  The code might have the following
form for a program XXX:


              :
        record format        integer       string
        ______ ______ prof f(_______ a, b, ______(40) c)
        record
        ______ (prof f) prof
        constant integer
        ________ _______ prof vsn = 1; ! Current version no of profile format.
        integer
        _______ flag
        switch
        ______ vsn(0:prof vsn)
              :
              :
        read profile("XXXPROF" {keyword unique to this program},
                     prof {returns information stored for "XXXPROF"},
                     pvsn {returns version no of stored profile info},
                     flag {return values described above} )
        if        start
        __ flag>4 _____
           printstring("Unable to access file SS#PROFILE.")
           newline
           return
           ______
        finish
        ______
        -> vsn(pvsn)

        vsn(0):
           ! pvsn was 0 on return - no profile info currently stored.
           prof_a = 4; prof_b = 7; prof_c = "Doughnuts"
           ! Elements of profile record set to defaults in use prior to
           ! introduction of profile scheme.
           printstring("XXX now uses a profile scheme - see documentation")
           newline
           ! This code is executed once for each user,
           ! so each gets message once only.

        vsn(1):
           ! Code to transform profile info to a version 2 format
           ! would go in here.

           ! Now write profile info to SS#PROFILE in latest format (if
           ! necessary).
           if               start
           __ pvsn#prof vsn _____
              write profile("XXXPROF", prof, prof vsn, flag)
              if        start
              __ flag>1 _____
                 printstring("Failed to write to file SS#PROFILE, FLAG =")
                 write(flag,2); newline
              finish
              ______
           finish
           ______