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