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