1 /*--------------------------------*-C-*---------------------------------*
2  * File:	xdefaults.c
3  *----------------------------------------------------------------------*
4  * Copyright 1997,1998 mj olesen <olesen@me.queensu.ca>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *----------------------------------------------------------------------*/
20 /*----------------------------------------------------------------------*
21  * Originally written:
22  *    1994      Robert Nation <nation@rocket.sanders.lockheed.com>
23  * Modifications:
24  *    1997,1998 mj olesen <olesen@me.queensu.ca>
25  *----------------------------------------------------------------------*/
26 /*----------------------------------------------------------------------*
27  * get resources from ~/.Xdefaults or ~/.Xresources with the memory-saving
28  * default or with XGetDefault() (#define USE_XGETDEFAULT)
29  *
30  * Coding style:
31  *	resource strings are indicated by an `rs_' prefix followed by
32  *	the resource name.
33  *	eg, `rs_saveLines' is the resource string corresponding to
34  *	    the `saveLines' resource
35  *----------------------------------------------------------------------*/
36 
37 #ifndef lint
38 static const char rcsid[] = "$Id: xdefaults.c,v 1.5 2005/12/06 17:08:44 sasha Exp $";
39 #endif
40 
41 #include "rxvt.h"		/* NECESSARY */
42 
43 /* #define DEBUG_RESOURCES */
44 
45 /* local functions referenced */
46 /*{{{ local variables */
47 static const char *rs_borderLess = NULL;
48 static const char *rs_loginShell = NULL;
49 static const char *rs_utmpInhibit = NULL;
50 static const char *rs_scrollBar = NULL;
51 static const char *rs_scrollBar_right = NULL;
52 static const char *rs_scrollBar_floating = NULL;
53 static const char *rs_scrollTtyOutput = NULL;
54 static const char *rs_scrollKeypress = NULL;
55 
56 #ifdef TRANSPARENT
57 static const char *rs_transparent = NULL;
58 static const char *rs_transparent_sb = NULL;
59 #endif
60 
61 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
62 static const char *rs_bigfont_key = NULL;
63 static const char *rs_smallfont_key = NULL;
64 #endif
65 
66 #ifndef NO_MAPALERT
67 # ifdef MAPALERT_OPTION
68 static const char *rs_mapAlert = NULL;
69 # endif
70 #endif
71 static const char *rs_visualBell = NULL;
72 static const char *rs_reverseVideo = NULL;
73 static const char *rs_cutToBeginningOfLine = NULL;
74 
75 #ifdef META8_OPTION
76 static const char *rs_meta8 = NULL;
77 #endif
78 #ifdef MULTICHAR_SET
79 static const char *rs_multichar_encoding = NULL;
80 #endif
81 #ifdef GREEK_SUPPORT
82 static const char *rs_greek_keyboard = NULL;
83 #endif
84 /*}}} */
85 
86 /*{{{ monolithic option/resource structure: */
87 /*
88  * `string' options MUST have a usage argument
89  * `switch' and `boolean' options have no argument
90  *
91  * if there's no desc(ription), it won't appear in usage()
92  */
93 static const struct {
94     unsigned long   flag;
95     const char    **dp;		/* data pointer */
96     const char     *const kw;	/* keyword */
97     const char     *const opt;	/* option */
98     const char     *const arg;	/* argument */
99     const char     *const desc;	/* description */
100 } optList[] = {
101 
102 /*
103  * INFO() - descriptive information only
104  * STRG() - command-line option, with/without resource
105  * RSTRG() - resource/long-option
106  * BOOL() - regular boolean `-/+' flag
107  * SWCH() - `-' flag
108  */
109 #define INFO(opt, arg, desc)			\
110     {0, NULL, NULL, opt, arg, desc}
111 #define STRG(p, kw, opt, arg, desc)		\
112     {0, &p, kw, opt, arg, desc}
113 #define RSTRG(p, kw, arg)			\
114     {0, &p, kw, NULL, arg, NULL}
115 #define BOOL(p, kw, opt, flag, desc)		\
116     {(Opt_Boolean|flag), &p, kw, opt, NULL, desc}
117 #define SWCH(opt, flag, desc)			\
118     {(flag), NULL, NULL, opt, NULL, desc}
119 
120 /* convenient macros */
121 #define optList_strlen(i)		\
122     (optList[i].flag ? 0 : (optList[i].arg ? strlen (optList[i].arg) : 1))
123 #define optList_isBool(i)		\
124     (optList[i].flag & Opt_Boolean)
125 #define optList_isReverse(i)		\
126     (optList[i].flag & Opt_Reverse)
127 #define optList_size()			\
128     (sizeof(optList) / sizeof(optList[0]))
129 
130     STRG(display_name, NULL, "display", "string",
131 	 "X server to contact"),
132     STRG(rs_term_name, "termName", "tn", "string",
133          "value of the TERM environment variable"),
134     STRG(rs_geometry, "geometry", "geometry", "geometry",
135          "size (in characters) and position"),
136     STRG(display_name, NULL, "d", NULL, NULL),	/* short form */
137     STRG(rs_geometry, NULL, "g", NULL, NULL),	/* short form */
138     BOOL(rs_reverseVideo, "reverseVideo", "rv", Opt_reverseVideo,
139          "reverse video"),
140 #ifdef _MYSTYLE_
141     STRG(rs_mystyle, "MyStyle", "mst", "name",
142          "MyStyle"),
143 #endif
144     STRG(rs_color[Color_bg], "background", "bg", "color",
145          "background color"),
146     STRG(rs_color[Color_fg], "foreground", "fg", "color",
147          "foreground color"),
148 /* colors: command-line long-option = resource name */
149     RSTRG(rs_color[minCOLOR + 0], "color0", "color"),
150     RSTRG(rs_color[minCOLOR + 1], "color1", "color"),
151     RSTRG(rs_color[minCOLOR + 2], "color2", "color"),
152     RSTRG(rs_color[minCOLOR + 3], "color3", "color"),
153     RSTRG(rs_color[minCOLOR + 4], "color4", "color"),
154     RSTRG(rs_color[minCOLOR + 5], "color5", "color"),
155     RSTRG(rs_color[minCOLOR + 6], "color6", "color"),
156     RSTRG(rs_color[minCOLOR + 7], "color7", "color"),
157 #ifndef NO_BRIGHTCOLOR
158     RSTRG(rs_color[minBrightCOLOR + 0], "color8", "color"),
159     RSTRG(rs_color[minBrightCOLOR + 1], "color9", "color"),
160     RSTRG(rs_color[minBrightCOLOR + 2], "color10", "color"),
161     RSTRG(rs_color[minBrightCOLOR + 3], "color11", "color"),
162     RSTRG(rs_color[minBrightCOLOR + 4], "color12", "color"),
163     RSTRG(rs_color[minBrightCOLOR + 5], "color13", "color"),
164     RSTRG(rs_color[minBrightCOLOR + 6], "color14", "color"),
165     RSTRG(rs_color[minBrightCOLOR + 7], "color15", "color"),
166 #endif				/* NO_BRIGHTCOLOR */
167 #ifndef NO_BOLDUNDERLINE
168     RSTRG(rs_color[Color_BD], "colorBD", "color"),
169     RSTRG(rs_color[Color_UL], "colorUL", "color"),
170 #endif				/* NO_BOLDUNDERLINE */
171 #ifdef KEEP_SCROLLCOLOR
172     RSTRG(rs_color[Color_scroll], "scrollColor", "color"),
173     RSTRG(rs_color[Color_trough], "troughColor", "color"),
174 #endif				/* KEEP_SCROLLCOLOR */
175 #if defined (BACKGROUND_IMAGE) || (MENUBAR_MAX)
176     RSTRG(rs_path, "path", "search path"),
177 #endif				/* defined (BACKGROUND_IMAGE) || (MENUBAR_MAX) */
178 #ifdef BACKGROUND_IMAGE
179     STRG(rs_backgroundPixmap,
180          "backgroundPixmap",
181          "pixmap", "file[;geom]", "background pixmap"),
182 #endif				/* BACKGROUND_IMAGE */
183 #if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT)
184     STRG(rs_backgroundType,
185          "backgroundType",
186          "bgtype", BGT_ALL, "type of the background pixmap transformation"),
187     STRG(rs_tintType,
188          "tintingType",
189          "tinttype", TINT_TYPE_ALL,
190 	 "defines function to be used for background tinting"),
191     STRG(rs_shade,
192          "shading",
193          "sh", "%", "make transparent background x% darker"),
194     STRG(rs_color[Color_tint],
195          "tinting",
196 	 "tint", "color",
197          "tinted transparency color"),
198 #endif
199     STRG(rs_textType,
200          "textType",
201          "txttype", GC_TYPE_ALL,
202 	 "defines function to be used for text drawing"),
203 #ifdef OFF_FOCUS_FADING
204     STRG(rs_fade,
205          "fading",
206          "fade", "%", "make colors x% darker when aterm is loosing focus."),
207 #endif
208 
209 #ifdef BOOL
210 #ifdef TRANSPARENT
211     BOOL(rs_transparent, "transparent", "tr", Opt_transparent,
212          "transparent background"),
213     BOOL(rs_transparent_sb, "transpscrollbar", "trsb", Opt_transparent_sb,
214          "transparent scrollbar"),
215 #endif
216 #endif
217 #if (MENUBAR_MAX)
218     RSTRG(rs_menu, "menu", "name[;tag]"),
219 #endif
220 #ifndef NO_BOLDFONT
221     STRG(rs_boldFont, "boldFont", "fb", "fontname", "bold text font"),
222 #endif
223     STRG(rs_font[0], "font", "fn", "fontname", "normal text font"),
224 /* fonts: command-line option = resource name */
225 #if NFONTS > 1
226     RSTRG(rs_font[1], "font1", "fontname"),
227 #endif
228 #if NFONTS > 2
229     RSTRG(rs_font[2], "font2", "fontname"),
230 #endif
231 #if NFONTS > 3
232     RSTRG(rs_font[3], "font3", "fontname"),
233 #endif
234 #if NFONTS > 4
235     RSTRG(rs_font[4], "font4", "fontname"),
236 #endif
237 #if NFONTS > 5
238     RSTRG(rs_font[5], "font5", "fontname"),
239 #endif
240 #if NFONTS > 6
241     RSTRG(rs_font[6], "font6", "fontname"),
242 #endif
243 #if NFONTS > 7
244     RSTRG(rs_font[7], "font7", "fontname"),
245 #endif
246 #ifdef MULTICHAR_SET
247     STRG(rs_mfont[0], "mfont", "fm", "fontname", "multichar font"),
248 
249 /* fonts: command-line option = resource name */
250 # if NFONTS > 1
251     RSTRG(rs_mfont[1], "mfont1", "fontname"),
252 # endif
253 # if NFONTS > 2
254     RSTRG(rs_mfont[2], "mfont2", "fontname"),
255 # endif
256 # if NFONTS > 3
257     RSTRG(rs_mfont[3], "mfont3", "fontname"),
258 # endif
259 # if NFONTS > 4
260     RSTRG(rs_mfont[4], "mfont4", "fontname"),
261 # endif
262 # if NFONTS > 5
263     RSTRG(rs_mfont[5], "mfont5", "fontname"),
264 # endif
265 # if NFONTS > 6
266     RSTRG(rs_mfont[6], "mfont6", "fontname"),
267 # endif
268 # if NFONTS > 7
269     RSTRG(rs_mfont[7], "mfont7", "fontname"),
270 # endif
271 #endif				/* MULTICHAR_SET */
272 
273 #ifdef MULTICHAR_SET
274     STRG(rs_multichar_encoding, "multichar_encoding", "km", "mode",
275          "multiple-character font encoding; mode = eucj | sjis | big5"),
276 #endif				/* MULTICHAR_SET */
277 #ifdef USE_XIM
278     STRG(rs_preeditType, "preeditType", "pt", "style",
279         "input style of input method; style = OverTheSpot | OffTheSpot | Root"),
280     STRG(rs_inputMethod, "inputMethod", "im", "name", "name of input method"),
281 #endif                         /* USE_XIM */
282 #ifdef GREEK_SUPPORT
283     STRG(rs_greek_keyboard, "greek_keyboard", "grk", "mode",
284          "greek keyboard mapping; mode = iso | ibm"),
285 #endif
286     SWCH("iconic", Opt_iconic, "start iconic"),
287     SWCH("ic", Opt_iconic, NULL),	/* short form */
288     STRG(rs_name, NULL, "name", "string",
289          "client instance, icon, and title strings"),
290     STRG(rs_title, "title", "title", "string", "title name for window"),
291     STRG(rs_title, NULL, "T", NULL, NULL),	/* short form */
292     STRG(rs_iconName, "iconName", "n", "string", "icon name for window"),
293 #ifndef NO_CURSORCOLOR
294     STRG(rs_color[Color_cursor], "cursorColor", "cr", "color",
295          "cursor color"),
296 /* command-line option = resource name */
297     RSTRG(rs_color[Color_cursor2], "cursorColor2", "color"),
298 #endif				/* NO_CURSORCOLOR */
299     STRG(rs_color[Color_pointer], "pointerColor", "pr", "color",
300          "pointer color"),
301     STRG(rs_borderWidth, "borderWidth", "bw", "number",
302          "width of border"),
303     STRG(rs_internal_border, "internalBorder", "ib", "number",
304          "width of the internal border"),
305     STRG(rs_color[Color_border], "borderColor", "bd", "color",
306          "border color"),
307     BOOL(rs_borderLess, "borderLess", "bl", Opt_borderLess, "no decoration"),
308     BOOL(rs_loginShell, "loginShell", "ls", Opt_loginShell, "login shell"),
309     BOOL(rs_scrollBar, "scrollBar", "sb", Opt_scrollBar, "scrollbar"),
310     BOOL(rs_scrollBar_right, "scrollBar_right", "sr", Opt_scrollBar_right,
311          "scrollbar right"),
312     BOOL(rs_scrollBar_floating, "scrollBar_floating", "st",
313          Opt_scrollBar_floating, "scrollbar without a trough"),
314     BOOL(rs_scrollTtyOutput, "scrollTtyOutput", NULL,
315          Opt_scrollTtyOutput, NULL),
316     BOOL(rs_scrollTtyOutput, NULL, "si", Opt_Reverse | Opt_scrollTtyOutput,
317 	 "scroll-on-tty-output inhibit"),
318     BOOL(rs_scrollKeypress, "scrollKey", "sk",
319          Opt_scrollKeypress, "scroll-on-keypress"),
320     STRG(rs_minBufferWidth, "minBufferWidth", "mbw", "number",
321          "minimum number of columns stored in buffer"),
322     STRG(rs_saveLines, "saveLines", "sl", "number",
323          "number of scrolled lines to save"),
324 #ifdef USE_LINESPACE
325     STRG(rs_lineSpace, "lineSpace", "lsp", "number",
326          "line space"),
327 #endif
328     BOOL(rs_utmpInhibit, "utmpInhibit", "ut", Opt_utmpInhibit,
329          "utmp inhibit"),
330     BOOL(rs_visualBell, "visualBell", "vb", Opt_visualBell, "visual bell"),
331 	BOOL(rs_cutToBeginningOfLine, "cutToBeginningOfLine", "cb", Opt_cutToBeginningOfLine,
332 			"cut to beginning of line"),
333 
334 #ifndef NO_MAPALERT
335 # ifdef MAPALERT_OPTION
336     BOOL(rs_mapAlert, "mapAlert", NULL, Opt_mapAlert, NULL),
337 # endif
338 #endif
339 #ifdef META8_OPTION
340     BOOL(rs_meta8, "meta8", NULL, Opt_meta8, NULL),
341     RSTRG(rs_modifier, "modifier", "string"),
342 #endif
343 #ifndef NO_BACKSPACE_KEY
344     RSTRG(rs_backspace_key, "backspacekey", "string"),
345 #endif
346 #ifndef NO_DELETE_KEY
347     RSTRG(rs_delete_key, "deletekey", "string"),
348 #endif
349 #ifdef PRINTPIPE
350     RSTRG(rs_print_pipe, "print-pipe", "string"),
351 #endif
352 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
353     RSTRG(rs_bigfont_key, "bigfont_key", "keysym"),
354     RSTRG(rs_smallfont_key, "smallfont_key", "keysym"),
355 #endif
356 #ifdef CUTCHAR_RESOURCE
357     RSTRG(rs_cutchars, "cutchars", "string"),
358 #endif				/* CUTCHAR_RESOURCE */
359     SWCH("C", Opt_console, "intercept console messages"),
360     INFO("e", "command arg ...", "command to execute")
361 };
362 
363 #undef INFO
364 #undef STRG
365 #undef RSTRG
366 #undef SWCH
367 #undef BOOL
368 /*}}} */
369 
370 /*{{{ list_options: */
371 /*----------------------------------------------------------------------*/
372 /* PROTO */
373 void
list_options()374 list_options()
375 {
376 #define INDENT 30
377     fprintf(stderr, "(");
378 #ifdef BACKGROUND_IMAGE
379     fprintf(stderr, "background image,");
380 #endif
381 #ifdef XPM
382     fprintf(stderr, "XPM,");
383 #endif
384 #ifdef USE_LIBASIMAGE
385 #ifdef JPEG
386     fprintf(stderr, "JPEG,");
387 #endif
388 #ifdef PNG
389     fprintf(stderr, "PNG,");
390 #endif
391     fprintf(stderr, "AfterStep integration,");
392 #ifdef _MYSTYLE_
393     fprintf(stderr, "AfterStep MyStyles,");
394 #else
395     fprintf(stderr, "no AfterStep MyStyles,");
396 #endif
397 #endif
398 #ifdef UTMP_SUPPORT
399     fprintf(stderr, "utmp,");
400 #endif
401 #ifdef MENUBAR
402     fprintf(stderr, "menubar,");
403 #endif
404 #ifdef KANJI
405     fprintf(stderr, "Kanji,");
406 #endif
407 #ifdef ZH
408     fprintf(stderr, "Chinese,");
409 #endif
410 #ifdef THAI
411     fprintf(stderr, "Thai,");
412 #endif
413 #ifdef XTERM_SCROLLBAR
414     fprintf(stderr, "XTerm-scrollbar,");
415 #endif
416 #ifdef GREEK_SUPPORT
417     fprintf(stderr, "Greek,");
418 #endif
419 #ifdef NO_BACKSPACE_KEY
420     fprintf(stderr, "no backspace,");
421 #endif
422 #ifdef NO_DELETE_KEY
423     fprintf(stderr, "no delete,");
424 #endif
425 #ifdef TRANSPARENT
426     fprintf(stderr, "transparency,");
427 #else
428     fprintf(stderr, "no transparency,");
429 # endif
430 #ifdef OFF_FOCUS_FADING
431     fprintf(stderr, "fading,");
432 #else
433     fprintf(stderr, "no fading,");
434 # endif
435 #ifdef NEXT_SCROLLBAR
436     fprintf(stderr, "NeXT scrollbar,");
437 # endif
438 #ifdef NO_RESOURCES
439     fprintf(stderr, "NoResources");
440 #else
441 # ifdef USE_XGETDEFAULT
442     fprintf(stderr, "XGetDefaults");
443 # else
444     fprintf(stderr, ".Xdefaults");
445 # endif
446 #endif
447 
448     fprintf(stderr, ")" );
449 
450 }
451 /*}}} */
452 
453 /*{{{ usage: */
454 /*----------------------------------------------------------------------*/
455 /* PROTO */
456 void
version(int type)457 version(int type)
458 {
459     switch (type) {
460         case 0:			/* brief listing */
461 	    fprintf(stderr, "%s version %s\n", APL_NAME,VERSION);
462 	    break ;
463         case 1:			/* full command-line listing */
464 	    fprintf(stderr, "%s version %s from %s\n", APL_NAME,VERSION, DATE);
465 	    list_options();
466 	    fprintf(stderr, "\n");
467 	    break ;
468 	case 2:			/* full resource listing */
469 	    fprintf(stderr, "%s\n", VERSION);
470 	    break ;
471     }
472     exit(EXIT_FAILURE);
473 }
474 /*}}} */
475 
476 /*{{{ usage: */
477 /*----------------------------------------------------------------------*/
478 /* PROTO */
479 void
usage(int type)480 usage(int type)
481 {
482     int             i, col;
483 
484     fprintf(stderr, "\nUsage v%s :", VERSION);
485     list_options();
486     fprintf(stderr, "\n%s", APL_NAME);
487 
488     switch (type) {
489     case 0:			/* brief listing */
490 	fprintf(stderr, " [-help][-V]\n");
491 	col = 3;
492 	for (i = 0; i < optList_size(); i++) {
493 	    if (optList[i].desc != NULL) {
494 		int             len = 2;
495 
496 		if (!optList_isBool(i)) {
497 		    len = optList_strlen(i);
498 		    if (len > 0)
499 			len++;	/* account for space */
500 		}
501 		len += 4 + strlen(optList[i].opt);
502 
503 		col += len;
504 		if (col > 79) {	/* assume regular width */
505 		    fprintf(stderr, "\n");
506 		    col = 3 + len;
507 		}
508 		fprintf(stderr, " [-");
509 		if (optList_isBool(i))
510 		    fprintf(stderr, "/+");
511 		fprintf(stderr, "%s", optList[i].opt);
512 		if (optList_strlen(i))
513 		    fprintf(stderr, " %s]", optList[i].arg);
514 		else
515 		    fprintf(stderr, "]");
516 	    }
517 	}
518 	fprintf(stderr, "\n\n");
519 	break;
520 
521     case 1:			/* full command-line listing */
522 	fprintf(stderr,
523 		" [options] [-e command args]\n\n"
524 		"where options include:\n");
525 
526 	for (i = 0; i < optList_size(); i++)
527 	    if (optList[i].desc != NULL)
528 		fprintf(stderr, "    %s%s %-*s%s%s\n",
529 			(optList_isBool(i) ? "-/+" : "-"),
530 			optList[i].opt,
531 			(INDENT - strlen(optList[i].opt)
532 			 + (optList_isBool(i) ? 0 : 2)),
533 			(optList[i].arg ? optList[i].arg : ""),
534 			(optList_isBool(i) ? "turn on/off " : ""),
535 			optList[i].desc);
536 	fprintf(stderr, "\n    --help to list long-options\n    --version for the version information\n\n");
537 	break;
538 
539     case 2:			/* full resource listing */
540 	fprintf(stderr,
541 		" [options] [-e command args]\n\n"
542 		"where resources (long-options) include:\n");
543 
544 	for (i = 0; i < optList_size(); i++)
545 	    if (optList[i].kw != NULL)
546 		fprintf(stderr, "    %s: %*s\n",
547 			optList[i].kw,
548 			(INDENT - strlen(optList[i].kw)),
549 			(optList_isBool(i) ? "boolean" : optList[i].arg));
550 
551 #ifdef KEYSYM_RESOURCE
552 	fprintf(stderr, "    " "keysym.sym" ": %*s\n",
553 		(INDENT - strlen("keysym.sym")), "keysym");
554 #endif
555 	fprintf(stderr, "\n    -help to list options\n    -version for the version information with options list\n\n");
556 	break;
557     }
558     exit(EXIT_FAILURE);
559 }
560 /*}}} */
561 
562 /*{{{ get command-line options before getting resources */
563 /* PROTO */
564 void
get_options(int argc,char * argv[])565 get_options(int argc, char *argv[])
566 {
567     int             i, bad_option = 0;
568     static const char *const On = "ON";
569     static const char *const Off = "OFF";
570 
571     for (i = 1; i < argc; i++) {
572 	int             entry, longopt = 0;
573 	const char     *flag;
574 	char           *opt = argv[i];
575 
576 #ifdef DEBUG_RESOURCES
577 	fprintf(stderr, "argv[%d] = %s: ", i, argv[i]);
578 #endif
579 	if (*opt == '-') {
580 	    flag = On;
581 	    if (*++opt == '-')
582 		longopt = *opt++;	/* long option */
583 	} else if (*opt == '+') {
584 	    flag = Off;
585 	    if (*++opt == '+')
586 		longopt = *opt++;	/* long option */
587 	} else {
588 	    bad_option = 1;
589 	    print_error("bad option \"%s\"", opt);
590 	    continue;
591 	}
592 
593 	if (!strcmp(opt, "help"))
594 	    usage(longopt ? 2 : 1);
595 	if (!strcmp(opt, "h"))
596 	    usage(0);
597 	if (!strcmp(opt, "version"))
598 	    version(longopt ? 2 : 1);
599 	if (!strcmp(opt, "V"))
600 	    version(0);
601 
602     /* feature: always try to match long-options */
603 	for (entry = 0; entry < optList_size(); entry++)
604 	    if ((optList[entry].kw && !strcmp(opt, optList[entry].kw)) ||
605 		(!longopt &&
606 		 optList[entry].opt && !strcmp(opt, optList[entry].opt)))
607 		break;
608 
609 	if (entry < optList_size()) {
610 	    if (optList_isReverse(entry))
611 		flag = flag == On ? Off : On;
612 	    if (optList_strlen(entry)) {	/* string value */
613 		char           *str = argv[++i];
614 
615 #ifdef DEBUG_RESOURCES
616 		fprintf(stderr, "string (%s,%s) = ",
617 			optList[entry].opt ? optList[entry].opt : "nil",
618 			optList[entry].kw ? optList[entry].kw : "nil");
619 #endif
620 		if (flag == On && str && optList[entry].dp) {
621 #ifdef DEBUG_RESOURCES
622 		    fprintf(stderr, "\"%s\"\n", str);
623 #endif
624 		    *(optList[entry].dp) = str;
625 
626 		/* special cases are handled in main.c:main() to allow
627 		 * X resources to set these values before we settle for
628 		 * default values
629 		 */
630 		}
631 #ifdef DEBUG_RESOURCES
632 		else
633 		    fprintf(stderr, "???\n");
634 #endif
635 	    } else {		/* boolean value */
636 #ifdef DEBUG_RESOURCES
637 		fprintf(stderr, "boolean (%s,%s) = %s\n",
638 			optList[entry].opt, optList[entry].kw, flag);
639 #endif
640 		if (flag == On)
641 		    Options |= (optList[entry].flag);
642 		else
643 		    Options &= ~(optList[entry].flag);
644 
645 		if (optList[entry].dp)
646 		    *(optList[entry].dp) = flag;
647 	    }
648 	} else
649 #ifdef KEYSYM_RESOURCE
650 	/* if (!strncmp (opt, "keysym.", strlen ("keysym."))) */
651 	if (Str_match(opt, "keysym.")) {
652 	    char           *str = argv[++i];
653 
654 	/*
655 	 * '7' is strlen("keysym.")
656 	 */
657 	    if (str != NULL)
658 		parse_keysym(opt + 7, str);
659 	} else
660 #endif
661 	{
662 	/* various old-style options, just ignore
663 	 * Obsolete since about Jan 96,
664 	 * so they can probably eventually be removed
665 	 */
666 	    const char     *msg = "bad";
667 
668 	    if (longopt) {
669 		opt--;
670 		bad_option = 1;
671 	    } else if (!strcmp(opt, "7") || !strcmp(opt, "8")
672 #ifdef GREEK_SUPPORT
673 	    /* obsolete 12 May 1996 (v2.17) */
674 		       || !Str_match(opt, "grk")
675 #endif
676 		)
677 		msg = "obsolete";
678 	    else
679 		bad_option = 1;
680 
681 	    print_error("%s option \"%s\"", msg, --opt);
682 	}
683     }
684 
685     if (bad_option)
686 	usage(0);
687 }
688 /*}}} */
689 
690 #ifndef NO_RESOURCES
691 /*----------------------------------------------------------------------*/
692 /*{{{ string functions */
693 /*
694  * a replacement for strcasecmp() to avoid linking an entire library
695  */
696 /* PROTO */
697 int
my_strcasecmp(const char * s1,const char * s2)698 my_strcasecmp(const char *s1, const char *s2)
699 {
700     for ( /*nil */ ; (*s1 && *s2); s1++, s2++) {
701 	register int    c1 = toupper(*s1);
702 	register int    c2 = toupper(*s2);
703 
704 	if (c1 != c2)
705 	    return (c1 - c2);
706     }
707     return (int)(*s1 - *s2);
708 }
709 
710 /*}}} */
711 
712 # ifdef KEYSYM_RESOURCE
713 /*
714  * Define key from XrmEnumerateDatabase.
715  *   quarks will be something like
716  *      "rxvt" "keysym" "0xFF01"
717  *   value will be a string
718  */
719 /* ARGSUSED */
720 /* PROTO */
721 Bool
define_key(XrmDatabase * database,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)722 define_key(XrmDatabase * database, XrmBindingList bindings, XrmQuarkList quarks, XrmRepresentation * type, XrmValue * value, XPointer closure)
723 {
724     int             last;
725 
726     for (last = 0; quarks[last] != NULLQUARK; last++)	/* look for last quark in list */
727 	;
728     last--;
729     parse_keysym(XrmQuarkToString(quarks[last]), (char *)value->addr);
730     return False;
731 }
732 
733 /*
734  * look for something like this (XK_Delete)
735  * rxvt*keysym.0xFFFF: "\177"
736  *
737  * arg will be
738  *      NULL for ~/.Xdefaults and
739  *      non-NULL for command-line options (need to allocate)
740  */
741 /* PROTO */
742 int
parse_keysym(char * str,char * arg)743 parse_keysym(char *str, char *arg)
744 {
745     char           *key_string;
746     int             n, sym;
747 
748     if (arg == NULL) {
749 	if ((n = Str_match(str, "keysym.")) == 0)
750 	    return 0;
751 	str += n;		/* skip `keysym.' */
752     }
753 /* some scanf() have trouble with a 0x prefix */
754     if (isdigit(str[0])) {
755 	if (str[0] == '0' && toupper(str[1]) == 'X')
756 	    str += 2;
757 	if (arg) {
758 	    if (sscanf(str, (strchr(str, ':') ? "%x:" : "%x"), &sym) != 1)
759 		return -1;
760 	} else {
761 	    if (sscanf(str, "%x:", &sym) != 1)
762 		return -1;
763 
764 	/* cue to ':', it's there since sscanf() worked */
765 	    str = strchr(str, ':');
766 	    str++;
767 	    arg = Str_trim(str);
768 	    if (arg == NULL)
769 		return -1;
770 	}
771     } else {
772     /*
773      * convert keysym name to keysym number
774      */
775 	if (arg == NULL) {
776 	    arg = str;
777 
778 	    arg = strchr(str, ':');
779 	    if (arg == NULL)
780 		return -1;
781 
782 	    *arg++ = '\0';
783 	    arg = Str_trim(arg);
784 	    if (arg == NULL)
785 		return -1;
786 	}
787 	sym = XStringToKeysym(str);
788 
789 	if (sym == None)
790 	    return -1;
791     }
792 
793     if (sym < 0xFF00 || sym > 0xFFFF)	/* we only do extended keys */
794 	return -1;
795     sym -= 0xFF00;
796 
797     if (KeySym_map[sym] != NULL)	/* already set ? */
798 	return -1;
799 
800     if ((n = strlen(arg)) == 0)
801 	return -1;
802 
803     key_string = MALLOC((n + 2) * sizeof(char));
804 
805     STRCPY(key_string + 1, arg);
806 
807     n = Str_escaped(key_string + 1);
808     if (n) {
809 	key_string[0] = min(n, 255);
810 	KeySym_map[sym] = (unsigned char *) key_string;
811     } else {
812 	FREE(key_string);
813 	return -1;
814     }
815 
816     return 1;
817 }
818 # endif				/* KEYSYM_RESOURCE */
819 
820 # ifndef USE_XGETDEFAULT
821 /*{{{ get_xdefaults() */
822 /*
823  * the matching algorithm used for memory-save fake resources
824  */
825 /* PROTO */
826 void
get_xdefaults(FILE * stream,const char * name)827 get_xdefaults(FILE * stream, const char *name)
828 {
829     unsigned int    len;
830     char           *str, buffer[256];
831 
832     if (stream == NULL)
833 	return;
834     len = strlen(name);
835     while ((str = fgets(buffer, sizeof(buffer), stream)) != NULL) {
836 	unsigned int    entry, n;
837 
838 	while (*str && isspace(*str))
839 	    str++;		/* leading whitespace */
840 
841 	if ((str[len] != '*' && str[len] != '.') ||
842 	    (len && strncmp(str, name, len)))
843 	    continue;
844 	str += (len + 1);	/* skip `name*' or `name.' */
845 
846 # ifdef KEYSYM_RESOURCE
847 	if (!parse_keysym(str, NULL))
848 # endif				/* KEYSYM_RESOURCE */
849 	    for (entry = 0; entry < optList_size(); entry++) {
850 		const char     *const kw = optList[entry].kw;
851 
852 		if (kw == NULL)
853 		    continue;
854 		n = strlen(kw);
855 		if (str[n] == ':' && Str_match(str, kw)) {
856 		/* skip `keyword:' */
857 		    str += (n + 1);
858 		    str = Str_skip_space(str);
859 		    str = Str_trim(str);
860 		    n = (str ? strlen(str) : 0);
861 		    if (n && *(optList[entry].dp) == NULL) {
862 		    /* not already set */
863 			int		s;
864 			char           *p = MALLOC((n + 1) * sizeof(char));
865 
866 			STRCPY(p, str);
867 			*(optList[entry].dp) = p;
868 			if (optList_isBool(entry)) {
869 			    s = my_strcasecmp(p, "TRUE") == 0
870 				|| my_strcasecmp(p, "YES") == 0
871 				|| my_strcasecmp(p, "ON") == 0
872 				|| my_strcasecmp(p, "1") == 0;
873 			    if (optList_isReverse(entry))
874 				s = !s;
875 			    if (s)
876 				Options |= (optList[entry].flag);
877 			    else {
878 				if (my_strcasecmp(str, "FALSE"))
879 				    print_error("Cannot parse value \"%s\" from resource \"%s\" as boolean",
880 						str, kw);
881 				Options &= ~(optList[entry].flag);
882 			    }
883 			}
884 		    }
885 		    break;
886 		}
887 	    }
888     }
889     rewind(stream);
890 }
891 /*}}} */
892 # endif				/* ! USE_XGETDEFAULT */
893 #endif				/* NO_RESOURCES */
894 
895 /*{{{ read the resources files */
896 /*
897  * using XGetDefault() or the hand-rolled replacement
898  */
899 /* ARGSUSED */
900 /* PROTO */
901 void
extract_resources(Display * display,const char * name)902 extract_resources(Display * display, const char *name)
903 {
904 #ifndef NO_RESOURCES
905 # ifdef USE_XGETDEFAULT
906 /*
907  * get resources using the X library function
908  */
909     int             entry;
910 
911 #  ifdef XrmEnumOneLevel
912     XrmName         name_prefix[3];
913     XrmClass        class_prefix[3];
914     char           *displayResource;
915     XrmDatabase     database;
916     char           *screenResource;
917     XrmDatabase     screenDatabase;
918 
919 /*
920  * Get screen-specific resources (X11R5) and merge into common resources.
921  */
922     database = NULL;
923     screenDatabase = NULL;
924     displayResource = XResourceManagerString(display);
925     if (displayResource != NULL)
926 	database = XrmGetStringDatabase(displayResource);
927     screenResource = XScreenResourceString(DefaultScreenOfDisplay(display));
928     if (screenResource != NULL)
929 	screenDatabase = XrmGetStringDatabase(screenResource);
930     XrmMergeDatabases(screenDatabase, &database);
931     XrmSetDatabase(display, database);
932 #  endif
933 
934     for (entry = 0; entry < optList_size(); entry++) {
935 	int		s;
936 	char           *p, *p0;
937 	const char     *kw = optList[entry].kw;
938 
939 	if (kw == NULL || *(optList[entry].dp) != NULL)
940 	    continue;		/* previously set */
941 
942 #define STRCMP(x, y)		strcmp((const char *)(x), (const char *)(y))
943 	p = XGetDefault(display, name, kw);
944 	p0 = XGetDefault(display, "!INVALIDPROGRAMMENAMEDONTMATCH!", kw);
945 	if (p == NULL || (p0 && STRCMP(p, p0) == 0)) {
946 	    p = XGetDefault(display, APL_SUBCLASS, kw);
947 	    if (p == NULL || (p0 && STRCMP(p, p0) == 0))
948 		p = XGetDefault(display, APL_CLASS, kw);
949 	}
950 	if (p == NULL && p0)
951 	    p = p0;
952 	if (p) {
953 	    *optList[entry].dp = p;
954 
955 	    if (optList_isBool(entry)) {
956 		s = my_strcasecmp(p, "TRUE") == 0
957 		    || my_strcasecmp(p, "YES") == 0
958 		    || my_strcasecmp(p, "ON") == 0
959 		    || my_strcasecmp(p, "1") == 0;
960 		if (optList_isReverse(entry))
961 		    s = !s;
962 		if (s)
963 		    Options |= (optList[entry].flag);
964 		else {
965 		    if (my_strcasecmp(p, "FALSE"))
966 			print_error("Cannot parse value \"%s\" from resource \"%s\" as boolean",
967 				    p, kw);
968 		    Options &= ~(optList[entry].flag);
969 		}
970 	    }
971 	}
972     }
973 
974 /*
975  * [R5 or later]: enumerate the resource database
976  */
977 #  ifdef XrmEnumOneLevel
978 #   ifdef KEYSYM_RESOURCE
979     name_prefix[0] = XrmStringToName(name);
980     name_prefix[1] = XrmStringToName("keysym");
981     name_prefix[2] = NULLQUARK;
982     class_prefix[0] = XrmStringToName(APL_SUBCLASS);
983     class_prefix[1] = XrmStringToName("Keysym");
984     class_prefix[2] = NULLQUARK;
985     XrmEnumerateDatabase(XrmGetDatabase(display),
986 			 name_prefix,
987 			 class_prefix,
988 			 XrmEnumOneLevel,
989 			 define_key,
990 			 NULL);
991     name_prefix[0] = XrmStringToName(APL_CLASS);
992     name_prefix[1] = XrmStringToName("keysym");
993     class_prefix[0] = XrmStringToName(APL_CLASS);
994     class_prefix[1] = XrmStringToName("Keysym");
995     XrmEnumerateDatabase(XrmGetDatabase(display),
996 			 name_prefix,
997 			 class_prefix,
998 			 XrmEnumOneLevel,
999 			 define_key,
1000 			 NULL);
1001 #   endif
1002 #  endif
1003 
1004 # else				/* USE_XGETDEFAULT */
1005 /* get resources the hard way, but save lots of memory */
1006     const char     *fname[] = { ".Xdefaults", ".Xresources" };
1007     FILE           *fd = NULL;
1008     char           *home;
1009 
1010     if ((home = getenv("HOME")) != NULL) {
1011 	int             i, len = strlen(home) + 2;
1012 	char           *f = NULL;
1013 
1014 	for (i = 0; i < (sizeof(fname) / sizeof(fname[0])); i++) {
1015 	    f = REALLOC(f, (len + strlen(fname[i])) * sizeof(char));
1016 
1017 	    sprintf(f, "%s/%s", home, fname[i]);
1018 
1019 	    if ((fd = fopen(f, "r")) != NULL)
1020 		break;
1021 	}
1022 	FREE(f);
1023     }
1024 /*
1025  * The normal order to match resources is the following:
1026  * @ global resources (partial match, ~/.Xdefaults)
1027  * @ application file resources (XAPPLOADDIR/Rxvt)
1028  * @ class resources (~/.Xdefaults)
1029  * @ private resources (~/.Xdefaults)
1030  *
1031  * However, for the hand-rolled resources, the matching algorithm
1032  * checks if a resource string value has already been allocated
1033  * and won't overwrite it with (in this case) a less specific
1034  * resource value.
1035  *
1036  * This avoids multiple allocation.  Also, when we've called this
1037  * routine command-line string options have already been applied so we
1038  * needn't to allocate for those resources.
1039  *
1040  * So, search in resources from most to least specific.
1041  *
1042  * Also, use a special sub-class so that we can use either or both of
1043  * "XTerm" and "Rxvt" as class names.
1044  */
1045 
1046     get_xdefaults(fd, name);
1047     get_xdefaults(fd, APL_SUBCLASS);
1048 
1049 #  ifdef XAPPLOADDIR
1050     {
1051 	FILE           *ad = fopen(XAPPLOADDIR "/" APL_SUBCLASS, "r");
1052 
1053 	if (ad != NULL) {
1054 	    get_xdefaults(ad, "");
1055 	    fclose(ad);
1056 	}
1057     }
1058 #  endif				/* XAPPLOADDIR */
1059 
1060     get_xdefaults(fd, APL_CLASS);
1061     get_xdefaults(fd, "");	/* partial match */
1062     if (fd != NULL)
1063 	fclose(fd);
1064 # endif				/* USE_XGETDEFAULT */
1065 #endif				/* NO_RESOURCES */
1066 
1067 /*
1068  * even without resources, at least do this setup for command-line
1069  * options and command-line long options
1070  */
1071 #ifdef MULTICHAR_SET
1072     set_multichar_encoding(rs_multichar_encoding);
1073 #endif
1074 #ifdef GREEK_SUPPORT
1075 /* this could be a function in grkelot.c */
1076 /* void set_greek_keyboard (const char * str); */
1077     if (rs_greek_keyboard) {
1078 	if (!strcmp(rs_greek_keyboard, "iso"))
1079 	    greek_setmode(GREEK_ELOT928);	/* former -grk9 */
1080 	else if (!strcmp(rs_greek_keyboard, "ibm"))
1081 	    greek_setmode(GREEK_IBM437);	/* former -grk4 */
1082     }
1083 #endif				/* GREEK_SUPPORT */
1084 
1085 #define to_keysym(pks,str) do { KeySym sym;\
1086 if (str && ((sym = XStringToKeysym(str)) != 0)) *pks = sym; } while (0)
1087 
1088 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
1089     to_keysym(&ks_bigfont, rs_bigfont_key);
1090     to_keysym(&ks_smallfont, rs_smallfont_key);
1091 #endif
1092 #undef to_keysym
1093 }
1094 /*}}} */
1095 /*----------------------- end-of-file (C source) -----------------------*/
1096