/*
	dircmp2 command
	alpha version 7 & beta version 1, derived from alpha version 6
	revision: 4.11.1995
	(C) 1995 Thomas Radtke
	E-Mail: Thomas.Radtke@rz.uni-osnabrueck.de
	covered by the GPL, see COPYING for details
*/

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MAXENTRY 1000
#define TABSIZE 2

int tab,rec,inv,cmp,dirs,fls,pathpart,help;
int tabulator=0;

int main(int argc, char **argv)
{
	int cnt;
	void dircmp2();

	rec=0;
	inv=0;
	cmp=0;
	dirs=0;
	fls=0;
	pathpart=0;
	help=0;
	tab=0;

	cnt=0;
	if (argc>1)
	{
		while (argv[++cnt][0]=='-' && cnt<argc)
		{
			switch(argv[cnt][1])
			{
				case 't':
					tab=1;
					break;
				case 'h':
					help=1;
					break;
				case 'p':
					pathpart=1;
					break;
				case 'f':
					fls=1;
					dirs=0;
					break;
				case 'i':
					inv=1;
					break;
				case 'd':
					dirs=1;
					fls=0;
					break;
				case 'c':
					cmp=1;
					break;
				case 'r':
					rec=1;
					break;
				default:
					fprintf(stderr,"%s: unknown option -%c\n",argv[0],argv[cnt][1]);
					exit(20);
					break;
			}
		}
		argc-=(cnt-1);
	}
	if (argc<2 || help)
	{
		fprintf(stderr,"usage: %s [-{cdfhiprt}] directory1 [directory2]\n",*argv);
		if (help)
		{
			fprintf(stderr,"\nThe %s command lists all files and directories of directory1, that\n",*argv);
			fprintf(stderr,"cannot be found in directory2. If directory2 is omitted, '.' is used\n\nFlags:\n\n");
			fprintf(stderr,"-c  compare files\n");
			fprintf(stderr,"-d  show only directorys\n");
			fprintf(stderr,"-f  show only files\n");
			fprintf(stderr,"-h  this page\n");
			fprintf(stderr,"-i  inverse comparison\n");
			fprintf(stderr,"-p  show full pathnames\n");
			fprintf(stderr,"-r  subdir scan\n");
			fprintf(stderr,"-t  indent subdir results\n");
			exit(0);
		}
		else {
			fprintf(stderr,"use option -h to show the help page\n");
			exit(20);
		}
	}

	if (argc==3)
		dircmp2(*argv,argv[cnt],argv[cnt+1]);
	else
		dircmp2(*argv,argv[cnt],(char *)".");
	exit(0);
}

