Newsgroups: comp.os.msdos.programmer
Subject: Re: How can you set an environment variable in a program?
From: hdtodd@wccnet.wcc.wesleyan.edu (H. D. Todd)
Date: Wed, 26 Aug 1992 13:42:11 GMT
Organization: Wesleyan University, Middletown, CT USA
Keywords: variable, C

In article <7923PB2w164w@jaflrn.UUCP> Jon Freivald <jaf@jaflrn.UUCP> writes:
>Subject: Re: How can you set an environment variable in a program?

>OK, I don't have TC 2.0, but I do have TC++ 1.0 & 2.0 -- no such critter
>as "setenv()" and "putenv()" only changes the environment for the
>current process -- as soon as you exit, the variable is gone...

	I sent this out a couple of weeks ago in response to a similar 
inquiry.  I should submit it to one of the archives (is SIMTEL the best 
starting point?).  It's a Turbo C program to modify the path (hence "mp") in 
the root DOS command.com process.  You could modify it to do whatever else 
you needed to do (though it's pretty handy on its own merits!).

						David Todd


                           MP -- Modify Path
USAGE
	MP [-{p|a} newpathnode | -r oldpathnode [newpathnode] ]*
FUNCTION
	MP modifies the working path for MS DOS environments by
prepending ("-p") or appending ("-a") a new path node to an existing path
environment or by replacing ("-r") an old path node ("oldpathnode") with
a new path node ("newpathnode") within the existing path.  For the -r
option, the field specifying "newpathnode" can be empty, thus deleting
"oldpathnode" from the search path entirely.
	Note that for the -r switch, the new path node that might replace 
the old path node in the PATH list may be omitted: if so, the old path node
is removed from the PATH list but is not replaced.  Since switches are 
processed in the order entered, a -r followed by a -p or -a can be used
to move a node from the interior of a PATH list to the beginning or end
of that list.
	This program operates on the PARENT process environment, thus
eliminating the requirement to use a batch file or enter a complete new
path specification to make minor modifications to the working path.
IMPLEMENTATION
	MP copies the environment block from the parent process to local
strings, modifies the local string for PATH, then copies the complete
set of environment strings back to the parent environment block.
ERROR CONDITIONS
	MP will report an error and leave the path unmodified if there
is insufficient room in the environment block for the modified PATH
environment variable.  In this situation, the path could not be
modified even at the command level.  To prepare for future use of MP or
changes to the path by other methods in this case, increase the size of
the environment block by modifying the CONFIG.SYS file line specifying 
	COMSPEC=dd:COMMAND.COM/e:nnn
to increase (or specify) the /e: parameter for the size of the
environment block.
	MP also reports if a switch is given with no nodename to process, if 
an invalid switch is given, or if switches are not prefixed with '-'.
LANGUAGE AND COMPATIBILITY
	MP is written in TURBOC and has been tested with DOS 3.3 and DOS
4.01.  Since it does not use DOS systems calls to effect the
modifications (and cannot, since DOS does not provide a mechanism for a
child process to change the environment block of its parent), MP may be
incompatible with future versions of DOS.
AUTHOR
	MP was written by H. D. Todd, Wesleyan University, December,
1990 and is supplied in source-code form.  The author would appreciate
receiving bug reports and modifications (send to
HDTodd@eagle.wesleyan.edu or HDTodd@wesleyan.bitnet).

/* mp.c
   Program to modify the path environment for MS-DOS.
   Written by H. D. Todd, Wesleyan University, 12/26/90 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#define MAXSTRS 100		/* increase this if you have more env strings */
#define MAXPATH 500		/* max size of path string */
#define PATHSEP ";"		/* separates node names in path */
void main(int argc, char *argv[])
{
  int i, num, envsize, len, nstrs=0, nextra, pathindex;
  char dowhat, varstg[MAXPATH], tmpstr[MAXPATH],
        *strptr[MAXSTRS], far *envp, far *envptr, *subloc;
  unsigned far *p_psp, far *p_env;
  struct {
         char link;
         unsigned int owner_psp;
         unsigned int blk_len;
         } far *envmcb;
  if (argc < 2) {
    fprintf(stderr, "Usage: mp [ -{p|a} newnodename | -r oldnodename newnodename]*\n");
    exit(1); }
/* Construct the PSP pointers */
  p_psp = MK_FP(_psp,0x16);    /*pointer to parent's PSP*/
  p_env = MK_FP(*p_psp,0x2c);  /*pointer to parent's environment ptr*/
  envptr = MK_FP(*p_env,0x00); /*pointer to parent's environment */
  envmcb = MK_FP(*p_env-1,0x00); /* pointer to parent env MCB */
  envsize = (*envmcb).blk_len<<4;
/* copy strings from parent's environment (FAR) to local strings */
   envp = envptr;
   while (*envp) {      /* env strings terminated by second null */
         int len;
         char far *fp;
         char *lp;
         for (len=0, fp=envp; *fp; fp++) len++;
         lp = strptr[nstrs++] = malloc(len+1);
         for ( ; (*lp++=*envp++); );
         }
/*  find the PATH= string among the env vars */
   for (pathindex=0; pathindex<nstrs; pathindex++) if (strnicmp(strptr[pathindex],"PATH=",5) ==0 ) break;
   if (pathindex>=nstrs) {
       fprintf(stderr, "MP: Can't find path var!\n");
       exit(1);
   }
   strcpy(varstg,strptr[pathindex]);
/*  now do what the switches tell us to do */
   while (--argc > 0 ) {
	if ( ( (dowhat=(*++argv)[0])) != '-') {
		fprintf(stderr, "MP: begin switches with '-', as in '-%c'\n", dowhat);
	     	exit(1);
	}
	dowhat = tolower(*++argv[0]);
	if (dowhat!='p' && dowhat!='a' && dowhat!='r') {
	   fprintf(stderr, "MP: invalid switch -%c\n", dowhat);
	   exit(1);
	};
	if (--argc <=0) {
		fprintf(stderr, "MP: switch -%c missing node name\n", dowhat);
		exit(1);
	}
	switch (dowhat) {
		case 'a':	strcat(varstg,PATHSEP);
				strcat(varstg,*++argv);
				break;
		case 'p':	strcpy(tmpstr,"PATH=");
				strcat(tmpstr,*++argv);
				strcat(tmpstr,PATHSEP);
				strcat(tmpstr,strpbrk(varstg,"=")+1);
				strcpy(varstg,tmpstr);
				break;
		case 'r':	if ( (subloc=strstr(varstg,*++argv)) == NULL) {
					fprintf(stderr,"MP: pathnode %s not found in current path\n", *argv);
					fprintf(stderr,"    replacement ignored");
					while ( *(argv+1)[0] != '-') {
						++argv;
						argc--;
					}
					break;
					};
				strcpy(tmpstr,subloc+strlen(*argv));
				if (*(argv+1)[0] != '-') {
					strcpy(subloc,*++argv);
					--argc;
				    }
                  else subloc = '\0';
				strcat(varstg,tmpstr);
				break;
	};
   }
/*  make sure we can copy it all back into the parent's env block */	
    strptr[pathindex] = &varstg;
    for (i=0, len=0; i<nstrs; i++) len += strlen(strptr[i]) + 1;
    if (len+1>envsize)  {
        fprintf(stderr,"MP: Env block too small to store updated PATH string\n");
        exit(1);
        }
      else {
/*  OK, do it */
        for (i=0; i<nstrs; i++) {
            for ( ; (*envptr++ = *strptr[i]++) ; ) ;
            *envptr = '\0';
        }
      }
}