ncurses 6.2 - patch 20200301
[ncurses.git] / test / tracemunch
1 #!/usr/bin/env perl
2 # $Id: tracemunch,v 1.27 2020/02/02 23:34:34 tom Exp $
3 ##############################################################################
4 # Copyright 2018-2019,2020 Thomas E. Dickey                                  #
5 # Copyright 1998-2005,2017 Free Software Foundation, Inc.                    #
6 #                                                                            #
7 # Permission is hereby granted, free of charge, to any person obtaining a    #
8 # copy of this software and associated documentation files (the "Software"), #
9 # to deal in the Software without restriction, including without limitation  #
10 # the rights to use, copy, modify, merge, publish, distribute, distribute    #
11 # with modifications, sublicense, and/or sell copies of the Software, and to #
12 # permit persons to whom the Software is furnished to do so, subject to the  #
13 # following conditions:                                                      #
14 #                                                                            #
15 # The above copyright notice and this permission notice shall be included in #
16 # all copies or substantial portions of the Software.                        #
17 #                                                                            #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   #
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    #
21 # THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    #
23 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        #
24 # DEALINGS IN THE SOFTWARE.                                                  #
25 #                                                                            #
26 # Except as contained in this notice, the name(s) of the above copyright     #
27 # holders shall not be used in advertising or otherwise to promote the sale, #
28 # use or other dealings in this Software without prior written               #
29 # authorization.                                                             #
30 ##############################################################################
31 # tracemunch -- compactify ncurses trace logs
32 #
33 # The error logs produced by ncurses with tracing enabled can be very tedious
34 # to wade through.  This script helps by compacting runs of log lines that
35 # can be conveniently expressed as higher-level operations.
36
37 use strict;
38 use warnings;
39
40 our $putattr =
41     'PutAttrChar\(\{\{ ' . "'(.)'"
42   . ' = 0[0-7]+ \}\}\) at \(([0-9]+), ([0-9]+)\)';
43 our $waddnstr =
44   'waddnstr\(0x([[:xdigit:]]+),"([^\"]+)",[0-9]+\) called \{A_NORMAL\}';
45
46 # If the trace is complete, we can infer addresses using the return value from
47 # newwin, etc.  But if it is incomplete, we can still check for special cases
48 # such as SCREEN* and WINDOW* parameters.  In this table, the type for the
49 # first parameter is encoded, relying upon an ncurses programming convention:
50 # 1 = SCREEN*
51 # 2 = WINDOW*
52 # 4 = TERMINAL*
53 our %known_p1 = qw(
54   TransformLine           1
55   _nc_freewin             2
56   _nc_initscr             1
57   _nc_makenew             1
58   _nc_mingw_console_read  1
59   _nc_reset_colors        1
60   _nc_scroll_optimize     1
61   _nc_tinfo               1
62   _nc_tinfo_mvcur         1
63   _nc_wgetch              2
64   adjust_window           2
65   assume_default_colors   1
66   attr_get                2
67   baudrate                1
68   beep                    1
69   border_set              2
70   box                     2
71   box_set                 2
72   can_change_color        1
73   cbreak                  1
74   clearok                 2
75   color_content           1
76   copywin                 2
77   curs_set                1
78   decrease_size           1
79   def_prog_mode           1
80   def_shell_mode          1
81   define_key              1
82   del_curterm             1
83   delay_output            1
84   delscreen               1
85   delwin                  2
86   derwin                  2
87   doupdate                1
88   dupwin                  2
89   echo                    1
90   endwin                  1
91   erasechar               1
92   filter                  1
93   flash                   1
94   flushinp                1
95   getattrs                2
96   getbegx                 2
97   getbegy                 2
98   getbkgd                 2
99   getcurx                 2
100   getcury                 2
101   getmaxx                 2
102   getmaxy                 2
103   getmouse                1
104   getparx                 2
105   getpary                 2
106   halfdelay               1
107   has_ic                  1
108   has_il                  1
109   has_key                 1
110   idcok                   2
111   idlok                   2
112   immedok                 2
113   increase_size           1
114   init_color              1
115   init_pair               1
116   intrflush               1
117   is_cleared              2
118   is_idcok                2
119   is_idlok                2
120   is_immedok              2
121   is_keypad               2
122   is_leaveok              2
123   is_linetouched          2
124   is_nodelay              2
125   is_notimeout            2
126   is_pad                  2
127   is_scrollok             2
128   is_subwin               2
129   is_syncok               2
130   is_term_resized         1
131   is_wintouched           2
132   key_defined             1
133   keybound                1
134   keyok                   1
135   keypad                  2
136   killchar                1
137   leaveok                 2
138   longname                1
139   meta                    2
140   mouseinterval           1
141   mousemask               1
142   mvcur                   1
143   mvderwin                2
144   mvwadd_wch              2
145   mvwadd_wchnstr          2
146   mvwadd_wchstr           2
147   mvwaddch                2
148   mvwaddchnstr            2
149   mvwaddchstr             2
150   mvwaddnstr              2
151   mvwaddnwstr             2
152   mvwaddstr               2
153   mvwaddwstr              2
154   mvwchgat                2
155   mvwdelch                2
156   mvwget_wch              2
157   mvwget_wstr             2
158   mvwgetch                2
159   mvwgetn_wstr            2
160   mvwgetnstr              2
161   mvwgetstr               2
162   mvwhline                2
163   mvwhline_set            2
164   mvwin                   2
165   mvwin_wch               2
166   mvwin_wchnstr           2
167   mvwin_wchstr            2
168   mvwinch                 2
169   mvwinchnstr             2
170   mvwinchstr              2
171   mvwins_nwstr            2
172   mvwins_wch              2
173   mvwins_wstr             2
174   mvwinsch                2
175   mvwinsnstr              2
176   mvwinsstr               2
177   mvwinstr                2
178   mvwinwstr               2
179   mvwvline                2
180   mvwvline_set            2
181   newpad                  1
182   newterm                 1
183   newwin                  1
184   nl                      1
185   nocbreak                1
186   nodelay                 2
187   noecho                  1
188   nofilter                1
189   nonl                    1
190   noqiflush               1
191   noraw                   1
192   notimeout               2
193   overlap                 2
194   overlay                 2
195   overwrite               2
196   pair_content            1
197   pecho_wchar             2
198   pechochar               2
199   pnoutrefresh            2
200   putwin                  2
201   qiflush                 1
202   raw                     1
203   redrawwin               2
204   reset_prog_mode         1
205   reset_shell_mode        1
206   resetty                 1
207   resize_term             1
208   resizeterm              1
209   restartterm             1
210   ripoffline              1
211   savetty                 1
212   scr_init                1
213   scr_restore             1
214   scr_set                 1
215   scroll                  2
216   scrollok                2
217   set_curterm             4
218   set_term                1
219   slk_attr                1
220   slk_attr_set            1
221   slk_attroff             1
222   slk_attron              1
223   slk_attrset             1
224   slk_clear               1
225   slk_color               1
226   slk_init                1
227   slk_label               1
228   slk_noutrefresh         1
229   slk_refresh             1
230   slk_restore             1
231   slk_set                 1
232   slk_touch               1
233   start_color             1
234   subwin                  2
235   syncok                  2
236   termattrs               1
237   termname                1
238   tgetflag                1
239   tgetnum                 1
240   tigetflag               1
241   tigetnum                1
242   tigetstr                1
243   tinfo                   1
244   touchline               2
245   touchwin                2
246   typeahead               1
247   unget_wch               1
248   ungetch                 1
249   ungetmouse              1
250   untouchwin              2
251   use_default_colors      1
252   use_env                 1
253   use_legacy_coding       1
254   use_screen              1
255   use_tioctl              1
256   use_window              2
257   vidattr                 1
258   vidputs                 1
259   vw_printw               2
260   vwprintw                2
261   wadd_wch                2
262   wadd_wchnstr            2
263   wadd_wchstr             2
264   waddch                  2
265   waddchnstr              2
266   waddchstr               2
267   waddnstr                2
268   waddnwstr               2
269   waddstr                 2
270   waddwstr                2
271   wattr_get               2
272   wattr_off               2
273   wattr_on                2
274   wattr_set               2
275   wattroff                2
276   wattron                 2
277   wattrset                2
278   wbkgd                   2
279   wbkgdset                2
280   wborder                 2
281   wborder_set             2
282   wchgat                  2
283   wclear                  2
284   wclrtobot               2
285   wclrtoeol               2
286   wcolor_set              2
287   wcursyncup              2
288   wdelch                  2
289   wdeleteln               2
290   wechochar               2
291   wenclose                2
292   werase                  2
293   wget_wch                2
294   wget_wstr               2
295   wgetbkgrnd              2
296   wgetch                  2
297   wgetch_events           2
298   wgetdelay               2
299   wgetn_wstr              2
300   wgetnstr                2
301   wgetparent              2
302   wgetscrreg              2
303   wgetstr                 2
304   whline                  2
305   whline_set              2
306   win_wch                 2
307   win_wchnstr             2
308   win_wchstr              2
309   winch                   2
310   winchnstr               2
311   winchstr                2
312   winnstr                 2
313   winnwstr                2
314   wins_nwstr              2
315   wins_wch                2
316   wins_wstr               2
317   winsch                  2
318   winsdelln               2
319   winsertln               2
320   winsnstr                2
321   winsstr                 2
322   winstr                  2
323   winwstr                 2
324   wmouse_trafo            2
325   wmove                   2
326   wnoutrefresh            2
327   wprintw                 2
328   wredrawln               2
329   wrefresh                2
330   wresize                 2
331   wscrl                   2
332   wsetscrreg              2
333   wstandend               2
334   wstandout               2
335   wsyncdown               2
336   wsyncup                 2
337   wtimeout                2
338   wtouchln                2
339   wvline                  2
340 );
341
342 our $scr_nums = 0;
343 our $thr_nums = 0;
344 our $trm_nums = 0;
345 our $try_nums = 0;
346 our $win_nums = 0;
347 our $curscr   = "";
348 our $newscr   = "";
349 our $stdscr   = "";
350 our %scr_addr;
351 our %thr_addr;
352 our %trm_addr;
353 our %try_addr;
354 our %win_addr;
355
356 sub has_addr($) {
357     my $value  = shift;
358     my $result = 0;
359     $result = 1 if ( $value =~ /\b0x[[:xdigit:]]+\b/i );
360     return $result;
361 }
362
363 sub transaddr($) {
364     my $arg = shift;
365     my $n;
366
367     $arg =~ s/\b$curscr\b/curscr/g if ($curscr);
368     $arg =~ s/\b$newscr\b/newscr/g if ($newscr);
369     $arg =~ s/\b$stdscr\b/stdscr/g if ($stdscr);
370     if ( &has_addr($arg) ) {
371         foreach my $addr ( keys %scr_addr ) {
372             $n = $scr_addr{$addr};
373             $arg =~ s/\b$addr\b/screen$n/g if ( defined $n );
374         }
375     }
376     if ( &has_addr($arg) ) {
377         foreach my $addr ( keys %thr_addr ) {
378             $n = $thr_addr{$addr};
379             $arg =~ s/\b$addr\b/thread$n/g if ( defined $n );
380         }
381     }
382     if ( &has_addr($arg) ) {
383         foreach my $addr ( keys %trm_addr ) {
384             $n = $trm_addr{$addr};
385             $arg =~ s/\b$addr\b/terminal$n/g if ( defined $n );
386         }
387     }
388     if ( &has_addr($arg) ) {
389         foreach my $addr ( keys %try_addr ) {
390             $n = $try_addr{$addr};
391             $arg =~ s/\b$addr\b/tries_$n/g if ( defined $n );
392         }
393     }
394     if ( &has_addr($arg) ) {
395         foreach my $addr ( keys %win_addr ) {
396             $n = $win_addr{$addr};
397             $arg =~ s/\b$addr\b/window$n/g if ( defined $n );
398         }
399     }
400     if ( &has_addr($arg) ) {
401         if ( $arg =~ /add_wch\((window\d+,)?0x[[:xdigit:]]+\)/i ) {
402             $arg =~ s/(0x[[:xdigit:]]+)[)]/\&wch)/i;
403         }
404         elsif (
405             $arg =~ /color_content\((screen\d+,)?\d+(,0x[[:xdigit:]]+){3}/i )
406         {
407             $arg =~ s/(,0x[[:xdigit:]]+){3}[)]/,\&r,\&g,\&b)/i;
408         }
409         elsif ( $arg =~ /pair_content\((screen\d+,)?\d+(,0x[[:xdigit:]]+){2}/i )
410         {
411             $arg =~ s/(,0x[[:xdigit:]]+){2}[)]/,\&fg,\&bg)/i;
412         }
413     }
414     if ( &has_addr($arg) and $arg =~ /called\s+\{/ ) {
415         my $func = $arg;
416         chomp $func;
417         $func =~ s/^.*called\s+\{([[:alnum:]_]+)\(.*$/$1/;
418         if ( defined $known_p1{$func} ) {
419             my $addr = $arg;
420             my $type = $known_p1{$func};
421             chomp $addr;
422             $addr =~ s/^[^(]+\((0x[[:xdigit:]]+).*/$1/i;
423             if ( $type == 1 ) {
424                 $scr_addr{$addr} = ++$scr_nums;
425                 $arg = &transaddr($arg);
426             }
427             elsif ( $type == 2 ) {
428                 $win_addr{$addr} = ++$win_nums;
429                 $arg = &transaddr($arg);
430             }
431             elsif ( $type == 4 ) {
432                 $trm_addr{$addr} = ++$trm_nums;
433                 $arg = &transaddr($arg);
434             }
435         }
436     }
437
438     return $arg;
439 }
440
441 sub muncher($) {
442     my $STDIN = shift;
443
444     while (<$STDIN>) {
445         my $addr;
446         my $n;
447         my $awaiting = "";
448
449       CLASSIFY: {
450
451             # just in case someone tries a file with cr/lf line-endings:
452             $_ =~ s/\r\n/\n/g;
453             $_ =~ s/\r/\n/g;
454
455             my $thread = "";
456             if ( $_ =~ /^(0x[[:xdigit:]]+):/ ) {
457                 $thr_addr{$1} = ++$thr_nums unless defined $thr_addr{$1};
458                 $thread = "thread" . $thr_addr{$1} . ":";
459                 $_ =~ s/^[^:]*://;
460             }
461
462             # Transform window pointer addresses so it's easier to compare logs
463             $awaiting = "curscr" if ( $_ =~ /creating curscr/ );
464             $awaiting = "newscr" if ( $_ =~ /creating newscr/ );
465             $awaiting = "stdscr" if ( $_ =~ /creating stdscr/ );
466             $awaiting = "screen" if ( $_ =~ /^(\+ )*called \{new_prescr\(\)/ );
467             if ( $_ =~ /^create :window 0x([[:xdigit:]]+)/ ) {
468                 $addr = "0x$1";
469                 if ( $awaiting eq "curscr" ) {
470                     $curscr = $addr;
471                 }
472                 elsif ( $awaiting eq "newscr" ) {
473                     $newscr = $addr;
474                 }
475                 elsif ( $awaiting eq "stdscr" ) {
476                     $stdscr = $addr;
477                 }
478                 else {
479                     $win_addr{$addr} = $win_nums++;
480                 }
481                 $awaiting = "";
482             }
483             elsif ( $_ =~ /^(\+ )*called \{set_curterm\((0x[[:xdigit:]]+)\)/ ) {
484                 $trm_addr{$2} = ++$trm_nums unless defined $trm_addr{$2};
485             }
486             elsif ( $_ =~ /^(\+ )*called \{_nc_add_to_try\((0x[[:xdigit:]]+),/ )
487             {
488                 $try_addr{$2} = ++$try_nums unless defined $try_addr{$2};
489             }
490             elsif ( $_ =~ /^(\+ )*_nc_alloc_screen_sp 0x([[:xdigit:]]+)/ ) {
491                 $addr = "0x$2";
492                 $scr_addr{$addr} = ++$scr_nums unless ( $scr_addr{$addr} );
493                 $awaiting = "";
494             }
495             elsif ( $_ =~ /^(\+ )*return }0x([[:xdigit:]]+)/ ) {
496                 $addr = "0x$2";
497                 if ( $awaiting eq "screen" ) {
498                     $scr_addr{$addr} = ++$scr_nums unless ( $scr_addr{$addr} );
499                 }
500             }
501             elsif ( $_ =~ /^\.\.\.deleted win=0x([[:xdigit:]]+)/ ) {
502                 $addr = "0x$1";
503                 $_    = &transaddr($_);
504                 if ( $addr eq $curscr ) {
505                     $curscr = "";
506                 }
507                 elsif ( $addr eq $newscr ) {
508                     $newscr = "";
509                 }
510                 elsif ( $addr eq $stdscr ) {
511                     $stdscr = "";
512                 }
513                 else {
514                     undef $win_addr{$addr};
515                 }
516             }
517
518             # Compactify runs of PutAttrChar calls (TR_CHARPUT)
519             if ( $_ =~ /$putattr/ ) {
520                 my $putattr_chars = $1;
521                 my $starty        = $2;
522                 my $startx        = $3;
523                 while (<$STDIN>) {
524                     if ( $_ =~ /$putattr/ ) {
525                         $putattr_chars .= $1;
526                     }
527                     else {
528                         last;
529                     }
530                 }
531                 print
532 "RUN of PutAttrChar()s: \"$putattr_chars\" from ${starty}, ${startx}\n";
533                 redo CLASSIFY;
534             }
535
536             # Compactify runs of waddnstr calls (TR_CALLS)
537             if ( $_ =~ /$waddnstr/ ) {
538                 my $waddnstr_chars = $2;
539                 my $winaddr        = $1;
540                 while (<$STDIN>) {
541                     if ( $_ =~ /$waddnstr/ && $1 eq $winaddr ) {
542                         $waddnstr_chars .= $2;
543                     }
544                     else {
545                         last;
546                     }
547                 }
548                 my $winaddstr = &transaddr($winaddr);
549                 print "RUN of waddnstr()s: $winaddr, \"$waddnstr_chars\"\n";
550                 redo CLASSIFY;
551             }
552
553             # More transformations can go here
554
555             # Repeated runs of anything
556             my $anyline     = &transaddr($_);
557             my $repeatcount = 1;
558             while (<$STDIN>) {
559                 if ( &transaddr($_) eq $anyline ) {
560                     $repeatcount++;
561                 }
562                 else {
563                     last;
564                 }
565             }
566             if ( $repeatcount > 1 ) {
567                 print "${repeatcount} REPEATS OF $anyline";
568             }
569             else {
570                 print $thread . $anyline;
571             }
572             redo CLASSIFY if $_;
573
574         }    # :CLASSIFY
575     }
576 }
577
578 if ( $#ARGV >= 0 ) {
579     while ( $#ARGV >= 0 ) {
580         my $file = shift @ARGV;
581         open my $ifh, "<", $file or die $!;
582         &muncher($ifh);
583     }
584 }
585 else {
586     &muncher( \*STDIN );
587 }
588
589 # tracemunch ends here