1 #ifdef INCS_NEED_DOT_H
2 #include <sys/types.h>
3 #include <dirent.h>
4 #include <ctype.h>
5 #else
6 #include <sys/types>
7 #include <dirent>
8 #include <ctype>
9 #endif
10 
11 #include "findfile.h"
12 #include "envdeps.h"
13 
14 // ====================================================================
15 // patmat: a routine for pattern matching
16 // author: Screenath Chary, Nov 29 1988
17 // ====================================================================
18 
patmat(char * raw,char * pat)19 static int patmat(char *raw, char *pat)
20 {
21 
22   size_t i;
23 
24   if (*pat == '\0' && *raw == '\0')
25     {
26       // if it is the end of both strings, then match
27       return 1;
28     }
29   if (*pat == '\0')
30     {
31       // if it is the end of only pat then mismatch
32       return 0;
33     }
34 
35   // if pattern is `*'
36 
37   if (*pat == '*')
38     {
39       if (*(pat + 1) == '\0')
40         {
41 	  // if pat is just `*' then match
42 	  return 1;
43         }
44       else
45         {
46 	  // else hunt for match or wild card
47 	  for (i = 0; i <= strlen(raw); i++)
48             {
49 	      if (tolower(*(raw + i)) == tolower(*(pat + 1)) ||
50 		  *(pat + 1) == '?')
51                 {
52 		  // if found, match rest of pattern
53 		  if (patmat(raw + i + 1, pat + 2) == 1)
54                     {
55 		      return 1;
56                     }
57                 }
58             }
59         }
60     }
61   else
62     {
63       if (*raw == '\0')
64         {
65           // we've reached the end of raw; return a mismatch
66 	  return 0;
67         }
68 
69       if (*pat == '?' || tolower(*pat) == tolower(*raw))
70         {
71           // if chars match then try and match rest of it
72 	  if (patmat(raw + 1, pat + 1) == 1)
73             {
74 	      return 1;
75             }
76         }
77     }
78 
79   // fell through; no match found
80   return 0;
81 }
82 
83 #ifdef UNIXLIKE
84 
85 
86 // ====================================================================
87 // private_adaptcase: a routine for woring with case-insensitive file
88 //            lists (like binkley flow files) on case sensitive file
89 //     	      systems
90 // author:    Tobias Ernst, Jan 1999
91 // ====================================================================
92 
93 /* The routine behaves as follows: It assumes that pathname
94    is a path name which may contain multiple dashes, and it assumes
95    that you run on a case sensitive file system but want / must to
96    match the path name insensitively. adaptcase takes every path
97    element out of pathname and uses findfirst to check if it
98    exists. If it exists, the path element is replaced by the exact
99    spelling as used by the file system. If it does not exist, it is
100    converted to lowercase.  This allows you to make you program deal
101    with things like mounts of DOS file systems under unix
102 
103    Return value is 1 if the file exists and 0 if not.
104 
105    Attention: Do not ever try to understand this code. I had to do
106    heavy caching and other optimizations in this routine in order to
107    reduce that startup time of msged to a reasonable value. (The
108    problem is that opendir / readdir is very slow ...). If you ever
109    have to fix something in this routine, you'd better rewrite it from
110 .   scratch.
111 */
112 
113 /* the cache will take  about 60 * 4192 + 30 * 512 * 4 bytes in this
114    configuration, i.e. 360K */
115 
116 #define adaptcase_cachesize   60
117 #define rawcache_stepsize   4192
118 #define cacheindex_stepsize  512
119 
120 struct adaptcase_cache_entry
121 {
122     char *query;
123     char *result;
124     char *raw_cache;
125     size_t *cache_index;
126     size_t n;
127 };
128 static int adaptcase_cache_position = -1;
129 static struct adaptcase_cache_entry adaptcase_cache[adaptcase_cachesize];
130 
131 static char *current_cache;
cache_sort_cmp(const void * a,const void * b)132 static int cache_sort_cmp(const void *a, const void *b)
133 {
134     return strcasecmp(current_cache+(*((const size_t *)a)),
135                       current_cache+(*((const size_t *)b)));
136 }
137 
cache_find_cmp(const void * a,const void * b)138 static int cache_find_cmp(const void *a, const void *b)
139 {
140     return strcasecmp((const char *)a, current_cache+(*((const size_t *)b)));
141 }
142 
143 /* #define TRACECACHE */
144 
145 #ifdef BSD
146 #define DIRENTLEN(x) ((x)->d_namlen)
147 #else
148 #define DIRENTLEN(x) (strlen((x)->d_name))
149 #endif
150 
private_adaptcase(char * pathname)151 static void private_adaptcase(char *pathname)
152 {
153     int i,j,k,l,n,nmax=0, found=1, addresult=0;
154     size_t *m; size_t raw_high, rawmax=0;
155     char buf[4096];
156     DIR *dirp = NULL;
157     struct dirent *dp;
158     char c;
159 
160 #ifdef TRACECACHE
161     FILE *ftrc;
162 #endif
163 
164     if (!*pathname)
165         return;
166 #ifdef TRACECACHE
167     ftrc = fopen ("trace.log", "a");
168     fprintf(ftrc, "--Query: %s\n", pathname);
169 #endif
170 
171     if (adaptcase_cache_position == -1)
172     {
173         /* initialise the cache */
174         memset(adaptcase_cache, 0, adaptcase_cachesize *
175                sizeof(struct adaptcase_cache_entry));
176         adaptcase_cache_position = 0;
177     }
178 
179     k = strlen(pathname);
180     if (k > 2)
181     {
182         for (k = k - 2; k>0 && pathname[k] != '/'; k--);
183     }
184     else
185     {
186         k = 0;
187     }
188 
189     j = 0; i = 0;
190 
191 
192 start_over:
193 
194     if (k != 0)
195     {
196         l = adaptcase_cache_position;
197         do
198         {
199             if (adaptcase_cache[l].query != NULL)
200             {
201                 if ((!memcmp(adaptcase_cache[l].query,pathname,k)) &&
202                     (adaptcase_cache[l].query[k] == '\0'))
203                 {
204                     /* cache hit for the directory */
205 #ifdef TRACECACHE
206                     fprintf (ftrc, "Cache hit for Dir: %s\n",
207                              adaptcase_cache[l].result);
208 #endif
209                     memcpy(buf, adaptcase_cache[l].result, k);
210                     buf[k] = '/';
211                     current_cache=adaptcase_cache[l].raw_cache;
212                     m = (size_t *) bsearch(pathname + k + 1,
213 					   adaptcase_cache[l].cache_index,
214 					   adaptcase_cache[l].n,
215 					   sizeof(size_t),
216 					   cache_find_cmp);
217                     if (m == 0)
218                     {
219 #ifdef TRACECACHE
220                         fprintf (ftrc, "Cache miss for file.\n");
221 #endif
222 
223                         /* file does not exist - convert to lower c. */
224                         for (n = k + 1; pathname[n-1]; n++)
225                         {
226                             buf[n] = tolower(pathname[n]);
227                         }
228                         memcpy(pathname, buf, n-1);
229 #ifdef TRACECACHE
230                         fprintf(ftrc, "Return: %s\n", pathname);
231                         fclose(ftrc);
232 #endif
233                         return;
234                     }
235                     else
236                     {
237 #ifdef TRACECACHE
238                         fprintf (ftrc, "Cache hit for file: %s\n",
239                                  adaptcase_cache[l].raw_cache+(*m));
240 #endif
241 
242                         /* file does exist = cache hit for the file */
243                         for (n = k + 1; pathname[n-1]; n++)
244                         {
245                             buf[n] =
246                                 adaptcase_cache[l].raw_cache[(*m) + n - k - 1];
247                         }
248                         assert(buf[n-1] == '\0');
249                         memcpy(pathname, buf, n-1);
250 #ifdef TRACECACHE
251                         fprintf(ftrc, "Return: %s\n", pathname);
252                         fclose(ftrc);
253 #endif
254                         return;
255                     }
256                 }
257             }
258             l = (l == 0) ? adaptcase_cachesize - 1 : l - 1;
259         } while (l != adaptcase_cache_position);
260 
261 #ifdef TRACECACHE
262         fprintf (ftrc, "Cache miss for directory.\n");
263 #endif
264 
265 
266         /* no hit for the directory */
267         addresult = 1;
268     }
269 
270 
271     while (pathname[i])
272     {
273         if (pathname[i] == '/')
274         {
275             buf[i] = pathname[i];
276             if (addresult && i == k)
277             {
278                 goto add_to_cache;
279             }
280 cache_failure:
281             i++;
282             buf[i]='\0';
283             dirp = opendir(buf);
284 #ifdef TRACECACHE
285             if (dirp == NULL)
286             {
287                 fprintf (ftrc, "Error opening directory %s\n", buf);
288             }
289 #endif
290         }
291         else
292         {
293             assert(i==0);
294             dirp = opendir("./");
295 #ifdef TRACECACHE
296             if (dirp == NULL)
297             {
298                 fprintf (ftrc, "Error opening directory ./\n");
299             }
300 #endif
301         }
302 
303         j = i;
304         for (; pathname[i] && pathname[i]!='/'; i++)
305             buf[i] = pathname[i];
306         buf[i] = '\0';
307         found = 0;
308 
309         if (dirp != NULL)
310         {
311             while ((dp = readdir(dirp)) != NULL)
312             {
313                 if (!strcasecmp(dp->d_name, buf + j))
314                 {
315                     /* file exists, take over it's name */
316 
317                     assert((size_t)(i - j) == DIRENTLEN(dp));
318                     memcpy(buf + j, dp->d_name, DIRENTLEN(dp) + 1);
319                     closedir(dirp);
320                     dirp = NULL;
321                     found = 1;
322                     break;
323                 }
324             }
325         }
326         if (!found)
327         {
328             /* file does not exist - so the rest is brand new and
329                should be converted to lower case */
330 
331             for (i = j; pathname[i]; i++)
332                 buf[i] = tolower(pathname[i]);
333             buf[i] = '\0';
334             if (dirp != NULL)
335             {
336                 closedir(dirp);
337             }
338             dirp = NULL;
339             break;
340         }
341     }
342     assert(strlen(pathname) == strlen(buf));
343 
344 add_to_cache:
345     while (addresult)
346     {
347         l = adaptcase_cache_position;
348         l = (l == adaptcase_cachesize - 1) ? 0 : l + 1;
349 
350         if (adaptcase_cache[l].query != NULL)
351         {
352             free(adaptcase_cache[l].query);
353             adaptcase_cache[l].query = NULL;
354         }
355         if (adaptcase_cache[l].result != NULL)
356         {
357             free(adaptcase_cache[l].result);
358             adaptcase_cache[l].result = NULL;
359         }
360         if (adaptcase_cache[l].raw_cache != NULL)
361         {
362             free(adaptcase_cache[l].raw_cache);
363             adaptcase_cache[l].raw_cache = NULL;
364         }
365         if ( (adaptcase_cache[l].query     = (char *) malloc(k + 1)) == NULL ||
366              (adaptcase_cache[l].result    = (char *) malloc(k + 1)) == NULL ||
367              (adaptcase_cache[l].raw_cache = (char *) malloc(rawmax = rawcache_stepsize)) == NULL ||
368              (adaptcase_cache[l].cache_index = (size_t *) malloc((nmax = cacheindex_stepsize) * sizeof(size_t))) == NULL )
369         {
370             goto cache_error;
371         }
372 
373         adaptcase_cache[l].n = 0;
374         raw_high = 0;
375 
376         c = buf[k]; buf[k] = '\0';
377         if ((dirp = opendir(buf)) == NULL)
378         {
379             buf[k] = c;
380             goto cache_error;
381         }
382         buf[k] = c;
383 
384         while ((dp = readdir(dirp)) != NULL)
385         {
386             if (raw_high + DIRENTLEN(dp) + 1 > rawmax)
387             {
388                 if ((adaptcase_cache[l].raw_cache =
389                      (char *) realloc(adaptcase_cache[l].raw_cache,
390                                       rawmax+=rawcache_stepsize)) == NULL)
391                 {
392                     goto cache_error;
393                 }
394             }
395 
396             if (adaptcase_cache[l].n == (size_t) nmax - 1)
397             {
398                 if ((adaptcase_cache[l].cache_index = (size_t *)
399                      realloc(adaptcase_cache[l].cache_index,
400                              (nmax+=cacheindex_stepsize) *
401                              sizeof(size_t))) == NULL)
402                 {
403                     goto cache_error;
404                 }
405             }
406 
407             memcpy (adaptcase_cache[l].raw_cache + raw_high,
408                     dp->d_name, DIRENTLEN(dp) + 1);
409             adaptcase_cache[l].cache_index[adaptcase_cache[l].n++] = raw_high;
410             raw_high += DIRENTLEN(dp) + 1;
411         }
412         closedir(dirp);
413         current_cache=adaptcase_cache[l].raw_cache;
414         qsort(adaptcase_cache[l].cache_index, adaptcase_cache[l].n,
415               sizeof(size_t), cache_sort_cmp);
416 
417         memcpy(adaptcase_cache[l].query, pathname, k);
418         adaptcase_cache[l].query[k] = '\0';
419         memcpy(adaptcase_cache[l].result, buf, k);
420         adaptcase_cache[l].result[k] = '\0';
421 
422         adaptcase_cache_position = l;
423 
424 #ifdef TRACECACHE
425         fprintf  (ftrc, "Sucessfully added cache entry.\n");
426 #endif
427         goto start_over;
428 
429     cache_error:
430         if (adaptcase_cache[l].query != NULL)
431         {
432             free(adaptcase_cache[l].query);
433             adaptcase_cache[l].query = NULL;
434         }
435         if (adaptcase_cache[l].result != NULL)
436         {
437             free(adaptcase_cache[l].result);
438             adaptcase_cache[l].result = NULL;
439         }
440         if (adaptcase_cache[l].raw_cache != NULL)
441         {
442             free(adaptcase_cache[l].raw_cache);
443             adaptcase_cache[l].raw_cache = NULL;
444         }
445         if (adaptcase_cache[l].cache_index != NULL)
446         {
447             free(adaptcase_cache[l].cache_index);
448             adaptcase_cache[l].cache_index = NULL;
449         }
450         if (dirp != NULL)
451         {
452             closedir(dirp);
453         }
454 #ifdef TRACECACHE
455         fprintf  (ftrc, "Error in building cache entry.\n");
456 #endif
457         addresult = 0;
458         goto cache_failure;
459     }
460 
461 #ifdef TRACECACHE
462     fprintf(ftrc, "Return: %s\n", pathname);
463     fclose(ftrc);
464 #endif
465     strcpy(pathname, buf);
466     return;
467 }
468 #endif
469 
470 
471 // ====================================================================
472 // This is the main routine of this module ... findfile
473 // It finds files that match patterns. By using private_adaptcase,
474 // it works fully case insensitive even on Unix.
475 // ====================================================================
476 
findfile(const CString & mask)477 CArray<CString>* findfile(const CString& mask)
478 {
479   size_t index;
480   CString strDir,strMask;
481                                 // find the corresponding directory name
482   for (index=mask.Length();index>0;index--)
483     {
484         if (mask.charAt(index-1)=='\\' ||
485             mask.charAt(index-1)=='/'  ||
486             mask.charAt(index-1)==':')
487             break;
488     }
489 
490   if (!index)                   // no directory information
491     strDir=".";
492   else
493     {
494       strDir=mask.substr(0,index-1);
495       if (strDir.charAt(index-1)==':')
496         strDir+=".";
497       else
498         if (index>=2)
499           strDir=mask.substr(0,index-2);
500         else
501           strDir="";
502     }
503   if (index<mask.Length())
504     strMask=mask.substr(index,mask.Length()-1);
505   else
506     strMask="*";
507 
508   struct dirent* dirent;
509   CArray<CString> *dirs;
510 
511   /*  if (strDir.Length()>2 ||
512       (strDir.Length() == 2 && strDir.charAt(1) != ':') ||
513       (strDir.Length() == 1 && strDir.charAt(0) != '.'))
514     {
515       // if we have a non-trivial directory name - SEARCH IT!
516       // this is slow, but the only way to get around case sensitivity
517       // problems on unix boxes that mount dos ressources ...
518 
519       dirs = findfile(strDir);
520     }
521   else */
522     {
523       dirs = new CArray<CString>;
524 #ifdef UNIXLIKE
525       private_adaptcase((char*)strDir);
526 #endif
527       dirs->Add(strDir);
528     }
529 
530   if (dirs == NULL)
531     return NULL;
532 
533   CArray<CString> *pArray=new CArray<CString>;
534 
535   for (unsigned long ndir = 0; ndir < dirs->Size(); ndir++)
536     {
537       DIR *hDir;
538       if (((*dirs)[ndir].Length() == 2) && ((*dirs)[ndir].charAt(1) == ':'))
539         {
540           CString s = ((*dirs)[ndir]);
541           s+=DEFDIRSEP;
542           hDir=opendir(s);
543         }
544       else if ((*dirs)[ndir].Length())
545         hDir=opendir((*dirs)[ndir]);
546       else
547         {
548           CString s;
549           s+=DEFDIRSEP;
550           hDir=opendir(s);
551         }
552 
553       if (hDir==NULL)
554         continue;
555 
556       while ((dirent=readdir(hDir))!=NULL)
557         {
558 	  if (patmat(dirent->d_name, strMask))
559 	    //          if (!fnmatch(strMask,dirent->d_name,FNM_FLAGS))
560             {
561               CString s((*dirs)[ndir]);
562               s+=DEFDIRSEP;
563               s+=dirent->d_name;
564               pArray->Add(s);
565             }
566         }
567       closedir(hDir);
568     }
569   delete dirs;
570   return pArray;
571 }
572 
573 
574 
575 // ====================================================================
576 // adaptcase: Returns 1 if the file exists, and 0 if not. On Unix,
577 //            the string that the fn parameter points to will be ad-
578 //            justed so that it exactly matches the spelling of the
579 //            file that has been found.
580 // ====================================================================
581 
582 
adaptcase(char * fn)583 int adaptcase(char *fn)
584 {
585   CArray<CString> *files = findfile(fn);
586   unsigned long l = 0;
587   const char *cp;
588 
589   if (files == NULL || files->Size() == 0)
590     {
591       if (files) delete files;
592       return 0;
593     }
594 
595   if (files->Size()>1)
596     {
597       for (l = 0; l<files->Size(); l++)
598         {
599           if (!strcmp((*files)[l],fn))
600             {
601               break;
602             }
603         }
604       if (l==files->Size())
605         {
606           l = 0;
607         }
608     }
609 
610   cp = (const char *)((*files)[l]);
611   if (cp[0]=='.' && (cp[1] == '/' || cp[1] == '\\'))
612     {
613       if (fn[0] != '.')
614         {
615           cp += 2;
616         }
617     }
618 
619   CheckCond((strlen(cp) == strlen(fn)),
620             "adaptcase used with wildcards");
621   strcpy(fn, cp);
622   return 1;
623 }
624 
625 
626 
627 
628