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>
40 #define MAXPATHLEN 1024
41 #endif /* ndef MAXPATHLEN */
44 #if defined(SVR4) || defined(SYSV) || defined(USG)
45 extern uid_t getuid();
47 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
60 int SFbuttonPressed = 0;
62 static int SFdoNotTouchDirPtr = 0;
64 static int SFdoNotTouchVorigin = 0;
66 static SFDir SFrootDir, SFhomeDir;
68 static SFLogin *SFlogins;
70 static int SFtwiddle = 0;
80 if (strcmp(path, SFcurrentDir)) {
83 (void) strncpy(SFcurrentDir, path, MAXPATHLEN);
99 for (j = dir->nEntries - 1; j >= 0; j--) {
100 if (dir->entries[j].shown != dir->entries[j].real) {
101 XtFree(dir->entries[j].shown);
103 XtFree(dir->entries[j].real);
106 XtFree((char *) dir->entries);
119 *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
127 char *cannotOpen = "<cannot open> ";
129 dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
130 dir->entries[0].statDone = 1;
131 SFstrdup(&dir->entries[0].real, cannotOpen);
132 dir->entries[0].shown = dir->entries[0].real;
134 dir->nChars = strlen(cannotOpen);
138 #ifdef SEL_FILE_IGNORE_CASE
141 register char *p, *q;
144 register char c1, c2;
161 while ((--n >= 0) && (c1 == c2)) {
163 return strncmp(psave, qsave, nsave);
176 return strncmp(psave, qsave, nsave);
181 #endif /* def SEL_FILE_IGNORE_CASE */
184 SFreplaceText(dir, str)
192 if (str[len - 1] == '/') {
193 (void) strcat(SFcurrentPath, str);
195 (void) strncat(SFcurrentPath, str, len - 1);
197 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
198 SFsetText(SFcurrentPath);
200 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
213 char *name, *growing;
215 SFEntry *entry, *max;
219 dir = &(SFdirs[SFdirEnd - 1]);
221 if (dir->beginSelection == -1) {
223 SFreplaceText(dir, str);
226 } else if (dir->beginSelection == dir->endSelection) {
227 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
231 max = &(dir->entries[dir->endSelection + 1]);
233 name = dir->entries[dir->beginSelection].shown;
234 SFstrdup(&growing, name);
238 entry = &(dir->entries[dir->beginSelection]);
239 while (entry < max) {
240 if (cmp = strncmp(growing, entry->shown, len)) {
249 * SFreplaceText() expects filename
251 growing[len - 2] = ' ';
253 growing[len - 1] = 0;
254 SFreplaceText(dir, growing);
263 register int i, last, max;
264 register char *name, save;
272 if (str[len - 1] == ' ') {
275 } else if (str[len - 1] == '/') {
281 entries = dir->entries;
285 name = entries[i].shown;
286 last = strlen(name) - 1;
290 #ifdef SEL_FILE_IGNORE_CASE
291 result = SFstrncmp(str, name, len);
292 #else /* def SEL_FILE_IGNORE_CASE */
293 result = strncmp(str, name, len);
294 #endif /* def SEL_FILE_IGNORE_CASE */
304 name = entries[i].shown;
305 last = strlen(name) - 1;
309 #ifdef SEL_FILE_IGNORE_CASE
310 result = SFstrncmp(str, name, len);
311 #else /* def SEL_FILE_IGNORE_CASE */
312 result = strncmp(str, name, len);
313 #endif /* def SEL_FILE_IGNORE_CASE */
325 (dir->beginSelection != begin) ||
326 (dir->endSelection != end - 1)
329 dir->beginSelection = begin;
330 if (str[strlen(str) - 1] == '/') {
331 dir->endSelection = begin;
333 dir->endSelection = end - 1;
337 if (dir->beginSelection != -1) {
339 dir->beginSelection = -1;
340 dir->endSelection = -1;
345 SFdoNotTouchVorigin ||
346 ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
348 SFdoNotTouchVorigin = 0;
353 if (i > max - SFlistSize) {
354 i = max - SFlistSize;
360 if (dir->vOrigin != i) {
373 dir = &(SFdirs[SFdirEnd - 1]);
374 if (dir->beginSelection != -1) {
377 dir->beginSelection = -1;
378 dir->endSelection = -1;
383 SFcompareLogins(p, q)
386 return strcmp(p->name, q->name);
395 SFEntry *entries = NULL;
402 entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
403 SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
404 entries[0].real = XtMalloc(3);
405 (void) strcpy(entries[0].real, "~");
406 entries[0].shown = entries[0].real;
407 entries[0].statDone = 1;
408 SFlogins[0].name = "";
409 pw = getpwuid((int) getuid());
410 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
416 while ((pw = getpwent()) && (*(pw->pw_name))) {
419 entries = (SFEntry *) XtRealloc(
421 (unsigned) (alloc * sizeof(SFEntry))
423 SFlogins = (SFLogin *) XtRealloc(
425 (unsigned) (alloc * sizeof(SFLogin))
428 len = strlen(pw->pw_name);
429 entries[i].real = XtMalloc((unsigned) (len + 3));
430 (void) strcat(strcpy(entries[i].real, "~"),
432 entries[i].shown = entries[i].real;
433 entries[i].statDone = 1;
434 if (len > maxChars) {
437 SFstrdup(&SFlogins[i].name, pw->pw_name);
438 SFstrdup(&SFlogins[i].dir, pw->pw_dir);
442 SFhomeDir.dir = XtMalloc(1) ;
443 SFhomeDir.dir[0] = 0 ;
444 SFhomeDir.path = SFcurrentPath ;
445 SFhomeDir.entries = entries ;
446 SFhomeDir.nEntries = i ;
447 SFhomeDir.vOrigin = 0 ; /* :-) */
448 SFhomeDir.nChars = maxChars + 2 ;
449 SFhomeDir.hOrigin = 0 ;
450 SFhomeDir.changed = 1 ;
451 SFhomeDir.beginSelection = -1 ;
452 SFhomeDir.endSelection = -1 ;
454 #if defined(SVR4) || defined(SYSV) || defined(USG)
455 qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
456 qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
457 #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
458 qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
459 qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
460 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
462 for (i--; i >= 0; i--) {
463 (void) strcat(entries[i].real, "/");
469 SFfindHomeDir(begin, end)
479 for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
480 if (!strcmp(SFhomeDir.entries[i].real, begin)) {
482 SFstrdup(&theRest, end);
483 (void) strcat(strcat(strncpy(SFcurrentPath,SFlogins[i].dir,
487 SFsetText(SFcurrentPath);
502 static int wasTwiddle = 0;
506 int SFdirPtrSave, SFdirEndSave;
510 SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
512 SFstrdup(&dir->dir, "/");
514 (void) SFgetDir(dir);
515 for (j = 1; j < alloc; j++) {
516 SFdirs[j].dir = NULL;
518 dir->path = SFcurrentPath + 1;
522 dir->beginSelection = -1;
523 dir->endSelection = -1;
524 SFhomeDir.dir = NULL;
527 SFdirEndSave = SFdirEnd;
530 SFdirPtrSave = SFdirPtr;
535 if (SFcurrentPath[0] == '~') {
540 if (!SFhomeDir.dir) {
547 SFdoNotTouchDirPtr = 1;
556 end = SFcurrentPath + 1;
564 while (*end++ == '/') {
569 while ((*end) && (*end++ != '/')) {
572 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
579 if (*(end - 1) == '/') {
583 if (SFfindHomeDir(begin, end)) {
591 SFdirs = (SFDir *) XtRealloc(
593 (unsigned) ((alloc *= 2) *
596 for (j = alloc / 2; j < alloc; j++) {
597 SFdirs[j].dir = NULL;
604 strcmp(dir->dir, begin)
610 SFstrdup(&dir->dir, begin);
615 dir->beginSelection = -1;
616 dir->endSelection = -1;
617 (void) SFfindFile(dir - 1, begin);
619 SFchdir(SFcurrentPath) ||
622 SFunreadableDir(dir);
631 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
640 if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
644 for (i = SFdirEnd; i < alloc; i++) {
650 if (SFdoNotTouchDirPtr) {
653 SFdirPtr = SFdirEnd - 1;
658 SFdirPtr = SFdirPtrSave;
660 SFdoNotTouchDirPtr = 0;
663 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
664 XawScrollbarSetThumb(
666 (float) (((double) SFdirPtr) / SFdirEnd),
667 (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) /
672 if (SFdirPtr != SFdirPtrSave) {
673 SFdrawLists(SF_DO_SCROLL);
675 for (i = 0; i < NR; i++) {
676 if (SFdirPtr + i < SFdirEnd) {
677 if (SFdirs[SFdirPtr + i].changed) {
678 SFdirs[SFdirPtr + i].changed = 0;
679 SFdrawList(i, SF_DO_SCROLL);
682 SFclearList(i, SF_DO_SCROLL);
696 text.length = strlen(path);
698 text.format = FMT8BIT;
700 XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
701 XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
708 SFbuttonPressList(w, n, event)
711 XButtonPressedEvent *event;
718 SFbuttonReleaseList(w, n, event)
721 XButtonReleasedEvent *event;
727 if (SFcurrentInvert[n] != -1) {
729 SFdoNotTouchDirPtr = 1;
731 SFdoNotTouchVorigin = 1;
732 dir = &(SFdirs[SFdirPtr + n]);
735 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
737 SFmotionList(w, n, event);
750 (!stat(".", &statBuf)) &&
751 (statBuf.st_mtime != dir->mtime)
755 * If the pointer is currently in the window that we are about
756 * to update, we must warp it to prevent the user from
757 * accidentally selecting the wrong file.
759 if (SFcurrentInvert[n] != -1) {
763 XtWindow(selFileLists[n]),
773 for (i = dir->nEntries - 1; i >= 0; i--) {
774 if (dir->entries[i].shown != dir->entries[i].real) {
775 XtFree(dir->entries[i].shown);
777 XtFree(dir->entries[i].real);
779 XtFree((char *) dir->entries);
781 SFunreadableDir(dir);
783 if (dir->vOrigin > dir->nEntries - SFlistSize) {
784 dir->vOrigin = dir->nEntries - SFlistSize;
786 if (dir->vOrigin < 0) {
789 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
790 dir->hOrigin = dir->nChars - SFcharsPerEntry;
792 if (dir->hOrigin < 0) {
795 dir->beginSelection = -1;
796 dir->endSelection = -1;
797 SFdoNotTouchVorigin = 1;
798 if ((dir + 1)->dir) {
799 (void) SFfindFile(dir, (dir + 1)->dir);
801 (void) SFfindFile(dir, dir->path);
804 if (!SFworkProcAdded) {
805 (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
830 to = dir->vOrigin + SFlistSize;
831 if (to > dir->nEntries) {
835 for (i = from; i < to; i++) {
836 str = dir->entries[i].real;
837 last = strlen(str) - 1;
840 if (stat(str, &statBuf)) {
843 new = SFstatChar(&statBuf);
855 SFdirModTimer(cl, id)
864 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
866 if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) {
869 if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) {
873 dir = &(SFdirs[SFdirPtr + n]);
876 if (SFchdir(SFcurrentPath)) {
888 SFcheckDir(n, dir) ||
889 ((f == n) && SFcheckFiles(dir))
891 SFdrawList(n, SF_DO_SCROLL);
896 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
897 SFdirModTimer, (XtPointer) NULL);
900 /* Return a single character describing what kind of file STATBUF is. */
904 struct stat *statBuf;
906 if (S_ISDIR (statBuf->st_mode)) {
908 } else if (S_ISREG (statBuf->st_mode)) {
909 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
911 } else if (S_ISSOCK (statBuf->st_mode)) {
913 #endif /* S_ISSOCK */