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);
113 *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
120 char *cannotOpen = "<cannot open> ";
122 dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
123 dir->entries[0].statDone = 1;
124 SFstrdup(&dir->entries[0].real, cannotOpen);
125 dir->entries[0].shown = dir->entries[0].real;
127 dir->nChars = strlen(cannotOpen);
130 #ifdef SEL_FILE_IGNORE_CASE
133 register char *p, *q;
136 register char c1, c2;
153 while ((--n >= 0) && (c1 == c2)) {
155 return strncmp(psave, qsave, nsave);
168 return strncmp(psave, qsave, nsave);
173 #endif /* def SEL_FILE_IGNORE_CASE */
176 SFreplaceText(dir, str)
184 if (str[len - 1] == '/') {
185 (void) strcat(SFcurrentPath, str);
187 (void) strncat(SFcurrentPath, str, len - 1);
189 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
190 SFsetText(SFcurrentPath);
192 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
204 char *name, *growing;
206 SFEntry *entry, *max;
210 dir = &(SFdirs[SFdirEnd - 1]);
212 if (dir->beginSelection == -1) {
214 SFreplaceText(dir, str);
217 } else if (dir->beginSelection == dir->endSelection) {
218 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
222 max = &(dir->entries[dir->endSelection + 1]);
224 name = dir->entries[dir->beginSelection].shown;
225 SFstrdup(&growing, name);
229 entry = &(dir->entries[dir->beginSelection]);
230 while (entry < max) {
231 if (cmp = strncmp(growing, entry->shown, len)) {
240 * SFreplaceText() expects filename
242 growing[len - 2] = ' ';
244 growing[len - 1] = 0;
245 SFreplaceText(dir, growing);
254 register int i, last, max;
255 register char *name, save;
263 if (str[len - 1] == ' ') {
266 } else if (str[len - 1] == '/') {
272 entries = dir->entries;
276 name = entries[i].shown;
277 last = strlen(name) - 1;
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 */
295 name = entries[i].shown;
296 last = strlen(name) - 1;
300 #ifdef SEL_FILE_IGNORE_CASE
301 result = SFstrncmp(str, name, len);
302 #else /* def SEL_FILE_IGNORE_CASE */
303 result = strncmp(str, name, len);
304 #endif /* def SEL_FILE_IGNORE_CASE */
316 (dir->beginSelection != begin) ||
317 (dir->endSelection != end - 1)
320 dir->beginSelection = begin;
321 if (str[strlen(str) - 1] == '/') {
322 dir->endSelection = begin;
324 dir->endSelection = end - 1;
328 if (dir->beginSelection != -1) {
330 dir->beginSelection = -1;
331 dir->endSelection = -1;
336 SFdoNotTouchVorigin ||
337 ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
339 SFdoNotTouchVorigin = 0;
344 if (i > max - SFlistSize) {
345 i = max - SFlistSize;
351 if (dir->vOrigin != i) {
364 dir = &(SFdirs[SFdirEnd - 1]);
365 if (dir->beginSelection != -1) {
368 dir->beginSelection = -1;
369 dir->endSelection = -1;
373 SFcompareLogins(p, q)
376 return strcmp(p->name, q->name);
385 SFEntry *entries = NULL;
392 entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
393 SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
394 entries[0].real = XtMalloc(3);
395 (void) strcpy(entries[0].real, "~");
396 entries[0].shown = entries[0].real;
397 entries[0].statDone = 1;
398 SFlogins[0].name = "";
399 pw = getpwuid((int) getuid());
400 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
406 while ((pw = getpwent()) && (*(pw->pw_name))) {
409 entries = (SFEntry *) XtRealloc(
411 (unsigned) (alloc * sizeof(SFEntry))
413 SFlogins = (SFLogin *) XtRealloc(
415 (unsigned) (alloc * sizeof(SFLogin))
418 len = strlen(pw->pw_name);
419 entries[i].real = XtMalloc((unsigned) (len + 3));
420 (void) strcat(strcpy(entries[i].real, "~"),
422 entries[i].shown = entries[i].real;
423 entries[i].statDone = 1;
424 if (len > maxChars) {
427 SFstrdup(&SFlogins[i].name, pw->pw_name);
428 SFstrdup(&SFlogins[i].dir, pw->pw_dir);
432 SFhomeDir.dir = XtMalloc(1) ;
433 SFhomeDir.dir[0] = 0 ;
434 SFhomeDir.path = SFcurrentPath ;
435 SFhomeDir.entries = entries ;
436 SFhomeDir.nEntries = i ;
437 SFhomeDir.vOrigin = 0 ; /* :-) */
438 SFhomeDir.nChars = maxChars + 2 ;
439 SFhomeDir.hOrigin = 0 ;
440 SFhomeDir.changed = 1 ;
441 SFhomeDir.beginSelection = -1 ;
442 SFhomeDir.endSelection = -1 ;
444 #if defined(SVR4) || defined(SYSV) || defined(USG)
445 qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
446 qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
447 #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
448 qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
449 qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
450 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
452 for (i--; i >= 0; i--) {
453 (void) strcat(entries[i].real, "/");
458 SFfindHomeDir(begin, end)
468 for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
469 if (!strcmp(SFhomeDir.entries[i].real, begin)) {
471 SFstrdup(&theRest, end);
472 (void) strcat(strcat(strcpy(SFcurrentPath,
473 SFlogins[i].dir), "/"), theRest);
475 SFsetText(SFcurrentPath);
489 static int wasTwiddle = 0;
493 int SFdirPtrSave, SFdirEndSave;
497 SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
499 SFstrdup(&dir->dir, "/");
501 (void) SFgetDir(dir);
502 for (j = 1; j < alloc; j++) {
503 SFdirs[j].dir = NULL;
505 dir->path = SFcurrentPath + 1;
509 dir->beginSelection = -1;
510 dir->endSelection = -1;
511 SFhomeDir.dir = NULL;
514 SFdirEndSave = SFdirEnd;
517 SFdirPtrSave = SFdirPtr;
522 if (SFcurrentPath[0] == '~') {
527 if (!SFhomeDir.dir) {
534 SFdoNotTouchDirPtr = 1;
543 end = SFcurrentPath + 1;
551 while (*end++ == '/') {
556 while ((*end) && (*end++ != '/')) {
559 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
566 if (*(end - 1) == '/') {
570 if (SFfindHomeDir(begin, end)) {
578 SFdirs = (SFDir *) XtRealloc(
580 (unsigned) ((alloc *= 2) *
583 for (j = alloc / 2; j < alloc; j++) {
584 SFdirs[j].dir = NULL;
591 strcmp(dir->dir, begin)
597 SFstrdup(&dir->dir, begin);
602 dir->beginSelection = -1;
603 dir->endSelection = -1;
604 (void) SFfindFile(dir - 1, begin);
606 SFchdir(SFcurrentPath) ||
609 SFunreadableDir(dir);
618 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
627 if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
631 for (i = SFdirEnd; i < alloc; i++) {
637 if (SFdoNotTouchDirPtr) {
640 SFdirPtr = SFdirEnd - 1;
645 SFdirPtr = SFdirPtrSave;
647 SFdoNotTouchDirPtr = 0;
650 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
651 XawScrollbarSetThumb(
653 (float) (((double) SFdirPtr) / SFdirEnd),
654 (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) /
659 if (SFdirPtr != SFdirPtrSave) {
660 SFdrawLists(SF_DO_SCROLL);
662 for (i = 0; i < NR; i++) {
663 if (SFdirPtr + i < SFdirEnd) {
664 if (SFdirs[SFdirPtr + i].changed) {
665 SFdirs[SFdirPtr + i].changed = 0;
666 SFdrawList(i, SF_DO_SCROLL);
669 SFclearList(i, SF_DO_SCROLL);
681 text.length = strlen(path);
683 text.format = FMT8BIT;
685 XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
686 XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
691 SFbuttonPressList(w, n, event)
694 XButtonPressedEvent *event;
701 SFbuttonReleaseList(w, n, event)
704 XButtonReleasedEvent *event;
710 if (SFcurrentInvert[n] != -1) {
712 SFdoNotTouchDirPtr = 1;
714 SFdoNotTouchVorigin = 1;
715 dir = &(SFdirs[SFdirPtr + n]);
718 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
720 SFmotionList(w, n, event);
733 (!stat(".", &statBuf)) &&
734 (statBuf.st_mtime != dir->mtime)
738 * If the pointer is currently in the window that we are about
739 * to update, we must warp it to prevent the user from
740 * accidentally selecting the wrong file.
742 if (SFcurrentInvert[n] != -1) {
746 XtWindow(selFileLists[n]),
756 for (i = dir->nEntries - 1; i >= 0; i--) {
757 if (dir->entries[i].shown != dir->entries[i].real) {
758 XtFree(dir->entries[i].shown);
760 XtFree(dir->entries[i].real);
762 XtFree((char *) dir->entries);
764 SFunreadableDir(dir);
766 if (dir->vOrigin > dir->nEntries - SFlistSize) {
767 dir->vOrigin = dir->nEntries - SFlistSize;
769 if (dir->vOrigin < 0) {
772 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
773 dir->hOrigin = dir->nChars - SFcharsPerEntry;
775 if (dir->hOrigin < 0) {
778 dir->beginSelection = -1;
779 dir->endSelection = -1;
780 SFdoNotTouchVorigin = 1;
781 if ((dir + 1)->dir) {
782 (void) SFfindFile(dir, (dir + 1)->dir);
784 (void) SFfindFile(dir, dir->path);
787 if (!SFworkProcAdded) {
788 (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
813 to = dir->vOrigin + SFlistSize;
814 if (to > dir->nEntries) {
818 for (i = from; i < to; i++) {
819 str = dir->entries[i].real;
820 last = strlen(str) - 1;
823 if (stat(str, &statBuf)) {
826 new = SFstatChar(&statBuf);
838 SFdirModTimer(cl, id)
847 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
849 if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) {
852 if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) {
856 dir = &(SFdirs[SFdirPtr + n]);
859 if (SFchdir(SFcurrentPath)) {
871 SFcheckDir(n, dir) ||
872 ((f == n) && SFcheckFiles(dir))
874 SFdrawList(n, SF_DO_SCROLL);
879 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
880 SFdirModTimer, (XtPointer) NULL);
883 /* Return a single character describing what kind of file STATBUF is. */
887 struct stat *statBuf;
889 if (S_ISDIR (statBuf->st_mode)) {
891 } else if (S_ISREG (statBuf->st_mode)) {
892 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
894 } else if (S_ISSOCK (statBuf->st_mode)) {
896 #endif /* S_ISSOCK */