trace.c revision 2e4f8982
1/* $XTermId: trace.c,v 1.166 2016/10/05 09:16:01 tom Exp $ */
2
3/*
4 * Copyright 1997-2015,2016 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 <version.h>
39
40#if OPT_TRACE
41
42#include <data.h>
43#include <trace.h>
44
45#include <time.h>
46#include <stdlib.h>
47#include <unistd.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <stdio.h>
51#include <stdarg.h>
52#include <assert.h>
53
54#include <X11/Xatom.h>
55#include <X11/Xmu/Atoms.h>
56
57#ifdef HAVE_X11_TRANSLATEI_H
58#include <X11/ConvertI.h>
59#include <X11/TranslateI.h>
60#else
61#ifdef __cplusplus
62extern "C" {
63#endif
64
65    extern String _XtPrintXlations(Widget w,
66				   XtTranslations xlations,
67				   Widget accelWidget,
68				   _XtBoolean includeRHS);
69#ifdef __cplusplus
70}
71#endif
72#endif
73const char *trace_who = "parent";
74
75static FILE *trace_fp;
76
77void
78Trace(const char *fmt,...)
79{
80    static const char *trace_out;
81    va_list ap;
82
83    if (trace_fp != 0
84	&& trace_who != trace_out) {
85	fclose(trace_fp);
86	trace_fp = 0;
87    }
88    trace_out = trace_who;
89
90    if (!trace_fp) {
91	unsigned oldmask = (unsigned) umask(077);
92	char name[BUFSIZ];
93#if 0				/* usually I do not want unique names */
94	int unique;
95	for (unique = 0;; ++unique) {
96	    if (unique)
97		sprintf(name, "Trace-%s.out-%d", trace_who, unique);
98	    else
99		sprintf(name, "Trace-%s.out", trace_who);
100	    if ((trace_fp = fopen(name, "r")) == 0) {
101		break;
102	    }
103	    fclose(trace_fp);
104	}
105#else
106	sprintf(name, "Trace-%s.out", trace_who);
107#endif
108	trace_fp = fopen(name, "w");
109	/*
110	 * Try to put the trace-file in user's home-directory if the current
111	 * directory is not writable.
112	 */
113	if (trace_fp == 0) {
114	    char *home = getenv("HOME");
115	    if (home != 0) {
116		sprintf(name, "%.*s/Trace-%.8s.out",
117			(BUFSIZ - 21), home,
118			trace_who);
119		trace_fp = fopen(name, "w");
120	    }
121	}
122	if (trace_fp != 0) {
123	    fprintf(trace_fp, "%s\n", xtermVersion());
124	    TraceIds(NULL, 0);
125	}
126	if (!trace_fp) {
127	    xtermWarning("Cannot open \"%s\"\n", name);
128	    exit(EXIT_FAILURE);
129	}
130	(void) umask(oldmask);
131    }
132
133    va_start(ap, fmt);
134    vfprintf(trace_fp, fmt, ap);
135    (void) fflush(trace_fp);
136    va_end(ap);
137}
138
139void
140TraceClose(void)
141{
142    if (trace_fp != 0) {
143	(void) fclose(trace_fp);
144	(void) fflush(stdout);
145	(void) fflush(stderr);
146	(void) visibleChars(NULL, 0);
147	(void) visibleIChars(NULL, 0);
148	trace_fp = 0;
149    }
150}
151
152void
153TraceIds(const char *fname, int lnum)
154{
155    Trace("process %d ", (int) getpid());
156#ifdef HAVE_UNISTD_H
157    Trace("real (%u/%u) effective (%u/%u)",
158	  (unsigned) getuid(), (unsigned) getgid(),
159	  (unsigned) geteuid(), (unsigned) getegid());
160#endif
161    if (fname != 0) {
162	Trace(" (%s@%d)\n", fname, lnum);
163    } else {
164	time_t now = time((time_t *) 0);
165	Trace("-- %s", ctime(&now));
166    }
167}
168
169void
170TraceTime(const char *fname, int lnum)
171{
172    time_t now;
173    if (fname != 0) {
174	Trace("datetime (%s@%d) ", fname, lnum);
175    }
176    now = time((time_t *) 0);
177    Trace("-- %s", ctime(&now));
178}
179
180static void
181formatAscii(char *dst, unsigned value)
182{
183    switch (value) {
184    case '\\':
185	sprintf(dst, "\\\\");
186	break;
187    case '\b':
188	sprintf(dst, "\\b");
189	break;
190    case '\n':
191	sprintf(dst, "\\n");
192	break;
193    case '\r':
194	sprintf(dst, "\\r");
195	break;
196    case '\t':
197	sprintf(dst, "\\t");
198	break;
199    default:
200	if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160))
201	    sprintf(dst, "\\%03o", value & 0xff);
202	else
203	    sprintf(dst, "%c", CharOf(value));
204	break;
205    }
206}
207
208#if OPT_DEC_CHRSET
209
210const char *
211visibleDblChrset(unsigned chrset)
212{
213    const char *result = "?";
214    switch (chrset) {
215    case CSET_SWL:
216	result = "CSET_SWL";
217	break;
218    case CSET_DHL_TOP:
219	result = "CSET_DHL_TOP";
220	break;
221    case CSET_DHL_BOT:
222	result = "CSET_DHL_BOT";
223	break;
224    case CSET_DWL:
225	result = "CSET_DWL";
226	break;
227    }
228    return result;
229}
230#endif
231
232const char *
233visibleScsCode(int chrset)
234{
235#define MAP(to,from) case from: result = to; break
236    const char *result = "<ERR>";
237    switch ((DECNRCM_codes) chrset) {
238	MAP("B", nrc_ASCII);
239	MAP("A", nrc_British);
240	MAP("A", nrc_British_Latin_1);
241	MAP("&4", nrc_Cyrillic);
242	MAP("0", nrc_DEC_Spec_Graphic);
243	MAP("1", nrc_DEC_Alt_Chars);
244	MAP("2", nrc_DEC_Alt_Graphics);
245	MAP("<", nrc_DEC_Supp);
246	MAP("%5", nrc_DEC_Supp_Graphic);
247	MAP(">", nrc_DEC_Technical);
248	MAP("4", nrc_Dutch);
249	MAP("5", nrc_Finnish);
250	MAP("C", nrc_Finnish2);
251	MAP("R", nrc_French);
252	MAP("f", nrc_French2);
253	MAP("Q", nrc_French_Canadian);
254	MAP("9", nrc_French_Canadian2);
255	MAP("K", nrc_German);
256	MAP("\"?", nrc_Greek);
257	MAP("F", nrc_Greek_Supp);
258	MAP("\"4", nrc_Hebrew);
259	MAP("%=", nrc_Hebrew2);
260	MAP("H", nrc_Hebrew_Supp);
261	MAP("Y", nrc_Italian);
262	MAP("M", nrc_Latin_5_Supp);
263	MAP("L", nrc_Latin_Cyrillic);
264	MAP("`", nrc_Norwegian_Danish);
265	MAP("E", nrc_Norwegian_Danish2);
266	MAP("6", nrc_Norwegian_Danish3);
267	MAP("%6", nrc_Portugese);
268	MAP("&5", nrc_Russian);
269	MAP("%3", nrc_SCS_NRCS);
270	MAP("Z", nrc_Spanish);
271	MAP("7", nrc_Swedish);
272	MAP("H", nrc_Swedish2);
273	MAP("=", nrc_Swiss);
274	MAP("%0", nrc_Turkish);
275	MAP("%2", nrc_Turkish2);
276	MAP("<UNK>", nrc_Unknown);
277    }
278#undef MAP
279    return result;
280}
281
282const char *
283visibleChars(const Char *buf, unsigned len)
284{
285    static char *result;
286    static unsigned used;
287
288    if (buf != 0) {
289	unsigned limit = ((len + 1) * 8) + 1;
290
291	if (limit > used) {
292	    used = limit;
293	    result = XtRealloc(result, used);
294	}
295	if (result != 0) {
296	    char *dst = result;
297	    *dst = '\0';
298	    while (len--) {
299		unsigned value = *buf++;
300		formatAscii(dst, value);
301		dst += strlen(dst);
302	    }
303	}
304    } else if (result != 0) {
305	free(result);
306	result = 0;
307	used = 0;
308    }
309    return NonNull(result);
310}
311
312const char *
313visibleIChars(const IChar *buf, unsigned len)
314{
315    static char *result;
316    static unsigned used;
317
318    if (buf != 0) {
319	unsigned limit = ((len + 1) * 8) + 1;
320
321	if (limit > used) {
322	    used = limit;
323	    result = XtRealloc(result, used);
324	}
325	if (result != 0) {
326	    char *dst = result;
327	    *dst = '\0';
328	    while (len--) {
329		unsigned value = *buf++;
330#if OPT_WIDE_CHARS
331		if (value > 255)
332		    sprintf(dst, "\\u+%04X", value);
333		else
334#endif
335		    formatAscii(dst, value);
336		dst += strlen(dst);
337	    }
338	}
339    } else if (result != 0) {
340	free(result);
341	result = 0;
342	used = 0;
343    }
344    return NonNull(result);
345}
346
347const char *
348visibleUChar(unsigned chr)
349{
350    IChar buf[1];
351    buf[0] = chr;
352    return visibleIChars(buf, 1);
353}
354
355const char *
356visibleEventType(int type)
357{
358    const char *result = "?";
359    switch (type) {
360	CASETYPE(KeyPress);
361	CASETYPE(KeyRelease);
362	CASETYPE(ButtonPress);
363	CASETYPE(ButtonRelease);
364	CASETYPE(MotionNotify);
365	CASETYPE(EnterNotify);
366	CASETYPE(LeaveNotify);
367	CASETYPE(FocusIn);
368	CASETYPE(FocusOut);
369	CASETYPE(KeymapNotify);
370	CASETYPE(Expose);
371	CASETYPE(GraphicsExpose);
372	CASETYPE(NoExpose);
373	CASETYPE(VisibilityNotify);
374	CASETYPE(CreateNotify);
375	CASETYPE(DestroyNotify);
376	CASETYPE(UnmapNotify);
377	CASETYPE(MapNotify);
378	CASETYPE(MapRequest);
379	CASETYPE(ReparentNotify);
380	CASETYPE(ConfigureNotify);
381	CASETYPE(ConfigureRequest);
382	CASETYPE(GravityNotify);
383	CASETYPE(ResizeRequest);
384	CASETYPE(CirculateNotify);
385	CASETYPE(CirculateRequest);
386	CASETYPE(PropertyNotify);
387	CASETYPE(SelectionClear);
388	CASETYPE(SelectionRequest);
389	CASETYPE(SelectionNotify);
390	CASETYPE(ColormapNotify);
391	CASETYPE(ClientMessage);
392	CASETYPE(MappingNotify);
393    }
394    return result;
395}
396
397const char *
398visibleNotifyMode(int code)
399{
400    const char *result = "?";
401    switch (code) {
402	CASETYPE(NotifyNormal);
403	CASETYPE(NotifyGrab);
404	CASETYPE(NotifyUngrab);
405	CASETYPE(NotifyWhileGrabbed);
406    }
407    return result;
408}
409
410const char *
411visibleNotifyDetail(int code)
412{
413    const char *result = "?";
414    switch (code) {
415	CASETYPE(NotifyAncestor);
416	CASETYPE(NotifyVirtual);
417	CASETYPE(NotifyInferior);
418	CASETYPE(NotifyNonlinear);
419	CASETYPE(NotifyNonlinearVirtual);
420	CASETYPE(NotifyPointer);
421	CASETYPE(NotifyPointerRoot);
422	CASETYPE(NotifyDetailNone);
423    }
424    return result;
425}
426
427const char *
428visibleSelectionTarget(Display *d, Atom a)
429{
430    const char *result = "?";
431
432    if (a == XA_STRING) {
433	result = "XA_STRING";
434    } else if (a == XA_TEXT(d)) {
435	result = "XA_TEXT()";
436    } else if (a == XA_COMPOUND_TEXT(d)) {
437	result = "XA_COMPOUND_TEXT()";
438    } else if (a == XA_UTF8_STRING(d)) {
439	result = "XA_UTF8_STRING()";
440    } else if (a == XA_TARGETS(d)) {
441	result = "XA_TARGETS()";
442    }
443
444    return result;
445}
446
447const char *
448visibleTekparse(int code)
449{
450    static const struct {
451	int code;
452	const char *name;
453    } table[] = {
454#include "Tekparse.cin"
455    };
456    const char *result = "?";
457    Cardinal n;
458    for (n = 0; n < XtNumber(table); ++n) {
459	if (table[n].code == code) {
460	    result = table[n].name;
461	    break;
462	}
463    }
464    return result;
465}
466
467const char *
468visibleVTparse(int code)
469{
470    static const struct {
471	int code;
472	const char *name;
473    } table[] = {
474#include "VTparse.cin"
475    };
476    const char *result = "?";
477    Cardinal n;
478    for (n = 0; n < XtNumber(table); ++n) {
479	if (table[n].code == code) {
480	    result = table[n].name;
481	    break;
482	}
483    }
484    return result;
485}
486
487const char *
488visibleXError(int code)
489{
490    static char temp[80];
491    const char *result = "?";
492    switch (code) {
493	CASETYPE(Success);
494	CASETYPE(BadRequest);
495	CASETYPE(BadValue);
496	CASETYPE(BadWindow);
497	CASETYPE(BadPixmap);
498	CASETYPE(BadAtom);
499	CASETYPE(BadCursor);
500	CASETYPE(BadFont);
501	CASETYPE(BadMatch);
502	CASETYPE(BadDrawable);
503	CASETYPE(BadAccess);
504	CASETYPE(BadAlloc);
505	CASETYPE(BadColor);
506	CASETYPE(BadGC);
507	CASETYPE(BadIDChoice);
508	CASETYPE(BadName);
509	CASETYPE(BadLength);
510	CASETYPE(BadImplementation);
511    default:
512	sprintf(temp, "%d", code);
513	result = temp;
514	break;
515    }
516    return result;
517}
518
519#if OPT_TRACE_FLAGS
520#define isScrnFlag(flag) ((flag) == LINEWRAPPED)
521
522static char *
523ScrnText(LineData *ld)
524{
525    return visibleIChars(ld->charData, ld->lineSize);
526}
527
528#define SHOW_BAD_LINE(name, ld) \
529	Trace("OOPS " #name " bad row\n")
530
531#define SHOW_SCRN_FLAG(name,code) \
532	Trace(#name " %s:%s\n", \
533	      code ? "*" : "", \
534	      ScrnText(ld))
535
536void
537LineClrFlag(LineData *ld, int flag)
538{
539    if (ld == 0) {
540	SHOW_BAD_LINE(LineClrFlag, ld);
541	assert(0);
542    } else if (isScrnFlag(flag)) {
543	SHOW_SCRN_FLAG(LineClrFlag, 0);
544    }
545
546    LineFlags(ld) &= ~flag;
547}
548
549void
550LineSetFlag(LineData *ld, int flag)
551{
552    if (ld == 0) {
553	SHOW_BAD_LINE(LineSetFlag, ld);
554	assert(0);
555    } else if (isScrnFlag(flag)) {
556	SHOW_SCRN_FLAG(LineSetFlag, 1);
557    }
558
559    LineFlags(ld) |= flag;
560}
561
562int
563LineTstFlag(LineData ld, int flag)
564{
565    int code = 0;
566    if (ld == 0) {
567	SHOW_BAD_LINE(LineTstFlag, ld);
568    } else {
569	code = LineFlags(ld);
570
571	if (isScrnFlag(flag)) {
572	    SHOW_SCRN_FLAG(LineTstFlag, code);
573	}
574    }
575    return code;
576}
577#endif /* OPT_TRACE_FLAGS */
578
579/*
580 * Trace the normal or alternate screen, showing color values up to 16, e.g.,
581 * for debugging with vttest.
582 */
583void
584TraceScreen(XtermWidget xw, int whichBuf)
585{
586    TScreen *screen = TScreenOf(xw);
587
588    if (screen->editBuf_index[whichBuf]) {
589	int row;
590
591	TRACE(("TraceScreen %d:\n", whichBuf));
592	for (row = 0; row <= screen->max_row; ++row) {
593	    LineData *ld = getLineData(screen, row);
594
595	    TRACE((" %3d:", row));
596	    if (ld != 0) {
597		int col;
598
599		for (col = 0; col < ld->lineSize; ++col) {
600		    int ch = (int) ld->charData[col];
601		    if (ch < ' ')
602			ch = ' ';
603		    if (ch >= 127)
604			ch = '#';
605		    TRACE(("%c", ch));
606		}
607		TRACE((":\n"));
608
609		TRACE(("  xx:"));
610		for (col = 0; col < ld->lineSize; ++col) {
611		    unsigned attrs = ld->attribs[col];
612		    char ch;
613		    if (attrs & PROTECTED) {
614			ch = '*';
615		    } else if (attrs & BLINK) {
616			ch = 'B';
617		    } else if (attrs & CHARDRAWN) {
618			ch = '+';
619		    } else {
620			ch = ' ';
621		    }
622		    TRACE(("%c", ch));
623		}
624		TRACE((":\n"));
625
626#if 0
627		TRACE(("  fg:"));
628		for (col = 0; col < ld->lineSize; ++col) {
629		    unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]);
630		    if (fg > 15)
631			fg = 15;
632		    TRACE(("%1x", fg));
633		}
634		TRACE((":\n"));
635
636		TRACE(("  bg:"));
637		for (col = 0; col < ld->lineSize; ++col) {
638		    unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]);
639		    if (bg > 15)
640			bg = 15;
641		    TRACE(("%1x", bg));
642		}
643		TRACE((":\n"));
644#endif
645	    } else {
646		TRACE(("null lineData\n"));
647	    }
648	}
649    } else {
650	TRACE(("TraceScreen %d is nil\n", whichBuf));
651    }
652}
653
654void
655TraceFocus(Widget w, XEvent *ev)
656{
657    TRACE(("trace_focus event type %d:%s\n",
658	   ev->type, visibleEventType(ev->type)));
659    switch (ev->type) {
660    case FocusIn:
661    case FocusOut:
662	{
663	    XFocusChangeEvent *event = (XFocusChangeEvent *) ev;
664	    TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail)));
665	    TRACE(("\tmode:   %s\n", visibleNotifyMode(event->mode)));
666	    TRACE(("\twindow: %#lx\n", event->window));
667	}
668	break;
669    case EnterNotify:
670    case LeaveNotify:
671	{
672	    XCrossingEvent *event = (XCrossingEvent *) ev;
673	    TRACE(("\tdetail:    %s\n", visibleNotifyDetail(event->detail)));
674	    TRACE(("\tmode:      %s\n", visibleNotifyMode(event->mode)));
675	    TRACE(("\twindow:    %#lx\n", event->window));
676	    TRACE(("\tfocus:     %d\n", event->focus));
677	    TRACE(("\troot:      %#lx\n", event->root));
678	    TRACE(("\tsubwindow: %#lx\n", event->subwindow));
679	}
680	break;
681    }
682    while (w != 0) {
683	TRACE(("w %p -> %#lx\n", (void *) w, XtWindow(w)));
684	w = XtParent(w);
685    }
686}
687
688void
689TraceSizeHints(XSizeHints * hints)
690{
691    TRACE(("size hints:\n"));
692    if (hints->flags & (USPosition | PPosition))
693	TRACE(("   position   %d,%d%s%s\n", hints->y, hints->x,
694	       (hints->flags & USPosition) ? " user" : "",
695	       (hints->flags & PPosition) ? " prog" : ""));
696    if (hints->flags & (USSize | PSize))
697	TRACE(("   size       %d,%d%s%s\n", hints->height, hints->width,
698	       (hints->flags & USSize) ? " user" : "",
699	       (hints->flags & PSize) ? " prog" : ""));
700    if (hints->flags & PMinSize)
701	TRACE(("   min        %d,%d\n", hints->min_height, hints->min_width));
702    if (hints->flags & PMaxSize)
703	TRACE(("   max        %d,%d\n", hints->max_height, hints->max_width));
704    if (hints->flags & PResizeInc)
705	TRACE(("   inc        %d,%d\n", hints->height_inc, hints->width_inc));
706    else
707	TRACE(("   inc        NONE!\n"));
708    if (hints->flags & PAspect)
709	TRACE(("   min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y));
710    if (hints->flags & PAspect)
711	TRACE(("   max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y));
712    if (hints->flags & PBaseSize)
713	TRACE(("   base       %d,%d\n", hints->base_height, hints->base_width));
714    if (hints->flags & PWinGravity)
715	TRACE(("   gravity    %d\n", hints->win_gravity));
716}
717
718static void
719TraceEventMask(const char *tag, long mask)
720{
721#define DATA(name) { name##Mask, #name }
722    /* *INDENT-OFF* */
723    static struct {
724	long mask;
725	const char *name;
726    } table[] = {
727	DATA(KeyPress),
728	DATA(KeyRelease),
729	DATA(ButtonPress),
730	DATA(ButtonRelease),
731	DATA(EnterWindow),
732	DATA(LeaveWindow),
733	DATA(PointerMotion),
734	DATA(PointerMotionHint),
735	DATA(Button1Motion),
736	DATA(Button2Motion),
737	DATA(Button3Motion),
738	DATA(Button4Motion),
739	DATA(Button5Motion),
740	DATA(ButtonMotion),
741	DATA(KeymapState),
742	DATA(Exposure),
743	DATA(VisibilityChange),
744	DATA(StructureNotify),
745	DATA(ResizeRedirect),
746	DATA(SubstructureNotify),
747	DATA(SubstructureRedirect),
748	DATA(FocusChange),
749	DATA(PropertyChange),
750	DATA(ColormapChange),
751	DATA(OwnerGrabButton),
752    };
753#undef DATA
754    Cardinal n;
755    /* *INDENT-ON* */
756
757    for (n = 0; n < XtNumber(table); ++n) {
758	if (table[n].mask & mask) {
759	    TRACE(("%s %s\n", tag, table[n].name));
760	}
761    }
762}
763
764void
765TraceWindowAttributes(XWindowAttributes * attrs)
766{
767    TRACE(("window attributes:\n"));
768    TRACE(("   position     %d,%d\n", attrs->y, attrs->x));
769    TRACE(("   size         %dx%d\n", attrs->height, attrs->width));
770    TRACE(("   border       %d\n", attrs->border_width));
771    TRACE(("   depth        %d\n", attrs->depth));
772    TRACE(("   bit_gravity  %d\n", attrs->bit_gravity));
773    TRACE(("   win_gravity  %d\n", attrs->win_gravity));
774    TRACE(("   root         %#lx\n", (long) attrs->root));
775    TRACE(("   class        %s\n", ((attrs->class == InputOutput)
776				    ? "InputOutput"
777				    : ((attrs->class == InputOnly)
778				       ? "InputOnly"
779				       : "unknown"))));
780    TRACE(("   map_state    %s\n", ((attrs->map_state == IsUnmapped)
781				    ? "IsUnmapped"
782				    : ((attrs->map_state == IsUnviewable)
783				       ? "IsUnviewable"
784				       : ((attrs->map_state == IsViewable)
785					  ? "IsViewable"
786					  : "unknown")))));
787    TRACE(("   all_events\n"));
788    TraceEventMask("        ", attrs->all_event_masks);
789    TRACE(("   your_events\n"));
790    TraceEventMask("        ", attrs->your_event_mask);
791    TRACE(("   no_propagate\n"));
792    TraceEventMask("        ", attrs->do_not_propagate_mask);
793}
794
795void
796TraceWMSizeHints(XtermWidget xw)
797{
798    XSizeHints sizehints = xw->hints;
799
800    getXtermSizeHints(xw);
801    TraceSizeHints(&xw->hints);
802    xw->hints = sizehints;
803}
804
805/*
806 * Some calls to XGetAtom() will fail, and we don't want to stop.  So we use
807 * our own error-handler.
808 */
809/* ARGSUSED */
810static int
811no_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED)
812{
813    return 1;
814}
815
816const char *
817ModifierName(unsigned modifier)
818{
819    const char *s = "";
820    if (modifier & ShiftMask)
821	s = " Shift";
822    else if (modifier & LockMask)
823	s = " Lock";
824    else if (modifier & ControlMask)
825	s = " Control";
826    else if (modifier & Mod1Mask)
827	s = " Mod1";
828    else if (modifier & Mod2Mask)
829	s = " Mod2";
830    else if (modifier & Mod3Mask)
831	s = " Mod3";
832    else if (modifier & Mod4Mask)
833	s = " Mod4";
834    else if (modifier & Mod5Mask)
835	s = " Mod5";
836    return s;
837}
838
839void
840TraceTranslations(const char *name, Widget w)
841{
842    String result;
843    XErrorHandler save = XSetErrorHandler(no_error);
844    XtTranslations xlations;
845    Widget xcelerat;
846
847    TRACE(("TraceTranslations for %s (widget %#lx) {{\n", name, (long) w));
848    if (w) {
849	XtVaGetValues(w,
850		      XtNtranslations, &xlations,
851		      XtNaccelerators, &xcelerat,
852		      (XtPointer) 0);
853	TRACE(("... xlations %#08lx\n", (long) xlations));
854	TRACE(("... xcelerat %#08lx\n", (long) xcelerat));
855	result = _XtPrintXlations(w, xlations, xcelerat, True);
856	TRACE(("%s\n", NonNull(result)));
857	if (result)
858	    XFree((char *) result);
859    } else {
860	TRACE(("none (widget is null)\n"));
861    }
862    TRACE(("}}\n"));
863    XSetErrorHandler(save);
864}
865
866XtGeometryResult
867TraceResizeRequest(const char *fn, int ln, Widget w,
868		   unsigned reqwide,
869		   unsigned reqhigh,
870		   Dimension *gotwide,
871		   Dimension *gothigh)
872{
873    XtGeometryResult rc;
874
875    TRACE(("%s@%d ResizeRequest %ux%u\n", fn, ln, reqhigh, reqwide));
876    rc = XtMakeResizeRequest((Widget) w,
877			     (Dimension) reqwide,
878			     (Dimension) reqhigh,
879			     gotwide, gothigh);
880    TRACE(("... ResizeRequest -> "));
881    if (gothigh && gotwide)
882	TRACE(("%dx%d ", *gothigh, *gotwide));
883    TRACE(("(%d)\n", rc));
884    return rc;
885}
886
887#define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name))
888#define XRES_B(name) Trace(#name " = %s\n", MtoS(resp->name))
889#define XRES_I(name) Trace(#name " = %d\n", resp->name)
890
891void
892TraceXtermResources(void)
893{
894    XTERM_RESOURCE *resp = &resource;
895
896    Trace("XTERM_RESOURCE settings:\n");
897    XRES_S(icon_geometry);
898    XRES_S(title);
899    XRES_S(icon_hint);
900    XRES_S(icon_name);
901    XRES_S(term_name);
902    XRES_S(tty_modes);
903    XRES_I(minBufSize);
904    XRES_I(maxBufSize);
905    XRES_B(hold_screen);
906    XRES_B(utmpInhibit);
907    XRES_B(utmpDisplayId);
908    XRES_B(messages);
909    XRES_S(menuLocale);
910    XRES_S(omitTranslation);
911    XRES_S(keyboardType);
912#if OPT_PRINT_ON_EXIT
913    XRES_I(printModeNow);
914    XRES_I(printModeOnXError);
915    XRES_I(printOptsNow);
916    XRES_I(printOptsOnXError);
917    XRES_S(printFileNow);
918    XRES_S(printFileOnXError);
919#endif
920#if OPT_SUNPC_KBD
921    XRES_B(sunKeyboard);
922#endif
923#if OPT_HP_FUNC_KEYS
924    XRES_B(hpFunctionKeys);
925#endif
926#if OPT_SCO_FUNC_KEYS
927    XRES_B(scoFunctionKeys);
928#endif
929#if OPT_SUN_FUNC_KEYS
930    XRES_B(sunFunctionKeys);
931#endif
932#if OPT_INITIAL_ERASE
933    XRES_B(ptyInitialErase);
934    XRES_B(backarrow_is_erase);
935#endif
936    XRES_B(useInsertMode);
937#if OPT_ZICONBEEP
938    XRES_I(zIconBeep);
939    XRES_S(zIconFormat);
940#endif
941#if OPT_PTY_HANDSHAKE
942    XRES_B(wait_for_map);
943    XRES_B(ptyHandshake);
944    XRES_B(ptySttySize);
945#endif
946#if OPT_REPORT_COLORS
947    XRES_B(reportColors);
948#endif
949#if OPT_REPORT_FONTS
950    XRES_B(reportFonts);
951#endif
952#if OPT_SAME_NAME
953    XRES_B(sameName);
954#endif
955#if OPT_SESSION_MGT
956    XRES_B(sessionMgt);
957#endif
958#if OPT_TOOLBAR
959    XRES_B(toolBar);
960#endif
961#if OPT_MAXIMIZE
962    XRES_B(maximized);
963    XRES_S(fullscreen_s);
964#endif
965}
966
967void
968TraceArgv(const char *tag, char **argv)
969{
970    int n = 0;
971
972    TRACE(("%s:\n", tag));
973    while (*argv != 0) {
974	TRACE(("  %d:%s\n", n++, *argv++));
975    }
976}
977
978static char *
979parse_option(char *dst, String src, int first)
980{
981    char *s;
982
983    if (!strncmp(src, "-/+", (size_t) 3)) {
984	dst[0] = (char) first;
985	strcpy(dst + 1, src + 3);
986    } else {
987	strcpy(dst, src);
988    }
989    for (s = dst; *s != '\0'; s++) {
990	if (*s == '#' || *s == '%' || *s == 'S') {
991	    s[1] = '\0';
992	} else if (*s == ' ') {
993	    *s = '\0';
994	    break;
995	}
996    }
997    return dst;
998}
999
1000static Bool
1001same_option(OptionHelp * opt, XrmOptionDescRec * res)
1002{
1003    char temp[BUFSIZ];
1004    return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option);
1005}
1006
1007static Bool
1008standard_option(String opt)
1009{
1010    static const char *table[] =
1011    {
1012	"+rv",
1013	"+synchronous",
1014	"-background",
1015	"-bd",
1016	"-bg",
1017	"-bordercolor",
1018	"-borderwidth",
1019	"-bw",
1020	"-display",
1021	"-fg",
1022	"-fn",
1023	"-font",
1024	"-foreground",
1025	"-geometry",
1026	"-iconic",
1027	"-name",
1028	"-reverse",
1029	"-rv",
1030	"-selectionTimeout",
1031	"-synchronous",
1032	"-title",
1033	"-xnllanguage",
1034	"-xrm",
1035	"-xtsessionID",
1036    };
1037    Cardinal n;
1038    char temp[BUFSIZ];
1039
1040    opt = parse_option(temp, opt, '-');
1041    for (n = 0; n < XtNumber(table); n++) {
1042	if (!strcmp(opt, table[n]))
1043	    return True;
1044    }
1045    return False;
1046}
1047
1048/*
1049 * Analyse the options/help messages for inconsistencies.
1050 */
1051void
1052TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count)
1053{
1054    OptionHelp *opt_array = sortedOpts(options, resources, res_count);
1055    size_t j, k;
1056    XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count);
1057    Bool first, found;
1058
1059    TRACE(("Checking options-tables for inconsistencies:\n"));
1060
1061#if 0
1062    TRACE(("Options listed in help-message:\n"));
1063    for (j = 0; options[j].opt != 0; j++)
1064	TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc));
1065    TRACE(("Options listed in resource-table:\n"));
1066    for (j = 0; j < res_count; j++)
1067	TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier));
1068#endif
1069
1070    /* list all options[] not found in resources[] */
1071    for (j = 0, first = True; options[j].opt != 0; j++) {
1072	found = False;
1073	for (k = 0; k < res_count; k++) {
1074	    if (same_option(&opt_array[j], &res_array[k])) {
1075		found = True;
1076		break;
1077	    }
1078	}
1079	if (!found) {
1080	    if (first) {
1081		TRACE(("Options listed in help, not found in resource list:\n"));
1082		first = False;
1083	    }
1084	    TRACE(("  %-28s%s\n", opt_array[j].opt,
1085		   standard_option(opt_array[j].opt) ? " (standard)" : ""));
1086	}
1087    }
1088
1089    /* list all resources[] not found in options[] */
1090    for (j = 0, first = True; j < res_count; j++) {
1091	found = False;
1092	for (k = 0; options[k].opt != 0; k++) {
1093	    if (same_option(&opt_array[k], &res_array[j])) {
1094		found = True;
1095		break;
1096	    }
1097	}
1098	if (!found) {
1099	    if (first) {
1100		TRACE(("Resource list items not found in options-help:\n"));
1101		first = False;
1102	    }
1103	    TRACE(("  %s\n", res_array[j].option));
1104	}
1105    }
1106
1107    TRACE(("Resource list items that will be ignored by XtOpenApplication:\n"));
1108    for (j = 0; j < res_count; j++) {
1109	switch (res_array[j].argKind) {
1110	case XrmoptionSkipArg:
1111	    TRACE(("  %-28s {param}\n", res_array[j].option));
1112	    break;
1113	case XrmoptionSkipNArgs:
1114	    TRACE(("  %-28s {%ld params}\n", res_array[j].option, (long)
1115		   res_array[j].value));
1116	    break;
1117	case XrmoptionSkipLine:
1118	    TRACE(("  %-28s {remainder of line}\n", res_array[j].option));
1119	    break;
1120	case XrmoptionIsArg:
1121	case XrmoptionNoArg:
1122	case XrmoptionResArg:
1123	case XrmoptionSepArg:
1124	case XrmoptionStickyArg:
1125	default:
1126	    break;
1127	}
1128    }
1129}
1130#else
1131extern void empty_trace(void);
1132void
1133empty_trace(void)
1134{
1135}
1136#endif
1137