5aac90c56ef33edbdc08fb1da9febe3ed664e407
[xboard.git] / filebrowser / path.c
1 /*
2  * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Software Research Associates not be used
9  * in advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  Software Research Associates
11  * makes no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
16  * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
17  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
19  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Author: Erik M. van der Poel
23  *         Software Research Associates, Inc., Tokyo, Japan
24  *         erik@sra.co.jp
25  */
26
27 #include <stdio.h>
28 #include <stdlib.h> /* for qsort */
29 #include "../config.h"
30
31 #ifdef SEL_FILE_IGNORE_CASE
32 #include <ctype.h>
33 #endif /* def SEL_FILE_IGNORE_CASE */
34
35 #include <X11/Xos.h>
36 #include <pwd.h>
37 #include "selfile.h"
38 #include "xstat.h"
39 #include <X11/Xaw/Scrollbar.h>
40
41 #ifndef MAXPATHLEN
42 #define MAXPATHLEN 1024
43 #endif /* ndef MAXPATHLEN */
44
45 #ifdef HAS_DIRENT_H
46 extern uid_t getuid();
47 #endif /* def HAS_DIRENT_H */
48
49 /* added missing prototypes */
50 extern void SFtextChanged();
51 extern int SFgetDir(SFDir *);
52 extern void SFdrawLists(int);
53 extern void SFdrawList(int, int);
54 extern void SFclearList(int, int);
55 extern void SFmotionList(Widget, int, XMotionEvent*);
56
57 typedef struct {
58         char    *name;
59         char    *dir;
60 } SFLogin;
61
62 SFDir *SFdirs = NULL;
63
64 int SFdirEnd;
65
66 int SFdirPtr;
67
68 int SFbuttonPressed = 0;
69
70 static int SFdoNotTouchDirPtr = 0;
71
72 static int SFdoNotTouchVorigin = 0;
73
74 static SFDir SFrootDir, SFhomeDir;
75
76 static SFLogin *SFlogins;
77
78 static int SFtwiddle = 0;
79
80 int
81 SFchdir(path)
82         char    *path;
83 {
84         int     result;
85
86         result = 0;
87
88         if (strcmp(path, SFcurrentDir)) {
89                 result = chdir(path);
90                 if (!result) {
91                   (void) strncpy(SFcurrentDir, path, MAXPATHLEN);
92                 }
93         }
94
95         return result;
96 }
97
98 static void
99 SFfree(i)
100         int     i;
101 {
102         register SFDir  *dir;
103         register int    j;
104
105         dir = &(SFdirs[i]);
106
107         for (j = dir->nEntries - 1; j >= 0; j--) {
108                 if (dir->entries[j].shown != dir->entries[j].real) {
109                         XtFree(dir->entries[j].shown);
110                 }
111                 XtFree(dir->entries[j].real);
112         }
113
114         XtFree((char *) dir->entries);
115
116         XtFree(dir->dir);
117
118         dir->dir = NULL;
119         return;
120 }
121
122 static void
123 SFstrdup(s1, s2)
124         char    **s1;
125         char    *s2;
126 {
127         *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
128         return;
129 }
130
131 static void
132 SFunreadableDir(dir)
133         SFDir   *dir;
134 {
135         char    *cannotOpen = "<cannot open> ";
136
137         dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
138         dir->entries[0].statDone = 1;
139         SFstrdup(&dir->entries[0].real, cannotOpen);
140         dir->entries[0].shown = dir->entries[0].real;
141         dir->nEntries = 1;
142         dir->nChars = strlen(cannotOpen);
143         return;
144 }
145
146 #ifdef SEL_FILE_IGNORE_CASE
147 static
148 SFstrncmp(p, q, n)
149         register char   *p, *q;
150         register int    n;
151 {
152         register char   c1, c2;
153         char            *psave, *qsave;
154         int             nsave;
155
156         psave = p;
157         qsave = q;
158         nsave = n;
159
160         c1 = *p++;
161         if (islower(c1)) {
162                 c1 = toupper(c1);
163         }
164         c2 = *q++;
165         if (islower(c2)) {
166                 c2 = toupper(c2);
167         }
168
169         while ((--n >= 0) && (c1 == c2)) {
170                 if (!c1) {
171                         return strncmp(psave, qsave, nsave);
172                 }
173                 c1 = *p++;
174                 if (islower(c1)) {
175                         c1 = toupper(c1);
176                 }
177                 c2 = *q++;
178                 if (islower(c2)) {
179                         c2 = toupper(c2);
180                 }
181         }
182
183         if (n < 0) {
184                 return strncmp(psave, qsave, nsave);
185         }
186
187         return c1 - c2;
188 }
189 #endif /* def SEL_FILE_IGNORE_CASE */
190
191 void
192 SFsetText(path)
193         char    *path;
194 {
195         XawTextBlock    text;
196
197         text.firstPos = 0;
198         text.length = strlen(path);
199         text.ptr = path;
200         text.format = FMT8BIT;
201
202         XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
203         XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
204
205         return;
206 }
207
208 static void
209 SFreplaceText(dir, str)
210         SFDir   *dir;
211         char    *str;
212 {
213         int     len;
214
215         *(dir->path) = 0;
216         len = strlen(str);
217         if (str[len - 1] == '/') {
218                 (void) strcat(SFcurrentPath, str);
219         } else {
220                 (void) strncat(SFcurrentPath, str, len - 1);
221         }
222         if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
223                 SFsetText(SFcurrentPath);
224         } else {
225                 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
226         }
227
228         SFtextChanged();
229         return;
230 }
231
232 static void
233 SFexpand(str)
234         char    *str;
235 {
236         int     len;
237         int     cmp;
238         char    *name, *growing;
239         SFDir   *dir;
240         SFEntry *entry, *max;
241
242         len = strlen(str);
243
244         dir = &(SFdirs[SFdirEnd - 1]);
245
246         if (dir->beginSelection == -1) {
247                 SFstrdup(&str, str);
248                 SFreplaceText(dir, str);
249                 XtFree(str);
250                 return;
251         } else if (dir->beginSelection == dir->endSelection) {
252                 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
253                 return;
254         }
255
256         max = &(dir->entries[dir->endSelection + 1]);
257
258         name = dir->entries[dir->beginSelection].shown;
259         SFstrdup(&growing, name);
260
261         cmp = 0;
262         while (!cmp) {
263                 entry = &(dir->entries[dir->beginSelection]);
264                 while (entry < max) {
265                         if (cmp = strncmp(growing, entry->shown, len)) {
266                                 break;
267                         }
268                         entry++;
269                 }
270                 len++;
271         }
272
273         /*
274          * SFreplaceText() expects filename
275          */
276         growing[len - 2] = ' ';
277
278         growing[len - 1] = 0;
279         SFreplaceText(dir, growing);
280         XtFree(growing);
281 }
282
283 static int
284 SFfindFile(dir, str)
285         SFDir           *dir;
286         register char   *str;
287 {
288         register int    i, last, max;
289         register char   *name, save;
290         SFEntry         *entries;
291         int             len;
292         int             begin, end;
293         int             result;
294
295         len = strlen(str);
296
297         if (str[len - 1] == ' ') {
298                 SFexpand(str);
299                 return 1;
300         } else if (str[len - 1] == '/') {
301                 len--;
302         }
303
304         max = dir->nEntries;
305
306         entries = dir->entries;
307
308         i = 0;
309         while (i < max) {
310                 name = entries[i].shown;
311                 last = strlen(name) - 1;
312                 save = name[last];
313                 name[last] = 0;
314
315 #ifdef SEL_FILE_IGNORE_CASE
316                 result = SFstrncmp(str, name, len);
317 #else /* def SEL_FILE_IGNORE_CASE */
318                 result = strncmp(str, name, len);
319 #endif /* def SEL_FILE_IGNORE_CASE */
320
321                 name[last] = save;
322                 if (result <= 0) {
323                         break;
324                 }
325                 i++;
326         }
327         begin = i;
328         while (i < max) {
329                 name = entries[i].shown;
330                 last = strlen(name) - 1;
331                 save = name[last];
332                 name[last] = 0;
333
334 #ifdef SEL_FILE_IGNORE_CASE
335                 result = SFstrncmp(str, name, len);
336 #else /* def SEL_FILE_IGNORE_CASE */
337                 result = strncmp(str, name, len);
338 #endif /* def SEL_FILE_IGNORE_CASE */
339
340                 name[last] = save;
341                 if (result) {
342                         break;
343                 }
344                 i++;
345         }
346         end = i;
347
348         if (begin != end) {
349                 if (
350                         (dir->beginSelection != begin) ||
351                         (dir->endSelection != end - 1)
352                 ) {
353                         dir->changed = 1;
354                         dir->beginSelection = begin;
355                         if (str[strlen(str) - 1] == '/') {
356                                 dir->endSelection = begin;
357                         } else {
358                                 dir->endSelection = end - 1;
359                         }
360                 }
361         } else {
362                 if (dir->beginSelection != -1) {
363                         dir->changed = 1;
364                         dir->beginSelection = -1;
365                         dir->endSelection = -1;
366                 }
367         }
368
369         if (
370                 SFdoNotTouchVorigin ||
371                 ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
372         ) {
373                 SFdoNotTouchVorigin = 0;
374                 return 0;
375         }
376
377         i = begin - 1;
378         if (i > max - SFlistSize) {
379                 i = max - SFlistSize;
380         }
381         if (i < 0) {
382                 i = 0;
383         }
384
385         if (dir->vOrigin != i) {
386                 dir->vOrigin = i;
387                 dir->changed = 1;
388         }
389
390         return 0;
391 }
392
393 static void
394 SFunselect()
395 {
396         SFDir   *dir;
397
398         dir = &(SFdirs[SFdirEnd - 1]);
399         if (dir->beginSelection != -1) {
400                 dir->changed = 1;
401         }
402         dir->beginSelection = -1;
403         dir->endSelection = -1;
404         return;
405 }
406
407 static int
408 SFcompareLogins(p, q)
409         SFLogin *p, *q;
410 {
411         return strcmp(p->name, q->name);
412 }
413
414 static void
415 SFgetHomeDirs()
416 {
417         struct passwd   *pw;
418         int             alloc;
419         int             i;
420         SFEntry         *entries = NULL;
421         int             len;
422         int             maxChars;
423
424         {
425                         alloc = 1;
426                         i = 1;
427                         entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
428                         SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
429                         entries[0].real = XtMalloc(3);
430                         (void) strcpy(entries[0].real, "~");
431                         entries[0].shown = entries[0].real;
432                         entries[0].statDone = 1;
433                         SFlogins[0].name = "";
434                         pw = getpwuid((int) getuid());
435                         SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
436                         maxChars = 0;
437         }
438
439         (void) setpwent();
440
441         while ((pw = getpwent()) && (*(pw->pw_name))) {
442                         if (i >= alloc) {
443                                 alloc *= 2;
444                                 entries = (SFEntry *) XtRealloc(
445                                         (char *) entries,
446                                         (unsigned) (alloc * sizeof(SFEntry))
447                                 );
448                                 SFlogins = (SFLogin *) XtRealloc(
449                                         (char *) SFlogins,
450                                         (unsigned) (alloc * sizeof(SFLogin))
451                                 );
452                         }
453                         len = strlen(pw->pw_name);
454                         entries[i].real = XtMalloc((unsigned) (len + 3));
455                         (void) strcat(strcpy(entries[i].real, "~"),
456                                 pw->pw_name);
457                         entries[i].shown = entries[i].real;
458                         entries[i].statDone = 1;
459                         if (len > maxChars) {
460                                 maxChars = len;
461                         }
462                         SFstrdup(&SFlogins[i].name, pw->pw_name);
463                         SFstrdup(&SFlogins[i].dir, pw->pw_dir);
464                         i++;
465         }
466
467         SFhomeDir.dir                   = XtMalloc(1)   ;
468         SFhomeDir.dir[0]                = 0             ;
469         SFhomeDir.path                  = SFcurrentPath ;
470         SFhomeDir.entries               = entries       ;
471         SFhomeDir.nEntries              = i             ;
472         SFhomeDir.vOrigin               = 0             ;       /* :-) */
473         SFhomeDir.nChars                = maxChars + 2  ;
474         SFhomeDir.hOrigin               = 0             ;
475         SFhomeDir.changed               = 1             ;
476         SFhomeDir.beginSelection        = -1            ;
477         SFhomeDir.endSelection          = -1            ;
478
479         qsort((char *) entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
480         qsort((char *) SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
481
482         for (i--; i >= 0; i--) {
483                 (void) strcat(entries[i].real, "/");
484         }
485         return;
486 }
487
488 static int
489 SFfindHomeDir(begin, end)
490         char    *begin, *end;
491 {
492         char    save;
493         char    *theRest;
494         int     i;
495
496         save = *end;
497         *end = 0;
498
499         for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
500                 if (!strcmp(SFhomeDir.entries[i].real, begin)) {
501                         *end = save;
502                         SFstrdup(&theRest, end);
503                         (void) strcat(strcat(strncpy(SFcurrentPath,SFlogins[i].dir,
504                                                      MAXPATHLEN), "/"),
505                                       theRest);
506                         XtFree(theRest);
507                         SFsetText(SFcurrentPath);
508                         SFtextChanged();
509                         return 1;
510                 }
511         }
512
513         *end = save;
514
515         return 0;
516 }
517
518 void
519 SFupdatePath()
520 {
521         static int      alloc;
522         static int      wasTwiddle = 0;
523         char            *begin, *end;
524         int             i, j;
525         int             prevChange;
526         int             SFdirPtrSave, SFdirEndSave;
527         SFDir           *dir;
528
529         if (!SFdirs) {
530                 SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
531                 dir = &(SFdirs[0]);
532                 SFstrdup(&dir->dir, "/");
533                 (void) SFchdir("/");
534                 (void) SFgetDir(dir);
535                 for (j = 1; j < alloc; j++) {
536                         SFdirs[j].dir = NULL;
537                 }
538                 dir->path = SFcurrentPath + 1;
539                 dir->vOrigin = 0;
540                 dir->hOrigin = 0;
541                 dir->changed = 1;
542                 dir->beginSelection = -1;
543                 dir->endSelection = -1;
544                 SFhomeDir.dir = NULL;
545         }
546
547         SFdirEndSave = SFdirEnd;
548         SFdirEnd = 1;
549
550         SFdirPtrSave = SFdirPtr;
551         SFdirPtr = 0;
552
553         begin = NULL;
554
555         if (SFcurrentPath[0] == '~') {
556                 if (!SFtwiddle) {
557                         SFtwiddle = 1;
558                         dir = &(SFdirs[0]);
559                         SFrootDir = *dir;
560                         if (!SFhomeDir.dir) {
561                                 SFgetHomeDirs();
562                         }
563                         *dir = SFhomeDir;
564                         dir->changed = 1;
565                 }
566                 end = SFcurrentPath;
567                 SFdoNotTouchDirPtr = 1;
568                 wasTwiddle = 1;
569         } else {
570                 if (SFtwiddle) {
571                         SFtwiddle = 0;
572                         dir = &(SFdirs[0]);
573                         *dir = SFrootDir;
574                         dir->changed = 1;
575                 }
576                 end = SFcurrentPath + 1;
577         }
578
579         i = 0;
580
581         prevChange = 0;
582
583         while (*end) {
584                 while (*end++ == '/') {
585                         ;
586                 }
587                 end--;
588                 begin = end;
589                 while ((*end) && (*end++ != '/')) {
590                         ;
591                 }
592                 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
593                         SFdirPtr = i - 1;
594                         if (SFdirPtr < 0) {
595                                 SFdirPtr = 0;
596                         }
597                 }
598                 if (*begin) {
599                         if (*(end - 1) == '/') {
600                                 char save = *end;
601
602                                 if (SFtwiddle) {
603                                         if (SFfindHomeDir(begin, end)) {
604                                                 return;
605                                         }
606                                 }
607                                 *end = 0;
608                                 i++;
609                                 SFdirEnd++;
610                                 if (i >= alloc) {
611                                         SFdirs = (SFDir *) XtRealloc(
612                                                 (char *) SFdirs,
613                                                 (unsigned) ((alloc *= 2) *
614                                                         sizeof(SFDir))
615                                         );
616                                         for (j = alloc / 2; j < alloc; j++) {
617                                                 SFdirs[j].dir = NULL;
618                                         }
619                                 }
620                                 dir = &(SFdirs[i]);
621                                 if (
622                                         (!(dir->dir)) ||
623                                         prevChange ||
624                                         strcmp(dir->dir, begin)
625                                 ) {
626                                         if (dir->dir) {
627                                                 SFfree(i);
628                                         }
629                                         prevChange = 1;
630                                         SFstrdup(&dir->dir, begin);
631                                         dir->path = end;
632                                         dir->vOrigin = 0;
633                                         dir->hOrigin = 0;
634                                         dir->changed = 1;
635                                         dir->beginSelection = -1;
636                                         dir->endSelection = -1;
637                                         (void) SFfindFile(dir - 1, begin);
638                                         if (
639                                                 SFchdir(SFcurrentPath) ||
640                                                 SFgetDir(dir)
641                                         ) {
642                                                 SFunreadableDir(dir);
643                                                 break;
644                                         }
645                                 }
646                                 *end = save;
647                                 if (!save) {
648                                         SFunselect();
649                                 }
650                         } else {
651                                 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
652                                         return;
653                                 }
654                         }
655                 } else {
656                         SFunselect();
657                 }
658         }
659
660         if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
661                 SFunselect();
662         }
663
664         for (i = SFdirEnd; i < alloc; i++) {
665                 if (SFdirs[i].dir) {
666                         SFfree(i);
667                 }
668         }
669
670         if (SFdoNotTouchDirPtr) {
671                 if (wasTwiddle) {
672                         wasTwiddle = 0;
673                         SFdirPtr = SFdirEnd - 1;
674                         if (SFdirPtr < 0) {
675                                 SFdirPtr = 0;
676                         }
677                 } else {
678                         SFdirPtr = SFdirPtrSave;
679                 }
680                 SFdoNotTouchDirPtr = 0;
681         }
682
683         if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
684                 XawScrollbarSetThumb(
685                         selFileHScroll,
686                         (float) (((double) SFdirPtr) / SFdirEnd),
687                         (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) /
688                                 SFdirEnd)
689                 );
690         }
691
692         if (SFdirPtr != SFdirPtrSave) {
693                 SFdrawLists(SF_DO_SCROLL);
694         } else {
695                 for (i = 0; i < NR; i++) {
696                         if (SFdirPtr + i < SFdirEnd) {
697                                 if (SFdirs[SFdirPtr + i].changed) {
698                                         SFdirs[SFdirPtr + i].changed = 0;
699                                         SFdrawList(i, SF_DO_SCROLL);
700                                 }
701                         } else {
702                                 SFclearList(i, SF_DO_SCROLL);
703                         }
704                 }
705         }
706         return;
707 }
708
709 /* ARGSUSED */
710 void
711 SFbuttonPressList(w, n, event)
712         Widget                  w;
713         int                     n;
714         XButtonPressedEvent     *event;
715 {
716         SFbuttonPressed = 1;
717 }
718
719 /* ARGSUSED */
720 void
721 SFbuttonReleaseList(w, n, event)
722         Widget                  w;
723         int                     n;
724         XButtonReleasedEvent    *event;
725 {
726         SFDir   *dir;
727
728         SFbuttonPressed = 0;
729
730         if (SFcurrentInvert[n] != -1) {
731                 if (n < 2) {
732                         SFdoNotTouchDirPtr = 1;
733                 }
734                 SFdoNotTouchVorigin = 1;
735                 dir = &(SFdirs[SFdirPtr + n]);
736                 SFreplaceText(
737                         dir,
738                         dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
739                 );
740                 SFmotionList(w, n, (XMotionEvent *) event);
741         }
742 }
743
744 static int
745 SFcheckDir(n, dir)
746         int             n;
747         SFDir           *dir;
748 {
749         struct stat     statBuf;
750         int             i;
751
752         if (
753                 (!stat(".", &statBuf)) &&
754                 (statBuf.st_mtime != dir->mtime)
755         ) {
756
757                 /*
758                  * If the pointer is currently in the window that we are about
759                  * to update, we must warp it to prevent the user from
760                  * accidentally selecting the wrong file.
761                  */
762                 if (SFcurrentInvert[n] != -1) {
763                         XWarpPointer(
764                                 SFdisplay,
765                                 None,
766                                 XtWindow(selFileLists[n]),
767                                 0,
768                                 0,
769                                 0,
770                                 0,
771                                 0,
772                                 0
773                         );
774                 }
775
776                 for (i = dir->nEntries - 1; i >= 0; i--) {
777                         if (dir->entries[i].shown != dir->entries[i].real) {
778                                 XtFree(dir->entries[i].shown);
779                         }
780                         XtFree(dir->entries[i].real);
781                 }
782                 XtFree((char *) dir->entries);
783                 if (SFgetDir(dir)) {
784                         SFunreadableDir(dir);
785                 }
786                 if (dir->vOrigin > dir->nEntries - SFlistSize) {
787                         dir->vOrigin = dir->nEntries - SFlistSize;
788                 }
789                 if (dir->vOrigin < 0) {
790                         dir->vOrigin = 0;
791                 }
792                 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
793                         dir->hOrigin = dir->nChars - SFcharsPerEntry;
794                 }
795                 if (dir->hOrigin < 0) {
796                         dir->hOrigin = 0;
797                 }
798                 dir->beginSelection = -1;
799                 dir->endSelection = -1;
800                 SFdoNotTouchVorigin = 1;
801                 if ((dir + 1)->dir) {
802                         (void) SFfindFile(dir, (dir + 1)->dir);
803                 } else {
804                         (void) SFfindFile(dir, dir->path);
805                 }
806
807                 if (!SFworkProcAdded) {
808                         (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
809                         SFworkProcAdded = 1;
810                 }
811
812                 return 1;
813         }
814
815         return 0;
816 }
817
818 /* Return a single character describing what kind of file STATBUF is.  */
819
820 char
821 SFstatChar (statBuf)
822         struct stat *statBuf;
823 {
824         if (S_ISDIR (statBuf->st_mode)) {
825                 return '/';
826         } else if (S_ISREG (statBuf->st_mode)) {
827           return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
828 #ifdef S_ISSOCK
829         } else if (S_ISSOCK (statBuf->st_mode)) {
830                 return '=';
831 #endif /* S_ISSOCK */
832         } else {
833                 return ' ';
834         }
835 }
836
837 static int
838 SFcheckFiles(dir)
839         SFDir   *dir;
840 {
841         int             from, to;
842         int             result;
843         char            old, new;
844         int             i;
845         char            *str;
846         int             last;
847         struct stat     statBuf;
848
849         result = 0;
850
851         from = dir->vOrigin;
852         to = dir->vOrigin + SFlistSize;
853         if (to > dir->nEntries) {
854                 to = dir->nEntries;
855         }
856
857         for (i = from; i < to; i++) {
858                 str = dir->entries[i].real;
859                 last = strlen(str) - 1;
860                 old = str[last];
861                 str[last] = 0;
862                 if (stat(str, &statBuf)) {
863                         new = ' ';
864                 } else {
865                         new = SFstatChar(&statBuf);
866                 }
867                 str[last] = new;
868                 if (new != old) {
869                         result = 1;
870                 }
871         }
872
873         return result;
874 }
875
876 void
877 SFdirModTimer(cl, id)
878         XtPointer       cl;
879         XtIntervalId    *id;
880 {
881         static int      n = -1;
882         static int      f = 0;
883         char            save;
884         SFDir           *dir;
885
886         if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
887                 n++;
888                 if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) {
889                         n = 0;
890                         f++;
891                         if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) {
892                                 f = 0;
893                         }
894                 }
895                 dir = &(SFdirs[SFdirPtr + n]);
896                 save = *(dir->path);
897                 *(dir->path) = 0;
898                 if (SFchdir(SFcurrentPath)) {
899                         *(dir->path) = save;
900
901                         /*
902                          * force a re-read
903                          */
904                         *(dir->dir) = 0;
905
906                         SFupdatePath();
907                 } else {
908                         *(dir->path) = save;
909                         if (
910                                 SFcheckDir(n, dir) ||
911                                 ((f == n) && SFcheckFiles(dir))
912                         ) {
913                                 SFdrawList(n, SF_DO_SCROLL);
914                         }
915                 }
916         }
917
918         SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
919                 SFdirModTimer, (XtPointer) NULL);
920 }