diff options
| author | Stefan Monnier | 2023-09-29 14:55:24 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2023-09-29 14:55:24 -0400 |
| commit | cc0d7d7a3867e4554f89262e4641c9845ee0d647 (patch) | |
| tree | a3c3ee2a6ce207bb969b21f50f802bf55954d1d1 /src | |
| parent | 01229fe0096e936ea8f4fad0d64967671c4b1892 (diff) | |
| download | emacs-cc0d7d7a3867e4554f89262e4641c9845ee0d647.tar.gz emacs-cc0d7d7a3867e4554f89262e4641c9845ee0d647.zip | |
search.c (re--describe-compiled): New function (bug#66261)
This provides a fairly primitive but handy way to see what
a regexp compiles to without having to enable REGEX_EMACS_DEBUG
and wade through tons of stderr output.
* doc/lispref/searching.texi (Regexp Problems): Mention
`re--describe-compiled`.
* src/regex-emacs.c (debug_putchar, print_fastmap)
(print_partial_compiled_pattern, print_compiled_pattern): Add `dest`
argument, and compile also when `ENABLE_CHECKING` is set.
(DEBUG_PRINT_COMPILED_PATTERN, print_double_string, regex_compile):
Adjust to additional argument.
* src/regex-emacs.h (print_compiled_pattern): Declare.
* src/search.c (Fre__describe_compiled): New function.
(syms_of_search): Defsubr it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/regex-emacs.c | 176 | ||||
| -rw-r--r-- | src/regex-emacs.h | 4 | ||||
| -rw-r--r-- | src/search.c | 41 |
3 files changed, 136 insertions, 85 deletions
diff --git a/src/regex-emacs.c b/src/regex-emacs.c index ad140908609..f4ea867f3c0 100644 --- a/src/regex-emacs.c +++ b/src/regex-emacs.c | |||
| @@ -268,7 +268,9 @@ typedef enum | |||
| 268 | on_failure_jump, | 268 | on_failure_jump, |
| 269 | 269 | ||
| 270 | /* Like on_failure_jump, but pushes a placeholder instead of the | 270 | /* Like on_failure_jump, but pushes a placeholder instead of the |
| 271 | current string position when executed. */ | 271 | current string position when executed. Upon failure, |
| 272 | the current string position is thus not restored. | ||
| 273 | Used only for single-char loops that don't require backtracking. */ | ||
| 272 | on_failure_keep_string_jump, | 274 | on_failure_keep_string_jump, |
| 273 | 275 | ||
| 274 | /* Just like 'on_failure_jump', except that it checks that we | 276 | /* Just like 'on_failure_jump', except that it checks that we |
| @@ -434,38 +436,27 @@ extract_number_and_incr (re_char **source) | |||
| 434 | /* If REGEX_EMACS_DEBUG is defined, print many voluminous messages | 436 | /* If REGEX_EMACS_DEBUG is defined, print many voluminous messages |
| 435 | (if the variable regex_emacs_debug is positive). */ | 437 | (if the variable regex_emacs_debug is positive). */ |
| 436 | 438 | ||
| 437 | #ifdef REGEX_EMACS_DEBUG | 439 | #if defined REGEX_EMACS_DEBUG || ENABLE_CHECKING |
| 438 | 440 | ||
| 439 | /* Use standard I/O for debugging. */ | 441 | /* Use standard I/O for debugging. */ |
| 440 | # include "sysstdio.h" | 442 | # include "sysstdio.h" |
| 441 | 443 | ||
| 442 | static int regex_emacs_debug = -100000; | ||
| 443 | |||
| 444 | # define DEBUG_STATEMENT(e) e | ||
| 445 | # define DEBUG_PRINT(...) \ | ||
| 446 | if (regex_emacs_debug > 0) fprintf (stderr, __VA_ARGS__) | ||
| 447 | # define DEBUG_COMPILES_ARGUMENTS | ||
| 448 | # define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ | ||
| 449 | if (regex_emacs_debug > 0) print_partial_compiled_pattern (s, e) | ||
| 450 | # define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ | ||
| 451 | if (regex_emacs_debug > 0) print_double_string (w, s1, sz1, s2, sz2) | ||
| 452 | |||
| 453 | static void | 444 | static void |
| 454 | debug_putchar (int c) | 445 | debug_putchar (FILE *dest, int c) |
| 455 | { | 446 | { |
| 456 | if (c >= 32 && c <= 126) | 447 | if (c >= 32 && c <= 126) |
| 457 | putc (c, stderr); | 448 | putc (c, dest); |
| 458 | else | 449 | else |
| 459 | { | 450 | { |
| 460 | unsigned int uc = c; | 451 | unsigned int uc = c; |
| 461 | fprintf (stderr, "{%02x}", uc); | 452 | fprintf (dest, "{%02x}", uc); |
| 462 | } | 453 | } |
| 463 | } | 454 | } |
| 464 | 455 | ||
| 465 | /* Print the fastmap in human-readable form. */ | 456 | /* Print the fastmap in human-readable form. */ |
| 466 | 457 | ||
| 467 | static void | 458 | static void |
| 468 | print_fastmap (char *fastmap) | 459 | print_fastmap (FILE *dest, char *fastmap) |
| 469 | { | 460 | { |
| 470 | bool was_a_range = false; | 461 | bool was_a_range = false; |
| 471 | int i = 0; | 462 | int i = 0; |
| @@ -475,7 +466,7 @@ print_fastmap (char *fastmap) | |||
| 475 | if (fastmap[i++]) | 466 | if (fastmap[i++]) |
| 476 | { | 467 | { |
| 477 | was_a_range = false; | 468 | was_a_range = false; |
| 478 | debug_putchar (i - 1); | 469 | debug_putchar (dest, i - 1); |
| 479 | while (i < (1 << BYTEWIDTH) && fastmap[i]) | 470 | while (i < (1 << BYTEWIDTH) && fastmap[i]) |
| 480 | { | 471 | { |
| 481 | was_a_range = true; | 472 | was_a_range = true; |
| @@ -483,12 +474,12 @@ print_fastmap (char *fastmap) | |||
| 483 | } | 474 | } |
| 484 | if (was_a_range) | 475 | if (was_a_range) |
| 485 | { | 476 | { |
| 486 | debug_putchar ('-'); | 477 | debug_putchar (dest, '-'); |
| 487 | debug_putchar (i - 1); | 478 | debug_putchar (dest, i - 1); |
| 488 | } | 479 | } |
| 489 | } | 480 | } |
| 490 | } | 481 | } |
| 491 | putc ('\n', stderr); | 482 | putc ('\n', dest); |
| 492 | } | 483 | } |
| 493 | 484 | ||
| 494 | 485 | ||
| @@ -496,7 +487,7 @@ print_fastmap (char *fastmap) | |||
| 496 | the START pointer into it and ending just before the pointer END. */ | 487 | the START pointer into it and ending just before the pointer END. */ |
| 497 | 488 | ||
| 498 | static void | 489 | static void |
| 499 | print_partial_compiled_pattern (re_char *start, re_char *end) | 490 | print_partial_compiled_pattern (FILE *dest, re_char *start, re_char *end) |
| 500 | { | 491 | { |
| 501 | int mcnt, mcnt2; | 492 | int mcnt, mcnt2; |
| 502 | re_char *p = start; | 493 | re_char *p = start; |
| @@ -504,50 +495,50 @@ print_partial_compiled_pattern (re_char *start, re_char *end) | |||
| 504 | 495 | ||
| 505 | if (start == NULL) | 496 | if (start == NULL) |
| 506 | { | 497 | { |
| 507 | fputs ("(null)\n", stderr); | 498 | fputs ("(null)\n", dest); |
| 508 | return; | 499 | return; |
| 509 | } | 500 | } |
| 510 | 501 | ||
| 511 | /* Loop over pattern commands. */ | 502 | /* Loop over pattern commands. */ |
| 512 | while (p < pend) | 503 | while (p < pend) |
| 513 | { | 504 | { |
| 514 | fprintf (stderr, "%td:\t", p - start); | 505 | fprintf (dest, "%td:\t", p - start); |
| 515 | 506 | ||
| 516 | switch ((re_opcode_t) *p++) | 507 | switch ((re_opcode_t) *p++) |
| 517 | { | 508 | { |
| 518 | case no_op: | 509 | case no_op: |
| 519 | fputs ("/no_op", stderr); | 510 | fputs ("/no_op", dest); |
| 520 | break; | 511 | break; |
| 521 | 512 | ||
| 522 | case succeed: | 513 | case succeed: |
| 523 | fputs ("/succeed", stderr); | 514 | fputs ("/succeed", dest); |
| 524 | break; | 515 | break; |
| 525 | 516 | ||
| 526 | case exactn: | 517 | case exactn: |
| 527 | mcnt = *p++; | 518 | mcnt = *p++; |
| 528 | fprintf (stderr, "/exactn/%d", mcnt); | 519 | fprintf (dest, "/exactn/%d", mcnt); |
| 529 | do | 520 | do |
| 530 | { | 521 | { |
| 531 | debug_putchar ('/'); | 522 | debug_putchar (dest, '/'); |
| 532 | debug_putchar (*p++); | 523 | debug_putchar (dest, *p++); |
| 533 | } | 524 | } |
| 534 | while (--mcnt); | 525 | while (--mcnt); |
| 535 | break; | 526 | break; |
| 536 | 527 | ||
| 537 | case start_memory: | 528 | case start_memory: |
| 538 | fprintf (stderr, "/start_memory/%d", *p++); | 529 | fprintf (dest, "/start_memory/%d", *p++); |
| 539 | break; | 530 | break; |
| 540 | 531 | ||
| 541 | case stop_memory: | 532 | case stop_memory: |
| 542 | fprintf (stderr, "/stop_memory/%d", *p++); | 533 | fprintf (dest, "/stop_memory/%d", *p++); |
| 543 | break; | 534 | break; |
| 544 | 535 | ||
| 545 | case duplicate: | 536 | case duplicate: |
| 546 | fprintf (stderr, "/duplicate/%d", *p++); | 537 | fprintf (dest, "/duplicate/%d", *p++); |
| 547 | break; | 538 | break; |
| 548 | 539 | ||
| 549 | case anychar: | 540 | case anychar: |
| 550 | fputs ("/anychar", stderr); | 541 | fputs ("/anychar", dest); |
| 551 | break; | 542 | break; |
| 552 | 543 | ||
| 553 | case charset: | 544 | case charset: |
| @@ -558,11 +549,11 @@ print_partial_compiled_pattern (re_char *start, re_char *end) | |||
| 558 | int length = CHARSET_BITMAP_SIZE (p - 1); | 549 | int length = CHARSET_BITMAP_SIZE (p - 1); |
| 559 | bool has_range_table = CHARSET_RANGE_TABLE_EXISTS_P (p - 1); | 550 | bool has_range_table = CHARSET_RANGE_TABLE_EXISTS_P (p - 1); |
| 560 | 551 | ||
| 561 | fprintf (stderr, "/charset [%s", | 552 | fprintf (dest, "/charset [%s", |
| 562 | (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); | 553 | (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); |
| 563 | 554 | ||
| 564 | if (p + (*p & 0x7f) >= pend) | 555 | if (p + (*p & 0x7f) >= pend) |
| 565 | fputs (" !extends past end of pattern! ", stderr); | 556 | fputs (" !extends past end of pattern! ", dest); |
| 566 | 557 | ||
| 567 | for (c = 0; c < 256; c++) | 558 | for (c = 0; c < 256; c++) |
| 568 | if (c / 8 < length | 559 | if (c / 8 < length |
| @@ -571,33 +562,33 @@ print_partial_compiled_pattern (re_char *start, re_char *end) | |||
| 571 | /* Are we starting a range? */ | 562 | /* Are we starting a range? */ |
| 572 | if (last + 1 == c && ! in_range) | 563 | if (last + 1 == c && ! in_range) |
| 573 | { | 564 | { |
| 574 | debug_putchar ('-'); | 565 | debug_putchar (dest, '-'); |
| 575 | in_range = true; | 566 | in_range = true; |
| 576 | } | 567 | } |
| 577 | /* Have we broken a range? */ | 568 | /* Have we broken a range? */ |
| 578 | else if (last + 1 != c && in_range) | 569 | else if (last + 1 != c && in_range) |
| 579 | { | 570 | { |
| 580 | debug_putchar (last); | 571 | debug_putchar (dest, last); |
| 581 | in_range = false; | 572 | in_range = false; |
| 582 | } | 573 | } |
| 583 | 574 | ||
| 584 | if (! in_range) | 575 | if (! in_range) |
| 585 | debug_putchar (c); | 576 | debug_putchar (dest, c); |
| 586 | 577 | ||
| 587 | last = c; | 578 | last = c; |
| 588 | } | 579 | } |
| 589 | 580 | ||
| 590 | if (in_range) | 581 | if (in_range) |
| 591 | debug_putchar (last); | 582 | debug_putchar (dest, last); |
| 592 | 583 | ||
| 593 | debug_putchar (']'); | 584 | debug_putchar (dest, ']'); |
| 594 | 585 | ||
| 595 | p += 1 + length; | 586 | p += 1 + length; |
| 596 | 587 | ||
| 597 | if (has_range_table) | 588 | if (has_range_table) |
| 598 | { | 589 | { |
| 599 | int count; | 590 | int count; |
| 600 | fputs ("has-range-table", stderr); | 591 | fputs ("has-range-table", dest); |
| 601 | 592 | ||
| 602 | /* ??? Should print the range table; for now, just skip it. */ | 593 | /* ??? Should print the range table; for now, just skip it. */ |
| 603 | p += 2; /* skip range table bits */ | 594 | p += 2; /* skip range table bits */ |
| @@ -608,160 +599,175 @@ print_partial_compiled_pattern (re_char *start, re_char *end) | |||
| 608 | break; | 599 | break; |
| 609 | 600 | ||
| 610 | case begline: | 601 | case begline: |
| 611 | fputs ("/begline", stderr); | 602 | fputs ("/begline", dest); |
| 612 | break; | 603 | break; |
| 613 | 604 | ||
| 614 | case endline: | 605 | case endline: |
| 615 | fputs ("/endline", stderr); | 606 | fputs ("/endline", dest); |
| 616 | break; | 607 | break; |
| 617 | 608 | ||
| 618 | case on_failure_jump: | 609 | case on_failure_jump: |
| 619 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 610 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 620 | fprintf (stderr, "/on_failure_jump to %td", p + mcnt - start); | 611 | fprintf (dest, "/on_failure_jump to %td", p + mcnt - start); |
| 621 | break; | 612 | break; |
| 622 | 613 | ||
| 623 | case on_failure_keep_string_jump: | 614 | case on_failure_keep_string_jump: |
| 624 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 615 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 625 | fprintf (stderr, "/on_failure_keep_string_jump to %td", | 616 | fprintf (dest, "/on_failure_keep_string_jump to %td", |
| 626 | p + mcnt - start); | 617 | p + mcnt - start); |
| 627 | break; | 618 | break; |
| 628 | 619 | ||
| 629 | case on_failure_jump_nastyloop: | 620 | case on_failure_jump_nastyloop: |
| 630 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 621 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 631 | fprintf (stderr, "/on_failure_jump_nastyloop to %td", | 622 | fprintf (dest, "/on_failure_jump_nastyloop to %td", |
| 632 | p + mcnt - start); | 623 | p + mcnt - start); |
| 633 | break; | 624 | break; |
| 634 | 625 | ||
| 635 | case on_failure_jump_loop: | 626 | case on_failure_jump_loop: |
| 636 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 627 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 637 | fprintf (stderr, "/on_failure_jump_loop to %td", | 628 | fprintf (dest, "/on_failure_jump_loop to %td", |
| 638 | p + mcnt - start); | 629 | p + mcnt - start); |
| 639 | break; | 630 | break; |
| 640 | 631 | ||
| 641 | case on_failure_jump_smart: | 632 | case on_failure_jump_smart: |
| 642 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 633 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 643 | fprintf (stderr, "/on_failure_jump_smart to %td", | 634 | fprintf (dest, "/on_failure_jump_smart to %td", |
| 644 | p + mcnt - start); | 635 | p + mcnt - start); |
| 645 | break; | 636 | break; |
| 646 | 637 | ||
| 647 | case jump: | 638 | case jump: |
| 648 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 639 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 649 | fprintf (stderr, "/jump to %td", p + mcnt - start); | 640 | fprintf (dest, "/jump to %td", p + mcnt - start); |
| 650 | break; | 641 | break; |
| 651 | 642 | ||
| 652 | case succeed_n: | 643 | case succeed_n: |
| 653 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 644 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 654 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); | 645 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); |
| 655 | fprintf (stderr, "/succeed_n to %td, %d times", | 646 | fprintf (dest, "/succeed_n to %td, %d times", |
| 656 | p - 2 + mcnt - start, mcnt2); | 647 | p - 2 + mcnt - start, mcnt2); |
| 657 | break; | 648 | break; |
| 658 | 649 | ||
| 659 | case jump_n: | 650 | case jump_n: |
| 660 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 651 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 661 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); | 652 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); |
| 662 | fprintf (stderr, "/jump_n to %td, %d times", | 653 | fprintf (dest, "/jump_n to %td, %d times", |
| 663 | p - 2 + mcnt - start, mcnt2); | 654 | p - 2 + mcnt - start, mcnt2); |
| 664 | break; | 655 | break; |
| 665 | 656 | ||
| 666 | case set_number_at: | 657 | case set_number_at: |
| 667 | EXTRACT_NUMBER_AND_INCR (mcnt, p); | 658 | EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| 668 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); | 659 | EXTRACT_NUMBER_AND_INCR (mcnt2, p); |
| 669 | fprintf (stderr, "/set_number_at location %td to %d", | 660 | fprintf (dest, "/set_number_at location %td to %d", |
| 670 | p - 2 + mcnt - start, mcnt2); | 661 | p - 2 + mcnt - start, mcnt2); |
| 671 | break; | 662 | break; |
| 672 | 663 | ||
| 673 | case wordbound: | 664 | case wordbound: |
| 674 | fputs ("/wordbound", stderr); | 665 | fputs ("/wordbound", dest); |
| 675 | break; | 666 | break; |
| 676 | 667 | ||
| 677 | case notwordbound: | 668 | case notwordbound: |
| 678 | fputs ("/notwordbound", stderr); | 669 | fputs ("/notwordbound", dest); |
| 679 | break; | 670 | break; |
| 680 | 671 | ||
| 681 | case wordbeg: | 672 | case wordbeg: |
| 682 | fputs ("/wordbeg", stderr); | 673 | fputs ("/wordbeg", dest); |
| 683 | break; | 674 | break; |
| 684 | 675 | ||
| 685 | case wordend: | 676 | case wordend: |
| 686 | fputs ("/wordend", stderr); | 677 | fputs ("/wordend", dest); |
| 687 | break; | 678 | break; |
| 688 | 679 | ||
| 689 | case symbeg: | 680 | case symbeg: |
| 690 | fputs ("/symbeg", stderr); | 681 | fputs ("/symbeg", dest); |
| 691 | break; | 682 | break; |
| 692 | 683 | ||
| 693 | case symend: | 684 | case symend: |
| 694 | fputs ("/symend", stderr); | 685 | fputs ("/symend", dest); |
| 695 | break; | 686 | break; |
| 696 | 687 | ||
| 697 | case syntaxspec: | 688 | case syntaxspec: |
| 698 | fputs ("/syntaxspec", stderr); | 689 | fputs ("/syntaxspec", dest); |
| 699 | mcnt = *p++; | 690 | mcnt = *p++; |
| 700 | fprintf (stderr, "/%d", mcnt); | 691 | fprintf (dest, "/%d", mcnt); |
| 701 | break; | 692 | break; |
| 702 | 693 | ||
| 703 | case notsyntaxspec: | 694 | case notsyntaxspec: |
| 704 | fputs ("/notsyntaxspec", stderr); | 695 | fputs ("/notsyntaxspec", dest); |
| 705 | mcnt = *p++; | 696 | mcnt = *p++; |
| 706 | fprintf (stderr, "/%d", mcnt); | 697 | fprintf (dest, "/%d", mcnt); |
| 707 | break; | 698 | break; |
| 708 | 699 | ||
| 709 | case at_dot: | 700 | case at_dot: |
| 710 | fputs ("/at_dot", stderr); | 701 | fputs ("/at_dot", dest); |
| 711 | break; | 702 | break; |
| 712 | 703 | ||
| 713 | case categoryspec: | 704 | case categoryspec: |
| 714 | fputs ("/categoryspec", stderr); | 705 | fputs ("/categoryspec", dest); |
| 715 | mcnt = *p++; | 706 | mcnt = *p++; |
| 716 | fprintf (stderr, "/%d", mcnt); | 707 | fprintf (dest, "/%d", mcnt); |
| 717 | break; | 708 | break; |
| 718 | 709 | ||
| 719 | case notcategoryspec: | 710 | case notcategoryspec: |
| 720 | fputs ("/notcategoryspec", stderr); | 711 | fputs ("/notcategoryspec", dest); |
| 721 | mcnt = *p++; | 712 | mcnt = *p++; |
| 722 | fprintf (stderr, "/%d", mcnt); | 713 | fprintf (dest, "/%d", mcnt); |
| 723 | break; | 714 | break; |
| 724 | 715 | ||
| 725 | case begbuf: | 716 | case begbuf: |
| 726 | fputs ("/begbuf", stderr); | 717 | fputs ("/begbuf", dest); |
| 727 | break; | 718 | break; |
| 728 | 719 | ||
| 729 | case endbuf: | 720 | case endbuf: |
| 730 | fputs ("/endbuf", stderr); | 721 | fputs ("/endbuf", dest); |
| 731 | break; | 722 | break; |
| 732 | 723 | ||
| 733 | default: | 724 | default: |
| 734 | fprintf (stderr, "?%d", *(p-1)); | 725 | fprintf (dest, "?%d", *(p-1)); |
| 735 | } | 726 | } |
| 736 | 727 | ||
| 737 | putc ('\n', stderr); | 728 | putc ('\n', dest); |
| 738 | } | 729 | } |
| 739 | 730 | ||
| 740 | fprintf (stderr, "%td:\tend of pattern.\n", p - start); | 731 | fprintf (dest, "%td:\tend of pattern.\n", p - start); |
| 741 | } | 732 | } |
| 742 | 733 | ||
| 743 | 734 | void | |
| 744 | static void | 735 | print_compiled_pattern (FILE *dest, struct re_pattern_buffer *bufp) |
| 745 | print_compiled_pattern (struct re_pattern_buffer *bufp) | ||
| 746 | { | 736 | { |
| 737 | if (!dest) | ||
| 738 | dest = stderr; | ||
| 747 | re_char *buffer = bufp->buffer; | 739 | re_char *buffer = bufp->buffer; |
| 748 | 740 | ||
| 749 | print_partial_compiled_pattern (buffer, buffer + bufp->used); | 741 | print_partial_compiled_pattern (dest, buffer, buffer + bufp->used); |
| 750 | fprintf (stderr, "%td bytes used/%td bytes allocated.\n", | 742 | fprintf (dest, "%td bytes used/%td bytes allocated.\n", |
| 751 | bufp->used, bufp->allocated); | 743 | bufp->used, bufp->allocated); |
| 752 | 744 | ||
| 753 | if (bufp->fastmap_accurate && bufp->fastmap) | 745 | if (bufp->fastmap_accurate && bufp->fastmap) |
| 754 | { | 746 | { |
| 755 | fputs ("fastmap: ", stderr); | 747 | fputs ("fastmap: ", dest); |
| 756 | print_fastmap (bufp->fastmap); | 748 | print_fastmap (dest, bufp->fastmap); |
| 757 | } | 749 | } |
| 758 | 750 | ||
| 759 | fprintf (stderr, "re_nsub: %td\t", bufp->re_nsub); | 751 | fprintf (dest, "re_nsub: %td\t", bufp->re_nsub); |
| 760 | fprintf (stderr, "regs_alloc: %d\t", bufp->regs_allocated); | 752 | fprintf (dest, "regs_alloc: %d\t", bufp->regs_allocated); |
| 761 | fprintf (stderr, "can_be_null: %d\n", bufp->can_be_null); | 753 | fprintf (dest, "can_be_null: %d\n", bufp->can_be_null); |
| 762 | /* Perhaps we should print the translate table? */ | 754 | /* Perhaps we should print the translate table? */ |
| 763 | } | 755 | } |
| 764 | 756 | ||
| 757 | #endif | ||
| 758 | |||
| 759 | #ifdef REGEX_EMACS_DEBUG | ||
| 760 | |||
| 761 | static int regex_emacs_debug = -100000; | ||
| 762 | |||
| 763 | # define DEBUG_STATEMENT(e) e | ||
| 764 | # define DEBUG_PRINT(...) \ | ||
| 765 | if (regex_emacs_debug > 0) fprintf (stderr, __VA_ARGS__) | ||
| 766 | # define DEBUG_COMPILES_ARGUMENTS | ||
| 767 | # define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ | ||
| 768 | if (regex_emacs_debug > 0) print_partial_compiled_pattern (stderr, s, e) | ||
| 769 | # define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ | ||
| 770 | if (regex_emacs_debug > 0) print_double_string (w, s1, sz1, s2, sz2) | ||
| 765 | 771 | ||
| 766 | static void | 772 | static void |
| 767 | print_double_string (re_char *where, re_char *string1, ptrdiff_t size1, | 773 | print_double_string (re_char *where, re_char *string1, ptrdiff_t size1, |
| @@ -775,12 +781,12 @@ print_double_string (re_char *where, re_char *string1, ptrdiff_t size1, | |||
| 775 | if (FIRST_STRING_P (where)) | 781 | if (FIRST_STRING_P (where)) |
| 776 | { | 782 | { |
| 777 | for (i = 0; i < string1 + size1 - where; i++) | 783 | for (i = 0; i < string1 + size1 - where; i++) |
| 778 | debug_putchar (where[i]); | 784 | debug_putchar (stderr, where[i]); |
| 779 | where = string2; | 785 | where = string2; |
| 780 | } | 786 | } |
| 781 | 787 | ||
| 782 | for (i = 0; i < string2 + size2 - where; i++) | 788 | for (i = 0; i < string2 + size2 - where; i++) |
| 783 | debug_putchar (where[i]); | 789 | debug_putchar (stderr, where[i]); |
| 784 | } | 790 | } |
| 785 | } | 791 | } |
| 786 | 792 | ||
| @@ -1760,7 +1766,7 @@ regex_compile (re_char *pattern, ptrdiff_t size, | |||
| 1760 | if (regex_emacs_debug > 0) | 1766 | if (regex_emacs_debug > 0) |
| 1761 | { | 1767 | { |
| 1762 | for (ptrdiff_t debug_count = 0; debug_count < size; debug_count++) | 1768 | for (ptrdiff_t debug_count = 0; debug_count < size; debug_count++) |
| 1763 | debug_putchar (pattern[debug_count]); | 1769 | debug_putchar (stderr, pattern[debug_count]); |
| 1764 | putc ('\n', stderr); | 1770 | putc ('\n', stderr); |
| 1765 | } | 1771 | } |
| 1766 | #endif | 1772 | #endif |
diff --git a/src/regex-emacs.h b/src/regex-emacs.h index bc357633135..d9adcc69443 100644 --- a/src/regex-emacs.h +++ b/src/regex-emacs.h | |||
| @@ -195,4 +195,8 @@ extern bool re_iswctype (int ch, re_wctype_t cc); | |||
| 195 | extern re_wctype_t re_wctype_parse (const unsigned char **strp, | 195 | extern re_wctype_t re_wctype_parse (const unsigned char **strp, |
| 196 | ptrdiff_t limit); | 196 | ptrdiff_t limit); |
| 197 | 197 | ||
| 198 | #if ENABLE_CHECKING | ||
| 199 | extern void print_compiled_pattern (FILE *dest, struct re_pattern_buffer *bufp); | ||
| 200 | #endif | ||
| 201 | |||
| 198 | #endif /* EMACS_REGEX_H */ | 202 | #endif /* EMACS_REGEX_H */ |
diff --git a/src/search.c b/src/search.c index 742a78cb0cd..014fd97d423 100644 --- a/src/search.c +++ b/src/search.c | |||
| @@ -3376,6 +3376,46 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */) | |||
| 3376 | set_buffer_internal_1 (old); | 3376 | set_buffer_internal_1 (old); |
| 3377 | return val; | 3377 | return val; |
| 3378 | } | 3378 | } |
| 3379 | |||
| 3380 | DEFUN ("re--describe-compiled", Fre__describe_compiled, Sre__describe_compiled, | ||
| 3381 | 1, 2, 0, | ||
| 3382 | doc: /* Return a string describing the compiled form of REGEXP. | ||
| 3383 | If RAW is non-nil, just return the actual bytecode. */) | ||
| 3384 | (Lisp_Object regexp, Lisp_Object raw) | ||
| 3385 | { | ||
| 3386 | struct regexp_cache *cache_entry | ||
| 3387 | = compile_pattern (regexp, NULL, | ||
| 3388 | (!NILP (BVAR (current_buffer, case_fold_search)) | ||
| 3389 | ? BVAR (current_buffer, case_canon_table) : Qnil), | ||
| 3390 | false, | ||
| 3391 | !NILP (BVAR (current_buffer, | ||
| 3392 | enable_multibyte_characters))); | ||
| 3393 | if (!NILP (raw)) | ||
| 3394 | return make_unibyte_string (cache_entry->buf.buffer, | ||
| 3395 | cache_entry->buf.used); | ||
| 3396 | else | ||
| 3397 | { /* FIXME: Why ENABLE_CHECKING? */ | ||
| 3398 | #if !ENABLE_CHECKING | ||
| 3399 | error ("Not available: rebuild with --enable-checking"); | ||
| 3400 | #elsif HAVE_OPEN_MEMSTREAM | ||
| 3401 | char *buffer = NULL; | ||
| 3402 | size_t size = 0; | ||
| 3403 | FILE* f = open_memstream (&buffer, &size); | ||
| 3404 | if (!f) | ||
| 3405 | report_file_error ("open_memstream failed", regexp); | ||
| 3406 | print_compiled_pattern (f, &cache_entry->buf); | ||
| 3407 | fclose (f); | ||
| 3408 | if (!buffer) | ||
| 3409 | return Qnil; | ||
| 3410 | Lisp_Object description = make_unibyte_string (buffer, size); | ||
| 3411 | free (buffer); | ||
| 3412 | return description; | ||
| 3413 | #else | ||
| 3414 | print_compiled_pattern (stderr, &cache_entry->buf); | ||
| 3415 | return build_string ("Description was sent to standard error"); | ||
| 3416 | #endif | ||
| 3417 | } | ||
| 3418 | } | ||
| 3379 | 3419 | ||
| 3380 | 3420 | ||
| 3381 | static void syms_of_search_for_pdumper (void); | 3421 | static void syms_of_search_for_pdumper (void); |
| @@ -3455,6 +3495,7 @@ is to bind it with `let' around a small expression. */); | |||
| 3455 | defsubr (&Smatch_data__translate); | 3495 | defsubr (&Smatch_data__translate); |
| 3456 | defsubr (&Sregexp_quote); | 3496 | defsubr (&Sregexp_quote); |
| 3457 | defsubr (&Snewline_cache_check); | 3497 | defsubr (&Snewline_cache_check); |
| 3498 | defsubr (&Sre__describe_compiled); | ||
| 3458 | 3499 | ||
| 3459 | pdumper_do_now_and_after_load (syms_of_search_for_pdumper); | 3500 | pdumper_do_now_and_after_load (syms_of_search_for_pdumper); |
| 3460 | } | 3501 | } |