[comp.sys.ibm.pc] Cannot putenv

toma@tekgvs.TEK.COM (Thomas Almy) (05/19/87)

I had been using a clever version of PUSHD/POPD, written in Turbo Pascal,
which saved the directory stack in an environmental variable string.  (This
program was posted here about a year ago).  Well it worked fine until my
environment became greater than 20 paragraphs.  At that point the Turbo
program dies because the maximum string size in Turbo is 255 characters.

Noticing the existance of getenv and putenv (yes!) in Microsoft C, I decided
to rewrite these programs.  After all, the hard work in the Turbo program
was to do the getenv and putenv operations.  Writing these programs in C
should have proved to be a snap.

But putenv() does not appear to actually set the environment!  Just the one
local to the program!  What good is this??

Considering this, the example program in the Microsoft manual (which sets
the path) is completely worthless.

I suppose I should have known better since Microsoft C's  library is supposed
to mimic *NIX as close as possible and putenv won't work there either!

Now it looks like I will have to rewrite putenv() (using the Turbo version as
a guide), but before I do, has anyone done this already?  Or is there a
public domain PUSHD/POPD out there that will do the job?

Tom Almy

mason@gargoyle.UChicago.EDU (Tony Mason) (05/19/87)

In article <2301@tekgvs.TEK.COM> toma@tekgvs.UUCP (Thomas Almy) writes:
>But putenv() does not appear to actually set the environment!  Just the one
>local to the program!  What good is this??
>
>Considering this, the example program in the Microsoft manual (which sets
>the path) is completely worthless.
>
>I suppose I should have known better since Microsoft C's  library is supposed
>to mimic *NIX as close as possible and putenv won't work there either!

This mechanism is rather useful for such obscure things as allowing a program
to control the environment of it's children.  I have used this for
rudimentary security (it actually works quite efficiently), multiple database
handling, path control, etc.

The erroneous assumption is that these routines should modify the parents
environment.  Since each program has its own environment, putenv works on the
current environment.  This environment is then passed onto children, but
disappears when the parent (and all its decendants) go away.

Programs which modify the parental environment (and it can be done fairly
easily in MS-DOS) seem to cause more problems than they are worth.  I don't
use commercial programs that think they can clobber my environment with
impunity (and there are several out there that do!)

Thus, the example Microsoft gives is useful because it allows the PROGRAM to
control its environment - it could take the current path, append a default
directory to it and let the library routines deal with where a file REALLY
is.

Tony Mason
Univ. of Chicago, Dept. of C.S.
ARPA: mason@gargoyle.uchicago.edu
UUCP: ...ihnp4!gargoyle!mason

madd@bucsb.bu.edu.UUCP (Jim "Jack" Frost) (05/19/87)

In article <2301@tekgvs.TEK.COM> toma@tekgvs.UUCP (Thomas Almy) writes:
>I had been using a clever version of PUSHD/POPD, written in Turbo Pascal,
>which saved the directory stack in an environmental variable string.  (This
>program was posted here about a year ago).  Well it worked fine until my
>environment became greater than 20 paragraphs.  At that point the Turbo
>program dies because the maximum string size in Turbo is 255 characters.
>[...]
>Now it looks like I will have to rewrite putenv() (using the Turbo version as
>a guide), but before I do, has anyone done this already?  Or is there a
>public domain PUSHD/POPD out there that will do the job?

If you already have the Turbo source, it might be easier to redefine
the string functions supported in TP.  I once wrote a series of
functions that operated on strings of up to 64K by defining strings
the way C does -- series of chars null terminated.  To do this, define
a type like:

  type str = ^array[0..0] of char;

[This of course will be limited to 32K strings because that's MAXINT,
but it's simple enough to start the array at -MAXINT to get 64K
(almost) strings.]

Then declare your string as an array of chars, making it as big as you
like:

  var bigstring = array[0..20000] of char;

A sample function would look like:

  function strlen(s : str);
  var l;
  begin
    l:= 0;
    while s^[l] <> chr(0) do
      l:= l+1;
    strlen:= l
  end;

Pass the string to functions using the addr() function:

  slen = strlen(addr(bigstring));

If you know C, then you realize that the str type is equivalent to the
(char *) type, while array[] of char is (char).  It's nice of TP not
to do array subscript checking by default, since it makes it easy to
create these kinds of functions (which are really really illegal in
standard Pascal, but terribly useful).

