! *viewer/parameters.pvc - Parameter Setting/Retrieving Object
! By Gord Davey
! (c) Copyright 2004-2005 Sage Software Canada Ltd.
! Version Info:
! Source Code File: $RCSfile: parameters.pvs,v $   Version: $Revision: 1.6 $
!      Last Edited: $Date: 2005/10/14 15:31:18 $   Author: $Author: gordd $
!
! This object contains the logic to add/modify/delete parameter entries.
! Used by programs to maintain current and default values for variables
! based on systemWide and/or Machine and/or User Name.
! Similar to a registry, but stored in a encrypted keyed file.
!
! Default info is stored in Application, with null machine and user name
! Other info is stored as Application + Machine Name + User Id
!
! Values for variables may be stored in a .prm file and retrieved/updated
!
! new("*obj/parameters" [,FileName$] )
! If a FileName is not given, then "*applications.prm" is assumed
!
! In the Get/Set Parameters function, the OPTION$ may be given as one of:
! "" (same as "USER+MACHINE") or "USER" or "MACHINE" or "USER+MACHINE" this
! allows you to set/retrieve parameters for a user without regard to the
! machine he/she is on, or for the machine without regard to the user
! that is logged into that machine. The default is to save parameters
! by both the user and machine.
!
! Default parameters for an App and its reference are saved with a null
! user and machine name. The default parameter list is the driving list
! and the user will always get the default values for a variable if
! there are no user/machine specific entries, or if the specific variable
! does not exist in the user/machine specific entries, but does in the
! default
!
! Application and Reference Names may be NULL (not recommended)
! Variables may be, string, numeric, boolean or system parameters
! global versions of the above variables are also allowed
! you cannot specify arrays for any variable type.
! Booleans are always set/returned as either 0 or 1, no matter
! what the values were when they were stored, any value of "" or "0"
! is returned as =0 all others as =1
!
! The file used to store the parameters in is encrypted with a password
! uses no field separators and extended records. Therefore you may store
! any type and amount of data up to just under 2 GB per variable. The
! data will not be visible by an external scan of the file.
!
! Because this program sets and retrieves variable names/values directly
! from the user's current workspace, variable names within this utility
! use a _._._. preamble to avoid naming conflicts. You should avoid using
! variable names in your applications that start with "_._._." or "_._._._."
!
!
def class "*viewer/parameters" create OnCreate required delete OnDelete required
!
    property Version$ = mid(mid("$Revision: 1.6 $",12), 1, len(mid("$Revision: 1.6 $",12)) - 2)
    local _._._.Channel
    local _._._.FileName$
    local _._._.UserName$
    local _._._.MachineName$
