5
* Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
7
* Permission to use, copy, modify, and distribute this software and its
8
* documentation for any purpose and without fee is hereby granted, provided
9
* that the above copyright notice appear in all copies and that both that
10
* copyright notice and this permission notice appear in supporting
11
* documentation, and that the name of Software Research Associates not be used
12
* in advertising or publicity pertaining to distribution of the software
13
* without specific, written prior permission. Software Research Associates
14
* makes no representations about the suitability of this software for any
15
* purpose. It is provided "as is" without express or implied warranty.
17
* SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
19
* IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
20
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23
* PERFORMANCE OF THIS SOFTWARE.
25
* Author: Erik M. van der Poel
26
* Software Research Associates, Inc., Tokyo, Japan
32
#ifdef SEL_FILE_IGNORE_CASE
34
#endif /* def SEL_FILE_IGNORE_CASE */
38
#include "SFinternal.h"
40
#include <X11/Xaw/Scrollbar.h>
42
#if defined(SVR4) || defined(SYSV) || defined(USG)
43
extern uid_t getuid();
45
#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
58
int SFbuttonPressed = 0;
60
static int SFdoNotTouchDirPtr = 0;
62
static int SFdoNotTouchVorigin = 0;
64
static SFDir SFrootDir, SFhomeDir;
66
static SFLogin *SFlogins;
68
static int SFtwiddle = 0;
70
void SFsetText(char *path);
80
if (strcmp(path, SFcurrentDir)) {
83
(void) strcpy(SFcurrentDir, path);
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);
118
*s1 = strcpy(XtMalloc((unsigned) (strlen(s2) + 1)), s2);
125
char *cannotOpen = "<cannot open> ";
127
dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
128
dir->entries[0].statDone = 1;
129
SFstrdup(&dir->entries[0].real, cannotOpen);
130
dir->entries[0].shown = dir->entries[0].real;
132
dir->nChars = strlen(cannotOpen);
135
#ifdef SEL_FILE_IGNORE_CASE
138
register char *p, *q;
141
register char c1, c2;
158
while ((--n >= 0) && (c1 == c2)) {
160
return strncmp(psave, qsave, nsave);
173
return strncmp(psave, qsave, nsave);
178
#endif /* def SEL_FILE_IGNORE_CASE */
181
SFreplaceText(dir, str)
189
if (str[len - 1] == '/') {
190
(void) strcat(SFcurrentPath, str);
192
(void) strncat(SFcurrentPath, str, len - 1);
194
if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
195
SFsetText(SFcurrentPath);
197
SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
209
char *name, *growing;
211
SFEntry *entry, *max;
215
dir = &(SFdirs[SFdirEnd - 1]);
217
if (dir->beginSelection == -1) {
219
SFreplaceText(dir, str);
222
} else if (dir->beginSelection == dir->endSelection) {
223
SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
227
max = &(dir->entries[dir->endSelection + 1]);
229
name = dir->entries[dir->beginSelection].shown;
230
SFstrdup(&growing, name);
234
entry = &(dir->entries[dir->beginSelection]);
235
while (entry < max) {
236
if (cmp = strncmp(growing, entry->shown, len)) {
245
* SFreplaceText() expects filename
247
growing[len - 2] = ' ';
249
growing[len - 1] = 0;
250
SFreplaceText(dir, growing);
259
register int i, last, max;
260
register char *name, save;
268
if (str[len - 1] == ' ') {
271
} else if (str[len - 1] == '/') {
277
entries = dir->entries;
281
name = entries[i].shown;
282
last = strlen(name) - 1;
286
#ifdef SEL_FILE_IGNORE_CASE
287
result = SFstrncmp(str, name, len);
288
#else /* def SEL_FILE_IGNORE_CASE */
289
result = strncmp(str, name, len);
290
#endif /* def SEL_FILE_IGNORE_CASE */
300
name = entries[i].shown;
301
last = strlen(name) - 1;
305
#ifdef SEL_FILE_IGNORE_CASE
306
result = SFstrncmp(str, name, len);
307
#else /* def SEL_FILE_IGNORE_CASE */
308
result = strncmp(str, name, len);
309
#endif /* def SEL_FILE_IGNORE_CASE */
321
(dir->beginSelection != begin) ||
322
(dir->endSelection != end - 1)
325
dir->beginSelection = begin;
326
if (str[strlen(str) - 1] == '/') {
327
dir->endSelection = begin;
329
dir->endSelection = end - 1;
333
if (dir->beginSelection != -1) {
335
dir->beginSelection = -1;
336
dir->endSelection = -1;
341
SFdoNotTouchVorigin ||
342
((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
344
SFdoNotTouchVorigin = 0;
349
if (i > max - SFlistSize) {
350
i = max - SFlistSize;
356
if (dir->vOrigin != i) {
369
dir = &(SFdirs[SFdirEnd - 1]);
370
if (dir->beginSelection != -1) {
373
dir->beginSelection = -1;
374
dir->endSelection = -1;
378
SFcompareLogins(const void *vp, const void *vq) {
379
SFLogin *p = (SFLogin *) vp, *q = (SFLogin *) vq;
380
return strcmp(p->name, q->name);
389
SFEntry *entries = NULL;
396
entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
397
SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
398
entries[0].real = XtMalloc(3);
399
(void) strcpy(entries[0].real, "~");
400
entries[0].shown = entries[0].real;
401
entries[0].statDone = 1;
402
SFlogins[0].name = "";
403
pw = getpwuid((int) getuid());
404
SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
410
while ((pw = getpwent()) && (*(pw->pw_name))) {
413
entries = (SFEntry *) XtRealloc(
415
(unsigned) (alloc * sizeof(SFEntry))
417
SFlogins = (SFLogin *) XtRealloc(
419
(unsigned) (alloc * sizeof(SFLogin))
422
len = strlen(pw->pw_name);
423
entries[i].real = XtMalloc((unsigned) (len + 3));
424
(void) strcat(strcpy(entries[i].real, "~"),
426
entries[i].shown = entries[i].real;
427
entries[i].statDone = 1;
428
if (len > maxChars) {
431
SFstrdup(&SFlogins[i].name, pw->pw_name);
432
SFstrdup(&SFlogins[i].dir, pw->pw_dir);
436
SFhomeDir.dir = XtMalloc(1) ;
437
SFhomeDir.dir[0] = 0 ;
438
SFhomeDir.path = SFcurrentPath ;
439
SFhomeDir.entries = entries ;
440
SFhomeDir.nEntries = i ;
441
SFhomeDir.vOrigin = 0 ; /* :-) */
442
SFhomeDir.nChars = maxChars + 2 ;
443
SFhomeDir.hOrigin = 0 ;
444
SFhomeDir.changed = 1 ;
445
SFhomeDir.beginSelection = -1 ;
446
SFhomeDir.endSelection = -1 ;
448
#if defined(SVR4) || defined(SYSV) || defined(USG)
449
qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
450
qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
451
#else /* defined(SVR4) || defined(SYSV) || defined(USG) */
452
qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
453
qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
454
#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
456
for (i--; i >= 0; i--) {
457
(void) strcat(entries[i].real, "/");
462
SFfindHomeDir(begin, end)
472
for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
473
if (!strcmp(SFhomeDir.entries[i].real, begin)) {
475
SFstrdup(&theRest, end);
476
(void) strcat(strcat(strcpy(SFcurrentPath,
477
SFlogins[i].dir), "/"), theRest);
479
SFsetText(SFcurrentPath);
493
static int wasTwiddle = 0;
497
int SFdirPtrSave, SFdirEndSave;
501
SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
503
SFstrdup(&dir->dir, "/");
505
(void) SFgetDir(dir);
506
for (j = 1; j < alloc; j++) {
507
SFdirs[j].dir = NULL;
509
dir->path = SFcurrentPath + 1;
513
dir->beginSelection = -1;
514
dir->endSelection = -1;
515
SFhomeDir.dir = NULL;
518
SFdirEndSave = SFdirEnd;
521
SFdirPtrSave = SFdirPtr;
526
if (SFcurrentPath[0] == '~') {
531
if (!SFhomeDir.dir) {
538
SFdoNotTouchDirPtr = 1;
547
end = SFcurrentPath + 1;
555
while (*end++ == '/') {
560
while ((*end) && (*end++ != '/')) {
563
if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
570
if (*(end - 1) == '/') {
574
if (SFfindHomeDir(begin, end)) {
582
SFdirs = (SFDir *) XtRealloc(
584
(unsigned) ((alloc *= 2) *
587
for (j = alloc / 2; j < alloc; j++) {
588
SFdirs[j].dir = NULL;
595
strcmp(dir->dir, begin)
601
SFstrdup(&dir->dir, begin);
606
dir->beginSelection = -1;
607
dir->endSelection = -1;
608
(void) SFfindFile(dir - 1, begin);
610
SFchdir(SFcurrentPath) ||
613
SFunreadableDir(dir);
622
if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
631
if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
635
for (i = SFdirEnd; i < alloc; i++) {
641
if (SFdoNotTouchDirPtr) {
644
SFdirPtr = SFdirEnd - 2;
649
SFdirPtr = SFdirPtrSave;
651
SFdoNotTouchDirPtr = 0;
654
if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
655
XawScrollbarSetThumb(
657
(float) (((double) SFdirPtr) / SFdirEnd),
658
(float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
663
if (SFdirPtr != SFdirPtrSave) {
664
SFdrawLists(SF_DO_SCROLL);
666
for (i = 0; i < 3; i++) {
667
if (SFdirPtr + i < SFdirEnd) {
668
if (SFdirs[SFdirPtr + i].changed) {
669
SFdirs[SFdirPtr + i].changed = 0;
670
SFdrawList(i, SF_DO_SCROLL);
673
SFclearList(i, SF_DO_SCROLL);
685
text.length = strlen(path);
687
text.format = FMT8BIT;
689
XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
690
XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
695
SFbuttonPressList(w, n, event)
698
XButtonPressedEvent *event;
705
SFbuttonReleaseList(w, n, event)
708
XButtonReleasedEvent *event;
714
if (SFcurrentInvert[n] != -1) {
716
SFdoNotTouchDirPtr = 1;
718
SFdoNotTouchVorigin = 1;
719
dir = &(SFdirs[SFdirPtr + n]);
722
dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
724
SFmotionList(w, n, event);
737
(!stat(".", &statBuf)) &&
738
(statBuf.st_mtime != dir->mtime)
742
* If the pointer is currently in the window that we are about
743
* to update, we must warp it to prevent the user from
744
* accidentally selecting the wrong file.
746
if (SFcurrentInvert[n] != -1) {
750
XtWindow(selFileLists[n]),
760
for (i = dir->nEntries - 1; i >= 0; i--) {
761
if (dir->entries[i].shown != dir->entries[i].real) {
762
XtFree(dir->entries[i].shown);
764
XtFree(dir->entries[i].real);
766
XtFree((char *) dir->entries);
768
SFunreadableDir(dir);
770
if (dir->vOrigin > dir->nEntries - SFlistSize) {
771
dir->vOrigin = dir->nEntries - SFlistSize;
773
if (dir->vOrigin < 0) {
776
if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
777
dir->hOrigin = dir->nChars - SFcharsPerEntry;
779
if (dir->hOrigin < 0) {
782
dir->beginSelection = -1;
783
dir->endSelection = -1;
784
SFdoNotTouchVorigin = 1;
785
if ((dir + 1)->dir) {
786
(void) SFfindFile(dir, (dir + 1)->dir);
788
(void) SFfindFile(dir, dir->path);
791
if (!SFworkProcAdded) {
792
SFworkProcId = XtAppAddWorkProc(SFapp, SFworkProc, NULL);
817
to = dir->vOrigin + SFlistSize;
818
if (to > dir->nEntries) {
822
for (i = from; i < to; i++) {
823
str = dir->entries[i].real;
824
last = strlen(str) - 1;
827
if (stat(str, &statBuf)) {
830
new = SFstatChar(&statBuf);
842
SFdirModTimer(cl, id)
851
if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
853
if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {
856
if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {
860
dir = &(SFdirs[SFdirPtr + n]);
863
if (SFchdir(SFcurrentPath)) {
875
SFcheckDir(n, dir) ||
876
((f == n) && SFcheckFiles(dir))
878
SFdrawList(n, SF_DO_SCROLL);
883
SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
884
SFdirModTimer, (XtPointer) NULL);
887
/* Return a single character describing what kind of file STATBUF is. */
891
struct stat *statBuf;
893
if (S_ISDIR (statBuf->st_mode)) {
895
} else if (S_ISREG (statBuf->st_mode)) {
896
return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
898
} else if (S_ISSOCK (statBuf->st_mode)) {
900
#endif /* S_ISSOCK */