trace.c revision e39b573c
1/* $XTermId: trace.c,v 1.125 2011/07/12 09:31:05 tom Exp $ */
2
3/*
4 * Copyright 1997-2010,2011 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/*
35 * debugging support via TRACE macro.
36 */
37
38#include <xterm.h>		/* for definition of GCC_UNUSED */
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 <stdio.h>
50#include <stdarg.h>
51#include <assert.h>
52
53#include <X11/Xatom.h>
54#include <X11/Xmu/Atoms.h>
55
56#ifdef HAVE_X11_TRANSLATEI_H
57#include <X11/TranslateI.h>
58#else
59#ifdef __cplusplus
60extern "C" {
61#endif
62
63    extern String _XtPrintXlations(Widget w,
64				   XtTranslations xlations,
65				   Widget accelWidget,
66				   _XtBoolean includeRHS);
67#ifdef __cplusplus
68}
69#endif
70#endif
71const char *trace_who = "parent";
72
73static FILE *trace_fp;
74
75void
76Trace(const char *fmt,...)
77{
78    static const char *trace_out;
79    va_list ap;
80
81    if (trace_fp != 0
82	&& trace_who != trace_out) {
83	fclose(trace_fp);
84	trace_fp = 0;
85    }
86    trace_out = trace_who;
87
88    if (!trace_fp) {
89	char name[BUFSIZ];
90#if 0				/* usually I do not want unique names */
91	int unique;
92	for (unique = 0;; ++unique) {
93	    if (unique)
94		sprintf(name, "Trace-%s.out-%d", trace_who, unique);
95	    else
96		sprintf(name, "Trace-%s.out", trace_who);
97	    if ((trace_fp = fopen(name, "r")) == 0) {
98		break;
99	    }
100	    fclose(trace_fp);
101	}
102#else
103	sprintf(name, "Trace-%s.out", trace_who);
104#endif
105	trace_fp = fopen(name, "w");
106	if (trace_fp != 0) {
107	    fprintf(trace_fp, "%s\n", xtermVersion());
108	    TraceIds(NULL, 0);
109	}
110    }
111    if (!trace_fp)
112	abort();
113
114    va_start(ap, fmt);
115    vfprintf(trace_fp, fmt, ap);
116    (void) fflush(trace_fp);
117    va_end(ap);
118}
119
120void
121TraceClose(void)
122{
123    if (trace_fp != 0) {
124	(void) fclose(trace_fp);
125	(void) fflush(stdout);
126	(void) fflush(stderr);
127	(void) visibleChars(NULL, 0);
128	(void) visibleIChars(NULL, 0);
129	(void) visibleIChar(NULL, 0);
130	trace_fp = 0;
131    }
132}
133
134void
135TraceIds(const char *fname, int lnum)
136{
137    Trace("process %d ", (int) getpid());
138#ifdef HAVE_UNISTD_H
139    Trace("real (%u/%u) effective (%u/%u)",
140	  (unsigned) getuid(), (unsigned) getgid(),
141	  (unsigned) geteuid(), (unsigned) getegid());
142#endif
143    if (fname != 0) {
144	Trace(" (%s@%d)\n", fname, lnum);
145    } else {
146	time_t now = time((time_t *) 0);
147	Trace("-- %s", ctime(&now));
148    }
149}
150
151static void
152formatAscii(char *dst, unsigned value)
153{
154    switch (value) {
155    case '\\':
156	sprintf(dst, "\\\\");
157	break;
158    case '\b':
159	sprintf(dst, "\\b");
160	break;
161    case '\n':
162	sprintf(dst, "\\n");
163	break;
164    case '\r':
165	sprintf(dst, "\\r");
166	break;
167    case '\t':
168	sprintf(dst, "\\t");
169	break;
170    default:
171	if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160))
172	    sprintf(dst, "\\%03o", value);
173	else
174	    sprintf(dst, "%c", CharOf(value));
175	break;
176    }
177}
178
179#if OPT_DEC_CHRSET
180
181const char *
182visibleChrsetName(unsigned chrset)
183{
184    const char *result = "?";
185    switch (chrset) {
186    case CSET_SWL:
187	result = "CSET_SWL";
188	break;
189    case CSET_DHL_TOP:
190	result = "CSET_DHL_TOP";
191	break;
192    case CSET_DHL_BOT:
193	result = "CSET_DHL_BOT";
194	break;
195    case CSET_DWL:
196	result = "CSET_DWL";
197	break;
198    }
199    return result;
200}
201#endif
202
203char *
204visibleChars(const Char * buf, unsigned len)
205{
206    static char *result;
207    static unsigned used;
208
209    if (buf != 0) {
210	unsigned limit = ((len + 1) * 8) + 1;
211	char *dst;
212
213	if (limit > used) {
214	    used = limit;
215	    result = XtRealloc(result, used);
216	}
217	if (result != 0) {
218	    dst = result;
219	    *dst = '\0';
220	    while (len--) {
221		unsigned value = *buf++;
222		formatAscii(dst, value);
223		dst += strlen(dst);
224	    }
225	}
226    } else if (result != 0) {
227	free(result);
228	result = 0;
229	used = 0;
230    }
231    return result;
232}
233
234char *
235visibleIChars(IChar * buf, unsigned len)
236{
237    static char *result;
238    static unsigned used;
239
240    if (buf != 0) {
241	unsigned limit = ((len + 1) * 8) + 1;
242	char *dst;
243
244	if (limit > used) {
245	    used = limit;
246	    result = XtRealloc(result, used);
247	}
248	if (result != 0) {
249	    dst = result;
250	    *dst = '\0';
251	    while (len--) {
252		unsigned value = *buf++;
253#if OPT_WIDE_CHARS
254		if (value > 255)
255		    sprintf(dst, "\\u+%04X", value);
256		else
257#endif
258		    formatAscii(dst, value);
259		dst += strlen(dst);
260	    }
261	}
262    } else if (result != 0) {
263	free(result);
264	result = 0;
265	used = 0;
266    }
267    return result;
268}
269
270char *
271visibleIChar(IChar * buf, unsigned len)
272{
273    static char *result;
274    static unsigned used;
275
276    if (buf != 0) {
277	unsigned limit = ((len + 1) * 8) + 1;
278	char *dst;
279
280	if (limit > used) {
281	    used = limit;
282	    result = XtRealloc(result, used);
283	}
284	if (result != 0) {
285	    dst = result;
286	    while (len--) {
287		unsigned value = *buf++;
288#if OPT_WIDE_CHARS
289		if (value > 255)
290		    sprintf(dst, "\\u+%04X", value);
291		else
292#endif
293		    formatAscii(dst, value);
294		dst += strlen(dst);
295	    }
296	}
297    } else if (result != 0) {
298	free(result);
299	result = 0;
300	used = 0;
301    }
302    return result;
303}
304
305#define CASETYPE(name) case name: result = #name; break
306
307const char *
308visibleKeyboardType(xtermKeyboardType type)
309{
310    const char *result = "?";
311    switch (type) {
312	CASETYPE(keyboardIsLegacy);	/* bogus vt220 codes for F1-F4, etc. */
313	CASETYPE(keyboardIsDefault);
314	CASETYPE(keyboardIsHP);
315	CASETYPE(keyboardIsSCO);
316	CASETYPE(keyboardIsSun);
317	CASETYPE(keyboardIsTermcap);
318	CASETYPE(keyboardIsVT220);
319    }
320    return result;
321}
322
323const char *
324visibleEventType(int type)
325{
326    const char *result = "?";
327    switch (type) {
328	CASETYPE(KeyPress);
329	CASETYPE(KeyRelease);
330	CASETYPE(ButtonPress);
331	CASETYPE(ButtonRelease);
332	CASETYPE(MotionNotify);
333	CASETYPE(EnterNotify);
334	CASETYPE(LeaveNotify);
335	CASETYPE(FocusIn);
336	CASETYPE(FocusOut);
337	CASETYPE(KeymapNotify);
338	CASETYPE(Expose);
339	CASETYPE(GraphicsExpose);
340	CASETYPE(NoExpose);
341	CASETYPE(VisibilityNotify);
342	CASETYPE(CreateNotify);
343	CASETYPE(DestroyNotify);
344	CASETYPE(UnmapNotify);
345	CASETYPE(MapNotify);
346	CASETYPE(MapRequest);
347	CASETYPE(ReparentNotify);
348	CASETYPE(ConfigureNotify);
349	CASETYPE(ConfigureRequest);
350	CASETYPE(GravityNotify);
351	CASETYPE(ResizeRequest);
352	CASETYPE(CirculateNotify);
353	CASETYPE(CirculateRequest);
354	CASETYPE(PropertyNotify);
355	CASETYPE(SelectionClear);
356	CASETYPE(SelectionRequest);
357	CASETYPE(SelectionNotify);
358	CASETYPE(ColormapNotify);
359	CASETYPE(ClientMessage);
360	CASETYPE(MappingNotify);
361    }
362    return result;
363}
364
365const char *
366visibleNotifyDetail(int code)
367{
368    const char *result = "?";
369    switch (code) {
370	CASETYPE(NotifyAncestor);
371	CASETYPE(NotifyVirtual);
372	CASETYPE(NotifyInferior);
373	CASETYPE(NotifyNonlinear);
374	CASETYPE(NotifyNonlinearVirtual);
375	CASETYPE(NotifyPointer);
376	CASETYPE(NotifyPointerRoot);
377	CASETYPE(NotifyDetailNone);
378    }
379    return result;
380}
381
382const char *
383visibleSelectionTarget(Display * d, Atom a)
384{
385    const char *result = "?";
386
387    if (a == XA_STRING) {
388	result = "XA_STRING";
389    } else if (a == XA_TEXT(d)) {
390	result = "XA_TEXT()";
391    } else if (a == XA_COMPOUND_TEXT(d)) {
392	result = "XA_COMPOUND_TEXT()";
393    } else if (a == XA_UTF8_STRING(d)) {
394	result = "XA_UTF8_STRING()";
395    } else if (a == XA_TARGETS(d)) {
396	result = "XA_TARGETS()";
397    }
398
399    return result;
400}
401
402const char *
403visibleXError(int code)
404{
405    static char temp[80];
406    const char *result = "?";
407    switch (code) {
408	CASETYPE(Success);
409	CASETYPE(BadRequest);
410	CASETYPE(BadValue);
411	CASETYPE(BadWindow);
412	CASETYPE(BadPixmap);
413	CASETYPE(BadAtom);
414	CASETYPE(BadCursor);
415	CASETYPE(BadFont);
416	CASETYPE(BadMatch);
417	CASETYPE(BadDrawable);
418	CASETYPE(BadAccess);
419	CASETYPE(BadAlloc);
420	CASETYPE(BadColor);
421	CASETYPE(BadGC);
422	CASETYPE(BadIDChoice);
423	CASETYPE(BadName);
424	CASETYPE(BadLength);
425	CASETYPE(BadImplementation);
426    default:
427	sprintf(temp, "%d", code);
428	result = temp;
429	break;
430    }
431    return result;
432}
433
434#if OPT_TRACE_FLAGS
435#define isScrnFlag(flag) ((flag) == LINEWRAPPED)
436
437static char *
438ScrnText(LineData * ld)
439{
440    return visibleIChars(ld->charData, ld->lineSize);
441}
442
443#define SHOW_BAD_LINE(name, ld) \
444	Trace("OOPS " #name " bad row\n")
445
446#define SHOW_SCRN_FLAG(name,code) \
447	Trace(#name " %s:%s\n", \
448	      code ? "*" : "", \
449	      ScrnText(ld))
450
451void
452LineClrFlag(LineData * ld, int flag)
453{
454    if (ld == 0) {
455	SHOW_BAD_LINE(LineClrFlag, ld);
456	assert(0);
457    } else if (isScrnFlag(flag)) {
458	SHOW_SCRN_FLAG(LineClrFlag, 0);
459    }
460
461    LineFlags(ld) &= ~flag;
462}
463
464void
465LineSetFlag(LineData * ld, int flag)
466{
467    if (ld == 0) {
468	SHOW_BAD_LINE(LineSetFlag, ld);
469	assert(0);
470    } else if (isScrnFlag(flag)) {
471	SHOW_SCRN_FLAG(LineSetFlag, 1);
472    }
473
474    LineFlags(ld) |= flag;
475}
476
477int
478LineTstFlag(LineData ld, int flag)
479{
480    int code = 0;
481    if (ld == 0) {
482	SHOW_BAD_LINE(LineTstFlag, ld);
483    } else {
484	code = LineFlags(ld);
485
486	if (isScrnFlag(flag)) {
487	    SHOW_SCRN_FLAG(LineTstFlag, code);
488	}
489    }
490    return code;
491}
492#endif /* OPT_TRACE_FLAGS */
493
494void
495TraceFocus(Widget w, XEvent * ev)
496{
497    TRACE(("trace_focus event type %d:%s\n",
498	   ev->type, visibleEventType(ev->type)));
499    switch (ev->type) {
500    case FocusIn:
501    case FocusOut:
502	{
503	    XFocusChangeEvent *event = (XFocusChangeEvent *) ev;
504	    TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail)));
505	    TRACE(("\tmode:   %d\n", event->mode));
506	    TRACE(("\twindow: %#lx\n", event->window));
507	}
508	break;
509    case EnterNotify:
510    case LeaveNotify:
511	{
512	    XCrossingEvent *event = (XCrossingEvent *) ev;
513	    TRACE(("\tdetail:    %s\n", visibleNotifyDetail(event->detail)));
514	    TRACE(("\tmode:      %d\n", event->mode));
515	    TRACE(("\twindow:    %#lx\n", event->window));
516	    TRACE(("\tfocus:     %d\n", event->focus));
517	    TRACE(("\troot:      %#lx\n", event->root));
518	    TRACE(("\tsubwindow: %#lx\n", event->subwindow));
519	}
520	break;
521    }
522    while (w != 0) {
523	TRACE(("w %p -> %#lx\n", (void *) w, XtWindow(w)));
524	w = XtParent(w);
525    }
526}
527
528void
529TraceSizeHints(XSizeHints * hints)
530{
531    TRACE(("size hints:\n"));
532    if (hints->flags & (USPosition | PPosition))
533	TRACE(("   position   %d,%d%s%s\n", hints->y, hints->x,
534	       hints->flags & USPosition ? " user" : "",
535	       hints->flags & PPosition ? " prog" : ""));
536    if (hints->flags & (USSize | PSize))
537	TRACE(("   size       %d,%d%s%s\n", hints->height, hints->width,
538	       hints->flags & USSize ? " user" : "",
539	       hints->flags & PSize ? " prog" : ""));
540    if (hints->flags & PMinSize)
541	TRACE(("   min        %d,%d\n", hints->min_height, hints->min_width));
542    if (hints->flags & PMaxSize)
543	TRACE(("   max        %d,%d\n", hints->max_height, hints->max_width));
544    if (hints->flags & PResizeInc)
545	TRACE(("   inc        %d,%d\n", hints->height_inc, hints->width_inc));
546    else
547	TRACE(("   inc        NONE!\n"));
548    if (hints->flags & PAspect)
549	TRACE(("   min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y));
550    if (hints->flags & PAspect)
551	TRACE(("   max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y));
552    if (hints->flags & PBaseSize)
553	TRACE(("   base       %d,%d\n", hints->base_height, hints->base_width));
554    if (hints->flags & PWinGravity)
555	TRACE(("   gravity    %d\n", hints->win_gravity));
556}
557
558void
559TraceWMSizeHints(XtermWidget xw)
560{
561    XSizeHints sizehints = xw->hints;
562
563    getXtermSizeHints(xw);
564    TraceSizeHints(&xw->hints);
565    xw->hints = sizehints;
566}
567
568/*
569 * Some calls to XGetAtom() will fail, and we don't want to stop.  So we use
570 * our own error-handler.
571 */
572/* ARGSUSED */
573static int
574no_error(Display * dpy GCC_UNUSED, XErrorEvent * event GCC_UNUSED)
575{
576    return 1;
577}
578
579void
580TraceTranslations(const char *name, Widget w)
581{
582    String result;
583    XErrorHandler save = XSetErrorHandler(no_error);
584    XtTranslations xlations;
585    Widget xcelerat;
586
587    TRACE(("TraceTranslations for %s (widget %#lx) {{\n", name, (long) w));
588    if (w) {
589	XtVaGetValues(w,
590		      XtNtranslations, &xlations,
591		      XtNaccelerators, &xcelerat,
592		      (XtPointer) 0);
593	TRACE(("... xlations %#08lx\n", (long) xlations));
594	TRACE(("... xcelerat %#08lx\n", (long) xcelerat));
595	result = _XtPrintXlations(w, xlations, xcelerat, True);
596	TRACE(("%s\n", NonNull(result)));
597	if (result)
598	    XFree((char *) result);
599    } else {
600	TRACE(("none (widget is null)\n"));
601    }
602    TRACE(("}}\n"));
603    XSetErrorHandler(save);
604}
605
606int
607TraceResizeRequest(const char *fn, int ln, Widget w,
608		   unsigned reqwide,
609		   unsigned reqhigh,
610		   Dimension * gotwide,
611		   Dimension * gothigh)
612{
613    int rc;
614
615    TRACE(("%s@%d ResizeRequest %ux%u\n", fn, ln, reqhigh, reqwide));
616    rc = XtMakeResizeRequest((Widget) w, reqwide, reqhigh, gotwide, gothigh);
617    TRACE(("... ResizeRequest -> "));
618    if (gothigh && gotwide)
619	TRACE(("%dx%d ", *gothigh, *gotwide));
620    TRACE(("(%d)\n", rc));
621    return rc;
622}
623
624#define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name))
625#define XRES_B(name) Trace(#name " = %s\n", BtoS(resp->name))
626#define XRES_I(name) Trace(#name " = %d\n", resp->name)
627
628void
629TraceXtermResources(void)
630{
631    XTERM_RESOURCE *resp = &resource;
632
633    Trace("XTERM_RESOURCE settings:\n");
634    XRES_S(icon_geometry);
635    XRES_S(title);
636    XRES_S(icon_name);
637    XRES_S(term_name);
638    XRES_S(tty_modes);
639    XRES_I(minBufSize);
640    XRES_I(maxBufSize);
641    XRES_B(hold_screen);
642    XRES_B(utmpInhibit);
643    XRES_B(utmpDisplayId);
644    XRES_B(messages);
645    XRES_S(menuLocale);
646    XRES_S(omitTranslation);
647    XRES_S(keyboardType);
648#if OPT_PRINT_ON_EXIT
649    XRES_I(printModeNow);
650    XRES_I(printModeOnXError);
651    XRES_I(printOptsNow);
652    XRES_I(printOptsOnXError);
653    XRES_S(printFileNow);
654    XRES_S(printFileOnXError);
655#endif
656#if OPT_SUNPC_KBD
657    XRES_B(sunKeyboard);
658#endif
659#if OPT_HP_FUNC_KEYS
660    XRES_B(hpFunctionKeys);
661#endif
662#if OPT_SCO_FUNC_KEYS
663    XRES_B(scoFunctionKeys);
664#endif
665#if OPT_SUN_FUNC_KEYS
666    XRES_B(sunFunctionKeys);
667#endif
668#if OPT_INITIAL_ERASE
669    XRES_B(ptyInitialErase);
670    XRES_B(backarrow_is_erase);
671#endif
672    XRES_B(useInsertMode);
673#if OPT_ZICONBEEP
674    XRES_I(zIconBeep);
675#endif
676#if OPT_PTY_HANDSHAKE
677    XRES_B(wait_for_map);
678    XRES_B(ptyHandshake);
679    XRES_B(ptySttySize);
680#endif
681#if OPT_SAME_NAME
682    XRES_B(sameName);
683#endif
684#if OPT_SESSION_MGT
685    XRES_B(sessionMgt);
686#endif
687#if OPT_TOOLBAR
688    XRES_B(toolBar);
689#endif
690#if OPT_MAXIMIZE
691    XRES_B(maximized);
692    XRES_S(fullscreen_s);
693#endif
694}
695
696void
697TraceArgv(const char *tag, char **argv)
698{
699    int n = 0;
700
701    TRACE(("%s:\n", tag));
702    while (*argv != 0) {
703	TRACE(("  %d:%s\n", n++, *argv++));
704    }
705}
706
707static char *
708parse_option(char *dst, String src, int first)
709{
710    char *s;
711
712    if (!strncmp(src, "-/+", (size_t) 3)) {
713	dst[0] = (char) first;
714	strcpy(dst + 1, src + 3);
715    } else {
716	strcpy(dst, src);
717    }
718    for (s = dst; *s != '\0'; s++) {
719	if (*s == '#' || *s == '%' || *s == 'S') {
720	    s[1] = '\0';
721	} else if (*s == ' ') {
722	    *s = '\0';
723	    break;
724	}
725    }
726    return dst;
727}
728
729static Bool
730same_option(OptionHelp * opt, XrmOptionDescRec * res)
731{
732    char temp[BUFSIZ];
733    return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option);
734}
735
736static Bool
737standard_option(String opt)
738{
739    static const char *table[] =
740    {
741	"+rv",
742	"+synchronous",
743	"-background",
744	"-bd",
745	"-bg",
746	"-bordercolor",
747	"-borderwidth",
748	"-bw",
749	"-display",
750	"-fg",
751	"-fn",
752	"-font",
753	"-foreground",
754	"-geometry",
755	"-iconic",
756	"-name",
757	"-reverse",
758	"-rv",
759	"-selectionTimeout",
760	"-synchronous",
761	"-title",
762	"-xnllanguage",
763	"-xrm",
764	"-xtsessionID",
765    };
766    Cardinal n;
767    char temp[BUFSIZ];
768
769    opt = parse_option(temp, opt, '-');
770    for (n = 0; n < XtNumber(table); n++) {
771	if (!strcmp(opt, table[n]))
772	    return True;
773    }
774    return False;
775}
776
777/*
778 * Analyse the options/help messages for inconsistencies.
779 */
780void
781TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count)
782{
783    OptionHelp *opt_array = sortedOpts(options, resources, res_count);
784    size_t j, k;
785    XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count);
786    Bool first, found;
787
788    TRACE(("Checking options-tables for inconsistencies:\n"));
789
790#if 0
791    TRACE(("Options listed in help-message:\n"));
792    for (j = 0; options[j].opt != 0; j++)
793	TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc));
794    TRACE(("Options listed in resource-table:\n"));
795    for (j = 0; j < res_count; j++)
796	TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier));
797#endif
798
799    /* list all options[] not found in resources[] */
800    for (j = 0, first = True; options[j].opt != 0; j++) {
801	found = False;
802	for (k = 0; k < res_count; k++) {
803	    if (same_option(&opt_array[j], &res_array[k])) {
804		found = True;
805		break;
806	    }
807	}
808	if (!found) {
809	    if (first) {
810		TRACE(("Options listed in help, not found in resource list:\n"));
811		first = False;
812	    }
813	    TRACE(("  %-28s%s\n", opt_array[j].opt,
814		   standard_option(opt_array[j].opt) ? " (standard)" : ""));
815	}
816    }
817
818    /* list all resources[] not found in options[] */
819    for (j = 0, first = True; j < res_count; j++) {
820	found = False;
821	for (k = 0; options[k].opt != 0; k++) {
822	    if (same_option(&opt_array[k], &res_array[j])) {
823		found = True;
824		break;
825	    }
826	}
827	if (!found) {
828	    if (first) {
829		TRACE(("Resource list items not found in options-help:\n"));
830		first = False;
831	    }
832	    TRACE(("  %s\n", res_array[j].option));
833	}
834    }
835
836    TRACE(("Resource list items that will be ignored by XtOpenApplication:\n"));
837    for (j = 0; j < res_count; j++) {
838	switch (res_array[j].argKind) {
839	case XrmoptionSkipArg:
840	    TRACE(("  %-28s {param}\n", res_array[j].option));
841	    break;
842	case XrmoptionSkipNArgs:
843	    TRACE(("  %-28s {%ld params}\n", res_array[j].option, (long)
844		   res_array[j].value));
845	    break;
846	case XrmoptionSkipLine:
847	    TRACE(("  %-28s {remainder of line}\n", res_array[j].option));
848	    break;
849	case XrmoptionIsArg:
850	case XrmoptionNoArg:
851	case XrmoptionResArg:
852	case XrmoptionSepArg:
853	case XrmoptionStickyArg:
854	default:
855	    break;
856	}
857    }
858}
859#else
860extern void empty_trace(void);
861void
862empty_trace(void)
863{
864}
865#endif
866