!
!
    function perform GetParameters(Application$, Reference$)
    ! Gets Default then User and sets them vars in the app
        local _._._.Count
        local _._._.Application$, _._._.Reference$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$

        enter (_._._.Application$), (_._._.Reference$)

        ! read and set from the default entries first.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,err=GP1DNoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = "" and \
              ucs(_._._._.UserName$)    = ""

            gosub SetTheVar
            _._._.Count++
            read (_._._.Channel,err=*break)iol=ParameterIOList
        wend

        GP1DNoMore:
        ! read and set users specific entries next.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:_._._.MachineName$:_._._.UserName$,kno=1,err=*next)
        read (_._._.Channel,err=GP1NoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = ucs(_._._.MachineName$) and \
              ucs(_._._._.UserName$)    = ucs(_._._.UserName$)

            gosub SetTheVar
            _._._.Count++
            read (_._._.Channel,err=*break)iol=ParameterIOList
        wend

        GP1NoMore:
        if _._._.Count \
            then return 1 \
            else return 0
!
!
    function perform GetParameters(Application$, Reference$, Options$)
    ! Gets Default then User and sets them vars in the app
        local _._._.Count
        local _._._.Application$, _._._.Reference$, _._._.Options$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$, _._._.u$, _._._.m$

        enter (_._._.Application$), (_._._.Reference$), (_._._.Options$)

        if pos("USER"=ucs(_._._.Options$),1)>0 or Options$="" \
            then _._._.u$=_._._.UserName$
        if pos("MACHINE"=ucs(_._._.Options$),1)>0 or Options$="" \
            then _._._.m$=_._._.MachineName$

        ! read and set from the default entries first.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,err=GP2DNoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = "" and \
              ucs(_._._._.UserName$)    = ""

            gosub SetTheVar
            _._._.Count++
            read (_._._.Channel,err=*break)iol=ParameterIOList
        wend

        GP2DNoMore:
        ! read and set users specific entries next.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:_._._.m$:_._._.u$,kno=1,err=*next)
        read (_._._.Channel,err=GP2NoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = ucs(_._._.m$) and \
              ucs(_._._._.UserName$)    = ucs(_._._.u$)

            gosub SetTheVar
            _._._.Count++
            read (_._._.Channel,err=*break)iol=ParameterIOList
        wend

        GP2NoMore:
        if _._._.Count \
            then return 1 \
            else return 0
!
!
    function perform GetDefaultParameters(Application$, Reference$)
    ! Gets just the default vars and sets them in the app
        local _._._.Count
        local _._._.Application$, _._._.Reference$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$

        enter (_._._.Application$), (_._._.Reference$)

        ! read and set from the default entries first.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,err=GDPNoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = "" and \
              ucs(_._._._.UserName$)    = ""

            gosub SetTheVar
            _._._.Count++
            read (_._._.Channel,err=*break)iol=ParameterIOList
        wend

        GDPNoMore:
        if _._._.count \
            then return 1 \
            else return 0
!
!
    function perform SetParameters(Application$, Reference$)
    ! for each entry in the default list, set the user specific variables to current values
        local _._._.Count,_._._.k$
        local _._._.Application$, _._._.Reference$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$
        enter (_._._.Application$), (_._._.Reference$)

        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)

        SP1TopLoop:
            _._._.k$=key(_._._.Channel,err=SP1NoMore)
            read (_._._.Channel,bsy=*same,err=SP1NoMore)iol=ParameterIOList

            if ucs(_._._._.Application$) <> ucs(_._._.Application$) or \
               ucs(_._._._.Reference$) <> ucs(_._._.Reference$) or \
               ucs(_._._._.MachineName$) <> "" or \
               ucs(_._._._.UserName$) <> "" \
                then goto SP1NoMore

            dim _._._._.EntryNumber$(10,"0")
            extract (_._._.Channel,key=_._._._.Application$:_._._._.Reference$: \
                                       _._._.MachineName$:_._._.UserName$: \
                                       _._._._.Counter$,bsy=*same,err=*next)_._._._.EntryNumber$
            gosub GetTheVar
            _._._._.Application$=ucs(_._._.Application$)
            _._._._.Reference$=ucs(_._._.Reference$)
            _._._._.MachineName$=ucs(_._._.MachineName$)
            _._._._.UserName$=ucs(_._._.UserName$)
            write (_._._.Channel,err=*next)iol=ParameterIOList
            _._._.Count++
            read (_._._.Channel,key=_._._.k$,err=*next)
        goto SP1TopLoop

        SP1NoMore:
        if _._._.Count \
            then return 1 \
            else return 0
