2063 lines
71 KiB
Raku
Executable File
2063 lines
71 KiB
Raku
Executable File
################################################################################################################
|
|
# gSTLFilt.pl: BD Software STL Error Message Decryptor (a Perl script)
|
|
# This version supports the gcc 2/3/4 C++ compiler/library
|
|
# It was tested under:
|
|
# DJGPP 2.95.2
|
|
# MinGW gcc 2.95.2, 3.2.3, 3.4.5, 4.1.1
|
|
# TDM gcc 4.2.2
|
|
#
|
|
|
|
$STLFilt_ID = "BD Software STL Message Decryptor v3.10 for gcc 2/3/4";
|
|
|
|
#
|
|
# (c) Copyright Leor Zolman 2002-2008. Permission to copy, use, modify, sell and
|
|
# distribute this software is granted provided this copyright notice appears
|
|
# in all copies. This software is provided "as is" without express or implied
|
|
# warranty, and with no claim as to its suitability for any purpose.
|
|
#
|
|
#################################################################################################################
|
|
# Visit www.bdsoft.com for information about BD Software's on-site training seminars #
|
|
# in C, C++, STL, Perl, Unix Fundamentals and Korn Shell Programming #
|
|
#################################################################################################################
|
|
#
|
|
# For quick installation instructions for the STL Error Decryptor, see QUICKSTART.txt.
|
|
# For manifest and other general information, see README.txt
|
|
#
|
|
# (Note: hard tab setting for this source file is: 4)
|
|
#
|
|
# Purpose: Transform STL template-based typenames from gcc error messages
|
|
# into a minimal, *readable* format. We might lose some details...
|
|
# but retain our sanity!
|
|
#
|
|
# This script may be used in several different ways:
|
|
# 1) With the "Proxy C++" program, C++.EXE (from the command-line or from within Dev-CPP)
|
|
# 2) With a batch/shell script driver for command-line use...
|
|
# For Windows: The companion batch file GFILT.BAT is provided as a sample driver for this script
|
|
# For Unix/Linux/OS X: The companion shell script "gfilt" is provided as a sample driver for
|
|
# this script, allowing arbitrary intermixing of compiler and Decryptor options
|
|
# on the command line.
|
|
#
|
|
# Acknowledgements:
|
|
# Scott Meyers taught his "Effective STL" seminar, where the project began.
|
|
# Thomas Becker wrote and helps me maintain the Win32 piping code used throughout both C++.CPP and
|
|
# the Perl scripts, keeping everyone talking despite all the curves thrown him (so far) by
|
|
# ActiveState and Microsoft. THANK YOU, Thomas!
|
|
# David Abrahams designed the long-typename-wrapping algorithm and continues to contribute actively
|
|
# to its evolution.
|
|
# David Smallberg came up with the "Proxy compiler" idea (but blame me for the name).
|
|
#
|
|
# For the complete list of folks whose feedback and de-bugging help contributed to this
|
|
# package, and also for the list of programming courses BD Software offers, see README.txt.
|
|
#
|
|
#
|
|
#################################################################################################################
|
|
#
|
|
# Script Options
|
|
# --------------
|
|
#
|
|
# Command line options are case insensitive, and may be preceded by either '-' or '/'.
|
|
# The Proxy C++, if being used, supplies many of these options as per settings in the
|
|
# Proxy-gcc.INI configuration file.
|
|
#
|
|
# Note that some of the Decryptor's behavior is controlled via command-line options,
|
|
# while other behavior may only be configured via hard-wired variable settings. Please
|
|
# examine the entire "User-Configurable Settings" section below to become familiar with
|
|
# all the customizable features.
|
|
#
|
|
# General options:
|
|
#
|
|
# -iter:x Set iterator policy to x, where x is s[short], m[edium] or l[ong]
|
|
# (See the assignments of $def_iter_policy and $newiter below for details)
|
|
#
|
|
# -cand:x Set "candidates" policy to x, where x is L[ong], M[edium] or S[hort]
|
|
# (See the assignment of $def_cand_policy below for details)
|
|
#
|
|
# -hdr:x Set STL header policy to x or nn, where x is L[ong], M[edium], or S[hort],
|
|
# -hdr:nn or nn is the # of errors to show in a cluster
|
|
# -hdr:LD Dave Abrahams re-ordering mode 1 (see below)
|
|
# -hdr:LD1 save as above
|
|
# -hdr:LD2 Dave Abrahams re-ordering mode 2
|
|
# (See the assignment of $def_hdr_policy below for details)
|
|
#
|
|
# -with:x Set "with clause" substitution policy to x, where x is L[ong] or S[hort]
|
|
# (See the assignment of $def_with_policy below for details)
|
|
#
|
|
# -path:x Set "show long pathnames" policy to x, where x is l[ong] or s[hort]
|
|
# (See the assignment of $def_path_policy below for details)
|
|
#
|
|
# -showback:x Set backtrace policy: Y (default) or N (suppress all backtrace lines)
|
|
#
|
|
# -width:nn Set output line width (break message lines at this column, or 0 for NO wrapping)
|
|
#
|
|
# -lognative Log all native messages to NativeLog.txt (for de-bugging)
|
|
#
|
|
# -banner:x Show Decryptor banner line: Y (default) or N
|
|
#
|
|
# -nullarg:xxx Add xxx to the list of "null argument" typenames that get stripped from the
|
|
# trailing portion of template argument lists. (See also the initializations of
|
|
# variable @nullargs). xxx must be fully qualified (including namespace).
|
|
#
|
|
# if xxx is 'clear', the null argument list is emptied; subsequent -nullarg
|
|
# specification appearing on the command line will work, but not the defaults
|
|
# as per the initialization of @nullargs below (unless they're re-specified
|
|
# using the -nullarg option later on the commmad line.)
|
|
#
|
|
# Options supporting long typename wrapping:
|
|
#
|
|
# (Note: If output width is set to 0, line wrapping is disabled and the
|
|
# following options have NO EFFECT)
|
|
#
|
|
# -break:x Break algorithm: D[ave Abrahams] (default) or P[lain]
|
|
# The "Dave" option wraps long complex typenames in a way that
|
|
# makes it easier to see parameter lists at various nesting depths.
|
|
#
|
|
# -cbreak:x Comma break: B = break before commas (default), A = break after
|
|
# [applies only in -break:D mode]
|
|
#
|
|
# -closewrap:x Wrap before unmatched closing delimiters: Y (default) or N
|
|
# [applies only in -break:D mode]
|
|
#
|
|
# -meta:x Configure for metaprogramming [Y] or vanilla wrapping [N] as follows:
|
|
#
|
|
# -meta:y (or just -meta) forces -break:D, and forces -cbreak and
|
|
# -closewrap options according to values specified in the $meta_y_cbreak
|
|
# and $meta_y_closewrap variable initializations, respectively.
|
|
#
|
|
# -meta:n forces -break:P (-cbreak and -closewrap don't apply)
|
|
#
|
|
# In either case, if the output width hasn't yet been set to a non-zero
|
|
# value, it is set to 80 (choosing a wrapping flavor makes no sense
|
|
# with wrapping disabled); this may be overridden by a subsequent -width
|
|
# option.
|
|
#
|
|
# Note: If no -meta option is present, the default values for -break,
|
|
# -cbreak and -closewrap are determined by the user-configurable
|
|
# settings of $break_algorithm, $comma_wrap and $close_wrap below.
|
|
#
|
|
# Note also that -meta is not configurable from the INI files, because
|
|
# it is intended as a command-line "override" mechanism. The individual
|
|
# settings of -break, -cbreak and -closewrap, however, *are* (and apply
|
|
# only when the /meta option is not used.)
|
|
#
|
|
#################################################################################################################
|
|
# User-configurable settings (use UPPER CASE ONLY for all alphabetics here (except $newiter):
|
|
#
|
|
####################################################################################
|
|
# The following twelve settings may be overridden by options on
|
|
# the command line (either explicitly, or when conveyed by the
|
|
# Proxy C++ from settings in Proxy-gcc.INI):
|
|
|
|
# default iterator policy (/iter:x option):
|
|
$def_iter_policy = 'L'; # 'L' (Long): NEVER remove iterator type name qualification
|
|
# 'M' (Medium): USUALLY remove iterator type name qualification
|
|
# leave intact when iter type may be significant
|
|
# to the diagnostic
|
|
# 'S' (Short): ALWAYS remove iterator type name qualification
|
|
|
|
$def_cand_policy = 'L'; # default candidate policy (/cand:x option):
|
|
# 'L' (long): Retain candidate list (same as: 'Y')
|
|
# 'M' (medium): Suppress candidates, but tell how many were suppressed
|
|
# 'S' (short): completely ignore candidate list (same as: 'N')
|
|
|
|
$def_hdr_policy = 'LD2'; # default standard header messages policy (/hdr:x option):
|
|
# 'L' (long): Retain all messages referring to standard header files (same as 'Y')
|
|
# 'M' (medium): Retain only the first $headers_to_show messages in each cluster
|
|
# 'S' (short): Discard all messages referring to standard header files (same as 'N')
|
|
# 'LD[1]' (long, Dave Abrahams re-ordering mode 1):
|
|
# actual error msg moves to front of instantiation backtrace
|
|
# 'LD2' (long, Dave Abrahams re-ordering mode 2):
|
|
# as above, with trigger line duplicated before the backtrace
|
|
|
|
$def_with_policy = 'S'; # default "with clause" substitution policy (/with:x option):
|
|
# 'L' (long): Do NOT substitute in template parameters in "with" clauses
|
|
# 'S' (short): Do substitute template parameters in "with" clauses
|
|
|
|
$def_path_policy = 'S'; # default long path policy (/path:x option):
|
|
# 'L' (long): Retain entire pathname in all cases (same as 'Y')
|
|
# 'S' (short): Discard all except base name from pathnames (same as 'N')
|
|
# [NOTE: Use L if you rely upon your IDE to locate errors in source files]
|
|
|
|
$def_hdrs_to_show = 1; # Default number of header messages to show for 'M' header policy
|
|
|
|
$banner = 'N'; # Show banner with Decryptor ID by default (/banner option)
|
|
|
|
$break_algorithm = 'D'; # P[lain] or D[ave Abrahams] line-breaking algorithm (/break:x option)
|
|
# (Note: line-breaking of any kind happens only if $output_width is non-zero)
|
|
|
|
$comma_wrap = 'B'; # wrap lines B[efore] or A[fter] commas. (/cbreak:x option)
|
|
# (Applies in Dave mode only.)
|
|
|
|
$close_wrap = 'Y'; # Force a break before close delimiters
|
|
# whose open is not on the same line (/closewrap:x option)
|
|
# (Applies in Dave mode only.)
|
|
|
|
$output_width = 80; # wrap at 80 columns by default (/width:nn option)
|
|
|
|
$show_backtraces = 'Y'; # show (Y) or suppress (N) backtrace messages (/showback:x option)
|
|
|
|
|
|
#####################################################################################
|
|
# The remaining settings are controlled strictly by their assigned
|
|
# value below (no corresponding command-line options offered):
|
|
|
|
$newiter = 'iter'; # ('iter' or 'IT' or...) shorten the word "iterator" to this
|
|
# Note: /iter:L forces $newiter to be 'iterator' (no filtering)
|
|
|
|
$tabsize = 4; # number of chars to incrementally indent lines
|
|
|
|
$advise_re_policy_opts = 1; # remind folks they can use /hdr:L and /cand:L to see more message details
|
|
|
|
$nix_only_once = 1; # suppress "undefined identifiers shown only once..." messages
|
|
|
|
$reformat_linenumbers = 0; # 1 to reformat lines numbers to LZ's preferred style (may conflict with
|
|
# cursor-placement mechanisms in some editors/IDE's)
|
|
|
|
$smush_amps_and_stars = 0; # 1 leaves asterisks/ampersands adjacent to preceding identifiers;
|
|
# 0 inserts a space between
|
|
|
|
$space_after_commas = 0; # 1 to force spaces after commas, 0 not to
|
|
|
|
$meta_y_cbreak = 'B'; # /meta:y forces this value for cbreak
|
|
$meta_y_closewrap = 'Y'; # /meta:y forces this values for closewrap
|
|
|
|
$wrap_own_msgs = 0; # wrap STL Decryptor messages to same output width
|
|
# as errors (1) or don't (0)
|
|
|
|
$keep_stdns = 0; # 0 to remove "std::" and related prefixes, 1 to retain them.
|
|
# NOTE: if set to 1, STL-related filtering will *not* work (for now). This option
|
|
# is designed for use in conjunction with /break:D to retain maximum detail in
|
|
# metaprogramming-style messages, rather than for use with STL library messages.
|
|
|
|
$show_internal_err = 1; # If set to 0, suppresses delimiter mismatch errors. Please leave at 1,
|
|
# and contact me as per the emitted instructions in the case of an
|
|
# internal error.
|
|
|
|
# default list of names of trailing type names to be stripped from the end of
|
|
# argument lists (the -nullarg:xxx command line option allows additional names to
|
|
# be added to the list, or for the these default ones to be cleared out):
|
|
|
|
@nullargs = qw(boost::tuples::null_type mpl_::void_ mpl_::na boost::detail::variant::void\d+);
|
|
# (Designed primarly for use with boost libraries tuple, mpl, etc...)
|
|
|
|
#@nullargs = qw(); # to totally disable the null args stripping feature by default, uncomment this
|
|
# line and comment out the initialization of @nullargs above.
|
|
|
|
|
|
#
|
|
# END of user-configurable settings (change anything below here AT YOUR OWN RISK.)
|
|
#################################################################################################################
|
|
|
|
|
|
$| = 1; # force output buffer flush after every line
|
|
|
|
$iter_policy = $def_iter_policy; # default iterator policy
|
|
|
|
$dave_move = 0; # true for /hdr:LD1
|
|
$dave_rep = 0; # true for /hdr:LD2
|
|
$in_backtrace = 0; # not processing a backtrace right now
|
|
|
|
if ("\u$def_hdr_policy" =~ 'LD[12]?')
|
|
{
|
|
$dave_move = 1;
|
|
$dave_rep = 0;
|
|
$dave_rep = 1 if "\u$def_hdr_policy" eq 'LD2';
|
|
$def_hdr_policy = 'L';
|
|
}
|
|
|
|
$header_policy = $def_hdr_policy; # default std. header message policy
|
|
$with_policy = $def_with_policy; # default "with clause" substitution policy
|
|
$headers_to_show = $def_hdrs_to_show; # number of headers to show for 'M' header policy
|
|
$candidate_policy = $def_cand_policy; # default candidate policy (gcc only)
|
|
$pathname_policy = $def_path_policy; # default pathname policy (gcc only)
|
|
|
|
$lognative = 0; # by default, not logging native messages
|
|
$suppressed_headers = 0; # true when we've suppressed at least one stdlib header
|
|
$suppressed_candidates = 0; # true when we've suppressed at least one template candidate
|
|
|
|
$pdbg = 0; # true to show print trace
|
|
$wrapdbg = 0; # de-bug wrap loop
|
|
$movedbg = 0; # de-bug Dave mode reordering
|
|
$delimdbg = 0; # de-bug /wrap:D mode delimiter parsing
|
|
$optdbg = 0; # show value of all command-line modfiable options
|
|
$choked = 0; # haven't choked yet with an internal error
|
|
|
|
|
|
sub scanback;
|
|
sub println;
|
|
sub print2;
|
|
sub break_and_print;
|
|
sub break_and_print_plain;
|
|
sub break_and_println_plain;
|
|
sub break_and_print_fragment;
|
|
sub lognative_header;
|
|
sub showkey;
|
|
|
|
|
|
# Little hack to avoid "Exiting subroutine via next" warnings on internal error:
|
|
sub NoWarn
|
|
{
|
|
$msg = shift (@_);
|
|
print "$msg" if $msg !~ /Exiting subroutine via next/;
|
|
}
|
|
|
|
$SIG{__WARN__} = "NoWarn";
|
|
|
|
@save_args = @ARGV; # lognative_header uses this
|
|
|
|
while (@ARGV) # process command-line options
|
|
{
|
|
if ($ARGV[0] =~ /^[\/-]iter:([SML])[A-Z]*$/i) # allow command-line iterator policy
|
|
{ # specification of form: /iter:x
|
|
print "$ARGV[0] " if $optdbg;
|
|
$iter_policy = "\u$1";
|
|
$newiter = 'iterator' if $iter_policy eq 'L';
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]cand:([YNSML])[A-Z]*$/i) # allow candidate policy
|
|
{ # specification of form: /cand:x
|
|
print "$ARGV[0] " if $optdbg;
|
|
$candidate_policy = "\u$1";
|
|
$candidate_policy =~ tr/NY/SL/;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]with:([YNSL])[A-Z]*$/i) # allow with clause policy
|
|
{ # specification of form: /with:x
|
|
print "$ARGV[0] " if $optdbg;
|
|
$with_policy = "\u$1";
|
|
$with_policy =~ tr/NY/LS/;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]hdr:L(D[12]?)$/i) # detect special "Dave Abrahams" header policy
|
|
{ # specifications of form: /hdr:LD /hdr:LD1 /hdr:LD2
|
|
print "$ARGV[0] " if $optdbg;
|
|
$header_policy = "L";
|
|
$dave_move = 1; # moving error line to before the trace
|
|
$dave_rep = 0;
|
|
$dave_rep = 1 if "\u$1" eq "D2"; # replicating trigger line
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]hdr:([YNSML])[a-ce-z]*$/i) # allow standard header policy
|
|
{ # specification of form: /hdr:x
|
|
print "$ARGV[0] " if $optdbg;
|
|
$header_policy = "\u$1";
|
|
$header_policy =~ tr/NY/SL/;
|
|
$headers_to_show = 0 if $header_policy eq 'S';
|
|
$dave_move = 0;
|
|
$dave_rep = 0;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]hdr:(\d+)/i) # allow standard header policy
|
|
{ # specification of form: /hdr:nn
|
|
print "$ARGV[0] " if $optdbg;
|
|
$header_policy = 'M';
|
|
$headers_to_show = $1;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]path:([SL])[A-Z]*$/i) # allow pathname policy
|
|
{ # specification of form: /path:x
|
|
print "$ARGV[0] " if $optdbg;
|
|
$pathname_policy = "\u$1";
|
|
$pathname_policy =~ tr/NY/SL/;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]banner:?([YN]?)[A-Z]*$/i) # banner:Y or N
|
|
{ # (just "/banner" means Y)
|
|
print "$ARGV[0] " if $optdbg;
|
|
$banner = "\u$1";
|
|
$banner = 'Y' if $banner eq "";
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]showback:?([YN]?)[A-Z]*$/i) # showback:Y or N
|
|
{ # (just "/showback" means Y)
|
|
print "$ARGV[0] " if $optdbg;
|
|
$show_backtraces = "\u$1";
|
|
$show_backtraces = 'Y' if $show_backtraces eq "";
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]width:(\d+)/i) # allow line output width spec
|
|
{ # of form: /width:n
|
|
print "$ARGV[0] " if $optdbg;
|
|
$output_width = $1;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]break:([DP])[A-Z]*$/i) # break: D or P
|
|
{
|
|
print "$ARGV[0] " if $optdbg;
|
|
$break_algorithm = "\u$1";
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]cbreak:([AB])[A-Z]*$/i) # comma break: B or A
|
|
{
|
|
print "$ARGV[0] " if $optdbg;
|
|
$comma_wrap = "\u$1";
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]closewrap:?([YN]?)[A-Z]*$/i) # closewrap:Y or N
|
|
{ # (just "/closewrap" means Y)
|
|
print "$ARGV[0] " if $optdbg;
|
|
$close_wrap = "\u$1";
|
|
$close_wrap = 'Y' if $close_wrap eq "";
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]nullarg:(.*)/i) # add to list of "null arg" identifiers
|
|
{
|
|
print "$ARGV[0] " if $optdbg;
|
|
if ($1 =~ /^clear$/i)
|
|
{
|
|
@nullargs = (); # "clear" means clear out null arg list
|
|
}
|
|
else
|
|
{
|
|
push @nullargs, $1; # any other name is appened to list
|
|
}
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
|
|
if ($ARGV[0] =~ /^[\/-]meta:?([YN]?)[A-Z]*$/i) # meta:Y or N
|
|
{ # (just "/meta" means Y)
|
|
if ("\u$1" =~ /^N/)
|
|
{
|
|
$break_algorithm = 'P';
|
|
}
|
|
else
|
|
{
|
|
$break_algorithm = 'D';
|
|
$comma_wrap = $meta_y_cbreak;
|
|
$close_wrap = $meta_y_closewrap;
|
|
}
|
|
$output_width = 80 if $output_width == 0;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
if ($ARGV[0] =~ /^[\/-]lognative/i) # allow log native msgs option
|
|
{ # of form: /lognative
|
|
print "$ARGV[0] " if $optdbg;
|
|
$lognative = 1;
|
|
shift;
|
|
next;
|
|
}
|
|
|
|
println "Warning: unrecognized gSTLFilt2.pl command line option: $ARGV[0]\n";
|
|
shift;
|
|
}
|
|
|
|
# List of "standard" header files names:
|
|
|
|
@keywords = qw(algo algorithm algobase bitset cassert cctype cerrno cfloat ciso646
|
|
climits clocale cmath complex csetjmp csignal cstdarg stdarg cstddef stddef
|
|
cstdio stdio cstdlib stdlib cstring ctime time cwchar cwtype cxxabi deque editbuf exception exception_defines
|
|
fstream fstream.h functional hashtable hash_map hash_set heap iomanip
|
|
ios iosfwd iostream iostream istream iterator limits list locale
|
|
map memory new new numeric ostream queue rope set slist
|
|
pair sstream stack stdexcept streambuf streambuf_iterator string
|
|
strstream strstream stream_iterator typeinfo utility valarray vector
|
|
basic_ios basic_string boost_concept_check char_traits codecvt concept_check
|
|
cpp_type_traits fpos functexcept generic_shadow gslice gslice_array indirect_array
|
|
ios_base localefwd stringfwd locale_facets mask_array pthread_allocimpl slice slice_array
|
|
type_traits valarray_array valarray_meta bastring complext fcomplex ldcomplex
|
|
std_valarray straits strfile tempbuf alloc floatio math
|
|
array random regex type_traits tuple unordered_map unordered_set
|
|
cfenv cinttypes cstdbool cstdint ctgmath
|
|
);
|
|
|
|
|
|
# Put 'em in a hash for rapid searching:
|
|
|
|
for (@keywords)
|
|
{
|
|
$keywords{$_}++;
|
|
}
|
|
|
|
|
|
print "\n" if $optdbg;
|
|
$tab = " " x $tabsize;
|
|
|
|
print "\n\n" . ("=" x $output_width) . "\n\n" if $pdbg or $wrapdbg or $movedbg or $delimdbg;
|
|
|
|
#
|
|
# This sections builds the $t ("type") regex from the ground up.
|
|
# After it is built, the component variables (except for $id) are not used again.
|
|
#
|
|
|
|
$sid = '\b[a-zA-Z_]\w*'; # pattern for a simple identifier or keyword
|
|
$id = "(?:$sid\:\:)*$sid"; # simple id preceded by an optional namespace qualifier
|
|
$p = '(?: ?\*)*'; # suffix for "ptr", "ptr to ptr", "ptr to ptr to ptr", ad nauseum.
|
|
$idp = "(?:$id )*$id ?$p ?"; # one or more identifiers/keywords with perhaps some *'s after
|
|
|
|
# simple id or basic template spec
|
|
$cid = "(?:$idp(?: ?const ?\\*? ?)?|$id<$idp(?: ?const ?\\*? ?)?(?:, ?$idp(?: ?const ?\\*? ?)?)*>$p) ?";
|
|
|
|
# a cid or template type with 1+ cid's as parameters
|
|
$t = "(?:$cid|$id<$cid(?:, ?$cid)*>$p|$id<$id<$cid>$p(?:, ?$id<$cid>$p)* ?>$p)";
|
|
|
|
println "$STLFilt_ID" if ($banner eq 'Y');
|
|
|
|
showkey $output_width if $pdbg;
|
|
|
|
lognative_header if $lognative;
|
|
|
|
$doing_candidates = 0;
|
|
$doing_stl_headers = 0;
|
|
$save_filename = '';
|
|
$this_is_gcc3 = 0;
|
|
$saw_instantiated = 0;
|
|
|
|
#
|
|
# Data structures supporting the Dave Abrahams mode line break algorithm:
|
|
#
|
|
|
|
@open_delims = ('(', '{', '<');
|
|
@close_delims= (')', '}', '>');
|
|
|
|
for (@open_delims) # list of "open" delimiters
|
|
{
|
|
$open_delims{$_}++;
|
|
}
|
|
|
|
for (@close_delims) # list of "close" delimiters
|
|
{
|
|
$close_delims{$_}++;
|
|
}
|
|
|
|
# create "opposites" table, mapping each delimiter to its complement:
|
|
for ($i = 0; $i < @open_delims; $i++)
|
|
{
|
|
$opps{$open_delims[$i]} = $close_delims[$i];
|
|
$opps{$close_delims[$i]} = $open_delims[$i];
|
|
}
|
|
|
|
|
|
# The following state varaibles are used for Dave-mode line re-ordering:
|
|
|
|
$pushed_back_line = "";
|
|
$displaying_error_msg = 0; # true if displaying actual error message of backtrace in re-order mode
|
|
$last_within_context = ""; # save "within this context" lines to detect duplicates and strip them
|
|
|
|
#
|
|
# NOTE: We cannot use a main loop of the form
|
|
#
|
|
# while( <> )
|
|
#
|
|
# because of ActivePerl's way of handling input from Win32 pipes
|
|
# connected to STDIN. (EOF is treated like an ordinary character.
|
|
# In particular, it doesn't get read unless FOLLOWED by a newline.
|
|
# Yeah, great, EOF followed by a newline.)
|
|
#
|
|
|
|
MAIN_LOOP:
|
|
while ( 1 )
|
|
{
|
|
if ($pushed_back_line ne "")
|
|
{
|
|
$_ = $pushed_back_line;
|
|
$pushed_back_line = "";
|
|
}
|
|
else
|
|
{
|
|
# Read the first char of the next line to see if it equals EOF.
|
|
# If we're the ones who write the code that writes to STDIN,
|
|
# we can guarantee that EOF is always preceded by a newline.
|
|
#
|
|
# We must do this in a loop, because if the next line is empty,
|
|
# then we have not read the first char of the next line, but
|
|
# the entire next line.
|
|
#
|
|
$newlines = "";
|
|
|
|
CHECK_FOR_EOF_LOOP:
|
|
while( 1 )
|
|
{
|
|
# Read one char.
|
|
$nextchar = "";
|
|
$numRead = read STDIN, $nextchar, 1;
|
|
|
|
# Normally, perl will return an undefined value from read if the next
|
|
# character was EOF. ActivePerl will simply read the EOF like any other
|
|
# character. Since we know that one of the newlines was ours, we print one
|
|
# less newline than we have seen. NOTE: It is possible that we have seen no
|
|
# newline at all. This happens if the CL output has no newline at the end.
|
|
# In that case, we have appended a newline, and that's good.
|
|
|
|
if (1 != $numRead or $nextchar eq "\032")
|
|
{
|
|
if ($newlines ne "")
|
|
{
|
|
chop $newlines;
|
|
print $newlines;
|
|
}
|
|
last MAIN_LOOP;
|
|
}
|
|
else # Else, if we have read a newline, we store it for later output and continue reading.
|
|
{
|
|
if ($nextchar eq "\n")
|
|
{
|
|
$newlines = $newlines . "\n";
|
|
}
|
|
|
|
# Else, if we have read something that's neither a newline nor EOF, we print
|
|
# the accumulated newlines and proceed to read and process the next line.
|
|
|
|
else
|
|
{
|
|
print $newlines;
|
|
last CHECK_FOR_EOF_LOOP;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Read the next line, prepend the first char, which has already been read.
|
|
$_ = <STDIN>;
|
|
|
|
# If the read failed, the pipe must have broken.
|
|
if (!defined $_)
|
|
{
|
|
print "\nSTL Decryptor: Input stream terminated abnormally (broken pipe?)\n";
|
|
last MAIN_LOOP;
|
|
}
|
|
|
|
$_ = $nextchar . $_;
|
|
}
|
|
|
|
|
|
#
|
|
# Done with special EOF-processing-enabled input handling.
|
|
# Now process the line (in $_):
|
|
#
|
|
|
|
$save_line_for_dbg = $_; # in case of a panic error
|
|
|
|
print LOGNATIVE $_ if $lognative; # log native message if requested
|
|
|
|
print "DBG: Next line to be processed:\n$_\n" if $movedbg;
|
|
|
|
s/{anonymous}/anonymous/g; # massage anonymous namespace specs to qualify as identifiers
|
|
s/<unnamed>/unnamed/g;
|
|
|
|
$obj = 0; # by default, not object file message
|
|
$obj = 1 if /\.o(bj)?\b/i or /\.a\b/i; # set $obj if an object or lib file
|
|
|
|
if ($obj)
|
|
{
|
|
print "************** PRINT DBG 1 **************\n" if $pdbg;
|
|
if (/(.*\):\s*)([\S].*)/) # look for possibly-mangled name followed by additional text...
|
|
{
|
|
$before = $1;
|
|
$after = "$2\n";
|
|
break_and_print_plain "$before"; # print the part containing possible mangled-name-from-hell
|
|
$_ = $after; # and process the rest normally.
|
|
}
|
|
else
|
|
{
|
|
break_and_print_plain "$_"; # print entire line containing possible mangled-name-from-hell
|
|
next;
|
|
}
|
|
}
|
|
|
|
next if $show_backtraces eq 'N' and (/\binstantiated from\b/ or /^\s*from /);
|
|
|
|
# get rid of useless messages from gcc
|
|
|
|
if ($nix_only_once)
|
|
{
|
|
next if /\(Each undeclared identifier is reported only once/;
|
|
next if /for each function it appears in\.\)/;
|
|
}
|
|
|
|
$has_lineno = 0;
|
|
$has_lineno = 1 if /^(.*\.(cpp|cxx|cc|h|hpp|tcc)\:(\d+\:) ?)/;
|
|
|
|
# strip prefix of form:
|
|
if (/^(.*\.(cpp|cxx|cc|h|hpp|tcc)\:(\d+\:)? ?)/ or # "pathname.h:n: " or
|
|
(/^((?:[a-zA-Z]\:)?[^:]*\b(\w+)(\.\w+)?\:(\d+\:)? ?)/ and exists $keywords{$2})) # std header
|
|
{
|
|
$prefix = "$1"; # and restore it later
|
|
s/^\Q$prefix//; # remove during filtering
|
|
}
|
|
else
|
|
{
|
|
$prefix = ""; # null prefix if none detected
|
|
}
|
|
|
|
|
|
# test if we're looking at a message referring to a standard header
|
|
# (note that the candidate policy trumps the header policy):
|
|
|
|
$needs_stripping = ($prefix =~ /stl_[a-zA-Z]\w*\.h:/i or
|
|
($prefix =~ m#([/\\])include\1(?:.*\1)*(\w+)# and exists $keywords{$2}));
|
|
|
|
$this_is_an_stl_header = ($needs_stripping and
|
|
!$doing_candidates and ($_ !~ /candidates are\:/));
|
|
|
|
# strip message referring to standard headers if header_policy is S:
|
|
|
|
if ($this_is_an_stl_header)
|
|
{
|
|
++$doing_stl_headers;
|
|
next if $header_policy eq 'S'; # skip all headers if using 'S' header policy
|
|
# skip all but first $headers_to_show if policy is 'M'
|
|
next if $doing_stl_headers > $headers_to_show and $header_policy eq 'M';
|
|
}
|
|
|
|
# if 'M' or 'S' header policy, tell how many skipped:
|
|
if (!$this_is_an_stl_header and ($doing_stl_headers > ($headers_to_show)) and $header_policy ne 'L')
|
|
{
|
|
println " [STL Decryptor: Suppressed " .
|
|
($doing_stl_headers - $headers_to_show) .
|
|
($header_policy eq 'M' ? " more " : " ") .
|
|
"STL standard header message" .
|
|
(($doing_stl_headers - $headers_to_show) != 1 ? "s" : "") . "]";
|
|
$suppressed_headers = 1;
|
|
}
|
|
|
|
$doing_stl_headers = 0 if !$this_is_an_stl_header;
|
|
|
|
|
|
# gcc: strip pathname from deadly-long stdlib file paths as per $pathname_policy:
|
|
|
|
if ($pathname_policy eq 'S' and $needs_stripping)
|
|
{
|
|
$preprefix = ""; # special case: preserve leading " from " phrase
|
|
if ($prefix =~ /^(.* from )/)
|
|
{
|
|
$preprefix = $1;
|
|
$prefix =~ s/^.* from //;
|
|
}
|
|
|
|
if ($prefix =~ /$sid\.(h|hpp|tcc|cpp|cxx|cc)\:/)
|
|
{ # case where there's an extension
|
|
$prefix =~ s/.*($sid\.(h|hpp|tcc|cpp|cxx|cc))\:/$preprefix$1:/;
|
|
}
|
|
else
|
|
{ # case where there's (perhaps) no extension
|
|
$prefix =~ s/^(?:[a-zA-Z]\:)?[^:]*\b(\w+(\.\w+)?\:(\d+\:)? ?)/$preprefix$1/;
|
|
}
|
|
}
|
|
|
|
# save filename, if any
|
|
|
|
if ($prefix =~ /^($sid\.(h|hpp|tcc))\:/)
|
|
{
|
|
$filename = $1; # save file basename
|
|
}
|
|
else
|
|
{
|
|
$filename = 'No filename';
|
|
}
|
|
|
|
if ($candidate_policy ne 'L' and /candidates are:/)
|
|
{
|
|
$doing_candidates++;
|
|
$save_filename = $filename;
|
|
$suppressed_candidates = 1;
|
|
next;
|
|
}
|
|
|
|
$this_is_gcc3 = 1 if $doing_candidates and / /;
|
|
|
|
# skip all messages referring to "candidates" (if req'd):
|
|
if ($candidate_policy ne 'L' and $doing_candidates and
|
|
($this_is_gcc3 and / /) or (!$this_is_gcc3 and $filename eq $save_filename))
|
|
{
|
|
$doing_candidates++;
|
|
next;
|
|
}
|
|
|
|
if (((!$this_is_gcc3 and $filename ne $save_filename) or $this_is_gcc3) and $doing_candidates)
|
|
{
|
|
println " [STL Decryptor: Suppressed $doing_candidates 'candidate' line" .
|
|
($doing_candidates != 1 ? "s" : "") . "]"
|
|
if $candidate_policy eq 'M';
|
|
$doing_candidates = 0;
|
|
}
|
|
|
|
s/no matching function for call to/No match for/;
|
|
|
|
###################################################################################################
|
|
# Do 'with' clause processing, transforming into plain-Jane type specifications:
|
|
|
|
if ($with_policy eq 'S')
|
|
{
|
|
# temporary eliminate [##] sequences:
|
|
@dims = ();
|
|
$dim_counter = 1;
|
|
|
|
while (/(\[(\d*)])/)
|
|
{
|
|
$old = $1;
|
|
$sub = $2;
|
|
s/\Q$old/zzz-$dim_counter-$sub-zzz/;
|
|
push @dims, $sub;
|
|
$dim_counter++;
|
|
}
|
|
|
|
while (/(.*)( \[with ([^]]*)])/)
|
|
{
|
|
$text = $1; # the original message text with placeholder names
|
|
$keyclause = $2; # the "with [...]" clause
|
|
$keylist = $3; # just the list of key/value mappings
|
|
|
|
chop $keylist if substr($keylist, -1, 1) eq ']';
|
|
|
|
%map = (); # clear the hash of key/value pairs
|
|
|
|
while($keylist =~ /(\w+) ?=/)
|
|
{
|
|
$key = $1;
|
|
$pos = $start = index($keylist, $key) + length($key) + 1;
|
|
if (substr($keylist, $pos, 1) eq '=')
|
|
{ $pos++; $start++; }
|
|
if (substr($keylist, $pos, 1) eq ' ')
|
|
{ $pos++; $start++; }
|
|
|
|
|
|
$depth = 0; # count <'s and >'s
|
|
$previous = ' ';
|
|
while ($pos <= length($keylist))
|
|
{
|
|
$next = substr ($keylist, $pos++, 1);
|
|
last if $depth == 0 and ($next eq ',' or ($next eq ']' and $previous ne '[')); # ignore "[]"
|
|
$previous = $next;
|
|
$depth++ if $next =~ /[<\[\(]/;
|
|
$depth-- if $next =~ /[>\]\)]/;
|
|
}
|
|
|
|
$value = substr($keylist, $start, $pos - $start - 1);
|
|
$map{$key} = $value;
|
|
|
|
last if $pos > length($keylist);
|
|
$keylist = substr($keylist, $pos);
|
|
}
|
|
|
|
# Apply substitutions to the original text fragment:
|
|
|
|
$newtext = $text;
|
|
while(($key, $value) = each(%map))
|
|
{
|
|
$newtext =~ s/\b$key\b/$value/g;
|
|
}
|
|
|
|
# Replace the original message text with the expanded version:
|
|
|
|
s/\Q$text/$newtext/;
|
|
|
|
# Delete the key/value list from the message:
|
|
|
|
s/\Q$keyclause//;
|
|
}
|
|
|
|
# restore [###] clauses:
|
|
$dim_counter = 1;
|
|
foreach $dim (@dims)
|
|
{
|
|
s/zzz-$dim_counter-$dim-zzz/[$dim]/g;
|
|
$dim_counter++;
|
|
}
|
|
}
|
|
|
|
# End 'with' clause processing
|
|
#############################################################################################
|
|
|
|
# eliminate standard namespace qualifiers (for now, required for STL filtering):
|
|
|
|
s/\bstd(ext)?\:\://g unless $keep_stdns;
|
|
s/\b__gnu_cxx\:\://g unless $keep_stdns;
|
|
|
|
s/note: //; # WTF? It's just noise.
|
|
s/typename //g; # ditto
|
|
|
|
# The following section strips out the "class" keyword when it is part
|
|
# of a type name, but not when it is part of the 'prose' of a message.
|
|
# To do this, we only strip the word "class" when it follows an
|
|
# odd-numbered single quote (1st, 3rd, 5th,
|
|
|
|
$out = ""; # accumulate result into $out
|
|
$old = $_;
|
|
|
|
while (1)
|
|
{
|
|
if (($pos = index ($old, "`")) == -1) # index of next opening quote
|
|
{ # if none,
|
|
$out .= $old; # we're done
|
|
last;
|
|
}
|
|
$out .= substr($old, 0, $pos + 1, ""); # splice up to & including the "'" to $out
|
|
$pos = index($old, "'"); # index of next closing quote in $out
|
|
$txt = substr($old, 0, $pos + 1, ""); # splice from $old into $txt
|
|
$txt =~ s/\bclass //g if !/\btypedef\b/; # filter out "class" from $txt
|
|
$out .= $txt; # concatenate result to cumulative result
|
|
} # loop for next fragment
|
|
$_ = $out; # done; update entire current line
|
|
|
|
|
|
# s/\bclass //g if !/typedef/; # strip "class" except in typedef errors
|
|
|
|
|
|
s/\bstruct ([^'])/$1/g if !/typedef/; # don't strip "struct" for *anonymous* structs or typedefs
|
|
|
|
s/\b_STLD?\:\://g unless $keep_stdns; # for STLPort
|
|
|
|
# simplify the ubiquitous "vanilla" string and i/ostreams (w/optional default allocator):
|
|
|
|
s/\b(_?basic_(string|if?stream|of?stream|([io]?stringstream)))<(char|wchar_t), ?(string_)?char_traits<\4>(, ?__default_alloc_template<(true|false), ?0>)? ?>\:\:\1/$2::$2/g;
|
|
s/\b_?basic_(string|if?stream|of?stream|([io]?stringstream))<(char|wchar_t), ?(string_)?char_traits<\3>(, ?__default_alloc_template<(true|false), ?0>)? ?>/$1/g;
|
|
s/\b(_?basic_(string|if?stream|of?stream|([io]?stringstream)))<(char|wchar_t), ?(string_)?char_traits<\4>(, allocator<\4>)? ?>\:\:\1/$2::$2/g;
|
|
s/\b_?basic_(string|if?stream|of?stream|([io]?stringstream))<(char|wchar_t), ?(string_)?char_traits<\3>(, allocator<\3>)? ?>/$1/g;
|
|
s/\b([io])stream_iterator<($t), ?($t), ?char_traits<\3>, ?($t)>/$1stream_iterator<$2>/g;
|
|
|
|
s/\b__normal_iterator<const $t, ?($t)>\:\:__normal_iterator\(/string::const_iterator(/g;
|
|
s/\b__normal_iterator<$t, ?($t)>\:\:__normal_iterator\(/string::iterator(/g;
|
|
|
|
|
|
# The following loop repeats until no transformations occur in the last complete iteration:
|
|
|
|
for ($pass = 1; ;$pass++) # pass count (for de-bugging purposes only)
|
|
{
|
|
my $before = $_; # save the current line; keep looping while changes happen
|
|
|
|
#
|
|
# Handle allocator clauses:
|
|
#
|
|
|
|
# delete allocators from template typenames completely:
|
|
|
|
$has_double_gt = 0;
|
|
$has_double_gt++ if />>/;
|
|
|
|
s/allocator<($t)>::rebind<\1>::other::($id)/allocator<$1>::$2/g;
|
|
s/\b,? ?allocator<$t ?>(,(0|1|true|false)) ?>/$2>/g;
|
|
s/, ?allocator<$id<($t), ?allocator<\1> ?> ?>//g;
|
|
s/, ?allocator<$t> ?>/>/g;
|
|
|
|
|
|
# remove allocator clauses
|
|
|
|
# gcc 4.x allocator types
|
|
|
|
s/, ?allocator<($t) ?>\:\:rebind<\1 ?>\:\:other>/>/g;
|
|
|
|
# remove allocator clauses if the message doesn't refer to an allocator explicitly:
|
|
|
|
unless (/' to '.*allocator</ or /allocator<$t>\:\:/)
|
|
{
|
|
s/, ?allocator<$t ?> ?//g; # the leading comma allows the full spec.
|
|
s/, ?const allocator<$t ?> ?&//g; # to appear in the error message details
|
|
s/,? ?(const )?$t\:\:allocator_type ?&//g;
|
|
}
|
|
|
|
|
|
if (!$has_double_gt)
|
|
{
|
|
while (/>>/)
|
|
{
|
|
s/>>/> >/g;
|
|
}
|
|
}
|
|
|
|
|
|
# gcc deque, deque iterators:
|
|
|
|
s/\bdeque<($t),0>/deque<$1>/g;
|
|
s/\b_Deque_iterator<($t), ?\1 ?&, ?\1 ?[*&](, ?0)?>\:\:_Deque_iterator ?\(/deque<$1>::iterator(/g;
|
|
s/\b_Deque_iterator<($t), ?\1 ?&, ?\1 ?[*&](, ?0)?>/deque<$1>::iterator/g;
|
|
|
|
s/\b_Deque_iterator<($t), ?const \1 ?&, ?const \1 ?[*&](,0)?>\:\:_Deque_iterator ?\(/deque<$1>::const_iterator(/g;
|
|
s/\b_Deque_iterator<($t), ?const \1 ?&, ?const \1 ?[*&](,0)?>/deque<$1>::const_iterator/g;
|
|
|
|
# gcc list iterators:
|
|
|
|
s/\b_List_iterator<($t), ?(const )?\1 ?&, ?(const )?\1 ?\*>\:\:_List_iterator ?\(/list<$1>::iterator(/g;
|
|
s/\b_List_iterator<($t), ?(const )?\1 ?&, ?(const )?\1 ?\*>/list<$1>::iterator/g;
|
|
|
|
s/\b_List_iterator<($t)>\:\:_List_iterator\(/list<$1>::iterator(/g;
|
|
s/\b_List_iterator<($t)>/list<$1>\:\:iterator/g;
|
|
|
|
s/\b_List_const_iterator<($t)>\:\:_List_const_iterator ?\(/list<$1>::const_iterator(/g;
|
|
s/\b_List_const_iterator<($t)>/list<$1>::const_iterator/g;
|
|
|
|
s/_List_node<($t)> ?\*/list<$1>::iterator/g;
|
|
s/_List_node_base ?\*/iterator/g;
|
|
s/_List_const_iterator/const_iterator/g;
|
|
s/_List_iterator/iterator/g;
|
|
|
|
# gcc slist iterators:
|
|
|
|
s/\b_Slist_iterator<($t), ?\1 ?&, ?\1 ?\*>\:\:_Slist_iterator ?\(/slist<$1>::iterator(/g;
|
|
s/\b_Slist_iterator<($t), ?const \1 ?&, ?const \1 ?\*>\:\:_Slist_iterator ?\(/slist<$1>::const_iterator(/g;
|
|
s/\b_Slist_iterator<($t), ?\1 ?&, ?\1 ?\*>/slist<$1>::iterator/g;
|
|
s/\b_Slist_iterator<($t), ?const \1 ?&, ?const \1 ?\*>/slist<$1>::const_iterator/g;
|
|
s/\b_Slist_node<($t)> ?\*/slist<$1>::iterator/g;
|
|
|
|
|
|
# gcc vector iterator:
|
|
|
|
s/\b__normal_iterator<($t) ?\*, vector<\1 ?> ?>\:\:__normal_iterator ?\(/vector<$1>::iterator(/g;
|
|
s/\b__normal_iterator<($t) ?\*, vector<\1 ?> ?>/vector<$1>::iterator/g;
|
|
s/\b__normal_iterator<($t) const ?\*, vector<\1 ?> ?>\:\:__normal_iterator ?\(/vector<$1>::const_iterator(/g;
|
|
s/\b__normal_iterator<const ($t) ?\*, ?vector<\1 ?> ?>\:\:__normal_iterator ?\(/vector<$1>::const_iterator(/g;
|
|
s/\b__normal_iterator<($t) const ?\*, vector<\1 ?> ?>/vector<$1>::const_iterator/g;
|
|
s/\b__normal_iterator<const ($t) ?\*, ?vector<\1 ?> ?>/vector<$1>::const_iterator/g;
|
|
|
|
|
|
# gcc map:
|
|
|
|
s/\b_Rb_tree<($t), ?pair<const \1, ?($t)>, ?_Select1st<pair<const \1, ?\2> ?> ?>/map<$1,$2>/g;
|
|
s/\b_Rb_tree<($t), ?pair<const \1, ?($t)>, ?_Select1st<pair<const \1, ?\2> ?>, ($t) ?>/map<$1,$2,$3>/g;
|
|
|
|
# s/\b_Rb_tree<($t), ?pair<const \1, ?($t)>, ?_Select1st<pair<const \1, ?\2> > ?>/map<$1,$2>/g;
|
|
s/\b_Rb_tree<($t), ?pair<const \1, ?($t)>, ?_Select1st<pair<const \1, ?\2> ?>, ($t)::rebind<pair<const \1, ?\2> >::other>/map<$1,$2,$3>/g;
|
|
|
|
|
|
# gcc map/multimap iterators:
|
|
|
|
s/\b_Rb_tree<($t), ?pair<const \1, ?($t)>, ?_Select1st<pair<const \1, ?\2> ?>::rebind<pair<const \1, ?\2> >::other>/multimap<$1,$2>/g;
|
|
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t) ?> ?>\:\:_Rb_tree_iterator\(const _Rb_tree_iterator<pair<const \1 ?, ?\2 ?> ?>&\)/gen_map<$1,$2>::iterator(const gen_map<$1,$2>::iterator &)/g;
|
|
s/\b_Rb_tree_const_iterator<pair<const ($t) ?, ?($t) ?> ?>\:\:_Rb_tree_const_iterator\(const _Rb_tree_const_iterator<pair<const \1 ?, ?\2 ?> ?>&\)/gen_map<$1,$2>::const_iterator(const gen_map<$1,$2>::const_iterator &)/g;
|
|
s/\b_Rb_tree_const_iterator<pair<const ($t) ?, ?($t) ?> ?>\:\:_Rb_tree_const_iterator\(const _Rb_tree_iterator<pair<const \1 ?, ?\2 ?> ?>&\)/gen_map<$1,$2>::const_iterator(const gen_map<$1,$2>::iterator &)/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t) ?> ?>\:\:_Rb_tree_iterator\(_Rb_tree_node<pair<const \1, ?\2 ?> ?>\*\)/gen_map<$1,$2>::iterator/g;
|
|
s/\b_Rb_tree_const_iterator<pair<const ($t) ?, ?($t) ?> ?>\:\:_Rb_tree_const_iterator\(const _Rb_tree_node<pair<const \1, ?\2 ?> ?>\*\)/gen_map<$1,$2>::iterator/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<($t) ?const, ?($t) ?> ?>/gen_map<$1,$2>::iterator/g;
|
|
s/\b_Rb_tree_const_iterator<pair<($t) ?const, ?($t) ?> ?>/gen_map<$1,$2>::const_iterator/g;
|
|
|
|
s/\b_Rb_tree_node<pair<const ($t), ?($t) ?> ?> ?\*/gen_map<$1,$2>::iterator/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t)>, ?pair<const \1, ?\2> ?&, ?pair<const \1, ?\2> ?\*>\:\:_Rb_tree_iterator ?\(/gen_map<$1,$2>::iterator(/g;
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t)>, ?pair<const \1, ?\2> ?&, ?pair<const \1, ?\2> ?\*>/gen_map<$1,$2>::iterator/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t)>, ?const pair<const \1, ?\2> ?&,const pair<const \1, ?\2> ?\*>\:\:_Rb_tree_iterator ?\(/gen_map<$1,$2>::const_iterator(/g;
|
|
s/\b_Rb_tree_iterator<pair<($t) ?const, ?($t)>, ?pair<\1 ?const, ?\2> ?&, ?pair<\1 ?const, ?\2> ?\*>\:\:_Rb_tree_iterator ?\(/gen_map<$1,$2>::const_iterator(/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t)>, ?const pair<const \1, ?\2> ?&,const pair<const \1, ?\2> ?\*>/gen_map<$1,$2>::const_iterator/g;
|
|
s/\b_Rb_tree_iterator<pair<($t) ?const, ?($t)>, ?pair<\1 ?const, ?\2> ?&, ?pair<\1 ?const, ?\2> ?\*>/gen_map<$1,$2>::const_iterator/g;
|
|
|
|
s/\b_Rb_tree_iterator<pair<const ($t) ?, ?($t)> ?>/gen_map<$1,$2>::iterator/g;
|
|
s/\b_Rb_tree_const_iterator<pair<const ($t) ?, ?($t)> ?>/gen_map<$1,$2>::const_iterator/g;
|
|
|
|
|
|
# gcc set/multiset/map/multimap iterator (who knows, lol?)
|
|
|
|
s/\b_Rb_tree_iterator\(($t)\)/gen_set_or_map::iterator($1)/g;
|
|
s/\b_Rb_tree_const_iterator<($t)>\:\:_Rb_tree_const_iterator\(/gen_set_or_map<$1>::const_iterator(/g;
|
|
s/\b_Rb_tree_const_iterator<($t)>/gen_set_or_map<$1>::const_iterator/g;
|
|
s/\b_Rb_tree_const_iterator\(($t)\)/gen_set_or_map::const_iterator($1)/g;
|
|
|
|
|
|
# Since the same iterator type is used for both set and multiset, we just
|
|
# say "gen_set<T>::iterator" to mean the "GENERIC" set/multiset iterator type:
|
|
|
|
# gcc set/multiset:
|
|
|
|
s/\b_Rb_tree<($t), ?\1, ?_Identity<$t>, ?($t)>/gen_set<$1,$2>/g;
|
|
s/\b_Rb_tree<($t), ?\1, ?_Identity<$t>>/gen_set<$1>/g;
|
|
|
|
|
|
# gcc set/multiset iterator:
|
|
|
|
s/\b_Rb_tree_iterator<($t), ?const \1 ?&, ?const \1 ?\*>::_Rb_tree_iterator ?\(/gen_set<$1>::iterator(/g;
|
|
|
|
s/\b_Rb_tree_iterator<($t), ?const \1 ?&, ?const \1 ?\*>/gen_set<$1>::iterator/g;
|
|
|
|
s/\b_Rb_tree_iterator<($t) \*, ?\1 ?\*const &, ?\1 ?\*const \*>::_Rb_tree_iterator ?\(/gen_set<$1>::iterator(/g;
|
|
s/\b_Rb_tree_iterator<($t) \*, ?\1 ?\*const &, ?\1 ?\*const \*>/gen_set<$1>::iterator/g;
|
|
|
|
s/[`']\b_Rb_tree_const_iterator ?<($t)>\:\:_Rb_tree_const_iterator\(const _Rb_tree_node<($t)> ?\*\)'/gen_set<$1>::const_iterator/g;
|
|
|
|
s/[`']\b_Rb_tree_iterator ?\(($t)\)'/gen_set<$1>::iterator/g;
|
|
s/[`']\b_Rb_tree_const_iterator ?\(($t)\)'/gen_set<$1>::const_iterator/g;
|
|
s/\b_Rb_tree_iterator ?\(($t)\)/gen_set<$1>::iterator/g;
|
|
s/\b_Rb_tree_const_iterator ?\((const $t)\)/gen_set<$1>::const_iterator/g;
|
|
s/\b_Rb_tree_iterator ?<($t)>/gen_set<$1>::iterator/g;
|
|
s/\b_Rb_tree_const_iterator ?<($t)>/gen_set<$1>::const_iterator/g;
|
|
|
|
s/\bconst _Rb_tree_node<($t) ?> ?\*/gen_set<$1>::const_iterator/g;
|
|
s/\b_Rb_tree_node<($t)> ?\*/gen_set<$1>::iterator/g;
|
|
|
|
|
|
# STLPort /gcc hash_set/_multiset:
|
|
|
|
s/\b(hash_(?:multi)?)set<($t)(, ?hash<\2 ?>)? ?(, ?equal_to<\2 ?>)? ?>/$1set<$2>/g;
|
|
s/\bhashtable<($t), ?\1, ?hash<\1 ?>, ?_Identity<\1 ?>, ?$t>/gen_hash_set<$1>/g;
|
|
|
|
|
|
# gcc hash_map/multimap:
|
|
|
|
s/\b(hash_(?:multi)?)map<($t), ?($t), ?hash<\2 ?>, ?($t)>/$1map<$2,$3>/g;
|
|
|
|
|
|
# gcc hash_set/hash_multiset iterator:
|
|
|
|
s/\b_Hashtable_const_iterator<($t), ?\1, ?hash<\1 ?>, ?_Identity<\1 ?>, ?$t>\:\:_Hashtable_const_iterator ?\(/gen_hash_set($1):const_iterator(/g;
|
|
s/\b_Hashtable_const_iterator<($t), ?\1, ?hash<\1 ?>, ?_Identity<\1 ?>, ?$t>/gen_hash_set($1):const_iterator/g;
|
|
s/\b_Hashtable_iterator<($t), ?\1, ?hash<\1 ?>, ?_Identity<\1 ?>, ?$t>\:\:_Hashtable_iterator ?\(/gen_hash_set($1):iterator(/g;
|
|
s/\b_Hashtable_iterator<($t), ?\1, ?hash<\1>, ?_Identity<\1>, ?$t>/gen_hash_set($1):iterator/g;
|
|
|
|
# gcc hash_map/hash_multimap:
|
|
|
|
s/\bhashtable<(pair<const ($t), ?($t)>), ?\2, ?hash<\2 ?>, ?_Select1st<\1 ?>, ?$t ?>/gen_hash_map<$2,$3>/g;
|
|
|
|
# gcc hash_set/hash_multiset value_type:
|
|
|
|
s/\bhashtable<($t), ?\1, ?hash<\1>, ?_Identity<\1>, ?$t>::value_type/$1/g;
|
|
|
|
# STLPort/gcc hash_map/_multimap iterators under VC7 (same "GENERIC" iterator approach as above):
|
|
|
|
s/\b_Hashtable_iterator<pair<const ($t), ?($t)>, ?\1, ?hash<\1 ?>, ?_Select1st<pair<const \1, ?\2> ?>, ?equal_to<\1 ?> ?>\:\:_Hashtable_iterator\(/gen_hash_map<$1,$2>::iterator(/g;
|
|
s/\b_Hashtable_const_iterator<pair<const ($t), ?($t)>, ?\1, ?hash<\1 ?>, ?_Select1st<pair<const \1, ?\2> ?>, ?equal_to<\1 ?> ?>\:\:_Hashtable_const_iterator\(/gen_hash_map<$1,$2>::const_iterator(/g;
|
|
s/\b_Hashtable_iterator<pair<const ($t), ?($t)>, ?\1, ?hash<\1 ?>, ?_Select1st<pair<const \1, ?\2> ?>, ?equal_to<\1 ?> ?>/gen_hash_map<$1,$2>::iterator/g;
|
|
s/\b_Hashtable_const_iterator<pair<const ($t), ?($t)>, ?\1, ?hash<\1 ?>, ?_Select1st<pair<const \1, ?\2> ?>, ?equal_to<\1 ?> ?>/gen_hash_map<$1,$2>::const_iterator/g;
|
|
|
|
# simplify default comparison function objects, leave others intact:
|
|
|
|
s/, ?_?less<$t ?>//g;
|
|
s/, ?Comp<$t ?>//g; # STLPort's default comparison function
|
|
|
|
last if $before eq $_; # keep looping if substitutions were actually made
|
|
}
|
|
|
|
# reverse iterators:
|
|
|
|
s/\breverse_iterator<($t)::iterator ?>/$1::reverse_iterator/g;
|
|
s/\breverse_iterator<($t)::const_iterator ?>/$1::const_reverse_iterator/g;
|
|
s/\bconst_reverse_iterator\:\:reverse_iterator/const_reverase_iterator/g;
|
|
|
|
# reduce iterators according to $iter_policy:
|
|
|
|
$olditer = '(reverse_)?(bidirectional_)?((back_)?insert_)?iterator';
|
|
if ($iter_policy eq 'M') # policy 'M': USUALLY remove:
|
|
{
|
|
unless (/( of type|' to '|from ')$t\:\:(const_)?$olditer/ # Shorten to $newiter and
|
|
or /iterator' does/) # *remove* the base type completely...
|
|
{ # as long as the error message doesn't
|
|
s/$t\:\:((const_)?$olditer)\b/$1/g; # mention iterators!
|
|
}
|
|
}
|
|
elsif ($iter_policy eq 'S') # policy 'S': ALWAYS remove:
|
|
{
|
|
s/$t\:\:((const_)?$olditer)\b/$1/g; # remove the base type completely
|
|
}
|
|
# All policies (including 'L'):
|
|
s/\biterator\b/$newiter/g;
|
|
s/\b(const_|reverse_|const_reverse_)iterator\b/$1$newiter/g;
|
|
|
|
# remove trailing "null args" from template parameter lists:
|
|
|
|
foreach $name (@nullargs)
|
|
{
|
|
s/(, ?$name ?)* ?>/>/g;
|
|
}
|
|
|
|
# reduce "double" constructor names 'T::T' to just 'T':
|
|
|
|
s/[`']string\:\:string([\('])/'string$1/g;
|
|
s/[`'](.*)\:\:\1([\('])/'$1$2/g;
|
|
|
|
# deal with some other non-critical (and often not even very aesthetic) spaces (or lack thereof):
|
|
|
|
s/>>>>>([\(:',*&])/> > > > >$1/g; # put spaces between the close brackets
|
|
s/>>>>([\(:',*&])/> > > >$1/g;
|
|
s/>>>([\(:',*&])/> > >$1/g;
|
|
|
|
if (/(.)>>(.)/) # careful, ">>" could be operator...
|
|
{
|
|
$before = $1;
|
|
$after = $2;
|
|
s/(.)>>([ \(:',*&])/$1> >$2/g unless (/operator ?>>/ or ($before eq ' ' and $after eq ' '));
|
|
}
|
|
|
|
|
|
s/([^> ]) >([^>=])/$1>$2/g; # remove space before '>' (unless between another '>' or '>=')
|
|
|
|
s/([\w>])([&*])/$1 $2/g if !$smush_amps_and_stars; # conditionally force space between identifier and '*' or '&'
|
|
|
|
s/,([^ ])/, $1/g if $space_after_commas; # add space *after* a comma, however, if desired.
|
|
|
|
|
|
s/ initializing argument / init. arg /;
|
|
|
|
# and FINALLY, print out the result of all transformations, preceded by saved prefix:
|
|
|
|
$_ = $prefix . $_;
|
|
s/\: /:/ if $break_algorithm eq 'D'; # lose "candidate" alignment in "Dave" wrap mode
|
|
|
|
# reformat line number indicator
|
|
s/\:(\d+)/($1)/g if $reformat_linenumbers;
|
|
|
|
if ($dave_move)
|
|
{
|
|
print "DBG: A\n" if $movedbg;
|
|
$has_from = /^\s*from /;
|
|
if (!$in_backtrace)
|
|
{
|
|
print "DBG: B\n" if $movedbg;
|
|
if (/:\s+In\b/i or /^\s*In file included from/)
|
|
{
|
|
$in_backtrace = 1; # template instantiation backtrace?
|
|
print "DBG: C (in_backtrace set to 1)\n" if $movedbg;
|
|
@backtrace = ();
|
|
}
|
|
}
|
|
elsif (/instantiated\s+from\s+here/)
|
|
{
|
|
print "DBG: D\n" if $movedbg;
|
|
$saved_trigger = $_;
|
|
}
|
|
elsif (/instantiated\s+from\s+[`']/) #` Fix syntax hilighting for emacs
|
|
{
|
|
$saw_instantiated = 1;
|
|
print "DBG: E (saw_instantiated set to 1)\n" if $movedbg;
|
|
}
|
|
elsif (/^\s*from .*[,:]$/)
|
|
{
|
|
$in_backtrace = 2; # header backtrace
|
|
print "DBG: F (in_backtrace set to 2)\n" if $movedbg;
|
|
}
|
|
else # we've come to the end.
|
|
{
|
|
print "DBG: G\n" if $movedbg;
|
|
|
|
# if we've already begun displaying the final error message:
|
|
|
|
if ($displaying_error_msg)
|
|
{
|
|
if (substr($_, 0, 1) =~ /\s/ or /within this context/) # if we see a line beginning with whitespace, it is a continuation of the actual error message:
|
|
{
|
|
if (/within this context/)
|
|
{
|
|
next if $last_within_context eq $_; # strip consecutive identical "within this context" lines (gcc bug?)
|
|
$last_within_context = $_;
|
|
}
|
|
break_and_print $_;
|
|
next;
|
|
}
|
|
else # if we see a line not starting with whitespace, finalize the re-order mode processing:
|
|
{
|
|
$last_within_context = ""; # reset "within this context" duplicate detection mechanism
|
|
break_and_print (shift @backtrace); # print 1st line of backtrace
|
|
|
|
# if replicating trigger, do it:
|
|
break_and_print $saved_trigger if $dave_rep and $saw_instantiated;
|
|
|
|
$backtrace[$#backtrace] =~ s/:$// # if header file backtrace, strip trailing
|
|
if $in_backtrace == 2 and @backtrace; # colon from last line
|
|
|
|
foreach $line (@backtrace) # now emit the accumulated backtrace
|
|
{
|
|
break_and_print $line;
|
|
}
|
|
print "\n";
|
|
$in_backtrace = 0;
|
|
print "DBG: I\n" if $movedbg;
|
|
|
|
$displaying_error_msg = 0;
|
|
$last_within_context = "";
|
|
$pushed_back_line = $_;
|
|
next;
|
|
}
|
|
}
|
|
|
|
if ($saw_instantiated or ($in_backtrace == 2 and $has_lineno and !$has_from))
|
|
{
|
|
print "DBG: H\n" if $movedbg;
|
|
print "************** PRINT DBG 2 **************\n" if $pdbg;
|
|
print "\n"; # let's set the "deep" error sequence apart
|
|
break_and_print $_; # print the first line of the actual error first
|
|
$displaying_error_msg = 1; # and go into displaying error message mode until we see a line beginning with non-ws
|
|
next;
|
|
}
|
|
elsif ($in_backtrace == 1) # template backtrace "false alarm"?
|
|
{
|
|
print "DBG: J\n" if $movedbg;
|
|
break_and_print (shift @backtrace); # yes.
|
|
$in_backtrace = 0; # reset for another round
|
|
}
|
|
}
|
|
|
|
print "DBG: K\n" if $movedbg;
|
|
if ($in_backtrace)
|
|
{
|
|
print "DBG: L\n" if $movedbg;
|
|
push @backtrace, $_;
|
|
next;
|
|
}
|
|
}
|
|
|
|
print "************** PRINT DBG 3 **************\n" if $pdbg;
|
|
break_and_print "$_";
|
|
}
|
|
|
|
|
|
if ($displaying_error_msg)
|
|
{
|
|
break_and_print (shift @backtrace); # print 1st line of backtrace
|
|
|
|
# if replicating trigger, do it:
|
|
break_and_print $saved_trigger if $dave_rep and $saw_instantiated;
|
|
|
|
$backtrace[$#backtrace] =~ s/:$// # if header file backtrace, strip trailing
|
|
if $in_backtrace == 2 and @backtrace; # colon from last line
|
|
|
|
foreach $line (@backtrace) # now emit the accumulated backtrace
|
|
{
|
|
break_and_print $line;
|
|
}
|
|
print "\n";
|
|
|
|
print "DBG: I2\n" if $movedbg;
|
|
}
|
|
|
|
close LOGNATIVE if $lognative; # close native messages logfile if active
|
|
|
|
if ($doing_candidates and $candidate_policy eq 'M')
|
|
{
|
|
println " [STL Decryptor: Suppressed $doing_candidates 'candidate' line" .
|
|
($doing_candidates != 1 ? "s" : "") . "]";
|
|
}
|
|
else
|
|
{
|
|
# if 'M' or 'S' header policy, tell how many skipped:
|
|
if (($doing_stl_headers > $headers_to_show) and $header_policy ne 'L')
|
|
{
|
|
println " [STL Decryptor: Suppressed " .
|
|
($doing_stl_headers - $headers_to_show) .
|
|
($header_policy eq 'M' ? " more " : " ") .
|
|
"STL standard header message" .
|
|
(($doing_stl_headers - $headers_to_show) != 1 ? "s" : "") . "]";
|
|
$suppressed_headers = 1;
|
|
}
|
|
}
|
|
|
|
if ($advise_re_policy_opts and ($suppressed_headers or $suppressed_candidates))
|
|
{
|
|
print "\nSTL Decryptor reminder";
|
|
print "s" if $suppressed_headers and $suppressed_candidates;
|
|
println ":";
|
|
println " Use the /hdr:L option to see all suppressed standard lib headers" if $suppressed_headers;
|
|
println " Use the /cand:L option to see all suppressed template candidates" if $suppressed_candidates;
|
|
}
|
|
|
|
if ($choked)
|
|
{
|
|
print "\n***************************************************************************\n";
|
|
print "A non-fatal, internal STL Decryptor error has occurred.\n";
|
|
if ($show_internal_err)
|
|
{
|
|
print "It should have said as much somewhere above, and then emitted the \n";
|
|
print "partially-filtered line.\n";
|
|
}
|
|
print "Please look for a file just created named NativeLog.txt,\n";
|
|
print "and email this file to leor\@bdsoft.com. This will greatly assist me\n";
|
|
print "to understand and try to correct the problem. Thank you!\n";
|
|
print "***************************************************************************\n";
|
|
}
|
|
|
|
exit 0;
|
|
|
|
|
|
sub break_and_print {
|
|
my $line = shift(@_);
|
|
|
|
if ($output_width == 0 or ($break_algorithm eq 'P' and length($line) < $output_width))
|
|
{
|
|
$line =~ s/\s+\n/\n/g; # delete trailing space on a line
|
|
print "************** PRINT DBG 4 **************\n" if $pdbg;
|
|
print "$line";
|
|
return;
|
|
}
|
|
|
|
if ($break_algorithm eq 'P')
|
|
{
|
|
print "************** PRINT DBG 5 **************\n" if $pdbg;
|
|
break_and_print_plain "$line";
|
|
return;
|
|
}
|
|
|
|
$nesting_level = 0; # track combined nesting level for () [] <> {}
|
|
$in_quotes = 0; # not in quotes
|
|
|
|
WRAPLOOP:
|
|
for ($frag_count = 0; ;$frag_count++)
|
|
{
|
|
print "\nDBG: Top of WRAPLOOP, line to process is: '$line'\n" if $wrapdbg;
|
|
print "DBG: top of WRAPLOOP a: frag_count = $frag_count, nesting_level = $nesting_level\n" if $wrapdbg;
|
|
print "DBG: tabsize = $tabsize, in_quotes = $in_quotes\n" if $wrapdbg;
|
|
|
|
$indentation = $nesting_level; # save indentation at start of every line
|
|
$width = $output_width - ($nesting_level * $tabsize);
|
|
|
|
print "DBG: top of WRAPLOOP: indentation = $indentation\n" if $wrapdbg;
|
|
print "DBG: width now $width \n" if $wrapdbg;
|
|
|
|
$line =~ s/^\s*//; # delete leading spaces
|
|
$line =~ s/,([^ \t])/, $1/g; # make sure commas are followed by a space for gcc2
|
|
|
|
|
|
if ($frag_count > 0) # make sure only 1st line of message hugs left margin
|
|
{
|
|
$indentation++;
|
|
$width -= $tabsize;
|
|
}
|
|
|
|
$at_left = 0; # recognize when there's no nested parens
|
|
$at_left = 1 if ($close_wrap eq 'N' and
|
|
($frag_count == 0 or ($frag_count > 0 and $nesting_level == 1)));
|
|
|
|
# Preprocess line, creating table mapping close- to open-parens:
|
|
|
|
print "\n\nDBG: line to process (width = $width, nesting_level = $nesting_level, in_quotes = $in_quotes):\n$line" if $pdbg or $delimdbg;
|
|
showkey $width if $pdbg or $delimdbg;
|
|
|
|
|
|
$first_unmatched_close = $width; # position of first unmatched close paren
|
|
$unmatched_close_nesting = $nesting_level; # the nesting level below which we'll consider a close paren to be unmatched
|
|
$initial_close = 0; # assume first character is not a close paren
|
|
|
|
@delims = (); # list of unmatched open delims
|
|
@delim_index = (); # for each open, record its position
|
|
@nesting_key = (); # record nesting level at each char position
|
|
@quoting_key = (); # record whether in quotations at each char position
|
|
|
|
# for each closer, we'll record the position of the corresponding opener in @delim_opener
|
|
|
|
# begin by resetting each position:
|
|
for ($i = 0; $i < length($line); $i++)
|
|
{
|
|
$delim_opener[$i] = -1;
|
|
}
|
|
|
|
for ($pos = 0; $pos < $width and $pos < length($line); $pos++)
|
|
{
|
|
$c = substr($line, $pos, 1);
|
|
|
|
print "DBG: delimiter de-bugging, column pos = $pos (char there = '$c')\n" if $delimdbg;
|
|
|
|
if (exists $open_delims{$c})
|
|
{
|
|
$before = ' ';
|
|
$before = substr($line, $pos-1, 1) if $pos > 0;
|
|
|
|
$beforetext = "";
|
|
$beforetext = substr($line, $pos - 8, 8) if ($pos >= 8); # looking for "operator"
|
|
|
|
$after = ' ';
|
|
if ($pos < (length($line) - 1))
|
|
{
|
|
$after = substr($line, $pos+1, 1);
|
|
$aftertext = substr($line, $pos+1);
|
|
}
|
|
# Exclude some special cases:
|
|
if (!($before eq '`' and $after eq '\'') and # `paren'
|
|
!($before eq ' ' and $after eq ' ' and $c eq '<') and # <space> < <space> (relop)
|
|
!( ($before eq $c or $after eq $c) and ($c eq '<')) and # two <'s in a row
|
|
!($c eq '<' and $after eq '=') and # <=
|
|
!($c eq '<' and ($after eq '"' or $before eq '"')) and # "< or <"
|
|
!($c eq '(' and $after eq ')') and # ()
|
|
!(($c eq '<' or $c eq '(') and $beforetext =~ /\boperator ?<?$/) and # operator<, operator<<, operator()
|
|
!($aftertext =~ /^first use/)
|
|
)
|
|
{
|
|
print "DBG: matched opening delim '$c', aftertext = '$aftertext'\n" if $delimdbg;
|
|
$nesting_level++;
|
|
push @delims, $c;
|
|
push @delim_index, $pos;
|
|
}
|
|
}
|
|
elsif (exists $close_delims{$c})
|
|
{
|
|
$before = ' ';
|
|
$before = substr($line, $pos-1, 1) if $pos > 0;
|
|
|
|
$beforetext = "";
|
|
$beforetext = substr($line, $pos - 10, 10) if ($pos >= 10); # looking for "operator"
|
|
|
|
$after = ' ';
|
|
if ($pos < (length($line) - 1))
|
|
{
|
|
$after = substr($line, $pos+1, 1);
|
|
$aftertext = substr($line, $pos+1);
|
|
}
|
|
# Exclude some special cases:
|
|
if (!($before eq '`' and $after eq '\'') and # `paren'
|
|
!($beforetext =~ /\s$/ and $c eq '>' and $after eq '>') and # whitespace >>
|
|
!($beforetext =~ /\s>$/ and $c eq '>' and $aftertext =~ /^\s/) and # whitespace >> whitespace
|
|
!($c eq '>' and $after eq '=') and # >=
|
|
!($c eq '>' and ($after eq '"' or $before eq '"')) and # "> or >"
|
|
!($c eq '>' and $beforetext =~ /\boperator ?>?$/) and # operator> or operator>>
|
|
!($c eq ')' and $before eq '(') and # ()
|
|
!($aftertext =~ /^first use/) and
|
|
!($before eq '-' and $c eq '>')) # special case: -> operator (!!)
|
|
{
|
|
print "DBG: matched closing delim '$c', aftertext = '$aftertext'\n" if $delimdbg;
|
|
$nesting_level--;
|
|
# If the nesting_level ever falls below its level at
|
|
# the beginning of the line, we have an unmatched
|
|
# close paren and we must force a break there.
|
|
if ($pos == 0)
|
|
{
|
|
# initial close delimiters don't count, we'll break after the nesting falls again
|
|
$initial_close = 1;
|
|
$unmatched_close_nesting--;
|
|
}
|
|
elsif ($close_wrap eq 'Y' and $in_quotes
|
|
and $first_unmatched_close > $pos
|
|
and $nesting_level < $unmatched_close_nesting)
|
|
{
|
|
$first_unmatched_close = $pos;
|
|
}
|
|
|
|
if (@delims > 0)
|
|
{
|
|
if ($c ne $opps{$delims[$#delims]})
|
|
{
|
|
if ($show_internal_err)
|
|
{
|
|
if (!$lognative)
|
|
{
|
|
lognative_header;
|
|
print LOGNATIVE "Raw unprocessed input line:\n$save_line_for_dbg\n\n"; # write out the unprocessed offending line }
|
|
$lognative = 1;
|
|
}
|
|
|
|
print LOGNATIVE "\nThe line at the point of the error was:\n$line\n";
|
|
print LOGNATIVE " " x $pos . "^\n";
|
|
print LOGNATIVE "\nNesting key: " . "@nesting_key\n";
|
|
|
|
print LOGNATIVE "\nSTL Decryptor ERROR: the char '$c' (position $pos) DOESN'T MATCH DELIMITER '$delims[$#delims]'!\n";
|
|
|
|
$choked = 1;
|
|
print "\n";
|
|
print " [An Internal STL Decryptor error has occurred while processing\n";
|
|
print " the line that follows. Note that the line has not been successfully\n";
|
|
print " wrapped, but substitutions should still be intact:]\n\n";
|
|
}
|
|
print "$line\n"; # write out the unwrapped line
|
|
next MAIN_LOOP;
|
|
}
|
|
else
|
|
{
|
|
pop @delims;
|
|
$delim_opener[$pos] = pop @delim_index; # map close index to open index
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elsif ($c =~ /[`']/)
|
|
{
|
|
$in_quotes = !$in_quotes;
|
|
}
|
|
$nesting_key[$pos] = $nesting_level; # track nesting level at each column
|
|
$quoting_key[$pos] = $in_quotes; # track nesting level at each column
|
|
}
|
|
|
|
# STEP 0: If there's an unmatched back-quote before the end of the line,
|
|
# and we're not in col. 1, and it isn't just `id', wrap before the back-quote:
|
|
|
|
if (length($line) > $width and substr($line, 0, $width-1) =~ /(`$id[^'`]*$)/) #` Fix syntax highlighting for emacs
|
|
{
|
|
$name_pos = $-[0];
|
|
|
|
if ($name_pos != 0)
|
|
{
|
|
print "*********** PRINT DBG 6 width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $name_pos) . "\n"));
|
|
$line = substr($line, $name_pos);
|
|
$nesting_level = $nesting_key[$name_pos - 1];
|
|
$in_quotes = $quoting_key[$name_pos - 1];
|
|
next WRAPLOOP;
|
|
}
|
|
}
|
|
|
|
# STEP 1: If there's an incomplete paren pair on the current line:
|
|
|
|
if (@delims)
|
|
{
|
|
#
|
|
# STEP 1A: Find the first open paren on the line whose matching close paren doesn't fit:
|
|
#
|
|
$open_pos = $delim_index[0];
|
|
|
|
while (1)
|
|
{
|
|
$beforeit = substr($line, 0, $open_pos);
|
|
|
|
# STEP 1Ai: If it's immediately preceded by >::ident[::ident...]
|
|
# or foo.template bar
|
|
# or foo.bar(...).template baz
|
|
|
|
if (($beforeit =~ /[>)](\s*(::|\.|->)?\s*$id)+$/) and $-[0] != 0)
|
|
{
|
|
# STEP 1A1a: If the opening angle bracket matching the 1st char of the r.e. above is on
|
|
# this line, move back to that position and go to 1Ai
|
|
$open_pos = $-[0];
|
|
if ($delim_opener[$open_pos] != -1)
|
|
{
|
|
$open_pos = $delim_opener[$open_pos];
|
|
next;
|
|
}
|
|
# STEP 1A1b: Else move to the first char of the r.e. above and go on to 1B (this is
|
|
# already where $open_pos indicates)
|
|
}
|
|
last;
|
|
}
|
|
|
|
if ($first_unmatched_close < $open_pos)
|
|
{
|
|
print "******** PRINT DBG 6A width=$width indent=$indentation ******\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $first_unmatched_close) . "\n"));
|
|
$line = substr($line, $first_unmatched_close);
|
|
$nesting_level = $nesting_key[$first_unmatched_close - 1];
|
|
$in_quotes = $quoting_key[$first_unmatched_close - 1];
|
|
next WRAPLOOP;
|
|
}
|
|
|
|
#
|
|
# STEP 1B: If we're on an open paren, and there's a comma earlier on the line at the same level,
|
|
# and the last such comma is not the first non-ws char on the line, wrap just before it
|
|
# and don't indent:
|
|
#
|
|
$c = substr($line, $open_pos, 1);
|
|
if (exists $open_delims{$c}) # if it's an open paren...
|
|
{
|
|
if ($in_quotes and scanback "$line")
|
|
{
|
|
# We've found the comma
|
|
if ($comma_wrap eq 'B' and $nesting_level > 0)
|
|
{
|
|
# Wrap just before $comma_pos:
|
|
print "******** PRINT DBG 7 width=$width indent=$indentation ******\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $comma_pos) . "\n"));
|
|
$line = substr($line, $comma_pos);
|
|
$nesting_level = $nesting_key[$comma_pos - 1];
|
|
$in_quotes = $quoting_key[$comma_pos - 1];
|
|
}
|
|
else
|
|
{
|
|
# Wrap just after $comma_pos:
|
|
print "******** PRINT DBG 8 width=$width indent=$indentation ******\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $comma_pos +1) . "\n"));
|
|
while (substr($line, $comma_pos + 1, 1) eq ' ')
|
|
{
|
|
$comma_pos++;
|
|
}
|
|
$line = substr($line, $comma_pos + 1);
|
|
$nesting_level = $nesting_key[$comma_pos];
|
|
$in_quotes = $quoting_key[$comma_pos];
|
|
}
|
|
next WRAPLOOP;
|
|
}
|
|
}
|
|
|
|
# STEP 1C: Else if it's an open paren:
|
|
# if $nesting_level is 0, wrap before the pattern
|
|
# if line begins at col. 1, wrap just after the open and indent the next line
|
|
|
|
$c = substr($line, $open_pos, 1);
|
|
if (exists $open_delims{$c}) # if it's an open paren...
|
|
{
|
|
print "*********** PRINT DBG 9 width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $open_pos + 1) . "\n"));
|
|
$width -= $tabsize;
|
|
$line = " " . substr($line, $open_pos + 1); # special case xtra leading indent
|
|
$nesting_level = $nesting_key[$open_pos];
|
|
$in_quotes = $quoting_key[$open_pos];
|
|
next WRAPLOOP;
|
|
}
|
|
else # It must be a close paren. Wrap just before it and unindent the next line:
|
|
{
|
|
print "*********** PRINT DBG 10 width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $open_pos) . "\n"));
|
|
$width += $tabsize;
|
|
$line = substr($line, $open_pos);
|
|
$nesting_level = $nesting_key[$open_pos - 1];
|
|
$in_quotes = $quoting_key[$open_pos - 1];
|
|
next WRAPLOOP;
|
|
}
|
|
}
|
|
elsif ($first_unmatched_close < $pos)
|
|
{
|
|
print "*********** PRINT DBG 10A width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $first_unmatched_close) . "\n"));
|
|
$line = substr($line, $first_unmatched_close);
|
|
$nesting_level = $nesting_key[$first_unmatched_close - 1];
|
|
$in_quotes = $quoting_key[$first_unmatched_close - 1];
|
|
next WRAPLOOP;
|
|
}
|
|
else
|
|
{
|
|
# STEP 2: If there is a comma at the current level of paren nesting AND
|
|
# we're not at a nesting level of 0:
|
|
$open_pos = $pos;
|
|
|
|
if (!$at_left and $in_quotes and scanback "$line")
|
|
{
|
|
if ($comma_wrap eq 'B' and $nesting_level > 0)
|
|
{
|
|
print "*********** PRINT DBG 11: width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $comma_pos) . "\n"));
|
|
$line = substr($line, $comma_pos);
|
|
$nesting_level = $nesting_key[$comma_pos - 1];
|
|
$in_quotes = $quoting_key[$comma_pos - 1];
|
|
}
|
|
else
|
|
{
|
|
print "*********** PRINT DBG 12: width=$width indent=$indentation *********\n" if $pdbg;
|
|
print2 ($indentation, (substr($line, 0, $comma_pos + 1) . "\n"));
|
|
while ($comma_pos < ($width - 1) and substr($line, $comma_pos + 1, 1) eq ' ')
|
|
{
|
|
$comma_pos++;
|
|
}
|
|
$line = substr($line, $comma_pos + 1);
|
|
$nesting_level = $nesting_key[$comma_pos];
|
|
$in_quotes = $quoting_key[$comma_pos];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# extra by LZ: if last part of line is "`identifier" we have an unbalanced
|
|
# nesting level, then break before the "`"
|
|
|
|
if (length($line) > $width )
|
|
{
|
|
$beforeit = substr($line, 0, $open_pos);
|
|
if ($line =~ /`$id/ or $line =~/`[+-=!*<>%^&|\/~]+/)
|
|
{
|
|
$name_pos = $-[0];
|
|
if ($name_pos != 0 and $name_pos < $width and
|
|
!(($beforeit =~ /`$id'/ or $beforeit =~ /`[+-=!*<>%^&|\/~]+'/)
|
|
and $+[0] < $width)) #'))) fix syntax highlighting for emacs
|
|
{
|
|
if (exists $close_delims{substr($line, 0, 1)}) # special case for leading close
|
|
{
|
|
print "*********** PRINT DBG 13: width=$width indent=$indentation *********\n" if $pdbg;
|
|
break_and_print_plain2 (($tab x ($indentation - 1)) .
|
|
substr($line, 0, $name_pos) . "\n");
|
|
}
|
|
else
|
|
{
|
|
print "*********** PRINT DBG 14: width=$width indent=$indentation *********\n" if $pdbg;
|
|
break_and_print_plain2 (($tab x $indentation) .
|
|
substr($line, 0, $name_pos) . "\n");
|
|
}
|
|
$line = substr($line, $name_pos);
|
|
$nesting_level = $nesting_key[$name_pos - 1];
|
|
$in_quotes = $quoting_key[$name_pos - 1];
|
|
next WRAPLOOP;
|
|
}
|
|
}
|
|
}
|
|
|
|
# STEP 3: Just break according to standard alrogithm
|
|
print "*********** PRINT DBG 15: width=$width indent=$indentation *********\n" if $pdbg;
|
|
$line = break_and_print_fragment ( $indentation, $width, $line);
|
|
|
|
return if $line eq "";
|
|
|
|
$nesting_level = $nesting_key[$broke_at];
|
|
$in_quotes = $quoting_key[$broke_at];
|
|
}
|
|
}
|
|
} # WRAPLOOP
|
|
}
|
|
|
|
|
|
#
|
|
# break entire line using "plain" rules:
|
|
# usage: break_and_print_plain line
|
|
#
|
|
|
|
sub break_and_print_plain {
|
|
my $line = shift(@_);
|
|
if ($output_width != 0)
|
|
{
|
|
return if ($line = break_and_print_fragment (0, $output_width, "$line")) eq "";
|
|
while (($line = break_and_print_fragment (1, $output_width - $tabsize, "$line")) ne "")
|
|
{}
|
|
}
|
|
else
|
|
{
|
|
$line =~ s/\s+\n/\n/g; # delete trailing space on a line
|
|
print "$line";
|
|
}
|
|
}
|
|
|
|
|
|
#
|
|
# Process line using "Plain" break algorithm up to first line break,
|
|
# return remainder of line for subsequent processing:
|
|
# usage: break_and_print_fragment indent line
|
|
#
|
|
# No matter what, don't break in the middle of a pathname...so as not
|
|
# to mess up tools that locate errors in files. If the line length has
|
|
# to exceed the /width setting, so be it in that case...
|
|
#
|
|
|
|
sub break_and_print_fragment {
|
|
my $indent = shift(@_);
|
|
my $width = shift(@_) - 1;
|
|
my $line = shift(@_);
|
|
|
|
$nl_pos = index($line, "\n");
|
|
if ($nl_pos == -1 or $nl_pos > $width)
|
|
{
|
|
if ($obj)
|
|
{
|
|
substr($line, $width - 1, 0) = "\n" if (length($line) > $width);
|
|
}
|
|
else
|
|
{
|
|
if (length($line) > $width)
|
|
{
|
|
if ($prefix ne "" and $line =~ /:\d+:\s/g and pos($line) > $width) # never break within pathname
|
|
{
|
|
substr($line, pos($line), 0) = "\n";
|
|
}
|
|
else
|
|
{
|
|
$pos = $width;
|
|
$theChar = substr($line, $pos, 1);
|
|
$theCharBefore = ($pos > 0) ? substr($line, $pos - 1, 1) : ' ';
|
|
$theCharAfter = substr($line, $pos + 1, 1);
|
|
|
|
while ( ($theChar !~ /[\n '`,:]/ and $pos > 0 and !($theChar =~ /\w/ and $theCharBefore !~ /\w/))
|
|
or ($theChar !~ /\s/ and $theCharBefore =~ /[:\/\\.]/)
|
|
or ($theChar eq ':' and $theCharAfter =~ /[\/\\.]/)
|
|
or ($theChar eq "'" and $theCharBefore !~ /\s/)
|
|
or ($theChar =~ /[A-Za-z]/ and $theCharBefore =~ /['"`]/)
|
|
)
|
|
{
|
|
$pos--;
|
|
$theCharAfter = $theChar;
|
|
$theChar = substr($line, $pos, 1);
|
|
$theCharBefore = ($pos > 0) ? substr($line, $pos - 1, 1) : ' ';
|
|
}
|
|
|
|
$pos-- if $pos > 0 and $theChar eq ':' and substr($line, $pos-1, 1) eq ':';
|
|
|
|
if ($pos == 0)
|
|
{
|
|
$pos += $width;
|
|
substr($line, $pos, 0) = "\n";
|
|
}
|
|
else
|
|
{
|
|
substr($line, $pos, $theChar eq ' ' ? 1 : 0) = "\n";
|
|
$pos += ($theChar eq ' ' ? 1 : 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$line =~ s/ +\n/\n/g; # delete trailing space on a line
|
|
|
|
$nl_pos = index($line, "\n");
|
|
if ($nl_pos == -1)
|
|
{
|
|
print2 ($indent, $line);
|
|
return "";
|
|
}
|
|
|
|
print2 ($indent, substr($line, 0, $nl_pos + 1));
|
|
$whats_left = substr($line, $nl_pos + 1);
|
|
$broke_at = $nl_pos - 1;
|
|
return "$whats_left";
|
|
}
|
|
|
|
|
|
sub println
|
|
{
|
|
if ($wrap_own_msgs)
|
|
{
|
|
break_and_println_plain shift(@_);
|
|
}
|
|
else
|
|
{
|
|
print shift(@_) . "\n";
|
|
}
|
|
}
|
|
|
|
|
|
#
|
|
# call break_and_print_plain/fragment, adjust leading comma
|
|
#
|
|
|
|
sub break_and_print_plain2 {
|
|
my $line = shift(@_);
|
|
$line =~ s/^(\s*) ,/$1,/; # Adjust leading comma
|
|
break_and_print_plain "$line";
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# break_and_println_plain: Break with Plain rules, add a newline:
|
|
#
|
|
|
|
sub break_and_println_plain {
|
|
break_and_print_plain shift(@_);
|
|
print "\n";
|
|
}
|
|
|
|
|
|
#
|
|
# print2: prints a line
|
|
# If using the 'Dave" break algorithm:
|
|
# Rule 1: Omits two spaces of indentation if there's a leading comma
|
|
# Rule 2: Reduces indentation by one tab if there's a leading close "paren"
|
|
# (unless already at far left)
|
|
#
|
|
# usage: print2 (indentation,line)
|
|
#
|
|
|
|
sub print2
|
|
{
|
|
my $indent = shift(@_);
|
|
my $line = shift(@_);
|
|
my $prefix = "";
|
|
|
|
if ($break_algorithm eq 'D')
|
|
{
|
|
if ($indent > 0) # special case for leading close - unindent just this line
|
|
{
|
|
$prefix = "$tab" x
|
|
((exists $close_delims{substr($line, 0, 1)} and $indent > 1) ? ($indent - 1) : $indent);
|
|
}
|
|
|
|
if (substr($line, 0, 1) eq "," and length($line) > 4) # if leading comma, omit two spaces
|
|
{ # of indentation
|
|
substr($prefix, length($prefix) - 4, 4) = " ";
|
|
}
|
|
|
|
# back up one space for open quotes to make alignment pretty in /break:D mode
|
|
if (substr($line, 0, 1) eq "`" and length($prefix) > 0) # ?? (was '`')
|
|
{
|
|
substr($prefix, 0, 1) = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$prefix = "$tab" x $indent;
|
|
}
|
|
|
|
print "$prefix" . $line;
|
|
}
|
|
|
|
|
|
#
|
|
# Scan backwards from position $open_pos for a comma at the same paren nesting level that is
|
|
# not the first non-whitespace on the line.
|
|
# return true if found, with $comma_pos indicating the position of the detected comma.
|
|
#
|
|
|
|
sub scanback
|
|
{
|
|
my $line = shift(@_);
|
|
my $c = substr($line, $open_pos, 1);
|
|
|
|
$nest_level = 0;
|
|
for ($comma_pos = $open_pos - 1; $comma_pos > 0; $comma_pos--) # scan back for comma at same level
|
|
{
|
|
$c = substr($line, $comma_pos, 1);
|
|
if (exists $open_delims{$c})
|
|
{ # bail if we come to an open before (working
|
|
last if $nest_level == 0; # to the left) its matching close
|
|
$nest_level--;
|
|
next;
|
|
}
|
|
elsif (exists $close_delims{$c})
|
|
{
|
|
$nest_level++;
|
|
next;
|
|
}
|
|
elsif ($c eq ',' and $nest_level == 0) # comma at same level?
|
|
{
|
|
for ($pos = $comma_pos - 1; $pos > 0; $pos--) # scan to start of line
|
|
{
|
|
if (substr($line, $pos, 1) !~ /\s/) # comma preceded by non-space?
|
|
{
|
|
return 1; # yes, so it is a valid comma
|
|
}
|
|
}
|
|
|
|
# It IS the first non-ws on the line.
|
|
last;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
sub lognative_header
|
|
{
|
|
open(LOGNATIVE, ">NativeLog.txt") or
|
|
die "STL Decryptor: Can't create NativeLog.txt. Bailing out.";
|
|
|
|
print LOGNATIVE "---------------------------------------------------------------------\n";
|
|
print LOGNATIVE "$STLFilt_ID\n";
|
|
print LOGNATIVE "---------------------------------------------------------------------\n";
|
|
|
|
print LOGNATIVE "Command line: '@save_args'\n";
|
|
|
|
print LOGNATIVE "banner = $banner\n";
|
|
print LOGNATIVE "break_algorithm = $break_algorithm\n";
|
|
print LOGNATIVE "comma_wrap = $comma_wrap\n";
|
|
print LOGNATIVE "close_wrap = $close_wrap\n";
|
|
print LOGNATIVE "output_width = $output_width\n";
|
|
print LOGNATIVE "tabsize = $tabsize\n";
|
|
print LOGNATIVE "advise_re_policy_opts = $advise_re_policy_opts\n";
|
|
print LOGNATIVE "reformat_linenumbers = $reformat_linenumbers\n";
|
|
print LOGNATIVE "wrap_own_msgs = $wrap_own_msgs\n";
|
|
print LOGNATIVE "header_policy = $header_policy\n";
|
|
print LOGNATIVE "with_policy = $with_policy\n";
|
|
print LOGNATIVE "headers_to_show = $headers_to_show\n";
|
|
print LOGNATIVE "candidate_policy = $candidate_policy\n";
|
|
print LOGNATIVE "pathname_policy = $pathname_policy\n";
|
|
print LOGNATIVE "show_backtraces = $show_backtraces\n";
|
|
print LOGNATIVE "---------------------------------------------------------------------\n";
|
|
print LOGNATIVE "Native input follows:\n";
|
|
print LOGNATIVE "---------------------------------------------------------------------\n\n";
|
|
}
|
|
|
|
|
|
|
|
sub showkey
|
|
{
|
|
my $width = shift (@_);
|
|
|
|
print ((" " x ($width - 1)) . "v\n");
|
|
print " 1 2 3 4 5 6 7 8 9\n";
|
|
print "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345\n";
|
|
}
|