Of course, these functions will operate considerably slower than their
TP counterparts, but in practice this is usually negligible.  I wrote
most of a shell program using them, with no problems.  The only thing
that's annoying is having to pass addr(stringname) instead of just
stringname, but you can get around this as follows:

  var strspace : array[0..whatever] of char;
      bigstr : str;
      len : integer;
      {...}

  begin
    bigstr:= addr(strspace);
    {...}
    len:= strlen(bigstr);
    {...}
  end.

You get the idea.  This might be a better solution to your problem,
because you can just replace functions within the program you already
have.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          Jim Frost * The Madd Hacker | UUCP: ..!harvard!bu-cs!bucsb!madd
  H H                                 | ARPA:           madd@bucsb.bu.edu
H-C-C-OH <- heehee          +---------+----------------------------------
  H H                       | "We are strangers in a world we never made"

martyl@rocksvax.UUCP (Marty Leisner) (05/20/87)

In article <2301@tekgvs.TEK.COM> toma@tekgvs.UUCP (Thomas Almy) writes:
>But putenv() does not appear to actually set the environment!  Just the one
>local to the program!  What good is this??
>
>Considering this, the example program in the Microsoft manual (which sets
>the path) is completely worthless.
>
I just spent a significant amount of time emulating putenv() for Aztec C (I
recompiled Allen Holub's shell and /util with Aztec and made some modifications --
Programs should generally only set environment variables to pass on to child 
processes.  I believe that's the way Unix works -- the child process 
inherits the environment of the parent but can't change the environment of the
parent.

MSDOS appears to do some flukey things with the environment (and I don't
think it is very well documented).  My understanding is when DOS loads a 
new program it makes a copy of the environment and the new program has a 
pointer into this space (aligned on a segment boundary).  If changes are
to be made, the environment needs to be copied into the user's data space and changes made there.

So the child program would have to take extraordinary actions to set the
parents environment (I think there's something about interrupt 2e which 
allows programs to send commands to command.com -- if this is so, doing a
SET var=name would set the parent environment (???)).  In addition, if the
child program would just clobber memory, how would it know it was overwriting
something which isn't environment space.

By the way, the environment allows me to overcome a significant limitation
of MSDOS (the 128 byte command line).  Aztec looks for a null environment
variable (an '=' with nothing in front) and will get a command line from
there if the C startup routine sees it.  So my shell automatically puts
extended command lines in the environment variable '=" before execing the
child process.  If the child was compiled by Aztec, it will get the command
line from the environment variable.


marty leisner
xerox corp.
leisner.henr@xerox.com
martyl@rocksvax.uucp

leder@ihlpm.UUCP (05/20/87)

In article <2301@tekgvs.TEK.COM>, toma@tekgvs.TEK.COM (Thomas Almy) writes:
> 
> 
> 
> I had been using a clever version of PUSHD/POPD, written in Turbo Pascal,
...
> to rewrite these programs.  After all, the hard work in the Turbo program
> was to do the getenv and putenv operations.  Writing these programs in C
> should have proved to be a snap.
> 
> But putenv() does not appear to actually set the environment!  Just the one
> local to the program!  What good is this??

Obviously, for your purposes it was not any good at all, but you were
close to the right solution.  There is an undocumented dos interrupt (i 
think that its 32, but i'm sure someone will help with the number. It was
reported in PC Mag. 

This interrupt sends a command for the lowest level COMMAND.COM to
execute, which since its environment pointer is still at the right place,
causes changes to the low level environment after the caller has exited.

First you may need to use the SETENV command that came with Microsoft C to
expand the size of your environment.

Bob Leder - just adding confusion to the chaos

catone@dsl.cis.upenn.edu (Tony Catone) (05/28/87)

In article <1092@rocksvax.UUCP> martyl@rocksvax.UUCP (Marty Leisner) writes:
>So the child program would have to take extraordinary actions to set the
>parents environment (I think there's something about interrupt 2e which 
>allows programs to send commands to command.com -- if this is so, doing a
>SET var=name would set the parent environment (???)).

There was much discussion about achieving just this effect within the
last month, in either PC-Mag or Info-PC Digest, or possibly both.
The master environment can be modified, once it is located through
the use of undocumented DOS function calls.  I'm leaving for 2 weeks
vacation (yea!) tomorrow, but if enough people email me, I'll dig
the information up and post it upon my return.

					- Tony
					  catone@dsl.cis.upenn.edu
					  catone@wharton.upenn.edu