!
!
    function perform SetParameters(Application$, Reference$, Options$)
    ! for each entry in the default list, set the user specific variables to current values
        local _._._.Count,_._._.k$
        local _._._.Application$, _._._.Reference$, _._._.Options$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$,_._._.u$,_._._.m$
        enter (_._._.Application$), (_._._.Reference$), (_._._.Options$)

        if pos("USER"=ucs(_._._.Options$),1)>0 or Options$="" \
            then _._._.u$=_._._.UserName$
        if pos("MACHINE"=ucs(_._._.Options$),1)>0 or Options$="" \
            then _._._.m$=_._._.MachineName$

        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)

        SP2TopLoop:
            _._._.k$=key(_._._.Channel,err=SP2NoMore)
            read (_._._.Channel,bsy=*same,err=SP2NoMore)iol=ParameterIOList

            if ucs(_._._._.Application$) <> ucs(_._._.Application$) or \
               ucs(_._._._.Reference$) <> ucs(_._._.Reference$) or \
               ucs(_._._._.MachineName$) <> "" or \
               ucs(_._._._.UserName$) <> "" \
                then goto SP2NoMore

            dim _._._._.EntryNumber$(10,"0")
            extract (_._._.Channel,key=_._._._.Application$:_._._._.Reference$: \
                                       _._._.m$:_._._.u$: \
                                       _._._._.Counter$,bsy=*same,err=*next)_._._._.EntryNumber$
            gosub GetTheVar
            _._._._.Application$=ucs(_._._.Application$)
            _._._._.Reference$=ucs(_._._.Reference$)
            _._._._.MachineName$=ucs(_._._.m$)
            _._._._.UserName$=ucs(_._._.u$)
            write (_._._.Channel,err=*next)iol=ParameterIOList
            _._._.Count++
            read (_._._.Channel,key=_._._.k$,err=*next)
        goto SP2TopLoop

        SP2NoMore:
        if _._._.Count \
            then return 1 \
            else return 0
!
!
    function perform SetDefaultParameters(Application$, Reference$)
    ! Using the list of default variables, updates the values in the default entry only
        local _._._.Count,_._._.k$
        local _._._.Application$, _._._.Reference$
        local _._._._.EntryNumber$, _._._._.Application$, _._._._.Reference$, \
              _._._._.MachineName$, _._._._.UserName$,  _._._._.Counter$, _._._.VariableName$, \
              _._._.DataType$,_._._.MinimumValue$, _._._.MaximumValue$, _._._.Prompt$, \
              _._._.CurrentValue$
        enter (_._._.Application$), (_._._.Reference$)

        ! read and set from the default entries first.
        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:_._._.Reference$:"":"",kno=1,err=*next)
        _._._.k$=key(_._._.Channel,err=SDPNoMore)
        extract (_._._.Channel,key=_._._.k$,bsy=*same,err=SDPNoMore)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(_._._.Application$) and \
              ucs(_._._._.Reference$)   = ucs(_._._.Reference$) and \
              ucs(_._._._.MachineName$) = "" and \
              ucs(_._._._.UserName$)    = ""

            gosub GetTheVar
            write (_._._.Channel,err=*break)iol=ParameterIOList
            _._._.Count++
            _._._.k$=key(_._._.Channel,err=*break)
            extract (_._._.Channel,key=_._._.k$,bsy=*same,err=*break)iol=ParameterIOList
        wend

        SDPNoMore:
        read (_._._.Channel,key="",bsy=*same,err=*next)iol=ParameterIOList
        if _._._.Count \
            then return 1 \
            else return 0
!
!
    function ExistsApplication(Application$)
        enter (Application$)

        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=_._._.Application$:"":"":"",kno=1,err=*next)
        read (_._._.Channel,err=*next)iol=ParameterIOList

        if ucs(_._._._.Application$) = ucs(Application$)  \
            then Exists = 1

        return Exists
!
!
    function ExistsReference(Application$, Reference$)
        enter (Application$), (Reference$)

        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=Application$:Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,err=*next)iol=ParameterIOList

        if ucs(_._._._.Application$) = ucs(Application$) and \
           ucs(_._._._.Reference$)   = ucs(Reference$) \
            then Exists = 1

        return Exists
!
!
    function ExistsVariable(Application$, Reference$, VariableName$, DataType$)
        enter (Application$), (Reference$), (VariableName$), (DataType$)

        if pos(ucs(DataType$)="SNBP",1)=0 \
            then return 0

        read data from "" to iol=ParameterIOList
        read (_._._.Channel,key=Application$:Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,err=*next)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(Application$) and \
              ucs(_._._._.Reference$)   = ucs(Reference$) and \
              ucs(_._._._.MachineName$) = "" and \
              ucs(_._._._.UserName$)    = ""

            if ucs(_._._.VariableName$) = ucs(VariableName$) and \
               ucs(_._._.DataType$) = ucs(DataType$) then \
            {   Exists = 1
                break
            }

            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList
        wend

        return Exists
