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