CSC 2405: Computer Systems II Program Execution Environment Execution Environment The main func*on is the entry point for C program execu*on int main( int argc, char * argv[]); The linker (called by the C compiler) specifies, in the executable program file, a special start- up rou*ne to be called before main The start- up rou*ne takes command line arguments and environment values from the kernel sets things up so that main is then called 1
Environment When a UNIX program is executed, it receives two pieces of data: the arguments the environment To C programs, both are arrays of character pointers all but the last of the character pointers point to a NULL- terminated string the last pointer is a NULL pointer A count of the number of arguments (not including the NULL pointer) is also passed Memory Layout of a C Program Low Address Text Data BSS Heap Stack High Address Command-Line Arguments and Environment Variables 2
Environment The global variable environ points to the array of environment strings (whose last entry is NULL) extern char **environ; /* environment array (not in any header) */ Environment One way to access the environment strings is to use the environ variable directly. Each environment string is of the form name=value extern char **environ; int main(int argc, char *argv[]) { } int i; for (i=0; environ[i]!= 0; i++) printf("%s\n",environ[i]); return 0; 3
Environment Example PWD=/mnt/a/mdamian/Systems/Shell TZ=US/Eastern HOSTNAME=tanner USER=mdamian MACHTYPE=sparc-sun-solaris2.9 OLDPWD=/mnt/a/mdamian/Systems LOGNAME=mdamian SHLVL=1 SHELL=/bin/bash HOSTTYPE=sparc OSTYPE=solaris2.9 HOME=/mnt/a/mdamian TERM=vt100 PATH=/usr/ccs/bin:/home2/jdk1.5.0/bin:/usr/sbin:/ opt/gnu/bin:/usr/bin:/opt/local/bin:/usr/local/ bin:.:/usr/ccs/bin:/usr/bin:/bin:/usr/sbin:/sbin:/ usr/gnu/bin:/usr2/local/bin:/mnt/local/bin:/usr/ucb SSH_TTY=/dev/pts/6 getenv Call Lis*ng an en*re environment is an unusual requirement Typically, the value for one environment variable is needed #include <stdlib.h> char *getenv(const char * var); var is the variable to find returns value or NULL if not found 4
getenv Example #include <stdio.h> #include <stdlib.h> int main(void) { char *s; s = getenv("logname"); if (s == NULL) printf("variable not found\n"); else printf("value is \"%s\"\n",s); } exit(exit_success); Some Environment variables Name HOME USER HOSTNAME PWD PATH Description your home directory your login ID the name of the host computer the current working directory a list of directories in which to look for executable commands 5
man Command: Your Best Friend Syntax is man command Shows information about the command Usually it takes multiple screens, so hit Space or Enter for more information When done, hit q to quit Hands On Part One In your systems directory, create another directory called environ In your directory systems/environ, write a program called env.c that retrieves the value of your HOME directory and prints it out. Sample execution: My home directory is /mnt/a/mdamian Extend your code to also print out the value of your current working directory (environ variable PWD). Sample execution: My current directory is /mnt/a/mdamian/systems/environ 6
C Standard Library Function: strtok The strtok Function char * strtok(char *s, char * delim); delim contains all characters separating the tokens if s is non-null: return pointer to beginning of first token in s, and terminate token with NULL. If s is NULL: use remainder of untokenized string from the last call to strtok 7
strtok in Action char * token; token = strtok(line,,; ); while(token!= NULL) { printf( Token is [%s]\n, token); token = strtok(null,,; ); } d o g, c a t ; NULL line token strtok in Action After first call token = strtok(line,,; ); d o g NULL c a t ; NULL line token Output is Token is [dog] 8
strtok in Action After second call token = strtok(null,,; ); d o g NULL c a t NULL NULL line token Output is Token is [cat] strtok in Action After third call token = strtok(null,,; ); the loop breaks. d o g NULL c a t NULL NULL line NULL token 9
What is the Output? #define MAX 80 char buf[max]; char * token; sprintf(buf, "%s", "This.is.my.strtok.test\n"); token = strtok(buf, ".\n"); printf("[%s], [%s] ", buf, token); token = strtok(null, ".\n"); printf("[%s], [%s] ", buf, token); token = strtok(null, ".\n"); printf("[%s], [%s] ", buf, token); token = strtok(buf, ".\n"); printf("[%s], [%s] ", buf, token); Hands On Part Two In your directory systems/environ, write a program called pathenv.c that retrieves the value of the PATH variable from the program environment, then prints out all search paths, one per line (use strtok). Sample execution: The shell search paths are: /usr/ccs/bin /home2/jdk1.5.0/bin /opt/gnu/bin /usr/sbin /usr/bin /opt/local/bin /usr/local/bin 10
Hands On Part Three Make a copy of your pathenv program (call it pathenvcopy). Then edit your original pathenv program to save the search paths in an array of strings before printing them out. More precisely, your program should do the following: 1. Retrieve the value of the PATH variable 2. Copy this string into a local buffer (use strcpy) 3. Extract the tokens and save them in an array of pointers:... NULL "/opt/gnu/bin" "/home2/jdk1.5.0/bin" "/usr/ccs/bin" 4. Print out each string in the array Hands On Part Four Reorganize your code from part three to include threefunctions void tokenize_path(); /* build the array of paths*/ void print_path(); /* print the paths */ void free_path(); /* deallocate the array */ The first function builds the array of search paths. The second function prints the paths, one per line. The main function should simply call these functions: int main(int argc, char * argv[]) { tokenize_path(); print_path(); free_path(); return 0; } Make sure the array of search paths is a GLOBAL variable, so that other functions (to be added later) can access it. 11
C Standard Library Function: fopen fclose File Input and Output So far, all input and output has been to standard input and from standard output: scanf() or getchar() or fgets(..., stdin) printf() or putchar() In most application and professional situations, you will need to read from/write to files 12
File I/O in C Before you can access a file you must open it! After you are done, you must close it! Synopsis #include <stdio.h> FILE *fp; FILE *fopen(char *name, char *mode); int fclose(file *fp); A data type defined in <stdio.h> The mode of access. The path name of the file FILE *fopen(char *name, char *mode) name may be Fully qualified: /tmp/code.c Relative to working directory:./fopen.pdf mode may be "r" read only "w" write only (create or discard previous contents) "a" append only (write at end; create if necessary) "r+" read and update (i.e., read-write) "w+" read-write (create or discard previous contents) "a+" read-append (write at end; create if necessary) Add "b" to mode string for binary files, e.g. rb, wb Returns NULL if the file does not exist 13
Hands On Part Five Extend your pathenv.c program with a function int file_exists(char * filepath); that returns 1 if the file with the given path exists and 0 otherwise. Hint: check out the value returned by fopen Add code to the main function to test out the file_exists function. Keep it simple. Hands On Part Six Extend your pathenv.c program with a function void find_path(char * filename); that prints out the directory containing the file given as argument. To do so: 1. Allocate a static buffer (e.g., char buf[100];) 2. In a loop over the search paths: a) Copy the next search path in the local buffer (use strcpy) b) Append the filename to the search path (use strcat) c) Check if the resulted file path exists (use file_exists) d) If the answer is yes, print the search path and return e) If the answer is no, continue the loop 14
Example: find_path( gcc )... NULL "/opt/gnu/bin" "/home2/jdk1.5.0/bin" "/usr/ccs/bin" searchpaths buf /usr/ccs/bin/gcc strcpy strcat file_exists(buf) returns 0 Example: find_path( gcc )... NULL searchpaths "/opt/gnu/bin" "/home2/jdk1.5.0/bin" "/usr/ccs/bin" buf /home2/jdk1.5.0/bin/gcc strcpy strcat file_exists(buf) returns 0 15
Example: find_path( gcc )... NULL searchpaths "/opt/gnu/bin" "/home2/jdk1.5.0/bin" "/usr/ccs/bin" buf /opt/gnu/bin/gcc strcpy strcat file_exists(buf) returns 1 print /opt/gnu/bin/gcc 16