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