#include #include #include #include #include #include #include "main.h" #include #include int file_exists(char *file) { struct stat foo; /* throw away argument for stat */ /* null files don't exist */ if (file == NULL) { return 0; } /* on success 0 is returned */ if (stat(file, &foo) == 0) { /* this is you checking whether the return value of stat is 1 */ return 1; /* true, happy, passed */ } return 0; } /* find out if $PAGER is set */ char* get_pager() { char *pager; pager = getenv("PAGER"); /* set pager to $PAGER environment variable */ if (pager == NULL) { /* if pager is NULL (the enviroment variable is unset) */ /* printf("PAGER is unset\n"); */ if ( file_exists("/usr/bin/less") ) { /* if /usr/bin/less exists as a file */ pager = "/usr/bin/less"; /* set pager to /usr/bin/less */ } } if (pager == NULL) { /* if pager is NULL (the enviroment variable is unset) */ if ( file_exists("/bin/more") ) { /* if /bin/more exists as a file */ pager = "/bin/more"; } } if (pager == NULL) { pager = "cat"; } return pager; } /* this function displays each file to the user */ int display_file(char *filename) { gzFile *file_ptr; char *pager; int wait_status; /* wait stores the exit status of the child here */ pid_t fork_result; int file_pipes[2] = {0}; char gzbuffer[2048] = {0}; int data_processed; /* leave curses mode to display the file */ kill_curses(); /* get the $PAGER env variable */ pager = get_pager(); /* first we create a pipe this will pass data between two processes */ if (pipe(file_pipes) != 0) { perror("pipe error"); exit(EXIT_FAILURE); } /* next the new process is created with fork() */ fork_result = fork(); /* check if fork() works */ if (fork_result == (pid_t)-1) { perror("fork error"); exit(EXIT_FAILURE); } /* now we have both parent and child processes */ switch (fork_result) { case -1: { perror("fork failed"); exit(1); } case 0: { /* we are in the childs thread of execution */ /* set stdin to a copy of the readable fd of the pipe */ close(file_pipes[1]); /* not using the write end of the pipe */ close(0); /* redirecting standard input */ dup(file_pipes[0]); /* duplicate the pipe, setting stdin */ /* close the pipes read and write fd's because we made a copy */ close(file_pipes[0]); /* stdin should be a copy now, so don't need */ /* call the external program */ (void)execlp(pager, pager, "-", (char *)NULL); /* DEBUG printf("should never get here...\n"); */ break; } default: { /* we are in the parents thread of execution */ close(file_pipes[0]); /* not using the read end of the pipe */ /* open the file for reading */ if ((file_ptr = gzopen(filename, "r")) == NULL) { perror("Cannot open file for reading"); return 1; } /* read the file line by line or until EOF */ while (gzgets(file_ptr, gzbuffer, 256) != Z_NULL) { /* user might quit before scrolling to EOF */ signal(SIGPIPE, SIG_IGN); /* send all the data to the child */ data_processed = write(file_pipes[1], gzbuffer, strlen(gzbuffer)); if (data_processed == -1) { perror("write error"); exit(EXIT_FAILURE); } if (data_processed != strlen(gzbuffer)) { /* data_processed is short .. should be rare */ exit(EXIT_FAILURE); } /* make sure we're not done with the file before continuing */ if (gzeof(file_ptr)) { break; } } close(file_pipes[1]); /* done with the writing end of the pipe */ /* close the file */ gzclose(file_ptr); /* wait for the child to finish */ wait(&wait_status); /* returns the PID of child */ /* continue with the main program */ break; } /* end default case */ } /* end switch */ return 0; }