Population

Directory Viewer---dynamic linking and static linking

    A.First Edition

    This is first edition of fourth assignment of comp229.

    B.The problem

6. [50%] Static and Dynamic Program Libraries

The attached sheets give basic information about static and dynamic program libraries.

For more information browse the course web page.

In this assignment, you are going to develop a static and a dynamic program libraries and

use them with your

mydv program of Assignment 3. Specifically do the following.

?

Modify (modularize) your mydv program of Assignment 3 so that it contains a main

program which calls the various functions your have written (as described in

Assignment 3).

?

Select all the functions that must be executed in every execution of your main program

and put them in a single source file, say

mydv_slib.c. Make the necessary

modifications to this source file so that these functions can be compiled independent of

the main program. Build a static library (

mydv_slib.a) of these functions.

?

Select all the functions that will be executed as required in an execution of your main

program and put them in another source file, say

mydv_dlib.c. Make the necessary

modifications to this source file so that these functions can be compiled independent of

the main program. Build a dynamic library (

mydv_dlib.so) of these functions.

?

Put the main program in a separate source file, say mydv_main.c. Make the necessary

changes so that the main program can call the functions from the static and dynamic

libraries you have developed.

?

Compile you main program and link it with the necessary program libraries

(

mydv_slib.a and mydv_dlib.so) to get the executable program mydv. Test your

executable program (

mydv) for all the test cases you used in Assignment 3.

Your submission should include the source files for the libraries and the main program and

all the output from test cases. You should also discuss the following.

(a) Do you really need the static library in this program? If so, explain why; if not, explain

the major advantage of using the static library in this program.

(b) Repeat (a) for the dynamic library.

    ¡¡

C.The idea of program
¡¡
1. No matter dynamic or static linking, the code are all the same.
2. If you want to make your life easy, don't try to follow the principle of object-oriented-programming.
Don't try to spend a whole day to make your function to be independent by not using global variables.
OOP simply costs time to design
a) You can simply divide your program into two parts: main and library.
b) If both main and library are using one common global variable, try to declare as:
"extern type variableName;". "extern" tells compiler this is an external reference. "type" is the type.
"variableName" is the name of external reference.
c) It seems to me that "type declaration" can not be referred, for example, I declared a struct MyStruct
which will be used in another file. I cannot use the way of "extern struct MyStruct". It won't works.
I have to declare the struct again. (That is why they usually keep all type definition in one single .h
file."
3. If you want to compile library to be static,
a) you can simply use "gcc -c filename.c -o objectfilename.o" to compile your source code to be object
file---binary file. Option "-c" means only compiling without linking.
b) User "ar rcs yourStaticLibName objectFileName.o anotherObject.o" to group many object file into one
library. Option "rcs" means if "yourStaticLibName" already include a previous version of any
"objectFileName", simply replace it. If not, create it and make an index for it. (I don't understand the
index, I guess it creates some data structure for fast searching.)
c) After creating static library, you can compile your main program by linking the library:
"gcc main.c myStaticLib -o myExecuteName".
4. If you want to compile library to be dynamic loading:
a) You must compile your source file to be "position-independent-code" and "shared":
"gcc -shared -fPIC sourceFile.c -o myDynamicLib". Option "-shared" means to make library sharable (Do I
explain anything?) and "-fPIC" means to make code "position-independent-code".
b) You must let your main program know that you want it to be dynamically linked with your dynamic library:
"gcc main.c myDyanmicLib -o myExecuteName". This actually puzzled me a lot because I didn't see difference
in linking format between "dynamic library" and "static library", at least from this command. Later Mr.
Zhang explained to me that "dynamic lib" and "static lib" are different since compilation. And linker knows
what you are going to link. So they simply keep the similar linking format for both "dynamic" and "static".
c) You already told your main program what dynamic library to link with at run time, but you haven't told
O.S. where to find the library: "setenv LD_LIBRARY_PATH ." Pay attention to last "dot"! You should leave
one space before the "dot" which stands for your current directory. If you saved your library in other
directory, change "dot" to that directory name and leave a space before that!
5. Static-linking executable is much bigger than dynamic-linking executable but it should run faster as no
dynamic-linking is performed during run-time.
¡¡

    D.The major functions

    C.Further improvement

    ¡¡

    //this is main program

    ////////////////////////////////////////////////////////////////////////////
    //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
    /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////
    //features of program:
    //1. I used quite a few of string arrays, enum types even function arrays.
    //2. I used too much global variables as flag of states which is ugly.
    //limits of program:
    //1. The arguments for user-defined including "dl" and "cd" is between 2-11.
    //	 Any number of commands arguments will be regarded as system commands.
    //2. All 5 options---"-all", "-modified","-smallerthan","-biggerthan","-range"---
    //	 can appear in any order and may or may not appear.
    //3. Sorting order is defined by last option: "-modified" by date, "-biggerthan"
    //	 and "-smallerthan" by size, the rest is by name.
    //4. Subdirectories won't be shown, including "." and  "..".
    //5. Hidden files would be removed whenever "-all" is not present in commands.
    //6. Whenever "cd" is used successfully, all states start again.
    //7. When no files in list, it will not do selections by commands any more.
    //8. Once "cd" is recognized, parameters after second one are ignored.
    ////////////////////////////////////////////////////////////////////////////////

    #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>

    extern int errno;
    extern char* sortedBy[3];
    extern int sortIndex;

    enum SortBy
    {ByName, ByDate, BySize};

    //a record to store file info
    struct FileInfo
    {
    	char name[31];
    	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);

    //a utility function does the printing job
    int printInfo();

    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;
    }

    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 printInfo()
    {
    	int i=0;
    	char str[23];
    	struct tm* t;
    	for (i=0; i<listCount; i++)
    	{
    		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("%-30s   %8d   %s\n", fileInfo[fileList[i]].name, fileInfo[fileList[i]].size, str);
    	}
    }

    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 the source code of library

    ¡¡

    #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];
    	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);

    enum SortBy
    {ByName, ByDate, BySize};

    //parameter for "PrintList()" to indicate what field to be sorted by
    char* sortedBy[3] = {"name", "date", "size"};
    //the actual enum SortBy variable for index of "sortedBy[3]"
    int sortIndex = 0;

    //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};

    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;
    				infoCount++;
    				fileList[listCount]=listCount; //means there is an index to...
    				listCount++;
    			}

    		}
    	}
    	return infoCount;
    }

    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;
    		}
    		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;
    		}
    	}
    }