Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

filesystem.C

Go to the documentation of this file.
00001 #include <dirent.h>
00002 #include <errno.h>
00003 #include <pwd.h>
00004 #include <stddef.h>
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <sys/stat.h>
00009 #include <sys/types.h>
00010 #include <time.h>
00011 #include <unistd.h>
00012 
00013 #include "filesystem.h"
00014 
00015 FileItem::FileItem()
00016 {
00017         path = 0;
00018         name = 0;
00019         reset();
00020 }
00021 
00022 FileItem::FileItem(char *path, 
00023         char *name, 
00024         int is_dir, 
00025         int64_t size, 
00026         int month, 
00027         int day, 
00028         int year,
00029         int64_t calendar_time)
00030 {
00031         this->path = new char[strlen(path)];
00032         this->name = new char[strlen(name)];
00033         if(this->path) strcpy(this->path, path);
00034         if(this->name) strcpy(this->name, name);
00035         this->is_dir = is_dir;
00036         this->size = size;
00037         this->month = month;
00038         this->day = day;
00039         this->year = year;
00040         this->calendar_time = calendar_time;
00041 }
00042 
00043 FileItem::~FileItem()
00044 {
00045         reset();
00046 }
00047 
00048 int FileItem::reset()
00049 {
00050         if(this->path) delete [] this->path;
00051         if(this->name) delete [] this->name;
00052         path = 0;
00053         name = 0;
00054         is_dir = 0;
00055         size = 0;
00056         month = 0;
00057         day = 0;
00058         year = 0;
00059         calendar_time = 0;
00060         return 0;
00061 }
00062 
00063 int FileItem::set_path(char *path)
00064 {
00065         if(this->path) delete [] this->path;
00066         this->path = new char[strlen(path) + 1];
00067         strcpy(this->path, path);
00068         return 0;
00069 }
00070 
00071 int FileItem::set_name(char *name)
00072 {
00073         if(this->name) delete [] this->name;
00074         this->name = new char[strlen(name) + 1];
00075         strcpy(this->name, name);
00076         return 0;
00077 }
00078 
00079 
00080 FileSystem::FileSystem()
00081 {
00082         reset_parameters();
00083         getcwd(current_dir, BCTEXTLEN);
00084         
00085 }
00086 
00087 FileSystem::~FileSystem()
00088 {
00089         delete_directory();
00090 }
00091 
00092 int FileSystem::reset_parameters()
00093 {
00094         show_all_files = 0;
00095         want_directory = 0;
00096         strcpy(filter, "");
00097         strcpy(current_dir, "");
00098         sort_order = SORT_ASCENDING;
00099         sort_field = SORT_PATH;
00100         return 0;
00101 }
00102 
00103 int FileSystem::delete_directory()
00104 {
00105         for(int i = 0; i < dir_list.total; i++)
00106         {
00107                 delete dir_list.values[i];
00108         }
00109         dir_list.remove_all();
00110         return 0;
00111 }
00112 
00113 int FileSystem::set_sort_order(int value)
00114 {
00115         this->sort_order = value;
00116 }
00117 
00118 int FileSystem::set_sort_field(int field)
00119 {
00120         this->sort_field = field;
00121 }
00122 
00123 // filename.with.dots.extension
00124 //   becomes
00125 // extension.dots.with.filename
00126 
00127 int FileSystem::dot_reverse_filename(char *out, const char *in)
00128 {
00129         int i, i2, j=0, lastdot;
00130         lastdot = strlen(in);
00131         for (i = strlen(in); i >= 0; i--){
00132 
00133         if (in[i] == '.') { 
00134                 i2 = i+1;
00135                 while (i2 < lastdot) 
00136                         out[j++] = in[i2++];
00137                 out[j++] = in[i];
00138                 lastdot = i;
00139                 }
00140         }
00141         i++;
00142         if (in[i] != '.') {
00143                 while (i < lastdot) out[j++] = in[i++];
00144         }
00145         out[j++] = '\0';
00146         return 0;
00147 }
00148 
00149 int FileSystem::compare_items(ArrayList<FileItem*> *dir_list, 
00150         int item1, 
00151         int item2)
00152 {
00153         int result = 0;
00154         FileItem *ptr1 = dir_list->values[item1];
00155         FileItem *ptr2 = dir_list->values[item2];
00156 
00157 // Default to name in ascending order
00158         switch(sort_field)
00159         {
00160                 char dotreversedname1[BCTEXTLEN], dotreversedname2[BCTEXTLEN];
00161 
00162                 case SORT_PATH:
00163                         result = (sort_order == SORT_ASCENDING) ? 
00164                                 strcasecmp(ptr1->name, ptr2->name) :
00165                                 strcasecmp(ptr2->name, ptr1->name);
00166                         break;
00167                 case SORT_SIZE:
00168                         if(ptr1->size == ptr2->size || ptr1->is_dir)
00169                                 result = strcasecmp(ptr1->name, ptr2->name);
00170                         else
00171                                 result = (sort_order == SORT_ASCENDING) ?
00172                                         (ptr1->size > ptr2->size) :
00173                                         (ptr2->size > ptr1->size);
00174                         break;
00175                 case SORT_DATE:
00176                         if(ptr1->calendar_time == ptr2->calendar_time)
00177                                 result = strcasecmp(ptr1->name, ptr2->name);
00178                         else
00179                                 result = (sort_order == SORT_ASCENDING) ?
00180                                         (ptr1->calendar_time > ptr2->calendar_time) :
00181                                         (ptr2->calendar_time > ptr1->calendar_time);
00182                         break;
00183                 case SORT_EXTENSION:
00184                         dot_reverse_filename(dotreversedname1,ptr1->name);
00185                         dot_reverse_filename(dotreversedname2,ptr2->name);
00186 
00187                         result = (sort_order == SORT_ASCENDING) ? 
00188                         strcasecmp(dotreversedname1, dotreversedname2) :
00189                         strcasecmp(dotreversedname2, dotreversedname1);
00190                         break;
00191         }
00192         return result;
00193 }
00194 
00195 
00196 int FileSystem::sort_table(ArrayList<FileItem*> *dir_list)
00197 {
00198         int changed;
00199         FileItem *temp;
00200         int i;
00201         
00202         changed = 1;
00203         while(changed)
00204         {
00205                 changed = 0;
00206                 for(i = 0; i < dir_list->total - 1; i++)
00207                 {
00208                         if(compare_items(dir_list, i, i + 1) > 0)
00209 //                      if(strcasecmp(dir_list->values[i]->name, dir_list->values[i + 1]->name) > 0)
00210                         {
00211                                 temp = dir_list->values[i];
00212                                 dir_list->values[i] = dir_list->values[i+1];
00213                                 dir_list->values[i+1] = temp;
00214                                 changed = 1;
00215                         }
00216                 }
00217         }
00218         return 0;
00219 }
00220 
00221 int FileSystem::combine(ArrayList<FileItem*> *dir_list, ArrayList<FileItem*> *file_list)
00222 {
00223         int i;
00224         FileItem *new_entry, *entry;
00225         
00226         sort_table(dir_list);
00227         for(i = 0; i < dir_list->total; i++)
00228         {
00229                 this->dir_list.append(dir_list->values[i]);
00230         }
00231 
00232         sort_table(file_list);
00233         for(i = 0; i < file_list->total; i++)
00234         {
00235                 this->dir_list.append(file_list->values[i]);
00236         }
00237         return 0;
00238 }
00239 
00240 void FileSystem::alphabetize()
00241 {
00242         sort_table(&dir_list);
00243 }
00244 
00245 int FileSystem::is_root_dir(char *path)
00246 {
00247         if(!strcmp(current_dir, "/")) return 1;
00248         return 0;
00249 }
00250 
00251 int FileSystem::test_filter(FileItem *file)
00252 {
00253         char *filter1 = 0, *filter2 = filter, *subfilter1, *subfilter2;
00254         int total_filters = 0;
00255         int result = 0;
00256         int done = 0, token_done;
00257         int token_number = 0;
00258 
00259 // Don't filter directories
00260         if(file->is_dir) return 0;
00261 
00262 // Empty filename string
00263         if(!file->name) return 1;
00264 
00265         do
00266         {
00267 // Get next token
00268                 filter1 = strchr(filter2, '[');
00269                 string[0] = 0;
00270 
00271 // Get next filter
00272                 if(filter1)
00273                 {
00274                         filter1++;
00275                         filter2 = strchr(filter1, ']');
00276 
00277                         if(filter2)
00278                         {
00279                                 int i;
00280                                 for(i = 0; filter1 + i < filter2; i++)
00281                                         string[i] = filter1[i];
00282                                 string[i] = 0;
00283                         }
00284                         else
00285                         {
00286                                 strcpy(string, filter1);
00287                                 done = 1;
00288                         }
00289                 }
00290                 else
00291                 {
00292                         if(!token_number) 
00293                                 strcpy(string, filter);
00294                         else
00295                                 done = 1;
00296                 }
00297 
00298 // Process the token
00299                 if(string[0] != 0)
00300                 {
00301                         char *path = file->name;
00302                         subfilter1 = string;
00303                         token_done = 0;
00304                         result = 0;
00305 
00306                         do
00307                         {
00308                                 string2[0] = 0;
00309                                 subfilter2 = strchr(subfilter1, '*');
00310 
00311                                 if(subfilter2)
00312                                 {
00313                                         int i;
00314                                         for(i = 0; subfilter1 + i < subfilter2; i++)
00315                                                 string2[i] = subfilter1[i];
00316                                         
00317                                         string2[i] = 0;
00318                                 }
00319                                 else
00320                                 {
00321                                         strcpy(string2, subfilter1);
00322                                         token_done = 1;
00323                                 }
00324 
00325                                 if(string2[0] != 0)
00326                                 {
00327 // Subfilter must exist at some later point in the string
00328                                         if(subfilter1 > string)
00329                                         {
00330                                                 if(!strstr(path, string2)) 
00331                                                 {
00332                                                         result = 1;
00333                                                         token_done = 1;
00334                                                 }
00335                                                 else
00336                                                 path = strstr(path, string2) + strlen(string2);
00337                                         }
00338                                         else
00339 // Subfilter must exist at this point in the string
00340                                         {
00341                                                 if(strncasecmp(path, string2, strlen(string2))) 
00342                                                 {
00343                                                         result = 1;
00344                                                         token_done = 1;
00345                                                 }
00346                                                 else
00347                                                 path += strlen(string2);
00348                                         }
00349 
00350 // String must terminate after subfilter
00351                                         if(!subfilter2)
00352                                         {
00353                                                 if(*path != 0)
00354                                                 {
00355                                                         result = 1;
00356                                                         token_done = 1;
00357                                                 }
00358                                         }
00359                                 }
00360                                 subfilter1 = subfilter2 + 1;
00361 // Let pass if no subfilter
00362                         }while(!token_done && !result);
00363                 }
00364                 token_number++;
00365         }while(!done && result);
00366 
00367         return result;
00368 }
00369 
00370 
00371 int FileSystem::update(char *new_dir)
00372 {
00373         DIR *dirstream;
00374         struct dirent64 *new_filename;
00375         struct stat ostat;
00376         struct tm *mod_time;
00377         int i, j, k, include_this;
00378         FileItem *new_file;
00379         char full_path[BCTEXTLEN], name_only[BCTEXTLEN];
00380         ArrayList<FileItem*>directories;
00381         ArrayList<FileItem*>files;
00382         int result = 0;
00383 
00384         delete_directory();
00385         if(new_dir != 0) strcpy(current_dir, new_dir);
00386         dirstream = opendir(current_dir);
00387         if(!dirstream) return 1;          // failed to open directory
00388 
00389         while(new_filename = readdir64(dirstream))
00390         {
00391                 include_this = 1;
00392 
00393 // File is directory heirarchy
00394                 if(!strcmp(new_filename->d_name, ".") || 
00395                         !strcmp(new_filename->d_name, "..")) include_this = 0;
00396 
00397 // File is hidden and we don't want all files
00398                 if(include_this && !show_all_files && new_filename->d_name[0] == '.') include_this = 0;
00399 
00400 // file not hidden
00401                 if(include_this)
00402         {
00403                         new_file = new FileItem;
00404                         sprintf(full_path, "%s", current_dir);
00405                         if(!is_root_dir(current_dir)) strcat(full_path, "/");
00406                         strcat(full_path, new_filename->d_name);
00407                         strcpy(name_only, new_filename->d_name);
00408                         new_file->set_path(full_path);
00409                         new_file->set_name(name_only);
00410 
00411 // Get information about the file.
00412                         if(!stat(full_path, &ostat))
00413                         {
00414                                 new_file->size = ostat.st_size;
00415                                 mod_time = localtime(&(ostat.st_mtime));
00416                                 new_file->month = mod_time->tm_mon + 1;
00417                                 new_file->day = mod_time->tm_mday;
00418                                 new_file->year = mod_time->tm_year + 1900;
00419                                 new_file->calendar_time = ostat.st_mtime;
00420 
00421                                 if(S_ISDIR(ostat.st_mode))
00422                                 {
00423                                         strcat(name_only, "/"); // is a directory
00424                                         new_file->is_dir = 1;
00425                                 }
00426 
00427 // File is excluded from filter
00428                                 if(include_this && test_filter(new_file)) include_this = 0;
00429 //printf("FileSystem::update 3 %d %d\n", include_this, test_filter(new_file));
00430 
00431 // File is not a directory and we just want directories
00432                                 if(include_this && want_directory && !new_file->is_dir) include_this = 0;
00433                         }
00434                         else
00435                         {
00436 //printf("FileSystem::update 3 %s\n", full_path);
00437                                 printf("FileSystem::update %s: %s\n",
00438                                         full_path,
00439                                         strerror(errno));
00440                                 include_this = 0;
00441                                 result = 1;
00442                         }
00443 
00444 // add to list
00445                         if(include_this)
00446                         {
00447                                 if(new_file->is_dir) directories.append(new_file);
00448                                 else files.append(new_file);
00449                         }
00450                         else
00451                                 delete new_file;
00452                 }
00453         }
00454 
00455         closedir(dirstream);
00456 // combine the directories and files in the master list
00457         combine(&directories, &files);
00458 // remove pointers
00459         directories.remove_all();
00460         files.remove_all();
00461 
00462         return result;
00463 // success
00464 }
00465 
00466 int FileSystem::set_filter(char *new_filter)
00467 {
00468         strcpy(filter, new_filter);
00469         return 0;
00470 }
00471 
00472 int FileSystem::set_show_all()
00473 {
00474         show_all_files = 1;
00475         return 0;
00476 }
00477 
00478 int FileSystem::set_want_directory()
00479 {
00480         want_directory = 1;
00481         return 0;
00482 }
00483 
00484 int FileSystem::is_dir(const char *path)      // return 0 if the text is a directory
00485 {
00486         if(!strlen(path)) return 0;
00487 
00488         char new_dir[BCTEXTLEN];
00489         struct stat ostat;    // entire name is a directory
00490 
00491         strcpy(new_dir, path);
00492         complete_path(new_dir);
00493         if(!stat(new_dir, &ostat) && S_ISDIR(ostat.st_mode)) return 0;
00494         return 1;
00495 }
00496 
00497 int FileSystem::create_dir(char *new_dir_)
00498 {
00499         char new_dir[BCTEXTLEN];
00500         strcpy(new_dir, new_dir_);
00501         complete_path(new_dir);
00502 
00503         mkdir(new_dir, S_IREAD | S_IWRITE | S_IEXEC);
00504         return 0;
00505 }
00506 
00507 int FileSystem::parse_tildas(char *new_dir)
00508 {
00509         if(new_dir[0] == 0) return 1;
00510 
00511 // Our home directory
00512         if(new_dir[0] == '~')
00513         {
00514 
00515                 if(new_dir[1] == '/' || new_dir[1] == 0)
00516                 {
00517 // user's home directory
00518                         char *home;
00519                         char string[BCTEXTLEN];
00520                         home = getenv("HOME");
00521 
00522 // print starting after tilda
00523                         if(home) sprintf(string, "%s%s", home, &new_dir[1]);
00524                         strcpy(new_dir, string);
00525                         return 0;
00526                 }
00527                 else
00528 // Another user's home directory
00529                 {                
00530                         char string[BCTEXTLEN], new_user[BCTEXTLEN];
00531                         struct passwd *pw;
00532                         int i, j;
00533       
00534                         for(i = 1, j = 0; new_dir[i] != 0 && new_dir[i] != '/'; i++, j++)
00535                         {                // copy user name
00536                                 new_user[j] = new_dir[i];
00537                         }
00538                         new_user[j] = 0;
00539       
00540                         setpwent();
00541                         while(pw = getpwent())
00542                         {
00543 // get info for user
00544                                 if(!strcmp(pw->pw_name, new_user))
00545                                 {
00546 // print starting after tilda
00547                                 sprintf(string, "%s%s", pw->pw_dir, &new_dir[i]);
00548                                 strcpy(new_dir, string);
00549                                 break;
00550                         }
00551                         }
00552                         endpwent();
00553                         return 0;
00554                 }
00555         }
00556         return 0;
00557 }
00558 
00559 int FileSystem::parse_directories(char *new_dir)
00560 {
00561 //printf("FileSystem::parse_directories 1 %s\n", new_dir);
00562         if(new_dir[0] != '/')
00563         {
00564 // extend path completely
00565                 char string[BCTEXTLEN];
00566 //printf("FileSystem::parse_directories 2 %s\n", current_dir);
00567                 if(!strlen(current_dir))
00568                 {
00569 // no current directory
00570                         strcpy(string, new_dir);
00571                 }
00572                 else
00573                 if(!is_root_dir(current_dir))
00574                 {
00575 // current directory is not root
00576                         if(current_dir[strlen(current_dir) - 1] == '/')
00577 // current_dir already has ending /
00578                         sprintf(string, "%s%s", current_dir, new_dir);
00579                         else
00580 // need ending /
00581                         sprintf(string, "%s/%s", current_dir, new_dir);
00582                 }
00583                 else
00584                         sprintf(string, "%s%s", current_dir, new_dir);
00585                 
00586 //printf("FileSystem::parse_directories 3 %s %s\n", new_dir, string);
00587                 strcpy(new_dir, string);
00588 //printf("FileSystem::parse_directories 4\n");
00589         }
00590         return 0;
00591 }
00592 
00593 int FileSystem::parse_dots(char *new_dir)
00594 {
00595 // recursively remove ..s
00596         int changed = 1;
00597         while(changed)
00598         {
00599                 int i, j, len;
00600                 len = strlen(new_dir);
00601                 changed = 0;
00602                 for(i = 0, j = 1; !changed && j < len; i++, j++)
00603                 {
00604                         if(new_dir[i] == '.' && new_dir[j] == '.')
00605                         {
00606                                 changed = 1;
00607                                 while(new_dir[i] != '/' && i > 0)
00608                                 {
00609 // look for first / before ..
00610                                         i--;
00611                                 }
00612 
00613 // find / before this /
00614                                 if(i > 0) i--;  
00615                                 while(new_dir[i] != '/' && i > 0)
00616                                 {
00617 // look for first / before first / before ..
00618                                         i--;
00619                                 }
00620 
00621 // i now equals /first filename before ..
00622 // look for first / after ..
00623                                 while(new_dir[j] != '/' && j < len)
00624                                 {
00625                                         j++;
00626                                 }
00627 
00628 // j now equals /first filename after ..
00629                                 while(j < len)
00630                                 {
00631                                         new_dir[i++] = new_dir[j++];
00632                                 }
00633 
00634                                 new_dir[i] = 0;
00635 // default to root directory
00636                                 if((new_dir[0]) == 0) sprintf(new_dir, "/");
00637                                 break;
00638                         }
00639                 }
00640         }
00641         return 0;
00642 }
00643 
00644 int FileSystem::complete_path(char *filename)
00645 {
00646 //printf("FileSystem::complete_path 1\n");
00647         if(!strlen(filename)) return 1;
00648 //printf("FileSystem::complete_path 1\n");
00649         parse_tildas(filename);
00650 //printf("FileSystem::complete_path 1\n");
00651         parse_directories(filename);
00652 //printf("FileSystem::complete_path 1\n");
00653         parse_dots(filename);
00654 // don't add end slash since this requires checking if dir
00655 //printf("FileSystem::complete_path 2\n");
00656         return 0;
00657 }
00658 
00659 int FileSystem::extract_dir(char *out, const char *in)
00660 {
00661         strcpy(out, in);
00662         if(is_dir(in))
00663         {
00664 // complete string is not directory
00665                 int i;
00666 
00667                 complete_path(out);
00668 
00669                 for(i = strlen(out); i > 0 && out[i - 1] != '/'; i--)
00670                 {
00671                         ;
00672                 }
00673                 if(i >= 0) out[i] = 0;
00674         }
00675         return 0;
00676 }
00677 
00678 int FileSystem::extract_name(char *out, const char *in, int test_dir)
00679 {
00680         int i;
00681 
00682         if(test_dir && !is_dir(in))
00683                 sprintf(out, "");    // complete string is directory
00684         else
00685         {
00686                 for(i = strlen(in)-1; i > 0 && in[i] != '/'; i--)
00687                 {
00688                         ;
00689                 }
00690                 if(in[i] == '/') i++;
00691                 strcpy(out, &in[i]);
00692         }
00693         return 0;
00694 }
00695 
00696 int FileSystem::join_names(char *out, char *dir_in, char *name_in)
00697 {
00698         strcpy(out, dir_in);
00699         int len = strlen(out);
00700         int result = 0;
00701         
00702         while(!result)
00703                 if(len == 0 || out[len] != 0) result = 1; else len--;
00704         
00705         if(len != 0)
00706         {
00707                 if(out[len] != '/') strcat(out, "/");
00708         }
00709         
00710         strcat(out, name_in);
00711         return 0;
00712 }
00713 
00714 long FileSystem::get_date(char *filename)
00715 {
00716         struct stat file_status;
00717         bzero(&file_status, sizeof(struct stat));
00718         stat(filename, &file_status);
00719         return file_status.st_mtime;
00720 }
00721 
00722 int64_t FileSystem::get_size(char *filename)
00723 {
00724         struct stat file_status;
00725         bzero(&file_status, sizeof(struct stat));
00726         stat(filename, &file_status);
00727         return file_status.st_size;
00728 }
00729 
00730 int FileSystem::change_dir(char *new_dir)
00731 {
00732         char new_dir_full[BCTEXTLEN];
00733         
00734         strcpy(new_dir_full, new_dir);
00735 
00736         complete_path(new_dir_full);
00737 // cut ending slash
00738         if(strcmp(new_dir_full, "/") && 
00739                 new_dir_full[strlen(new_dir_full) - 1] == '/') 
00740                 new_dir_full[strlen(new_dir_full) - 1] = 0;
00741         update(new_dir_full);
00742         return 0;
00743 }
00744 
00745 int FileSystem::set_current_dir(char *new_dir)
00746 {
00747         strcpy(current_dir, new_dir);
00748         return 0;
00749 }
00750 
00751 int FileSystem::add_end_slash(char *new_dir)
00752 {
00753         if(new_dir[strlen(new_dir) - 1] != '/') strcat(new_dir, "/");
00754         return 0;
00755 }
00756 
00757 char* FileSystem::get_current_dir()
00758 {
00759         return current_dir;
00760 }
00761 
00762 int FileSystem::total_files()
00763 {
00764         return dir_list.total;
00765 }
00766 
00767 
00768 FileItem* FileSystem::get_entry(int entry)
00769 {
00770         return dir_list.values[entry];
00771 }

Generated on Sun Jan 8 13:26:34 2006 for Guicast-svn by  doxygen 1.4.4