/* $XTermId: trace.c,v 1.166 2016/10/05 09:16:01 tom Exp $ */ /* * Copyright 1997-2015,2016 by Thomas E. Dickey * * All Rights Reserved * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name(s) of the above copyright * holders shall not be used in advertising or otherwise to promote the * sale, use or other dealings in this Software without prior written * authorization. */ /* * debugging support via TRACE macro. */ #include /* for definition of GCC_UNUSED */ #include #if OPT_TRACE #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_TRANSLATEI_H #include #include #else #ifdef __cplusplus extern "C" { #endif extern String _XtPrintXlations(Widget w, XtTranslations xlations, Widget accelWidget, _XtBoolean includeRHS); #ifdef __cplusplus } #endif #endif const char *trace_who = "parent"; static FILE *trace_fp; void Trace(const char *fmt,...) { static const char *trace_out; va_list ap; if (trace_fp != 0 && trace_who != trace_out) { fclose(trace_fp); trace_fp = 0; } trace_out = trace_who; if (!trace_fp) { unsigned oldmask = (unsigned) umask(077); char name[BUFSIZ]; #if 0 /* usually I do not want unique names */ int unique; for (unique = 0;; ++unique) { if (unique) sprintf(name, "Trace-%s.out-%d", trace_who, unique); else sprintf(name, "Trace-%s.out", trace_who); if ((trace_fp = fopen(name, "r")) == 0) { break; } fclose(trace_fp); } #else sprintf(name, "Trace-%s.out", trace_who); #endif trace_fp = fopen(name, "w"); /* * Try to put the trace-file in user's home-directory if the current * directory is not writable. */ if (trace_fp == 0) { char *home = getenv("HOME"); if (home != 0) { sprintf(name, "%.*s/Trace-%.8s.out", (BUFSIZ - 21), home, trace_who); trace_fp = fopen(name, "w"); } } if (trace_fp != 0) { fprintf(trace_fp, "%s\n", xtermVersion()); TraceIds(NULL, 0); } if (!trace_fp) { xtermWarning("Cannot open \"%s\"\n", name); exit(EXIT_FAILURE); } (void) umask(oldmask); } va_start(ap, fmt); vfprintf(trace_fp, fmt, ap); (void) fflush(trace_fp); va_end(ap); } void TraceClose(void) { if (trace_fp != 0) { (void) fclose(trace_fp); (void) fflush(stdout); (void) fflush(stderr); (void) visibleChars(NULL, 0); (void) visibleIChars(NULL, 0); trace_fp = 0; } } void TraceIds(const char *fname, int lnum) { Trace("process %d ", (int) getpid()); #ifdef HAVE_UNISTD_H Trace("real (%u/%u) effective (%u/%u)", (unsigned) getuid(), (unsigned) getgid(), (unsigned) geteuid(), (unsigned) getegid()); #endif if (fname != 0) { Trace(" (%s@%d)\n", fname, lnum); } else { time_t now = time((time_t *) 0); Trace("-- %s", ctime(&now)); } } void TraceTime(const char *fname, int lnum) { time_t now; if (fname != 0) { Trace("datetime (%s@%d) ", fname, lnum); } now = time((time_t *) 0); Trace("-- %s", ctime(&now)); } static void formatAscii(char *dst, unsigned value) { switch (value) { case '\\': sprintf(dst, "\\\\"); break; case '\b': sprintf(dst, "\\b"); break; case '\n': sprintf(dst, "\\n"); break; case '\r': sprintf(dst, "\\r"); break; case '\t': sprintf(dst, "\\t"); break; default: if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160)) sprintf(dst, "\\%03o", value & 0xff); else sprintf(dst, "%c", CharOf(value)); break; } } #if OPT_DEC_CHRSET const char * visibleDblChrset(unsigned chrset) { const char *result = "?"; switch (chrset) { case CSET_SWL: result = "CSET_SWL"; break; case CSET_DHL_TOP: result = "CSET_DHL_TOP"; break; case CSET_DHL_BOT: result = "CSET_DHL_BOT"; break; case CSET_DWL: result = "CSET_DWL"; break; } return result; } #endif const char * visibleScsCode(int chrset) { #define MAP(to,from) case from: result = to; break const char *result = ""; switch ((DECNRCM_codes) chrset) { MAP("B", nrc_ASCII); MAP("A", nrc_British); MAP("A", nrc_British_Latin_1); MAP("&4", nrc_Cyrillic); MAP("0", nrc_DEC_Spec_Graphic); MAP("1", nrc_DEC_Alt_Chars); MAP("2", nrc_DEC_Alt_Graphics); MAP("<", nrc_DEC_Supp); MAP("%5", nrc_DEC_Supp_Graphic); MAP(">", nrc_DEC_Technical); MAP("4", nrc_Dutch); MAP("5", nrc_Finnish); MAP("C", nrc_Finnish2); MAP("R", nrc_French); MAP("f", nrc_French2); MAP("Q", nrc_French_Canadian); MAP("9", nrc_French_Canadian2); MAP("K", nrc_German); MAP("\"?", nrc_Greek); MAP("F", nrc_Greek_Supp); MAP("\"4", nrc_Hebrew); MAP("%=", nrc_Hebrew2); MAP("H", nrc_Hebrew_Supp); MAP("Y", nrc_Italian); MAP("M", nrc_Latin_5_Supp); MAP("L", nrc_Latin_Cyrillic); MAP("`", nrc_Norwegian_Danish); MAP("E", nrc_Norwegian_Danish2); MAP("6", nrc_Norwegian_Danish3); MAP("%6", nrc_Portugese); MAP("&5", nrc_Russian); MAP("%3", nrc_SCS_NRCS); MAP("Z", nrc_Spanish); MAP("7", nrc_Swedish); MAP("H", nrc_Swedish2); MAP("=", nrc_Swiss); MAP("%0", nrc_Turkish); MAP("%2", nrc_Turkish2); MAP("", nrc_Unknown); } #undef MAP return result; } const char * visibleChars(const Char *buf, unsigned len) { static char *result; static unsigned used; if (buf != 0) { unsigned limit = ((len + 1) * 8) + 1; if (limit > used) { used = limit; result = XtRealloc(result, used); } if (result != 0) { char *dst = result; *dst = '\0'; while (len--) { unsigned value = *buf++; formatAscii(dst, value); dst += strlen(dst); } } } else if (result != 0) { free(result); result = 0; used = 0; } return NonNull(result); } const char * visibleIChars(const IChar *buf, unsigned len) { static char *result; static unsigned used; if (buf != 0) { unsigned limit = ((len + 1) * 8) + 1; if (limit > used) { used = limit; result = XtRealloc(result, used); } if (result != 0) { char *dst = result; *dst = '\0'; while (len--) { unsigned value = *buf++; #if OPT_WIDE_CHARS if (value > 255) sprintf(dst, "\\u+%04X", value); else #endif formatAscii(dst, value); dst += strlen(dst); } } } else if (result != 0) { free(result); result = 0; used = 0; } return NonNull(result); } const char * visibleUChar(unsigned chr) { IChar buf[1]; buf[0] = chr; return visibleIChars(buf, 1); } const char * visibleEventType(int type) { const char *result = "?"; switch (type) { CASETYPE(KeyPress); CASETYPE(KeyRelease); CASETYPE(ButtonPress); CASETYPE(ButtonRelease); CASETYPE(MotionNotify); CASETYPE(EnterNotify); CASETYPE(LeaveNotify); CASETYPE(FocusIn); CASETYPE(FocusOut); CASETYPE(KeymapNotify); CASETYPE(Expose); CASETYPE(GraphicsExpose); CASETYPE(NoExpose); CASETYPE(VisibilityNotify); CASETYPE(CreateNotify); CASETYPE(DestroyNotify); CASETYPE(UnmapNotify); CASETYPE(MapNotify); CASETYPE(MapRequest); CASETYPE(ReparentNotify); CASETYPE(ConfigureNotify); CASETYPE(ConfigureRequest); CASETYPE(GravityNotify); CASETYPE(ResizeRequest); CASETYPE(CirculateNotify); CASETYPE(CirculateRequest); CASETYPE(PropertyNotify); CASETYPE(SelectionClear); CASETYPE(SelectionRequest); CASETYPE(SelectionNotify); CASETYPE(ColormapNotify); CASETYPE(ClientMessage); CASETYPE(MappingNotify); } return result; } const char * visibleNotifyMode(int code) { const char *result = "?"; switch (code) { CASETYPE(NotifyNormal); CASETYPE(NotifyGrab); CASETYPE(NotifyUngrab); CASETYPE(NotifyWhileGrabbed); } return result; } const char * visibleNotifyDetail(int code) { const char *result = "?"; switch (code) { CASETYPE(NotifyAncestor); CASETYPE(NotifyVirtual); CASETYPE(NotifyInferior); CASETYPE(NotifyNonlinear); CASETYPE(NotifyNonlinearVirtual); CASETYPE(NotifyPointer); CASETYPE(NotifyPointerRoot); CASETYPE(NotifyDetailNone); } return result; } const char * visibleSelectionTarget(Display *d, Atom a) { const char *result = "?"; if (a == XA_STRING) { result = "XA_STRING"; } else if (a == XA_TEXT(d)) { result = "XA_TEXT()"; } else if (a == XA_COMPOUND_TEXT(d)) { result = "XA_COMPOUND_TEXT()"; } else if (a == XA_UTF8_STRING(d)) { result = "XA_UTF8_STRING()"; } else if (a == XA_TARGETS(d)) { result = "XA_TARGETS()"; } return result; } const char * visibleTekparse(int code) { static const struct { int code; const char *name; } table[] = { #include "Tekparse.cin" }; const char *result = "?"; Cardinal n; for (n = 0; n < XtNumber(table); ++n) { if (table[n].code == code) { result = table[n].name; break; } } return result; } const char * visibleVTparse(int code) { static const struct { int code; const char *name; } table[] = { #include "VTparse.cin" }; const char *result = "?"; Cardinal n; for (n = 0; n < XtNumber(table); ++n) { if (table[n].code == code) { result = table[n].name; break; } } return result; } const char * visibleXError(int code) { static char temp[80]; const char *result = "?"; switch (code) { CASETYPE(Success); CASETYPE(BadRequest); CASETYPE(BadValue); CASETYPE(BadWindow); CASETYPE(BadPixmap); CASETYPE(BadAtom); CASETYPE(BadCursor); CASETYPE(BadFont); CASETYPE(BadMatch); CASETYPE(BadDrawable); CASETYPE(BadAccess); CASETYPE(BadAlloc); CASETYPE(BadColor); CASETYPE(BadGC); CASETYPE(BadIDChoice); CASETYPE(BadName); CASETYPE(BadLength); CASETYPE(BadImplementation); default: sprintf(temp, "%d", code); result = temp; break; } return result; } #if OPT_TRACE_FLAGS #define isScrnFlag(flag) ((flag) == LINEWRAPPED) static char * ScrnText(LineData *ld) { return visibleIChars(ld->charData, ld->lineSize); } #define SHOW_BAD_LINE(name, ld) \ Trace("OOPS " #name " bad row\n") #define SHOW_SCRN_FLAG(name,code) \ Trace(#name " %s:%s\n", \ code ? "*" : "", \ ScrnText(ld)) void LineClrFlag(LineData *ld, int flag) { if (ld == 0) { SHOW_BAD_LINE(LineClrFlag, ld); assert(0); } else if (isScrnFlag(flag)) { SHOW_SCRN_FLAG(LineClrFlag, 0); } LineFlags(ld) &= ~flag; } void LineSetFlag(LineData *ld, int flag) { if (ld == 0) { SHOW_BAD_LINE(LineSetFlag, ld); assert(0); } else if (isScrnFlag(flag)) { SHOW_SCRN_FLAG(LineSetFlag, 1); } LineFlags(ld) |= flag; } int LineTstFlag(LineData ld, int flag) { int code = 0; if (ld == 0) { SHOW_BAD_LINE(LineTstFlag, ld); } else { code = LineFlags(ld); if (isScrnFlag(flag)) { SHOW_SCRN_FLAG(LineTstFlag, code); } } return code; } #endif /* OPT_TRACE_FLAGS */ /* * Trace the normal or alternate screen, showing color values up to 16, e.g., * for debugging with vttest. */ void TraceScreen(XtermWidget xw, int whichBuf) { TScreen *screen = TScreenOf(xw); if (screen->editBuf_index[whichBuf]) { int row; TRACE(("TraceScreen %d:\n", whichBuf)); for (row = 0; row <= screen->max_row; ++row) { LineData *ld = getLineData(screen, row); TRACE((" %3d:", row)); if (ld != 0) { int col; for (col = 0; col < ld->lineSize; ++col) { int ch = (int) ld->charData[col]; if (ch < ' ') ch = ' '; if (ch >= 127) ch = '#'; TRACE(("%c", ch)); } TRACE((":\n")); TRACE((" xx:")); for (col = 0; col < ld->lineSize; ++col) { unsigned attrs = ld->attribs[col]; char ch; if (attrs & PROTECTED) { ch = '*'; } else if (attrs & BLINK) { ch = 'B'; } else if (attrs & CHARDRAWN) { ch = '+'; } else { ch = ' '; } TRACE(("%c", ch)); } TRACE((":\n")); #if 0 TRACE((" fg:")); for (col = 0; col < ld->lineSize; ++col) { unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]); if (fg > 15) fg = 15; TRACE(("%1x", fg)); } TRACE((":\n")); TRACE((" bg:")); for (col = 0; col < ld->lineSize; ++col) { unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]); if (bg > 15) bg = 15; TRACE(("%1x", bg)); } TRACE((":\n")); #endif } else { TRACE(("null lineData\n")); } } } else { TRACE(("TraceScreen %d is nil\n", whichBuf)); } } void TraceFocus(Widget w, XEvent *ev) { TRACE(("trace_focus event type %d:%s\n", ev->type, visibleEventType(ev->type))); switch (ev->type) { case FocusIn: case FocusOut: { XFocusChangeEvent *event = (XFocusChangeEvent *) ev; TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail))); TRACE(("\tmode: %s\n", visibleNotifyMode(event->mode))); TRACE(("\twindow: %#lx\n", event->window)); } break; case EnterNotify: case LeaveNotify: { XCrossingEvent *event = (XCrossingEvent *) ev; TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail))); TRACE(("\tmode: %s\n", visibleNotifyMode(event->mode))); TRACE(("\twindow: %#lx\n", event->window)); TRACE(("\tfocus: %d\n", event->focus)); TRACE(("\troot: %#lx\n", event->root)); TRACE(("\tsubwindow: %#lx\n", event->subwindow)); } break; } while (w != 0) { TRACE(("w %p -> %#lx\n", (void *) w, XtWindow(w))); w = XtParent(w); } } void TraceSizeHints(XSizeHints * hints) { TRACE(("size hints:\n")); if (hints->flags & (USPosition | PPosition)) TRACE((" position %d,%d%s%s\n", hints->y, hints->x, (hints->flags & USPosition) ? " user" : "", (hints->flags & PPosition) ? " prog" : "")); if (hints->flags & (USSize | PSize)) TRACE((" size %d,%d%s%s\n", hints->height, hints->width, (hints->flags & USSize) ? " user" : "", (hints->flags & PSize) ? " prog" : "")); if (hints->flags & PMinSize) TRACE((" min %d,%d\n", hints->min_height, hints->min_width)); if (hints->flags & PMaxSize) TRACE((" max %d,%d\n", hints->max_height, hints->max_width)); if (hints->flags & PResizeInc) TRACE((" inc %d,%d\n", hints->height_inc, hints->width_inc)); else TRACE((" inc NONE!\n")); if (hints->flags & PAspect) TRACE((" min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y)); if (hints->flags & PAspect) TRACE((" max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y)); if (hints->flags & PBaseSize) TRACE((" base %d,%d\n", hints->base_height, hints->base_width)); if (hints->flags & PWinGravity) TRACE((" gravity %d\n", hints->win_gravity)); } static void TraceEventMask(const char *tag, long mask) { #define DATA(name) { name##Mask, #name } /* *INDENT-OFF* */ static struct { long mask; const char *name; } table[] = { DATA(KeyPress), DATA(KeyRelease), DATA(ButtonPress), DATA(ButtonRelease), DATA(EnterWindow), DATA(LeaveWindow), DATA(PointerMotion), DATA(PointerMotionHint), DATA(Button1Motion), DATA(Button2Motion), DATA(Button3Motion), DATA(Button4Motion), DATA(Button5Motion), DATA(ButtonMotion), DATA(KeymapState), DATA(Exposure), DATA(VisibilityChange), DATA(StructureNotify), DATA(ResizeRedirect), DATA(SubstructureNotify), DATA(SubstructureRedirect), DATA(FocusChange), DATA(PropertyChange), DATA(ColormapChange), DATA(OwnerGrabButton), }; #undef DATA Cardinal n; /* *INDENT-ON* */ for (n = 0; n < XtNumber(table); ++n) { if (table[n].mask & mask) { TRACE(("%s %s\n", tag, table[n].name)); } } } void TraceWindowAttributes(XWindowAttributes * attrs) { TRACE(("window attributes:\n")); TRACE((" position %d,%d\n", attrs->y, attrs->x)); TRACE((" size %dx%d\n", attrs->height, attrs->width)); TRACE((" border %d\n", attrs->border_width)); TRACE((" depth %d\n", attrs->depth)); TRACE((" bit_gravity %d\n", attrs->bit_gravity)); TRACE((" win_gravity %d\n", attrs->win_gravity)); TRACE((" root %#lx\n", (long) attrs->root)); TRACE((" class %s\n", ((attrs->class == InputOutput) ? "InputOutput" : ((attrs->class == InputOnly) ? "InputOnly" : "unknown")))); TRACE((" map_state %s\n", ((attrs->map_state == IsUnmapped) ? "IsUnmapped" : ((attrs->map_state == IsUnviewable) ? "IsUnviewable" : ((attrs->map_state == IsViewable) ? "IsViewable" : "unknown"))))); TRACE((" all_events\n")); TraceEventMask(" ", attrs->all_event_masks); TRACE((" your_events\n")); TraceEventMask(" ", attrs->your_event_mask); TRACE((" no_propagate\n")); TraceEventMask(" ", attrs->do_not_propagate_mask); } void TraceWMSizeHints(XtermWidget xw) { XSizeHints sizehints = xw->hints; getXtermSizeHints(xw); TraceSizeHints(&xw->hints); xw->hints = sizehints; } /* * Some calls to XGetAtom() will fail, and we don't want to stop. So we use * our own error-handler. */ /* ARGSUSED */ static int no_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) { return 1; } const char * ModifierName(unsigned modifier) { const char *s = ""; if (modifier & ShiftMask) s = " Shift"; else if (modifier & LockMask) s = " Lock"; else if (modifier & ControlMask) s = " Control"; else if (modifier & Mod1Mask) s = " Mod1"; else if (modifier & Mod2Mask) s = " Mod2"; else if (modifier & Mod3Mask) s = " Mod3"; else if (modifier & Mod4Mask) s = " Mod4"; else if (modifier & Mod5Mask) s = " Mod5"; return s; } void TraceTranslations(const char *name, Widget w) { String result; XErrorHandler save = XSetErrorHandler(no_error); XtTranslations xlations; Widget xcelerat; TRACE(("TraceTranslations for %s (widget %#lx) {{\n", name, (long) w)); if (w) { XtVaGetValues(w, XtNtranslations, &xlations, XtNaccelerators, &xcelerat, (XtPointer) 0); TRACE(("... xlations %#08lx\n", (long) xlations)); TRACE(("... xcelerat %#08lx\n", (long) xcelerat)); result = _XtPrintXlations(w, xlations, xcelerat, True); TRACE(("%s\n", NonNull(result))); if (result) XFree((char *) result); } else { TRACE(("none (widget is null)\n")); } TRACE(("}}\n")); XSetErrorHandler(save); } XtGeometryResult TraceResizeRequest(const char *fn, int ln, Widget w, unsigned reqwide, unsigned reqhigh, Dimension *gotwide, Dimension *gothigh) { XtGeometryResult rc; TRACE(("%s@%d ResizeRequest %ux%u\n", fn, ln, reqhigh, reqwide)); rc = XtMakeResizeRequest((Widget) w, (Dimension) reqwide, (Dimension) reqhigh, gotwide, gothigh); TRACE(("... ResizeRequest -> ")); if (gothigh && gotwide) TRACE(("%dx%d ", *gothigh, *gotwide)); TRACE(("(%d)\n", rc)); return rc; } #define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name)) #define XRES_B(name) Trace(#name " = %s\n", MtoS(resp->name)) #define XRES_I(name) Trace(#name " = %d\n", resp->name) void TraceXtermResources(void) { XTERM_RESOURCE *resp = &resource; Trace("XTERM_RESOURCE settings:\n"); XRES_S(icon_geometry); XRES_S(title); XRES_S(icon_hint); XRES_S(icon_name); XRES_S(term_name); XRES_S(tty_modes); XRES_I(minBufSize); XRES_I(maxBufSize); XRES_B(hold_screen); XRES_B(utmpInhibit); XRES_B(utmpDisplayId); XRES_B(messages); XRES_S(menuLocale); XRES_S(omitTranslation); XRES_S(keyboardType); #if OPT_PRINT_ON_EXIT XRES_I(printModeNow); XRES_I(printModeOnXError); XRES_I(printOptsNow); XRES_I(printOptsOnXError); XRES_S(printFileNow); XRES_S(printFileOnXError); #endif #if OPT_SUNPC_KBD XRES_B(sunKeyboard); #endif #if OPT_HP_FUNC_KEYS XRES_B(hpFunctionKeys); #endif #if OPT_SCO_FUNC_KEYS XRES_B(scoFunctionKeys); #endif #if OPT_SUN_FUNC_KEYS XRES_B(sunFunctionKeys); #endif #if OPT_INITIAL_ERASE XRES_B(ptyInitialErase); XRES_B(backarrow_is_erase); #endif XRES_B(useInsertMode); #if OPT_ZICONBEEP XRES_I(zIconBeep); XRES_S(zIconFormat); #endif #if OPT_PTY_HANDSHAKE XRES_B(wait_for_map); XRES_B(ptyHandshake); XRES_B(ptySttySize); #endif #if OPT_REPORT_COLORS XRES_B(reportColors); #endif #if OPT_REPORT_FONTS XRES_B(reportFonts); #endif #if OPT_SAME_NAME XRES_B(sameName); #endif #if OPT_SESSION_MGT XRES_B(sessionMgt); #endif #if OPT_TOOLBAR XRES_B(toolBar); #endif #if OPT_MAXIMIZE XRES_B(maximized); XRES_S(fullscreen_s); #endif } void TraceArgv(const char *tag, char **argv) { int n = 0; TRACE(("%s:\n", tag)); while (*argv != 0) { TRACE((" %d:%s\n", n++, *argv++)); } } static char * parse_option(char *dst, String src, int first) { char *s; if (!strncmp(src, "-/+", (size_t) 3)) { dst[0] = (char) first; strcpy(dst + 1, src + 3); } else { strcpy(dst, src); } for (s = dst; *s != '\0'; s++) { if (*s == '#' || *s == '%' || *s == 'S') { s[1] = '\0'; } else if (*s == ' ') { *s = '\0'; break; } } return dst; } static Bool same_option(OptionHelp * opt, XrmOptionDescRec * res) { char temp[BUFSIZ]; return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option); } static Bool standard_option(String opt) { static const char *table[] = { "+rv", "+synchronous", "-background", "-bd", "-bg", "-bordercolor", "-borderwidth", "-bw", "-display", "-fg", "-fn", "-font", "-foreground", "-geometry", "-iconic", "-name", "-reverse", "-rv", "-selectionTimeout", "-synchronous", "-title", "-xnllanguage", "-xrm", "-xtsessionID", }; Cardinal n; char temp[BUFSIZ]; opt = parse_option(temp, opt, '-'); for (n = 0; n < XtNumber(table); n++) { if (!strcmp(opt, table[n])) return True; } return False; } /* * Analyse the options/help messages for inconsistencies. */ void TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count) { OptionHelp *opt_array = sortedOpts(options, resources, res_count); size_t j, k; XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count); Bool first, found; TRACE(("Checking options-tables for inconsistencies:\n")); #if 0 TRACE(("Options listed in help-message:\n")); for (j = 0; options[j].opt != 0; j++) TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc)); TRACE(("Options listed in resource-table:\n")); for (j = 0; j < res_count; j++) TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier)); #endif /* list all options[] not found in resources[] */ for (j = 0, first = True; options[j].opt != 0; j++) { found = False; for (k = 0; k < res_count; k++) { if (same_option(&opt_array[j], &res_array[k])) { found = True; break; } } if (!found) { if (first) { TRACE(("Options listed in help, not found in resource list:\n")); first = False; } TRACE((" %-28s%s\n", opt_array[j].opt, standard_option(opt_array[j].opt) ? " (standard)" : "")); } } /* list all resources[] not found in options[] */ for (j = 0, first = True; j < res_count; j++) { found = False; for (k = 0; options[k].opt != 0; k++) { if (same_option(&opt_array[k], &res_array[j])) { found = True; break; } } if (!found) { if (first) { TRACE(("Resource list items not found in options-help:\n")); first = False; } TRACE((" %s\n", res_array[j].option)); } } TRACE(("Resource list items that will be ignored by XtOpenApplication:\n")); for (j = 0; j < res_count; j++) { switch (res_array[j].argKind) { case XrmoptionSkipArg: TRACE((" %-28s {param}\n", res_array[j].option)); break; case XrmoptionSkipNArgs: TRACE((" %-28s {%ld params}\n", res_array[j].option, (long) res_array[j].value)); break; case XrmoptionSkipLine: TRACE((" %-28s {remainder of line}\n", res_array[j].option)); break; case XrmoptionIsArg: case XrmoptionNoArg: case XrmoptionResArg: case XrmoptionSepArg: case XrmoptionStickyArg: default: break; } } } #else extern void empty_trace(void); void empty_trace(void) { } #endif