Note: This is not the current faq for comp.unix. programmers. It was the first faq for cup. It's presented here for historical purposes only. This is still a work in progress, feel free to share any questions or answers. comp.unix.programmer FAQ - Maintainer Patrick Horgan Contributors: Patrick J. Horgan patrick at ootbcomp.com Stephen Baynes bay...@ukpsshp1.serigate.philips.nl James Raynard <jrayn...@dial.pipex.com> Michael F. Quigley (mich...@cybernetics.net) Daniel Brandt dbra...@crl.com Steve Badrich sbadr...@mcimail.com 1) How does fork work? 2) How can I find out the value of/set an environment variable from a program? 3) I have to monitor more than one (fd/connection/stream) at a time. How do I manage all of them? 4) How can I tell when the other end of a connection shuts down? (question 1 of the sockets FAQ) 5) How can I get a more precise timer? (question 4.6 of comp.unix.questions FAQ) 6) How can a parent and child process communicate. 7) My program generates a lot of zombie processes. How do I get rid of them? (question 3.13 of the comp.unix.questions FAQ) 8) How do I find out the address of a remote site connected to me? (question IV.9 of the sockets FAQ) 9) How do I find out the address of my socket? 10) How do I get my program to act like a daemon? 11) What books can I read to learn about Unix programming. 12) Where can I get the source from these books? 13) How can I look at process in the system like ps does? 14) How can I debug the children after a fork? 15) How can I tell how much memory my system has? 16) Given a pid, how can I tell if it's a running program? 17) After running my program once I can't run it again until some time out happens...The os complains about the port already being in use. (question II.7 in the sockets FAQ) 18) system()/pclose()/waitpid() doesn't seem to return the exit value of my process...or the exit value is shifted left 16 bits...what's the deal? 19) How can I make my program not echo input like login does when asking for your password? 20) How can I check and see if a key was pressed? I'm looking for something like the dos kbhit() command. 21) How can I move the cursor around the screen, to do full screen editing without using curses? ~~~ 1) How does fork work? #include <sys/types.h> #include <unistd.h> pid_t fork(void); The fork() function is used to create a new process from an existing process. The new process is called the child process, and the existing process is called the parent. You can tell which is which by checking the return value from fork(). The parent gets the childs pid returned to him, but the child gets 0 returned to him. Thus this simple code illustrate's the basics of it. main() { int pid; if((pid=fork())>0){ /* pid greater than zero is parent getting the child's pid */ printf("Child's pid is %d\n",pid); } else if(!pid){ /* pid of zero is the child */ /* Here we're the child...what should we do? */ } else{ /* Here pid is -1, the fork failed */ /* Some possible reasons are that you're */ /* out of process slots or virtual memory */ perror("The fork failed!"); } } Of help when doing this is knowing just what is and is not inherited by the child. This list can vary depending on Unix implementation, so take it with a grain of salt. Note that the child gets COPIES of these things, not the real thing. Note that the following two sections talk about the usual state of affairs, it can vary between OSs. Inherited by the child from the parent: o real user ID, real group ID, effective user ID, effective group ID. o supplementary group IDs o environment o stack o memory o open file descriptors o close-on-exec flags o signal handling settings o set-user-ID and set-group-ID mode bits o nice value o scheduler class o process group ID o session ID o current working directory o root directory o file mode creation mask (umask) o resource limits o controlling terminal o saved user ID and group ID Unique to the child: o process ID o different parent process ID o Own copy of file descriptors and directory streams. o process, text, data and other memory locks are NOT inherited. o process times, in the tms struct o resource utilizations are set to 0 o pending signals initialized to the empty set o timers created by timer_create not inherited o asynchronous input or output operations not inherited ~~~ 2) How can I find out the value of/set an environment variable from a program? Getting the value of an environment variable is done by using getenv(3C). #include <stdlib.h> char *getenv(const char *name); Setting the value of an environment variable is done by using putenv(3C). #include <stdlib.h> int putenv(char *string); Suppose you wanted to get the value for the TERM environment variable. You would use this code. char *envvar; envvar=getenv("TERM"); printf("The value for the environment variable TERM is " if(envvar){ printf("%s\n",envvar); } else{ printf("not set.\n" } Now suppose you wanted to create a new environment variable called MYVAR, with a value of MYVAL. This is how you'd do it. char envbuf[256]; sprintf(envbuf,"MYVAR=%s","MYVAL"); if(putenv(envbuf)){ printf("Sorry, putenv() couldn't find the memory for %s\n",envbuf); /* Might exit() or something here if you can't live without it */ } ~~~ 3) I have to monitor more than one (fd/connection/stream) at a time. How do I manage all of them? The answer to this one can vary depending on whether you're using system V or bsd derived unix. BSD derivative will use select() and SYSV derivatives will use poll(). Note that SVR4 supports select() as well. For portability, it might very well be the best to stick with select(), but don't be afraid to go with poll() if you're sure that you won't need to port. Note that the particular fds that work as expected with this can vary by OS. We'll cover each. First, for each, you may want to put the file descriptor in non-blocking mode. You do this in a variety of ways. If you're using open() to get a file descriptor, you can use the O_NONBLOCK flag to put the stream in non-blocking mode. fd=open("our/file",O_RDWR|O_NONBLOCK); If one is already open, we can use fcntl() to put it in non-blocking mode. int flags; if((flags=fcntl(fd,F_GETFL,0))!=-1){ if(fcntl(fd,F_SETFL,(flags|O_NONBLOCK))==-1){ fprintf(stderr,"fcntl(fd,O_NONBLOCK) failed with errno %d",errno); } } We can also use an ioctl() to put the stream in non-blocking mode. const int one=1; if(ioctl(fd,FIONBIO,&one)==-1){ fprintf(stderr,"ioctl(fd,FIONBIO,1) failed with errno %d",errno); } As you can see the ioctl() is simpler, but the choice is up to you. Either method works with socket under BSD or SYSV. Now assume that you've got two file descriptors, fd1, and fd2. Whether these file descriptors came from socket() call, or open() is immaterial, we'll just call them file descriptors, and assume that you've put each of them in non-blocking mode. BSD (actually works with SVR4 as well.) The first thing we'll do is learn about the fd_set. An fd_set is essentially an array of bits, with each bit position corresponding to a file descriptor number, with bit 0 corresponding to fd number 0, etc... fd0 fd1 fd2 +---+---+---+-------------------------+ | 0 | 0 | 0 | . . . | +---+---+---+-------------------------+ We know something is true about an fd if the corresponding bit is turned on. fd0 fd1 fd2 +---+---+---+-------------------------+ | 0 | 1 | 0 | . . . | +---+---+---+-------------------------+ so in this case, we'd know that something, (depending on context,) was true about fd1, but not about fd0 or fd2. If you #include <sys/types.h> you'll get access to several macros that make dealing with fd_set's easier. The first one is FD_ZERO, and is used to set all the bits to zero. fd_set myfds; int fd1,fd2; FD_ZERO(&myfds); Then we can use another macro, FD_SET, to pull up the bits that we're interested in. FD_SET(fd1,&myfds); FD_SET(fd2,&myfds); Now before using select we only need one more thing. select will want an argument that says the number of file descriptors we care about in the fd_set. You have to start from zero, and go up to the highest file descriptor number you have. The usual thing is to use the maximum of the fd numbers, (plus one to make it a number instead of an offset.) int fd_max; fd_max = 1+ fd1<fd2?fd2:fd1; Now we can tell select about what we want to do: if(select(fd_max,&myfds,(fd_set *)0,(fd_set *)0, (struct timeval *)0)<0){ if(errno!=EINTR){ /* Here you had some failure other than an expected one. * You might want to abort execution. * an EINTR just means that some interrupt happened...in this * case we usually just start over. */ } else{ continue; } } Now we want to be able to tell if something is available for reading, so we use another macro, FD_ISSET, to check. if(FD_ISSET(fd1,&myfds)){ /* Something available from fd1, read it and process it. */ } if(FD_ISSET(fd2,&myfds)){ /* Something available from fd2, read it and process it. */ } Now I'm sure that you noticed that there were some other unused arguments to the select call. ~~~ 6) How can a parent and child process communicate. A parent and child can communicate through any of the normal inter-process communication schemes, but also have some special ways to communicate that take advantage of their relationship as a parent and child. One of the most obvious is that the parent can get the exit status of the child. Since the child inherits file descriptors from its parent, the parent can open both ends of a pipe, fork, then the parent close one end and the child close the other end of the pipe. This is what happens when you call the popen() routine to run another program from within yours, i.e. you can write the the file descriptor returned from popen() and the child process sees it as its stdin, and you can read from the file descriptor and see what the program wrote to it's stdout. ~~~ 7) My program generates a lot of zombie processes. How do I get rid of them? 7a) What is a zombie? When a program forks and the child finishes before the parent, the kernel still keeps some of its information about the child in case the parent might need it - for example, the parent may need to check the child's exit status. To be able to get this information, the parent calls wait(); when this happens, the kernel can discard the information. In the interval between the child terminating and the parent calling wait(), the child is said to be a "zombie" (if you do 'ps', the child will have a 'Z' in its status field to indicate this). Even though it's not running, it's still taking up some system resources; in particular an entry in the process table. This is not good, as the process table has a fixed number of entries and it is possible for the system to run out of them. Even if the system doesn't run out, there is a limit on the number of processes each user can run, which is usually smaller than the system's limit. This is one of the reasons why you should always check if fork() failed, by the way! If the parent terminates without calling wait(), the child is "adopted" by 'init', which handles the work necessary to cleanup after the child. (This is a special system program with process ID 1 - it's actually the first program to run after the system boots up). 7b) How do get rid of zombies? Apart from hoping the parent will call wait(), or rebooting the system, there isn't any way to get rid of them. A much better strategy is to prevent them happening in the first place. This is discussed in detail in the unix questions FAQ. Here's some sample code for the POSIX way of doing this:- #include <sys/types.h> /* must include this before any other sys headers */ #include <sys/wait.h> /* header for waitpid() and various macros */ #include <signal.h> /* header for signal functions */ #include <stdio.h> /* header for fprintf() */ #include <unistd.h> /* header for fork() */ void sig_chld(int); /* prototype for our SIGCHLD handler */ int main() { struct sigaction act; pid_t pid; /* Assign sig_chld as our SIGCHLD handler */ act.sa_handler = sig_chld; /* We don't want to block any other signals in this example */ sigemptyset(&act.sa_mask); /* * We're only interested in children that have terminated, not ones * which have been stopped (eg user pressing control-Z at terminal) */ act.sa_flags = SA_NOCLDSTOP; /* * Make these values effective. If we were writing a real * application, we would probably save the old value instead of * passing NULL. */ if (sigaction(SIGCHLD, &act, NULL) < 0) { fprintf(stderr, "sigaction failed\n"); return 1; } /* Fork */ if ((pid = fork()) < 0) { /* always check this! */ fprintf(stderr, "fork failed\n"); return 1; } else if (pid == 0) /* child - finish straight away */ return 7; /* exit status = 7 */ else { /* parent */ sleep(10); /* give child time to finish */ return 0; } } /* * The signal handler function - only gets called when a SIGCHLD * is received, ie when a child terminates */ void sig_chld(int signo) { int status, child_val; /* Wait for any child without blocking */ if (waitpid(-1, &status, WNOHANG) < 0) { /* * calling standard I/O functions like fprintf() in a * signal handler is not recommended, but probably OK * in toy programs like this one. */ fprintf(stderr, "waitpid failed\n"); } /* * We now have the info in 'status' and can manipulate it using * the macros in wait.h. */ if (WIFEXITED(status)) /* did child exit normally? */ child_val = WEXITSTATUS(status); /* get child's exit status */ printf("child's exited normally with status %d\n", child_val); } (Hmm, maybe that's a bit long for a short answer 8-) -- James Raynard, Edinburgh, Scotland ~~~ 10) How do I get my program to act like a daemon? Entering Daemon Mode by Patrick J. Horgan (patr...@amdahl.com) Here's the steps to become a daemon. (1) fork() so the parent can exit, this returns control to the command line or shell invoking your program. This step is required so that the new process is guaranteed not to be a process group leader. The next step, setsid() fails if you're a process group leader. (2) setsid() to become a process group and session group leader. Since a controlling terminal is associated with a session, and this new session has not yet acquired a controlling terminal our process now has no controlling terminal, (a good thing.) (3) fork() again so the parent, (the session group leader,) can exit. This means that we, as a non-session group leader, can never regain a controlling terminal. (4) chdir("/") to ensure that our process doesn't keep any directory in use. Failure to do this could make it so that an administrator couldn't unmount a slice, because it was our current directory. (5) umask(0) so that we have complete control over the permissions of anything we write. We don't know what umask we may have inherited. (6) close() fds 0, 1, and 2. This releases the standard in, out, and error we inherited from our parent process. We have no way of knowing where these fds might have been redirected to. Note that many daemons use sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the maximun open files/process. Then in a loop, the daemon can close all possible file descriptors. You have to decide if you need to do this or not. If you think that there might be file-descriptors open you should close them, since there's a limit on number of concurrent file descriptors. See NOTE below. (7) Create a new stdout, an example might be: open("/dev/console",O_RDWR). (8) dup2() twice to duplicate the fd for standard out for standard in and standard error. NOTE: If you're started from inetd some of this is a little different, you don't have to do the first fork, and fds 0, 1, and 2 are set up to be the connected socket. That means you should probably skip steps 6, 7 and 8. ~~~ 11) What books can I read to learn about Unix programming. "Unix Network Programming" W. Richard Stevens (c) Prentice Hall, 1990 ISBN 0-13-949876-1 [This is frequently recomemended. I have just got a copy, but not had time to read it.] "Advanced Programming in the Unix Environment" W. Richard Stevens (c) Addison-Wesley, 1992 ISBN 0-201-56317-7 "Internetworking with TCP/IP Volume III" Douglas E. Comer / David L. Stevens (c) Prentice Hall, 1993 ISBN 0-13-474222-2 The O'Reily Nutshell book on Make. [Recomended. Its a good series too] There is also Valhalia's (may have the spelling wrong) book on the unix operating system varients. "Unix the new frontiers" if I recall the title right. I am reading it at the moment at home and can check the details if you need it. It is very good if you want to know more about what goes on under the bonnett of different unix versions. Also check the archives for misc.books.technical A Concise Guide to UNIX books ~~~ 12) Where can I get the source from these books? For Stevens, ftp://ftp.uu.net./published/books/stevens.advprog.tar ~~~ 13) How can I look at process in the system like ps does? The answer is that this is system dependent...I thought you wouldn't like that. I'll show you how to write the same routine, one to return a pid given a name using two systems... The first one uses the privileged kvm SunOS4 routines to walk through system structures and pull information out of the process table. The second one uses the /proc process file system available on many SYSV sytems to do the same thing. Each of them has the ability to skip the FIRST match found if the skipit arg is set to the pid of the first one. The SunOS4 version requires root permissions to run. The SYSV version uses file permissions. Generally /proc permissions are set so that only the owner of the process has read permission. That means that most of the time you want to be running as root. SUNOS 4 version #define _KMEMUSER #include <sys/proc.h> #include <kvm.h> #include <fcntl.h> char regexpstr[256]; #define INIT register char *sp=regexpstr; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(pointer) return(pointer); #define ERROR(val) #include <regexp.h> pid_t getpidbyname(char *name,pid_t skipit) { kvm_t *kd; char **arg; int error; char *p_name=NULL; char expbuf[256]; char **freeme; int curpid; struct user * cur_user; struct user myuser; struct proc * cur_proc; if((kd=kvm_open(NULL,NULL,NULL,O_RDONLY,NULL))==NULL){ return(-1); } sprintf(regexpstr,"^.*/%s$",name); compile(NULL,expbuf,expbuf+256,'\0'); while(cur_proc=kvm_nextproc(kd)){ curpid = cur_proc->p_pid; if((cur_user=kvm_getu(kd,cur_proc))!=NULL){ error=kvm_getcmd(kd,cur_proc,cur_user,&arg,NULL); if(error==-1){ if(cur_user->u_comm[0]!='\0'){ p_name=cur_user->u_comm; } } else{ p_name=arg[0]; } } if(p_name){ if(!strcmp(p_name,name)){ if(error!=-1){ free(arg); } if(skipit!=-1 && ourretval==skipit){ ourretval=-1; } else{ close(fd); break; } break; } else{ if(step(p_name,expbuf)){ if(error!=-1){ free(arg); } break; } } } if(error!=-1){ free(arg); } p_name=NULL; } kvm_close(kd); if(p_name!=NULL){ return(curpid); } return (-1); } SYSV version pid_t getpidbyname(char *name,pid_t skipit) { DIR *dp; struct dirent *dirp; prpsinfo_t retval; int fd; pid_t ourretval=-1; if((dp=opendir("/proc"))==NULL){ return -1; } chdir("/proc"); while((dirp=readdir(dp))!=NULL){ if(dirp->d_name[0]!='.'){ if((fd=open(dirp->d_name,O_RDONLY))!=-1){ if(ioctl(fd,PIOCPSINFO,&retval)!=-1){ if(!strcmp(retval.pr_fname,name)){ ourretval=(pid_t)atoi(dirp->d_name); if(skipit!=-1 && ourretval==skipit){ ourretval=-1; } else{ close(fd); break; } } } close(fd); } } } closedir(dp); return ourretval; } ~~~ 14) How can I debug the children after a fork? There are several answers to this, some modern debuggers, like Sun's dbx and debugger, let you tell the debugger to follow the child, the parent, both, or ask you what to do during a fork(). Sometimes though you just have to be able to grab the process. The process won't wait for you to grab it though, so if it's a short lived process, you might want to either have it sleep for 30 seconds, or try this great idea from James Raynard: int pause_mode = 1; ... if ((pid = fork()) > 0) { /* child */ while (pause_mode) sleep(5); ... } ... and then set pause_mode equal to 0 after you have attached to the child, and debug in the usual way! Once you have it waiting for you, gdb lets you say "attach <pid>" to start debugging the pid. dbx and kin expect "debug - <pid>". From the command line you can start dbx to attach to a running process by dbx - <pid> ~~~ 16) Given a pid, how can I tell if it's a running program? (This is an ambiguous question. I'll assume it means "given a pid, how can I tell if there's a process with that pid?", rather than "is it stopped/a zombie, etc") Use kill with 0 for the signal number:- #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { pid_t pid; if (argc != 2) { fprintf(stderr, "usage: ./a.out <process ID>\n"); return -1; } pid = atol(argv[1]); if (kill(pid, 0) == 0) printf("process with ID %ld is running\n", pid); else printf("no process with ID %ld\n", pid); return 0; } This works from the command line as well:- $ kill -0 3120 # Process 3120 is running - nothing happens $ kill -0 9999 # Process 9999 is not running - complain and return 1 kill: (9999) - No such pid $ echo $? 1 $ ~~~ 18) system()/pclose()/waitpid() doesn't seem to return the exit value of my process...or the exit value is shifted left 16 bits...what's the deal? The man page is right, and so are you! If you read the man page for waitpid() you'll find that the return code for the process is "encoded." The value returned by the process is normally in the top 16 bits, and the rest is used for other things. You can't rely on this though, not if you want to be portable, so the suggestion is that you use the macros defined by wstat(5). Macros defined by wstat(5) include (stat is the value returned by waitpid(): WIFEXITED(stat) - Non zero if child exited normally. WEXITSTATUS(stat) - exit code returned by child WIFSIGNALED(stat) - Non-zero if child was terminated by a signal WTERMSIG(stat) - signal number that terminated child WIFSTOPPED(stat) - non-zero if child is stopped WSTOPSIG(stat) - number of signal that stopped child WIFCONTINUED(stat) - non-zero if status was for continued child WCOREDUMP(stat) - If WIFSIGNALED(stat) non-zero this is non-zero if core dumped ~~~ 19) How can I make my program not echo input like login does when asking for your password? The first answer is to call getpass(3C) if you want to get a password. If you need a more general understanding of how to do this an example implementation of getpass illustrates the technique. Adapted from Stevens' Advanced Programming In The Unix Environment #include <signal.h> #include <stdio.h> #include <termios.h> #define MAX_PASS_LEN 18 char * getpass(const char *prompt) { static char buf[MAX_PASS_LEN + 1 ]; char *ptr; sigset_t sig,sigsave; struct termios term, termsave; FILE *fp; int c; if((fp=fopen(ctermid(NULL),"r+")) == NULL) return NULL; setbuf(fp,NULL); sigemptyset(&sig); /* block SIGINT & SIGTSTP, save signal mask */ sigaddset(&sig,SIGINT); sigaddset(&sig,SIGTSTP); sigprocmask(SIG_BLOCK,&sig, &sigsave); tcgetattr(fileno(fp),&termsave); term=termsave; term.c_lflag&= ~(ECHO | ECHOE | ECHOK | ECHONL); tcsetattr(fileno(fp),TCSAFLUSH,&term); fputs(prompt,fp); ptr=buf; while((c=getc(fp)) !=EOF && c!='\n'){ if(ptr<&buf[MAX_PASS_LEN]) *ptr++=c; } *ptr=0; putc('\n',fp); tcsetattr(fileno(fp),TCSAFLUSH,&termsave); sigprocmask(SIG_SETMASK,&sigsave,NULL); fclose(fp); return buf; } ~~~ 20) How can I check and see if a key was pressed? I'm looking for something like the dos kbhit() command. I have several answers here, from several folks. Basically, there are two modes in which Unix terminals operate, canonical and non-canonical mode.(*) In canonical mode, input is processed line by line; this is how a terminal is set up by default. Under most circumstances, input is not passed to the application until the user presses the return key. In non-canonical mode, input is not read on a line-by-line basis. There are several ways to specify how it is read; either by waiting a given amount of time, asking for a certain number of characters to be entered, or a combination of the two, or just by reading all the characters that happen to be immediately available. It is possible to change the terminal mode from the command line by using stty(1). From within a program, this is done by using tcsetattr() to set the terminal attributes (if the system doesn't support tcsetattr(), there are certain arguments to ioctl() that can do this). When changing the terminal mode, it is important to reset the terminal to its original mode before terminating the program, as leaving it in a strange mode will be very annoying to the user! This should be done by saving the original mode. A common mistake is something like the following:- struct termios myterm; ... tcgetattr(STDIN_FILENO, &myterm); /* get terminal input attributes */ my_term.c_lflag &= ~ECHO; /* turn off input echoing */ tcsetattr(fd, TCSAFLUSH, &myterm); /* set new attributes */ ... /* do something here */ my_term.c_lflag |= ECHO; /* turn echoing back on */ tcsetattr(fd, TCSAFLUSH, &myterm); The problem is that echoing may have already been turned off for some reason, and something else may be depending on it being turned off. This scenario is unlikely, but not impossible. The correct way to reset the terminal mode is to save the original attributes in a safe place and use those attributes to reset the terminal. Here's the solution to the question, which turns line-buffering off, by putting the terminal into non-canonical mode:- #include <termios.h> #include <unistd.h> int get_a_char(void) { struct termios oldterm, newterm; char c; /* Get the current terminal state and save it in oldterm*/ if (tcgetattr(STDIN_FILENO, &oldterm) < 0) { error("tcgetattr failed"); return -1; } /* * structure copy the terminal state into newterm - have to * do this member by member if you don't have ANSI C compiler!*/ newterm = oldterm; /* prepare to put terminal into CBREAK mode */ newterm.c_lflag &= ~(ECHO | ICANON); newterm.c_cc[VMIN] = 1; newterm.c_cc[VTIME] = 0; /* * Put terminal in CBREAK mode - this will turn off echo * and line buffering. */ if (tcsetattr(STDIN_FILENO, &newterm) < 0) { error("tcsetattr failed"); return -1; } /* read a character from the terminal */ if (read(STDIN_FILENO, &c, 1) != 1) { error("read failed"); return -1; } /* Leave terminal as how we found it */ if (tcsetattr(STDIN_FILENO, &oldterm) < 0) { error("tcsetattr failed"); return -1; } /* Return the character read to the caller */ return c; } /* * Simplistic test program for the above. * It just reads a charcter from the terminal, until the user types * 'Q' or 'q'. */ int main() { int c; while ((c = get_a_char()) != -1) { if (c == 'Q' || c == 'q') break; printf("You pressed %c!\n", c); } return 0; } (*) Some systems, mainly BSD ones, have three modes, known as cooked, cbreak (or half-cooked) and raw. Cooked mode is the same as canonical, cbreak and raw are the same as non-canonical but differ in the way control characters are handled (cbreak handles some of them, raw doesn't). -- James Raynard, Edinburgh, Scotland /* This is one way to detect keystrokes in the input stream, similar to the combination of kbhit() and getch() in the DOS compiler. It should work on many flavors of Unix. Many programmers who are familiar with DOS are frustrated when they discover that getc() and getchar() don't even see any input until the user hits the RETURN key. This means the program is hung there forever if the user falls asleep. It's a showstopper for those who like to execute code between keystrokes in order to accomplish a variety of stupid programming tricks. If your compiler is POSIX-compliant, as it would be if you are using the GCC compiler, for example, the following code should work. It compiles under GCC on a SunOS and also under Linux. It works by changing how the port is read, whereas curses actually takes over the terminal and therefore needs all sorts of terminal definitions. This POSIX-compliant code should work with any sort of terminal, and even works on a remote terminal if you redirect the stdin and stdout to a port. */ #define _POSIX_SOURCE 1 /* forces POSIX definitions to be used in all header files */ #include <termios.h> #include <stdio.h> #include <unistd.h> struct termios systerm; /* declare our name "systerm" as structure */ int charin( void ); /* declare function */ int main( int argc, char *argv[] ) /* start main function */ { int inp; /* local integer */ /* As best as I can understand it, the following five lines read the port attributes, and set the minimum characters to zero and the time to one-tenth second. By reading in the port attributes, you can then reset them before exiting so that everything is restored to normal. The echo is turned off and the keyboard buffering is set to non-canonical (raw) mode. Setting the VTIME to one-tenth second, as in this case, makes the input loop 200% less processor-intensive. */ tcgetattr( STDIN_FILENO, &systerm ); systerm.c_lflag &= ~( ICANON | ECHO ); systerm.c_cc[ VMIN ] = 0; systerm.c_cc[ VTIME ] = 1; tcsetattr( STDIN_FILENO, TCSAFLUSH, &systerm ); printf( "\n\n\nEnter Q to Quit\n\n" ); printf( "The periods prove that we really ARE\n" ); printf( "executing code between keystrokes.\n\n" ); printf( "Input: " ); fflush( stdout ); /* in this raw mode, any output that doesn't end in \n must be explicitly flushed */ while( 1 ) { inp = charin(); /* call the character input function */ if( inp == (int)'Q' || inp == (int)'q' ) /* if request to exit */ { printf( "\n" ); systerm.c_lflag |= ICANON | ECHO; tcsetattr( STDIN_FILENO, TCSANOW, &systerm ); /* the above three lines should precede any exit, so that the terminal is restored to its normal mode */ exit( 0 ); } } } int charin( void ) { int w; char wus; w = read( STDIN_FILENO, &wus, 1 ); if( w != 0 ) { printf( "%c", wus ); /* we do our own echo here */ } else { printf( "." ); /* if this executes, it means the read timed out and returned 0. in other words, this is where you can execute code between the keystrokes. */ } fflush( stdout ); /* flush is required */ return (int)wus; } /* ===================================================================== Public Information Research, PO Box 680635, San Antonio TX 78268, USA Tel:210-509-3160 Fax:210-509-3161 Nonprofit publisher of NameBase Daniel Brandt: dbra...@crl.com [president] Steve Badrich: sbadr...@mcimail.com [NewsLine editor] ===================================================================== */ From: michael@ws0 (Michael Quigley) I found this code snipped in NCSA httpd 1.4. It looks like the authors borrowed it from other sources. ;) --8<-- extern char** environ; /* taken from bdflush-1.5 for Linux source code */ void inststr(char *dst[], int argc, char *src) { if (strlen(src) <= strlen(dst[0])) { char *ptr; for (ptr = dst[0]; *ptr; *(ptr++) = '\0'); strcpy(dst[0], src); } else { /* stolen from the source to perl 4.036 (assigning to $0) */ char *ptr, *ptr2; int count; ptr = dst[0] + strlen(dst[0]); for (count = 1; count < argc; count++) { if (dst[count] == ptr + 1) ptr += strlen(++ptr); } if (environ[0] == ptr + 1) { for (count = 0; environ[count]; count++) if (environ[count] == ptr + 1) ptr += strlen(++ptr); } count = 0; for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) { *ptr2 = '\0'; count++; } strncpy(dst[0], src, count); } } --8<-- And the following stub: /* it.c */ main(int argc, char **argv) { inststr(argv, argc, "Hello world!"); while(1); } produces the output: 6063 p0 Ss 0:00.71 -tcsh (tcsh) 6481 p0 R 0:01.49 Hello world! (it) 6482 p0 R+ 0:00.01 ps -ax I'm going to look around to see if I can find any other implementations. - Mike