Population

Directory Viewer---makefile

    A.Third Edition

    This is third edition of fifth assignment of comp229. And there is some improvement such as the mode of file will

    be displayed as "ls" does. Also a makefile makes compiling automatic.

    B.The problem

    ¡¡

C.The idea of program
¡¡
1. How to make makefile? Makefile is simply a script file specifying two things:
Which file is depending which file and how should do with each file.
2. The file you specify is followed with a ":" and behind ":" is the file it depends on.
3. The label is also the file name.
4. If you are using "echo", make sure you quote what you want to display.
5. Setenv won't work, you have to specify library path independently.
¡¡

    D.The major functions

    C.Further improvement

    ¡¡

    //this is main program: main.c

    #include <stdio.h>

    extern char* prompt;
    //these are my own defined utility functions
    //this check the command of "dl" and "cd" then send all rest
    //arguments to "checkOptions()"
    extern int checkCmd(char* cmd);

    //get user input string from keyboard and store in the parameter
    extern int input(char* str);

    int main()
    {
    	char str[256];
    	write(0, prompt, strlen(prompt));
    	//input will only return 0 unless "exit" met
    	while (input(str))
    	{
    		checkCmd(str);
    		write(0, prompt, strlen(prompt));
    	}

    	return 0;
    }

    //this is static library program: staticLib.c

    ////////////////////////////////////////////////////////////////////////////
    //program: Assignment 3 of comp229
    //author: Qingzhe Huang
    //ID: 5037735
    //date: Oct. 24, 2003
    //purpose of program: to use system call to implement "dv" directory viewer
    /////////////////////////////////////////////////////////////////////////////

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <unistd.h>
    #include <dirent.h>
    #include <time.h>
    //#include <fcntl.h>

    //these are all functions defined in assignment and
    //would be linked dynamically
    extern int SelectMonth(char* month);
    extern int ChangeDir(char* dir);
    extern int GetAllFiles();
    extern int RemoveHidden();
    extern int SelectRange(char* begin, char* end);
    extern int SelectDate(int date);
    extern int SelectBigger(int size);
    extern int SelectSmaller(int size);
    extern void PrintList(char* sortby);

    int sortIndex = 0;
    extern int errno;
    char* sortedBy[3] = {"name", "date", "size"};

    enum SortBy
    {ByName, ByDate, BySize};

    //a record to store file info
    struct FileInfo
    {
    	char name[31];
    	char perm[10];
    	long size;
    	time_t  mdate;
    } fileInfo[1024];

    //the fileInfo counter
    int infoCount =0;

    //fileList stores the file index interested by user
    int fileList[1024]={0};
    //this is its counter
    int listCount =0;

    //the parameter for "SelectRange()"
    char beginStr[2];
    char endStr[2];

    //flag for "GetAllFiles()", 1 means re-read all files which is
    //default, until set to 0 by "cd" parameter
    int reRead=1;

    //a simple way to change string to index, is it faster than MIA's little
    //switch function "MonToStr"?
    char* months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
    	"Sep", "Oct", "Nov", "Dec"};

    //the command prompt for our "directory viewer"
    char* prompt = "mydv: ";

    //this is the directory name, cause I need to display several times
    //in different functions, I have to make it global.
    char buffer[256];

    //these are my own defined utility functions
    //this check the command of "dl" and "cd" then send all rest
    //arguments to "checkOptions()"
    int checkCmd(char* cmd);

    //this will collect user input lines until "exit" int input(char* str);
    //check all options and call each "selection" functions by options accordingly
    int checkOptions(char** options, int count);

    //get user input string from keyboard and store in the parameter
    int input(char* str);

    int input(char* str)
    {
    	char* ptr = str;
    	while (1)
    	{
    		read(0, ptr, 1);
    		if (*ptr==10)
    		{
    			break;
    		}
    		ptr++;
    	}
    	*ptr = '\0';
    	return strcmp(str, "exit");
    }

    int checkCmd(char* cmd)
    {
    	char* ptr = cmd;
    	//is there any limit for command line parameters? Yes, I said it is 20
    	//who would say no????:)
    	char* options[20];
    	int count = 0, i;
    	pid_t pid=0;
    	//if user enters nothing, it is not NULL!!!
    	if (!strcmp(cmd, ""))
    	{
    		return 0;
    	}
    	//\n should also be delimiter
    	while (options[count]=strtok(ptr, " \n"))
    	{
    		ptr = NULL;
    		count++;
    	}
    	//then we can pass options as char**
    	options[count] = NULL; //just make sure it is null at end
    	//the maximum and minimum of parameters
    	if (count<=11&&count>=2)
    	{
    		if (!strcmp(options[0], "cd"))
    		{
    			//I won't check all other parameters
    			if (ChangeDir(options[1])==1)
    			{
    				reRead =1;//need re-Getallfiles
    				return 1;
    			}
    			else
    			{
    				return -1;
    			}
    		}
    		if (!strcmp(options[0], "dl"))
    		{
    			if (reRead)
    			{
    				GetAllFiles();
    				//make sure all files will be read only once with
    				//multiple "dl"
    				reRead =0;
    			}
    			//passing char**
    			return checkOptions(&options[1], count-1);

    		}
    	}

    	//fork another process to execute whatever user input
    	if ((pid = fork())==0)
    	{
    		execvp(options[0], options);
    		printf("%s\n", strerror(errno));
    		exit(-1);
    	}
    	//waiting utill user returns...
    	wait(NULL);
    	return 1;

    }

    int checkOptions(char** options, int count)
    {
    	int i=0;
    	int result=0;
    	int removeHidden=1;
    	char string[256];
    	//make sure there is any file
    	while (i<count&&listCount)
    	{
    		if (!strcmp(options[i], "-range"))
    		{
    			if (i+1<count)
    			{
    				//since it is only a character
    				beginStr[0] = options[i+1][0];
    				beginStr[1] = '\0';
    				endStr[0] = options[i+1][2];
    				endStr[1] = '\0';

    				listCount=SelectRange(beginStr, endStr);
    				i+=2;
    				continue;
    			}
    			else
    			{
    				printf("%s\n", "missing parameter for -range options");
    				return -1;

    			}
    		}
    		if (!strcmp(options[i], "-modified"))
    		{
    			if (i+1< count)
    			{
    				//this is for month
    				listCount=SelectMonth(options[i+1]);
    				i+=2;
    			}
    			else
    			{
    				printf("%s\n", "missing parameter for -modified options");
    			    return -1;
    			}

    			if (i<count)
    			{
    				if (strcmp(options[i], "-all")&&strcmp(options[i], "-range")
    					&&strcmp(options[i], "-biggerthan")&&strcmp(options[i],"-smallerthan"))
    				{
    					listCount=SelectDate(atoi(options[i]));
    					i++;
    				}
    			}
    			continue;
    		}

    		if (!strcmp(options[i], "-biggerthan"))
    		{
    			if (i+1<count)
    			{
    				listCount = SelectBigger(atoi(options[i+1]));
    				i+=2;
    				continue;
    			}
    			else
    			{
    				printf("%s\n", "missing parameter for -biggerthan options");
    				return -1;
    			}
    		}

    		if (!strcmp(options[i], "-smallerthan"))
    		{
    			if (i+1<count)
    			{
    				listCount=SelectSmaller(atoi(options[i+1]));
    				i+=2;
    				continue;
    			}
    			else
    			{
    				printf("%s\n", "missing parameter for -smallerthan options");
    				return -1;
    			}
    		}

    		if (!strcmp(options[i], "-all"))
    		{
    			removeHidden=0;
    			i++;
    			sortIndex = ByName;
    			continue;
    		}
    		if (i==0)
    		{
    			printf("%s\n", "invalide parameter!");
    			return -1;
    		}
    		i++;
    	}
    	if (removeHidden)
    	{
    		listCount = RemoveHidden();

    	}
    	//if there is no more files,
    	if (!listCount)
    	{
    		//I cannot understand why printf doesn't work properly
    		//it won't display until the function returns, so I have to
    		//use system call "write" which is very fast
    		strcpy(string, "Directory ");
    		strcat(string, buffer);
    		strcat(string, " does not contain any files.\n");
    		write(0, string, strlen(string));
    //		printf("Directory %s does not contain any files.", buffer);
    	}
    	else
    	{
    		PrintList(sortedBy[sortIndex]);
    		return result;
    	}
    }

    ¡¡

    //this is dynamic library program: dynamicLib.c

    ¡¡

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <unistd.h>
    #include <dirent.h>
    #include <time.h>

    struct FileInfo
    {
    	char name[31];
    	char perm[10];
    	long size;
    	time_t  mdate;
    };

    extern int fileList[1024];
    extern int errno;
    extern struct FileInfo fileInfo[1024];
    extern int infoCount;
    extern int listCount;
    extern char* months[12];
    extern char buffer[256];

    //these are all functions defined in assignment
    int SelectMonth(char* month);
    int ChangeDir(char* dir);
    int GetAllFiles();
    int RemoveHidden();
    int SelectRange(char* begin, char* end);
    int SelectDate(int date);
    int SelectBigger(int size);
    int SelectSmaller(int size);
    void PrintList(char* sortby);

    short octArray[9]={0400,0200,0100,0040,0020,0010,0004,0002,0001};
    char permStr[10]= "rwxrwxrwx";

    enum SortBy
    {ByName, ByDate, BySize};

    //parameter for "PrintList()" to indicate what field to be sorted by

    //the actual enum SortBy variable for index of "sortedBy[3]"
    extern int sortIndex;
    extern char* sortedBy[3];

    //a utility function does the printing job
    int printInfo();
    void setPermStr(struct stat* s, char* perm);

    //three callback function for "qsort"
    int compName(const void*, const void*);
    int compDate(const void*, const void*);
    int compSize(const void*, const void*);

    //a function pointer array so as to be used in "qsort"
    int (*compFuns[3])(const void*, const void*) = {compName, compDate, compSize};

    void setPermStr(struct stat* s, char* perm)
    {
    	int i;
    	for (i=0; i<9; i++)
    	{
    		if (s->st_mode&octArray[i])
    		{
    			perm[i]=permStr[i];
    		}
    		else
    		{
    			perm[i]='-';
    		}
    	}
    	perm[9]='\0';
    }

    int ChangeDir(char* dir)
    {
    	int temp =0;
    	if ((temp=chdir(dir))==-1)
    	{
    		printf("Directory %s does not exist.\n", dir);
    		return -1;
    	}
    	else
    	{
    		return 1;

    	}
    }

    int GetAllFiles()
    {
    	char fileName[256];
    	DIR *dp=NULL;
    	struct dirent *d;
    	struct stat s;

    	//maybe MIA's way is simple---dir = ".";
    	if (!(dp = opendir(getcwd(buffer, 256))))
    	{
    		printf("%s\n", strerror(errno));
    		return -1;
    	}
    	//strcat(buffer, buffer[strlen(buffer)]=='/'?"":"/");
    	infoCount=listCount=0;
    	while (d=readdir(dp))
    	{
    		if (stat(d->d_name, &s)==-1)
    		{
    			printf("cannot access file %s\n", d->d_name);
    			continue;
    		}
    		else
    		{
    			//we shall not select directories
    			if (S_ISDIR(s.st_mode))
    			{
    				continue;
    			}
    		}

    		if (d->d_ino!=0)
    		{
    			//strcpy(fileInfo[infoCount].name, buffer);
    			//printf("%s\n", d->d_name);
    			if (stat(d->d_name, &s)!=-1)
    			{
    				strcpy(fileInfo[infoCount].name, d->d_name);
    				fileInfo[infoCount].size = s.st_size;
    				fileInfo[infoCount].mdate = s.st_mtime;
    				setPermStr(&s, fileInfo[infoCount].perm);
    				infoCount++;
    				fileList[listCount]=listCount; //means there is an index to...
    				listCount++;
    			}

    		}
    	}
    	return infoCount;
    }

    int printInfo()
    {
    	int i=0;
    	char str[23];
    	struct tm* t;
    	for (i=0; i<listCount; i++)
    	{
    		printf("%s", fileInfo[fileList[i]].perm);
    		t = gmtime(&fileInfo[fileList[i]].mdate);
    		sprintf(str, "%s %02d, %4d; %02d:%02d:%02d", months[t->tm_mon], t->tm_mday,
    			t->tm_year + 1900, 	t->tm_hour, t->tm_min, t->tm_sec);

    		printf("  %8d   %s %-30s \n", fileInfo[fileList[i]].size, str, fileInfo[fileList[i]].name);
    	}
    }

    int SelectMonth(char* month)
    {
    	int i, temp=0;
    	int imonth=0;//the month
    	//find out the index of month
    	for (i=0; i<12; i++)
    	{
    		if (!strcmp(month, months[i]))
    		{
    			imonth=i;
    			break;
    		}
    	}

    	for (i=0; i<listCount; i++)
    	{
    		if (gmtime(&fileInfo[fileList[i]].mdate)->tm_mon==imonth)
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}

    	}
    	listCount = temp;
    	sortIndex = ByDate;
    	return listCount;
    }

    int RemoveHidden()
    {
    	int i, temp=0;
    	for (i=0; i<listCount; i++)
    	{
    		if (fileInfo[fileList[i]].name[0]!='.')
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}

    	}
    	listCount=temp;
    	return listCount;
    }

    int SelectBigger(int size)
    {
    	int i, temp=0;
    	for (i=0; i<listCount; i++)
    	{
    		if (fileInfo[fileList[i]].size>=size)
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}
    	}
    	listCount =temp;
    	sortIndex = BySize;
    	return listCount;
    }

    int SelectSmaller(int size)
    {
    	int i, temp=0;
    	for (i=0; i<listCount; i++)
    	{
    		if (fileInfo[fileList[i]].size<=size)
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}
    	}
    	listCount =temp;
    	sortIndex = BySize;
    	return listCount;
    }

    int SelectRange(char* begin, char* end)
    {
    	int i, temp=0;
    	char* ptr;
    	for (i=0; i<listCount; i++)
    	{
    		if (fileInfo[fileList[i]].name[0]=='.')
    		{
    			ptr = fileInfo[fileList[i]].name + 1;
    		}
    		else
    		{
    			ptr = fileInfo[fileList[i]].name;
    		}
    		//so it uses the first character to compare
    		if (ptr[0]>=begin[0]&&ptr[0]<=end[0])
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}

    /*
    		if (strcmp(ptr, begin)>=0
    			&&strcmp(ptr, end)<=0)
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}
    		*/
    	}
    	listCount =temp;
    	sortIndex = ByName;
    	return listCount;
    }

    //this is mad! I already defined an enum type global variable to
    //indicate what should by sorted, however, I was forced to pass a
    //string instead of an enum index which I need to use a loop to find out!!!
    void PrintList(char* sortby)
    {
    	int i=0;
    	int (*comp)(const void*, const void*);//comp function pointer
    	for (i=0; i<3; i++)
    	{
    		if (!strcmp(sortby, sortedBy[i]))
    		{
    			comp = compFuns[i];
    			break;
    		}
    	}

    	qsort(fileList, listCount, sizeof(int), comp);
    	printInfo();
    }

    int SelectDate(int date)
    {
    	int i, temp=0;
    	for (i=0; i<listCount; i++)
    	{
    		if (gmtime(&fileInfo[fileList[i]].mdate)->tm_mday==date)
    		{
    			fileList[temp]=fileList[i];
    			temp++;
    		}

    	}
    	listCount = temp;
    	sortIndex = ByDate;
    	return listCount;
    }

    //the help for UNIX is so BAAAAAAAAAAD that they give a wrong example
    //which won't work under gcc which doesn't allow modify const pointer!!!!
    int compName(const void*first, const void*second)
    {
    	//int* pi = first, *pj = second;
    	//int i = *pi;
    	//int j = *pj;
    	int i = *((int*)first);
    	int j = *((int*)second);
    	return strcmp(fileInfo[i].name, fileInfo[j].name);

    }

    //this is the bug place
    int compDate(const void*first, const void*second)
    {
    	int tempi = *((int*)first);  //is it strange?
    	int tempj = *((int*)second);//is it strange?
    	long i=fileInfo[tempi].mdate;
    	long j=fileInfo[tempj].mdate;

    	if ( i< j)
    	{
    		return -1;
    	}
    	else
    	{
    		if (i>j)
    		{
    			return 1;
    		}
    		else
    		{
    			return 0;
    		}
    	}
    }

    int compSize(const void*first, const void*second)
    {
    	int pi = *((int*)first);
    	int pj = *((int*)second);

    	int i=fileInfo[pi].size;
    	int j=fileInfo[pj].size;

    	if ( i< j)
    	{
    		return -1;
    	}
    	else
    	{
    		if (i>j)
    		{
    			return 1;
    		}
    		else
    		{
    			return 0;
    		}
    	}
    }

    //this is makefile: makefile

    all:dynamic.a mydv
    	@echo "make complete."
    dynamic.a : dynamicLib.c
    	@echo "compiling dynamic library..."
    	gcc -shared -fPIC dynamicLib.c -o dynamic.a
    mydv : main.c static.a
    	@echo "creating executable program(mydv) ..."
    	gcc main.c static.a dynamic.a -o mydv
    static.a : static.o
    	@echo "creating static library(static.a)..."
    	ar rcs static.a static.o
    static.o:staticLib.c
    	@echo "compiling static library(static.o)..."
    	gcc -c staticLib.c -o static.o
    clear :
    	rm *.a *.o mydv

    ¡¡

    ¡¡