Path: utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!mailrus!tut.cis.ohio-state.edu!osu-cis!att-cb!clyde!watmath!watdragon!violet!ajmyrvold From: ajmyrvold@violet.waterloo.edu (Alan Myrvold) Newsgroups: comp.sys.ibm.pc Subject: Re: Changing environment PERMANENTLY from within a C program Message-ID: <6244@watdragon.waterloo.edu> Date: 5 Apr 88 20:05:34 GMT References: <2621@saturn.ucsc.edu> Sender: daemon@watdragon.waterloo.edu Reply-To: ajmyrvold@violet.waterloo.edu (Alan Myrvold) Distribution: na Organization: U. of Waterloo, Ontario Lines: 272 In article <2621@saturn.ucsc.edu> lupin3@ucscb.UCSC.EDU (-=/ Count Lupin III /=-) writes: >Can someone tell me a way to change an environment variable from >within a C program, and have the change be permanent when the program >terminates? Using the putenv() call only changes the copy of the >environment local to the C program; I need a way to change the environment >of the COMMAND shell which exec'ed the C program. I often wondered that myself. Perhaps the correct attitude is : "If Microsoft intended you to change the COMMAND.COM environment from within an application program, they would have made it easier to do" Anyway, attached is a Turbo C version 1.0 program which changes the parent's environment area. This program defines a variable called TODAY, with a date string that will match those put out by the DOS dir command. When the program terminates, the variable is still defined. A batch file called TODAY.BAT could contain : dir *.* | find "%TODAY%" and this would show the files modified today, provided the TODAY environment variable has been set. Happy hacking. Alan Myrvold ajmyrvold@violet.waterloo.edu ------------------------------------------------------------------- Si je t'aime? Bien sur que je t'aime! Ne suis-je pas en train de te le prouver encore une fois, dans ce lit? ------------------------------------------------------------------- Alan Myrvold ajmyrvold@violet.waterloo.edu ------------------------------------------------------------------- - setenv.c -------------------------------------------------------- /* Demonstrate changing parent's environment with Turbo C v. 1.0 written 4-05-88 by Alan J. Myrvold ajmyrvold@violet.waterloo.edu WARNING WARNING WARNING - virtually no error checking is done !! use at own risk !! This program defines an environment variable called TODAY, which contains today's date in the same format DOS uses in directory listings. So a file called TODAY.BAT containing : dir *.* | find "%TODAY%" will show files in the current directory which were modified today, if the TODAY environment variable has been set. */ /* Technical information : A program's PSP contains a pointer at offset 44 (decimal) to a COPY of the parent's environment. The environment is a set of strings of the form NAME=value, each terminated by a NULL byte. An additional NULL byte marks the end of the environment. The environment area is ALWAYS paragraph aligned i.e. on a 16 byte boundary. Searching backwards from the PSP, I consistently find two copies of the envronment area. The program : finds the two areas reads one into memory udpates the TODAY variable writes BOTH out to memory */ #include #include #include #include #include #include #include int env_size_bytes(unsigned env_seg) /* Determine the length of the environment area in bytes */ { int n; n = 0; while (peekb(env_seg,n) != 0) { while (peekb(env_seg,n) != 0) n++; n++; } return(n); } int env_size_strings(unsigned env_seg) /* Determine how many strings are in the environment area */ { int k,n; k = n = 0; while (peekb(env_seg,n) != 0) { k++; while (peekb(env_seg,n) != 0) n++; n++; } return(k); } int peek_cmp(unsigned seg1,unsigned seg2,int nbytes) /* A trivial compare routine for segement aligned data items */ { int i; for (i = 0; (i < nbytes) && (peekb(seg1,i) == peekb(seg2,i)); i++); return(i == nbytes); } void find_env(unsigned seg_ray[2]) { unsigned psp_seg,copy_of_seg,env_seg; int k,n; /* Find first copy of environment */ psp_seg = getpsp(); copy_of_seg = peek(psp_seg,44); /* Set return value to non-garabage */ seg_ray[0] = seg_ray[1] = copy_of_seg; /* Search back to find 2 copies of environment */ n = env_size_bytes(copy_of_seg); env_seg = copy_of_seg - 1; for (k = 0; (env_seg != 0) && (k < 2); k++) { while ((env_seg != 0) && (peek_cmp(copy_of_seg,env_seg,n) == 0)) { env_seg--; } if (env_seg != 0) { seg_ray[k] = env_seg; env_seg--; } } /* If not found, display error message and abort */ if (k != 2) { printf("ERROR : Two copies of the environment were not found\n"); exit(0); } } void read_env(unsigned env_seg,int *k,char ***s,char ***t) /* Read environment into a malloc'd array of malloc'd strings */ { int i,j,n; *k = env_size_strings(env_seg); *s = (char **) malloc((*k)*sizeof(char *)); *t = (char **) malloc((*k)*sizeof(char *)); n = 0; for (i = 0; i < *k; i++) { for (j = 0; peekb(env_seg,n+j) != '='; j++); (*s)[i] = (char *) malloc(j+1); for (j = 0; peekb(env_seg,n+j) != '='; j++) ((*s)[i])[j] = peekb(env_seg,n+j); ((*s)[i])[j] = 0; n += j + 1; for (j = 0; peekb(env_seg,n+j) != 0; j++); (*t)[i] = (char *) malloc(j+1); for (j = 0; peekb(env_seg,n+j) != 0; j++) ((*t)[i])[j] = peekb(env_seg,n+j); ((*t)[i])[j] = 0; n += j + 1; } } void write_env(unsigned env_seg,int k,char **s,char **t) /* Write the environment back out to memory */ { int i,j,n; n = 0; for (i = 0; i < k; i++) { for (j = 0; (s[i])[j] != 0; j++) { pokeb(env_seg,n,(s[i])[j]); n++; } pokeb(env_seg,n,'='); n++; for (j = 0; (t[i])[j] != 0; j++) { pokeb(env_seg,n,(t[i])[j]); n++; } pokeb(env_seg,n,0); n++; } pokeb(env_seg,n,0); } char *get_env_var(int k,char **s,char **t,char *var) /* Return the value of the environment variable or NULL if not found */ { char *val; int i; val = NULL; for (i = 0; i < k; i++) if (stricmp(s[i],var) == 0) val = t[i]; return(val); } void set_env_var(int *k,char ***s,char ***t,char *var,char *val) /* Set a new or existing environment variable to a new value */ { int i,done; done = 0; for (i = 0; i < *k; i++) if (stricmp((*s)[i],var) == 0) { /* Existing variable */ done = 1; free((*t)[i]); (*t)[i] = (char *) malloc(1+strlen(val)); strcpy((*t)[i],val); } if (!done) { /* New environment varaible */ (*k)++; *s = realloc(*s,(*k)*sizeof(char *)); *t = realloc(*t,(*k)*sizeof(char *)); (*s)[*k-1] = (char *) malloc(1+strlen(var)); strcpy((*s)[*k-1],var); strupr((*s)[*k-1]); (*t)[*k-1] = (char *) malloc(1+strlen(val)); strcpy((*t)[*k-1],val); } } void show_env(int k,char **s,char **t) /* Display the array of environment strings */ { int i; for (i = 0; i < k; i++) printf("%s=%s\n",s[i],t[i]); } main() { unsigned env_seg[2]; char **s,**t,tmp[20]; int k; long now; struct tm *local; /* Find and read environment */ find_env(env_seg); read_env(env_seg[1],&k,&s,&t); /* Get today's date into a string */ time(&now); local = localtime(&now); sprintf(tmp,"%d-%02d-%02d",1 + local -> tm_mon,local -> tm_mday, local -> tm_year); /* Set the TODAY variable in the environment */ set_env_var(&k,&s,&t,"TODAY",tmp); /* Update BOTH copies of the environment */ write_env(env_seg[0],k,s,t); write_env(env_seg[1],k,s,t); }