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