!
!
! Only adds to the default entry, if it does not already exist.
    function AddVariable(Application$,  Reference$, \
                         VariableName$, DataType$, \
                         MinimumValue$, MaximumValue$, \
                         Prompt$, DefaultValue$)
    ! Adds to default Name List
        local Counter, UnusedEntry
        enter (Application$), (Reference$), \
              (VariableName$), (DataType$), \
              (MinimumValue$), (MaximumValue$), \
              (Prompt$), (CurrentValue$)

        if not(_obj'IsValid(VariableName$, DataType$, MinimumValue$, \
                        MaximumValue$, Prompt$, CurrentValue$)) \
            then return 0

        AVRestartScanLoop:
        read (_._._.Channel,key=Application$:Reference$:"":"",kno=1,err=*next)
        read (_._._.Channel,bsy=*same,err=*next)iol=ParameterIOList

        ! Application and Reference of default entry, Do Not exist.
        if ucs(_._._._.Application$) <> ucs(Application$) or \
           ucs(_._._._.Reference$) <> ucs(Reference$) or \
           ucs(_._._._.MachineName$) <> "" or \
           ucs(_._._._.UserName$) <> "" then \
        {   _._._._.EntryNumber$ = dim(10,"0")
            _._._._.Application$ = ucs(Application$)
            _._._._.Reference$ = ucs(Reference$)
            _._._._.MachineName$ = ""
            _._._._.UserName$ = ""
            _._._._.Counter$ = "00000"
              _._._.VariableName$ = VariableName$
              _._._.DataType$ = ucs(DataType$)
              _._._.MinimumValue$ = MinimumValue$
              _._._.MaximumValue$ = MaximumValue$
              _._._.Prompt$ = Prompt$
              _._._.CurrentValue$ = CurrentValue$
            write (_._._.Channel,dom=AVRestartScanLoop)iol=ParameterIOList
            return 1
        }

        ! At least one entry for this app and reference
        AVMainScanLoop:

        if ucs(_._._.VariableName$) = ucs(VariableName$) \
            then return 0 ! Variable is already set

        if _._._._.Counter$ <> str(Counter:"00000") \
            then UnusedEntry = Counter

        Counter++

        if Counter > 99999 or UnusedEntry > 99999 \
            then return 0

        read (_._._.Channel,bsy=*same, err=AvFinishedScanLoop)iol=ParameterIOList


        ! Application and Reference do exist. Spin through, find an entry Counter,
        ! and ensure no other var of same name exist
        if ucs(_._._._.Application$) <> ucs(Application$) or \
           ucs(_._._._.Reference$) <> ucs(Reference$) or \
           ucs(_._._._.MachineName$) <> "" or \
           ucs(_._._._.UserName$) <> "" \
            then goto AVFinishedScanLoop

        goto AVMainScanLoop

        AVFinishedScanLoop:
        _._._._.EntryNumber$ = dim(10,"0")
        _._._._.Application$ = ucs(Application$)
        _._._._.Reference$ = ucs(Reference$)
        _._._._.MachineName$ = ""
        _._._._.UserName$ = ""
        if UnusedEntry>0 \
            then _._._._.Counter$ = str(UnusedEntry:"00000") \
            else _._._._.Counter$ = str(Counter:"00000")
          _._._.VariableName$ = VariableName$
          _._._.DataType$ = ucs(DataType$)
          _._._.MinimumValue$ = MinimumValue$
          _._._.MaximumValue$ = MaximumValue$
          _._._.Prompt$ = Prompt$
          _._._.CurrentValue$ = CurrentValue$

        write (_._._.Channel,dom=AVRestartScanLoop)iol=ParameterIOList
        return 1
!
!
    function local IsValid(VariableName$, DataType$, MinimumValue$, MaximumValue$, Prompt$, DefaultValue$)
        enter VariableName$, DataType$, MinimumValue$, MaximumValue$, Prompt$, DefaultValue$

        if pos("[]() =~!@#^&*`':;?/<>,{}|\/+-"=VariableName$,1)>0 \
            then return 0
        if pos(ucs(DataType$)="SNBP",1)=0 \
            then return 0

        Valid=1
        switch ucs(DataType$)
            case "S"
                if pos("%"=VariableName$,1)>1 \
                    then Valid=0; break
                if pos("$"=VariableName$,1)>0 and pos("$"=VariableName$,1)<len(VariableName$) \
                    then Valid=0; break

                Valid=0; x=num(MinimumValue$,err=*next); Valid=1
                if Valid=0 \
                    then break
                if fpt(x)>0 \
                    then Valid=0; break

                Valid=0; y=num(MaximumValue$,err=*next); Valid=1
                if Valid=0 \
                    then break
                if fpt(y)>0 \
                    then Valid=0; break

                Valid=1
                if x=0 and y=0 \
                    then break ! No Min and no max

                if x=0 and y \
                    then break ! has min, but max is unlimited

                if x and y and y<x \
                    then Valid=0; break ! has min and max, but max is less than min
                break

            case "N"
                if pos("$"=VariableName$,1)>0 \
                    then Valid=0; break
                if pos("%"=mid(VariableName$,2,len(VariableName$)-2),1)>0 or VariableName$="%%" \
                    then Valid=0; break

                if pos("1234567890.,-+"^MinimumValue$,1)>0 \
                    then Valid=0; break
                if pos("1234567890.,-+"^MaximumValue$,1)>0 \
                    then Valid=0; break

                Valid=0; x=num(MinimumValue$,err=*next); Valid=1
                if Valid=0 \
                    then break

                Valid=0; y=num(MaximumValue$,err=*next); Valid=1
                if Valid=0 \
                    then break

                Valid=1
                if y<x \
                    then Valid=0; break
                break

            case "B"
                if pos("$"=VariableName$,1)>0 \
                    then Valid=0; break
                if pos("%"=mid(VariableName$,2,len(VariableName$)-2),1)>0 or VariableName$="%%" \
                    then Valid=0; break

                MinimumValue$="0"
                MaximumValue$="1"
                break

            case "P"
                if pos("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!,"^VariableName$,1)>0 \
                    then Valid=0; break
                MinimumValue$=""
                MaximumValue$=""
                VariableName$=ucs(VariableName$)
                break
        esac
        return Valid
!
!
    function RemoveVariable(Application$,  Reference$, \
                            VariableName$, DataType$)
    ! Removes from User and Default Name list
        local Counter,k$
        enter (Application$), (Reference$), \
              (VariableName$), (DataType$)

        if pos(ucs(DataType$)="SNBP",1)=0 \
            then return 0

        read (_._._.Channel,key=Application$:Reference$:"":"",kno=1,err=*next)
        k$=key(_._._.Channel,err=RVDone)
        read (_._._.Channel,bsy=*same,err=RVDone)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(Application$) and \
              ucs(_._._._.Reference$) = ucs(Reference$)

            if ucs(_._._.VariableName$)=ucs(VariableName$) and \
               ucs(_._._.DataType$)=ucs(DataType$) then \
            {   remove(_._._.Channel,key=_._._._.EntryNumber$,bsy=*same,err=*next);
                    Counter++
            }

            k$=key(_._._.Channel,err=*break)
            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList

        wend

        RVDone:
        if Counter>0 \
            then return 1 \
            else return 0
!
!
    function RemoveReference(Application$, Reference$)
    ! Removes from User and Default Name list
        local Counter,k$
        enter (Application$), (Reference$)

        read (_._._.Channel,key=Application$:Reference$:"":"",kno=1,err=*next)
        k$=key(_._._.Channel,err=RRDone)
        read (_._._.Channel,bsy=*same,err=RRDone)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(Application$) and \
              ucs(_._._._.Reference$) = ucs(Reference$)

            remove(_._._.Channel,key=_._._._.EntryNumber$,bsy=*same,err=*next);
                Counter++

            k$=key(_._._.Channel,err=*break)
            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList

        wend

        RRDone:
        if Counter>0 \
            then return 1 \
            else return 0
!
!
    function RemoveApplication(Application$)
    ! Removes from User and Default Name list
        local Counter,k$
        enter (Application$)

        read (_._._.Channel,key=Application$:"":"":"",kno=1,err=*next)
        k$=key(_._._.Channel,err=RADone)
        read (_._._.Channel,bsy=*same,err=RADone)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(Application$)

            remove(_._._.Channel,key=_._._._.EntryNumber$,bsy=*same,err=*next);
                Counter++

            k$=key(_._._.Channel,err=*break)
            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList

        wend

        RADone:
        if Counter>0 \
            then return 1 \
            else return 0
!
!
    function CloneReference(Application$, SourceReference$, TargetReference$)
        local Counter,k$
        enter (Application$), (SourceReference$), (TargetReference$)

        read (_._._.Channel,key=Application$:SourceReference$:"":"",kno=1,err=*next)
        k$=key(_._._.Channel,err=CRDone)
        read (_._._.Channel,bsy=*same,err=CRDone)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(Application$) and \
              ucs(_._._._.Reference$)   = ucs(SourceReference$)

            _._._._.Reference$=TargetReference$
            _._._._.EntryNumber$ = dim(10,"0")
            write(_._._.Channel,bsy=*same,err=*next)iol=ParameterIOList;
                Counter++

            read(_._._.Channel,key=k$,bsy=*same,err=*break)iol=ParameterIOList
            k$=key(_._._.Channel,err=*break)
            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList

        wend

        CRDone:
        if Counter>0 \
            then return 1 \
            else return 0
!
!
    function CloneApplication(SourceApplication$, TargetApplication$)
        local Counter,k$
        enter (SourceApplication$), (TargetApplication$)

        read (_._._.Channel,key=SourceApplication$:"":"":"",kno=1,err=*next)
        k$=key(_._._.Channel,err=CADone)
        read (_._._.Channel,bsy=*same,err=CADone)iol=ParameterIOList

        while ucs(_._._._.Application$) = ucs(SourceApplication$)

            _._._._.Application$=TargetApplication$
            _._._._.EntryNumber$ = dim(10,"0")
            write(_._._.Channel,bsy=*same,err=*next)iol=ParameterIOList;
                Counter++

            read(_._._.Channel,key=k$,bsy=*same,err=*break)iol=ParameterIOList
            k$=key(_._._.Channel,err=*break)
            read (_._._.Channel,bsy=*same,err=*break)iol=ParameterIOList

        wend

        CADone:
        if Counter>0 \
            then return 1 \
            else return 0


fnend
!
OnCreate:

    enter _._._.FileName$,err=*next

    if _._._.FileName$="" \
        then _._._.FileName$="*applications.prm"

    _._._.Channel=hfn
    OCRetryOpen:
    open object (_._._.Channel,key="*PaRaMTr",err=OC_OpenErr) _._._.FileName$

    if %APS and %APS'SessionID$>"" then \
    {   _._._.UserName$=%APS'ClientUID$
        _._._.MachineName$=%APS'ClientNID$
    }

    if _._._.UserName$="" and tcb(88)>0 and ucs(mid(mse,32,1))="W" then \
    {   call "[wdx]*windx.utl;Get_Val","UID",_._._.UserName$
        call "[wdx]*windx.utl;Get_Val","NID",_._._.MachineName$
    }

    if _._._.UserName$="" then \
    {   _._._.UserName$=UID
        _._._.MachineName$=NID
    }
    return

    OC_OpenErr:
    if err=12 then \
    {   keyed _._._.FileName$,[1:1:10:"+"], \
                              [2:1:32:"C"]+[3:1:96:"CU"]+[4:1:50:"C"]+[5:1:50:"C"]+[6:1:5], \
                              [4:1:50:"C"]+[2:1:32:"C"]+[3:1:96:"C"]+[6:1:5], \
                              [5:1:50:"C"]+[2:1:32:"C"]+[3:1:96:"C"]+[6:1:5], \
                              0,-30000,opt="X",sep=*,bsz=31
        open object lock (_._._.Channel) _._._.FileName$
        if pos("IX" = ucs(SYS)) \
            then invoke "chmod 666 "+pth(_._._.Channel), err=*proceed
        password (_._._.Channel) "*PaRaMTr" required for open and on data
        close (_._._.Channel)
        goto OCRetryOpen
    }
    exit err

