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