| 1 | /* |
| 2 | * Copyright (c) 1983 Regents of the University of California. |
| 3 | * All rights reserved. The Berkeley software License Agreement |
| 4 | * specifies the terms and conditions for redistribution. |
| 5 | */ |
| 6 | |
| 7 | #ifndef lint |
| 8 | static char sccsid[] = "@(#)printsym.c 5.5 (Berkeley) %G%"; |
| 9 | #endif not lint |
| 10 | |
| 11 | static char rcsid[] = "$Header: printsym.c,v 1.4 87/04/15 00:23:35 donn Exp $"; |
| 12 | |
| 13 | /* |
| 14 | * Printing of symbolic information. |
| 15 | */ |
| 16 | |
| 17 | #include "defs.h" |
| 18 | #include "symbols.h" |
| 19 | #include "languages.h" |
| 20 | #include "printsym.h" |
| 21 | #include "tree.h" |
| 22 | #include "eval.h" |
| 23 | #include "mappings.h" |
| 24 | #include "process.h" |
| 25 | #include "runtime.h" |
| 26 | #include "machine.h" |
| 27 | #include "names.h" |
| 28 | #include "keywords.h" |
| 29 | #include "main.h" |
| 30 | #include <ctype.h> |
| 31 | |
| 32 | #ifndef public |
| 33 | #endif |
| 34 | |
| 35 | /* |
| 36 | * Maximum number of arguments to a function. |
| 37 | * This is used as a check for the possibility that the stack has been |
| 38 | * overwritten and therefore a saved argument pointer might indicate |
| 39 | * to an absurdly large number of arguments. |
| 40 | */ |
| 41 | |
| 42 | #define MAXARGSPASSED 20 |
| 43 | |
| 44 | /* |
| 45 | * Return a pointer to the string for the name of the class that |
| 46 | * the given symbol belongs to. |
| 47 | */ |
| 48 | |
| 49 | private String clname[] = { |
| 50 | "bad use", "constant", "type", "variable", "array", "array", |
| 51 | "dynarray", "subarray", "fileptr", "record", "field", |
| 52 | "procedure", "function", "funcvar", |
| 53 | "ref", "pointer", "file", "set", "range", "label", "withptr", |
| 54 | "scalar", "string", "program", "improper", "variant", |
| 55 | "procparam", "funcparam", "module", "tag", "common", "extref", "typeref" |
| 56 | }; |
| 57 | |
| 58 | public String classname(s) |
| 59 | Symbol s; |
| 60 | { |
| 61 | return clname[ord(s->class)]; |
| 62 | } |
| 63 | |
| 64 | /* |
| 65 | * Note the entry of the given block, unless it's the main program. |
| 66 | */ |
| 67 | |
| 68 | public printentry(s) |
| 69 | Symbol s; |
| 70 | { |
| 71 | if (s != program) { |
| 72 | printf("\nentering %s ", classname(s)); |
| 73 | printname(stdout, s); |
| 74 | printf("\n"); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /* |
| 79 | * Note the exit of the given block |
| 80 | */ |
| 81 | |
| 82 | public printexit(s) |
| 83 | Symbol s; |
| 84 | { |
| 85 | if (s != program) { |
| 86 | printf("leaving %s ", classname(s)); |
| 87 | printname(stdout, s); |
| 88 | printf("\n\n"); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /* |
| 93 | * Note the call of s from t. |
| 94 | */ |
| 95 | |
| 96 | public printcall(s, t) |
| 97 | Symbol s, t; |
| 98 | { |
| 99 | printf("calling "); |
| 100 | printname(stdout, s); |
| 101 | printparams(s, nil); |
| 102 | printf(" from %s ", classname(t)); |
| 103 | printname(stdout, t); |
| 104 | printf("\n"); |
| 105 | } |
| 106 | |
| 107 | /* |
| 108 | * Note the return from s. If s is a function, print the value |
| 109 | * it is returning. This is somewhat painful, since the function |
| 110 | * has actually just returned. |
| 111 | */ |
| 112 | |
| 113 | public printrtn(s) |
| 114 | Symbol s; |
| 115 | { |
| 116 | register Symbol t; |
| 117 | register int len; |
| 118 | Boolean isindirect; |
| 119 | |
| 120 | printf("returning "); |
| 121 | if (s->class == FUNC && (!istypename(s->type,"void"))) { |
| 122 | len = size(s->type); |
| 123 | if (canpush(len)) { |
| 124 | t = rtype(s->type); |
| 125 | isindirect = (Boolean) (t->class == RECORD or t->class == VARNT); |
| 126 | pushretval(len, isindirect); |
| 127 | printval(s->type); |
| 128 | putchar(' '); |
| 129 | } else { |
| 130 | printf("(value too large) "); |
| 131 | } |
| 132 | } |
| 133 | printf("from "); |
| 134 | printname(stdout, s); |
| 135 | printf("\n"); |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | * Print the values of the parameters of the given procedure or function. |
| 140 | * The frame distinguishes recursive instances of a procedure. |
| 141 | * |
| 142 | * If the procedure or function is internal, the argument count is |
| 143 | * not valid so we ignore it. |
| 144 | */ |
| 145 | |
| 146 | public printparams(f, frame) |
| 147 | Symbol f; |
| 148 | Frame frame; |
| 149 | { |
| 150 | Symbol param; |
| 151 | int n, m, s; |
| 152 | |
| 153 | n = nargspassed(frame); |
| 154 | if (isinternal(f)) { |
| 155 | n = 0; |
| 156 | } |
| 157 | printf("("); |
| 158 | param = f->chain; |
| 159 | if (param != nil or n > 0) { |
| 160 | m = n; |
| 161 | if (param != nil) { |
| 162 | for (;;) { |
| 163 | s = psize(param) div sizeof(Word); |
| 164 | if (s == 0) { |
| 165 | s = 1; |
| 166 | } |
| 167 | m -= s; |
| 168 | if (showaggrs) { |
| 169 | printv(param, frame); |
| 170 | } else { |
| 171 | printparamv(param, frame); |
| 172 | } |
| 173 | param = param->chain; |
| 174 | if (param == nil) break; |
| 175 | printf(", "); |
| 176 | } |
| 177 | } |
| 178 | if (m > 0) { |
| 179 | if (m > MAXARGSPASSED) { |
| 180 | m = MAXARGSPASSED; |
| 181 | } |
| 182 | if (f->chain != nil) { |
| 183 | printf(", "); |
| 184 | } |
| 185 | for (;;) { |
| 186 | --m; |
| 187 | printf("0x%x", argn(n - m, frame)); |
| 188 | if (m <= 0) break; |
| 189 | printf(", "); |
| 190 | } |
| 191 | } |
| 192 | } |
| 193 | printf(")"); |
| 194 | } |
| 195 | |
| 196 | /* |
| 197 | * Test if a symbol should be printed. We don't print files, |
| 198 | * for example, simply because there's no good way to do it. |
| 199 | * The symbol must be within the given function. |
| 200 | */ |
| 201 | |
| 202 | public Boolean should_print(s) |
| 203 | Symbol s; |
| 204 | { |
| 205 | Boolean b; |
| 206 | register Symbol t; |
| 207 | |
| 208 | switch (s->class) { |
| 209 | case VAR: |
| 210 | case FVAR: |
| 211 | if (isparam(s)) { |
| 212 | b = false; |
| 213 | } else { |
| 214 | t = rtype(s->type); |
| 215 | if (t == nil) { |
| 216 | b = false; |
| 217 | } else { |
| 218 | switch (t->class) { |
| 219 | case FILET: |
| 220 | case SET: |
| 221 | case BADUSE: |
| 222 | b = false; |
| 223 | break; |
| 224 | |
| 225 | default: |
| 226 | b = true; |
| 227 | break; |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | break; |
| 232 | |
| 233 | default: |
| 234 | b = false; |
| 235 | break; |
| 236 | } |
| 237 | return b; |
| 238 | } |
| 239 | |
| 240 | /* |
| 241 | * Print out a parameter value. |
| 242 | * |
| 243 | * Since this is intended to be printed on a single line with other information |
| 244 | * aggregate values are not printed. |
| 245 | */ |
| 246 | |
| 247 | public printparamv (p, frame) |
| 248 | Symbol p; |
| 249 | Frame frame; |
| 250 | { |
| 251 | Symbol t; |
| 252 | |
| 253 | t = rtype(p->type); |
| 254 | switch (t->class) { |
| 255 | case ARRAY: |
| 256 | case OPENARRAY: |
| 257 | case DYNARRAY: |
| 258 | case SUBARRAY: |
| 259 | t = rtype(t->type); |
| 260 | if (compatible(t, t_char)) { |
| 261 | printv(p, frame); |
| 262 | } else { |
| 263 | printf("%s = (...)", symname(p)); |
| 264 | } |
| 265 | break; |
| 266 | |
| 267 | case RECORD: |
| 268 | printf("%s = (...)", symname(p)); |
| 269 | break; |
| 270 | |
| 271 | default: |
| 272 | printv(p, frame); |
| 273 | break; |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * Print the name and value of a variable. |
| 279 | */ |
| 280 | |
| 281 | public printv(s, frame) |
| 282 | Symbol s; |
| 283 | Frame frame; |
| 284 | { |
| 285 | Address addr; |
| 286 | int len; |
| 287 | |
| 288 | if (isambiguous(s) and ismodule(container(s))) { |
| 289 | printname(stdout, s); |
| 290 | printf(" = "); |
| 291 | } else { |
| 292 | printf("%s = ", symname(s)); |
| 293 | } |
| 294 | if (isvarparam(s) and not isopenarray(s)) { |
| 295 | rpush(address(s, frame), sizeof(Address)); |
| 296 | addr = pop(Address); |
| 297 | } else { |
| 298 | addr = address(s, frame); |
| 299 | } |
| 300 | len = size(s); |
| 301 | if (not canpush(len)) { |
| 302 | printf("*** expression too large ***"); |
| 303 | } else if (isreg(s)) { |
| 304 | push(Address, addr); |
| 305 | printval(s->type); |
| 306 | } else { |
| 307 | rpush(addr, len); |
| 308 | printval(s->type); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | * Print out the name of a symbol. |
| 314 | */ |
| 315 | |
| 316 | public printname(f, s) |
| 317 | File f; |
| 318 | Symbol s; |
| 319 | { |
| 320 | if (s == nil) { |
| 321 | fprintf(f, "(noname)"); |
| 322 | } else if (s == program) { |
| 323 | fprintf(f, "."); |
| 324 | } else if (isredirected() or isambiguous(s)) { |
| 325 | printwhich(f, s); |
| 326 | } else { |
| 327 | fprintf(f, "%s", symname(s)); |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | /* |
| 332 | * Print the fully specified variable that is described by the given identifer. |
| 333 | */ |
| 334 | |
| 335 | public printwhich(f, s) |
| 336 | File f; |
| 337 | Symbol s; |
| 338 | { |
| 339 | printouter(f, container(s)); |
| 340 | fprintf(f, "%s", symname(s)); |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | * Print the fully qualified name of each symbol that has the same name |
| 345 | * as the given symbol. |
| 346 | */ |
| 347 | |
| 348 | public printwhereis(f, s) |
| 349 | File f; |
| 350 | Symbol s; |
| 351 | { |
| 352 | register Name n; |
| 353 | register Symbol t; |
| 354 | |
| 355 | checkref(s); |
| 356 | n = s->name; |
| 357 | t = lookup(n); |
| 358 | printwhich(f, t); |
| 359 | t = t->next_sym; |
| 360 | while (t != nil) { |
| 361 | if (t->name == n) { |
| 362 | putc(' ', f); |
| 363 | printwhich(f, t); |
| 364 | } |
| 365 | t = t->next_sym; |
| 366 | } |
| 367 | putc('\n', f); |
| 368 | } |
| 369 | |
| 370 | private printouter(f, s) |
| 371 | File f; |
| 372 | Symbol s; |
| 373 | { |
| 374 | Symbol outer; |
| 375 | |
| 376 | if (s != nil) { |
| 377 | outer = container(s); |
| 378 | if (outer != nil and outer != program) { |
| 379 | printouter(f, outer); |
| 380 | } |
| 381 | fprintf(f, "%s.", symname(s)); |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | public printdecl(s) |
| 386 | Symbol s; |
| 387 | { |
| 388 | Language lang; |
| 389 | |
| 390 | checkref(s); |
| 391 | if (s->language == nil or s->language == primlang) { |
| 392 | lang = findlanguage(".s"); |
| 393 | } else { |
| 394 | lang = s->language; |
| 395 | } |
| 396 | (*language_op(lang, L_PRINTDECL))(s); |
| 397 | } |
| 398 | |
| 399 | /* |
| 400 | * Straight dump of symbol information. |
| 401 | */ |
| 402 | |
| 403 | public psym(s) |
| 404 | Symbol s; |
| 405 | { |
| 406 | printf("name\t%s\n", symname(s)); |
| 407 | printf("lang\t%s\n", language_name(s->language)); |
| 408 | printf("level\t%d\n", s->level); |
| 409 | printf("class\t%s\n", classname(s)); |
| 410 | printf("type\t0x%x", s->type); |
| 411 | if (s->type != nil and s->type->name != nil) { |
| 412 | printf(" (%s)", symname(s->type)); |
| 413 | } |
| 414 | printf("\nchain\t0x%x", s->chain); |
| 415 | if (s->chain != nil and s->chain->name != nil) { |
| 416 | printf(" (%s)", symname(s->chain)); |
| 417 | } |
| 418 | printf("\nblock\t0x%x", s->block); |
| 419 | if (s->block != nil and s->block->name != nil) { |
| 420 | printf(" ("); |
| 421 | printname(stdout, s->block); |
| 422 | putchar(')'); |
| 423 | } |
| 424 | putchar('\n'); |
| 425 | switch (s->class) { |
| 426 | case TYPE: |
| 427 | printf("size\t%d\n", size(s)); |
| 428 | break; |
| 429 | |
| 430 | case VAR: |
| 431 | case REF: |
| 432 | switch (s->storage) { |
| 433 | case INREG: |
| 434 | printf("reg\t%d\n", s->symvalue.offset); |
| 435 | break; |
| 436 | |
| 437 | case STK: |
| 438 | printf("offset\t%d\n", s->symvalue.offset); |
| 439 | break; |
| 440 | |
| 441 | case EXT: |
| 442 | printf("address\t0x%x\n", s->symvalue.offset); |
| 443 | break; |
| 444 | } |
| 445 | printf("size\t%d\n", size(s)); |
| 446 | break; |
| 447 | |
| 448 | case RECORD: |
| 449 | case VARNT: |
| 450 | printf("size\t%d\n", s->symvalue.offset); |
| 451 | break; |
| 452 | |
| 453 | case FIELD: |
| 454 | printf("offset\t%d\n", s->symvalue.field.offset); |
| 455 | printf("size\t%d\n", s->symvalue.field.length); |
| 456 | break; |
| 457 | |
| 458 | case PROG: |
| 459 | case PROC: |
| 460 | case FUNC: |
| 461 | printf("address\t0x%x\n", s->symvalue.funcv.beginaddr); |
| 462 | if (isinline(s)) { |
| 463 | printf("inline procedure\n"); |
| 464 | } |
| 465 | if (nosource(s)) { |
| 466 | printf("does not have source information\n"); |
| 467 | } else { |
| 468 | printf("has source information\n"); |
| 469 | } |
| 470 | break; |
| 471 | |
| 472 | case RANGE: |
| 473 | prangetype(s->symvalue.rangev.lowertype); |
| 474 | printf("lower\t%d\n", s->symvalue.rangev.lower); |
| 475 | prangetype(s->symvalue.rangev.uppertype); |
| 476 | printf("upper\t%d\n", s->symvalue.rangev.upper); |
| 477 | break; |
| 478 | |
| 479 | default: |
| 480 | /* do nothing */ |
| 481 | break; |
| 482 | } |
| 483 | } |
| 484 | |
| 485 | private prangetype(r) |
| 486 | Rangetype r; |
| 487 | { |
| 488 | switch (r) { |
| 489 | case R_CONST: |
| 490 | printf("CONST"); |
| 491 | break; |
| 492 | |
| 493 | case R_ARG: |
| 494 | printf("ARG"); |
| 495 | break; |
| 496 | |
| 497 | case R_TEMP: |
| 498 | printf("TEMP"); |
| 499 | break; |
| 500 | |
| 501 | case R_ADJUST: |
| 502 | printf("ADJUST"); |
| 503 | break; |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | /* |
| 508 | * Print out the value on top of the stack according to the given type. |
| 509 | */ |
| 510 | |
| 511 | public printval(t) |
| 512 | Symbol t; |
| 513 | { |
| 514 | Symbol s; |
| 515 | |
| 516 | checkref(t); |
| 517 | if (t->class == TYPEREF) { |
| 518 | resolveRef(t); |
| 519 | } |
| 520 | switch (t->class) { |
| 521 | case PROC: |
| 522 | case FUNC: |
| 523 | s = pop(Symbol); |
| 524 | printf("%s", symname(s)); |
| 525 | break; |
| 526 | |
| 527 | default: |
| 528 | if (t->language == nil or t->language == primlang) { |
| 529 | (*language_op(findlanguage(".c"), L_PRINTVAL))(t); |
| 530 | } else { |
| 531 | (*language_op(t->language, L_PRINTVAL))(t); |
| 532 | } |
| 533 | break; |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | /* |
| 538 | * Print out the value of a record, field by field. |
| 539 | */ |
| 540 | |
| 541 | public printrecord(s) |
| 542 | Symbol s; |
| 543 | { |
| 544 | Symbol f; |
| 545 | |
| 546 | if (s->chain == nil) { |
| 547 | error("record has no fields"); |
| 548 | } |
| 549 | printf("("); |
| 550 | sp -= size(s); |
| 551 | f = s->chain; |
| 552 | if (f != nil) { |
| 553 | for (;;) { |
| 554 | printfield(f); |
| 555 | f = f->chain; |
| 556 | if (f == nil) break; |
| 557 | printf(", "); |
| 558 | } |
| 559 | } |
| 560 | printf(")"); |
| 561 | } |
| 562 | |
| 563 | /* |
| 564 | * Print out a field. |
| 565 | */ |
| 566 | |
| 567 | private printfield(f) |
| 568 | Symbol f; |
| 569 | { |
| 570 | Stack *savesp; |
| 571 | register int off, len; |
| 572 | |
| 573 | printf("%s = ", symname(f)); |
| 574 | savesp = sp; |
| 575 | off = f->symvalue.field.offset; |
| 576 | len = f->symvalue.field.length; |
| 577 | sp += ((off + len + BITSPERBYTE - 1) div BITSPERBYTE); |
| 578 | printval(f); |
| 579 | sp = savesp; |
| 580 | } |
| 581 | |
| 582 | /* |
| 583 | * Print out the contents of an array. |
| 584 | * Haven't quite figured out what the best format is. |
| 585 | * |
| 586 | * This is rather inefficient. |
| 587 | * |
| 588 | * The "2*elsize" is there since "printval" drops the stack by elsize. |
| 589 | */ |
| 590 | |
| 591 | public printarray(a) |
| 592 | Symbol a; |
| 593 | { |
| 594 | Stack *savesp, *newsp; |
| 595 | Symbol eltype; |
| 596 | long elsize; |
| 597 | String sep; |
| 598 | |
| 599 | savesp = sp; |
| 600 | sp -= (size(a)); |
| 601 | newsp = sp; |
| 602 | eltype = rtype(a->type); |
| 603 | elsize = size(eltype); |
| 604 | printf("("); |
| 605 | if (eltype->class == RECORD or eltype->class == ARRAY or |
| 606 | eltype->class == VARNT) { |
| 607 | sep = "\n"; |
| 608 | putchar('\n'); |
| 609 | } else { |
| 610 | sep = ", "; |
| 611 | } |
| 612 | for (sp += elsize; sp <= savesp; sp += 2*elsize) { |
| 613 | if (sp - elsize != newsp) { |
| 614 | fputs(sep, stdout); |
| 615 | } |
| 616 | printval(eltype); |
| 617 | } |
| 618 | sp = newsp; |
| 619 | if (streq(sep, "\n")) { |
| 620 | putchar('\n'); |
| 621 | } |
| 622 | printf(")"); |
| 623 | } |
| 624 | |
| 625 | /* |
| 626 | * Print out the value of a real number in Pascal notation. |
| 627 | * This is, unfortunately, different than what one gets |
| 628 | * from "%g" in printf. |
| 629 | */ |
| 630 | |
| 631 | public prtreal(r) |
| 632 | double r; |
| 633 | { |
| 634 | extern char *index(); |
| 635 | char buf[256]; |
| 636 | |
| 637 | # ifdef IRIS |
| 638 | sprintf(buf, "%lg", r); |
| 639 | # else |
| 640 | sprintf(buf, "%g", r); |
| 641 | # endif |
| 642 | if (buf[0] == '.') { |
| 643 | printf("0%s", buf); |
| 644 | } else if (buf[0] == '-' and buf[1] == '.') { |
| 645 | printf("-0%s", &buf[1]); |
| 646 | } else { |
| 647 | printf("%s", buf); |
| 648 | } |
| 649 | if (index(buf, '.') == nil) { |
| 650 | printf(".0"); |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | /* |
| 655 | * Print out a character using ^? notation for unprintables. |
| 656 | */ |
| 657 | |
| 658 | public printchar(c) |
| 659 | char c; |
| 660 | { |
| 661 | if (c == 0) { |
| 662 | putchar('\\'); |
| 663 | putchar('0'); |
| 664 | } else if (c == '\n') { |
| 665 | putchar('\\'); |
| 666 | putchar('n'); |
| 667 | } else if (c > 0 and c < ' ') { |
| 668 | putchar('^'); |
| 669 | putchar(c - 1 + 'A'); |
| 670 | } else if (c >= ' ' && c <= '~') { |
| 671 | putchar(c); |
| 672 | } else { |
| 673 | printf("\\0%o",c&0xff); |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | /* |
| 678 | * Print out a value for a range type (integer, char, or boolean). |
| 679 | */ |
| 680 | |
| 681 | public printRangeVal (val, t) |
| 682 | long val; |
| 683 | Symbol t; |
| 684 | { |
| 685 | if (t == t_boolean->type or istypename(t->type, "boolean")) { |
| 686 | if ((boolean) val) { |
| 687 | printf("true"); |
| 688 | } else { |
| 689 | printf("false"); |
| 690 | } |
| 691 | } else if (t == t_char->type or istypename(t->type, "char")) { |
| 692 | if (varIsSet("$hexchars")) { |
| 693 | printf("0x%lx", val); |
| 694 | } else { |
| 695 | putchar('\''); |
| 696 | printchar(val); |
| 697 | putchar('\''); |
| 698 | } |
| 699 | } else if (varIsSet("$hexints")) { |
| 700 | printf("0x%lx", val); |
| 701 | } else if (t->symvalue.rangev.lower >= 0) { |
| 702 | printf("%lu", val); |
| 703 | } else { |
| 704 | printf("%ld", val); |
| 705 | } |
| 706 | } |
| 707 | |
| 708 | /* |
| 709 | * Print out an enumerated value by finding the corresponding |
| 710 | * name in the enumeration list. |
| 711 | */ |
| 712 | |
| 713 | public printEnum (i, t) |
| 714 | integer i; |
| 715 | Symbol t; |
| 716 | { |
| 717 | register Symbol e; |
| 718 | |
| 719 | e = t->chain; |
| 720 | while (e != nil and e->symvalue.constval->value.lcon != i) { |
| 721 | e = e->chain; |
| 722 | } |
| 723 | if (e != nil) { |
| 724 | printf("%s", symname(e)); |
| 725 | } else { |
| 726 | printf("%d", i); |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | /* |
| 731 | * Print out a null-terminated string (pointer to char) |
| 732 | * starting at the given address. |
| 733 | */ |
| 734 | |
| 735 | public printString (addr, quotes) |
| 736 | Address addr; |
| 737 | boolean quotes; |
| 738 | { |
| 739 | register Address a; |
| 740 | register integer i, len; |
| 741 | register boolean endofstring; |
| 742 | register int unprintables; |
| 743 | #define MAXGARBAGE 4 |
| 744 | union { |
| 745 | char ch[sizeof(Word)]; |
| 746 | int word; |
| 747 | } u; |
| 748 | |
| 749 | if (varIsSet("$hexstrings")) { |
| 750 | printf("0x%x", addr); |
| 751 | } else { |
| 752 | if (quotes) { |
| 753 | putchar('"'); |
| 754 | } |
| 755 | a = addr; |
| 756 | unprintables = 0; |
| 757 | endofstring = false; |
| 758 | while (not endofstring) { |
| 759 | dread(&u, a, sizeof(u)); |
| 760 | i = 0; |
| 761 | do { |
| 762 | if (u.ch[i] == '\0') { |
| 763 | endofstring = true; |
| 764 | } else { |
| 765 | printchar(u.ch[i]); |
| 766 | if (!isascii(u.ch[i]) and ++unprintables > MAXGARBAGE) { |
| 767 | endofstring = true; |
| 768 | printf("..."); |
| 769 | } |
| 770 | } |
| 771 | ++i; |
| 772 | } while (i < sizeof(Word) and not endofstring); |
| 773 | a += sizeof(Word); |
| 774 | } |
| 775 | if (quotes) { |
| 776 | putchar('"'); |
| 777 | } |
| 778 | } |
| 779 | } |