!
OnDelete:
    if _._._.Channel \
        then close(_._._.Channel)
    return
!
SetTheVar:
    switch _._._.DataType$
        case "S"
            via _._._.VariableName$ = _._._.CurrentValue$, err=*next; break
            via _._._.VariableName$ = "", err=*next ;break
            break

        case "N"
            via _._._.VariableName$ = num(_._._.CurrentValue$,err=*next); break
            via _._._.VariableName$ = 0, err=*next; break
            break

        case "B"
            via _._._.VariableName$ = tbl(num(_._._.CurrentValue$,err=*next) = 0, 1, 0); break
            via _._._.VariableName$ = 0, err=*next; break
            break

        case "P"
            setparam evs("'"+sub(_._._.VariableName$,"'","")+"'")=num(_._._.CurrentValue$,err=*next); break
            break
    esac
    return
!
GetTheVar:
    switch _._._.DataType$
        case "S"
            _._._.CurrentValue$=vis(_._._.VariableName$,err=*next); break
            _._._.CurrentValue$=""; break

        case "N"
            _._._.CurrentValue$=str(vin(_._._.VariableName$,err=*next)); break
            _._._.CurrentValue$="0"; break

        case "B"
            _._._.CurrentValue$=str(tbl(vin(_._._.VariableName$,err=*next)=0, 1, 0)); break
            _._._.CurrentValue$="1"; break

        case "P"
            _._._.CurrentValue$=str(prm(evs("'"+sub(_._._.VariableName$,"'","")+"'"),err=*next)); break
            _._._.CurrentValue$="-1"; break

    esac
    return

