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