1 /*
2 * Copyright (c) 1994-2009, 2013-2016, 2019 Paul Mattes.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Paul Mattes nor his contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * save.c
32 * Implements the response to the WM_SAVE_YOURSELF message and
33 * x3270 profiles.
34 */
35
36 #include "globals.h"
37 #include "xglobals.h"
38
39 #include <X11/StringDefs.h>
40 #include <X11/Xatom.h>
41 #include <pwd.h>
42 #include <errno.h>
43 #include "appres.h"
44 #include "resources.h"
45
46 #include "codepage.h"
47 #if !defined(USE_APP_DEFAULTS) /*[*/
48 # include "fallbacks.h"
49 #endif /*]*/
50 #include "idle.h"
51 #include "keymap.h"
52 #include "lazya.h"
53 #include "popups.h"
54 #include "save.h"
55 #include "screen.h"
56 #include "toggles.h"
57 #include "utils.h"
58 #include "xappres.h"
59 #include "xkeypad.h"
60 #include "xsave.h"
61 #include "xscreen.h"
62
63 /* Support for WM_SAVE_YOURSELF. */
64
65 char *command_string = NULL;
66
67 static char *cmd;
68 static int cmd_len;
69
70 #define NWORDS 1024
71
72 static char **tmp_cmd;
73 static int tcs;
74
75 static Status x_get_window_attributes(Window w, XWindowAttributes *wa);
76
77 /* Search for an option in the tmp_cmd array. */
78 static int
cmd_srch(const char * s)79 cmd_srch(const char *s)
80 {
81 int i;
82
83 for (i = 1; i < tcs; i++) {
84 if (tmp_cmd[i] && !strcmp(tmp_cmd[i], s)) {
85 return i;
86 }
87 }
88 return 0;
89 }
90
91 /* Replace an options in the tmp_cmd array. */
92 static void
cmd_replace(int ix,const char * s)93 cmd_replace(int ix, const char *s)
94 {
95 XtFree(tmp_cmd[ix]);
96 tmp_cmd[ix] = XtNewString(s);
97 }
98
99 /* Append an option to the tmp_cmd array. */
100 static void
cmd_append(const char * s)101 cmd_append(const char *s)
102 {
103 tmp_cmd[tcs++] = XtNewString(s);
104 tmp_cmd[tcs] = (char *) NULL;
105 }
106
107 /* Delete an option from the tmp_cmd array. */
108 static void
cmd_delete(int ix)109 cmd_delete(int ix)
110 {
111 XtFree(tmp_cmd[ix]);
112 tmp_cmd[ix] = (char *) NULL;
113 }
114
115 /* Save the screen geometry. */
116 static void
save_xy(void)117 save_xy(void)
118 {
119 char *tbuf;
120 Window window, frame, child;
121 XWindowAttributes wa;
122 int x, y;
123 int ix;
124
125 window = XtWindow(toplevel);
126 if (!x_get_window_attributes(window, &wa))
127 return;
128 XTranslateCoordinates(display, window, wa.root,
129 -wa.border_width, -wa.border_width,
130 &x, &y, &child);
131
132 frame = XtWindow(toplevel);
133 while (true) {
134 Window root, parent;
135 Window *wchildren;
136 unsigned int nchildren;
137
138 int status = XQueryTree(display, frame, &root, &parent, &wchildren,
139 &nchildren);
140 if (status && wchildren) {
141 XFree((char *)wchildren);
142 }
143 if (parent == root || !parent || !status) {
144 break;
145 }
146 frame = parent;
147 }
148 if (frame != window) {
149 if (!x_get_window_attributes(frame, &wa)) {
150 return;
151 }
152 x = wa.x;
153 y = wa.y;
154 }
155
156 tbuf = lazyaf("+%d+%d", x, y);
157 if ((ix = cmd_srch("-geometry"))) {
158 cmd_replace(ix + 1, tbuf);
159 } else {
160 cmd_append("-geometry");
161 cmd_append(tbuf);
162 }
163 }
164
165 /* Save the icon information: state, label, geometry. */
166 static void
save_icon(void)167 save_icon(void)
168 {
169 unsigned char *data;
170 int iconX, iconY;
171 char *tbuf;
172 int ix;
173 unsigned long nitems;
174
175 {
176 Atom actual_type;
177 int actual_format;
178 unsigned long leftover;
179
180 if (XGetWindowProperty(display, XtWindow(toplevel), a_state, 0L, 2L,
181 False, a_state, &actual_type, &actual_format, &nitems,
182 &leftover, &data) != Success) {
183 return;
184 }
185 if (actual_type != a_state || actual_format != 32 || nitems < 1) {
186 return;
187 }
188 }
189
190 ix = cmd_srch("-iconic");
191 if (*(unsigned long *)data == IconicState) {
192 if (!ix) {
193 cmd_append("-iconic");
194 }
195 } else {
196 if (ix) {
197 cmd_delete(ix);
198 }
199 }
200
201 if (nitems < 2) {
202 return;
203 }
204
205 {
206 Window icon_window;
207 XWindowAttributes wa;
208 Window child;
209
210 icon_window = *(Window *)(data + sizeof(unsigned long));
211 if (icon_window == None) {
212 return;
213 }
214 if (!x_get_window_attributes(icon_window, &wa)) {
215 return;
216 }
217 XTranslateCoordinates(display, icon_window, wa.root,
218 -wa.border_width, -wa.border_width, &iconX, &iconY, &child);
219 if (!iconX && !iconY) {
220 return;
221 }
222 }
223
224 tbuf = lazyaf("%d", iconX);
225 ix = cmd_srch(OptIconX);
226 if (ix) {
227 cmd_replace(ix + 1, tbuf);
228 } else {
229 cmd_append(OptIconX);
230 cmd_append(tbuf);
231 }
232
233 tbuf = lazyaf("%d", iconY);
234 ix = cmd_srch(OptIconY);
235 if (ix) {
236 cmd_replace(ix + 1, tbuf);
237 } else {
238 cmd_append(OptIconY);
239 cmd_append(tbuf);
240 }
241 return;
242 }
243
244 /* Save the keymap information. */
245 static void
save_keymap(void)246 save_keymap(void)
247 {
248 /* Note: keymap propogation is deliberately disabled, because it
249 may vary from workstation to workstation. The recommended
250 way of specifying keymaps is through your .Xdefaults or the
251 KEYMAP or KEYBD environment variables, which can be easily set
252 in your .login or .profile to machine-specific values; the
253 -keymap switch is really for debugging or testing keymaps.
254
255 I'm sure I'll regret this. */
256
257 #if defined(notdef) /*[*/
258 if (current_keymap) {
259 add_string(v, OptKeymap);
260 add_string(v, current_keymap);
261 }
262 #endif /*]*/
263 }
264
265 /* Save the model name. */
266 static void
save_model(void)267 save_model(void)
268 {
269 int ix;
270
271 if (!model_changed) {
272 return;
273 }
274 if ((ix = cmd_srch(OptModel)) && strcmp(tmp_cmd[ix], model_name)) {
275 cmd_replace(ix + 1, model_name);
276 } else {
277 cmd_append(OptModel);
278 cmd_append(model_name);
279 }
280 }
281
282 /* Save the emulator font. */
283 static void
save_efont(void)284 save_efont(void)
285 {
286 int ix;
287
288 if (!efont_changed) {
289 return;
290 }
291 if ((ix = cmd_srch(OptEmulatorFont)) && strcmp(tmp_cmd[ix], efontname)) {
292 cmd_replace(ix + 1, efontname);
293 } else {
294 cmd_append(OptEmulatorFont);
295 cmd_append(efontname);
296 }
297 }
298
299 /* Save the keypad state. */
300 static void
save_keypad(void)301 save_keypad(void)
302 {
303 int ix;
304
305 ix = cmd_srch(OptKeypadOn);
306 if (xappres.keypad_on || keypad_popped) {
307 if (!ix) {
308 cmd_append(OptKeypadOn);
309 }
310 } else {
311 if (ix) {
312 cmd_delete(ix);
313 }
314 }
315 }
316
317 /* Save the scrollbar state. */
318 static void
save_scrollbar(void)319 save_scrollbar(void)
320 {
321 int i_on, i_off;
322
323 if (!scrollbar_changed) {
324 return;
325 }
326 i_on = cmd_srch(OptScrollBar);
327 i_off = cmd_srch(OptNoScrollBar);
328 if (toggled(SCROLL_BAR)) {
329 if (!i_on) {
330 if (i_off) {
331 cmd_replace(i_off, OptScrollBar);
332 } else {
333 }
334 cmd_append(OptScrollBar);
335 }
336 } else {
337 if (!i_off) {
338 if (i_on) {
339 cmd_replace(i_on, OptNoScrollBar);
340 } else {
341 cmd_append(OptNoScrollBar);
342 }
343 }
344 }
345 }
346
347 /* Save the name of the host we are connected to. */
348 static void
save_host(void)349 save_host(void)
350 {
351 char *space;
352
353 if (!CONNECTED) {
354 return;
355 }
356 space = strchr(full_current_host, ' ');
357 if (space == (char *) NULL) {
358 cmd_append(full_current_host);
359 } else {
360 char *tmp = XtNewString(full_current_host);
361 char *port;
362
363 space = strchr(tmp, ' ');
364 *space = '\0';
365 cmd_append(tmp);
366 port = space + 1;
367 while (*port == ' ') {
368 port++;
369 }
370 if (*port) {
371 cmd_append(port);
372 }
373 XtFree(tmp);
374 }
375 }
376
377 /* Save the settings of each of the toggles. */
378 static void
save_toggles(void)379 save_toggles(void)
380 {
381 toggle_index_t i;
382 int j;
383 int ix;
384
385 for (i = 0; i < N_TOGGLES; i++) {
386 toggle_index_t tix = toggle_names[i].index;
387
388 if (!toggle_changed(tix)) {
389 continue;
390 }
391
392 /*
393 * Find the last "-set" or "-clear" for this toggle.
394 * If there is a preferred alias, delete them instead.
395 */
396 ix = 0;
397 for (j = 1; j < tcs; j++) {
398 if (tmp_cmd[j] &&
399 (!strcmp(tmp_cmd[j], OptSet) ||
400 !strcmp(tmp_cmd[j], OptClear)) &&
401 tmp_cmd[j+1] &&
402 !strcmp(tmp_cmd[j+1], toggle_names[i].name)) {
403
404 if (toggle_names[i].is_alias) {
405 cmd_delete(j);
406 cmd_delete(j + 1);
407 } else {
408 ix = j;
409 }
410 }
411 }
412
413 /* Handle aliased switches. */
414 switch (tix) {
415 case SCROLL_BAR:
416 continue; /* +sb/-sb done separately */
417 case TRACING:
418 ix = cmd_srch(OptTrace);
419 if (toggled(TRACING)) {
420 if (!ix) {
421 cmd_append(OptTrace);
422 }
423 } else {
424 if (ix) {
425 cmd_delete(ix);
426 }
427 }
428 continue;
429 default:
430 break;
431 }
432
433 /* If need be, switch "-set" with "-clear", or append one. */
434 if (toggled(tix)) {
435 if (ix && strcmp(tmp_cmd[ix], OptSet)) {
436 cmd_replace(ix, OptSet);
437 } else if (!ix) {
438 cmd_append(OptSet);
439 cmd_append(toggle_names[i].name);
440 }
441 } else {
442 if (ix && strcmp(tmp_cmd[ix], OptClear)) {
443 cmd_replace(ix, OptClear);
444 } else if (!ix) {
445 cmd_append(OptClear);
446 cmd_append(toggle_names[i].name);
447 }
448 }
449 }
450 }
451
452 /* Remove a positional parameter from the command line. */
453 static void
remove_positional(char * s)454 remove_positional(char *s)
455 {
456 char *c;
457
458 c = cmd + cmd_len - 2; /* last byte of last arg */
459 while (*c && c >= cmd) {
460 c--;
461 }
462 if (strcmp(s, c + 1)) {
463 XtError("Command-line switches must precede positional arguments");
464 }
465 cmd_len = c - cmd;
466 }
467
468 /* Save a copy of he XA_WM_COMMAND poperty. */
469 void
save_init(int argc,char * hostname,char * port)470 save_init(int argc, char *hostname, char *port)
471 {
472 Atom actual_type;
473 int actual_format;
474 unsigned long nitems;
475 unsigned long bytes_after;
476
477 /*
478 * Fetch the initial value of the XA_COMMAND property and store
479 * it in 'cmd'.
480 */
481 XGetWindowProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
482 0L, 1000000L, False, XA_STRING, &actual_type, &actual_format,
483 &nitems, &bytes_after, (unsigned char **)&cmd);
484 if (nitems == 0) {
485 XtError("Could not get initial XA_COMMAND property");
486 }
487 cmd_len = nitems * (actual_format / 8);
488
489 /*
490 * Now locate the hostname and port positional arguments, and
491 * remove them. If they aren't the last two components of the
492 * command line, abort.
493 */
494 switch (argc) {
495 case 3:
496 remove_positional(port);
497 /* fall through */
498 case 2:
499 remove_positional(hostname);
500 break;
501 }
502 }
503
504 /* Handle a WM_SAVE_YOURSELF ICCM. */
505 void
save_yourself(void)506 save_yourself(void)
507 {
508 int i;
509 char *c, *c2;
510 int len;
511
512 Replace(command_string, NULL);
513
514 /* Copy the original command line into tmp_cmd. */
515 tmp_cmd = (char **) XtMalloc(sizeof(char *) * NWORDS);
516 tcs = 0;
517 i = 0;
518 c = cmd;
519 while (i < cmd_len) {
520 c = cmd + i;
521 tmp_cmd[tcs++] = XtNewString(c);
522 i += strlen(c);
523 i++;
524 }
525 tmp_cmd[tcs] = (char *) NULL;
526
527 /* Replace the first element with the program name. */
528 cmd_replace(0, programname);
529
530 /* Save options. */
531 save_xy();
532 save_icon();
533 save_keymap();
534 save_model();
535 save_efont();
536 save_keypad();
537 save_scrollbar();
538 save_toggles();
539 save_host();
540
541 /* Copy what's left into contiguous memory. */
542 len = 0;
543 for (i = 0; i < tcs; i++) {
544 if (tmp_cmd[i]) {
545 len += strlen(tmp_cmd[i]) + 1;
546 }
547 }
548 c = XtMalloc(len);
549 c[0] = '\0';
550 c2 = c;
551 for (i = 0; i < tcs; i++) {
552 if (tmp_cmd[i]) {
553 strcpy(c2, tmp_cmd[i]);
554 c2 += strlen(c2) + 1;
555 XtFree(tmp_cmd[i]);
556 }
557 }
558 Free(tmp_cmd);
559
560 /* Change the property. */
561 XChangeProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
562 XA_STRING, 8, PropModeReplace, (unsigned char *)c, len);
563
564 /* Save a readable copy of the command string for posterity. */
565 command_string = c;
566 while (((c2 = strchr(c, '\0')) != NULL) &&
567 (c2 - command_string < len-1)) {
568 *c2 = ' ';
569 c = c2 + 1;
570 }
571 }
572
573 /* Support for x3270 profiles. */
574
575 #define PROFILE_ENV "X3270PRO"
576 #define NO_PROFILE_ENV "NOX3270PRO"
577 #define RDB_ENV "X3270RDB"
578 #define DEFAULT_PROFILE "~/.x3270pro"
579
580 char *profile_name = NULL;
581 static char *xcmd;
582 static int xargc;
583 static char **xargv;
584
585 typedef struct scs {
586 struct scs *next;
587 char *name;
588 } scs_t;
589 scs_t *cc_list = NULL;
590
591 void
charset_list_changed(char * charset)592 charset_list_changed(char *charset)
593 {
594 scs_t *c;
595
596 for (c = cc_list; c != NULL; c = c->next) {
597 if (!strcasecmp(c->name, charset)) {
598 return;
599 }
600 }
601 c = (scs_t *)Malloc(sizeof(scs_t));
602 c->name = NewString(charset);
603 c->next = cc_list;
604 cc_list = c;
605 }
606
607 /* Save one option in the file. */
608 static void
save_opt(FILE * f,const char * full_name,const char * opt_name,const char * res_name,const char * value)609 save_opt(FILE *f, const char *full_name, const char *opt_name,
610 const char *res_name, const char *value)
611 {
612 fprintf(f, "! %s ", full_name);
613 if (opt_name != NULL) {
614 fprintf(f, " (%s)", opt_name);
615 }
616 fprintf(f, "\n%s.%s: %s\n", XtName(toplevel), res_name, value);
617 }
618
619 /* Save the current options settings in a profile. */
620 bool
save_options(char * n)621 save_options(char *n)
622 {
623 FILE *f;
624 bool exists = false;
625 char *ct;
626 toggle_index_t i;
627 time_t clk;
628 char *buf;
629 bool any_toggles = false;
630
631 if (n == NULL || *n == '\0') {
632 return false;
633 }
634
635 /* Open the file. */
636 n = do_subst(n, DS_VARS | DS_TILDE);
637 f = fopen(n, "r");
638 if (f != NULL) {
639 fclose(f);
640 exists = true;
641 }
642 f = fopen(n, "a");
643 if (f == NULL) {
644 popup_an_errno(errno, "Cannot open %s", n);
645 XtFree(n);
646 return false;
647 }
648
649 /* Save the name. */
650 Replace(profile_name, n);
651
652 /* Print the header. */
653 clk = time((time_t *)0);
654 ct = ctime(&clk);
655 if (ct[strlen(ct)-1] == '\n') {
656 ct[strlen(ct)-1] = '\0';
657 }
658 if (exists) {
659 fprintf(f, "! File updated %s by %s\n", ct, build);
660 } else {
661 fprintf(f,
662 "! x3270 profile\n\
663 ! File created %s by %s\n\
664 ! This file overrides xrdb and .Xdefaults.\n\
665 ! To skip reading this file, set %s in the environment.\n\
666 !\n",
667 ct, build, NO_PROFILE_ENV);
668 }
669
670 /* Save most of the toggles. */
671 for (i = 0; toggle_names[i].name; i++) {
672 toggle_index_t tix = toggle_names[i].index;
673
674 if (toggle_names[i].is_alias || !toggle_changed(tix)) {
675 continue;
676 }
677 if (!any_toggles) {
678 fprintf(f, "! toggles (%s, %s)\n", OptSet, OptClear);
679 any_toggles = true;
680 }
681 fprintf(f, "%s.%s: %s\n", XtName(toplevel),
682 toggle_names[i].name,
683 toggled(tix)? ResTrue: ResFalse);
684 }
685
686 /* Save the keypad state. */
687 if (keypad_changed) {
688 save_opt(f, "keypad state", OptKeypadOn, ResKeypadOn,
689 (xappres.keypad_on || keypad_popped)? ResTrue: ResFalse);
690 }
691
692 /* Save other menu-changeable options. */
693 if (efont_changed) {
694 save_opt(f, "emulator font", OptEmulatorFont, ResEmulatorFont,
695 efontname);
696 }
697 if (model_changed) {
698 buf = xs_buffer("%d", model_num);
699 save_opt(f, "model", OptModel, ResModel, buf);
700 Free(buf);
701 }
702 if (oversize_changed) {
703 buf = xs_buffer("%dx%d", ov_cols, ov_rows);
704 save_opt(f, "oversize", OptOversize, ResOversize, buf);
705 Free(buf);
706 }
707 if (scheme_changed && xappres.color_scheme != NULL) {
708 save_opt(f, "color scheme", OptColorScheme, ResColorScheme,
709 xappres.color_scheme);
710 }
711 if (keymap_changed && current_keymap != NULL) {
712 save_opt(f, "keymap", OptKeymap, ResKeymap, current_keymap);
713 }
714 if (codepage_changed) {
715 save_opt(f, "codepage", OptCodePage, ResCodePage, get_codepage_name());
716 }
717 if (idle_changed) {
718 save_opt(f, "idle command", NULL, ResIdleCommand, idle_command);
719 save_opt(f, "idle timeout", NULL, ResIdleTimeout, idle_timeout_string);
720 save_opt(f, "idle enabled", NULL, ResIdleCommandEnabled,
721 (idle_user_enabled == IDLE_PERM)? ResTrue: ResFalse);
722 }
723
724 /* Done. */
725 fclose(f);
726
727 return true;
728 }
729
730 /* Save a copy of the command-line options. */
731 void
save_args(int argc,char * argv[])732 save_args(int argc, char *argv[])
733 {
734 int i;
735 int len = 0;
736
737 for (i = 0; i < argc; i++) {
738 len += strlen(argv[i]) + 1;
739 }
740 xcmd = XtMalloc(len + 1);
741 xargv = (char **)XtMalloc((argc + 1) * sizeof(char *));
742 len = 0;
743 for (i = 0; i < argc; i++) {
744 xargv[i] = xcmd + len;
745 strcpy(xcmd + len, argv[i]);
746 len += strlen(argv[i]) + 1;
747 }
748 xargv[i] = NULL;
749 *(xcmd + len) = '\0';
750 xargc = argc;
751 }
752
753 #if !defined(USE_APP_DEFAULTS) /*[*/
754 #define DEF_NAME "x3270"
755 #define NLEN (sizeof(DEF_NAME) - 1)
756 #define DOT_NAME DEF_NAME "."
757 #define STAR_NAME DEF_NAME "*"
758
759 /* Substitute an alternate name in the fallback resource definitions. */
760 static char *
subst_name(unsigned char * fallbacks)761 subst_name(unsigned char *fallbacks)
762 {
763 char *tlname;
764 char *s, *t;
765 bool eol = true;
766 int nname = 0;
767 size_t nlen;
768 int flen;
769 char *new_fallbacks;
770
771 /* If the name is the same, do nothing. */
772 if (!strcmp((tlname = XtName(toplevel)), DEF_NAME)) {
773 return (char *)fallbacks;
774 }
775
776 /* Count the number of instances of "x3270" in the fallbacks. */
777 s = (char *)fallbacks;
778 while (*s) {
779 if (eol && (!strncmp(s, DOT_NAME, NLEN + 1) ||
780 !strncmp(s, STAR_NAME, NLEN + 1))) {
781 nname++;
782 s += NLEN;
783 eol = false;
784 } else if (*s == '\n') {
785 eol = true;
786 } else {
787 eol = false;
788 }
789 s++;
790 }
791 if (!nname) {
792 return (char *)fallbacks;
793 }
794
795 /* Allocate a buffer to do the substitution into. */
796 if ((nlen = strlen(tlname)) > NLEN) {
797 flen = strlen((char *)fallbacks) + ((nlen - NLEN) * nname) + 1;
798 } else {
799 flen = strlen((char *)fallbacks) - ((NLEN - nlen) * nname) + 1;
800 }
801 new_fallbacks = Malloc(flen);
802
803 /* Substitute. */
804 s = (char *)fallbacks;
805 t = new_fallbacks;
806 while (*s) {
807 if (eol && (!strncmp(s, DOT_NAME, NLEN + 1) ||
808 !strncmp(s, STAR_NAME, NLEN + 1))) {
809 strcpy(t, tlname);
810 t += nlen;
811 s += NLEN;
812 eol = false;
813 } else if (*s == '\n') {
814 eol = true;
815 } else {
816 eol = false;
817 }
818 *t++ = *s++;
819 }
820 *t = '\0';
821 return new_fallbacks;
822 }
823 #endif /*]*/
824
825 /* Merge in the options settings from a profile. */
826 void
merge_profile(XrmDatabase * d,char * session,bool mono)827 merge_profile(XrmDatabase *d, char *session, bool mono)
828 {
829 const char *fname;
830 char *env_resources;
831 XrmDatabase dd;
832
833 #if !defined(USE_APP_DEFAULTS) /*[*/
834 /* Start with the fallbacks. */
835 dd = XrmGetStringDatabase(subst_name(common_fallbacks));
836 if (dd == NULL) {
837 XtError("Can't parse common fallbacks");
838 }
839 XrmMergeDatabases(dd, d);
840 dd = XrmGetStringDatabase(subst_name(mono? mono_fallbacks:
841 color_fallbacks));
842 if (dd == NULL) {
843 XtError("Can't parse mono/color fallbacks");
844 }
845 XrmMergeDatabases(dd, d);
846 #endif /*]*/
847
848 if (session == NULL && getenv(NO_PROFILE_ENV) != NULL) {
849 profile_name = do_subst(DEFAULT_PROFILE, DS_VARS | DS_TILDE);
850 } else {
851 /* Open the file. */
852 if (session != NULL) {
853 fname = session;
854 } else {
855 fname = getenv(PROFILE_ENV);
856 }
857 if (fname == NULL || *fname == '\0') {
858 fname = DEFAULT_PROFILE;
859 }
860 profile_name = do_subst(fname, DS_VARS | DS_TILDE);
861
862 /* Create a resource database from the file. */
863 dd = XrmGetFileDatabase(profile_name);
864 if (dd != NULL) {
865 /* Merge in the profile options. */
866 XrmMergeDatabases(dd, d);
867 } else if (session != NULL) {
868 Error("Session file not found");
869 }
870 }
871
872 /* See if there are any environment resources. */
873 env_resources = getenv(RDB_ENV);
874 if (env_resources != NULL) {
875 dd = XrmGetStringDatabase(env_resources);
876 if (dd != NULL) {
877 XrmMergeDatabases(dd, d);
878 }
879 }
880
881 /* Merge the saved command-line options back on top of those. */
882 dd = NULL;
883 XrmParseCommand(&dd, options, num_options, programname, &xargc, xargv);
884 XrmMergeDatabases(dd, d);
885
886 /* Free the saved command-line options. */
887 XtFree(xcmd);
888 xcmd = NULL;
889 Replace(xargv, NULL);
890 }
891
892 bool
read_resource_file(const char * filename,bool fatal)893 read_resource_file(const char *filename, bool fatal)
894 {
895 XrmDatabase dd, rdb;
896
897 dd = XrmGetFileDatabase(filename);
898 if (dd == NULL) {
899 return false;
900 }
901
902 rdb = XtDatabase(display);
903 XrmMergeDatabases(dd, &rdb);
904 return true;
905 }
906
907 /*
908 * Safe routine for querying window attributes
909 */
910 static int
dummy_error_handler(Display * d _is_unused,XErrorEvent * e _is_unused)911 dummy_error_handler(Display *d _is_unused, XErrorEvent *e _is_unused)
912 {
913 return 0;
914 }
915
916 static Status
x_get_window_attributes(Window w,XWindowAttributes * wa)917 x_get_window_attributes(Window w, XWindowAttributes *wa)
918 {
919 XErrorHandler old_handler;
920 Status s;
921
922 old_handler = XSetErrorHandler(dummy_error_handler);
923
924 s = XGetWindowAttributes(display, w, wa);
925 if (!s) {
926 fprintf(stderr, "Error: querying bad window 0x%lx\n", w);
927 }
928
929 XSetErrorHandler(old_handler);
930
931 return s;
932 }
933