2 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
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.
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.
22 * Author: Erik M. van der Poel
23 * Software Research Associates, Inc., Tokyo, Japan
29 #ifdef SEL_FILE_IGNORE_CASE
31 #endif /* def SEL_FILE_IGNORE_CASE */
37 #include <X11/Xaw/Scrollbar.h>
39 #if defined(SVR4) || defined(SYSV) || defined(USG)
40 extern uid_t getuid();
42 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
55 int SFbuttonPressed = 0;
57 static int SFdoNotTouchDirPtr = 0;
59 static int SFdoNotTouchVorigin = 0;
61 static SFDir SFrootDir, SFhomeDir;
63 static SFLogin *SFlogins;
65 static int SFtwiddle = 0;
75 if (strcmp(path, SFcurrentDir)) {
78 (void) strcpy(SFcurrentDir, path);
94 for (j = dir->nEntries - 1; j >= 0; j--) {
95 if (dir->entries[j].shown != dir->entries[j].real) {
96 XtFree(dir->entries[j].shown);
98 XtFree(dir->entries[j].real);
101 XtFree((char *) dir->entries);
114 *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
122 char *cannotOpen = "<cannot open> ";
124 dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
125 dir->entries[0].statDone = 1;
126 SFstrdup(&dir->entries[0].real, cannotOpen);
127 dir->entries[0].shown = dir->entries[0].real;
129 dir->nChars = strlen(cannotOpen);
133 #ifdef SEL_FILE_IGNORE_CASE
136 register char *p, *q;
139 register char c1, c2;
156 while ((--n >= 0) && (c1 == c2)) {
158 return strncmp(psave, qsave, nsave);
171 return strncmp(psave, qsave, nsave);
176 #endif /* def SEL_FILE_IGNORE_CASE */
179 SFreplaceText(dir, str)
187 if (str[len - 1] == '/') {
188 (void) strcat(SFcurrentPath, str);
190 (void) strncat(SFcurrentPath, str, len - 1);
192 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
193 SFsetText(SFcurrentPath);
195 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
208 char *name, *growing;
210 SFEntry *entry, *max;
214 dir = &(SFdirs[SFdirEnd - 1]);
216 if (dir->beginSelection == -1) {
218 SFreplaceText(dir, str);
221 } else if (dir->beginSelection == dir->endSelection) {
222 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
226 max = &(dir->entries[dir->endSelection + 1]);
228 name = dir->entries[dir->beginSelection].shown;
229 SFstrdup(&growing, name);
233 entry = &(dir->entries[dir->beginSelection]);
234 while (entry < max) {
235 if (cmp = strncmp(growing, entry->shown, len)) {
244 * SFreplaceText() expects filename
246 growing[len - 2] = ' ';
248 growing[len - 1] = 0;
249 SFreplaceText(dir, growing);
258 register int i, last, max;
259 register char *name, save;
267 if (str[len - 1] == ' ') {
270 } else if (str[len - 1] == '/') {
276 entries = dir->entries;
280 name = entries[i].shown;
281 last = strlen(name) - 1;
285 #ifdef SEL_FILE_IGNORE_CASE
286 result = SFstrncmp(str, name, len);
287 #else /* def SEL_FILE_IGNORE_CASE */
288 result = strncmp(str, name, len);
289 #endif /* def SEL_FILE_IGNORE_CASE */
299 name = entries[i].shown;
300 last = strlen(name) - 1;
304 #ifdef SEL_FILE_IGNORE_CASE
305 result = SFstrncmp(str, name, len);
306 #else /* def SEL_FILE_IGNORE_CASE */
307 result = strncmp(str, name, len);
308 #endif /* def SEL_FILE_IGNORE_CASE */
320 (dir->beginSelection != begin) ||
321 (dir->endSelection != end - 1)
324 dir->beginSelection = begin;
325 if (str[strlen(str) - 1] == '/') {
326 dir->endSelection = begin;
328 dir->endSelection = end - 1;
332 if (dir->beginSelection != -1) {
334 dir->beginSelection = -1;
335 dir->endSelection = -1;
340 SFdoNotTouchVorigin ||
341 ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
343 SFdoNotTouchVorigin = 0;
348 if (i > max - SFlistSize) {
349 i = max - SFlistSize;
355 if (dir->vOrigin != i) {
368 dir = &(SFdirs[SFdirEnd - 1]);
369 if (dir->beginSelection != -1) {
372 dir->beginSelection = -1;
373 dir->endSelection = -1;
378 SFcompareLogins(p, q)
381 return strcmp(p->name, q->name);
390 SFEntry *entries = NULL;
397 entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
398 SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
399 entries[0].real = XtMalloc(3);
400 (void) strcpy(entries[0].real, "~");
401 entries[0].shown = entries[0].real;
402 entries[0].statDone = 1;
403 SFlogins[0].name = "";
404 pw = getpwuid((int) getuid());
405 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
411 while ((pw = getpwent()) && (*(pw->pw_name))) {
414 entries = (SFEntry *) XtRealloc(
416 (unsigned) (alloc * sizeof(SFEntry))
418 SFlogins = (SFLogin *) XtRealloc(
420 (unsigned) (alloc * sizeof(SFLogin))
423 len = strlen(pw->pw_name);
424 entries[i].real = XtMalloc((unsigned) (len + 3));
425 (void) strcat(strcpy(entries[i].real, "~"),
427 entries[i].shown = entries[i].real;
428 entries[i].statDone = 1;
429 if (len > maxChars) {
432 SFstrdup(&SFlogins[i].name, pw->pw_name);
433 SFstrdup(&SFlogins[i].dir, pw->pw_dir);
437 SFhomeDir.dir = XtMalloc(1) ;
438 SFhomeDir.dir[0] = 0 ;
439 SFhomeDir.path = SFcurrentPath ;
440 SFhomeDir.entries = entries ;
441 SFhomeDir.nEntries = i ;
442 SFhomeDir.vOrigin = 0 ; /* :-) */
443 SFhomeDir.nChars = maxChars + 2 ;
444 SFhomeDir.hOrigin = 0 ;
445 SFhomeDir.changed = 1 ;
446 SFhomeDir.beginSelection = -1 ;
447 SFhomeDir.endSelection = -1 ;
449 #if defined(SVR4) || defined(SYSV) || defined(USG)
450 qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
451 qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
452 #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
453 qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
454 qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
455 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
457 for (i--; i >= 0; i--) {
458 (void) strcat(entries[i].real, "/");
464 SFfindHomeDir(begin, end)
474 for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
475 if (!strcmp(SFhomeDir.entries[i].real, begin)) {
477 SFstrdup(&theRest, end);
478 (void) strcat(strcat(strcpy(SFcurrentPath,
479 SFlogins[i].dir), "/"), theRest);
481 SFsetText(SFcurrentPath);
496 static int wasTwiddle = 0;
500 int SFdirPtrSave, SFdirEndSave;
504 SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
506 SFstrdup(&dir->dir, "/");
508 (void) SFgetDir(dir);
509 for (j = 1; j < alloc; j++) {
510 SFdirs[j].dir = NULL;
512 dir->path = SFcurrentPath + 1;
516 dir->beginSelection = -1;
517 dir->endSelection = -1;
518 SFhomeDir.dir = NULL;
521 SFdirEndSave = SFdirEnd;
524 SFdirPtrSave = SFdirPtr;
529 if (SFcurrentPath[0] == '~') {
534 if (!SFhomeDir.dir) {
541 SFdoNotTouchDirPtr = 1;
550 end = SFcurrentPath + 1;
558 while (*end++ == '/') {
563 while ((*end) && (*end++ != '/')) {
566 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
573 if (*(end - 1) == '/') {
577 if (SFfindHomeDir(begin, end)) {
585 SFdirs = (SFDir *) XtRealloc(
587 (unsigned) ((alloc *= 2) *
590 for (j = alloc / 2; j < alloc; j++) {
591 SFdirs[j].dir = NULL;
598 strcmp(dir->dir, begin)
604 SFstrdup(&dir->dir, begin);
609 dir->beginSelection = -1;
610 dir->endSelection = -1;
611 (void) SFfindFile(dir - 1, begin);
613 SFchdir(SFcurrentPath) ||
616 SFunreadableDir(dir);
625 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
634 if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
638 for (i = SFdirEnd; i < alloc; i++) {
644 if (SFdoNotTouchDirPtr) {
647 SFdirPtr = SFdirEnd - 1;
652 SFdirPtr = SFdirPtrSave;
654 SFdoNotTouchDirPtr = 0;
657 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
658 XawScrollbarSetThumb(
660 (float) (((double) SFdirPtr) / SFdirEnd),
661 (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) /
666 if (SFdirPtr != SFdirPtrSave) {
667 SFdrawLists(SF_DO_SCROLL);
669 for (i = 0; i < NR; i++) {
670 if (SFdirPtr + i < SFdirEnd) {
671 if (SFdirs[SFdirPtr + i].changed) {
672 SFdirs[SFdirPtr + i].changed = 0;
673 SFdrawList(i, SF_DO_SCROLL);
676 SFclearList(i, SF_DO_SCROLL);
690 text.length = strlen(path);
692 text.format = FMT8BIT;
694 XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
695 XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
702 SFbuttonPressList(w, n, event)
705 XButtonPressedEvent *event;
712 SFbuttonReleaseList(w, n, event)
715 XButtonReleasedEvent *event;
721 if (SFcurrentInvert[n] != -1) {
723 SFdoNotTouchDirPtr = 1;
725 SFdoNotTouchVorigin = 1;
726 dir = &(SFdirs[SFdirPtr + n]);
729 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
731 SFmotionList(w, n, event);
744 (!stat(".", &statBuf)) &&
745 (statBuf.st_mtime != dir->mtime)
749 * If the pointer is currently in the window that we are about
750 * to update, we must warp it to prevent the user from
751 * accidentally selecting the wrong file.
753 if (SFcurrentInvert[n] != -1) {
757 XtWindow(selFileLists[n]),
767 for (i = dir->nEntries - 1; i >= 0; i--) {
768 if (dir->entries[i].shown != dir->entries[i].real) {
769 XtFree(dir->entries[i].shown);
771 XtFree(dir->entries[i].real);
773 XtFree((char *) dir->entries);
775 SFunreadableDir(dir);
777 if (dir->vOrigin > dir->nEntries - SFlistSize) {
778 dir->vOrigin = dir->nEntries - SFlistSize;
780 if (dir->vOrigin < 0) {
783 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
784 dir->hOrigin = dir->nChars - SFcharsPerEntry;
786 if (dir->hOrigin < 0) {
789 dir->beginSelection = -1;
790 dir->endSelection = -1;
791 SFdoNotTouchVorigin = 1;
792 if ((dir + 1)->dir) {
793 (void) SFfindFile(dir, (dir + 1)->dir);
795 (void) SFfindFile(dir, dir->path);
798 if (!SFworkProcAdded) {
799 (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
824 to = dir->vOrigin + SFlistSize;
825 if (to > dir->nEntries) {
829 for (i = from; i < to; i++) {
830 str = dir->entries[i].real;
831 last = strlen(str) - 1;
834 if (stat(str, &statBuf)) {
837 new = SFstatChar(&statBuf);
849 SFdirModTimer(cl, id)
858 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
860 if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) {
863 if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) {
867 dir = &(SFdirs[SFdirPtr + n]);
870 if (SFchdir(SFcurrentPath)) {
882 SFcheckDir(n, dir) ||
883 ((f == n) && SFcheckFiles(dir))
885 SFdrawList(n, SF_DO_SCROLL);
890 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
891 SFdirModTimer, (XtPointer) NULL);
894 /* Return a single character describing what kind of file STATBUF is. */
898 struct stat *statBuf;
900 if (S_ISDIR (statBuf->st_mode)) {
902 } else if (S_ISREG (statBuf->st_mode)) {
903 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
905 } else if (S_ISSOCK (statBuf->st_mode)) {
907 #endif /* S_ISSOCK */