trace.c revision d522f475
1/* $XTermId: trace.c,v 1.83 2007/12/31 20:58:29 tom Exp $ */ 2 3/************************************************************ 4 5Copyright 1997-2006,2007 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 if (hints->flags & PAspect) 442 TRACE((" min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y)); 443 if (hints->flags & PAspect) 444 TRACE((" max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y)); 445 if (hints->flags & PBaseSize) 446 TRACE((" base %d,%d\n", hints->base_height, hints->base_width)); 447 if (hints->flags & PWinGravity) 448 TRACE((" gravity %d\n", hints->win_gravity)); 449} 450 451void 452TraceWMSizeHints(XtermWidget xw) 453{ 454 XSizeHints sizehints = xw->hints; 455 456 getXtermSizeHints(xw); 457 TraceSizeHints(&xw->hints); 458 xw->hints = sizehints; 459} 460 461/* 462 * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 463 * our own error-handler. 464 */ 465static int 466no_error(Display * dpy GCC_UNUSED, XErrorEvent * event GCC_UNUSED) 467{ 468 return 1; 469} 470 471void 472TraceTranslations(const char *name, Widget w) 473{ 474 String result; 475 XErrorHandler save = XSetErrorHandler(no_error); 476 XtTranslations xlations; 477 Widget xcelerat; 478 479 TRACE(("TraceTranslations for %s (widget %#lx)\n", name, (long) w)); 480 if (w) { 481 XtVaGetValues(w, 482 XtNtranslations, &xlations, 483 XtNaccelerators, &xcelerat, 484 (XtPointer) 0); 485 TRACE(("... xlations %#08lx\n", (long) xlations)); 486 TRACE(("... xcelerat %#08lx\n", (long) xcelerat)); 487 result = _XtPrintXlations(w, xlations, xcelerat, True); 488 TRACE(("%s\n", result != 0 ? result : "(null)")); 489 if (result) 490 XFree(result); 491 } else { 492 TRACE(("none (widget is null)\n")); 493 } 494 XSetErrorHandler(save); 495} 496 497#define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name)) 498#define XRES_B(name) Trace(#name " = %s\n", BtoS(resp->name)) 499#define XRES_I(name) Trace(#name " = %d\n", resp->name) 500 501void 502TraceXtermResources(void) 503{ 504 XTERM_RESOURCE *resp = &resource; 505 506 Trace("XTERM_RESOURCE settings:\n"); 507 XRES_S(xterm_name); 508 XRES_S(icon_geometry); 509 XRES_S(title); 510 XRES_S(icon_name); 511 XRES_S(term_name); 512 XRES_S(tty_modes); 513 XRES_B(hold_screen); 514 XRES_B(utmpInhibit); 515 XRES_B(utmpDisplayId); 516 XRES_B(messages); 517#if OPT_SUNPC_KBD 518 XRES_B(sunKeyboard); 519#endif 520#if OPT_HP_FUNC_KEYS 521 XRES_B(hpFunctionKeys); 522#endif 523#if OPT_SCO_FUNC_KEYS 524 XRES_B(scoFunctionKeys); 525#endif 526#if OPT_SUN_FUNC_KEYS 527 XRES_B(sunFunctionKeys); 528#endif 529#if OPT_INITIAL_ERASE 530 XRES_B(ptyInitialErase); 531 XRES_B(backarrow_is_erase); 532#endif 533 XRES_B(useInsertMode); 534#if OPT_ZICONBEEP 535 XRES_I(zIconBeep); 536#endif 537#if OPT_PTY_HANDSHAKE 538 XRES_B(wait_for_map); 539 XRES_B(ptyHandshake); 540 XRES_B(ptySttySize); 541#endif 542#if OPT_SAME_NAME 543 XRES_B(sameName); 544#endif 545#if OPT_SESSION_MGT 546 XRES_B(sessionMgt); 547#endif 548} 549 550void 551TraceArgv(const char *tag, char **argv) 552{ 553 int n = 0; 554 555 TRACE(("%s:\n", tag)); 556 while (*argv != 0) { 557 TRACE((" %d:%s\n", n++, *argv++)); 558 } 559} 560 561static char * 562parse_option(char *dst, char *src, int first) 563{ 564 char *s; 565 566 if (!strncmp(src, "-/+", 3)) { 567 dst[0] = first; 568 strcpy(dst + 1, src + 3); 569 } else { 570 strcpy(dst, src); 571 } 572 for (s = dst; *s != '\0'; s++) { 573 if (*s == '#' || *s == '%' || *s == 'S') { 574 s[1] = '\0'; 575 } else if (*s == ' ') { 576 *s = '\0'; 577 break; 578 } 579 } 580 return dst; 581} 582 583static Bool 584same_option(OptionHelp * opt, XrmOptionDescRec * res) 585{ 586 char temp[BUFSIZ]; 587 return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option); 588} 589 590static Bool 591standard_option(char *opt) 592{ 593 static const char *table[] = 594 { 595 "+rv", 596 "+synchronous", 597 "-background", 598 "-bd", 599 "-bg", 600 "-bordercolor", 601 "-borderwidth", 602 "-bw", 603 "-display", 604 "-fg", 605 "-fn", 606 "-font", 607 "-foreground", 608 "-geometry", 609 "-iconic", 610 "-name", 611 "-reverse", 612 "-rv", 613 "-selectionTimeout", 614 "-synchronous", 615 "-title", 616 "-xnllanguage", 617 "-xrm", 618 "-xtsessionID", 619 }; 620 Cardinal n; 621 char temp[BUFSIZ]; 622 623 opt = parse_option(temp, opt, '-'); 624 for (n = 0; n < XtNumber(table); n++) { 625 if (!strcmp(opt, table[n])) 626 return True; 627 } 628 return False; 629} 630 631/* 632 * Analyse the options/help messages for inconsistencies. 633 */ 634void 635TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count) 636{ 637 OptionHelp *opt_array = sortedOpts(options, resources, res_count); 638 size_t j, k; 639 XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count); 640 Bool first, found; 641 642 TRACE(("Checking options-tables for inconsistencies:\n")); 643 644#if 0 645 TRACE(("Options listed in help-message:\n")); 646 for (j = 0; options[j].opt != 0; j++) 647 TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc)); 648 TRACE(("Options listed in resource-table:\n")); 649 for (j = 0; j < res_count; j++) 650 TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier)); 651#endif 652 653 /* list all options[] not found in resources[] */ 654 for (j = 0, first = True; options[j].opt != 0; j++) { 655 found = False; 656 for (k = 0; k < res_count; k++) { 657 if (same_option(&opt_array[j], &res_array[k])) { 658 found = True; 659 break; 660 } 661 } 662 if (!found) { 663 if (first) { 664 TRACE(("Options listed in help, not found in resource list:\n")); 665 first = False; 666 } 667 TRACE((" %-28s%s\n", opt_array[j].opt, 668 standard_option(opt_array[j].opt) ? " (standard)" : "")); 669 } 670 } 671 672 /* list all resources[] not found in options[] */ 673 for (j = 0, first = True; j < res_count; j++) { 674 found = False; 675 for (k = 0; options[k].opt != 0; k++) { 676 if (same_option(&opt_array[k], &res_array[j])) { 677 found = True; 678 break; 679 } 680 } 681 if (!found) { 682 if (first) { 683 TRACE(("Resource list items not found in options-help:\n")); 684 first = False; 685 } 686 TRACE((" %s\n", res_array[j].option)); 687 } 688 } 689 690 TRACE(("Resource list items that will be ignored by XtOpenApplication:\n")); 691 for (j = 0; j < res_count; j++) { 692 switch (res_array[j].argKind) { 693 case XrmoptionSkipArg: 694 TRACE((" %-28s {param}\n", res_array[j].option)); 695 break; 696 case XrmoptionSkipNArgs: 697 TRACE((" %-28s {%ld params}\n", res_array[j].option, (long) 698 res_array[j].value)); 699 break; 700 case XrmoptionSkipLine: 701 TRACE((" %-28s {remainder of line}\n", res_array[j].option)); 702 break; 703 case XrmoptionIsArg: 704 case XrmoptionNoArg: 705 case XrmoptionResArg: 706 case XrmoptionSepArg: 707 case XrmoptionStickyArg: 708 default: 709 break; 710 } 711 } 712} 713