1 /*************************************************************************
2
3 XEDITOR.C -- Simple text editor for JSPICE3
4 Copyright (C) Stephen R. Whiteley 1995, All rights reserved
5 Version 1.0 1/17/95
6
7 *************************************************************************/
8
9 #ifdef SPICE_MAKE
10 #include "spice.h"
11 #include "ftedefs.h"
12 #include "spfteext.h"
13 #else
14 #define HAVE_X11
15 #endif
16
17 #ifdef HAVE_X11
18
19 #include <stdio.h>
20 #include <signal.h>
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <pwd.h>
26
27 #include <X11/Intrinsic.h>
28 #include <X11/StringDefs.h>
29 #include <X11/Xaw/Paned.h>
30 #include <X11/Xaw/AsciiText.h>
31 #include <X11/Xaw/Label.h>
32 #include <X11/Xaw/Viewport.h>
33 #include <X11/Xaw/Command.h>
34 #include <X11/Xaw/Box.h>
35 #include <X11/Shell.h>
36
37 typedef enum {QUIT, SAVE, SAVEAS, SOURCE, LOAD, TEXTMOD} event_type;
38
39 #ifdef STAND_ALONE
40 typedef enum {NOGO, NO_EXIST, READ_OK, WRITE_OK} check_type;
41 typedef struct {
42 Widget shell;
43 Widget form;
44 Widget text;
45 Widget title;
46 Widget butbox;
47 Widget popup;
48 Widget popup_text;
49 Widget message;
50 Atom wm_delete;
51 String *popup_sens_list;
52 Bool TextChanged;
53 event_type Last;
54 String saved_as;
55 } widget_bag;
56
57 #else
58 #define XEDITOR
59 #include "x11util.h"
60 #endif
61
62 #ifdef __STDC__
63 extern int xeditor(char*);
64 #else
65 extern int xeditor();
66 #endif
67
68 #ifdef __STDC__
69 static char *nextarg(void);
70 static int errorhandler(Display*, XErrorEvent*);
71 static void CRaction(Widget, XEvent*, String*, Cardinal*);
72 static void QUaction(Widget, XEvent*, String*, Cardinal*);
73 static void Quit(Widget, XtPointer, XtPointer);
74 static void Save(Widget, XtPointer, XtPointer);
75 static void SaveAs(Widget, XtPointer, XtPointer);
76 static void Source(Widget, XtPointer, XtPointer);
77 static void Load(Widget, XtPointer, XtPointer);
78 static void Change(Widget, XtPointer, XtPointer);
79 static void DoSaveAs(Widget, XtPointer, XtPointer);
80 static Bool same(char*, char*);
81 static void DoLoad(Widget, XtPointer, XtPointer);
82 #ifdef STAND_ALONE
83 static void PopUpInput(String, String, void(*)(), widget_bag*);
84 static void PopDownInput(Widget, XtPointer, XtPointer);
85 static void PopUpMessage(String, widget_bag*);
86 static void PopDownMessage(Widget, XtPointer, XtPointer);
87 static void CenterWidgetOnWidget(Widget, Widget);
88 static check_type CheckFile(char*, int, widget_bag*);
89 static void ToTop(Widget, XtPointer, XEvent*, Boolean*);
90 static char *tilde_expand(char*);
91 #endif
92 static void PopUpHelp(Widget, XtPointer, XtPointer);
93 static void PopDownHelp(Widget, XtPointer, XtPointer);
94
95 #else
96
97 static char *nextarg();
98 static int errorhandler();
99 static void CRaction();
100 static void QUaction();
101 static void Quit();
102 static void Save();
103 static void SaveAs();
104 static void Source();
105 static void Load();
106 static void Change();
107 static void DoSaveAs();
108 static Bool same();
109 static void DoLoad();
110 #ifdef STAND_ALONE
111 static void PopUpInput();
112 static void PopDownInput();
113 static void PopUpMessage();
114 static void PopDownMessage();
115 static void CenterWidgetOnWidget();
116 static check_type CheckFile();
117 static void ToTop();
118 static char *tilde_expand();
119 #endif
120 static void PopUpHelp();
121 static void PopDownHelp();
122 #endif
123
124 #ifdef STAND_ALONE
125 Display *Xdisplay;
126 #else
127 extern Display *Xdisplay;
128 #endif
129
130 static char *oneLineTranslations =
131 "<Key>Return: cr_action()\n<Key>Delete: delete-next-character()";
132 static char *textTranslations = "<Key>Delete: delete-next-character()";
133 static char *butTranslations = "<Btn1Up>: notify() reset()";
134 static char *wmTranslations = "<Message>WM_PROTOCOLS: quit_action()";
135 static char *sens_list[] = {"save_as", "load", 0};
136
137 #ifdef STAND_ALONE
138
139 static String fallback_resources[] = {
140
141 "xeditor.xeditor.background: lightgrey",
142 "xeditor.xeditor.buttonbox.background: lightblue",
143 "xeditor.xeditor.buttonbox.Command.background: yellow",
144
145 "xeditor.popup.form.background: lightblue",
146 "xeditor.popup.form.Command.background: yellow",
147 "xeditor.popup.form.Label.background: pink",
148
149 "xeditor.popup_m.form_m.background: pink",
150 "xeditor.popup_m.form_m.Command.background: yellow",
151
152 "xeditor.popup_h.form_h.background: lightgrey",
153 "xeditor.popup_h.form_h.buttonbox.background: lightblue",
154 "xeditor.popup_h.form_h.buttonbox.Command.background: yellow",
155 "xeditor.popup_h.form_h.buttonbox.Label.background: pink",
156 NULL
157 };
158
159 static XtActionsRec actions[] = {
160 {"cr_action", CRaction},
161 {"quit_action", QUaction}
162 };
163
164 int NumArgs;
165 char **Args;
166
167
168 int
main(argc,argv)169 main(argc, argv)
170
171 int argc;
172 char **argv;
173 {
174 XtAppContext app_con;
175
176 /* initialize X toolkit */
177 XtToolkitInitialize();
178 app_con = XtCreateApplicationContext();
179 XtAppSetFallbackResources(app_con, fallback_resources);
180 Xdisplay = XtOpenDisplay(app_con, NULL, NULL, "Xeditor", NULL, 0,
181 &argc, argv);
182 if (!Xdisplay) {
183 fprintf(stderr, "Error: can't open display\n");
184 exit(1);
185 }
186 XtAppAddActions(app_con, actions, XtNumber(actions));
187 XSetErrorHandler(errorhandler);
188
189 NumArgs = argc;
190 Args = argv;
191 if (NumArgs > 1) {
192 Args++;
193 NumArgs--;
194 xeditor(*Args);
195 }
196 else
197 xeditor(NULL);
198 XtAppMainLoop(app_con);
199 return (0);
200 }
201
202
203 static char *
nextarg()204 nextarg()
205 {
206 if (NumArgs > 1) {
207 Args++;
208 NumArgs--;
209 return (*Args);
210 }
211 return ("");
212 }
213
214
215 static int
errorhandler(display,errorev)216 errorhandler(display, errorev)
217
218 Display *display;
219 XErrorEvent *errorev;
220 {
221 char ErrorMessage[1024];
222
223 XGetErrorText(display, errorev->error_code, ErrorMessage, 1024);
224 printf(ErrorMessage);
225 return (0);
226 }
227 #endif
228
229
230 static void
CRaction(caller,call_data,params,numparams)231 CRaction(caller, call_data, params, numparams)
232
233 Widget caller;
234 XEvent *call_data;
235 String *params;
236 Cardinal *numparams;
237 {
238 /* simulate a button press when CR entered in text of popup */
239 Widget action = XtNameToWidget(XtParent(caller), "action");
240
241 if (action)
242 XtCallCallbacks(action, XtNcallback, NULL);
243 }
244
245
246 static void
QUaction(caller,call_data,params,numparams)247 QUaction(caller, call_data, params, numparams)
248
249 Widget caller;
250 XEvent *call_data;
251 String *params;
252 Cardinal *numparams;
253 {
254 /* simulate a Quit button press when DeleteWindow requested */
255 Widget quit;
256
257 quit = XtNameToWidget(caller, "xeditor.buttonbox.quit");
258 if (!quit)
259 quit = XtNameToWidget(caller, "form.cancel");
260 if (!quit)
261 quit = XtNameToWidget(caller, "form_h.buttonbox.cancel_h");
262 if (!quit)
263 quit = XtNameToWidget(caller, "form_m.cancel_m");
264
265 if (quit)
266 XtCallCallbacks(quit, XtNcallback, NULL);
267 }
268
269
270 int
xeditor(fname)271 xeditor(fname)
272 char *fname;
273
274 /* Create a new window... */
275 {
276 Widget button;
277 widget_bag *w;
278 check_type which;
279 char buf[256];
280 static char tmpl[] = "/tmp/xeXXXXXX";
281
282 /* Assume Xt toolkit is initialized! */
283 w = (widget_bag*) XtMalloc(sizeof(widget_bag));
284
285 w->shell = XtAppCreateShell(NULL, "Jspice3",
286 applicationShellWidgetClass, Xdisplay, NULL, 0);
287 XtOverrideTranslations(w->shell, XtParseTranslationTable(wmTranslations));
288 w->form = XtVaCreateManagedWidget("xeditor", formWidgetClass,
289 w->shell, NULL);
290
291 w->butbox = XtVaCreateManagedWidget("buttonbox", boxWidgetClass,
292 w->form,
293 XtNwidth, 650,
294 XtNleft, XtChainLeft,
295 XtNright, XtChainLeft,
296 XtNbottom, XtChainTop,
297 XtNtop, XtChainTop,
298 NULL);
299
300 w->title = XtVaCreateManagedWidget("titlelabel", labelWidgetClass,
301 w->form,
302 XtNborderWidth, 0,
303 XtNfromHoriz, w->butbox,
304 XtNvertDistance, 10,
305 XtNhorizDistance, 20,
306 XtNleft, XtChainLeft,
307 XtNright, XtChainLeft,
308 XtNbottom, XtChainTop,
309 XtNtop, XtChainTop,
310 XtNresizable, True,
311 NULL);
312
313 button = XtVaCreateManagedWidget("quit", commandWidgetClass,
314 w->butbox,
315 XtNlabel, "Quit",
316 NULL);
317 XtAddCallback(button, XtNcallback, Quit, (XtPointer)w);
318 XtOverrideTranslations(button, XtParseTranslationTable(butTranslations));
319
320 button = XtVaCreateManagedWidget("save", commandWidgetClass,
321 w->butbox,
322 XtNlabel, "Save",
323 NULL);
324 XtAddCallback(button, XtNcallback, Save, (XtPointer)w);
325 XtSetSensitive(button, False);
326
327 button = XtVaCreateManagedWidget("save_as", commandWidgetClass,
328 w->butbox,
329 XtNlabel, "Save as",
330 NULL);
331 XtAddCallback(button, XtNcallback, SaveAs, (XtPointer)w);
332 XtOverrideTranslations(button, XtParseTranslationTable(butTranslations));
333
334 #ifndef STAND_ALONE
335 button = XtVaCreateManagedWidget("source", commandWidgetClass,
336 w->butbox,
337 XtNlabel, "Source",
338 NULL);
339 XtAddCallback(button, XtNcallback, Source, (XtPointer)w);
340 XtOverrideTranslations(button, XtParseTranslationTable(butTranslations));
341 #endif
342
343 button = XtVaCreateManagedWidget("load", commandWidgetClass,
344 w->butbox,
345 XtNlabel, "Load",
346 NULL);
347 XtAddCallback(button, XtNcallback, Load, (XtPointer)w);
348 XtOverrideTranslations(button, XtParseTranslationTable(butTranslations));
349
350 button = XtVaCreateManagedWidget("help", commandWidgetClass,
351 w->butbox,
352 XtNlabel, "Help",
353 NULL);
354 #ifdef STAND_ALONE
355 XtAddCallback(button, XtNcallback, PopUpHelp, (XtPointer)w);
356 XtOverrideTranslations(button, XtParseTranslationTable(butTranslations));
357 #else
358 XtAddCallback(button, XtNcallback, PopUpHelp, (XtPointer)"xeditor");
359 #endif
360
361 w->text = XtVaCreateManagedWidget("main_text", asciiTextWidgetClass,
362 w->form,
363 XtNtype, XawAsciiFile,
364 XtNeditType, XawtextRead,
365 XtNallowResize, True,
366 XtNscrollHorizontal, XawtextScrollWhenNeeded,
367 XtNscrollVertical, XawtextScrollWhenNeeded,
368 XtNfromVert, w->butbox,
369 XtNwidth, 660,
370 XtNheight, 350,
371 XtNstring, "/dev/null",
372 XtNtop, XtChainTop,
373 NULL);
374 XtAddCallback(XawTextGetSource(w->text), XtNcallback, Change,
375 (XtPointer)w);
376 XtOverrideTranslations(w->text, XtParseTranslationTable(textTranslations));
377
378 XtRealizeWidget(w->shell);
379 w->wm_delete = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", False);
380 XSetWMProtocols(Xdisplay, XtWindow(w->shell), &w->wm_delete, 1);
381
382 if (fname && *fname) {
383 strcpy(buf, fname);
384 cp_pathfix(buf);
385 fname = buf;
386 }
387 which = CheckFile(fname, R_OK, w);
388 if (which == NOGO) {
389 fname = (char*)mktemp(tmpl);
390 }
391 else if (which == READ_OK) {
392 XtVaSetValues(w->text, XtNstring, fname, NULL);
393 /* switch to edit mode, file may be read only in which
394 * case the load will fail if in edit mode
395 */
396 XtVaSetValues(w->text, XtNeditType, XawtextEdit, NULL);
397 }
398 XtVaSetValues(w->title, XtNlabel, fname, NULL);
399 w->TextChanged = False;
400 w->popup = NULL;
401 w->saved_as = NULL;
402 w->Last = LOAD;
403 w->popup_sens_list = sens_list;
404
405 return (0);
406 }
407
408
409 /* ARGSUSED */
410 static void
Quit(caller,client_data,call_data)411 Quit(caller, client_data, call_data)
412
413 Widget caller;
414 XtPointer client_data, call_data;
415 {
416 widget_bag *w = (widget_bag*)client_data;
417
418 if (w->TextChanged && (w->Last != QUIT)) {
419 w->Last = QUIT;
420 PopUpMessage(
421 "Text has been modified. Hit Quit again to quit", w);
422 return;
423 }
424 XtDestroyWidget(w->shell);
425 XtFree((char*)w);
426 #ifdef STAND_ALONE
427 kill(0,SIGINT);
428 #endif
429 }
430
431
432 /* ARGSUSED */
433 static void
Save(caller,client_data,call_data)434 Save(caller, client_data, call_data)
435
436 Widget caller;
437 XtPointer client_data, call_data;
438 {
439 widget_bag *w = (widget_bag*)client_data;
440 Arg args[1];
441 String fname;
442
443 w->Last = SAVE;
444 XtVaGetValues(w->title, XtNlabel, &fname, NULL);
445 if (CheckFile(fname, W_OK, w) == NOGO)
446 return;
447
448 if (!XawAsciiSaveAsFile(XawTextGetSource(w->text), fname)) {
449 PopUpMessage("Unknown error, text not saved", w);
450 return;
451 }
452 PopUpMessage("Text saved", w);
453 /* This can be called with TextChanged false if we saved
454 * under a new name, and made no subsequent changes.
455 */
456 if (w->TextChanged) {
457 w->TextChanged = False;
458 XtAddCallback(XawTextGetSource(w->text), XtNcallback, Change,
459 (XtPointer)w);
460 }
461 XtSetSensitive(caller, False);
462 if (w->saved_as) {
463 XtFree(w->saved_as);
464 w->saved_as = NULL;
465 }
466 }
467
468
469 /* ARGSUSED */
470 static void
SaveAs(caller,client_data,call_data)471 SaveAs(caller, client_data, call_data)
472
473 Widget caller;
474 XtPointer client_data, call_data;
475 {
476 widget_bag *w = (widget_bag*)client_data;
477 String fname;
478 XawTextPosition begin, end;
479
480 w->Last = SAVEAS;
481 XawTextGetSelectionPos(w->text, &begin, &end);
482 if (begin == end) {
483 XtVaGetValues(w->title, XtNlabel, &fname, NULL);
484 PopUpInput(fname, "Save File", DoSaveAs, (widget_bag*)client_data);
485 }
486 else
487 PopUpInput("", "Save Block", DoSaveAs, (widget_bag*)client_data);
488 }
489
490
491 #ifndef STAND_ALONE
492 /* ARGSUSED */
493 static void
Source(caller,client_data,call_data)494 Source(caller, client_data, call_data)
495
496 Widget caller;
497 XtPointer client_data, call_data;
498 {
499 widget_bag *w = (widget_bag*)client_data;
500 char *fname;
501 FILE *fp;
502
503 w->Last = SOURCE;
504 if (w->TextChanged) {
505 fname = smktemp("sp");
506 if ((fp = inp_pathopen(fname, "w")) == NULL) {
507 PopUpMessage("Unknown error, can't create temp file", w);
508 return;
509 }
510 fclose(fp);
511 if (!XawAsciiSaveAsFile(XawTextGetSource(w->text), fname)) {
512 PopUpMessage("Unknown error, can't write temp file", w);
513 return;
514 }
515 inp_srcedit(fname, False, False);
516 PopUpMessage("Text sourced (temporary file)", w);
517 }
518 else {
519 if (w->saved_as)
520 fname = w->saved_as;
521 else {
522 XtVaGetValues(w->title, XtNlabel, &fname, NULL);
523 }
524 fname = copy(fname);
525 inp_srcedit(fname, True, False);
526 PopUpMessage("Text sourced (permanent file)", w);
527 }
528 }
529 #endif
530
531
532 /* ARGSUSED */
533 static void
Load(caller,client_data,call_data)534 Load(caller, client_data, call_data)
535
536 Widget caller;
537 XtPointer client_data, call_data;
538 {
539 widget_bag *w = (widget_bag*)client_data;
540 char *newfname = NULL;
541
542 if (w->TextChanged && (w->Last != LOAD)) {
543 w->Last = LOAD;
544 PopUpMessage(
545 "Text has been modified. Hit Load again to load", w);
546 return;
547 }
548 #ifdef STAND_ALONE
549 newfname = nextarg();
550 #endif
551 PopUpInput(newfname ? newfname : "", "Load file", DoLoad,
552 (widget_bag*)client_data);
553 }
554
555
556 /* ARGSUSED */
557 static void
Change(caller,client_data,call_data)558 Change(caller, client_data, call_data)
559
560 Widget caller;
561 XtPointer client_data, call_data;
562 {
563 widget_bag *w = (widget_bag*)client_data;
564
565 w->Last = TEXTMOD;
566 w->TextChanged = True;
567 XtSetSensitive(XtNameToWidget(w->butbox, "save"), True);
568 XtRemoveCallback(caller, XtNcallback, Change, (XtPointer)w);
569 }
570
571
572 /* ARGSUSED */
573 static void
DoSaveAs(caller,client_data,call_data)574 DoSaveAs(caller, client_data, call_data)
575
576 Widget caller;
577 XtPointer client_data, call_data;
578 {
579 String fname, oldfname;
580 widget_bag *w = (widget_bag*)client_data;
581 XawTextPosition begin, end;
582 FILE *fp;
583 String s, string;
584 int len;
585 String mesg;
586 char buf[256];
587
588 XtVaGetValues(w->popup_text, XtNstring, &fname, NULL);
589 if (fname && *fname) {
590 strcpy(buf, fname);
591 cp_pathfix(buf);
592 fname = buf;
593 }
594 if (CheckFile(fname, W_OK, w) == NOGO)
595 return;
596
597 XawTextGetSelectionPos(w->text, &begin, &end);
598 if (begin == end) {
599 /* no selected text */
600 if (!XawAsciiSaveAsFile(XawTextGetSource(w->text), fname)) {
601 PopUpMessage("Unknown error, text not saved", w);
602 return;
603 }
604 XtVaGetValues(w->title, XtNlabel, &oldfname, NULL);
605 if (same(fname, oldfname)) {
606 if (!w->TextChanged) {
607 PopUpMessage("Text not modified", w);
608 return;
609 }
610 if (w->saved_as)
611 XtFree(w->saved_as), w->saved_as = NULL;
612 w->TextChanged = False;
613 XtSetSensitive(XtNameToWidget(w->butbox, "save"), False);
614 XtAddCallback(XawTextGetSource(w->text), XtNcallback, Change,
615 (XtPointer)w);
616 mesg = "Text saved";
617 }
618 else {
619 if (w->saved_as)
620 XtFree(w->saved_as);
621 w->saved_as = XtMalloc(strlen(fname) + 1);
622 strcpy(w->saved_as, fname);
623 if (w->TextChanged) {
624 w->TextChanged = False;
625 XtAddCallback(XawTextGetSource(w->text), XtNcallback, Change,
626 (XtPointer)w);
627 }
628 mesg = "Text saved under new name";
629 }
630 }
631 else {
632
633 if ((fp = fopen(fname, "w")) == NULL) {
634 PopUpMessage("Unknown error, block not saved", w);
635 return;
636 }
637 string = XFetchBytes(Xdisplay, &len);
638 for (s = string; len; s++,len--)
639 putc(*s,fp);
640 fclose(fp);
641 XFree(string);
642 mesg = "Selected block saved";
643 }
644 PopDownInput(caller, client_data, call_data);
645 PopUpMessage(mesg, w);
646 }
647
648
649 static Bool
same(s,t)650 same(s, t)
651
652 char *s, *t;
653 {
654 while (isspace(*s)) s++;
655 while (isspace(*t)) t++;
656 for (; *s && *t; s++, t++)
657 if (*s != *t) return (False);
658 if (*s && !isspace(*s)) return (False);
659 if (*t && !isspace(*t)) return (False);
660 return (True);
661 }
662
663
664 /* ARGSUSED */
665 static void
DoLoad(caller,client_data,call_data)666 DoLoad(caller, client_data, call_data)
667
668 Widget caller;
669 XtPointer client_data, call_data;
670 {
671 String fname;
672 widget_bag *w = (widget_bag*)client_data;
673 check_type which;
674 char buf[256];
675
676 XtVaGetValues(w->popup_text, XtNstring, &fname, NULL);
677 if (fname && *fname) {
678 strcpy(buf, fname);
679 cp_pathfix(buf);
680 fname = buf;
681 }
682 which = CheckFile(fname, R_OK, w);
683 if (which == NOGO)
684 return;
685 XtVaSetValues(w->text, XtNeditType, XawtextRead, NULL);
686 if (which == NO_EXIST)
687 XtVaSetValues(w->text, XtNstring, "/dev/null", NULL);
688 else
689 XtVaSetValues(w->text, XtNstring, fname, NULL);
690 XtVaSetValues(w->text, XtNeditType, XawtextEdit, NULL);
691
692 /* ick! seems to be the only way to guarantee getting the
693 * right label size after a window resize
694 */
695 XtDestroyWidget(w->title);
696 w->title = XtVaCreateManagedWidget("titlelabel", labelWidgetClass,
697 w->form,
698 XtNborderWidth, 0,
699 XtNfromHoriz, w->butbox,
700 XtNvertDistance, 10,
701 XtNhorizDistance, 20,
702 XtNleft, XtChainLeft,
703 XtNright, XtChainLeft,
704 XtNbottom, XtChainTop,
705 XtNtop, XtChainTop,
706 XtNlabel, fname,
707 NULL);
708
709 PopDownInput(caller, client_data, call_data);
710 if (w->TextChanged) {
711 w->TextChanged = False;
712 XtSetSensitive(XtNameToWidget(w->butbox, "save"), False);
713 XtAddCallback(XawTextGetSource(w->text), XtNcallback, Change,
714 (XtPointer)w);
715 }
716 if (w->saved_as) {
717 XtFree(w->saved_as);
718 w->saved_as = NULL;
719 }
720 }
721
722 #ifdef STAND_ALONE
723
724 static void
PopUpInput(initial_str,action_str,action_callback,w)725 PopUpInput(initial_str, action_str, action_callback, w)
726
727 String initial_str, action_str;
728 void (*action_callback)();
729 widget_bag *w;
730 {
731 Widget form;
732 Widget label;
733 Widget cancel;
734 Widget action;
735 Dimension width, b_width, d;
736 char **p;
737
738 w->popup = XtVaCreatePopupShell("popup", transientShellWidgetClass,
739 w->shell, NULL);
740 XtOverrideTranslations(w->popup, XtParseTranslationTable(wmTranslations));
741 XtAddEventHandler(w->popup, VisibilityChangeMask,
742 False, ToTop, (XtPointer)w);
743
744 form = XtVaCreateManagedWidget("form", formWidgetClass, w->popup,
745 NULL);
746
747 label = XtVaCreateManagedWidget("label", labelWidgetClass,
748 form,
749 XtNlabel, "Enter filename: ",
750 XtNleft, XtChainLeft,
751 XtNright, XtChainLeft,
752 XtNresizable, TRUE,
753 XtNborderWidth, 0,
754 NULL);
755
756 w->popup_text = XtVaCreateManagedWidget("text", asciiTextWidgetClass,
757 form,
758 XtNfromVert, label,
759 XtNleft, XtChainLeft,
760 XtNright, XtChainRight,
761 XtNeditType, XawtextEdit,
762 XtNresizable, TRUE,
763 XtNresize, XawtextResizeWidth,
764 XtNstring, initial_str,
765 NULL);
766 XtOverrideTranslations(w->popup_text,
767 XtParseTranslationTable(oneLineTranslations));
768
769 action = XtVaCreateManagedWidget("action", commandWidgetClass,
770 form,
771 XtNlabel, action_str,
772 XtNfromVert, w->popup_text,
773 XtNleft, XtChainLeft,
774 XtNright, XtChainLeft,
775 NULL);
776 XtOverrideTranslations(action, XtParseTranslationTable(butTranslations));
777
778 cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass,
779 form,
780 XtNlabel, "Cancel",
781 XtNfromVert, w->popup_text,
782 XtNfromHoriz, action,
783 XtNleft, XtChainLeft,
784 XtNright, XtChainLeft,
785 NULL);
786
787 XtAddCallback(cancel, XtNcallback, PopDownInput, (XtPointer)w);
788 XtAddCallback(action, XtNcallback, action_callback, (XtPointer)w);
789 XtRealizeWidget(w->popup);
790 XSetWMProtocols(Xdisplay, XtWindow(w->popup), &w->wm_delete, 1);
791 CenterWidgetOnWidget(w->popup,w->shell);
792
793 XtVaGetValues(form,
794 XtNwidth, &width,
795 XtNborderWidth, &b_width,
796 XtNdefaultDistance, &d,
797 NULL);
798 width -= 2*(b_width + d + 1);
799 XtVaSetValues(w->popup_text, XtNwidth, width, NULL);
800
801 XtPopup(w->popup, XtGrabNone);
802 XtSetKeyboardFocus(w->popup, w->popup_text);
803 XtSetKeyboardFocus(w->shell, w->popup);
804 for (p = w->popup_sens_list; *p; p++)
805 XtSetSensitive(XtNameToWidget(w->butbox, *p), False);
806 }
807
808
809 /* ARGSUSED */
810 static void
PopDownInput(caller,client_data,call_data)811 PopDownInput(caller, client_data, call_data)
812
813 Widget caller;
814 XtPointer client_data, call_data;
815 {
816 widget_bag *w = (widget_bag*)client_data;
817 char **p;
818
819 XtSetKeyboardFocus(w->shell, None);
820 XtPopdown(w->popup);
821 for (p = w->popup_sens_list; *p; p++)
822 XtSetSensitive(XtNameToWidget(w->butbox, *p), True);
823 w->popup = NULL;
824 }
825
826
827 static void
PopUpMessage(message_str,w)828 PopUpMessage(message_str, w)
829
830 String message_str;
831 widget_bag *w;
832 {
833 Widget popup;
834 Widget form;
835 Widget label;
836 Widget cancel;
837 XColor visualcolor, exactcolor;
838
839 popup = XtVaCreatePopupShell("popup_m", transientShellWidgetClass,
840 w->shell, NULL);
841 XtOverrideTranslations(popup, XtParseTranslationTable(wmTranslations));
842 XtAddEventHandler(popup, VisibilityChangeMask,
843 False, ToTop, (XtPointer)w);
844
845 form = XtVaCreateManagedWidget("form_m", formWidgetClass, popup,
846 NULL);
847
848 cancel = XtVaCreateManagedWidget("cancel_m", commandWidgetClass,
849 form,
850 XtNlabel, "OK",
851 XtNleft, XtChainLeft,
852 XtNright, XtChainLeft,
853 NULL);
854
855 XAllocNamedColor(Xdisplay,
856 DefaultColormap(Xdisplay, DefaultScreen(Xdisplay)),
857 "red", &exactcolor, &visualcolor);
858 label = XtVaCreateManagedWidget("label_m", labelWidgetClass,
859 form,
860 XtNlabel, message_str,
861 XtNleft, XtChainLeft,
862 XtNright, XtChainLeft,
863 XtNfromHoriz, cancel,
864 XtNresizable, TRUE,
865 XtNborderWidth, 2,
866 XtNborderColor, visualcolor.pixel,
867 NULL);
868
869 w->message = popup;
870 XtAddCallback(cancel, XtNcallback, PopDownMessage, (XtPointer)w);
871 XtAddEventHandler(form, KeyPressMask, False, (XtEventHandler)PopDownMessage,
872 (XtPointer)w);
873 XtRealizeWidget(popup);
874 XSetWMProtocols(Xdisplay, XtWindow(popup), &w->wm_delete, 1);
875 CenterWidgetOnWidget(popup, w->shell);
876 if (w->popup)
877 XtSetSensitive(w->popup, False);
878 XtSetSensitive(w->form, False);
879 XtSetKeyboardFocus(w->shell, form);
880 XtPopup(popup, XtGrabExclusive);
881 }
882
883
884 /* ARGSUSED */
885 static void
PopDownMessage(caller,client_data,call_data)886 PopDownMessage(caller, client_data, call_data)
887
888 Widget caller;
889 XtPointer client_data, call_data;
890 {
891 widget_bag *w = (widget_bag*)client_data;
892
893 if (w->popup) {
894 XtSetKeyboardFocus(w->shell, w->popup);
895 XtPopdown(w->message);
896 XtSetSensitive(w->popup, True);
897 }
898 else {
899 XtSetKeyboardFocus(w->shell, None);
900 XtPopdown(w->message);
901 }
902 XtSetSensitive(w->form, True);
903 }
904
905
906 static void
CenterWidgetOnWidget(sub,master)907 CenterWidgetOnWidget(sub, master)
908
909 Widget sub, master;
910 {
911 Dimension width, height, b_width;
912 Position x, y, max_x, max_y;
913
914 XtVaGetValues(master,
915 XtNx, &x,
916 XtNy, &y,
917 XtNwidth, &width,
918 XtNheight, &height,
919 XtNborderWidth, &b_width,
920 NULL);
921
922 width += 2*b_width;
923 height += 2*b_width;
924 height += 2*b_width;
925 x += (Position)width/2;
926 y += (Position)height/2;
927
928 XtVaGetValues(sub,
929 XtNwidth, &width,
930 XtNheight, &height,
931 XtNborderWidth, &b_width,
932 NULL);
933
934 width += 2*b_width;
935 height += 2*b_width;
936 x -= (Position)width/2;
937 if (x < 0) x = 0;
938 y -= (Position)height/2;
939 if (y < 0) y = 0;
940 if (y > (max_y = (Position) (XtScreen(sub)->height - height))) y = max_y;
941
942 XtVaSetValues(sub, XtNx, x, XtNy, y, NULL);
943 }
944
945
946 static check_type
CheckFile(fname,mode,w)947 CheckFile(fname, mode, w)
948
949 char *fname;
950 int mode;
951 widget_bag *w;
952 {
953 char buf[512];
954 struct stat st;
955 FILE *fp;
956 char *msg = "Error: can't %s file %s";
957
958 /* check filename */
959 if (!fname) return (NOGO);
960 while (isspace(*fname)) fname++;
961 if (!*fname) return (NOGO);
962
963 if (!access(fname, F_OK)) {
964 /* named file exists */
965 if (stat(fname, &st))
966 return (NOGO); /* shouldn't happen */
967
968 if ((st.st_mode&S_IFMT) != S_IFLNK &&
969 (st.st_mode&S_IFMT) != S_IFREG) goto bad;
970 /* not a simple file or symbolic link */
971 }
972
973 switch (mode) {
974 case R_OK:
975 if (access(fname,R_OK)) {
976 /* can't open for reading */
977 if (!access(fname,F_OK)) goto bad; /* it exists, so error */
978 return (NO_EXIST);
979 }
980 return (READ_OK);
981 case W_OK:
982 if (access(fname,W_OK)) {
983 /* can't open for writing */
984 if (!access(fname,F_OK)) goto bad; /* it exists, so error */
985 fp = fopen(fname,"w");
986 if (!fp) goto bad;
987 fclose(fp);
988 }
989 return (WRITE_OK);
990 }
991 bad:
992 sprintf(buf, msg, (mode == R_OK) ? "read" : "write", fname);
993 PopUpMessage(buf, w);
994 return (NOGO);
995 }
996
997
998 /* ARGSUSED */
999 static void
ToTop(caller,clientdata,event,ctd)1000 ToTop(caller, clientdata, event, ctd)
1001
1002 Widget caller;
1003 XtPointer clientdata;
1004 XEvent *event;
1005 Boolean *ctd;
1006 {
1007 /* prevent windows from disappearing */
1008 widget_bag *w = (widget_bag*)clientdata;
1009
1010 XVisibilityEvent *vev = (XVisibilityEvent*)event;
1011 XWindowChanges xv;
1012
1013 if (vev->state == VisibilityFullyObscured) {
1014 xv.sibling = XtWindow(w->shell);
1015 xv.stack_mode = Above;
1016 XReconfigureWMWindow(vev->display, vev->window,
1017 DefaultScreen(vev->display), CWSibling|CWStackMode, &xv);
1018 }
1019 }
1020
1021
1022 static char help_text[] = "\
1023 Command buttons:\n\
1024 Quit: Exit the editor\n\
1025 Save: Save the current buffer to the named file\n\
1026 Save As: Save the current buffer or marked block to a new file\n\
1027 Load: Input a new text file for editing\n\
1028 Help: Bring up help text\n\n\
1029 Key bindings:\n\
1030 Ctrl-a Beginning Of Line Meta-b Backward Word\n\
1031 Ctrl-b Backward Character Meta-f Forward Word\n\
1032 Ctrl-d Delete Next Character Meta-i Insert File\n\
1033 Ctrl-e End Of Line Meta-k Kill To End Of Paragraph\n\
1034 Ctrl-f Forward Character Meta-q Form Paragraph\n\
1035 Ctrl-g Multiply Reset Meta-v Previous Page\n\
1036 Ctrl-h Delete Previous Character Meta-y Insert Current Selection\n\
1037 Ctrl-j Newline And Indent Meta-z Scroll One Line Down\n\
1038 Ctrl-k Kill To End Of Line Meta-d Delete Next Word\n\
1039 Ctrl-l Redraw Display Meta-D Kill Word\n\
1040 Ctrl-m Newline Meta-h Delete Previous Word\n\
1041 Ctrl-n Next Line Meta-H Backward Kill Word\n\
1042 Ctrl-o Newline And Backup Meta-< Beginning Of File\n\
1043 Ctrl-p Previous Line Meta-> End Of File\n\
1044 Ctrl-r Search/Replace Backward Meta-] Forward Paragraph\n\
1045 Ctrl-s Search/Replace Forward Meta-[ Backward Paragraph\n\
1046 Ctrl-t Transpose Characters Delete Delete next character\n\
1047 Ctrl-u Multiply by 4 Meta-Delete Delete Previous Word\n\
1048 Ctrl-v Next Page Meta-Shift-Delete Kill Previous Word\n\
1049 Ctrl-w Kill Selection Meta-Backspace Delete Previous Word\n\
1050 Ctrl-y Unkill Meta-Shift-Backspace Kill Previous Word\n\
1051 Ctrl-z Scroll One Line Up\n\n\
1052 Pointer button bindings (cut and paste text):\n\
1053 Button 1 Down Start Selection\n\
1054 Button 1 Motion Adjust Selection\n\
1055 Button 1 Up End Selection (cut)\n\n\
1056 Button 2 Down Insert Current Selection (paste)\n\n\
1057 Button 3 Down Extend Current Selection\n\
1058 Button 3 Motion Adjust Selection\n\
1059 Button 3 Up End Selection (cut)\n";
1060
1061
1062
1063 /* ARGSUSED */
1064 static void
PopUpHelp(caller,client_data,call_data)1065 PopUpHelp(caller, client_data, call_data)
1066
1067 Widget caller;
1068 XtPointer client_data, call_data;
1069 {
1070 Widget popup;
1071 Widget form;
1072 Widget butbox;
1073 Widget label;
1074 Widget cancel;
1075 Widget text;
1076 widget_bag *w = (widget_bag*)client_data;
1077 Position x, y;
1078 Widget *wpass;
1079
1080 XtVaGetValues(w->shell, XtNx, &x, XtNy, &y, NULL);
1081
1082
1083 popup = XtVaCreatePopupShell("popup_h", transientShellWidgetClass,
1084 w->shell,
1085 XtNx, x + 50,
1086 XtNy, y + 50,
1087 NULL);
1088 XtOverrideTranslations(popup, XtParseTranslationTable(wmTranslations));
1089
1090 form = XtVaCreateManagedWidget("form_h", formWidgetClass, popup,
1091 NULL);
1092
1093 butbox = XtVaCreateManagedWidget("buttonbox", boxWidgetClass,
1094 form,
1095 XtNwidth, 650,
1096 XtNleft, XtChainLeft,
1097 XtNright, XtChainLeft,
1098 XtNbottom, XtChainTop,
1099 XtNtop, XtChainTop,
1100 NULL);
1101
1102 label = XtVaCreateManagedWidget("label_h", labelWidgetClass,
1103 butbox,
1104 XtNlabel, "Xeditor Help",
1105 XtNborderWidth, 2,
1106 NULL);
1107
1108 cancel = XtVaCreateManagedWidget("cancel_h", commandWidgetClass,
1109 butbox,
1110 XtNlabel, "Cancel",
1111 XtNfromHoriz, label,
1112 NULL);
1113
1114 text = XtVaCreateManagedWidget("text_h", asciiTextWidgetClass,
1115 form,
1116 XtNtype, XawAsciiString,
1117 XtNeditType, XawtextRead,
1118 XtNallowResize, True,
1119 XtNscrollHorizontal, XawtextScrollWhenNeeded,
1120 XtNscrollVertical, XawtextScrollWhenNeeded,
1121 XtNfromVert, butbox,
1122 XtNwidth, 600,
1123 XtNheight, 400,
1124 XtNstring, help_text,
1125 XtNdisplayCaret, False,
1126 NULL);
1127
1128 wpass = (Widget*)XtMalloc(2*sizeof(Widget));
1129 wpass[0] = popup;
1130 wpass[1] = w->butbox;
1131 XtAddCallback(cancel, XtNcallback, PopDownHelp, (XtPointer)wpass);
1132 XtRealizeWidget(popup);
1133 XSetWMProtocols(Xdisplay, XtWindow(popup), &w->wm_delete, 1);
1134 XtPopup(popup, XtGrabNone);
1135 XtSetSensitive(XtNameToWidget(w->butbox, "help"), False);
1136 }
1137
1138
1139 /* ARGSUSED */
1140 static void
PopDownHelp(caller,client_data,call_data)1141 PopDownHelp(caller, client_data, call_data)
1142
1143 Widget caller;
1144 XtPointer client_data, call_data;
1145 {
1146 Widget *w = (Widget*)client_data;
1147
1148 XtPopdown(w[0]);
1149 XtSetSensitive(XtNameToWidget(w[1], "help"), True);
1150 XtFree((char*)w);
1151 }
1152
1153
1154 void
cp_pathfix(buf)1155 cp_pathfix(buf)
1156
1157 char *buf;
1158 {
1159 char *s;
1160
1161 if (index(buf,'~')) {
1162 s = tilde_expand(buf);
1163 if (s) {
1164 strcpy(buf,s);
1165 XtFree(s);
1166 }
1167 }
1168 }
1169
1170
1171 static char *
tilde_expand(string)1172 tilde_expand(string)
1173
1174 char *string;
1175 {
1176 struct passwd *pw;
1177 char *tail;
1178 char buf[BSIZE_SP];
1179 char *k, c;
1180 char *ret;
1181
1182 while (*string && isspace(*string))
1183 string++;
1184
1185 if (*string != '~') {
1186 ret = XtMalloc(strlen(string) + 1);
1187 strcpy(ret, string);
1188 return (ret);
1189 }
1190
1191 string += 1;
1192
1193 if (!*string || *string == '/') {
1194 pw = getpwuid(getuid());
1195 *buf = 0;
1196 }
1197 else {
1198 k = buf;
1199 while ((c = *string) && c != '/')
1200 *k++ = c, string++;
1201 *k = 0;
1202 pw = getpwnam(buf);
1203 }
1204
1205 if (pw) {
1206 strcpy(buf, pw->pw_dir);
1207 if (*string)
1208 strcat(buf, string);
1209 }
1210 else
1211 return (NULL);
1212
1213 ret = XtMalloc(strlen(buf) + 1);
1214 strcpy(ret, buf);
1215 return (ret);
1216 }
1217
1218
1219 #else /* STAND_ALONE */
1220
1221 /* ARGSUSED */
1222 static void
PopUpHelp(caller,client_data,call_data)1223 PopUpHelp(caller, client_data, call_data)
1224
1225 Widget caller;
1226 XtPointer client_data, call_data;
1227 {
1228 wordlist wl;
1229
1230 wl.wl_prev = wl.wl_next = NULL;
1231 wl.wl_word = (char*)client_data;
1232 com_ghelp(&wl);
1233 }
1234
1235
1236 void
com_xeditor(wl)1237 com_xeditor(wl)
1238
1239 wordlist *wl;
1240 {
1241 if (wl)
1242 xeditor(wl->wl_word);
1243 else
1244 xeditor(NULL);
1245 }
1246
1247
1248 #endif /* STAND_ALONE */
1249
1250 #else /* HAVE_X11 */
1251
1252 #ifdef STAND_ALONE
main()1253 main()
1254 { printf("This doesn't exist without X!\n"); }
1255
1256 #else
1257
1258 /* ARGSUSED */
1259 int
xeditor(s)1260 xeditor(s)
1261 char *s;
1262 { return (1); }
1263
1264
1265 void
com_xeditor(wl)1266 com_xeditor(wl)
1267
1268 wordlist *wl;
1269 {
1270 fprintf(cp_err, "Xeditor is available under X only\n");
1271 }
1272
1273 #endif /* STAND_ALONE */
1274
1275 #endif /* HAVE_X11 */
1276