trace.c revision 2eaa94a1
1/* $XTermId: trace.c,v 1.85 2008/06/03 20:52:34 tom Exp $ */ 2 3/************************************************************ 4 5Copyright 1997-2007,2008 by Thomas E. Dickey 6 7 All Rights Reserved 8 9Permission to use, copy, modify, and distribute this software and its 10documentation for any purpose and without fee is hereby granted, 11provided that the above copyright notice appear in all copies and that 12both that copyright notice and this permission notice appear in 13supporting documentation, and that the name of the above listed 14copyright holder(s) not be used in advertising or publicity pertaining 15to distribution of the software without specific, written prior 16permission. 17 18THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD 19TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 20AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE 21LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 26********************************************************/ 27 28/* 29 * debugging support via TRACE macro. 30 */ 31 32#include <xterm.h> /* for definition of GCC_UNUSED */ 33#include <data.h> 34#include <trace.h> 35 36#include <time.h> 37#include <stdlib.h> 38#include <unistd.h> 39#include <sys/types.h> 40#include <stdio.h> 41#include <stdarg.h> 42#include <assert.h> 43 44#ifdef HAVE_X11_TRANSLATEI_H 45#include <X11/TranslateI.h> 46#else 47#ifdef __cplusplus 48extern "C" { 49#endif 50 51 extern String _XtPrintXlations(Widget w, 52 XtTranslations xlations, 53 Widget accelWidget, 54 _XtBoolean includeRHS); 55#ifdef __cplusplus 56} 57#endif 58#endif 59char *trace_who = "parent"; 60 61void 62Trace(const char *fmt,...) 63{ 64 static FILE *fp; 65 static char *trace_out; 66 va_list ap; 67 68 if (fp != 0 69 && trace_who != trace_out) { 70 fclose(fp); 71 fp = 0; 72 } 73 trace_out = trace_who; 74 75 if (!fp) { 76 char name[BUFSIZ]; 77#if 0 /* usually I do not want unique names */ 78 int unique; 79 for (unique = 0;; ++unique) { 80 if (unique) 81 sprintf(name, "Trace-%s.out-%d", trace_who, unique); 82 else 83 sprintf(name, "Trace-%s.out", trace_who); 84 if ((fp = fopen(name, "r")) == 0) { 85 break; 86 } 87 fclose(fp); 88 } 89#else 90 sprintf(name, "Trace-%s.out", trace_who); 91#endif 92 fp = fopen(name, "w"); 93 if (fp != 0) { 94 fprintf(fp, "%s\n", xtermVersion()); 95 TraceIds(NULL, 0); 96 } 97 } 98 if (!fp) 99 abort(); 100 101 va_start(ap, fmt); 102 if (fmt != 0) { 103 vfprintf(fp, fmt, ap); 104 (void) fflush(fp); 105 } else { 106 (void) fclose(fp); 107 (void) fflush(stdout); 108 (void) fflush(stderr); 109 } 110 va_end(ap); 111} 112 113void 114TraceIds(const char *fname, int lnum) 115{ 116 Trace("process %d ", (int) getpid()); 117#ifdef HAVE_UNISTD_H 118 Trace("real (%u/%u) effective (%u/%u)", 119 (unsigned) getuid(), (unsigned) getgid(), 120 (unsigned) geteuid(), (unsigned) getegid()); 121#endif 122 if (fname != 0) { 123 Trace(" (%s@%d)\n", fname, lnum); 124 } else { 125 time_t now = time((time_t *) 0); 126 Trace("-- %s", ctime(&now)); 127 } 128} 129 130static void 131formatAscii(char *dst, unsigned value) 132{ 133 switch (value) { 134 case '\\': 135 sprintf(dst, "\\\\"); 136 break; 137 case '\b': 138 sprintf(dst, "\\b"); 139 break; 140 case '\n': 141 sprintf(dst, "\\n"); 142 break; 143 case '\r': 144 sprintf(dst, "\\r"); 145 break; 146 case '\t': 147 sprintf(dst, "\\t"); 148 break; 149 default: 150 if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160)) 151 sprintf(dst, "\\%03o", value); 152 else 153 sprintf(dst, "%c", CharOf(value)); 154 break; 155 } 156} 157 158#if OPT_DEC_CHRSET 159 160const char * 161visibleChrsetName(int chrset) 162{ 163 const char *result = "?"; 164 switch (chrset) { 165 case CSET_SWL: 166 result = "CSET_SWL"; 167 break; 168 case CSET_DHL_TOP: 169 result = "CSET_DHL_TOP"; 170 break; 171 case CSET_DHL_BOT: 172 result = "CSET_DHL_BOT"; 173 break; 174 case CSET_DWL: 175 result = "CSET_DWL"; 176 break; 177 } 178 return result; 179} 180#endif 181 182char * 183visibleChars(PAIRED_CHARS(Char * buf, Char * buf2), unsigned len) 184{ 185 static char *result; 186 static unsigned used; 187 unsigned limit = ((len + 1) * 8) + 1; 188 char *dst; 189 190 if (limit > used) { 191 used = limit; 192 result = XtRealloc(result, used); 193 } 194 dst = result; 195 *dst = '\0'; 196 while (len--) { 197 unsigned value = *buf++; 198#if OPT_WIDE_CHARS 199 if (buf2 != 0) { 200 value |= (*buf2 << 8); 201 buf2++; 202 } 203 if (value > 255) 204 sprintf(dst, "\\u+%04X", value); 205 else 206#endif 207 formatAscii(dst, value); 208 dst += strlen(dst); 209 } 210 return result; 211} 212 213char * 214visibleIChar(IChar * buf, unsigned len) 215{ 216 static char *result; 217 static unsigned used; 218 unsigned limit = ((len + 1) * 6) + 1; 219 char *dst; 220 221 if (limit > used) { 222 used = limit; 223 result = XtRealloc(result, used); 224 } 225 dst = result; 226 while (len--) { 227 unsigned value = *buf++; 228#if OPT_WIDE_CHARS 229 if (value > 255) 230 sprintf(dst, "\\u+%04X", value); 231 else 232#endif 233 formatAscii(dst, value); 234 dst += strlen(dst); 235 } 236 return result; 237} 238 239#define CASETYPE(name) case name: result = #name; break; 240 241const char * 242visibleKeyboardType(xtermKeyboardType type) 243{ 244 const char *result = "?"; 245 switch (type) { 246 CASETYPE(keyboardIsLegacy); /* bogus vt220 codes for F1-F4, etc. */ 247 CASETYPE(keyboardIsDefault); 248 CASETYPE(keyboardIsHP); 249 CASETYPE(keyboardIsSCO); 250 CASETYPE(keyboardIsSun); 251 CASETYPE(keyboardIsTermcap); 252 CASETYPE(keyboardIsVT220); 253 } 254 return result; 255} 256 257const char * 258visibleEventType(int type) 259{ 260 const char *result = "?"; 261 switch (type) { 262 CASETYPE(KeyPress); 263 CASETYPE(KeyRelease); 264 CASETYPE(ButtonPress); 265 CASETYPE(ButtonRelease); 266 CASETYPE(MotionNotify); 267 CASETYPE(EnterNotify); 268 CASETYPE(LeaveNotify); 269 CASETYPE(FocusIn); 270 CASETYPE(FocusOut); 271 CASETYPE(KeymapNotify); 272 CASETYPE(Expose); 273 CASETYPE(GraphicsExpose); 274 CASETYPE(NoExpose); 275 CASETYPE(VisibilityNotify); 276 CASETYPE(CreateNotify); 277 CASETYPE(DestroyNotify); 278 CASETYPE(UnmapNotify); 279 CASETYPE(MapNotify); 280 CASETYPE(MapRequest); 281 CASETYPE(ReparentNotify); 282 CASETYPE(ConfigureNotify); 283 CASETYPE(ConfigureRequest); 284 CASETYPE(GravityNotify); 285 CASETYPE(ResizeRequest); 286 CASETYPE(CirculateNotify); 287 CASETYPE(CirculateRequest); 288 CASETYPE(PropertyNotify); 289 CASETYPE(SelectionClear); 290 CASETYPE(SelectionRequest); 291 CASETYPE(SelectionNotify); 292 CASETYPE(ColormapNotify); 293 CASETYPE(ClientMessage); 294 CASETYPE(MappingNotify); 295 } 296 return result; 297} 298 299const char * 300visibleXError(int code) 301{ 302 static char temp[80]; 303 const char *result = "?"; 304 switch (code) { 305 CASETYPE(Success); 306 CASETYPE(BadRequest); 307 CASETYPE(BadValue); 308 CASETYPE(BadWindow); 309 CASETYPE(BadPixmap); 310 CASETYPE(BadAtom); 311 CASETYPE(BadCursor); 312 CASETYPE(BadFont); 313 CASETYPE(BadMatch); 314 CASETYPE(BadDrawable); 315 CASETYPE(BadAccess); 316 CASETYPE(BadAlloc); 317 CASETYPE(BadColor); 318 CASETYPE(BadGC); 319 CASETYPE(BadIDChoice); 320 CASETYPE(BadName); 321 CASETYPE(BadLength); 322 CASETYPE(BadImplementation); 323 default: 324 sprintf(temp, "%d", code); 325 result = temp; 326 break; 327 } 328 return result; 329} 330 331#if OPT_TRACE_FLAGS 332#define isScrnFlag(flag) ((flag) == LINEWRAPPED) 333 334static char * 335ScrnText(TScreen * screen, int row) 336{ 337 Char *chars = SCRN_BUF_CHARS(screen, row); 338#if OPT_WIDE_CHARS 339 Char *widec = 0; 340#endif 341 342 if_OPT_WIDE_CHARS(screen, { 343 widec = SCRN_BUF_WIDEC(screen, row); 344 }); 345 return visibleChars(PAIRED_CHARS(chars, widec), screen->max_col + 1); 346} 347 348#if OPT_TRACE_FLAGS > 1 349#define DETAILED_FLAGS(name) \ 350 Trace("TEST " #name " %d [%d..%d] top %d chars %p (%d)\n", \ 351 row, \ 352 -screen->savedlines, \ 353 screen->max_row, \ 354 screen->topline, \ 355 SCRN_BUF_CHARS(screen, row), \ 356 (&(SCRN_BUF_FLAGS(screen, row)) - screen->visbuf) / MAX_PTRS) 357#else 358#define DETAILED_FLAGS(name) /* nothing */ 359#endif 360 361#define SHOW_BAD_ROW(name, screen, row) \ 362 Trace("OOPS " #name " bad row %d [%d..%d]\n", \ 363 row, -(screen->savedlines), screen->max_row) 364 365#define SHOW_SCRN_FLAG(name,code) \ 366 Trace(#name " {%d, top=%d, saved=%d}%05d%s:%s\n", \ 367 row, screen->topline, screen->savedlines, \ 368 ROW2ABS(screen, row), \ 369 code ? "*" : "", \ 370 ScrnText(screen, row)) 371 372void 373ScrnClrFlag(TScreen * screen, int row, int flag) 374{ 375 DETAILED_FLAGS(ScrnClrFlag); 376 if (!okScrnRow(screen, row)) { 377 SHOW_BAD_ROW(ScrnClrFlag, screen, row); 378 assert(0); 379 } else if (isScrnFlag(flag)) { 380 SHOW_SCRN_FLAG(ScrnClrFlag, 0); 381 } 382 383 SCRN_BUF_FLAGS(screen, row) = 384 (Char *) ((long) SCRN_BUF_FLAGS(screen, row) & ~(flag)); 385} 386 387void 388ScrnSetFlag(TScreen * screen, int row, int flag) 389{ 390 DETAILED_FLAGS(ScrnSetFlag); 391 if (!okScrnRow(screen, row)) { 392 SHOW_BAD_ROW(ScrnSetFlag, screen, row); 393 assert(0); 394 } else if (isScrnFlag(flag)) { 395 SHOW_SCRN_FLAG(ScrnSetFlag, 1); 396 } 397 398 SCRN_BUF_FLAGS(screen, row) = 399 (Char *) (((long) SCRN_BUF_FLAGS(screen, row) | (flag))); 400} 401 402int 403ScrnTstFlag(TScreen * screen, int row, int flag) 404{ 405 int code = 0; 406 if (!okScrnRow(screen, row)) { 407 SHOW_BAD_ROW(ScrnTstFlag, screen, row); 408 } else { 409 code = ((long) SCRN_BUF_FLAGS(screen, row) & (flag)) != 0; 410 411 DETAILED_FLAGS(ScrnTstFlag); 412 if (!okScrnRow(screen, row)) { 413 SHOW_BAD_ROW(ScrnSetFlag, screen, row); 414 assert(0); 415 } else if (isScrnFlag(flag)) { 416 SHOW_SCRN_FLAG(ScrnTstFlag, code); 417 } 418 } 419 return code; 420} 421#endif /* OPT_TRACE_FLAGS */ 422 423void 424TraceSizeHints(XSizeHints * hints) 425{ 426 TRACE(("size hints:\n")); 427 if (hints->flags & (USPosition | PPosition)) 428 TRACE((" position %d,%d%s%s\n", hints->y, hints->x, 429 hints->flags & USPosition ? " user" : "", 430 hints->flags & PPosition ? " prog" : "")); 431 if (hints->flags & (USSize | PSize)) 432 TRACE((" size %d,%d%s%s\n", hints->height, hints->width, 433 hints->flags & USSize ? " user" : "", 434 hints->flags & PSize ? " prog" : "")); 435 if (hints->flags & PMinSize) 436 TRACE((" min %d,%d\n", hints->min_height, hints->min_width)); 437 if (hints->flags & PMaxSize) 438 TRACE((" max %d,%d\n", hints->max_height, hints->max_width)); 439 if (hints->flags & PResizeInc) 440 TRACE((" inc %d,%d\n", hints->height_inc, hints->width_inc)); 441 else 442 TRACE((" inc NONE!\n")); 443 if (hints->flags & PAspect) 444 TRACE((" min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y)); 445 if (hints->flags & PAspect) 446 TRACE((" max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y)); 447 if (hints->flags & PBaseSize) 448 TRACE((" base %d,%d\n", hints->base_height, hints->base_width)); 449 if (hints->flags & PWinGravity) 450 TRACE((" gravity %d\n", hints->win_gravity)); 451} 452 453void 454TraceWMSizeHints(XtermWidget xw) 455{ 456 XSizeHints sizehints = xw->hints; 457 458 getXtermSizeHints(xw); 459 TraceSizeHints(&xw->hints); 460 xw->hints = sizehints; 461} 462 463/* 464 * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 465 * our own error-handler. 466 */ 467static int 468no_error(Display * dpy GCC_UNUSED, XErrorEvent * event GCC_UNUSED) 469{ 470 return 1; 471} 472 473void 474TraceTranslations(const char *name, Widget w) 475{ 476 String result; 477 XErrorHandler save = XSetErrorHandler(no_error); 478 XtTranslations xlations; 479 Widget xcelerat; 480 481 TRACE(("TraceTranslations for %s (widget %#lx)\n", name, (long) w)); 482 if (w) { 483 XtVaGetValues(w, 484 XtNtranslations, &xlations, 485 XtNaccelerators, &xcelerat, 486 (XtPointer) 0); 487 TRACE(("... xlations %#08lx\n", (long) xlations)); 488 TRACE(("... xcelerat %#08lx\n", (long) xcelerat)); 489 result = _XtPrintXlations(w, xlations, xcelerat, True); 490 TRACE(("%s\n", result != 0 ? result : "(null)")); 491 if (result) 492 XFree(result); 493 } else { 494 TRACE(("none (widget is null)\n")); 495 } 496 XSetErrorHandler(save); 497} 498 499int 500TraceResizeRequest(const char *fn, int ln, Widget w, 501 Dimension reqwide, 502 Dimension reqhigh, 503 Dimension * gotwide, 504 Dimension * gothigh) 505{ 506 int rc; 507 508 TRACE(("%s@%d ResizeRequest %dx%d\n", fn, ln, reqhigh, reqwide)); 509 rc = XtMakeResizeRequest((Widget) w, reqwide, reqhigh, gotwide, gothigh); 510 TRACE(("... ResizeRequest -> ")); 511 if (gothigh && gotwide) 512 TRACE(("%dx%d ", *gothigh, *gotwide)); 513 TRACE(("(%d)\n", rc)); 514 return rc; 515} 516 517#define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name)) 518#define XRES_B(name) Trace(#name " = %s\n", BtoS(resp->name)) 519#define XRES_I(name) Trace(#name " = %d\n", resp->name) 520 521void 522TraceXtermResources(void) 523{ 524 XTERM_RESOURCE *resp = &resource; 525 526 Trace("XTERM_RESOURCE settings:\n"); 527 XRES_S(xterm_name); 528 XRES_S(icon_geometry); 529 XRES_S(title); 530 XRES_S(icon_name); 531 XRES_S(term_name); 532 XRES_S(tty_modes); 533 XRES_B(hold_screen); 534 XRES_B(utmpInhibit); 535 XRES_B(utmpDisplayId); 536 XRES_B(messages); 537#if OPT_SUNPC_KBD 538 XRES_B(sunKeyboard); 539#endif 540#if OPT_HP_FUNC_KEYS 541 XRES_B(hpFunctionKeys); 542#endif 543#if OPT_SCO_FUNC_KEYS 544 XRES_B(scoFunctionKeys); 545#endif 546#if OPT_SUN_FUNC_KEYS 547 XRES_B(sunFunctionKeys); 548#endif 549#if OPT_INITIAL_ERASE 550 XRES_B(ptyInitialErase); 551 XRES_B(backarrow_is_erase); 552#endif 553 XRES_B(useInsertMode); 554#if OPT_ZICONBEEP 555 XRES_I(zIconBeep); 556#endif 557#if OPT_PTY_HANDSHAKE 558 XRES_B(wait_for_map); 559 XRES_B(ptyHandshake); 560 XRES_B(ptySttySize); 561#endif 562#if OPT_SAME_NAME 563 XRES_B(sameName); 564#endif 565#if OPT_SESSION_MGT 566 XRES_B(sessionMgt); 567#endif 568} 569 570void 571TraceArgv(const char *tag, char **argv) 572{ 573 int n = 0; 574 575 TRACE(("%s:\n", tag)); 576 while (*argv != 0) { 577 TRACE((" %d:%s\n", n++, *argv++)); 578 } 579} 580 581static char * 582parse_option(char *dst, char *src, int first) 583{ 584 char *s; 585 586 if (!strncmp(src, "-/+", 3)) { 587 dst[0] = first; 588 strcpy(dst + 1, src + 3); 589 } else { 590 strcpy(dst, src); 591 } 592 for (s = dst; *s != '\0'; s++) { 593 if (*s == '#' || *s == '%' || *s == 'S') { 594 s[1] = '\0'; 595 } else if (*s == ' ') { 596 *s = '\0'; 597 break; 598 } 599 } 600 return dst; 601} 602 603static Bool 604same_option(OptionHelp * opt, XrmOptionDescRec * res) 605{ 606 char temp[BUFSIZ]; 607 return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option); 608} 609 610static Bool 611standard_option(char *opt) 612{ 613 static const char *table[] = 614 { 615 "+rv", 616 "+synchronous", 617 "-background", 618 "-bd", 619 "-bg", 620 "-bordercolor", 621 "-borderwidth", 622 "-bw", 623 "-display", 624 "-fg", 625 "-fn", 626 "-font", 627 "-foreground", 628 "-geometry", 629 "-iconic", 630 "-name", 631 "-reverse", 632 "-rv", 633 "-selectionTimeout", 634 "-synchronous", 635 "-title", 636 "-xnllanguage", 637 "-xrm", 638 "-xtsessionID", 639 }; 640 Cardinal n; 641 char temp[BUFSIZ]; 642 643 opt = parse_option(temp, opt, '-'); 644 for (n = 0; n < XtNumber(table); n++) { 645 if (!strcmp(opt, table[n])) 646 return True; 647 } 648 return False; 649} 650 651/* 652 * Analyse the options/help messages for inconsistencies. 653 */ 654void 655TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count) 656{ 657 OptionHelp *opt_array = sortedOpts(options, resources, res_count); 658 size_t j, k; 659 XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count); 660 Bool first, found; 661 662 TRACE(("Checking options-tables for inconsistencies:\n")); 663 664#if 0 665 TRACE(("Options listed in help-message:\n")); 666 for (j = 0; options[j].opt != 0; j++) 667 TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc)); 668 TRACE(("Options listed in resource-table:\n")); 669 for (j = 0; j < res_count; j++) 670 TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier)); 671#endif 672 673 /* list all options[] not found in resources[] */ 674 for (j = 0, first = True; options[j].opt != 0; j++) { 675 found = False; 676 for (k = 0; k < res_count; k++) { 677 if (same_option(&opt_array[j], &res_array[k])) { 678 found = True; 679 break; 680 } 681 } 682 if (!found) { 683 if (first) { 684 TRACE(("Options listed in help, not found in resource list:\n")); 685 first = False; 686 } 687 TRACE((" %-28s%s\n", opt_array[j].opt, 688 standard_option(opt_array[j].opt) ? " (standard)" : "")); 689 } 690 } 691 692 /* list all resources[] not found in options[] */ 693 for (j = 0, first = True; j < res_count; j++) { 694 found = False; 695 for (k = 0; options[k].opt != 0; k++) { 696 if (same_option(&opt_array[k], &res_array[j])) { 697 found = True; 698 break; 699 } 700 } 701 if (!found) { 702 if (first) { 703 TRACE(("Resource list items not found in options-help:\n")); 704 first = False; 705 } 706 TRACE((" %s\n", res_array[j].option)); 707 } 708 } 709 710 TRACE(("Resource list items that will be ignored by XtOpenApplication:\n")); 711 for (j = 0; j < res_count; j++) { 712 switch (res_array[j].argKind) { 713 case XrmoptionSkipArg: 714 TRACE((" %-28s {param}\n", res_array[j].option)); 715 break; 716 case XrmoptionSkipNArgs: 717 TRACE((" %-28s {%ld params}\n", res_array[j].option, (long) 718 res_array[j].value)); 719 break; 720 case XrmoptionSkipLine: 721 TRACE((" %-28s {remainder of line}\n", res_array[j].option)); 722 break; 723 case XrmoptionIsArg: 724 case XrmoptionNoArg: 725 case XrmoptionResArg: 726 case XrmoptionSepArg: 727 case XrmoptionStickyArg: 728 default: 729 break; 730 } 731 } 732} 733