! File Layout for a Parameter file
! Field 1,  EntryNumber          10 byte string - Zero Filled Auto Increment
! Field 2,  Application$         32
! Field 3,  Reference$           96
! Field 4,  MachineName$         50
! Field 5,  UserName$            50
! Field 6,  Counter$             5 byte string zero filled number
!
! Field 7,  VariableName$        Name of variable/parameter to set
! Field 8,  DataType$            string|Number|Boolean|system Parameter 1 byte
! Field 9,  MinimumValue$        string of minimum setting
! Field 10, MaximumValue$        string of maximum setting
! Field 11, Prompt$              Description for Prompts, first char is * then its a message lib key
! Field 12, CurrentValue$        Current Value of VariableName
!
! keyed "Filename",[1:1:10:"+"],[2:1:32:"C"]+[3:1:96:"CU"]+[4:1:50:"C"]+[5:1:50:"C"]+[6:1:5],0,-30000,opt="X",sep=*,bsz=31
ParameterIOList: iolist _._._._.EntryNumber$, \
                        _._._._.Application$,_._._._.Reference$, \
                        _._._._.MachineName$,_._._._.UserName$, \
                        _._._._.Counter$,_._._.VariableName$, \
                        _._._.DataType$,_._._.MinimumValue$, \
                        _._._.MaximumValue$,_._._.Prompt$, \
                        _._._.CurrentValue$
!
! Note:
! For strings, the min and max values are string lengths
! For numerics, the min and max values are numbers
! For booleans, the min=0 and the max=1
! for Parameters, the min and max are ignored.
