[comp.unix.questions] More questions about how to issue a C-SHELL command within a C program

jian@kuhub.cc.ukans.edu (08/15/90)

Yesterday I asked for help about how to issue a C-SHELL command within a C 
program. I was lucky: serveral people came up with immediate answers. I very
much appreciate those answers.

According to the answers and what I read from the menu, system() and execlp()
should work without any doubts. However, I can't make it. What I want to do
is to issue a csh command to change terminal type within a C program. I did 
try:
        system("csh -cf \"setenv TERM adm3a"); 
   and
        system("/bin/csh -c 'setenv TERM adm3a");

   and
        execlp("/bin/csh", "csh", "-c", "setenv TERM adm3a", (char *) 0);

There was not any runtime errors if I embeded one of above statements into my
C program. But none of them can change the terminal type. I don't know why.
Would someone point me another way to change terminal type within a C program
or give me some hints what I did wrong. I would appreciate any helps.

Jian Q. Li
jian@kuhub.cc.ukans.edu

merlyn@iwarp.intel.com (Randal Schwartz) (08/16/90)

In article <25285.26c9113d@kuhub.cc.ukans.edu>, jian@kuhub writes:
| Yesterday I asked for help about how to issue a C-SHELL command within a C 
| program. I was lucky: serveral people came up with immediate answers. I very
| much appreciate those answers.
| 
| According to the answers and what I read from the menu, system() and execlp()
| should work without any doubts. However, I can't make it. What I want to do
| is to issue a csh command to change terminal type within a C program. I did 
| try:
|         system("csh -cf \"setenv TERM adm3a"); 
|    and
|         system("/bin/csh -c 'setenv TERM adm3a");
| 
|    and
|         execlp("/bin/csh", "csh", "-c", "setenv TERM adm3a", (char *) 0);
| 
| There was not any runtime errors if I embeded one of above statements into my
| C program. But none of them can change the terminal type. I don't know why.
| Would someone point me another way to change terminal type within a C program
| or give me some hints what I did wrong. I would appreciate any helps.

Aha.  As I said in my private mail, *why* would you want to execute a
csh command?  Now I can see.

The short answer:

You *cannot* change an environment variable (such as TERM) from a
child process.  The shell provides a *copy* of its environment to the
children processes (such as your C program), so changes to that copy
(or in your case, using a further csh which has its *own* copy), will
not affect the parent shell.  This is by design, so don't ask "Well,
are they going to fix this some day?"

The longer answer:

If you invoke a program from the shell in such a way that the shell is
going to expect an answer back and take action on that, you can get
away with it.  For example, if your program "pickterm" is invoked
from the csh as:

	setenv TERM `pickterm`

then all "pickterm" has to do is output the desired term-type on
stdout.  If you need interaction, you may need to arrange for the csh
to get it from a file.  For example,

	pickterm /tmp/$$ && setenv TERM `cat /tmp/$$`
	rm /tmp/$$

in which case pickterm would open /tmp/$$ for output, put the desired
termtype into it after interacting with the user, and then exit
successfully.

Either of these solutions could be wrapped up inside an alias to
prevent the nitty gritties from being exposed to the poor user.

Just another Unix hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

fpb@ittc.wec.com (Frank P. Bresz) (08/16/90)

In article <1990Aug15.221504.348@iwarp.intel.com> merlyn@iwarp.intel.com (Randal Schwartz) writes:
>In article <25285.26c9113d@kuhub.cc.ukans.edu>, jian@kuhub writes:

	[ Stuff deleted ]

>|         execlp("/bin/csh", "csh", "-c", "setenv TERM adm3a", (char *) 0);
>| 
>| There was not any runtime errors if I embeded one of above statements into my
>| C program. But none of them can change the terminal type. I don't know why.
>| Would someone point me another way to change terminal type within a C program
>| or give me some hints what I did wrong. I would appreciate any helps.

>The short answer:

>You *cannot* change an environment variable (such as TERM) from a
>child process.  The shell provides a *copy* of its environment to the
>children processes (such as your C program), so changes to that copy
>(or in your case, using a further csh which has its *own* copy), will
>not affect the parent shell.  This is by design, so don't ask "Well,
>are they going to fix this some day?"

	Why not just use the putenv system call with something akin to:

putenv("TERM=adm3a");	/* notify subprocess that it is an adm3a terminal */