void dircmp2(char *argv, char *argv1, char *argv2)
{
	DIR *dir1,*dir2;
	struct dirent *entry;
	int d1,d2,s1,s2,equal,ind1,ind2,i,j,k;
	struct stat fileinfo,fileinfo2;
	char *buf,*buf2,*buffer1,*buffer2;
	int fh;
	char **dir_name_list_1,**dir_name_list_2;
	void tabul();

	if (!(dir_name_list_1=(char **)malloc(MAXENTRY*sizeof(char *))))
	{
		printf("%s: memory exhausted\n",argv);
		exit(20);
	}
	if (!(dir_name_list_2=(char **)malloc(MAXENTRY*sizeof(char *))))
	{
		printf("%s: memory exhausted\n",argv);
		exit(20);
	}
	if (!(dir1=(DIR *)opendir((char *)argv1)))
	{
		fprintf(stderr,"%s: nonexistant directory %s\n",argv,argv1);
		exit(20);
	}
	if (!(dir2=(DIR *)opendir((char *)argv2)))
	{
		fprintf(stderr,"%s: nonexistant directory %s\n",argv,argv2);
		closedir(dir1);
		exit(20);
	}

	ind1=0;
	ind2=0;

	while ((entry=(struct dirent *)readdir(dir1)))
	{
		if (!strcmp(".",entry->d_name) || !strcmp("..",entry->d_name)) continue;
		if (!(dir_name_list_1[ind1]=(char *)malloc(entry->d_namlen+1))) {
			printf("%s: memory exhausted\n",argv);
			closedir(dir1);
			closedir(dir2);
			exit(20);
		}
		strcpy(dir_name_list_1[ind1],entry->d_name);
		if (ind1++==MAXENTRY)
		{
			printf("%s: too much entries\n",argv);
			closedir(dir1);
			closedir(dir2);
			exit(20);
		}
	}
	while ((entry=(struct dirent *)readdir(dir2)))
	{
		if (!strcmp(".",entry->d_name) || !strcmp("..",entry->d_name)) continue;
		if (!(dir_name_list_2[ind2]=(char *)malloc(entry->d_namlen+1))) {
			printf("%s: memory exhausted\n",argv);
			closedir(dir1);
			closedir(dir2);
			exit(20);
		}
		strcpy(dir_name_list_2[ind2],entry->d_name);
		if (ind2++==MAXENTRY)
		{
			printf("%s: too much entries\n",argv);
			closedir(dir1);
			closedir(dir2);
			exit(20);
		}
	}

	for (i=0; i<ind1; i++) {
		equal=0;
		for (j=0; j<ind2; j++) {
			if (!strcmp(dir_name_list_1[i],dir_name_list_2[j])) {
				equal=1;
				break;
			}
		}
		if ((inv && equal) || (!inv && !equal) || (!inv && equal && (cmp || rec))) {
			if (!(buf=(char *)malloc(strlen(dir_name_list_1[i])+strlen(argv1)+2))) {
				printf("%s: memory exhausted\n",argv);
				closedir(dir1);
				closedir(dir2);
				exit(20);
			}
			*buf=(char)0;
			strcpy(buf,argv1);
			strcat(buf,"/");
			strcat(buf,dir_name_list_1[i]);
			stat(buf,&fileinfo);
			d1=S_ISDIR(fileinfo.st_mode);
			if (equal) {
				if (!(buf2=(char *)malloc(strlen(dir_name_list_2[j])+strlen(argv2)+2))) {
					printf("%s: memory exhausted\n",argv);
					closedir(dir1);
					closedir(dir2);
					exit(20);
				}
				*buf2=(char)0;
				strcpy(buf2,argv2);
				strcat(buf2,"/");
				strcat(buf2,dir_name_list_2[j]);
				stat(buf2,&fileinfo2);
				d2=S_ISDIR(fileinfo2.st_mode);
				if (d1!=d2) equal=0;
				else if (cmp && fileinfo.st_size!=fileinfo2.st_size) equal=0;
				else if (!d1 && cmp) {
					buffer1=(char *)malloc(fileinfo.st_size+1);
					buffer2=(char *)malloc(fileinfo.st_size+1);
					if (!buffer1 || !buffer2) {
						fprintf(stderr,"%s: warning: memory exhausted\n",argv);
						fprintf(stderr,"the files %s and %s are considered to be different\n",buf,buf2);
						if (buffer1) free(buffer1);
						if (buffer2) free(buffer2);
						equal=0;
					}
					else {
						fh=open(buf,O_RDONLY,0);
						s1=read(fh,buffer1,fileinfo.st_size);
						close(fh);
						fh=open(buf2,O_RDONLY,0);
						s2=read(fh,buffer2,fileinfo.st_size);
						close(fh);
						if (s1!=fileinfo.st_size) {
							printf("%s: error reading file %s\n",argv,buf);
							closedir(dir1);
							closedir(dir2);
							exit(20);
						}
						if (s2!=fileinfo.st_size) {
							printf("%s: error reading file %s\n",argv,buf2);
							closedir(dir1);
							closedir(dir2);
							exit(20);
						}
						for (k=0; k<fileinfo.st_size; k++) {
							if (buffer1[k]!=buffer2[k]) break;
						}
						free(buffer1);
						free(buffer2);
						if (k!=fileinfo.st_size) equal=0;
					}
				}
			}
			if (rec && equal && d1) {
				tabulator+=TABSIZE;
				dircmp2(argv,buf,buf2);
				tabulator-=TABSIZE;
			}
			else if ((inv && equal) || (!inv && !equal)) {
				if ((d1 && dirs) || (!d1 && fls) || (!dirs && !fls)) {
					if (!pathpart) {
						if (tab) tabul();
						printf("%s\n",dir_name_list_1[i]);
					}
					else {
						if (tab) tabul();
						printf("%s\n",buf);
					}
				}
			}
		}
	}
	closedir(dir1);
	closedir(dir2);
	free(dir_name_list_1);
	free(dir_name_list_2);
	return;
}

void tabul()
{
	int i;

	for (i=0; i<tabulator; i++) printf(" ");
}
