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