//Deian Stefan
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <setjmp.h>
#include <string.h>

#define  PAGER "/usr/bin/less"

jmp_buf int_jump;

void int_handler(int sig) {
	longjmp(int_jump,1);
}

int main(int argc, char *argv[]) {

	struct sigaction sig;
	int fd,i,rc,n,wrote,readno,cstatus,cpid,pfd[2];
	char buff[8192];

	rc=fd=0;
	i=1;
	sig.sa_handler=int_handler;
	sigaction(SIGPIPE,&sig,NULL); 

	if(argc==1) {
		goto read_stdin;
	}
	for(;i<argc;i++) {
		if(argv[i][0]=='-'&&argv[i][1]=='\0') {
			fd=0;
			goto read_stdin;
		}
		if( (fd = open(argv[i],O_RDONLY)) < 0 ) {	
			fprintf(stderr,
				"Failed to open file %s for reading: %s\n",
				argv[i],strerror(errno));
			rc=-1;
			continue;
		}
read_stdin:
		if(pipe(pfd)<0) {
			fprintf(stderr, "Failed to create pipe: %s\n",
					strerror(errno));
			return -1;
		}

		switch((cpid=fork())) {
			case -1:
				fprintf(stderr, "Failed to fork(2): %s\n",
						strerror(errno));
				return -1;
			case 0:
				if(dup2(pfd[0],0) < 0) {
					fprintf(stderr,
						"Failed to dup2(2): %s\n",
						strerror(errno));
					return -1;
				}
				close(pfd[0]);
				close(pfd[1]);
				if(fd!=0) { close(fd); }

				if(execl(PAGER,PAGER,(char*)0) < 0) {
					fprintf(stderr,
						"Failed to execl %s: %s\n",
						PAGER,strerror(errno));
					return -1;
				}
			default: break;
		}
		close(pfd[0]);
		if(setjmp(int_jump)) {
			if(fd!=0) { close(fd); }
			close(pfd[1]); 
			continue;
		}

		readno=0;
		while( (readno=read(fd,buff,sizeof(buff))) > 0 ) {
			n=wrote=0;
			while(wrote<readno) {
				if((n=write(pfd[1],buff+wrote,readno-wrote))<0) {
					fprintf(stderr,
						"Failed to write to pipe: %s\n",
						strerror(errno));
					return -1;
				}
				wrote+=n;
			}
		}
		if(fd!=0) { close(fd); }
		close(pfd[1]);

		if(readno<0) {
			fprintf(stderr,
				"Failed to read from file %s: %s\n",
				fd?argv[i]:"stdin",strerror(errno));
			rc=-1;
			continue;
		}

		if(waitpid(cpid,&cstatus,0)<0) {
			fprintf(stderr,
				"waitpid() failed waiting for child pid %d: %s\n",
				cpid,strerror(errno));
			return -1;
		} 
	}
	
	return rc;
}