--
+--------------------+
|fbresz@ittc.wec.com |  My opinions are my own, I'm not paid
|uunet!ittc!fbresz   |  enough to make an official statement  
|(412)733-6749       |  +-----------------------------------+
|Fax: (412)733-6444  |  |      THIS SPACE FOR SALE!!!       |
+--------------------+  +-----------------------------------+

merlyn@iwarp.intel.com (Randal Schwartz) (08/16/90)

In article <FPB.90Aug16004855@ittc.ittc.wec.com>, fpb@ittc (Frank P. Bresz) writes:
| 	Why not just use the putenv system call with something akin to:
| 
| putenv("TERM=adm3a");	/* notify subprocess that it is an adm3a terminal */

Nope.  That changes the *current* process (the C program), not the
parent process (the parent shell).  You *must* involve the parent
process if you want programs invoked after the C program to see the
change (unless you intend the C program to perform all the future
invocations... yuck).

Just another UNIX hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/16/90)

In article <25285.26c9113d@kuhub.cc.ukans.edu> jian@kuhub.cc.ukans.edu writes:
>        system("/bin/csh -c 'setenv TERM adm3a");

(You're missing a quote ')

>But none of them can change the terminal type. I don't know why.

Your problem is that no change made to the environment variables of a
subprocess can affect the environment variables of an ancestor process.

This is why most of us make sure our TERM environment variable is properly
set up by a file that is SOURCED, not executed in a subprocess, when our
shell starts up (e.g. .profile or .login).

guy@auspex.auspex.com (Guy Harris) (08/17/90)

>Would someone point me another way to change terminal type within a C program
>or give me some hints what I did wrong. I would appreciate any helps.

As noted, the environment isn't "global", so setting an environment
variable such as TERM in one process won't affect its value in any other
existing processes; it'll only affect its initial value in processes
forked from that process.

If you want to change the value of an environment variable in a process
running some arbitrary C program, check whether your system has the
"putenv" routine (look for PUTENV(3) in the manual - unless you have
some SCO system wherein they "improved" the manuals by changing the
names of the sections, in which case I've no idea what the name would
be).  If not, see whether it has the "setenv" routine.

If it has one or the other of those routines, the manual page should
show you how to set an environment variable using the routine.

Why do you need to change the setting of TERM within a program?  The
ultimate problem may lie deeper.  (Also bear in mind that you should set
TERM *before* you call *any* "curses" or "termcap" routines; otherwise,
"curses" or "termcap" will start out using the old value of TERM, not
the new value.)

peter@ficc.ferranti.com (Peter da Silva) (08/17/90)

In article <25285.26c9113d@kuhub.cc.ukans.edu>, jian@kuhub.cc.ukans.edu writes:
>         execlp("/bin/csh", "csh", "-c", "setenv TERM adm3a", (char *) 0);

You can't set your environment from a subshell. An environment is owned by
a process and inherited by its children, but never passed back. You need to
do something like print the commands on standard output, the way "tset" does:

47 % tset -s
set noglob;
setenv TERM at/386 console ;
setenv TERMCAP 'at386:am:bw:eo:xo:xt:bs:co#80:li#25:kn#4:ae=^P:al=\E[1L:cd=\E[0J:ce=\E[0K:cl=\E[2J\E[H:cm=\E[%i%2;%2H:ct=\E[3g:dc=\E[1P:dl=\E[1M:ho=\E[H:ic=\E[1@:K1=\EOp:K2=\EOq:K3=\EOr:K4=\EOs:K5=\EOt:K6=\EOu:K7=\EOv:K8=\EOw:K9=\EOx:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\EOT:k6=\EOU:k7=\EOV:k8=\EOW:k9=\EOX:kb=\b:kd=\E[B:kh=\E[H:kl=\E[D:kr=\E[C:ku=\E[A:nd=\E[C:se=\E[m:so=\E[7m:st=\EH:ue=\E[m:up=\E[A:us=\E[4m:ko=do,nd,up,ho';
unset noglob;
48 % grep tset .login
tset -s ... >/tmp/tset$$
source /tmp/tset$$
rm /tmp/tset$$
49 % 

This way the variables get set in the parent shell and so stick around after
the subshell or your C program (which is also a child of the shell) exits.

If you just want to set variables for programs you call, try "putenv".
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com (currently not working)
peter@hackercorp.com