r136: This commit was manufactured by cvs2svn to create tag 'hv_1_1_8'.
[cinelerra_cv/ct.git] / hvirtual / guicast / filesystem.C
blobec0d3ec3c708bc717587e3522b7bfdc100818fd1
1 #include <pwd.h>
2 #include <stddef.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <time.h>
9 #include <dirent.h>
10 #include <unistd.h>
12 #include "filesystem.h"
14 FileItem::FileItem()
16         path = 0;
17         name = 0;
18         reset();
21 FileItem::FileItem(char *path, 
22         char *name, 
23         int is_dir, 
24         int64_t size, 
25         int month, 
26         int day, 
27         int year,
28         int64_t calendar_time)
30         this->path = new char[strlen(path)];
31         this->name = new char[strlen(name)];
32         if(this->path) strcpy(this->path, path);
33         if(this->name) strcpy(this->name, name);
34         this->is_dir = is_dir;
35         this->size = size;
36         this->month = month;
37         this->day = day;
38         this->year = year;
39         this->calendar_time = calendar_time;
42 FileItem::~FileItem()
44         reset();
47 int FileItem::reset()
49         if(this->path) delete [] this->path;
50         if(this->name) delete [] this->name;
51         path = 0;
52         name = 0;
53         is_dir = 0;
54         size = 0;
55         month = 0;
56         day = 0;
57         year = 0;
58         calendar_time = 0;
59         return 0;
62 int FileItem::set_path(char *path)
64         if(this->path) delete [] this->path;
65         this->path = new char[strlen(path) + 1];
66         strcpy(this->path, path);
67         return 0;
70 int FileItem::set_name(char *name)
72         if(this->name) delete [] this->name;
73         this->name = new char[strlen(name) + 1];
74         strcpy(this->name, name);
75         return 0;
79 FileSystem::FileSystem()
81         reset_parameters();
82         getcwd(current_dir, BCTEXTLEN);
83         
86 FileSystem::~FileSystem()
88         delete_directory();
91 int FileSystem::reset_parameters()
93         show_all_files = 0;
94         want_directory = 0;
95         strcpy(filter, "");
96         strcpy(current_dir, "");
97         sort_order = SORT_ASCENDING;
98         sort_field = SORT_PATH;
99         return 0;
102 int FileSystem::delete_directory()
104         for(int i = 0; i < dir_list.total; i++)
105         {
106                 delete dir_list.values[i];
107         }
108         dir_list.remove_all();
109         return 0;
112 int FileSystem::set_sort_order(int value)
114         this->sort_order = value;
117 int FileSystem::set_sort_field(int field)
119         this->sort_field = field;
122 int FileSystem::compare_items(ArrayList<FileItem*> *dir_list, 
123         int item1, 
124         int item2)
126         int result = 0;
127         FileItem *ptr1 = dir_list->values[item1];
128         FileItem *ptr2 = dir_list->values[item2];
130 // Default to name in ascending order
131         switch(sort_field)
132         {
133                 case SORT_PATH:
134                         result = (sort_order == SORT_ASCENDING) ? 
135                                 strcasecmp(ptr1->name, ptr2->name) :
136                                 strcasecmp(ptr2->name, ptr1->name);
137                         break;
138                 case SORT_SIZE:
139                         if(ptr1->size == ptr2->size || ptr1->is_dir)
140                                 result = strcasecmp(ptr1->name, ptr2->name);
141                         else
142                                 result = (sort_order == SORT_ASCENDING) ?
143                                         (ptr1->size > ptr2->size) :
144                                         (ptr2->size > ptr1->size);
145                         break;
146                 case SORT_DATE:
147                         if(ptr1->calendar_time == ptr2->calendar_time)
148                                 result = strcasecmp(ptr1->name, ptr2->name);
149                         else
150                                 result = (sort_order == SORT_ASCENDING) ?
151                                         (ptr1->calendar_time > ptr2->calendar_time) :
152                                         (ptr2->calendar_time > ptr1->calendar_time);
153                         break;
154         }
155         return result;
159 int FileSystem::sort_table(ArrayList<FileItem*> *dir_list)
161         int changed;
162         FileItem *temp;
163         int i;
164         
165         changed = 1;
166         while(changed)
167         {
168                 changed = 0;
169                 for(i = 0; i < dir_list->total - 1; i++)
170                 {
171                         if(compare_items(dir_list, i, i + 1) > 0)
172 //                      if(strcasecmp(dir_list->values[i]->name, dir_list->values[i + 1]->name) > 0)
173                         {
174                                 temp = dir_list->values[i];
175                                 dir_list->values[i] = dir_list->values[i+1];
176                                 dir_list->values[i+1] = temp;
177                                 changed = 1;
178                         }
179                 }
180         }
181         return 0;
184 int FileSystem::combine(ArrayList<FileItem*> *dir_list, ArrayList<FileItem*> *file_list)
186         int i;
187         FileItem *new_entry, *entry;
188         
189         sort_table(dir_list);
190         for(i = 0; i < dir_list->total; i++)
191         {
192                 this->dir_list.append(dir_list->values[i]);
193         }
195         sort_table(file_list);
196         for(i = 0; i < file_list->total; i++)
197         {
198                 this->dir_list.append(file_list->values[i]);
199         }
200         return 0;
203 int FileSystem::is_root_dir(char *path)
205         if(!strcmp(current_dir, "/")) return 1;
206         return 0;
209 int FileSystem::test_filter(FileItem *file)
211         char *filter1 = 0, *filter2 = filter, *subfilter1, *subfilter2;
212         int total_filters = 0;
213         int result = 0;
214         int done = 0, token_done;
215         int token_number = 0;
217 // Don't filter directories
218         if(file->is_dir) return 0;
219 // Empty filename string
220         if(!file->name) return 1;
222         do
223         {
224 // Get next token
225                 filter1 = strchr(filter2, '[');
226                 string[0] = 0;
228 // Get next filter
229                 if(filter1)
230                 {
231                         filter1++;
232                         filter2 = strchr(filter1, ']');
234                         if(filter2)
235                         {
236                                 int i;
237                                 for(i = 0; filter1 + i < filter2; i++)
238                                         string[i] = filter1[i];
239                                 string[i] = 0;
240                         }
241                         else
242                         {
243                                 strcpy(string, filter1);
244                                 done = 1;
245                         }
246                 }
247                 else
248                 {
249                         if(!token_number) 
250                                 strcpy(string, filter);
251                         else
252                                 done = 1;
253                 }
255 // Process the token
256                 if(string[0] != 0)
257                 {
258                         char *path = file->name;
259                         subfilter1 = string;
260                         token_done = 0;
261                         result = 0;
263                         do
264                         {
265                                 string2[0] = 0;
266                                 subfilter2 = strchr(subfilter1, '*');
268                                 if(subfilter2)
269                                 {
270                                         int i;
271                                         for(i = 0; subfilter1 + i < subfilter2; i++)
272                                                 string2[i] = subfilter1[i];
273                                         
274                                         string2[i] = 0;
275                                 }
276                                 else
277                                 {
278                                         strcpy(string2, subfilter1);
279                                         token_done = 1;
280                                 }
282                                 if(string2[0] != 0)
283                                 {
284 // Subfilter must exist at some later point in the string
285                                         if(subfilter1 > string)
286                                         {
287                                                 if(!strstr(path, string2)) 
288                                                 {
289                                                         result = 1;
290                                                         token_done = 1;
291                                                 }
292                                                 else
293                                                 path = strstr(path, string2) + strlen(string2);
294                                         }
295                                         else
296 // Subfilter must exist at this point in the string
297                                         {
298                                                 if(strncasecmp(path, string2, strlen(string2))) 
299                                                 {
300                                                         result = 1;
301                                                         token_done = 1;
302                                                 }
303                                                 else
304                                                 path += strlen(string2);
305                                         }
307 // String must terminate after subfilter
308                                         if(!subfilter2)
309                                         {
310                                                 if(*path != 0)
311                                                 {
312                                                         result = 1;
313                                                         token_done = 1;
314                                                 }
315                                         }
316                                 }
317                                 subfilter1 = subfilter2 + 1;
318 // Let pass if no subfilter
319                         }while(!token_done && !result);
320                 }
321                 token_number++;
322         }while(!done && result);
324         return result;
328 int FileSystem::update(char *new_dir)
330         DIR *dirstream;
331         struct dirent64 *new_filename;
332         struct stat ostat;
333         struct tm *mod_time;
334         int i, j, k, include_this;
335         FileItem *new_file;
336         char full_path[BCTEXTLEN], name_only[BCTEXTLEN];
337         ArrayList<FileItem*>directories;
338         ArrayList<FileItem*>files;
340         delete_directory();
341         if(new_dir != 0) strcpy(current_dir, new_dir);
342         dirstream = opendir(current_dir);
343         if(!dirstream) return 1;          // failed to open directory
345         while(new_filename = readdir64(dirstream))
346         {
347                 include_this = 1;
349 // File is directory heirarchy
350                 if(!strcmp(new_filename->d_name, ".") || 
351                         !strcmp(new_filename->d_name, "..")) include_this = 0;
353 // File is hidden and we don't want all files
354                 if(include_this && !show_all_files && new_filename->d_name[0] == '.') include_this = 0;
356 // file not hidden
357                 if(include_this)
358         {
359                         new_file = new FileItem;
360                         sprintf(full_path, "%s", current_dir);
361                         if(!is_root_dir(current_dir)) strcat(full_path, "/");
362                         strcat(full_path, new_filename->d_name);
363                         strcpy(name_only, new_filename->d_name);
364                         new_file->set_path(full_path);
365                         new_file->set_name(name_only);
367 // Get information about the file.
368                         if(!stat(full_path, &ostat))
369                         {
370                                 new_file->size = ostat.st_size;
371                                 mod_time = localtime(&(ostat.st_mtime));
372                                 new_file->month = mod_time->tm_mon + 1;
373                                 new_file->day = mod_time->tm_mday;
374                                 new_file->year = mod_time->tm_year + 1900;
375                                 new_file->calendar_time = ostat.st_mtime;
377                                 if(S_ISDIR(ostat.st_mode))
378                                 {
379                                         strcat(name_only, "/"); // is a directory
380                                         new_file->is_dir = 1;
381                                 }
383 // File is excluded from filter
384                                 if(include_this && test_filter(new_file)) include_this = 0;
385 //printf("FileSystem::update 3 %d %d\n", include_this, test_filter(new_file));
387 // File is not a directory and we just want directories
388                                 if(include_this && want_directory && !new_file->is_dir) include_this = 0;
389                         }
390                         else
391                         {
392 //printf("FileSystem::update 3 %s\n", full_path);
393                                 include_this = 0;
394                         }
396 // add to list
397                         if(include_this)
398                         {
399                                 if(new_file->is_dir) directories.append(new_file);
400                                 else files.append(new_file);
401                         }
402                         else
403                                 delete new_file;
404                 }
405         }
407         closedir(dirstream);
408 // combine the directories and files in the master list
409         combine(&directories, &files);
410 // remove pointers
411         directories.remove_all();
412         files.remove_all();
414         return 0;           // success
417 int FileSystem::set_filter(char *new_filter)
419         strcpy(filter, new_filter);
420         return 0;
423 int FileSystem::set_show_all()
425         show_all_files = 1;
426         return 0;
429 int FileSystem::set_want_directory()
431         want_directory = 1;
432         return 0;
435 int FileSystem::is_dir(const char *path)      // return 0 if the text is a directory
437         if(!strlen(path)) return 0;
439         char new_dir[BCTEXTLEN];
440         struct stat ostat;    // entire name is a directory
442         strcpy(new_dir, path);
443         complete_path(new_dir);
444         if(!stat(new_dir, &ostat) && S_ISDIR(ostat.st_mode)) return 0;
445         return 1;
448 int FileSystem::create_dir(char *new_dir_)
450         char new_dir[BCTEXTLEN];
451         strcpy(new_dir, new_dir_);
452         complete_path(new_dir);
454         mkdir(new_dir, S_IREAD | S_IWRITE | S_IEXEC);
455         return 0;
458 int FileSystem::parse_tildas(char *new_dir)
460         if(new_dir[0] == 0) return 1;
462 // Our home directory
463         if(new_dir[0] == '~')
464         {
466                 if(new_dir[1] == '/' || new_dir[1] == 0)
467                 {
468 // user's home directory
469                         char *home;
470                         char string[BCTEXTLEN];
471                         home = getenv("HOME");
473 // print starting after tilda
474                         if(home) sprintf(string, "%s%s", home, &new_dir[1]);
475                         strcpy(new_dir, string);
476                         return 0;
477                 }
478                 else
479 // Another user's home directory
480                 {                
481                         char string[BCTEXTLEN], new_user[BCTEXTLEN];
482                         struct passwd *pw;
483                         int i, j;
484       
485                         for(i = 1, j = 0; new_dir[i] != 0 && new_dir[i] != '/'; i++, j++)
486                         {                // copy user name
487                                 new_user[j] = new_dir[i];
488                         }
489                         new_user[j] = 0;
490       
491                         setpwent();
492                         while(pw = getpwent())
493                         {
494 // get info for user
495                                 if(!strcmp(pw->pw_name, new_user))
496                                 {
497 // print starting after tilda
498                                 sprintf(string, "%s%s", pw->pw_dir, &new_dir[i]);
499                                 strcpy(new_dir, string);
500                                 break;
501                         }
502                         }
503                         endpwent();
504                         return 0;
505                 }
506         }
507         return 0;
510 int FileSystem::parse_directories(char *new_dir)
512 //printf("FileSystem::parse_directories 1 %s\n", new_dir);
513         if(new_dir[0] != '/')
514         {
515 // extend path completely
516                 char string[BCTEXTLEN];
517 //printf("FileSystem::parse_directories 2 %s\n", current_dir);
518                 if(!strlen(current_dir))
519                 {
520 // no current directory
521                         strcpy(string, new_dir);
522                 }
523                 else
524                 if(!is_root_dir(current_dir))
525                 {
526 // current directory is not root
527                         if(current_dir[strlen(current_dir) - 1] == '/')
528 // current_dir already has ending /
529                         sprintf(string, "%s%s", current_dir, new_dir);
530                         else
531 // need ending /
532                         sprintf(string, "%s/%s", current_dir, new_dir);
533                 }
534                 else
535                         sprintf(string, "%s%s", current_dir, new_dir);
536                 
537 //printf("FileSystem::parse_directories 3 %s %s\n", new_dir, string);
538                 strcpy(new_dir, string);
539 //printf("FileSystem::parse_directories 4\n");
540         }
541         return 0;
544 int FileSystem::parse_dots(char *new_dir)
546 // recursively remove ..s
547         int changed = 1;
548         while(changed)
549         {
550                 int i, j, len;
551                 len = strlen(new_dir);
552                 changed = 0;
553                 for(i = 0, j = 1; !changed && j < len; i++, j++)
554                 {
555                         if(new_dir[i] == '.' && new_dir[j] == '.')
556                         {
557                                 changed = 1;
558                                 while(new_dir[i] != '/' && i > 0)
559                                 {
560 // look for first / before ..
561                                         i--;
562                                 }
564 // find / before this /
565                                 if(i > 0) i--;  
566                                 while(new_dir[i] != '/' && i > 0)
567                                 {
568 // look for first / before first / before ..
569                                         i--;
570                                 }
572 // i now equals /first filename before ..
573 // look for first / after ..
574                                 while(new_dir[j] != '/' && j < len)
575                                 {
576                                         j++;
577                                 }
579 // j now equals /first filename after ..
580                                 while(j < len)
581                                 {
582                                         new_dir[i++] = new_dir[j++];
583                                 }
585                                 new_dir[i] = 0;
586 // default to root directory
587                                 if((new_dir[0]) == 0) sprintf(new_dir, "/");
588                                 break;
589                         }
590                 }
591         }
592         return 0;
595 int FileSystem::complete_path(char *filename)
597 //printf("FileSystem::complete_path 1\n");
598         if(!strlen(filename)) return 1;
599 //printf("FileSystem::complete_path 1\n");
600         parse_tildas(filename);
601 //printf("FileSystem::complete_path 1\n");
602         parse_directories(filename);
603 //printf("FileSystem::complete_path 1\n");
604         parse_dots(filename);
605 // don't add end slash since this requires checking if dir
606 //printf("FileSystem::complete_path 2\n");
607         return 0;
610 int FileSystem::extract_dir(char *out, const char *in)
612         strcpy(out, in);
613         if(is_dir(in))
614         {
615 // complete string is not directory
616                 int i;
618                 complete_path(out);
620                 for(i = strlen(out); i > 0 && out[i] != '/'; i--)
621                 {
622                         ;
623                 }
624                 if(i >= 0) out[i] = 0;
625         }
626         return 0;
629 int FileSystem::extract_name(char *out, const char *in, int test_dir)
631         int i;
633         if(test_dir && !is_dir(in))
634                 sprintf(out, "");    // complete string is directory
635         else
636         {
637                 for(i = strlen(in)-1; i > 0 && in[i] != '/'; i--)
638                 {
639                         ;
640                 }
641                 if(in[i] == '/') i++;
642                 strcpy(out, &in[i]);
643         }
644         return 0;
647 int FileSystem::join_names(char *out, char *dir_in, char *name_in)
649         strcpy(out, dir_in);
650         int len = strlen(out);
651         int result = 0;
652         
653         while(!result)
654                 if(len == 0 || out[len] != 0) result = 1; else len--;
655         
656         if(len != 0)
657         {
658                 if(out[len] != '/') strcat(out, "/");
659         }
660         
661         strcat(out, name_in);
662         return 0;
665 long FileSystem::get_date(char *filename)
667         struct stat file_status;
668         bzero(&file_status, sizeof(struct stat));
669         stat (filename, &file_status);
670         return file_status.st_mtime;
673 int64_t FileSystem::get_size(char *filename)
675         struct stat file_status;
676         bzero(&file_status, sizeof(struct stat));
677         stat(filename, &file_status);
678         return file_status.st_size;
681 int FileSystem::change_dir(char *new_dir)
683         char new_dir_full[BCTEXTLEN];
684         
685         strcpy(new_dir_full, new_dir);
687         complete_path(new_dir_full);
688 // cut ending slash
689         if(strcmp(new_dir_full, "/") && 
690                 new_dir_full[strlen(new_dir_full) - 1] == '/') 
691                 new_dir_full[strlen(new_dir_full) - 1] = 0;
692         update(new_dir_full);
693         return 0;
696 int FileSystem::set_current_dir(char *new_dir)
698         strcpy(current_dir, new_dir);
699         return 0;
702 int FileSystem::add_end_slash(char *new_dir)
704         if(new_dir[strlen(new_dir) - 1] != '/') strcat(new_dir, "/");
705         return 0;
708 char* FileSystem::get_current_dir()
710         return current_dir;
713 int FileSystem::total_files()
715         return dir_list.total;
719 FileItem* FileSystem::get_entry(int entry)
721         return dir_list.values[entry];