lupin3@ucscb.UCSC.EDU (-=/ Count Lupin III /=-) (04/04/88)
My older brother has a request; since he does not bother to read the net (he feels my time is worthless enough :) he had me post this, and read all the replies. I have been watching for subjects which addressed this question, and have seen none; so I have posted this article. If you feel that this info is current enough to do a followup, fine; otherwise, you can mail me your answer, or mail it directly to him (acct. "webster", same path). Here is his question: | o / +------X---cut-here----------------------------------- | O \ 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. A magazine I read suggested this as the solution: system( "SET FOO=BAR"); but this did not work for me. The environment remained unchanged when the program terminated. | o / +------X---cut-here----------------------------------- | O \ aTdHvAaNnKcSe. -- /|\ /|\ .. . . . . . . . . . . | |\| |\| .. . . . . . . . . . . |/|\|/|\|/|| _ _ _ _ |_| _ _ |_ -__ _ _ARPA: lupin3@ucscb.ucsc.EDU | |/| |/|L_ (_\( ( (_/ | |(_\_) (_ || )(_)_)UUCP: *!ucbvax!ucscc!ucscb!lupin3 \|/ \|/ larry / hastings _/ BITNET: lupin3@ucscb@ucscc.BITNET MetaWare Inc "I saved Esquire readers from exploding pies." --Michael J. Fox Sail the High C! Disclaimer:[MetaWare, UCSC] -> opinion != lhastings -> opinion
ajmyrvold@violet.waterloo.edu (Alan Myrvold) (04/06/88)
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 <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <process.h> #include <conio.h> #include <dos.h> 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); }
ajmyrvold@violet.waterloo.edu (Alan Myrvold) (04/06/88)
OOPS ... bug in my earlier posting! Re: <6244@watdragon.waterloo.edu> on changing the environment areas. Change : >/* Update BOTH copies of the environment */ > write_env(env_seg[0],k,s,t); > write_env(env_seg[1],k,s,t); to : >/* Update ONE copy of the environment */ > write_env(env_seg[1],k,s,t); Sorry about my initial confusion, but I still don't understand it all completely. ------------------------------------------------------------------- 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 -------------------------------------------------------------------