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
28 #include <stdlib.h> /* for qsort */
29 #include "../config.h"
31 #ifdef SEL_FILE_IGNORE_CASE
33 #endif /* def SEL_FILE_IGNORE_CASE */
39 #include <X11/Xaw/Scrollbar.h>
42 #define MAXPATHLEN 1024
43 #endif /* ndef MAXPATHLEN */
46 extern uid_t getuid();
47 #endif /* def HAS_DIRENT_H */
49 /* added missing prototypes */
50 extern void SFtextChanged();
51 extern int SFgetDir(SFDir *);
52 extern void SFdrawLists(int);
53 extern void SFdrawList(int, int);
54 extern void SFclearList(int, int);
55 extern void SFmotionList(Widget, int, XMotionEvent*);
68 int SFbuttonPressed = 0;
70 static int SFdoNotTouchDirPtr = 0;
72 static int SFdoNotTouchVorigin = 0;
74 static SFDir SFrootDir, SFhomeDir;
76 static SFLogin *SFlogins;
78 static int SFtwiddle = 0;
88 if (strcmp(path, SFcurrentDir)) {
91 (void) strncpy(SFcurrentDir, path, MAXPATHLEN);
107 for (j = dir->nEntries - 1; j >= 0; j--) {
108 if (dir->entries[j].shown != dir->entries[j].real) {
109 XtFree(dir->entries[j].shown);
111 XtFree(dir->entries[j].real);
114 XtFree((char *) dir->entries);
127 *s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
135 char *cannotOpen = "<cannot open> ";
137 dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
138 dir->entries[0].statDone = 1;
139 SFstrdup(&dir->entries[0].real, cannotOpen);
140 dir->entries[0].shown = dir->entries[0].real;
142 dir->nChars = strlen(cannotOpen);
146 #ifdef SEL_FILE_IGNORE_CASE
149 register char *p, *q;
152 register char c1, c2;
169 while ((--n >= 0) && (c1 == c2)) {
171 return strncmp(psave, qsave, nsave);
184 return strncmp(psave, qsave, nsave);
189 #endif /* def SEL_FILE_IGNORE_CASE */
198 text.length = strlen(path);
200 text.format = FMT8BIT;
202 XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
203 XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
209 SFreplaceText(dir, str)
217 if (str[len - 1] == '/') {
218 (void) strcat(SFcurrentPath, str);
220 (void) strncat(SFcurrentPath, str, len - 1);
222 if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
223 SFsetText(SFcurrentPath);
225 SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
238 char *name, *growing;
240 SFEntry *entry, *max;
244 dir = &(SFdirs[SFdirEnd - 1]);
246 if (dir->beginSelection == -1) {
248 SFreplaceText(dir, str);
251 } else if (dir->beginSelection == dir->endSelection) {
252 SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
256 max = &(dir->entries[dir->endSelection + 1]);
258 name = dir->entries[dir->beginSelection].shown;
259 SFstrdup(&growing, name);
263 entry = &(dir->entries[dir->beginSelection]);
264 while (entry < max) {
265 if (cmp = strncmp(growing, entry->shown, len)) {
274 * SFreplaceText() expects filename
276 growing[len - 2] = ' ';
278 growing[len - 1] = 0;
279 SFreplaceText(dir, growing);
288 register int i, last, max;
289 register char *name, save;
297 if (str[len - 1] == ' ') {
300 } else if (str[len - 1] == '/') {
306 entries = dir->entries;
310 name = entries[i].shown;
311 last = strlen(name) - 1;
315 #ifdef SEL_FILE_IGNORE_CASE
316 result = SFstrncmp(str, name, len);
317 #else /* def SEL_FILE_IGNORE_CASE */
318 result = strncmp(str, name, len);
319 #endif /* def SEL_FILE_IGNORE_CASE */
329 name = entries[i].shown;
330 last = strlen(name) - 1;
334 #ifdef SEL_FILE_IGNORE_CASE
335 result = SFstrncmp(str, name, len);
336 #else /* def SEL_FILE_IGNORE_CASE */
337 result = strncmp(str, name, len);
338 #endif /* def SEL_FILE_IGNORE_CASE */
350 (dir->beginSelection != begin) ||
351 (dir->endSelection != end - 1)
354 dir->beginSelection = begin;
355 if (str[strlen(str) - 1] == '/') {
356 dir->endSelection = begin;
358 dir->endSelection = end - 1;
362 if (dir->beginSelection != -1) {
364 dir->beginSelection = -1;
365 dir->endSelection = -1;
370 SFdoNotTouchVorigin ||
371 ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
373 SFdoNotTouchVorigin = 0;
378 if (i > max - SFlistSize) {
379 i = max - SFlistSize;
385 if (dir->vOrigin != i) {
398 dir = &(SFdirs[SFdirEnd - 1]);
399 if (dir->beginSelection != -1) {
402 dir->beginSelection = -1;
403 dir->endSelection = -1;
408 SFcompareLogins(p, q)
411 return strcmp(p->name, q->name);
420 SFEntry *entries = NULL;
427 entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
428 SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
429 entries[0].real = XtMalloc(3);
430 (void) strcpy(entries[0].real, "~");
431 entries[0].shown = entries[0].real;
432 entries[0].statDone = 1;
433 SFlogins[0].name = "";
434 pw = getpwuid((int) getuid());
435 SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
441 while ((pw = getpwent()) && (*(pw->pw_name))) {
444 entries = (SFEntry *) XtRealloc(
446 (unsigned) (alloc * sizeof(SFEntry))
448 SFlogins = (SFLogin *) XtRealloc(
450 (unsigned) (alloc * sizeof(SFLogin))
453 len = strlen(pw->pw_name);
454 entries[i].real = XtMalloc((unsigned) (len + 3));
455 (void) strcat(strcpy(entries[i].real, "~"),
457 entries[i].shown = entries[i].real;
458 entries[i].statDone = 1;
459 if (len > maxChars) {
462 SFstrdup(&SFlogins[i].name, pw->pw_name);
463 SFstrdup(&SFlogins[i].dir, pw->pw_dir);
467 SFhomeDir.dir = XtMalloc(1) ;
468 SFhomeDir.dir[0] = 0 ;
469 SFhomeDir.path = SFcurrentPath ;
470 SFhomeDir.entries = entries ;
471 SFhomeDir.nEntries = i ;
472 SFhomeDir.vOrigin = 0 ; /* :-) */
473 SFhomeDir.nChars = maxChars + 2 ;
474 SFhomeDir.hOrigin = 0 ;
475 SFhomeDir.changed = 1 ;
476 SFhomeDir.beginSelection = -1 ;
477 SFhomeDir.endSelection = -1 ;
479 qsort((char *) entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
480 qsort((char *) SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
482 for (i--; i >= 0; i--) {
483 (void) strcat(entries[i].real, "/");
489 SFfindHomeDir(begin, end)
499 for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
500 if (!strcmp(SFhomeDir.entries[i].real, begin)) {
502 SFstrdup(&theRest, end);
503 (void) strcat(strcat(strncpy(SFcurrentPath,SFlogins[i].dir,
507 SFsetText(SFcurrentPath);
522 static int wasTwiddle = 0;
526 int SFdirPtrSave, SFdirEndSave;
530 SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
532 SFstrdup(&dir->dir, "/");
534 (void) SFgetDir(dir);
535 for (j = 1; j < alloc; j++) {
536 SFdirs[j].dir = NULL;
538 dir->path = SFcurrentPath + 1;
542 dir->beginSelection = -1;
543 dir->endSelection = -1;
544 SFhomeDir.dir = NULL;
547 SFdirEndSave = SFdirEnd;
550 SFdirPtrSave = SFdirPtr;
555 if (SFcurrentPath[0] == '~') {
560 if (!SFhomeDir.dir) {
567 SFdoNotTouchDirPtr = 1;
576 end = SFcurrentPath + 1;
584 while (*end++ == '/') {
589 while ((*end) && (*end++ != '/')) {
592 if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
599 if (*(end - 1) == '/') {
603 if (SFfindHomeDir(begin, end)) {
611 SFdirs = (SFDir *) XtRealloc(
613 (unsigned) ((alloc *= 2) *
616 for (j = alloc / 2; j < alloc; j++) {
617 SFdirs[j].dir = NULL;
624 strcmp(dir->dir, begin)
630 SFstrdup(&dir->dir, begin);
635 dir->beginSelection = -1;
636 dir->endSelection = -1;
637 (void) SFfindFile(dir - 1, begin);
639 SFchdir(SFcurrentPath) ||
642 SFunreadableDir(dir);
651 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
660 if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
664 for (i = SFdirEnd; i < alloc; i++) {
670 if (SFdoNotTouchDirPtr) {
673 SFdirPtr = SFdirEnd - 1;
678 SFdirPtr = SFdirPtrSave;
680 SFdoNotTouchDirPtr = 0;
683 if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
684 XawScrollbarSetThumb(
686 (float) (((double) SFdirPtr) / SFdirEnd),
687 (float) (((double) ((SFdirEnd < NR) ? SFdirEnd : NR)) /
692 if (SFdirPtr != SFdirPtrSave) {
693 SFdrawLists(SF_DO_SCROLL);
695 for (i = 0; i < NR; i++) {
696 if (SFdirPtr + i < SFdirEnd) {
697 if (SFdirs[SFdirPtr + i].changed) {
698 SFdirs[SFdirPtr + i].changed = 0;
699 SFdrawList(i, SF_DO_SCROLL);
702 SFclearList(i, SF_DO_SCROLL);
711 SFbuttonPressList(w, n, event)
714 XButtonPressedEvent *event;
721 SFbuttonReleaseList(w, n, event)
724 XButtonReleasedEvent *event;
730 if (SFcurrentInvert[n] != -1) {
732 SFdoNotTouchDirPtr = 1;
734 SFdoNotTouchVorigin = 1;
735 dir = &(SFdirs[SFdirPtr + n]);
738 dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
740 SFmotionList(w, n, (XMotionEvent *) event);
753 (!stat(".", &statBuf)) &&
754 (statBuf.st_mtime != dir->mtime)
758 * If the pointer is currently in the window that we are about
759 * to update, we must warp it to prevent the user from
760 * accidentally selecting the wrong file.
762 if (SFcurrentInvert[n] != -1) {
766 XtWindow(selFileLists[n]),
776 for (i = dir->nEntries - 1; i >= 0; i--) {
777 if (dir->entries[i].shown != dir->entries[i].real) {
778 XtFree(dir->entries[i].shown);
780 XtFree(dir->entries[i].real);
782 XtFree((char *) dir->entries);
784 SFunreadableDir(dir);
786 if (dir->vOrigin > dir->nEntries - SFlistSize) {
787 dir->vOrigin = dir->nEntries - SFlistSize;
789 if (dir->vOrigin < 0) {
792 if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
793 dir->hOrigin = dir->nChars - SFcharsPerEntry;
795 if (dir->hOrigin < 0) {
798 dir->beginSelection = -1;
799 dir->endSelection = -1;
800 SFdoNotTouchVorigin = 1;
801 if ((dir + 1)->dir) {
802 (void) SFfindFile(dir, (dir + 1)->dir);
804 (void) SFfindFile(dir, dir->path);
807 if (!SFworkProcAdded) {
808 (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
818 /* Return a single character describing what kind of file STATBUF is. */
822 struct stat *statBuf;
824 if (S_ISDIR (statBuf->st_mode)) {
826 } else if (S_ISREG (statBuf->st_mode)) {
827 return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
829 } else if (S_ISSOCK (statBuf->st_mode)) {
831 #endif /* S_ISSOCK */
852 to = dir->vOrigin + SFlistSize;
853 if (to > dir->nEntries) {
857 for (i = from; i < to; i++) {
858 str = dir->entries[i].real;
859 last = strlen(str) - 1;
862 if (stat(str, &statBuf)) {
865 new = SFstatChar(&statBuf);
877 SFdirModTimer(cl, id)
886 if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
888 if ((n > NR-1) || (SFdirPtr + n >= SFdirEnd)) {
891 if ((f > NR-1) || (SFdirPtr + f >= SFdirEnd)) {
895 dir = &(SFdirs[SFdirPtr + n]);
898 if (SFchdir(SFcurrentPath)) {
910 SFcheckDir(n, dir) ||
911 ((f == n) && SFcheckFiles(dir))
913 SFdrawList(n, SF_DO_SCROLL);
918 SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
919 SFdirModTimer, (XtPointer) NULL);