1 /*
2 * DIRUTE.C
3 *
4 * Written on 30-Jul-90 by jim nutt and released to the public domain.
5 *
6 */
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include <huskylib/huskylib.h>
17
18 #define __DIRUTE_C
19
20 #if defined(__WATCOMC__) && defined(WINNT)
21 #include <wtypes.h>
22 #endif
23
24 #include "dirute.h"
25 #include "strextra.h"
26 #include "memextra.h"
27
28
29 #if defined(OS216)
30 #include <time.h>
31 #include <dos.h>
32 #include <io.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #define INCL_DOSPROCESS
38 #include <os2.h>
39
40 union
41 {
42 FDATE a;
43 unsigned int b;
44 }
45 dc;
46
47 union
48 {
49 FTIME a;
50 unsigned int b;
51 }
52 tc;
53
54 static struct _FILEFINDBUF InfoBuf;
55
56 HDIR hDir;
57 USHORT cSearch;
58 USHORT usAttrib;
59
60 #define FILENAMELEN 255
61
dir_findfirst(char * filename,int attribute,struct _dta * dta)62 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
63 {
64 hDir = 0x0001;
65 usAttrib = attribute;
66 cSearch = 1;
67
68 if (DosFindFirst2(filename, &hDir, usAttrib, &InfoBuf, (USHORT) (sizeof(InfoBuf) * cSearch), &cSearch, FIL_STANDARD, (ULONG) NULL) != 0)
69 {
70 DosFindClose(hDir);
71 errno = ENOENT;
72 return -1;
73 }
74 else
75 {
76 dta->attrib = (char)InfoBuf.attrFile;
77 dta->size = InfoBuf.cbFile;
78 dc.a = InfoBuf.fdateLastWrite;
79 tc.a = InfoBuf.ftimeLastWrite;
80 dta->wr_time = tc.b;
81 dta->wr_date = dc.b;
82 strcpy(dta->name, InfoBuf.achName);
83 errno = 0;
84 return 0;
85 }
86 }
87
dir_findnext(struct _dta * dta)88 int dir_findnext(struct _dta *dta)
89 {
90 if (DosFindNext(hDir, &InfoBuf, (USHORT) (FILENAMELEN + 23), &cSearch) || cSearch != 1)
91 {
92 DosFindClose(hDir);
93 errno = ENOENT;
94 return -1;
95 }
96 else
97 {
98 dta->attrib = (char)InfoBuf.attrFile;
99 dta->size = InfoBuf.cbFile;
100 dc.a = InfoBuf.fdateLastWrite;
101 tc.a = InfoBuf.ftimeLastWrite;
102 dta->wr_time = tc.b;
103 dta->wr_date = dc.b;
104 strcpy(dta->name, InfoBuf.achName);
105 errno = 0;
106 return 0;
107 }
108 }
109
110 #error The drive letter routines are not yet implemented for this platform.
111 #error You might want to copypaste them from the 32-bit OS/2 section.
112
113 #elif defined(OS2)
114 #define INCL_DOSPROCESS
115 #include <os2.h>
116
117 union
118 {
119 FDATE a;
120 unsigned int b;
121 }
122 dc;
123
124 union
125 {
126 FTIME a;
127 unsigned int b;
128 }
129 tc;
130
131 static FILEFINDBUF3 InfoBuf;
132
133 HDIR hDir;
134 ULONG cSearch;
135 ULONG usAttrib;
136
137 #define FILENAMELEN 255
138
dir_findfirst(char * filename,int attribute,struct _dta * dta)139 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
140 {
141 hDir = 0x0001;
142 usAttrib = attribute;
143 cSearch = 1;
144
145 if (DosFindFirst((unsigned char *)filename, &hDir, usAttrib, &InfoBuf,
146 sizeof InfoBuf, &cSearch, FIL_STANDARD) != 0)
147 {
148 DosFindClose(hDir);
149 errno = DIRUTE_NONE;
150 return -1;
151 }
152 else
153 {
154 dta->attrib = (char)InfoBuf.attrFile;
155 dta->size = InfoBuf.cbFile;
156 dc.a = InfoBuf.fdateLastWrite;
157 tc.a = InfoBuf.ftimeLastWrite;
158 dta->wr_time = tc.b;
159 dta->wr_date = dc.b;
160 strcpy(dta->name, InfoBuf.achName);
161 errno = 0;
162 return 0;
163 }
164 }
165
dir_findnext(struct _dta * dta)166 int dir_findnext(struct _dta *dta)
167 {
168 if (DosFindNext(hDir, &InfoBuf, (USHORT) (FILENAMELEN + 23), &cSearch) || cSearch != 1)
169 {
170 DosFindClose(hDir);
171 errno = DIRUTE_NONE;
172 return -1;
173 }
174 else
175 {
176 dta->attrib = (char)InfoBuf.attrFile;
177 dta->size = InfoBuf.cbFile;
178 dc.a = InfoBuf.fdateLastWrite;
179 tc.a = InfoBuf.ftimeLastWrite;
180 dta->wr_time = tc.b;
181 dta->wr_date = dc.b;
182 strcpy(dta->name, InfoBuf.achName);
183 errno = 0;
184 return 0;
185 }
186 }
187
188 /* drive letter routines for OS/2 32 Bit */
189
190 const int drive_letters = 1;
191
dir_setdrive(int d)192 void dir_setdrive(int d)
193 {
194 DosSetDefaultDisk((ULONG)d + 1UL);
195 }
dir_getdrive(void)196 int dir_getdrive(void)
197 {
198 unsigned long drivenr;
199 unsigned long logmap;
200
201 DosQueryCurrentDisk((PULONG)(&drivenr), (PULONG)(&logmap));
202
203 return drivenr - 1;
204 }
dir_getdrivelist(void)205 char *dir_getdrivelist(void)
206 {
207 unsigned long drivenr;
208 unsigned long logmap;
209 char *str = xmalloc(27);
210 int i , j;
211 unsigned long comp = 1;
212
213 DosQueryCurrentDisk((PULONG)(&drivenr), (PULONG)(&logmap));
214
215 for (i = 0, j = 0; i < 26; i++, comp = comp * 2UL)
216 {
217 if (logmap & comp)
218 {
219 str[j++] = (char)('A' + i);
220 }
221 }
222 str[j] = '\0';
223 return str;
224 }
225
226
227
228 #elif defined(__RSXNT__) || defined(__CYGWIN__) || defined (__MINGW32__) || (defined(_MSC_VER) && (_MSC_VER >= 1200)) || (defined (__WATCOMC__) && defined(__NT__))
229 #define WIN32_LEAN_AND_MEAN
230 #define NOGDI
231 #define NOUSER
232 #include <windows.h>
233
234 static HANDLE hDirA = INVALID_HANDLE_VALUE;
235 static WIN32_FIND_DATA InfoBuf;
236 static DWORD dwFileAttributes;
237
238 static int dir_find_common(struct _dta *dta);
239
dir_findfirst(char * filename,int attribute,struct _dta * dta)240 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
241 {
242 if (hDirA != INVALID_HANDLE_VALUE)
243 {
244 FindClose(hDirA);
245 }
246
247 dwFileAttributes = attribute;
248
249 hDirA = FindFirstFile(filename, &InfoBuf);
250 return dir_find_common(dta);
251 }
252
dir_findnext(struct _dta * dta)253 int dir_findnext(struct _dta *dta)
254 {
255 if (!FindNextFile(hDirA, &InfoBuf))
256 {
257 if (hDirA != INVALID_HANDLE_VALUE)
258 {
259 FindClose(hDirA);
260 hDirA = INVALID_HANDLE_VALUE;
261 }
262 }
263 return dir_find_common(dta);
264 }
265
dir_find_common(struct _dta * dta)266 static int dir_find_common(struct _dta *dta)
267 {
268 while (hDirA != INVALID_HANDLE_VALUE)
269 {
270 if (!(InfoBuf.dwFileAttributes &
271 (~(dwFileAttributes | DIR_ARCHVD))))
272 {
273 if (strlen(InfoBuf.cFileName) < sizeof(dta->name))
274 {
275 break;
276 }
277 }
278 if (!FindNextFile(hDirA, &InfoBuf))
279 {
280 if (hDirA != INVALID_HANDLE_VALUE)
281 {
282 FindClose(hDirA);
283 hDirA = INVALID_HANDLE_VALUE;
284 }
285 }
286 }
287 if (hDirA != INVALID_HANDLE_VALUE)
288 {
289 dta->attrib = (unsigned char)(InfoBuf.dwFileAttributes);
290 dta->size = (long)(InfoBuf.nFileSizeLow);
291 strcpy(dta->name, InfoBuf.cFileName);
292 errno = 0;
293 return 0;
294 }
295 else
296 {
297 errno = DIRUTE_NONE;
298 return -1;
299 }
300 }
301
302 /* drive letter routines for RSX compiler on NT 32 Bit */
303
304 const int drive_letters = 1;
305
dir_setdrive(int d)306 void dir_setdrive(int d)
307 {
308 char buf[3];
309 buf[0] = d + 'A';
310 buf[1] = ':';
311 buf[2] = '\0';
312 SetCurrentDirectory(buf);
313 }
dir_getdrive(void)314 int dir_getdrive(void)
315 {
316 char buf[FILENAME_MAX + 1];
317
318 #if defined (__WATCOMC__) || defined(__CYGWIN__) || defined (__MINGW32__) || (defined(_MSC_VER) && (_MSC_VER >= 1200))
319 GetCurrentDirectory(FILENAME_MAX, buf);
320 #else
321 GetCurrentDirectory(buf, FILENAME_MAX);
322 #endif
323 return (toupper(buf[0]) - 'A');
324 }
dir_getdrivelist(void)325 char *dir_getdrivelist(void)
326 {
327 unsigned long logmap;
328 char *str = xmalloc(27);
329 int i , j;
330 unsigned long comp = 1;
331
332 logmap = GetLogicalDrives();
333
334 for (i = 0, j = 0; i < 26; i++, comp = comp * 2UL)
335 {
336 if (logmap & comp)
337 {
338 str[j++] = 'A' + i;
339 }
340 }
341 str[j] = '\0';
342 return str;
343 }
344
345
346 #elif defined(__TURBOC__)
347
348 #include <dos.h>
349 #include <dir.h>
350
351 static struct ffblk ffblk;
352
dir_findfirst(char * filename,int attribute,struct _dta * dta)353 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
354 {
355 int done;
356
357 done = findfirst(filename, &ffblk, attribute);
358
359 if (!done)
360 {
361 strcpy(dta->name, ffblk.ff_name);
362 dta->wr_time = ffblk.ff_fdate;
363 dta->wr_date = ffblk.ff_ftime;
364 dta->size = ffblk.ff_fsize;
365 dta->attrib = ffblk.ff_attrib;
366 return 0;
367 }
368 return -1;
369 }
370
dir_findnext(struct _dta * dta)371 int dir_findnext(struct _dta *dta)
372 {
373 if (!findnext(&ffblk))
374 {
375 strcpy(dta->name, ffblk.ff_name);
376 dta->wr_time = ffblk.ff_fdate;
377 dta->wr_date = ffblk.ff_ftime;
378 dta->size = ffblk.ff_fsize;
379 dta->attrib = ffblk.ff_attrib;
380 return 0;
381 }
382 return -1;
383 }
384
385 /* drive letter routines for Borland C */
386
387 const int drive_letters = 1;
388
dir_setdrive(int d)389 void dir_setdrive(int d)
390 {
391 setdisk(d);
392 }
dir_getdrive(void)393 int dir_getdrive(void)
394 {
395 return getdisk();
396 }
397 #if defined(WINNT) || defined(__NT__)
398 #define NOUSER
399 #include <windows.h>
dir_getdrivelist(void)400 char *dir_getdrivelist(void)
401 {
402 unsigned long logmap;
403 char *str = xmalloc(27);
404 int i , j;
405 unsigned long comp = 1;
406
407 logmap = GetLogicalDrives();
408
409 for (i = 0, j = 0; i < 26; i++, comp = comp * 2UL)
410 {
411 if (logmap & comp)
412 {
413 str[j++] = 'A' + i;
414 }
415 }
416 str[j] = '\0';
417 return str;
418 }
419 #else
dir_getdrivelist(void)420 char *dir_getdrivelist(void)
421 {
422 int ct = 0, curd, i;
423 char *buf = xmalloc(27);
424
425 curd = getdisk();
426
427 for (i = 0; i < 26; i++)
428 {
429 setdisk(i);
430 if (i == getdisk())
431 {
432 buf[ct++] = i + 'A';
433 }
434 }
435 buf[ct] = '\0';
436 setdisk(curd);
437
438 return buf;
439 }
440 #endif
441
442 #elif defined(PACIFIC)
443
444 #include "rfind1st.h"
445
446 static struct DSTRUCT dstr;
447
dir_findfirst(char * filename,int attribute,struct _dta * dta)448 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
449 {
450 if (rfind_1st(filename, attribute, &dstr) != NULL)
451 {
452 strcpy(dta->name, dstr.NAME);
453 dta->wr_time = dstr.DATE;
454 dta->wr_date = dstr.TIME;
455 dta->size = dstr.FSIZE;
456 dta->attrib = dstr.ATTRIBUTE;
457 return 0;
458 }
459 return -1;
460 }
461
dir_findnext(struct _dta * dta)462 int dir_findnext(struct _dta *dta)
463 {
464 if (rfind_nxt(&dstr) != NULL)
465 {
466 strcpy(dta->name, dstr.NAME);
467 dta->wr_time = dstr.DATE;
468 dta->wr_date = dstr.TIME;
469 dta->size = dstr.FSIZE;
470 dta->attrib = dstr.ATTRIBUTE;
471 return 0;
472 }
473 return -1;
474 }
475
476 #error You must implement the drive letter routines for this platform first!
477
478 #elif defined(SASC)
479 #include <dos.h>
480
481 extern int __msflag;
482 static struct FileInfoBlock info;
483 static int error;
484 static int oldmsf;
485
dir_findfirst(char * filename,int attribute,struct _dta * dta)486 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
487 {
488 oldmsf = __msflag;
489 __msflag = 1;
490 error = dfind(&info, filename, 0);
491 __msflag = oldmsf;
492 while (error == 0)
493 {
494 strcpy(dta->name, info.fib_FileName);
495 return 0;
496 }
497 return -1;
498 }
499
dir_findnext(struct _dta * dta)500 int dir_findnext(struct _dta *dta)
501 {
502 oldmsf = __msflag;
503 __msflag = 1;
504 error = dnext(&info);
505 __msflag = oldmsf;
506 if (error == 0)
507 {
508 strcpy(dta->name, info.fib_FileName);
509 return 0;
510 }
511 return -1;
512 }
513
514 #error You must implement the drive letter routines for this platform first!
515
516 #elif defined(UNIX)
517
518 /*
519 * Support for UNIX goes here - use the POSIX.1 routines:
520 * opendir, scandir, readdir, etc.
521 */
522
523 #include <unistd.h>
524 #include <dirent.h>
525 #include <sys/types.h>
526 #include <sys/stat.h>
527 #include <ctype.h>
528
529 #if (defined(__unix__) || defined(unix)) && !defined(USG)
530 #include <sys/param.h> /* used to differentiate BSD from SYSV */
531 #endif
532
533
534 static DIR *dir;
535 static struct dirent *de;
536 static int ff_attribute;
537 static char firstbit[FILENAME_MAX + 1];
538 static char lastbit[FILENAME_MAX + 1];
539 static char fullname[FILENAME_MAX + 1];
540
match(const char * name,const char * pattern,int attribute,int mode,int rdonly)541 static int match(const char *name, const char *pattern, int attribute,
542 int mode, int rdonly)
543 {
544 char *matpattern;
545 char *matname;
546 char *cp;
547 int rc;
548 if (!(attribute & DIR_NO_WILDCARDS))
549 {
550 matpattern = strdup(pattern);
551 matname = strdup(name);
552
553 if (matpattern == NULL || matname == NULL)
554 {
555 return 0;
556 }
557
558 if (attribute & DIR_ICASE)
559 {
560 for (cp=matpattern; *cp; cp++)
561 {
562 *cp = toupper(*cp);
563 }
564 for (cp=matname; *cp; cp++)
565 {
566 *cp = toupper(*cp);
567 }
568 }
569
570 rc = patmat(matname, matpattern);
571
572 free(matname);
573 free(matpattern);
574 }
575 else
576 {
577 rc = !stricmp(pattern, name);
578 }
579
580 if (rc)
581 {
582 /* the name matches, now check the other criteria */
583
584 if (!(attribute & DIR_READON)) /* read only files not allowed */
585 {
586 if ((!S_ISDIR(mode)) && (rdonly))
587 {
588 return 0;
589 }
590 }
591
592 if (!(attribute & DIR_DIRECT)) /* directories not allowed */
593 {
594 if (S_ISDIR(mode))
595 {
596 return 0;
597 }
598 }
599
600 return 1;
601 }
602
603 return 0;
604
605 }
606
607
dir_findfirst(char * filename,int attribute,struct _dta * dta)608 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
609 {
610 char *p;
611 int fin = 0;
612 struct stat sb;
613
614 p = strrchr(filename, '/');
615 if (p == NULL)
616 {
617 strcpy(firstbit, ".");
618 strcpy(lastbit, filename);
619 }
620 else
621 {
622 memcpy(firstbit, filename, p - filename);
623 firstbit[p - filename] = '\0';
624 strcpy(lastbit, p + 1);
625 }
626 if (!*firstbit)
627 {
628 dir = opendir("/");
629 }
630 else
631 {
632 dir = opendir(firstbit);
633 }
634 if (dir == NULL)
635 {
636 return -1;
637 }
638 while (!fin)
639 {
640 de = readdir(dir);
641 if (de == NULL)
642 {
643 closedir(dir);
644 dir = NULL;
645 return -1;
646 }
647
648 strcpy(fullname, firstbit);
649 strcat(fullname, "/");
650 strcat(fullname, de->d_name);
651
652 if (stat(fullname, &sb))
653 {
654 closedir(dir);
655 dir = NULL;
656 return -1;
657 }
658
659 if (match(de->d_name, lastbit,
660 attribute, sb.st_mode, access(fullname, W_OK)))
661 {
662 fin = 1;
663 }
664 }
665 strcpy(dta->name, de->d_name);
666 if (S_ISDIR(sb.st_mode))
667 {
668 dta->attrib = DIR_DIRECT;
669 }
670 else if (access(fullname, W_OK))
671 {
672 dta->attrib = DIR_READON;
673 }
674 else
675 {
676 dta->attrib = DIR_NORMAL;
677 }
678 dta->size = sb.st_size;
679 ff_attribute = attribute;
680 return 0;
681 }
682
dir_findnext(struct _dta * dta)683 int dir_findnext(struct _dta *dta)
684 {
685 int fin = 0;
686 struct stat sb;
687
688 while (!fin)
689 {
690 de = readdir(dir);
691 if (de == NULL)
692 {
693 closedir(dir);
694 dir = NULL;
695 return -1;
696 }
697 strcpy(fullname, firstbit);
698 strcat(fullname, "/");
699 strcat(fullname, de->d_name);
700
701 if (stat(fullname, &sb))
702 {
703 closedir(dir);
704 dir = NULL;
705 return -1;
706 }
707
708 if (match(de->d_name, lastbit, ff_attribute,
709 sb.st_mode, access(fullname, W_OK)))
710 {
711 fin = 1;
712 }
713 }
714 strcpy(dta->name, de->d_name);
715 if (S_ISDIR(sb.st_mode))
716 {
717 dta->attrib = DIR_DIRECT;
718 }
719 else if (access(fullname, W_OK))
720 {
721 dta->attrib = DIR_READON;
722 }
723 else
724 {
725 dta->attrib = DIR_NORMAL;
726 }
727 dta->size = sb.st_size;
728 return 0;
729 }
730
dir_findclose(struct _dta * dta)731 void dir_findclose(struct _dta *dta)
732 {
733 if (dir != NULL)
734 {
735 closedir(dir);
736 dir = NULL;
737 }
738 }
739
740 /* UNIX does not have drive letters */
741
742 const int drive_letters = 0;
743
dir_setdrive(int d)744 void dir_setdrive(int d)
745 {
746 }
dir_getdrive(void)747 int dir_getdrive(void)
748 {
749 return 2;
750 }
dir_getdrivelist(void)751 char *dir_getdrivelist(void)
752 {
753 return xstrdup("C");
754 }
755
756
757
758 #else /* MSC version of these routines */
759
760 #include <dos.h>
761
762 struct find_t ffblk;
763
dir_findfirst(char * filename,int attribute,struct _dta * dta)764 int dir_findfirst(char *filename, int attribute, struct _dta *dta)
765 {
766 int done;
767
768 done = _dos_findfirst(filename, attribute, &ffblk);
769
770 if (!done)
771 {
772 strcpy(dta->name, ffblk.name);
773 dta->wr_time = ffblk.wr_date;
774 dta->wr_date = ffblk.wr_time;
775 dta->size = ffblk.size;
776 dta->attrib = ffblk.attrib;
777 return 0;
778 }
779 return -1;
780 }
781
dir_findnext(struct _dta * dta)782 int dir_findnext(struct _dta *dta)
783 {
784 if (!_dos_findnext(&ffblk))
785 {
786 strcpy(dta->name, ffblk.name);
787 dta->wr_time = ffblk.wr_date;
788 dta->wr_date = ffblk.wr_time;
789 dta->size = ffblk.size;
790 dta->attrib = ffblk.attrib;
791 return 0;
792 }
793 return -1;
794 }
795
796 /* Drive letter routines for Microsoft C */
797 /* I have no idea if these ones work. I copied them from Borland. */
798
799 const int drive_letters = 1;
800
dir_setdrive(int d)801 void dir_setdrive(int d)
802 {
803 int e = d;
804 _dos_setdrive(d, &e);
805 }
dir_getdrive(void)806 int dir_getdrive(void)
807 {
808 int d;
809 _dos_getdrive(&d);
810 return d;
811 }
812 #if defined(WINNT) || defined(__NT__)
813 #define NOUSER
814 #include <windows.h>
dir_getdrivelist(void)815 char *dir_getdrivelist(void)
816 {
817 ungsigned long logmap;
818 char *str = xmalloc(27);
819 int i , j;
820 unsigned long comp = 1;
821
822 logmap = GetLogicalDrives();
823
824 for (i = 0, j = 0; i < 26; i++, comp = comp * 2UL)
825 {
826 if (logmap & comp)
827 {
828 str[j++] = 'A' + i;
829 }
830 }
831 str[j] = '\0';
832 return str;
833 }
834 #else
dir_getdrivelist(void)835 char *dir_getdrivelist(void)
836 {
837 int ct = 0, curd, i;
838 char *buf = xmalloc(27);
839
840 curd = dir_getdrive();
841
842 for (i = 0; i < 26; i++)
843 {
844 dir_setdrive(i);
845 if (i == dir_getdrive())
846 {
847 buf[ct++] = i + 'A';
848 }
849 }
850 buf[ct] = '\0';
851 dir_setdrive(curd);
852
853 return buf;
854 }
855 #endif
856
857 #endif
858
859
860
861 #ifdef UNIX
862
863 /* The adaptcase routine behaves as follows: It assumes that pathname
864 is a path name which may contain multiple dashes, and it assumes
865 that you run on a case sensitive file system but want / must to
866 match the path name insensitively. adaptcase takes every path
867 element out of pathname and uses findfirst to check if it
868 exists. If it exists, the path element is replaced by the exact
869 spelling as used by the file system. If it does not exist, it is
870 converted to lowercase. This allows you to make you program deal
871 with things like mounts of DOS file systems under unix
872
873 Return value is 1 if the file exists and 0 if not.
874
875 Attention: Do not ever try to understand this code. I had to do
876 heavy caching and other optimizations in this routine in order to
877 reduce that startup time of msged to a reasonable value. (The
878 problem is that opendir / readdir is very slow ...). If you ever
879 have to fix something in this routine, you'd better rewrite it from
880 scratch.
881 */
882
883 /* the cache will take about 30 * 4192 + 30 * 512 * 4 bytes in this
884 configuration, i.e. 180K */
885
886 #define adaptcase_cachesize 30
887 #define rawcache_stepsize 4192
888 #define cacheindex_stepsize 512
889
890 struct adaptcase_cache_entry
891 {
892 char *query;
893 char *result;
894 char *raw_cache;
895 size_t *cache_index;
896 size_t n;
897 };
898 static int adaptcase_cache_position = -1;
899 static struct adaptcase_cache_entry adaptcase_cache[adaptcase_cachesize];
900
901 static char *current_cache;
cache_sort_cmp(const void * a,const void * b)902 static int cache_sort_cmp(const void *a, const void *b)
903 {
904 return stricmp(current_cache+(*((const size_t *)a)),
905 current_cache+(*((const size_t *)b)));
906 }
907
cache_find_cmp(const void * a,const void * b)908 static int cache_find_cmp(const void *a, const void *b)
909 {
910 return stricmp((const char *)a, current_cache+(*((const size_t *)b)));
911 }
912
913 /* #define TRACECACHE */
914
915 #ifdef BSD
916 #define DIRENTLEN(x) ((x)->d_namlen)
917 #else
918 #define DIRENTLEN(x) (strlen((x)->d_name))
919 #endif
920
adaptcase(char * pathname)921 void adaptcase(char *pathname)
922 {
923 int i,j,k,l,n,nmax, found=1, addresult=0;
924 size_t *m; size_t raw_high, rawmax;
925 char buf[FILENAME_MAX + 1];
926 DIR *dirp = NULL;
927 struct dirent *dp;
928 char c;
929
930 #ifdef TRACECACHE
931 FILE *ftrc;
932 #endif
933
934 if (!*pathname)
935 return;
936 #ifdef TRACECACHE
937 ftrc = fopen ("trace.log", "a");
938 fprintf(ftrc, "--Query: %s\n", pathname);
939 #endif
940
941 if (adaptcase_cache_position == -1)
942 {
943 /* initialise the cache */
944 memset(adaptcase_cache, 0, adaptcase_cachesize *
945 sizeof(struct adaptcase_cache_entry));
946 adaptcase_cache_position = 0;
947 }
948
949 k = strlen(pathname);
950 if (k > 2)
951 {
952 for (k = k - 2; k>0 && pathname[k] != '/'; k--);
953 }
954 else
955 {
956 k = 0;
957 }
958
959 j = 0; i = 0;
960
961
962 start_over:
963
964 if (k != 0)
965 {
966 l = adaptcase_cache_position;
967 do
968 {
969 if (adaptcase_cache[l].query != NULL)
970 {
971 if ((!memcmp(adaptcase_cache[l].query,pathname,k)) &&
972 (adaptcase_cache[l].query[k] == '\0'))
973 {
974 /* cache hit for the directory */
975 #ifdef TRACECACHE
976 fprintf (ftrc, "Cache hit for Dir: %s\n",
977 adaptcase_cache[l].result);
978 #endif
979 memcpy(buf, adaptcase_cache[l].result, k);
980 buf[k] = '/';
981 current_cache=adaptcase_cache[l].raw_cache;
982 m = bsearch(pathname + k + 1,
983 adaptcase_cache[l].cache_index,
984 adaptcase_cache[l].n,
985 sizeof(size_t),
986 cache_find_cmp);
987 if (m == 0)
988 {
989 #ifdef TRACECACHE
990 fprintf (ftrc, "Cache miss for file.\n");
991 #endif
992
993 /* file does not exist - convert to lower c. */
994 for (n = k + 1; pathname[n-1]; n++)
995 {
996 buf[n] = tolower(pathname[n]);
997 }
998 memcpy(pathname, buf, n-1);
999 #ifdef TRACECACHE
1000 fprintf(ftrc, "Return: %s\n", pathname);
1001 fclose(ftrc);
1002 #endif
1003 return;
1004 }
1005 else
1006 {
1007 #ifdef TRACECACHE
1008 fprintf (ftrc, "Cache hit for file: %s\n",
1009 adaptcase_cache[l].raw_cache+(*m));
1010 #endif
1011
1012 /* file does exist = cache hit for the file */
1013 for (n = k + 1; pathname[n-1]; n++)
1014 {
1015 buf[n] =
1016 adaptcase_cache[l].raw_cache[(*m) + n - k - 1];
1017 }
1018 assert(buf[n-1] == '\0');
1019 memcpy(pathname, buf, n-1);
1020 #ifdef TRACECACHE
1021 fprintf(ftrc, "Return: %s\n", pathname);
1022 fclose(ftrc);
1023 #endif
1024 return;
1025 }
1026 }
1027 }
1028 l = (l == 0) ? adaptcase_cachesize - 1 : l - 1;
1029 } while (l != adaptcase_cache_position);
1030
1031 #ifdef TRACECACHE
1032 fprintf (ftrc, "Cache miss for directory.\n");
1033 #endif
1034
1035
1036 /* no hit for the directory */
1037 addresult = 1;
1038 }
1039
1040
1041 while (pathname[i])
1042 {
1043 if (pathname[i] == '/')
1044 {
1045 buf[i] = pathname[i];
1046 if (addresult && i == k)
1047 {
1048 goto add_to_cache;
1049 }
1050 cache_failure:
1051 i++;
1052 buf[i]='\0';
1053 dirp = opendir(buf);
1054 #ifdef TRACECACHE
1055 if (dirp == NULL)
1056 {
1057 fprintf (ftrc, "Error opening directory %s\n", buf);
1058 }
1059 #endif
1060 }
1061 else
1062 {
1063 assert(i==0);
1064 dirp = opendir("./");
1065 #ifdef TRACECACHE
1066 if (dirp == NULL)
1067 {
1068 fprintf (ftrc, "Error opening directory ./\n");
1069 }
1070 #endif
1071 }
1072
1073 j = i;
1074 for (; pathname[i] && pathname[i]!='/'; i++)
1075 buf[i] = pathname[i];
1076 buf[i] = '\0';
1077 found = 0;
1078
1079 if (dirp != NULL)
1080 {
1081 while ((dp = readdir(dirp)) != NULL)
1082 {
1083 if (!strcasecmp(dp->d_name, buf + j))
1084 {
1085 /* file exists, take over it's name */
1086
1087 assert(i - j == DIRENTLEN(dp));
1088 memcpy(buf + j, dp->d_name, DIRENTLEN(dp) + 1);
1089 closedir(dirp);
1090 dirp = NULL;
1091 found = 1;
1092 break;
1093 }
1094 }
1095 }
1096 if (!found)
1097 {
1098 /* file does not exist - so the rest is brand new and
1099 should be converted to lower case */
1100
1101 for (i = j; pathname[i]; i++)
1102 buf[i] = tolower(pathname[i]);
1103 buf[i] = '\0';
1104 if (dirp != NULL)
1105 {
1106 closedir(dirp);
1107 }
1108 dirp = NULL;
1109 break;
1110 }
1111 }
1112 assert(strlen(pathname) == strlen(buf));
1113
1114 add_to_cache:
1115 while (addresult)
1116 {
1117 l = adaptcase_cache_position;
1118 l = (l == adaptcase_cachesize - 1) ? 0 : l + 1;
1119
1120 if (adaptcase_cache[l].query != NULL)
1121 {
1122 free(adaptcase_cache[l].query);
1123 adaptcase_cache[l].query = NULL;
1124 }
1125 if (adaptcase_cache[l].result != NULL)
1126 {
1127 free(adaptcase_cache[l].result);
1128 adaptcase_cache[l].result = NULL;
1129 }
1130 if (adaptcase_cache[l].raw_cache != NULL)
1131 {
1132 free(adaptcase_cache[l].raw_cache);
1133 adaptcase_cache[l].raw_cache = NULL;
1134 }
1135 if ( (adaptcase_cache[l].query = malloc(k + 1)) == NULL ||
1136 (adaptcase_cache[l].result = malloc(k + 1)) == NULL ||
1137 (adaptcase_cache[l].raw_cache = malloc(rawmax = rawcache_stepsize)) == NULL ||
1138 (adaptcase_cache[l].cache_index = malloc((nmax = cacheindex_stepsize) * sizeof(size_t))) == NULL )
1139 {
1140 goto cache_error;
1141 }
1142
1143 adaptcase_cache[l].n = 0;
1144 raw_high = 0;
1145
1146 c = buf[k]; buf[k] = '\0';
1147 if ((dirp = opendir(buf)) == NULL)
1148 {
1149 buf[k] = c;
1150 goto cache_error;
1151 }
1152 buf[k] = c;
1153
1154 while ((dp = readdir(dirp)) != NULL)
1155 {
1156 if (raw_high + DIRENTLEN(dp) + 1 > rawmax)
1157 {
1158 if ((adaptcase_cache[l].raw_cache =
1159 realloc(adaptcase_cache[l].raw_cache,
1160 rawmax+=rawcache_stepsize)) == NULL)
1161 {
1162 goto cache_error;
1163 }
1164 }
1165
1166 if (adaptcase_cache[l].n == nmax - 1)
1167 {
1168 if ((adaptcase_cache[l].cache_index =
1169 realloc(adaptcase_cache[l].cache_index,
1170 (nmax+=cacheindex_stepsize) *
1171 sizeof(size_t))) == NULL)
1172 {
1173 goto cache_error;
1174 }
1175 }
1176
1177 memcpy (adaptcase_cache[l].raw_cache + raw_high,
1178 dp->d_name, DIRENTLEN(dp) + 1);
1179 adaptcase_cache[l].cache_index[adaptcase_cache[l].n++] = raw_high;
1180 raw_high += DIRENTLEN(dp) + 1;
1181 }
1182 closedir(dirp);
1183 current_cache=adaptcase_cache[l].raw_cache;
1184 qsort(adaptcase_cache[l].cache_index, adaptcase_cache[l].n,
1185 sizeof(size_t), cache_sort_cmp);
1186
1187 memcpy(adaptcase_cache[l].query, pathname, k);
1188 adaptcase_cache[l].query[k] = '\0';
1189 memcpy(adaptcase_cache[l].result, buf, k);
1190 adaptcase_cache[l].result[k] = '\0';
1191
1192 adaptcase_cache_position = l;
1193
1194 #ifdef TRACECACHE
1195 fprintf (ftrc, "Sucessfully added cache entry.\n");
1196 #endif
1197 goto start_over;
1198
1199 cache_error:
1200 if (adaptcase_cache[l].query != NULL)
1201 {
1202 free(adaptcase_cache[l].query);
1203 adaptcase_cache[l].query = NULL;
1204 }
1205 if (adaptcase_cache[l].result != NULL)
1206 {
1207 free(adaptcase_cache[l].result);
1208 adaptcase_cache[l].result = NULL;
1209 }
1210 if (adaptcase_cache[l].raw_cache != NULL)
1211 {
1212 free(adaptcase_cache[l].raw_cache);
1213 adaptcase_cache[l].raw_cache = NULL;
1214 }
1215 if (adaptcase_cache[l].cache_index != NULL)
1216 {
1217 free(adaptcase_cache[l].cache_index);
1218 adaptcase_cache[l].cache_index = NULL;
1219 }
1220 if (dirp != NULL)
1221 {
1222 closedir(dirp);
1223 }
1224 #ifdef TRACECACHE
1225 fprintf (ftrc, "Error in building cache entry.\n");
1226 #endif
1227 addresult = 0;
1228 goto cache_failure;
1229 }
1230
1231 #ifdef TRACECACHE
1232 fprintf(ftrc, "Return: %s\n", pathname);
1233 fclose(ftrc);
1234 #endif
1235 strcpy(pathname, buf);
1236 return;
1237 }
1238 #endif
1239
1240 #if defined (TEST)
main(int argc,char ** argv)1241 int main(int argc, char **argv)
1242 {
1243 if (argc < 2)
1244 return 0;
1245
1246 adaptcase(argv[1]);
1247 printf ("%s\n", argv[1]);
1248
1249 return 0;
1250 }
1251
1252 #endif
1253
1254
1255