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