1 /*********************************************************************/
2 /*  bibView: Administration of BibTeX-Databases                      */
3 /*           (Verwaltung von BibTeX-Literaturdatenbanken)            */
4 /*                                                                   */
5 /*  Module:  FileNom.c                                               */
6 /*                                                                   */
7 /*             - File Selection Box                                  */
8 /*               Adapted and modified Widget from aXe editor         */
9 /*                                                                   */
10 /*  Author:  Holger Martin,  martinh@informatik.tu-muenchen.de       */
11 /*           Peter M. Urban, urban@informatik.tu-muenchen.de         */
12 /*                                                                   */
13 /*  History:                                                         */
14 /*    11.22.91  HM   created                                         */
15 /*    05.26.92       Version 1.0 released                            */
16 /*                                                                   */
17 /*  Copyright 1992 TU MUENCHEN	                                     */
18 /*    See ./Copyright for complete rights and liability information. */
19 /*                                                                   */
20 /*********************************************************************/
21 
22 /*
23  * Copyright 1991 The University of Newcastle upon Tyne
24  *
25  * Permission to use, copy, modify and distribute this software and its
26  * documentation for any purpose other than its commercial exploitation
27  * is hereby granted without fee, provided that the above copyright
28  * notice appear in all copies and that both that copyright notice and
29  * this permission notice appear in supporting documentation, and that
30  * the name of The University of Newcastle upon Tyne not be used in
31  * advertising or publicity pertaining to distribution of the software
32  * without specific, written prior permission. The University of
33  * Newcastle upon Tyne makes no representations about the suitability of
34  * this software for any purpose. It is provided "as is" without express
35  * or implied warranty.
36  *
37  * THE UNIVERSITY OF NEWCASTLE UPON TYNE DISCLAIMS ALL WARRANTIES WITH
38  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
39  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
40  * NEWCASTLE UPON TYNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44  * PERFORMANCE OF THIS SOFTWARE.
45  *
46  * Author:  Jim Wight (j.k.wight@newcastle.ac.uk)
47  *          Computing Laboratory, University of Newcastle upon Tyne, UK
48  */
49 
50 #include <X11/IntrinsicP.h>
51 #include <X11/StringDefs.h>
52 #include <X11/Xaw/MenuButton.h>
53 #include <X11/Xaw/SimpleMenu.h>
54 #include <X11/Xaw/SmeBSB.h>
55 #include <X11/Xaw/Viewport.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Scrollbar.h>
58 #include <X11/Xaw/AsciiText.h>
59 #include <X11/Xaw/Command.h>
60 #include <X11/Xos.h>
61 
62 #include <sys/param.h>
63 #include <sys/stat.h>
64 #include <errno.h>
65 #ifndef HAVE_DIR
66 #include <dirent.h>
67 #include <limits.h> /* for _POSIX_PATH_MAX */
68 #include <stdlib.h> /* for `qsort'. */
69 #else
70 #include <sys/dir.h>
71 #define dirent direct
72 #include <limits.h> /* for _POSIX_PATH_MAX */
73 #include <stdlib.h> /* for `qsort'. */
74 #endif
75 #include <stdio.h>
76 #include <pwd.h>
77 
78 extern char *getenv();
79 
80 extern char *actual_path;
81 
82 
83 #include "FileNomP.h"
84 
85 #define Offset(field) XtOffsetOf(FileNominatorRec, fileNominator.field)
86 
87 #ifdef ACTION_PROBLEM
88 static int first_in = 1;
89 #endif
90 
91 static XtResource resources[] = {
92     {XtNselectCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
93 	 Offset(select_callback), XtRCallback, (XtPointer) NULL},
94     {XtNselectMenu, XtCSelectMenu, XtRString, sizeof(String),
95 	 Offset(select_menu), XtRString, (XtPointer) NULL},
96     {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
97 	 Offset(cancel_callback), XtRCallback, (XtPointer) NULL},
98     {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
99 	 Offset(margin), XtRImmediate, (XtPointer) 10},
100     {XtNnumberRows, XtCNumberStrings, XtRInt, sizeof(int),
101 	 Offset(number_rows), XtRImmediate, (XtPointer) 15},
102     {XtNshowDotFiles, XtCShowDotFiles, XtRBoolean, sizeof(Boolean),
103 	 Offset(show_dot_files), XtRImmediate, (XtPointer) True},
104     {XtNbellLevel, XtCBellLevel, XtRInt, sizeof(int),
105 	 Offset(bell_level), XtRImmediate, (XtPointer) 100},
106 };
107 
108 #undef Offset
109 
110 #define Child(w,child) (((FileNominatorWidget) w)->fileNominator.child)
111 #define List(w) (((FileNominatorWidget) w)->fileNominator.listList)
112 #define Rows(w) (((FileNominatorWidget) w)->fileNominator.number_rows)
113 #define CurrentDir(w) (((FileNominatorWidget) w)->fileNominator.currentDir)
114 #define WatchingChanges(w) (((FileNominatorWidget) w)->fileNominator.watchingChanges)
115 #define Nomination(w) (((FileNominatorWidget) w)->fileNominator.nomination)
116 #define ShowDotFiles(w) (((FileNominatorWidget) w)->fileNominator.show_dot_files)
117 #define BellLevel(w) (((FileNominatorWidget) w)->fileNominator.bell_level)
118 
119 
120 
121 static struct passwd *my_passwd;
122 
123 static char pathTranslations[] =
124     "<BtnDown>:reset() MakeMenu() XawPositionSimpleMenu(menu) MenuPopup(menu)";
125 
126 static char listTranslations[] =
127     "<Btn1Up>(2):         Set() Nominate() Unset()\n\
128      <Btn1Down>,<Btn1Up>: Set() Notify() \n\
129      <Btn2Up>:            Set() Notify() Nominate() Unset()";
130 
131 static char filenameTranslations[] =
132      "<Key>Return: Nominate() \n\
133       <Key>Escape: ToggleDotFiles()";
134 
135 static char selectTranslations[] =
136     "<Btn1Up>: Nominate() unset()";
137 
138 static char selectMenuTranslations[] =
139     "<Btn3Down>: XawPositionSimpleMenu(selectMenu) MenuPopup(selectMenu)";
140 
141 static void MakeMenu(), Nominate(), ToggleDotFiles();
142 
143 static XtActionsRec pathActions[] = {
144     "MakeMenu", MakeMenu,
145     "Nominate", Nominate,
146     "ToggleDotFiles", ToggleDotFiles,
147 };
148 
149 static void                     CancelCallback();
150 static void                     ChangeDir();
151 static void                     SelectDir();
152 static void                     FillWindow();
153 static void                     ReplaceFilename();
154 static void                     AsciiSourceChanged();
155 static void                     WatchForChanges();
156 static void                     DontWatchForChanges();
157 static void                     CollapsePath();
158 
159 static void Initialize(), PositionChildren(), Realize(), Destroy();
160 
161 FileNominatorClassRec fileNominatorClassRec = {
162     /* Core class part */
163   {
164     /* superclass	     */	(WidgetClass) &widgetClassRec,
165     /* class_name	     */ "FileNominator",
166     /* widget_size	     */ sizeof(FileNominatorRec),
167     /* class_initialize      */ NULL,
168     /* class_part_initialize */ NULL,
169     /* class_inited          */	FALSE,
170     /* initialize	     */	Initialize,
171     /* initialize_hook       */	NULL,
172     /* realize		     */	Realize,
173     /* actions		     */	NULL,
174     /* num_actions	     */	0,
175     /* resources	     */	resources,
176     /* num_resources	     */	XtNumber(resources),
177     /* xrm_class	     */	NULLQUARK,
178     /* compress_motion	     */	TRUE,
179     /* compress_exposure     */	XtExposeCompressMultiple,
180     /* compress_enterleave   */	TRUE,
181     /* visible_interest	     */	FALSE,
182     /* destroy		     */	Destroy,
183     /* resize		     */	PositionChildren,
184     /* expose		     */	NULL,
185     /* set_values	     */	NULL,
186     /* set_values_hook       */	NULL,
187     /* set_values_almost     */	XtInheritSetValuesAlmost,
188     /* get_values_hook       */	NULL,
189     /* accept_focus	     */	NULL,
190     /* version		     */	XtVersion,
191     /* callback offsets      */	NULL,
192     /* tm_table              */	NULL,
193     /* query_geometry	     */	XtInheritQueryGeometry,
194     /* display_accelerator   */	NULL,
195     /* extension	     */	NULL,
196   },
197    /* FileNominator class part */
198   {
199     /* extension	     */	NULL,
200   }
201 };
202 
203 WidgetClass fileNominatorWidgetClass = (WidgetClass) &fileNominatorClassRec;
204 
205 static void
CalculateSize(fnw,width,height)206 CalculateSize(fnw, width, height)
207     FileNominatorWidget fnw;
208     Dimension *width, *height;
209 {
210     int file_width = 2 * Child(fnw,filename_widget)->core.width +
211 	2 * Child(fnw,filename_widget)->core.border_width;
212     int select_width = 2 * Child(fnw,select_widget)->core.width +
213 	2 * Child(fnw,select_widget)->core.border_width + fnw->fileNominator.margin +
214 	    Child(fnw,cancel_widget)->core.width +
215 		2 * Child(fnw,cancel_widget)->core.border_width +
216 		    Child(fnw,path_widget)->core.width +
217 	2 * Child(fnw,path_widget)->core.border_width + fnw->fileNominator.margin;
218 
219     int max;
220 
221     if (fnw->fileNominator.margin == 0)
222     {
223 	max = select_width - 4 * (Child(fnw,select_widget)->core.border_width) >
224 	    file_width - 2 * Child(fnw,filename_widget)->core.border_width ?
225 		select_width - 4 * (Child(fnw,select_widget)->core.border_width) :
226 		    file_width - 2 * Child(fnw,filename_widget)->core.border_width;
227     }
228     else
229     {
230 	max = select_width > file_width ? select_width : file_width;
231     }
232     *width = max + 2 * fnw->fileNominator.margin;
233     *height = Child(fnw,viewport_widget)->core.height +
234 	    Child(fnw,filename_widget)->core.height +
235 		Child(fnw,select_widget)->core.height +
236 		    4 * fnw->fileNominator.margin;
237 
238     if (fnw->fileNominator.margin == 0)
239     {
240 	*height += 2 * (Child(fnw,filename_widget)->core.border_width);
241     }
242     else
243     {
244 	*height += 2 * (Child(fnw,filename_widget)->core.border_width +
245 		       Child(fnw,viewport_widget)->core.border_width +
246 		       Child(fnw,select_widget)->core.border_width);
247     }
248 }
249 
250 static void
PositionChildren(fnw)251 PositionChildren(fnw)
252     FileNominatorWidget fnw;
253 {
254     if (fnw->fileNominator.margin == 0)
255     {
256 	XtConfigureWidget(Child(fnw,filename_widget),
257 			  0, 0,
258 			  fnw->core.width,
259 			  fnw->core.height -
260 			  Child(fnw,viewport_widget)->core.height -
261 			  2 * Child(fnw,viewport_widget)->core.border_width -
262 			  Child(fnw,select_widget)->core.height,
263 			  0);
264     }
265     else
266     {
267           XtConfigureWidget(Child(fnw,filename_widget),
268 		      fnw->fileNominator.margin,
269 		      fnw->fileNominator.margin,
270 	              fnw->core.width -
271                       2 * fnw->fileNominator.margin -
272                       2 * Child(fnw,filename_widget)->core.border_width,
273 		      fnw->core.height -
274 		      2 * Child(fnw,filename_widget)->core.border_width -
275 		      Child(fnw,viewport_widget)->core.height -
276 		      2 * Child(fnw,viewport_widget)->core.border_width -
277 		      Child(fnw,select_widget)->core.height -
278 		      2 * Child(fnw,select_widget)->core.border_width -
279 		      4 * fnw->fileNominator.margin,
280 		      Child(fnw,filename_widget)->core.border_width);
281       }
282 
283     if (fnw->fileNominator.margin == 0)
284     {
285 	XtConfigureWidget(Child(fnw,viewport_widget),
286 			  -(Child(fnw,viewport_widget)->core.border_width),
287 			  Child(fnw,filename_widget)->core.height,
288 			  fnw->core.width,
289 			  Child(fnw,viewport_widget)->core.height,
290 			  Child(fnw,viewport_widget)->core.border_width);
291     }
292     else
293     {
294 	XtConfigureWidget(Child(fnw,viewport_widget),
295                           fnw->fileNominator.margin,
296 			  fnw->core.height -
297 			  Child(fnw,select_widget)->core.height -
298 			  2 * Child(fnw,select_widget)->core.border_width -
299 			  Child(fnw,viewport_widget)->core.height -
300 			  2 * Child(fnw,viewport_widget)->core.border_width -
301 			  2 * fnw->fileNominator.margin,
302 			  fnw->core.width -
303 			  2 * fnw->fileNominator.margin -
304 			  2 * Child(fnw,viewport_widget)->core.border_width,
305 			  Child(fnw,viewport_widget)->core.height,
306 			  Child(fnw,viewport_widget)->core.border_width);
307     }
308 
309     if (fnw->fileNominator.margin == 0)
310     {
311 	XtMoveWidget(Child(fnw,select_widget), -1,
312 		     fnw->core.height -
313 		     Child(fnw,select_widget)->core.height - 1);
314     }
315     else
316     {
317 	XtMoveWidget(Child(fnw,select_widget), fnw->fileNominator.margin,
318 		     fnw->core.height -
319 		     fnw->fileNominator.margin -
320 		     2 * Child(fnw,select_widget)->core.border_width -
321 		     Child(fnw,select_widget)->core.height);
322     }
323 
324 
325     if (fnw->fileNominator.margin == 0)
326     {
327 	XtMoveWidget(Child(fnw,path_widget),
328 		     Child(fnw,select_widget)->core.width,
329 		     fnw->core.height -
330 		     Child(fnw,select_widget)->core.height - 1);
331     }
332     else
333     {
334 	XtMoveWidget(Child(fnw,path_widget),
335 		     Child(fnw,select_widget)->core.width +
336 		     2 * Child(fnw,select_widget)->core.border_width +
337 		     2 * fnw->fileNominator.margin,
338 		     fnw->core.height -
339 		     fnw->fileNominator.margin -
340 		     2 * Child(fnw,select_widget)->core.border_width -
341 		     Child(fnw,select_widget)->core.height);
342     }
343 
344     if (fnw->fileNominator.margin == 0)
345     {
346 	XtMoveWidget(Child(fnw,cancel_widget),
347 		     Child(fnw,select_widget)->core.width +
348 		     Child(fnw,path_widget)->core.width +
349 		     Child(fnw,select_widget)->core.border_width,
350 		     fnw->core.height -
351 		     Child(fnw,select_widget)->core.height - 1);
352     }
353     else
354     {
355 	XtMoveWidget(Child(fnw,cancel_widget),
356 		     Child(fnw,path_widget)->core.width +
357 		     2 * Child(fnw,path_widget)->core.border_width +
358 		     Child(fnw,select_widget)->core.width +
359 		     2 * Child(fnw,select_widget)->core.border_width +
360 		     3 * fnw->fileNominator.margin,
361 		     fnw->core.height -
362 		     fnw->fileNominator.margin -
363 		     2 * Child(fnw,select_widget)->core.border_width -
364 		     Child(fnw,select_widget)->core.height);
365     }
366 }
367 
368 /* ARGSUSED */
369 static void
Initialize(req,new,args,num_args)370 Initialize(req, new, args, num_args)
371     Widget req, new;
372     ArgList args;
373     Cardinal *num_args;
374 {
375     FileNominatorWidget fnw = (FileNominatorWidget) new;
376     Widget sMenu, menuEntry;
377     String menuList, p, q;
378 
379     List(new) = NULL;
380     Nomination(new).directoryPart = NULL;
381     Nomination(new).filenamePart = NULL;
382 #ifdef SYSV
383     (void) getcwd(CurrentDir(new), MAXPATHLEN);
384 #else
385     (void) getwd(CurrentDir(new));
386 #endif
387 
388     if (actual_path==NULL){
389        actual_path = (char *) XtMalloc(MAXPATHLEN+1);
390        strcpy(actual_path, CurrentDir(new));
391        }
392     else{
393        if (CurrentDir(new)[strlen(CurrentDir(new)) - 1] != '/')
394           {
395   	   strcat(CurrentDir(new), "/");
396           }
397        if (*actual_path != '/'){
398           strcat(CurrentDir(new), actual_path);
399           strcpy(actual_path, CurrentDir(new));
400 	  CollapsePath(actual_path, CurrentDir(new));
401           }
402        else
403 	  CollapsePath(actual_path, CurrentDir(new));
404        }
405     if (CurrentDir(new)[strlen(CurrentDir(new)) - 1] != '/')
406     {
407 	strcat(CurrentDir(new), "/");
408     }
409     WatchingChanges(new) = False;
410 
411     Child(fnw,viewport_widget)
412 	= XtVaCreateWidget("viewport", viewportWidgetClass, new,
413 			   XtNallowVert, True,
414 			   XtNallowHoriz, True,
415 			   NULL);
416 
417     Child(fnw,list_widget) =
418 	XtVaCreateManagedWidget("list", listWidgetClass, Child(fnw,viewport_widget),
419 				XtNdefaultColumns, 1,
420 				XtNforceColumns, True,
421 				NULL);
422 
423     XtOverrideTranslations(Child(fnw,list_widget),
424 			   XtParseTranslationTable(listTranslations));
425     XtAddCallback(Child(fnw,list_widget), XtNcallback, ReplaceFilename, NULL);
426     FillWindow(fnw);
427 
428     Child(fnw,filename_widget)
429 	= XtVaCreateWidget("filename", asciiTextWidgetClass, new,
430 			   XtNeditType, XawtextEdit,
431 			   NULL);
432     XtOverrideTranslations(Child(fnw,filename_widget),
433 			   XtParseTranslationTable(filenameTranslations));
434 
435     XtSetKeyboardFocus(new, Child(fnw,filename_widget));
436     WatchForChanges(fnw);
437 
438     Child(fnw,select_widget)
439 	= XtVaCreateWidget("select", commandWidgetClass, new,
440                            XtNlabel,  "OK",
441 			   NULL);
442     XtOverrideTranslations(Child(fnw,select_widget),
443 			   XtParseTranslationTable(selectTranslations));
444     if (fnw->fileNominator.select_menu)
445     {
446 	sMenu = XtVaCreatePopupShell("selectMenu",
447 				     simpleMenuWidgetClass, Child(fnw,select_widget),
448 				     NULL);
449 	menuList = XtNewString(fnw->fileNominator.select_menu);
450 	p = menuList;
451 	for (p = menuList;  (q = (char *)index(p, ':'));  p = q + 1)
452 	{
453 	    *q = '\0';
454 	    menuEntry = XtVaCreateManagedWidget(p,
455 						smeBSBObjectClass, sMenu,
456 						NULL);
457 	    XtAddCallback(menuEntry, XtNcallback, SelectDir, NULL);
458 	}
459 	menuEntry = XtVaCreateManagedWidget(p,
460 					    smeBSBObjectClass, sMenu,
461 					    NULL);
462 	XtAddCallback(menuEntry, XtNcallback, SelectDir, NULL);
463 	XtVaSetValues(sMenu,
464 		      XtNpopupOnEntry, menuEntry,
465 		      NULL);
466 
467 	XtOverrideTranslations(Child(fnw,select_widget),
468 			      XtParseTranslationTable(selectMenuTranslations));
469 
470 	XtFree(menuList);
471     }
472 
473 #ifdef GERMAN
474     Child(fnw,path_widget)
475 	= XtVaCreateWidget("path", menuButtonWidgetClass, new,
476                            XtNlabel,  "Pfad",
477 			   NULL);
478 #else
479     Child(fnw,path_widget)
480 	= XtVaCreateWidget("path", menuButtonWidgetClass, new,
481                            XtNlabel,  "Path",
482 			   NULL);
483 #endif
484     XtOverrideTranslations(Child(fnw,path_widget),
485 			   XtParseTranslationTable(pathTranslations));
486 #ifdef ACTION_PROBLEM
487 if (first_in == 1){
488 #endif
489     XtAppAddActions(XtWidgetToApplicationContext(new),
490 		    pathActions, XtNumber(pathActions));
491     XawSimpleMenuAddGlobalActions(XtWidgetToApplicationContext(new));
492 #ifdef ACTION_PROBLEM
493     first_in = 0;
494     }
495 #endif
496 
497 #ifdef GERMAN
498     Child(fnw,cancel_widget)
499 	= XtVaCreateWidget("cancel", commandWidgetClass, new,
500                              XtNlabel,  "Abbruch",
501                              NULL);
502 #else
503     Child(fnw,cancel_widget)
504 	= XtVaCreateWidget("cancel", commandWidgetClass, new,
505                              XtNlabel,  "Cancel",
506                              NULL);
507 #endif
508     XtAddCallback(Child(fnw,cancel_widget), XtNcallback, CancelCallback, NULL);
509 
510     CalculateSize(fnw, &fnw->core.width, &fnw->core.height);
511     PositionChildren(fnw);
512 }
513 
514 static void
Realize(w,valueMask,attributes)515 Realize(w, valueMask, attributes)
516     Widget w;
517     XtValueMask *valueMask;
518     XSetWindowAttributes *attributes;
519 {
520     (*fileNominatorWidgetClass->core_class.superclass->core_class.realize)
521 	(w, valueMask, attributes);
522 
523     XtRealizeWidget(Child(w,viewport_widget));
524     XtRealizeWidget(Child(w,list_widget));
525     XtRealizeWidget(Child(w,filename_widget));
526     XtRealizeWidget(Child(w,select_widget));
527     XtRealizeWidget(Child(w,path_widget));
528     XtRealizeWidget(Child(w,cancel_widget));
529 
530     XMapSubwindows(XtDisplay(w), XtWindow(w));
531 }
532 
Destroy(w)533 static void Destroy(w)
534     Widget w;
535 {
536     int idx;
537     FileNominatorWidget fnw = (FileNominatorWidget) w;
538     XtDestroyWidget(Child(fnw,list_widget));
539     XtDestroyWidget(Child(fnw,viewport_widget));
540     XtDestroyWidget(Child(fnw,filename_widget));
541     XtDestroyWidget(Child(fnw,select_widget));
542     XtDestroyWidget(Child(fnw,path_widget));
543     XtDestroyWidget(Child(fnw,cancel_widget));
544 
545     idx = 0;
546     while (List(fnw)[idx])
547     {
548 	XtFree(List(fnw)[idx++]);
549     }
550     XtFree(List(fnw)[idx]);
551     XtFree((char *)List(fnw));
552 
553     strcpy(actual_path, Nomination(fnw).directoryPart);
554 
555     XtFree(Nomination(fnw).directoryPart);
556     XtFree(Nomination(fnw).filenamePart);
557 }
558 
559 /* ARGSUSED */
560 static void
CancelCallback(w,client_data,call_data)561 CancelCallback(w, client_data, call_data)
562      Widget w;
563      XtPointer client_data, call_data;
564 {
565     XtCallCallbacks(XtParent(w), XtNcancelCallback, NULL);
566 }
567 
568 /* ARGSUSED */
569 static void
DestroyMenu(w,client_data,call_data)570 DestroyMenu(w, client_data, call_data)
571      Widget w;
572      XtPointer client_data, call_data;
573 {
574     XtDestroyWidget(w);
575 }
576 
577 /* ARGSUSED */
578 static void
MakeMenu(w,event,params,num_params)579 MakeMenu(w, event, params, num_params)
580      Widget w;
581      XEvent *event;
582      String *params;
583      Cardinal *num_params;
584 {
585     FileNominatorWidget fnw = (FileNominatorWidget) XtParent(w);
586     String menuName;
587     Widget menu, menuEntry;
588     char *where, *p1, *p2;
589     int menuItem = 1, len;
590 
591     XtVaGetValues(w,
592 		  XtNmenuName, &menuName,
593 		  NULL);
594 
595     menu = XtVaCreatePopupShell(menuName,
596 				simpleMenuWidgetClass, w,
597 				NULL);
598     XtAddCallback(menu, XtNpopdownCallback, DestroyMenu, NULL);
599 
600     where = XtNewString(CurrentDir(fnw));
601     menuEntry = XtVaCreateManagedWidget("/",
602 					smeBSBObjectClass, menu, NULL);
603     XtAddCallback(menuEntry, XtNcallback, ChangeDir, (XtPointer) menuItem++);
604     p1 = where + 1;
605     len = strlen(where);
606     while (p1 < &where[len])
607     {
608 	if (!(p2 = (char *)index(p1, '/')))
609 	{
610 	    p2 = &where[len];
611 	}
612 	*p2 = '\0';
613 	menuEntry = XtVaCreateManagedWidget(p1,
614 					    smeBSBObjectClass, menu, NULL);
615 	XtAddCallback(menuEntry, XtNcallback, ChangeDir,
616 		      (XtPointer) menuItem++);
617 	p1 = p2 + 1;
618     }
619 
620     XtVaSetValues(menu,
621 		  XtNpopupOnEntry, menuEntry,
622 		  NULL);
623 
624     XtFree(where);
625 }
626 
627 static void
ChangeDirectory(fnw,position)628 ChangeDirectory(fnw, position)
629      FileNominatorWidget fnw;
630      int position;
631 {
632     String p;
633     int m;
634 
635     if (position > 0)
636     {
637 	p = CurrentDir(fnw);
638 	for (m = 0;  m < position;  ++m)
639 	{
640 	    while(*p++ != '/')
641 		;
642 	}
643 	*p = '\0';
644     }
645 
646     XtVaSetValues(Child(fnw, filename_widget),
647 		  XtNstring, "",
648 		  NULL);
649 
650     FillWindow(fnw);
651 
652     PositionChildren(fnw);
653 }
654 
655 /* ARGSUSED */
656 static void
ChangeDir(w,client_data,call_data)657 ChangeDir(w, client_data, call_data)
658      Widget w;
659      XtPointer client_data, call_data;
660 {
661     FileNominatorWidget fnw
662         = (FileNominatorWidget) XtParent(XtParent(XtParent(w)));
663 
664     ChangeDirectory(fnw, (int) client_data);
665 }
666 
667 /* ARGSUSED */
668 static void
SelectDir(w,client_data,call_data)669 SelectDir(w, client_data, call_data)
670      Widget w;
671      XtPointer client_data, call_data;
672 {
673     FileNominatorWidget fnw
674         = (FileNominatorWidget) XtParent(XtParent(XtParent(w)));
675     String label;
676 
677     XtVaGetValues(w,
678 		  XtNlabel, &label,
679 		  NULL);
680 
681     XtVaSetValues(Child(fnw,filename_widget),
682 		  XtNstring, label,
683 		  NULL);
684 
685     Nominate(Child(fnw,select_widget), NULL, NULL, NULL);
686 }
687 
688 /* ARGSUSED */
689 static void
Nominate(w,event,params,num_params)690 Nominate(w, event, params, num_params)
691      Widget w;
692      XEvent *event;
693      String *params;
694      Cardinal *num_params;
695 {
696     FileNominatorWidget fnw;
697     char *nomination, *home, *name_ende, selection[MAXPATHLEN], *newPath, *r;
698     struct stat fstats;
699     int status, len;
700 
701     if (XtIsSubclass(w, listWidgetClass))
702     {
703 	fnw = (FileNominatorWidget) XtParent(XtParent(w));
704     }
705     else
706     {
707 	fnw = (FileNominatorWidget) XtParent(w);
708     }
709 
710     XtVaGetValues(Child(fnw,filename_widget),
711 		  XtNstring, &nomination,
712 		  NULL);
713 
714     selection[0] = '\0';
715     if (*nomination == '/')
716     {
717 	strcpy(selection, nomination);
718     }
719     else if (*nomination == '~' && *(nomination+1) == '\0' &&
720 	    (home = getenv("HOME")))
721     {
722 	strcpy(selection, home);
723 	strcat(selection, &nomination[1]);
724     }
725     else if (*nomination == '~')
726     {   name_ende  = strchr(nomination, '/');
727 	if (name_ende != NULL){
728 	   *name_ende = '\0';
729 	   name_ende++;
730         }
731 	my_passwd = getpwnam (&nomination[1]);
732 	if (my_passwd!=NULL){
733 	   strcpy(selection, my_passwd->pw_dir);
734 	   if (name_ende != NULL){
735               strcat(selection, "/");
736 	      strcat(selection, name_ende);
737 	      }
738            }
739         else if (home = getenv("HOME"))
740 	   strcpy(selection, home);
741 
742     }
743     else
744     {
745 	if (strlen(CurrentDir(fnw)) > 1)
746 	{
747 	    strcpy(selection, CurrentDir(fnw));
748 	}
749 	strcat(selection, "/");
750 	strcat(selection, nomination);
751     }
752 
753     len = strlen(selection);
754     if (len != 0)
755     {
756 	newPath = (char *) XtMalloc(len + 2);
757 	CollapsePath(selection, newPath);
758 	status = stat(newPath, &fstats);
759 	if (status != -1 && fstats.st_mode & S_IFDIR)
760 	{
761 	    if (access(newPath, R_OK) == 0)
762 	    {
763 		if (newPath[strlen(newPath) - 1] != '/')
764 		{
765 		    strcat(newPath, "/");
766 		}
767 		strcpy(CurrentDir(fnw), newPath);
768 		ChangeDirectory(fnw, 0);
769 	    }
770 	    else
771 	    {
772 		XBell(XtDisplay(fnw), BellLevel(fnw));
773 	    }
774 	}
775 	else if (status == 0 || (status == -1 && errno == ENOENT))
776 	{
777 	    status = access(newPath, R_OK | W_OK);
778 	    r = (char *)rindex(newPath, '/');
779 	    XtFree(Nomination(fnw).filenamePart);
780 	    Nomination(fnw).filenamePart = XtNewString(r + 1);
781 	    Nomination(fnw).filenameStatus = (status == 0) ? status : errno;
782 	    *(r + 1) = '\0';
783 	    XtFree(Nomination(fnw).directoryPart);
784 	    status = access(newPath, R_OK);
785 	    if (strcmp(newPath, CurrentDir(fnw)) != 0 && status == 0)
786 	    {
787 		strcpy(CurrentDir(fnw), newPath);
788 		ChangeDirectory(fnw, 0);
789 		Nomination(fnw).directoryPart = XtNewString(CurrentDir(fnw));
790 	    }
791 	    else
792 	    {
793 		Nomination(fnw).directoryPart = XtNewString(newPath);
794 	    }
795 	    Nomination(fnw).directoryStatus = (status == 0) ? status : errno;
796 	    XtCallCallbacks((Widget) fnw, XtNselectCallback,
797 			                        (XtPointer) &Nomination(fnw));
798 	}
799 	else
800 	{
801             XBell(XtDisplay(fnw), BellLevel(fnw));
802 	}
803 	XtFree(newPath);
804     }
805 }
806 
807 #ifndef HAVE_DIR
808 /* Comparison function for dirent*, used by `qsort'. */
809 static int
direntpcmp(i,j)810 direntpcmp( i, j)
811 struct dirent **i, **j;
812 {
813     return (strcmp ((*i)->d_name, (*j)->d_name ));
814 }
815 #endif
816 
817 static void
FillWindow(fnw)818 FillWindow(fnw)
819     Widget fnw;
820 {
821     XFontStruct *font;
822     Dimension height, internalHeight, rowSpacing;
823     int num, newNum, idx;
824     struct dirent  **namelist;
825 #ifndef HAVE_DIR
826     DIR *dirp;
827     struct dirent *direntp;
828     int direntp_size;
829 #else
830     extern int alphasort();
831 #endif
832     char buf[MAXPATHLEN], *bp;
833     String name;
834     struct stat fstats;
835     unsigned int namlen;
836 #ifdef HAVE_DIR
837     num = scandir(CurrentDir(fnw), &namelist, (int(*)())0, alphasort);
838 #else
839     /* Read the directory `CurrentDir(fnw)'
840        and set the `dirent's in `namelist'. */
841        dirp = opendir( CurrentDir(fnw) );
842        direntp_size = sizeof(struct dirent)+ _POSIX_PATH_MAX;
843        direntp = (struct dirent *)XtMalloc( direntp_size );
844        /* Read the directory a first time, to get              */
845        /* the number `num' of entries and to allocate namedir. */
846        num = 0;
847        while ( (direntp = readdir(dirp)) != NULL ) num++;
848        namelist = (struct dirent **)XtMalloc( (num+1)*sizeof(struct dirent *));
849        num = 0;
850        rewinddir( dirp );
851        while ( TRUE ) {
852 	 if ( (direntp = readdir(dirp)) == NULL ) break;
853 	 namelist[num] = (struct dirent *) XtMalloc(direntp_size);
854 	 bcopy(direntp, namelist[num], direntp_size);
855 	 num++;
856 	 direntp = (struct dirent *)XtMalloc( direntp_size );
857        }
858        XtFree( (char *)direntp );
859        (void)closedir( dirp );
860 
861     /* Sort the directory entries in `namelist'. */
862        qsort( namelist, num, sizeof(struct dirent*), direntpcmp );
863 #endif
864 
865     if (num <= 0)
866     {
867 	return;
868     }
869 
870     if (List(fnw))
871     {
872         idx = 0;
873         while (List(fnw)[idx])
874         {
875             XtFree(List(fnw)[idx++]);
876         }
877 	XtFree(List(fnw)[idx]);
878 	XtFree((char *)List(fnw));
879     }
880     List(fnw) = (String *) XtMalloc((num + 1) * sizeof(String));
881 
882     strcpy(buf, CurrentDir(fnw));
883     strcat(buf, "/");
884     bp = buf + strlen(buf);
885     for(idx = 0, newNum = 0; idx < num;  idx++)
886     {
887 	name = namelist[idx]->d_name;
888 	if (ShowDotFiles(fnw) || (!ShowDotFiles(fnw) &&
889 				  (*name != '.'
890 				  || ((strcmp(name, ".") == 0) ||
891 				      (strcmp(name, "..") == 0)))))
892 	{
893 	    List(fnw)[newNum] = XtMalloc(strlen(name) + 2);
894 	    strcpy(List(fnw)[newNum], name);
895 	    strcpy(bp, name);
896 	    (void) stat(buf, &fstats);
897 	    if (fstats.st_mode & S_IFDIR)
898 	    {
899 		strcat(List(fnw)[newNum], "/");
900 	    }
901 	    ++newNum;
902 	}
903     }
904 
905     for(idx = 0; idx < num;  idx++)
906     {
907 	XtFree((char *)namelist[idx]);
908     }
909     XtFree((char *)namelist);
910 
911     List(fnw)[newNum] = NULL;
912 
913     XtVaGetValues(Child(fnw,list_widget),
914                   XtNfont, &font,
915                   XtNinternalHeight, &internalHeight,
916 		  XtNrowSpacing, &rowSpacing,
917                   NULL);
918 
919     height = Rows(fnw) * (font->max_bounds.ascent +
920 		     font->max_bounds.descent + rowSpacing) -
921 			 rowSpacing + 2 * internalHeight;
922 
923     XtVaSetValues(Child(fnw,viewport_widget),
924                   XtNheight, height,
925                   NULL);
926 
927     XawListChange(Child(fnw,list_widget), List(fnw), newNum, -1, True);
928 }
929 
930 /* ARGSUSED */
931 static void
ToggleDotFiles(w,event,params,num_params)932 ToggleDotFiles(w, event, params, num_params)
933      Widget w;
934      XEvent *event;
935      String *params;
936      Cardinal *num_params;
937 {
938     Widget fnw = XtParent(w);
939     Boolean showDotFiles;
940 
941     XtVaGetValues(fnw,
942 		  XtNshowDotFiles, &showDotFiles,
943 		  NULL);
944 
945     XtVaSetValues(fnw,
946 		  XtNshowDotFiles, !showDotFiles,
947 		  NULL);
948 
949     XtVaSetValues(w,
950 		  XtNstring, "./",
951 		  NULL);
952 
953     Nominate(Child(fnw,select_widget), NULL, NULL, NULL);
954 }
955 
956 /* ARGSUSED */
957 static void
ReplaceFilename(w,client_data,call_data)958 ReplaceFilename(w, client_data, call_data)
959      Widget w;
960      XtPointer client_data, call_data;
961 {
962     FileNominatorWidget fnw
963 	= (FileNominatorWidget) XtParent(XtParent(w));
964 
965     XawListReturnStruct *list = XawListShowCurrent(Child(fnw,list_widget));
966 
967     XtVaSetValues(Child(fnw,filename_widget),
968 		  XtNstring, list->string,
969 		  NULL);
970 
971     XawTextSetInsertionPoint(Child(fnw,filename_widget),
972 			     (XawTextPosition) strlen(list->string));
973 
974     WatchForChanges(fnw);
975 }
976 
977 /* ARGSUSED */
978 static void
AsciiSourceChanged(w,client_data,call_data)979 AsciiSourceChanged(w, client_data, call_data)
980 Widget w;
981 XtPointer client_data, call_data;
982 {
983     FileNominatorWidget fnw = (FileNominatorWidget) client_data;
984 
985     DontWatchForChanges(fnw);
986 
987     XawListUnhighlight(Child(fnw,list_widget));
988 }
989 
990 static void
WatchForChanges(fnw)991 WatchForChanges(fnw)
992      Widget fnw;
993 {
994     if (!WatchingChanges(fnw))
995     {
996 	XtAddCallback(XawTextGetSource(Child(fnw,filename_widget)), XtNcallback,
997 		      AsciiSourceChanged, (XtPointer) fnw);
998 
999 	WatchingChanges(fnw) = True;
1000     }
1001 }
1002 
1003 static void
DontWatchForChanges(fnw)1004 DontWatchForChanges(fnw)
1005      Widget fnw;
1006 {
1007     XtRemoveCallback(XawTextGetSource(Child(fnw,filename_widget)), XtNcallback,
1008 		     AsciiSourceChanged, (XtPointer) fnw);
1009 
1010     WatchingChanges(fnw) = False;
1011 }
1012 
1013 static void
CollapsePath(in,out)1014 CollapsePath(in, out)
1015      char *in, *out;
1016 {
1017     char *p = in, *q = out, *pend = p + strlen(p);
1018 
1019     while (p < pend)
1020     {
1021 	if (*p != '/')
1022 	{
1023 	    *q++ = *p++;
1024 	}
1025 	else if (p + 1 < pend && *(p + 1) == '/')
1026 	{
1027 	    ++p;
1028 	}
1029 	else if ( (p + 2 == pend && *(p + 1) == '.') ||
1030 		  (p + 2 < pend && *(p + 1) == '.' && *(p + 2) == '/') )
1031 	{
1032 	    p += 2;
1033 	}
1034 	else if ( (p + 3 == pend && *(p + 1) == '.' && *(p + 2) == '.') ||
1035 		 (p + 3 < pend && *(p + 1) == '.'
1036 		                      && *(p + 2) == '.' && *(p + 3) == '/') )
1037 	{
1038 	    while (q > out && *--q != '/')
1039 		;
1040 	    p += 3;
1041 	}
1042 	else
1043 	{
1044 	    *q++ = *p++;
1045 	}
1046     }
1047     if (q == out)
1048     {
1049 	*q++ = '/';
1050     }
1051 
1052     while (q > out)
1053     {
1054 	if (*--q != '/')
1055 	    break;
1056     }
1057     *++q = '\0';
1058 }
1059 
1060 String
FileNominatorGetDirectory(fnw)1061 FileNominatorGetDirectory(fnw)
1062      Widget fnw;
1063 {
1064     if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1065     {
1066 	return CurrentDir(fnw);
1067     }
1068     else
1069     {
1070 	return NULL;
1071     }
1072 }
1073 
1074 String
FileNominatorGetFileName(fnw)1075 FileNominatorGetFileName(fnw)
1076 Widget fnw;
1077 {
1078     String newName;
1079 
1080     if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1081     {
1082 
1083       FileNominatorStruct data =  Nomination(fnw);
1084 
1085       if (data.directoryStatus == 0)
1086       {
1087 	newName = XtMalloc(strlen(data.filenamePart) + 1);
1088 	strcpy(newName, data.filenamePart);
1089 	strcpy(actual_path, data.directoryPart);
1090         return newName;
1091       }
1092       else
1093 	return NULL;
1094     }
1095     else
1096     {
1097 	return NULL;
1098     }
1099 }
1100 
1101 String
FileNominatorGetFullFileName(fnw)1102 FileNominatorGetFullFileName(fnw)
1103      Widget fnw;
1104 {
1105     String newName;
1106 
1107     if (XtIsSubclass(fnw, fileNominatorWidgetClass))
1108     {
1109 
1110       FileNominatorStruct data =  Nomination(fnw);
1111 
1112       if (data.directoryStatus == 0)
1113       {
1114 	newName = XtMalloc(strlen(data.directoryPart)
1115 			   + strlen(data.filenamePart) + 1);
1116 	strcpy(newName, data.directoryPart);
1117 	strcat(newName, data.filenamePart);
1118 	strcpy(actual_path, data.directoryPart);
1119         return newName;
1120       }
1121       else
1122 	return NULL;
1123     }
1124     else
1125     {
1126 	return NULL;
1127     }
1128 }
1129 
1130 
1131 void
FileNominatorSetDirectory(fnw,dir)1132 FileNominatorSetDirectory(fnw, dir)
1133      Widget fnw;
1134      String dir;
1135 {
1136     if (!XtIsSubclass(fnw, fileNominatorWidgetClass))
1137     {
1138 	return;
1139     }
1140 
1141     /* Should do more checks */
1142     strcpy(CurrentDir(fnw), dir);
1143     if (dir[strlen(dir) - 1] != '/')
1144     {
1145 	strcat(CurrentDir(fnw), "/");
1146     }
1147 
1148     ChangeDirectory(fnw, 0);
1149 }
1150