1 /* $XTermId: trace.c,v 1.234 2021/09/14 20:09:56 tom Exp $ */
2 
3 /*
4  * Copyright 1997-2020,2021 by Thomas E. Dickey
5  *
6  *                         All Rights Reserved
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Except as contained in this notice, the name(s) of the above copyright
28  * holders shall not be used in advertising or otherwise to promote the
29  * sale, use or other dealings in this Software without prior written
30  * authorization.
31  */
32 
33 /*
34  * debugging support via TRACE macro.
35  */
36 
37 #include <xterm.h>		/* for definition of GCC_UNUSED */
38 #include <xstrings.h>
39 #include <wcwidth.h>
40 #include <version.h>
41 
42 #if OPT_TRACE
43 
44 #include <data.h>
45 #include <trace.h>
46 
47 #include <time.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <stdio.h>
53 #include <assert.h>
54 
55 #include <X11/Xatom.h>
56 #include <X11/Xmu/Atoms.h>
57 #include <X11/Xmu/Error.h>
58 
59 #ifdef HAVE_X11_TRANSLATEI_H
60 #include <X11/ConvertI.h>
61 #include <X11/TranslateI.h>
62 #else
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66 
67     extern String _XtPrintXlations(Widget w,
68 				   XtTranslations xlations,
69 				   Widget accelWidget,
70 				   _XtBoolean includeRHS);
71 #ifdef __cplusplus
72 }
73 #endif
74 #endif
75 const char *trace_who = "parent";
76 
77 static FILE *trace_fp;
78 
79 static FILE *
TraceOpen(void)80 TraceOpen(void)
81 {
82     static const char *trace_out;
83 
84     if (trace_fp != 0
85 	&& trace_who != trace_out) {
86 	fclose(trace_fp);
87 	trace_fp = 0;
88     }
89     trace_out = trace_who;
90 
91     if (!trace_fp) {
92 	static char dot[] = ".";
93 	mode_t oldmask = umask(077);
94 	/*
95 	 * Put the trace-file in user's home-directory if the current
96 	 * directory is not writable.
97 	 */
98 	char *home = (access(dot, R_OK | W_OK) == 0) ? dot : getenv("HOME");
99 	char *name = malloc(strlen(home) + strlen(trace_who) + 50);
100 #if OPT_TRACE_UNIQUE		/* usually I do not want unique names */
101 	int unique;
102 	for (unique = 0;; ++unique) {
103 	    if (unique)
104 		sprintf(name, "%s/Trace-%s.out-%d", home, trace_who, unique);
105 	    else
106 		sprintf(name, "%s/Trace-%s.out", home, trace_who);
107 	    if ((trace_fp = fopen(name, "r")) == 0) {
108 		break;
109 	    }
110 	    fclose(trace_fp);
111 	}
112 #else
113 	sprintf(name, "%s/Trace-%s.out", home, trace_who);
114 #endif
115 	trace_fp = fopen(name, "w");
116 	if (trace_fp != 0) {
117 	    fprintf(trace_fp, "%s\n", xtermVersion());
118 	    TraceIds(NULL, 0);
119 	}
120 	if (!trace_fp) {
121 	    xtermWarning("Cannot open \"%s\"\n", name);
122 	    exit(EXIT_FAILURE);
123 	}
124 	(void) umask(oldmask);
125 	free(name);
126     }
127     return trace_fp;
128 }
129 
130 void
Trace(const char * fmt,...)131 Trace(const char *fmt, ...)
132 {
133     va_list ap;
134     FILE *fp = TraceOpen();
135 
136     va_start(ap, fmt);
137     vfprintf(fp, fmt, ap);
138     (void) fflush(fp);
139     va_end(ap);
140 }
141 
142 void
TraceVA(const char * fmt,va_list ap)143 TraceVA(const char *fmt, va_list ap)
144 {
145     FILE *fp = TraceOpen();
146 
147     vfprintf(fp, fmt, ap);
148     (void) fflush(fp);
149 }
150 
151 void
TraceClose(void)152 TraceClose(void)
153 {
154     if (trace_fp != 0) {
155 	(void) fclose(trace_fp);
156 	(void) fflush(stdout);
157 	(void) fflush(stderr);
158 	(void) visibleChars(NULL, 0);
159 	(void) visibleIChars(NULL, 0);
160 	trace_fp = 0;
161     }
162 }
163 
164 void
TraceXError(Display * d,XErrorEvent * ev)165 TraceXError(Display *d, XErrorEvent *ev)
166 {
167     FILE *fp = TraceOpen();
168     (void) XmuPrintDefaultErrorMessage(d, ev, fp);
169     (void) fflush(fp);
170 }
171 
172 void
TraceIds(const char * fname,int lnum)173 TraceIds(const char *fname, int lnum)
174 {
175     Trace("process %d ", (int) getpid());
176 #ifdef HAVE_UNISTD_H
177     Trace("real (%u/%u) effective (%u/%u)",
178 	  (unsigned) getuid(), (unsigned) getgid(),
179 	  (unsigned) geteuid(), (unsigned) getegid());
180 #endif
181     if (fname != 0) {
182 	Trace(" (%s@%d)\n", fname, lnum);
183     } else {
184 	time_t now = time((time_t *) 0);
185 	Trace("-- %s", ctime(&now));
186     }
187 }
188 
189 void
TraceTime(const char * fname,int lnum)190 TraceTime(const char *fname, int lnum)
191 {
192     time_t now;
193     if (fname != 0) {
194 	Trace("datetime (%s@%d) ", fname, lnum);
195     }
196     now = time((time_t *) 0);
197     Trace("-- %s", ctime(&now));
198 }
199 
200 static void
formatAscii(char * dst,unsigned value)201 formatAscii(char *dst, unsigned value)
202 {
203     switch (value) {
204     case '\\':
205 	sprintf(dst, "\\\\");
206 	break;
207     case '\b':
208 	sprintf(dst, "\\b");
209 	break;
210     case '\n':
211 	sprintf(dst, "\\n");
212 	break;
213     case '\r':
214 	sprintf(dst, "\\r");
215 	break;
216     case '\t':
217 	sprintf(dst, "\\t");
218 	break;
219     default:
220 	if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160))
221 	    sprintf(dst, "\\%03o", value & 0xff);
222 	else
223 	    sprintf(dst, "%c", CharOf(value));
224 	break;
225     }
226 }
227 
228 #if OPT_DEC_CHRSET
229 
230 const char *
visibleDblChrset(unsigned chrset)231 visibleDblChrset(unsigned chrset)
232 {
233     const char *result = "?";
234     switch (chrset) {
235     case CSET_SWL:
236 	result = "CSET_SWL";
237 	break;
238     case CSET_DHL_TOP:
239 	result = "CSET_DHL_TOP";
240 	break;
241     case CSET_DHL_BOT:
242 	result = "CSET_DHL_BOT";
243 	break;
244     case CSET_DWL:
245 	result = "CSET_DWL";
246 	break;
247     }
248     return result;
249 }
250 #endif
251 
252 const char *
visibleScsCode(DECNRCM_codes chrset)253 visibleScsCode(DECNRCM_codes chrset)
254 {
255 #define MAP(to,from) case from: result = to ":" #from; break
256     const char *result = "<ERR>";
257     switch ((DECNRCM_codes) chrset) {
258 	MAP("B", nrc_ASCII);
259 	MAP("A", nrc_British);
260 	MAP("A", nrc_British_Latin_1);
261 	MAP("&4", nrc_DEC_Cyrillic);
262 	MAP("0", nrc_DEC_Spec_Graphic);
263 	MAP("1", nrc_DEC_Alt_Chars);
264 	MAP("2", nrc_DEC_Alt_Graphics);
265 	MAP("<", nrc_DEC_Supp);
266 	MAP("%5", nrc_DEC_Supp_Graphic);
267 	MAP(">", nrc_DEC_Technical);
268 	MAP("4", nrc_Dutch);
269 	MAP("5", nrc_Finnish);
270 	MAP("C", nrc_Finnish2);
271 	MAP("R", nrc_French);
272 	MAP("f", nrc_French2);
273 	MAP("Q", nrc_French_Canadian);
274 	MAP("9", nrc_French_Canadian2);
275 	MAP("K", nrc_German);
276 	MAP("\"?", nrc_DEC_Greek_Supp);
277 	MAP("\">", nrc_Greek);
278 	MAP("F", nrc_ISO_Greek_Supp);
279 	MAP("\"4", nrc_DEC_Hebrew_Supp);
280 	MAP("%=", nrc_Hebrew);
281 	MAP("H", nrc_ISO_Hebrew_Supp);
282 	MAP("Y", nrc_Italian);
283 	MAP("A", nrc_ISO_Latin_1_Supp);
284 	MAP("B", nrc_ISO_Latin_2_Supp);
285 	MAP("M", nrc_ISO_Latin_5_Supp);
286 	MAP("L", nrc_ISO_Latin_Cyrillic);
287 	MAP("`", nrc_Norwegian_Danish);
288 	MAP("E", nrc_Norwegian_Danish2);
289 	MAP("6", nrc_Norwegian_Danish3);
290 	MAP("%6", nrc_Portugese);
291 	MAP("&5", nrc_Russian);
292 	MAP("%3", nrc_SCS_NRCS);
293 	MAP("Z", nrc_Spanish);
294 	MAP("7", nrc_Swedish);
295 	MAP("H", nrc_Swedish2);
296 	MAP("=", nrc_Swiss);
297 	MAP("%2", nrc_Turkish);
298 	MAP("%0", nrc_DEC_Turkish_Supp);
299 	MAP("<UNK>", nrc_Unknown);
300     }
301 #undef MAP
302     return result;
303 }
304 
305 const char *
visibleChars(const Char * buf,unsigned len)306 visibleChars(const Char *buf, unsigned len)
307 {
308     static char *result;
309     static unsigned used;
310 
311     if (buf != 0) {
312 	unsigned limit = ((len + 1) * 8) + 1;
313 
314 	if (limit > used) {
315 	    used = limit;
316 	    result = XtRealloc(result, used);
317 	}
318 	if (result != 0) {
319 	    char *dst = result;
320 	    *dst = '\0';
321 	    while (len--) {
322 		unsigned value = *buf++;
323 		formatAscii(dst, value);
324 		dst += strlen(dst);
325 	    }
326 	}
327     } else {
328 	FreeAndNull(result);
329 	used = 0;
330     }
331     return NonNull(result);
332 }
333 
334 const char *
visibleEventMode(EventMode value)335 visibleEventMode(EventMode value)
336 {
337     const char *result;
338     switch (value) {
339     case NORMAL:
340 	result = "NORMAL";
341 	break;
342     case LEFTEXTENSION:
343 	result = "LEFTEXTENSION";
344 	break;
345     case RIGHTEXTENSION:
346 	result = "RIGHTEXTENSION";
347 	break;
348     default:
349 	result = "?";
350 	break;
351     }
352     return result;
353 }
354 
355 const char *
visibleIChars(const IChar * buf,unsigned len)356 visibleIChars(const IChar *buf, unsigned len)
357 {
358     static char *result;
359     static unsigned used;
360 
361     if (buf != 0) {
362 	unsigned limit = ((len + 1) * 12) + 1;
363 
364 	if (limit > used) {
365 	    used = limit;
366 	    result = XtRealloc(result, used);
367 	}
368 	if (result != 0) {
369 	    char *dst = result;
370 	    *dst = '\0';
371 	    while (len--) {
372 		unsigned value = *buf++;
373 #if OPT_WIDE_CHARS
374 		if (value > 255)
375 		    sprintf(dst, "\\U+%04X", value);
376 		else
377 #endif
378 		    formatAscii(dst, value);
379 		dst += strlen(dst);
380 	    }
381 	}
382     } else {
383 	FreeAndNull(result);
384 	used = 0;
385     }
386     return NonNull(result);
387 }
388 
389 const char *
visibleUChar(unsigned chr)390 visibleUChar(unsigned chr)
391 {
392     IChar buf[1];
393     buf[0] = (IChar) chr;
394     return visibleIChars(buf, 1);
395 }
396 
397 const char *
visibleEventType(int type)398 visibleEventType(int type)
399 {
400     const char *result = "?";
401     switch (type) {
402 	CASETYPE(KeyPress);
403 	CASETYPE(KeyRelease);
404 	CASETYPE(ButtonPress);
405 	CASETYPE(ButtonRelease);
406 	CASETYPE(MotionNotify);
407 	CASETYPE(EnterNotify);
408 	CASETYPE(LeaveNotify);
409 	CASETYPE(FocusIn);
410 	CASETYPE(FocusOut);
411 	CASETYPE(KeymapNotify);
412 	CASETYPE(Expose);
413 	CASETYPE(GraphicsExpose);
414 	CASETYPE(NoExpose);
415 	CASETYPE(VisibilityNotify);
416 	CASETYPE(CreateNotify);
417 	CASETYPE(DestroyNotify);
418 	CASETYPE(UnmapNotify);
419 	CASETYPE(MapNotify);
420 	CASETYPE(MapRequest);
421 	CASETYPE(ReparentNotify);
422 	CASETYPE(ConfigureNotify);
423 	CASETYPE(ConfigureRequest);
424 	CASETYPE(GravityNotify);
425 	CASETYPE(ResizeRequest);
426 	CASETYPE(CirculateNotify);
427 	CASETYPE(CirculateRequest);
428 	CASETYPE(PropertyNotify);
429 	CASETYPE(SelectionClear);
430 	CASETYPE(SelectionRequest);
431 	CASETYPE(SelectionNotify);
432 	CASETYPE(ColormapNotify);
433 	CASETYPE(ClientMessage);
434 	CASETYPE(MappingNotify);
435     }
436     return result;
437 }
438 
439 const char *
visibleMappingMode(int code)440 visibleMappingMode(int code)
441 {
442     const char *result = "?";
443     switch (code) {
444 	CASETYPE(MappingModifier);
445 	CASETYPE(MappingKeyboard);
446 	CASETYPE(MappingPointer);
447     }
448     return result;
449 }
450 
451 const char *
visibleNotifyMode(int code)452 visibleNotifyMode(int code)
453 {
454     const char *result = "?";
455     switch (code) {
456 	CASETYPE(NotifyNormal);
457 	CASETYPE(NotifyGrab);
458 	CASETYPE(NotifyUngrab);
459 	CASETYPE(NotifyWhileGrabbed);
460     }
461     return result;
462 }
463 
464 const char *
visibleNotifyDetail(int code)465 visibleNotifyDetail(int code)
466 {
467     const char *result = "?";
468     switch (code) {
469 	CASETYPE(NotifyAncestor);
470 	CASETYPE(NotifyVirtual);
471 	CASETYPE(NotifyInferior);
472 	CASETYPE(NotifyNonlinear);
473 	CASETYPE(NotifyNonlinearVirtual);
474 	CASETYPE(NotifyPointer);
475 	CASETYPE(NotifyPointerRoot);
476 	CASETYPE(NotifyDetailNone);
477     }
478     return result;
479 }
480 
481 const char *
visibleSelectionTarget(Display * d,Atom a)482 visibleSelectionTarget(Display *d, Atom a)
483 {
484     const char *result = "?";
485 
486     if (a == XA_STRING) {
487 	result = "XA_STRING";
488     } else if (a == XA_TEXT(d)) {
489 	result = "XA_TEXT()";
490     } else if (a == XA_COMPOUND_TEXT(d)) {
491 	result = "XA_COMPOUND_TEXT()";
492     } else if (a == XA_UTF8_STRING(d)) {
493 	result = "XA_UTF8_STRING()";
494     } else if (a == XA_TARGETS(d)) {
495 	result = "XA_TARGETS()";
496     }
497 
498     return result;
499 }
500 
501 const char *
visibleTekparse(int code)502 visibleTekparse(int code)
503 {
504     static const struct {
505 	int code;
506 	const char *name;
507     } table[] = {
508 #include "Tekparse.cin"
509     };
510     const char *result = "?";
511     Cardinal n;
512     for (n = 0; n < XtNumber(table); ++n) {
513 	if (table[n].code == code) {
514 	    result = table[n].name;
515 	    break;
516 	}
517     }
518     return result;
519 }
520 
521 const char *
visibleVTparse(int code)522 visibleVTparse(int code)
523 {
524     static const struct {
525 	int code;
526 	const char *name;
527     } table[] = {
528 #include "VTparse.cin"
529     };
530     const char *result = "?";
531     Cardinal n;
532     for (n = 0; n < XtNumber(table); ++n) {
533 	if (table[n].code == code) {
534 	    result = table[n].name;
535 	    break;
536 	}
537     }
538     return result;
539 }
540 
541 const char *
visibleXError(int code)542 visibleXError(int code)
543 {
544     static char temp[80];
545     const char *result = "?";
546     switch (code) {
547 	CASETYPE(Success);
548 	CASETYPE(BadRequest);
549 	CASETYPE(BadValue);
550 	CASETYPE(BadWindow);
551 	CASETYPE(BadPixmap);
552 	CASETYPE(BadAtom);
553 	CASETYPE(BadCursor);
554 	CASETYPE(BadFont);
555 	CASETYPE(BadMatch);
556 	CASETYPE(BadDrawable);
557 	CASETYPE(BadAccess);
558 	CASETYPE(BadAlloc);
559 	CASETYPE(BadColor);
560 	CASETYPE(BadGC);
561 	CASETYPE(BadIDChoice);
562 	CASETYPE(BadName);
563 	CASETYPE(BadLength);
564 	CASETYPE(BadImplementation);
565     default:
566 	sprintf(temp, "%d", code);
567 	result = temp;
568 	break;
569     }
570     return result;
571 }
572 
573 #if OPT_TRACE_FLAGS
574 #define isScrnFlag(flag) ((flag) == LINEWRAPPED)
575 
576 static char *
ScrnText(LineData * ld)577 ScrnText(LineData *ld)
578 {
579     return visibleIChars(ld->charData, ld->lineSize);
580 }
581 
582 #define SHOW_BAD_LINE(name, ld) \
583 	Trace("OOPS " #name " bad row\n")
584 
585 #define SHOW_SCRN_FLAG(name,code) \
586 	Trace(#name " %s:%s\n", \
587 	      code ? "*" : "", \
588 	      ScrnText(ld))
589 
590 void
LineClrFlag(LineData * ld,int flag)591 LineClrFlag(LineData *ld, int flag)
592 {
593     if (ld == 0) {
594 	SHOW_BAD_LINE(LineClrFlag, ld);
595 	assert(0);
596     } else if (isScrnFlag(flag)) {
597 	SHOW_SCRN_FLAG(LineClrFlag, 0);
598     }
599 
600     LineFlags(ld) &= ~flag;
601 }
602 
603 void
LineSetFlag(LineData * ld,int flag)604 LineSetFlag(LineData *ld, int flag)
605 {
606     if (ld == 0) {
607 	SHOW_BAD_LINE(LineSetFlag, ld);
608 	assert(0);
609     } else if (isScrnFlag(flag)) {
610 	SHOW_SCRN_FLAG(LineSetFlag, 1);
611     }
612 
613     LineFlags(ld) |= flag;
614 }
615 
616 int
LineTstFlag(LineData ld,int flag)617 LineTstFlag(LineData ld, int flag)
618 {
619     int code = 0;
620     if (ld == 0) {
621 	SHOW_BAD_LINE(LineTstFlag, ld);
622     } else {
623 	code = LineFlags(ld);
624 
625 	if (isScrnFlag(flag)) {
626 	    SHOW_SCRN_FLAG(LineTstFlag, code);
627 	}
628     }
629     return code;
630 }
631 #endif /* OPT_TRACE_FLAGS */
632 
633 const char *
TraceAtomName(Display * dpy,Atom atom)634 TraceAtomName(Display *dpy, Atom atom)
635 {
636     static char *result;
637     free(result);
638     if (atom != 0) {
639 	result = XGetAtomName(dpy, atom);
640     } else {
641 	result = x_strdup("NONE");
642     }
643     return result;
644 }
645 
646 /*
647  * Trace the normal or alternate screen, showing color values up to 16, e.g.,
648  * for debugging with vttest.
649  */
650 void
TraceScreen(XtermWidget xw,int whichBuf)651 TraceScreen(XtermWidget xw, int whichBuf)
652 {
653     TScreen *screen = TScreenOf(xw);
654 
655     if (screen->editBuf_index[whichBuf]) {
656 	int row;
657 
658 	TRACE(("TraceScreen %d:\n", whichBuf));
659 	for (row = 0; row <= screen->max_row; ++row) {
660 	    LineData *ld = getLineData(screen, row);
661 
662 	    TRACE((" %3d:", row));
663 	    if (ld != 0) {
664 		int col;
665 
666 		for (col = 0; col < ld->lineSize; ++col) {
667 		    int ch = (int) ld->charData[col];
668 		    if (ch < ' ')
669 			ch = ' ';
670 		    if (ch >= 127)
671 			ch = '#';
672 		    TRACE(("%c", ch));
673 		}
674 		TRACE((":\n"));
675 
676 #if 0
677 		TRACE(("  xx:"));
678 		for (col = 0; col < ld->lineSize; ++col) {
679 		    unsigned attrs = ld->attribs[col];
680 		    char ch;
681 		    if (attrs & PROTECTED) {
682 			ch = '*';
683 		    } else if (attrs & BLINK) {
684 			ch = 'B';
685 		    } else if (attrs & CHARDRAWN) {
686 			ch = '+';
687 		    } else {
688 			ch = ' ';
689 		    }
690 		    TRACE(("%c", ch));
691 		}
692 		TRACE((":\n"));
693 #endif
694 
695 #if 0
696 		TRACE(("  fg:"));
697 		for (col = 0; col < ld->lineSize; ++col) {
698 		    unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]);
699 		    if (fg > 15)
700 			fg = 15;
701 		    TRACE(("%1x", fg));
702 		}
703 		TRACE((":\n"));
704 
705 		TRACE(("  bg:"));
706 		for (col = 0; col < ld->lineSize; ++col) {
707 		    unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]);
708 		    if (bg > 15)
709 			bg = 15;
710 		    TRACE(("%1x", bg));
711 		}
712 		TRACE((":\n"));
713 #endif
714 	    } else {
715 		TRACE(("null lineData\n"));
716 	    }
717 	}
718     } else {
719 	TRACE(("TraceScreen %d is nil\n", whichBuf));
720     }
721 }
722 
723 static char *
formatEventMask(char * target,unsigned source,Boolean buttons)724 formatEventMask(char *target, unsigned source, Boolean buttons)
725 {
726 #define DATA(name) { name ## Mask, #name }
727     static struct {
728 	unsigned mask;
729 	const char *name;
730     } table[] = {
731 	DATA(Shift),
732 	    DATA(Lock),
733 	    DATA(Control),
734 	    DATA(Mod1),
735 	    DATA(Mod2),
736 	    DATA(Mod3),
737 	    DATA(Mod4),
738 	    DATA(Mod5),
739 	    DATA(Button1),
740 	    DATA(Button2),
741 	    DATA(Button3),
742 	    DATA(Button4),
743 	    DATA(Button5),
744     };
745 #undef DATA
746     Cardinal n;
747     char marker = L_CURL;
748     char *base = target;
749 
750     for (n = 0; n < XtNumber(table); ++n) {
751 	if (!buttons && (table[n].mask >= Button1Mask))
752 	    continue;
753 	if ((table[n].mask & source)) {
754 	    UIntClr(source, table[n].mask);
755 	    sprintf(target, "%c%s", marker, table[n].name);
756 	    target += strlen(target);
757 	    marker = '|';
758 	}
759     }
760 
761     if (source != 0) {
762 	sprintf(target, "%c?%#x", marker, source);
763 	target += strlen(target);
764 	marker = '|';
765     }
766 
767     if (marker == L_CURL)
768 	*target++ = L_CURL;
769     *target++ = R_CURL;
770 
771     *target = '\0';
772     return base;
773 }
774 
775 void
TraceEvent(const char * tag,XEvent * ev,String * params,Cardinal * num_params)776 TraceEvent(const char *tag, XEvent *ev, String *params, Cardinal *num_params)
777 {
778     char mask_buffer[160];
779 
780     TRACE(("Event #%lu %s: %#lx %s",
781 	   ev->xany.serial,
782 	   tag,
783 	   ev->xany.window,
784 	   visibleEventType(ev->type)));
785 
786     switch (ev->type) {
787     case KeyPress:
788 	/* FALLTHRU */
789     case KeyRelease:
790 	TRACE((" keycode 0x%04X %s",
791 	       ev->xkey.keycode,
792 	       formatEventMask(mask_buffer, ev->xkey.state, False)));
793 	break;
794     case ButtonPress:
795 	/* FALLTHRU */
796     case ButtonRelease:
797 	TRACE((" button %u state %#x %s",
798 	       ev->xbutton.button,
799 	       ev->xbutton.state,
800 	       formatEventMask(mask_buffer, ev->xbutton.state, True)));
801 	break;
802     case MotionNotify:
803 	TRACE((" (%d,%d) state %#x %s",
804 	       ev->xmotion.y_root,
805 	       ev->xmotion.x_root,
806 	       ev->xmotion.state,
807 	       formatEventMask(mask_buffer, ev->xmotion.state, True)));
808 	break;
809     case EnterNotify:
810     case LeaveNotify:
811 	TRACE((" at %d,%d root %d,%d %s %s",
812 	       ev->xcrossing.y,
813 	       ev->xcrossing.x,
814 	       ev->xcrossing.y_root,
815 	       ev->xcrossing.x_root,
816 	       visibleNotifyMode(ev->xcrossing.mode),
817 	       visibleNotifyDetail(ev->xcrossing.detail)));
818 	break;
819     case FocusIn:
820     case FocusOut:
821 	TRACE((" %s %s",
822 	       visibleNotifyMode(ev->xfocus.mode),
823 	       visibleNotifyDetail(ev->xfocus.detail)));
824 	break;
825     case MapNotify:
826 	TRACE((" event %#lx %s",
827 	       ev->xmap.event,
828 	       ev->xmap.override_redirect ? "override" : ""));
829 	break;
830     case UnmapNotify:
831 	TRACE((" event %#lx %s",
832 	       ev->xunmap.event,
833 	       ev->xunmap.from_configure ? "configure" : ""));
834 	break;
835     case ReparentNotify:
836 	TRACE((" at %d,%d event %#lx parent %#lx %s",
837 	       ev->xreparent.y,
838 	       ev->xreparent.x,
839 	       ev->xreparent.event,
840 	       ev->xreparent.parent,
841 	       ev->xreparent.override_redirect ? "override" : ""));
842 	break;
843     case ConfigureNotify:
844 	TRACE((" at %d,%d size %dx%d bd %d above %#lx",
845 	       ev->xconfigure.y,
846 	       ev->xconfigure.x,
847 	       ev->xconfigure.height,
848 	       ev->xconfigure.width,
849 	       ev->xconfigure.border_width,
850 	       ev->xconfigure.above));
851 	break;
852     case CreateNotify:
853 	TRACE((" at %d,%d size %dx%d bd %d",
854 	       ev->xcreatewindow.y,
855 	       ev->xcreatewindow.x,
856 	       ev->xcreatewindow.height,
857 	       ev->xcreatewindow.width,
858 	       ev->xcreatewindow.border_width));
859 	break;
860     case ResizeRequest:
861 	TRACE((" size %dx%d",
862 	       ev->xresizerequest.height,
863 	       ev->xresizerequest.width));
864 	break;
865     case PropertyNotify:
866 	TRACE((" %s %s",
867 	       TraceAtomName(XtDisplay(toplevel), ev->xproperty.atom),
868 	       ((ev->xproperty.state == PropertyNewValue)
869 		? "NewValue"
870 		: ((ev->xproperty.state == PropertyDelete)
871 		   ? "Delete"
872 		   : "?"))));
873 
874 	break;
875     case Expose:
876 	TRACE((" at %d,%d size %dx%d count %d",
877 	       ev->xexpose.y,
878 	       ev->xexpose.x,
879 	       ev->xexpose.height,
880 	       ev->xexpose.width,
881 	       ev->xexpose.count));
882 	break;
883     case MappingNotify:
884 	TRACE((" %s first_keycode %d count %d",
885 	       visibleMappingMode(ev->xmapping.request),
886 	       ev->xmapping.first_keycode,
887 	       ev->xmapping.count));
888 	break;
889     case VisibilityNotify:
890 	TRACE((" state %d",
891 	       ev->xvisibility.state));
892 	break;
893     case KeymapNotify:
894 	{
895 	    Cardinal j;
896 	    for (j = 0; j < XtNumber(ev->xkeymap.key_vector); ++j) {
897 		if (ev->xkeymap.key_vector[j] != 0) {
898 		    Cardinal k;
899 		    for (k = 0; k < 8; ++k) {
900 			if (ev->xkeymap.key_vector[j] & (1 << k)) {
901 			    TRACE((" key%u", (j * 8) + k));
902 			}
903 		    }
904 		}
905 	    }
906 	}
907 	break;
908     case NoExpose:
909 	TRACE((" send_event:%d display %p major:%d minor:%d",
910 	       ev->xnoexpose.send_event,
911 	       (void *) ev->xnoexpose.display,
912 	       ev->xnoexpose.major_code,
913 	       ev->xnoexpose.minor_code));
914 	break;
915     case GraphicsExpose:
916 	TRACE((" send_event:%d display %p major:%d minor:%d",
917 	       ev->xgraphicsexpose.send_event,
918 	       (void *) ev->xgraphicsexpose.display,
919 	       ev->xgraphicsexpose.major_code,
920 	       ev->xgraphicsexpose.minor_code));
921 	break;
922     case SelectionClear:
923 	TRACE((" selection:%s",
924 	       TraceAtomName(ev->xselectionclear.display,
925 			     ev->xselectionclear.selection)));
926 	break;
927     case SelectionRequest:
928 	TRACE((" owner:%#lx requestor:%#lx",
929 	       ev->xselectionrequest.owner,
930 	       ev->xselectionrequest.requestor));
931 	TRACE((" selection:%s",
932 	       TraceAtomName(ev->xselectionrequest.display,
933 			     ev->xselectionrequest.selection)));
934 	TRACE((" target:%s",
935 	       TraceAtomName(ev->xselectionrequest.display,
936 			     ev->xselectionrequest.target)));
937 	TRACE((" property:%s",
938 	       TraceAtomName(ev->xselectionrequest.display,
939 			     ev->xselectionrequest.property)));
940 	break;
941     default:
942 	TRACE((":FIXME"));
943 	break;
944     }
945     TRACE(("\n"));
946     if (params != 0 && *num_params != 0) {
947 	Cardinal n;
948 	for (n = 0; n < *num_params; ++n) {
949 	    TRACE(("  param[%d] = %s\n", n, params[n]));
950 	}
951     }
952 }
953 
954 #if OPT_RENDERFONT && OPT_WIDE_CHARS
955 void
TraceFallback(XtermWidget xw,const char * tag,unsigned wc,int n,XftFont * font)956 TraceFallback(XtermWidget xw, const char *tag, unsigned wc, int n, XftFont *font)
957 {
958     TScreen *screen = TScreenOf(xw);
959     XGlyphInfo gi;
960     int expect = my_wcwidth((wchar_t) wc);
961     int hijack = mk_wcwidth_cjk((wchar_t) wc);
962     int actual;
963 
964     XftTextExtents32(screen->display, font, &wc, 1, &gi);
965     actual = ((gi.xOff + FontWidth(screen) - 1)
966 	      / FontWidth(screen));
967 
968     TRACE(("FALLBACK #%d %s U+%04X %d,%d pos,"
969 	   " %d,%d off," " %dx%d size,"
970 	   " %d/%d next," " %d vs %d/%d cells%s\n",
971 	   n + 1, tag, wc,
972 	   gi.y, gi.x,
973 	   gi.yOff, gi.xOff,
974 	   gi.height, gi.width,
975 	   font->max_advance_width,
976 	   FontWidth(screen),
977 	   actual, expect, hijack,
978 	   ((actual != expect)
979 	    ? ((actual == hijack)
980 	       ? " OOPS"
981 	       : " oops")
982 	    : "")));
983 }
984 #endif /* OPT_RENDERFONT */
985 
986 void
TraceFocus(Widget w,XEvent * ev)987 TraceFocus(Widget w, XEvent *ev)
988 {
989     TRACE(("trace_focus event type %d:%s\n",
990 	   ev->type, visibleEventType(ev->type)));
991     switch (ev->type) {
992     case FocusIn:
993     case FocusOut:
994 	{
995 	    XFocusChangeEvent *event = (XFocusChangeEvent *) ev;
996 	    TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail)));
997 	    TRACE(("\tmode:   %s\n", visibleNotifyMode(event->mode)));
998 	    TRACE(("\twindow: %#lx\n", event->window));
999 	}
1000 	break;
1001     case EnterNotify:
1002     case LeaveNotify:
1003 	{
1004 	    XCrossingEvent *event = (XCrossingEvent *) ev;
1005 	    TRACE(("\tdetail:    %s\n", visibleNotifyDetail(event->detail)));
1006 	    TRACE(("\tmode:      %s\n", visibleNotifyMode(event->mode)));
1007 	    TRACE(("\twindow:    %#lx\n", event->window));
1008 	    TRACE(("\tfocus:     %d\n", event->focus));
1009 	    TRACE(("\troot:      %#lx\n", event->root));
1010 	    TRACE(("\tsubwindow: %#lx\n", event->subwindow));
1011 	}
1012 	break;
1013     }
1014     while (w != 0) {
1015 	TRACE(("w %p -> %#lx\n", (void *) w, XtWindow(w)));
1016 	w = XtParent(w);
1017     }
1018 }
1019 
1020 void
TraceSizeHints(XSizeHints * hints)1021 TraceSizeHints(XSizeHints * hints)
1022 {
1023     TRACE(("size hints:\n"));
1024     if (hints->flags & (USPosition | PPosition)) {
1025 	TRACE(("   position   %d,%d%s%s\n", hints->y, hints->x,
1026 	       (hints->flags & USPosition) ? " user" : "",
1027 	       (hints->flags & PPosition) ? " prog" : ""));
1028     }
1029     if (hints->flags & (USSize | PSize)) {
1030 	TRACE(("   size       %d,%d%s%s\n", hints->height, hints->width,
1031 	       (hints->flags & USSize) ? " user" : "",
1032 	       (hints->flags & PSize) ? " prog" : ""));
1033     }
1034     if (hints->flags & PMinSize) {
1035 	TRACE(("   min        %d,%d\n", hints->min_height, hints->min_width));
1036     }
1037     if (hints->flags & PMaxSize) {
1038 	TRACE(("   max        %d,%d\n", hints->max_height, hints->max_width));
1039     }
1040     if (hints->flags & PResizeInc) {
1041 	TRACE(("   inc        %d,%d\n", hints->height_inc, hints->width_inc));
1042     } else {
1043 	TRACE(("   inc        NONE!\n"));
1044     }
1045     if (hints->flags & PAspect) {
1046 	TRACE(("   min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y));
1047 	TRACE(("   max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y));
1048     }
1049     if (hints->flags & PBaseSize) {
1050 	TRACE(("   base       %d,%d\n", hints->base_height, hints->base_width));
1051     }
1052     if (hints->flags & PWinGravity) {
1053 	TRACE(("   gravity    %d\n", hints->win_gravity));
1054     }
1055 }
1056 
1057 static void
TraceEventMask(const char * tag,long mask)1058 TraceEventMask(const char *tag, long mask)
1059 {
1060 #define DATA(name) { name##Mask, #name }
1061     /* *INDENT-OFF* */
1062     static struct {
1063 	long mask;
1064 	const char *name;
1065     } table[] = {
1066 	DATA(KeyPress),
1067 	DATA(KeyRelease),
1068 	DATA(ButtonPress),
1069 	DATA(ButtonRelease),
1070 	DATA(EnterWindow),
1071 	DATA(LeaveWindow),
1072 	DATA(PointerMotion),
1073 	DATA(PointerMotionHint),
1074 	DATA(Button1Motion),
1075 	DATA(Button2Motion),
1076 	DATA(Button3Motion),
1077 	DATA(Button4Motion),
1078 	DATA(Button5Motion),
1079 	DATA(ButtonMotion),
1080 	DATA(KeymapState),
1081 	DATA(Exposure),
1082 	DATA(VisibilityChange),
1083 	DATA(StructureNotify),
1084 	DATA(ResizeRedirect),
1085 	DATA(SubstructureNotify),
1086 	DATA(SubstructureRedirect),
1087 	DATA(FocusChange),
1088 	DATA(PropertyChange),
1089 	DATA(ColormapChange),
1090 	DATA(OwnerGrabButton),
1091     };
1092 #undef DATA
1093     Cardinal n;
1094     /* *INDENT-ON* */
1095 
1096     for (n = 0; n < XtNumber(table); ++n) {
1097 	if (table[n].mask & mask) {
1098 	    TRACE(("%s %s\n", tag, table[n].name));
1099 	}
1100     }
1101 }
1102 
1103 void
TraceWindowAttributes(XWindowAttributes * attrs)1104 TraceWindowAttributes(XWindowAttributes * attrs)
1105 {
1106     TRACE(("window attributes:\n"));
1107     TRACE(("   position     %d,%d\n", attrs->y, attrs->x));
1108     TRACE(("   size         %dx%d\n", attrs->height, attrs->width));
1109     TRACE(("   border       %d\n", attrs->border_width));
1110     TRACE(("   depth        %d\n", attrs->depth));
1111     TRACE(("   bit_gravity  %d\n", attrs->bit_gravity));
1112     TRACE(("   win_gravity  %d\n", attrs->win_gravity));
1113     TRACE(("   root         %#lx\n", (long) attrs->root));
1114     TRACE(("   class        %s\n", ((attrs->class == InputOutput)
1115 				    ? "InputOutput"
1116 				    : ((attrs->class == InputOnly)
1117 				       ? "InputOnly"
1118 				       : "unknown"))));
1119     TRACE(("   map_state    %s\n", ((attrs->map_state == IsUnmapped)
1120 				    ? "IsUnmapped"
1121 				    : ((attrs->map_state == IsUnviewable)
1122 				       ? "IsUnviewable"
1123 				       : ((attrs->map_state == IsViewable)
1124 					  ? "IsViewable"
1125 					  : "unknown")))));
1126     TRACE(("   all_events\n"));
1127     TraceEventMask("        ", attrs->all_event_masks);
1128     TRACE(("   your_events\n"));
1129     TraceEventMask("        ", attrs->your_event_mask);
1130     TRACE(("   no_propagate\n"));
1131     TraceEventMask("        ", attrs->do_not_propagate_mask);
1132 }
1133 
1134 void
TraceWMSizeHints(XtermWidget xw)1135 TraceWMSizeHints(XtermWidget xw)
1136 {
1137     XSizeHints sizehints = xw->hints;
1138 
1139     getXtermSizeHints(xw);
1140     TraceSizeHints(&xw->hints);
1141     xw->hints = sizehints;
1142 }
1143 
1144 const char *
ModifierName(unsigned modifier)1145 ModifierName(unsigned modifier)
1146 {
1147     const char *s = "";
1148     if (modifier & ShiftMask)
1149 	s = " Shift";
1150     else if (modifier & LockMask)
1151 	s = " Lock";
1152     else if (modifier & ControlMask)
1153 	s = " Control";
1154     else if (modifier & Mod1Mask)
1155 	s = " Mod1";
1156     else if (modifier & Mod2Mask)
1157 	s = " Mod2";
1158     else if (modifier & Mod3Mask)
1159 	s = " Mod3";
1160     else if (modifier & Mod4Mask)
1161 	s = " Mod4";
1162     else if (modifier & Mod5Mask)
1163 	s = " Mod5";
1164     return s;
1165 }
1166 
1167 void
TraceTranslations(const char * name,Widget w)1168 TraceTranslations(const char *name, Widget w)
1169 {
1170     String result;
1171     XErrorHandler save = XSetErrorHandler(ignore_x11_error);
1172     XtTranslations xlations;
1173     Widget xcelerat;
1174 
1175     TRACE(("TraceTranslations for %s (widget %#lx) " TRACE_L "\n",
1176 	   name, (long) w));
1177     if (w) {
1178 	XtVaGetValues(w,
1179 		      XtNtranslations, &xlations,
1180 		      XtNaccelerators, &xcelerat,
1181 		      (XtPointer) 0);
1182 	TRACE(("... xlations %#08lx\n", (long) xlations));
1183 	TRACE(("... xcelerat %#08lx\n", (long) xcelerat));
1184 	result = _XtPrintXlations(w, xlations, xcelerat, True);
1185 	TRACE(("%s\n", NonNull(result)));
1186 	if (result)
1187 	    XFree((char *) result);
1188     } else {
1189 	TRACE(("none (widget is null)\n"));
1190     }
1191     TRACE((TRACE_R "\n"));
1192     XSetErrorHandler(save);
1193 }
1194 
1195 XtGeometryResult
TraceResizeRequest(const char * fn,int ln,Widget w,unsigned reqwide,unsigned reqhigh,Dimension * gotwide,Dimension * gothigh)1196 TraceResizeRequest(const char *fn, int ln, Widget w,
1197 		   unsigned reqwide,
1198 		   unsigned reqhigh,
1199 		   Dimension *gotwide,
1200 		   Dimension *gothigh)
1201 {
1202     XtGeometryResult rc;
1203 
1204     TRACE(("%s@%d ResizeRequest %ux%u\n", fn, ln, reqhigh, reqwide));
1205     rc = XtMakeResizeRequest((Widget) w,
1206 			     (Dimension) reqwide,
1207 			     (Dimension) reqhigh,
1208 			     gotwide, gothigh);
1209     TRACE(("... ResizeRequest -> "));
1210     if (gothigh && gotwide)
1211 	TRACE(("%dx%d ", *gothigh, *gotwide));
1212     TRACE(("(%d)\n", rc));
1213     return rc;
1214 }
1215 
1216 #define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name))
1217 #define XRES_B(name) Trace(#name " = %s\n", MtoS(resp->name))
1218 #define XRES_I(name) Trace(#name " = %d\n", resp->name)
1219 
1220 void
TraceXtermResources(void)1221 TraceXtermResources(void)
1222 {
1223     XTERM_RESOURCE *resp = &resource;
1224 
1225     Trace("XTERM_RESOURCE settings:\n");
1226     XRES_S(icon_geometry);
1227     XRES_S(title);
1228     XRES_S(icon_hint);
1229     XRES_S(icon_name);
1230     XRES_S(term_name);
1231     XRES_S(tty_modes);
1232     XRES_I(minBufSize);
1233     XRES_I(maxBufSize);
1234     XRES_B(hold_screen);
1235     XRES_B(utmpInhibit);
1236     XRES_B(utmpDisplayId);
1237     XRES_B(messages);
1238     XRES_S(menuLocale);
1239     XRES_S(omitTranslation);
1240     XRES_S(keyboardType);
1241 #ifdef HAVE_LIB_XCURSOR
1242     XRES_S(cursorTheme);
1243 #endif
1244 #if OPT_PRINT_ON_EXIT
1245     XRES_I(printModeNow);
1246     XRES_I(printModeOnXError);
1247     XRES_I(printOptsNow);
1248     XRES_I(printOptsOnXError);
1249     XRES_S(printFileNow);
1250     XRES_S(printFileOnXError);
1251 #endif
1252 #if OPT_SUNPC_KBD
1253     XRES_B(sunKeyboard);
1254 #endif
1255 #if OPT_HP_FUNC_KEYS
1256     XRES_B(hpFunctionKeys);
1257 #endif
1258 #if OPT_SCO_FUNC_KEYS
1259     XRES_B(scoFunctionKeys);
1260 #endif
1261 #if OPT_SUN_FUNC_KEYS
1262     XRES_B(sunFunctionKeys);
1263 #endif
1264 #if OPT_INITIAL_ERASE
1265     XRES_B(ptyInitialErase);
1266     XRES_B(backarrow_is_erase);
1267 #endif
1268     XRES_B(useInsertMode);
1269 #if OPT_ZICONBEEP
1270     XRES_I(zIconBeep);
1271     XRES_S(zIconFormat);
1272 #endif
1273 #if OPT_PTY_HANDSHAKE
1274     XRES_B(wait_for_map);
1275     XRES_B(ptyHandshake);
1276     XRES_B(ptySttySize);
1277 #endif
1278 #if OPT_REPORT_CCLASS
1279     XRES_B(reportCClass);
1280 #endif
1281 #if OPT_REPORT_COLORS
1282     XRES_B(reportColors);
1283 #endif
1284 #if OPT_REPORT_FONTS
1285     XRES_B(reportFonts);
1286 #endif
1287 #if OPT_REPORT_ICONS
1288     XRES_B(reportIcons);
1289 #endif
1290 #if OPT_SAME_NAME
1291     XRES_B(sameName);
1292 #endif
1293 #if OPT_SESSION_MGT
1294     XRES_B(sessionMgt);
1295 #endif
1296 #if OPT_TOOLBAR
1297     XRES_B(toolBar);
1298 #endif
1299 #if OPT_MAXIMIZE
1300     XRES_B(maximized);
1301     XRES_S(fullscreen_s);
1302 #endif
1303 #if USE_DOUBLE_BUFFER
1304     XRES_B(buffered);
1305     XRES_I(buffered_fps);
1306 #endif
1307 }
1308 
1309 void
TraceArgv(const char * tag,char ** argv)1310 TraceArgv(const char *tag, char **argv)
1311 {
1312     TRACE(("%s:\n", tag));
1313     if (argv != 0) {
1314 	int n = 0;
1315 
1316 	while (*argv != 0) {
1317 	    TRACE(("  %d:%s\n", n++, *argv++));
1318 	}
1319     }
1320 }
1321 
1322 static char *
parse_option(char * dst,String src,int first)1323 parse_option(char *dst, String src, int first)
1324 {
1325     char *s;
1326 
1327     if (!strncmp(src, "-/+", (size_t) 3)) {
1328 	dst[0] = (char) first;
1329 	strcpy(dst + 1, src + 3);
1330     } else {
1331 	strcpy(dst, src);
1332     }
1333     for (s = dst; *s != '\0'; s++) {
1334 	if (*s == '#' || *s == '%' || *s == 'S') {
1335 	    s[1] = '\0';
1336 	} else if (*s == ' ') {
1337 	    *s = '\0';
1338 	    break;
1339 	}
1340     }
1341     return dst;
1342 }
1343 
1344 static Bool
same_option(OptionHelp * opt,XrmOptionDescRec * res)1345 same_option(OptionHelp * opt, XrmOptionDescRec * res)
1346 {
1347     char temp[BUFSIZ];
1348     return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option);
1349 }
1350 
1351 static Bool
standard_option(String opt)1352 standard_option(String opt)
1353 {
1354     static const char *table[] =
1355     {
1356 	"+rv",
1357 	"+synchronous",
1358 	"-background",
1359 	"-bd",
1360 	"-bg",
1361 	"-bordercolor",
1362 	"-borderwidth",
1363 	"-bw",
1364 	"-display",
1365 	"-fg",
1366 	"-fn",
1367 	"-font",
1368 	"-foreground",
1369 	"-geometry",
1370 	"-iconic",
1371 	"-name",
1372 	"-reverse",
1373 	"-rv",
1374 	"-selectionTimeout",
1375 	"-synchronous",
1376 	"-title",
1377 	"-xnllanguage",
1378 	"-xrm",
1379 	"-xtsessionID",
1380     };
1381     Cardinal n;
1382     char temp[BUFSIZ];
1383 
1384     opt = parse_option(temp, opt, '-');
1385     for (n = 0; n < XtNumber(table); n++) {
1386 	if (!strcmp(opt, table[n]))
1387 	    return True;
1388     }
1389     return False;
1390 }
1391 
1392 /*
1393  * Analyse the options/help messages for inconsistencies.
1394  */
1395 void
TraceOptions(OptionHelp * options,XrmOptionDescRec * resources,Cardinal res_count)1396 TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count)
1397 {
1398     OptionHelp *opt_array = sortedOpts(options, resources, res_count);
1399     size_t j, k;
1400     XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count);
1401     Bool first, found;
1402 
1403     TRACE(("Checking options-tables for inconsistencies:\n"));
1404 
1405 #if 0
1406     TRACE(("Options listed in help-message:\n"));
1407     for (j = 0; options[j].opt != 0; j++)
1408 	TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc));
1409     TRACE(("Options listed in resource-table:\n"));
1410     for (j = 0; j < res_count; j++)
1411 	TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier));
1412 #endif
1413 
1414     /* list all options[] not found in resources[] */
1415     for (j = 0, first = True; options[j].opt != 0; j++) {
1416 	found = False;
1417 	for (k = 0; k < res_count; k++) {
1418 	    if (same_option(&opt_array[j], &res_array[k])) {
1419 		found = True;
1420 		break;
1421 	    }
1422 	}
1423 	if (!found) {
1424 	    if (first) {
1425 		TRACE(("Options listed in help, not found in resource list:\n"));
1426 		first = False;
1427 	    }
1428 	    TRACE(("  %-28s%s\n", opt_array[j].opt,
1429 		   standard_option(opt_array[j].opt) ? " (standard)" : ""));
1430 	}
1431     }
1432 
1433     /* list all resources[] not found in options[] */
1434     for (j = 0, first = True; j < res_count; j++) {
1435 	found = False;
1436 	for (k = 0; options[k].opt != 0; k++) {
1437 	    if (same_option(&opt_array[k], &res_array[j])) {
1438 		found = True;
1439 		break;
1440 	    }
1441 	}
1442 	if (!found) {
1443 	    if (first) {
1444 		TRACE(("Resource list items not found in options-help:\n"));
1445 		first = False;
1446 	    }
1447 	    TRACE(("  %s\n", res_array[j].option));
1448 	}
1449     }
1450 
1451     TRACE(("Resource list items that will be ignored by XtOpenApplication:\n"));
1452     for (j = 0; j < res_count; j++) {
1453 	switch (res_array[j].argKind) {
1454 	case XrmoptionSkipArg:
1455 	    TRACE(("  %-28s {param}\n", res_array[j].option));
1456 	    break;
1457 	case XrmoptionSkipNArgs:
1458 	    TRACE(("  %-28s {%ld params}\n", res_array[j].option, (long)
1459 		   res_array[j].value));
1460 	    break;
1461 	case XrmoptionSkipLine:
1462 	    TRACE(("  %-28s {remainder of line}\n", res_array[j].option));
1463 	    break;
1464 	case XrmoptionIsArg:
1465 	case XrmoptionNoArg:
1466 	case XrmoptionResArg:
1467 	case XrmoptionSepArg:
1468 	case XrmoptionStickyArg:
1469 	default:
1470 	    break;
1471 	}
1472     }
1473 }
1474 #else
1475 extern void empty_trace(void);
1476 void
empty_trace(void)1477 empty_trace(void)
1478 {
1479 }
1480 #endif
1481