Fwd: Suggestions for "User" command.

Brian K. White brian at aljex.com
Wed Mar 2 16:16:28 PST 2011


On 3/2/2011 5:09 PM, Dave Snyder wrote:
> ----- Forwarded Message -----
> | From: "Dave Snyder"<dave at wisvis.com>
> | To: "Kenneth Brody"<kenbrody at spamcop.net>
> | Sent: Wednesday, March 2, 2011 4:01:00 PM
> | Subject: Re: Suggestions for "User" command.
> | ----- Original Message -----
> | | From: "Kenneth Brody"<kenbrody at spamcop.net>
> | | To: "Dave Snyder"<dave at wisvis.com>
> | | Cc: filepro-list at lists.celestial.com
> | | Sent: Wednesday, March 2, 2011 3:44:46 PM
> | | Subject: Re: Suggestions for "User" command.
> | | On 3/2/2011 4:33 PM, Dave Snyder wrote:
> | | [... Exiting a USER command ...]
> | |>
> | |>  Anyone have any brilliant ideas for ending the external program
> | |>  besides my @keyX solution.
> | | [...]
> | |
> | | Yes. When your program receives EOF on stdin, exit. No need for any
> | | special "I need to tell the USER program that I'm exiting" logic.
> | |
> | | --
> | | Kenneth Brody
>
>
> I understand. But when I get to the next record (remember that I'm in
> *clerk) and try to use the external program, I have a problem. I originally
> thought that the
>
> if not program
> then user program = /appl/bin/ext-prog
>
> logic would just start the external script again, but that doesn't
> seem to be the case.

I use user in a only a few, but very frequently and heavily used 
routines and I don't have special exit logic in the user command other 
than what Ken said, nor do I ever close aliasname, nor do I have a 
problem with child processes being left behind.

What I DO have is what Ken said, and the fact that I write my processing 
and the user script in such a way as to make it almost impossible to get 
out of step with each other.

There are 2 all important rules I adhere to.

1) The user process is a script that has a very simple "while read" loop 
that loops forever. No special exit command. No variation in the 
sequence of expected input and output. I _always_ read and write exactly 
the same number of lines in exactly the same pattern every iteration of 
the loop. This may mean capturing the output of some commands that can't 
be counted on to always do exactly the same thing, so that I can have 
the script always do exactly the same thing.

2) In processing, _all_ interaction with the user command is done in a 
single gosub, and that gosub has as little fancy conditional logic as 
possible. This is to guarantee that the conversation between processing 
and user script is not merely always in sync, but hard to break by 
fundamental design.

The processing gosub includes the "user foo = foo" right at the top and 
it's _always_ encountered before the first attempted read or write. No 
conditional logic to avoid it.
There is no "close foo" anywhere.

This means when the user starts a clerk session using this table, they 
will have no child user process until the first time the gosub is used, 
if ever.

After the first time the gosub is used, the user process will stay 
around until they exit clerk.

All the time they are in clerk, after the first time they use that user 
process, the user process could be thought of as a harmless idle 
co-process waiting there to perform further jobs if the user needs it. 
When the user moves to another record or recalcs the current record, the 
user command in the gosub will re-use the existing user process, not 
start up a new one, _IF_ the alias name has not changed and if the old 
one has not been closed. You don't need to try to ensure this yourself 
by putting something on the If: line of the user command.

There is one problem with user when used in a cgi process under apache. 
It can cause apache to hang and never conclude it's response to the 
browser. It looks like a page that never finishes loading.
In that case you do have to put special deliberate exit logic in your 
user command. But that's less robust than the way I describe above.


Here is a sample user script:

#!/bin/ksh
KEY="$1"
LANG=C
tr_b64orig='+/=\n'  # url-unsafe chars in base64 output
tr_urlsafe='\-_.~'  # url-safe replacements for above

case ${0##*/} in

  cgc) # encrypt
   while read ; do
    print -- "${REPLY}\c" |openssl rc4-40 -K $KEY -iv '' -a |tr 
$tr_b64orig $tr_urlsafe
    echo
   done
  ;;

  uncgc) # decrypt
   while read ; do
    print -- "${REPLY}\c" |tr $tr_urlsafe $tr_b64orig |openssl rc4-40 -K 
$KEY -iv '' -a -d
    echo
   done
  ;;

esac


And here is the gosub: (the script is named cgc and is in $PATH , so I 
don't have to specify the full path here, which is more portable and 
flexible, and there is no reason not to have the alias the same as the 
actual script name, it simplifies reading to me since the actual script 
name is not referred to in any other way in any other place, so there is 
no potential for confusion or ambiguity)

encrypt: If:
Then: user cgc = cgc
If:
Then: cgc = plaintext
If:
Then: encrypted = cgc
If:
Then: return

This is used a _lot_ and has been just like this for several years by 
us. It's well proven. Sco open server, Solaris, Linux, Freebsd.

-- 
bkw


More information about the Filepro-list mailing list