From: Robert Dubner <[email protected]>
Date: Sun, 6 Sep 2026 16:33:11 -0400
Subject: [PATCH] cobol: Improve INSPECT performance.
Separated INSPECT library routines into single-byte and multi-byte
versions for one level of speed improvment, and created task-specific
routines for searching within memory for strings.
gcc/cobol/ChangeLog:
* genapi.cc (inspect_replacing): Use SBC version.
(parser_inspect_conv): Likewise.
libgcobol/ChangeLog:
* inspect.cc (the_alpha_and_omega_sbc): Modified.
(the_alpha_and_omega_backward_sbc): New routine.
(match_lengths_sbc): New routine.
(matches_sbc): Improved routine.
(set_trailing_bounds_sbc): Likewise.
(__gg__inspect_format_1_sbc): Likewise.
(__gg__inspect_format_2_sbc): New routine.
(__gg__inspect_format_4_sbc): New routine.
---
gcc/cobol/genapi.cc | 39 +-
libgcobol/inspect.cc | 1045 ++++++++++++++++++++++++++++++++++++------
2 files changed, 931 insertions(+), 153 deletions(-)
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 53d6c2be75c..11c0cfad721 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -10347,12 +10347,26 @@ inspect_replacing(int backward,
tree params = build_array_of_referlets(pcbl_index, pcbl_refers.data());
// Do the actual call:
- gg_call(VOID,
- "__gg__inspect_format_2",
- backward ? integer_one_node : integer_zero_node,
- integers,
- params,
- NULL_TREE);
+ charmap_t *charmap =
__gg__get_charmap(identifier_1.field->codeset.encoding);
+ if( charmap->stride() == 1 && !charmap->is_like_utf8() )
+ {
+ // The variables are ASCII or EBCDIC
+ gg_call(VOID,
+ "__gg__inspect_format_2_sbc",
+ backward ? integer_one_node : integer_zero_node,
+ integers,
+ params,
+ NULL_TREE);
+ }
+ else
+ {
+ gg_call(VOID,
+ "__gg__inspect_format_2",
+ backward ? integer_one_node : integer_zero_node,
+ integers,
+ params,
+ NULL_TREE);
+ }
}
void
@@ -10395,8 +10409,19 @@ parser_inspect_conv(cbl_refer_t input,
SHOW_PARSE_END
}
+ const char *format_4;
+ charmap_t *charmap = __gg__get_charmap(input.field->codeset.encoding);
+ if( charmap->stride() == 1 && !charmap->is_like_utf8() )
+ {
+ format_4 = "__gg__inspect_format_4_sbc";
+ }
+ else
+ {
+ format_4 = "__gg__inspect_format_4";
+ }
+
gg_call(CHAR_P,
- "__gg__inspect_format_4",
+ format_4,
backward ? integer_one_node : integer_zero_node,
input.field ? gg_get_address_of(input.field->var_decl_node)
: null_pointer_node,
diff --git a/libgcobol/inspect.cc b/libgcobol/inspect.cc
index 682caac38b3..ac212ef2945 100644
--- a/libgcobol/inspect.cc
+++ b/libgcobol/inspect.cc
@@ -8,7 +8,6 @@
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
- * * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
disclaimer
* in the documentation and/or other materials provided with the
* distribution.
@@ -290,9 +289,10 @@ typedef struct comparand_sbc
size_t id_2_index;
cbl_inspect_bound_t operation;
std::string identifier_3; // The thing to be found
-//q std::string identifier_5; // The replacement, for FORMAT 2
+ std::string identifier_5; // The replacement, for FORMAT 2
size_t alpha; // The start location within normalized_id_1
size_t omega; // The end+1 location within normalized_id_1
+ size_t trailing_bound;
size_t leading_count;
bool leading;
bool first;
@@ -710,8 +710,8 @@ the_alpha_and_omega_sbc(const std::string
&id_before,
// This is the AFTER delimiter. We look for the first occurrence of
that
// delimiter in id_1 that occurs to the left of BEFORE/omega
- alpha = haystack.substr(0, omega).find(id_after);
- if( alpha == std::string::npos )
+ alpha = haystack.find(id_after);
+ if( alpha == std::string::npos || alpha + id_after.length() > omega )
{
// If there is no AFTER to the left of omega, then we can't find
anything
// in this haystack.
@@ -728,6 +728,135 @@ the_alpha_and_omega_sbc(const std::string
&id_before,
}
}
+static void
+the_alpha_and_omega_backward_sbc(const std::string &id_before,
+ const std::string &id_after,
+ const std::string &haystack,
+ size_t &alpha,
+ size_t &omega)
+ {
+ alpha = 0;
+ omega = haystack.length();
+
+ if( id_before.length() )
+ {
+ size_t found = haystack.rfind(id_before);
+ if( found != std::string::npos )
+ {
+ alpha = found + id_before.length();
+ }
+ }
+
+ if( id_after.length() )
+ {
+ size_t found = haystack.rfind(id_after, omega - 1);
+ if( found != std::string::npos && found >= alpha )
+ {
+ omega = found;
+ }
+ else
+ {
+ omega = alpha;
+ }
+ }
+ }
+
+static void
+match_lengths_sbc(std::string &id_target,
+ const std::string &id_source)
+ {
+ id_target.assign(id_source.length(), id_target[0]);
+ }
+
+static inline bool
+matches_sbc(const std::string &haystack,
+ size_t offset,
+ const std::string &needle,
+ size_t length)
+ {
+ const char *candidate = haystack.data() + offset;
+ const char *pattern = needle.data();
+
+ if( length == 0 )
+ {
+ return true;
+ }
+
+ if( candidate[0] != pattern[0] )
+ {
+ return false;
+ }
+
+ if( length == 1 )
+ {
+ return true;
+ }
+
+ if( candidate[length-1] != pattern[length-1] )
+ {
+ return false;
+ }
+
+ if( length == 2 )
+ {
+ return true;
+ }
+
+ return memcmp(candidate + 1, pattern + 1, length - 2) == 0;
+ }
+
+static void
+set_trailing_bounds_sbc(std::vector<comparand_sbc> &comparands,
+ const std::string &haystack,
+ bool backward)
+ {
+ // Forward replacement never changes the unread suffix, and backward
+ // replacement never changes the unread prefix. Consequently, each
+ // TRAILING run can be found once instead of being rescanned at every
+ // candidate position.
+ for(size_t i=0; i<comparands.size(); i++)
+ {
+ comparand_sbc &comparand = comparands[i];
+ if( comparand.operation != bound_trailing_e )
+ {
+ continue;
+ }
+
+ size_t length = comparand.identifier_3.length();
+ if( length == 0 || comparand.alpha >= comparand.omega )
+ {
+ comparand.trailing_bound = backward
+ ? comparand.alpha
+ : comparand.omega;
+ continue;
+ }
+ if( backward )
+ {
+ comparand.trailing_bound = comparand.alpha;
+ while( length <= comparand.omega - comparand.trailing_bound
+ && matches_sbc(haystack,
+ comparand.trailing_bound,
+ comparand.identifier_3,
+ length) )
+ {
+ comparand.trailing_bound += length;
+ }
+ }
+ else
+ {
+ comparand.trailing_bound = comparand.omega;
+ while( length <= comparand.trailing_bound - comparand.alpha
+ && matches_sbc(haystack,
+ comparand.trailing_bound - length,
+ comparand.identifier_3,
+ length) )
+ {
+ comparand.trailing_bound -= length;
+ }
+ }
+ }
+ }
+
static void
the_alpha_and_omega_backward( const normalized_operand &id_before,
const normalized_operand &id_after,
@@ -2672,16 +2801,11 @@ __gg__inspect_format_4( int backward,
extern "C"
void
__gg__inspect_format_1_sbc( int backward,
- size_t integers[],
+ const size_t integers[],
const cblc_referlet_t *params)
{
// When this routine is called, we know we are working in a
single-byte-coded
// codeset like ASCII or EBCDIC.
- if( backward )
- {
- return inspect_backward_format_1(integers, params);
- }
-
size_t int_index = 0;
size_t cblc_index = 0;
@@ -2702,6 +2826,7 @@ __gg__inspect_format_1_sbc( int backward,
= normalize_id_sbc(id1, id1_o, id1_s,
id1->encoding);
std::vector<comparand_sbc> comparands;
+ comparands.reserve(n_identifier_2);
for(size_t i=0; i<n_identifier_2; i++)
{
@@ -2753,11 +2878,22 @@ __gg__inspect_format_1_sbc( int backward,
id4_after_o,
id4_after_s,
id1->encoding);
- the_alpha_and_omega_sbc(normalized_id_4_before,
- normalized_id_4_after,
- normalized_id_1,
- next_comparand.alpha,
- next_comparand.omega);
+ if( backward )
+ {
+ the_alpha_and_omega_backward_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+ else
+ {
+ the_alpha_and_omega_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
comparands.push_back(next_comparand);
break;
@@ -2771,6 +2907,7 @@ __gg__inspect_format_1_sbc( int backward,
// We need to build up pair_count comparand structures:
+ comparands.reserve(comparands.size() + pair_count);
for(size_t k=0; k<pair_count; k++)
{
comparand_sbc next_comparand = {};
@@ -2806,11 +2943,22 @@ __gg__inspect_format_1_sbc( int backward,
id4_after_o,
id4_after_s,
id1->encoding);
- the_alpha_and_omega_sbc(normalized_id_4_before,
- normalized_id_4_after,
- normalized_id_1,
- next_comparand.alpha,
- next_comparand.omega);
+ if( backward )
+ {
+ the_alpha_and_omega_backward_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+ else
+ {
+ the_alpha_and_omega_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
next_comparand.leading = true;
next_comparand.leading_count = 0;
comparands.push_back(next_comparand);
@@ -2820,170 +2968,239 @@ __gg__inspect_format_1_sbc( int backward,
}
}
- // We are now ready to walk through identifier-1, character by
- // character, checking each of the comparands for a match:
-
- // We are now set up to accomplish the data flow described
- // in the language specification. We loop through the
- // the character positions in normalized_id_1:
- size_t leftmost = 0;
- size_t rightmost = leftmost + normalized_id_1.length();
+ set_trailing_bounds_sbc(comparands, normalized_id_1, backward);
- while( leftmost < rightmost )
+ if( backward )
{
- // For each leftmost position, we check each of the
- // pairs:
+ size_t rightmost = normalized_id_1.length();
+ size_t the_end_of_the_world = rightmost;
- for(size_t k=0; k<comparands.size(); k++)
+ while( rightmost > 0 )
{
- if( leftmost < comparands[k].alpha )
- {
- // This can't be a match, because leftmost is
- // to the left of the comparand's alpha.
- continue;
- }
- if( leftmost + comparands[k].identifier_3.length() >
comparands[k].omega)
- {
- // This can't be a match, because the rightmost
- // character of the comparand falls to the right
- // of the comparand's omega
- continue;
- }
- // A match is theoretically possible, because all
- // the characters of the comparand fall between
- // alpha and omega:
- bool possible_match = true;
+ size_t rightmost_delta = 0;
+ rightmost -= 1;
- if( comparands[k].operation != bound_characters_e )
+ for(size_t k=0; k<comparands.size(); k++)
{
- for(size_t m=0; m<comparands[k].identifier_3.length(); m++)
+ size_t length = comparands[k].identifier_3.length();
+
+ if( rightmost < comparands[k].alpha )
{
- if( comparands[k].identifier_3[m] !=
normalized_id_1[leftmost+m] )
- {
- possible_match = false;
- break;
- }
+ continue;
}
- }
- if( possible_match )
- {
- // The characters of the comparand match the
- // characters at leftmost.
- bool match = false;
- switch( comparands[k].operation )
+ if( rightmost + length > comparands[k].omega )
{
- case bound_first_e:
- // This can't happen in a FORMAT_1
- warnx("The compiler goofed: "
- "INSPECT FORMAT 1 "
- "shouldn't have "
- "bound_first_e");
- abort();
- break;
+ continue;
+ }
+ if( rightmost + length > the_end_of_the_world )
+ {
+ continue;
+ }
- case bound_characters_e:
- match = true;
- break;
+ bool possible_match = true;
+ if( comparands[k].operation != bound_characters_e )
+ {
+ possible_match = matches_sbc(normalized_id_1,
+ rightmost,
+ comparands[k].identifier_3,
+ length);
+ }
- case bound_all_e:
- {
- // We have a match.
- match = true;
- break;
- }
+ if( possible_match )
+ {
+ bool match = false;
- case bound_leading_e:
+ switch( comparands[k].operation )
{
- // We have a match at leftmost. But we need to figure out if
this
- // particular match is valid for LEADING.
-
- // Hang onto your hat. This is delightfully clever.
- //
- // This position is LEADING if:
- // 1) .leading is still true
- // 2) leftmost / (length_of_comparand ) = current_count
- //
- // I get chills every time I look at that.
+ case bound_first_e:
+ warnx("The compiler goofed: "
+ "INSPECT FORMAT 1 "
+ "shouldn't have "
+ "bound_first_e");
+ abort();
+ break;
+
+ case bound_characters_e:
+ case bound_all_e:
+ match = true;
+ break;
- if( comparands[k].leading )
- {
- // So far, so good.
- size_t count = ((leftmost - comparands[k].alpha))
- / comparands[k].identifier_3.length();
- if( count == comparands[k].leading_count )
+ case bound_leading_e:
+ if( comparands[k].leading
+ && rightmost
+ + length * (comparands[k].leading_count + 1)
+ == comparands[k].omega )
{
- // This means that the match here is just the latest of a
- // string of LEADING matches that started at .alpha
comparands[k].leading_count += 1;
match = true;
+ rightmost_delta = length - 1;
}
+ break;
+
+ case bound_trailing_e:
+ match = rightmost + length <= comparands[k].trailing_bound
+ && (rightmost - comparands[k].alpha) % length == 0;
+ break;
+ }
+
+ if( match )
+ {
+ id_2_results[comparands[k].id_2_index].result += 1;
+ the_end_of_the_world = rightmost;
+ if( rightmost_delta > rightmost )
+ {
+ rightmost = 0;
+ }
+ else
+ {
+ rightmost -= rightmost_delta;
}
break;
}
+ }
+ else
+ {
+ comparands[k].leading = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // We are now ready to walk through identifier-1, character by
+ // character, checking each of the comparands for a match.
+ size_t leftmost = 0;
+ size_t rightmost = normalized_id_1.length();
- case bound_trailing_e:
+ while( leftmost < rightmost )
+ {
+ // For each leftmost position, we check each of the pairs.
+
+ for(size_t k=0; k<comparands.size(); k++)
+ {
+ size_t length = comparands[k].identifier_3.length();
+
+ if( leftmost < comparands[k].alpha )
+ {
+ // This can't be a match, because leftmost is
+ // to the left of the comparand's alpha.
+ continue;
+ }
+ if( leftmost + length > comparands[k].omega )
+ {
+ // This can't be a match, because the rightmost
+ // character of the comparand falls to the right
+ // of the comparand's omega
+ continue;
+ }
+ // A match is theoretically possible, because all
+ // the characters of the comparand fall between
+ // alpha and omega:
+ bool possible_match = true;
+
+ if( comparands[k].operation != bound_characters_e )
+ {
+ possible_match = matches_sbc(normalized_id_1,
+ leftmost,
+ comparands[k].identifier_3,
+ length);
+ }
+ if( possible_match )
+ {
+ // The characters of the comparand match the
+ // characters at leftmost.
+ bool match = false;
+ switch( comparands[k].operation )
{
- // We have a match at leftmost.
- //
- // We want to know if this is a trailing match. For that to
be,
- // all of the possible matches from here to the omega have to
be
- // true as well:
+ case bound_first_e:
+ // This can't happen in a FORMAT_1
+ warnx("The compiler goofed: "
+ "INSPECT FORMAT 1 "
+ "shouldn't have "
+ "bound_first_e");
+ abort();
+ break;
+
+ case bound_characters_e:
+ match = true;
+ break;
- if( (comparands[k].omega-leftmost)
- % comparands[k].identifier_3.length() == 0 )
+ case bound_all_e:
{
- // The remaining number of characters is correct for a
match.
- // Keep checking.
-
- // Assume a match until we learn otherwise:
+ // We have a match.
match = true;
- size_t local_left = leftmost;
- local_left += comparands[k].identifier_3.length();
- while( match && local_left < comparands[k].omega )
+ break;
+ }
+
+ case bound_leading_e:
+ {
+ // We have a match at leftmost. But we need to figure out
if this
+ // particular match is valid for LEADING.
+
+ // Hang onto your hat. This is delightfully clever.
+ //
+ // This position is LEADING if:
+ // 1) .leading is still true
+ // 2) leftmost / (length_of_comparand ) = current_count
+ //
+ // I get chills every time I look at that.
+
+ if( comparands[k].leading )
{
- for(size_t m=0; m<comparands[k].identifier_3.length();
m++)
+ // So far, so good.
+ size_t count = ((leftmost - comparands[k].alpha))
+ / length;
+ if( count == comparands[k].leading_count )
{
- if( comparands[k].identifier_3[m]
- !=
normalized_id_1[local_left+m] )
- {
- // We have a mismatched character, so no trailing
match is
- // possible
- match = false;
- break;
- }
+ // This means that the match here is just the latest of
a
+ // string of LEADING matches that started at .alpha
+ comparands[k].leading_count += 1;
+ match = true;
}
- local_left += comparands[k].identifier_3.length();
}
+ break;
+ }
+
+ case bound_trailing_e:
+ {
+ // We have a match at leftmost.
+ //
+ // We want to know if this is a trailing match. For that
to be,
+ // all of the possible matches from here to the omega have
to be
+ // true as well:
+
+ match = leftmost >= comparands[k].trailing_bound
+ && (comparands[k].omega-leftmost) % length == 0;
+ break;
}
- break;
}
- }
- if( match )
- {
- // We have a match at leftmost:
+ if( match )
+ {
+ // We have a match at leftmost:
- // Bump the result counter
- id_2_results[comparands[k].id_2_index].result += 1;
+ // Bump the result counter
+ id_2_results[comparands[k].id_2_index].result += 1;
- // Adjust the leftmost pointer to point to
- // the rightmost character of the matched
- // string, keeping in mind that it will be
- // bumped again after we break out of the
- // k<pair_count loop:
- leftmost += comparands[k].identifier_3.length() - 1;
- break;
+ // Adjust the leftmost pointer to point to
+ // the rightmost character of the matched
+ // string, keeping in mind that it will be
+ // bumped again after we break out of the
+ // k<pair_count loop:
+ leftmost += length - 1;
+ break;
+ }
+ }
+ else
+ {
+ // We are within alpha/omega, but there was no
+ // match, which permanently disqualifies the
+ // possibility of LEADING
+ comparands[k].leading = false;
}
}
- else
- {
- // We are within alpha/omega, but there was no
- // match, which permanently disqualifies the
- // possibility of LEADING
- comparands[k].leading = false;
- }
+ leftmost += 1;
}
- leftmost += 1;
}
// Add our results to the identifier_2 values:
@@ -3012,3 +3229,539 @@ __gg__inspect_format_1_sbc( int backward,
truncation_e);
}
}
+
+extern "C"
+void
+__gg__inspect_format_2_sbc( int backward,
+ const size_t integers[],
+ const cblc_referlet_t *params)
+ {
+ // When this routine is called, we know we are working in a
single-byte-coded
+ // codeset like ASCII or EBCDIC.
+ size_t int_index = 0;
+ size_t cblc_index = 0;
+
+ // Reference the language specification for the meanings of
identifier_X
+
+ // Pick up identifier_1, which is the string being inspected.
+ cblc_field_t *id1 = params[cblc_index].field;
+ size_t id1_o = params[cblc_index].offset;
+ size_t id1_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ std::string normalized_id_1
+ = normalize_id_sbc(id1, id1_o, id1_s, id1->encoding);
+
+ std::vector<comparand_sbc> comparands;
+
+ // Pick up the count of operations.
+ size_t nbounds = integers[int_index++];
+ comparands.reserve(nbounds);
+
+ for(size_t j=0; j<nbounds; j++)
+ {
+ cbl_inspect_bound_t operation
+ = (cbl_inspect_bound_t)integers[int_index++];
+
+ switch( operation )
+ {
+ case bound_characters_e:
+ {
+ comparand_sbc next_comparand = {};
+ next_comparand.operation = operation;
+
+ const cblc_field_t *id5 = params[cblc_index].field;
+ size_t id5_o = params[cblc_index].offset;
+ size_t id5_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ const cblc_field_t *id4_before = params[cblc_index].field;
+ size_t id4_before_o = params[cblc_index].offset;
+ size_t id4_before_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ const cblc_field_t *id4_after = params[cblc_index].field;
+ size_t id4_after_o = params[cblc_index].offset;
+ size_t id4_after_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ next_comparand.identifier_3.assign(1, '\0');
+ next_comparand.identifier_5
+ = normalize_id_sbc(id5, id5_o, id5_s, id1->encoding);
+ next_comparand.identifier_5.resize(1);
+
+ std::string normalized_id_4_before
+ = normalize_id_sbc(id4_before,
+ id4_before_o,
+ id4_before_s,
+ id1->encoding);
+ std::string normalized_id_4_after
+ = normalize_id_sbc(id4_after,
+ id4_after_o,
+ id4_after_s,
+ id1->encoding);
+
+ if( backward )
+ {
+ the_alpha_and_omega_backward_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+ else
+ {
+ the_alpha_and_omega_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+ comparands.push_back(next_comparand);
+ break;
+ }
+
+ default:
+ {
+ // There are pair_count identifier-3/identifier-5 pairs, each
with
+ // possible PHRASE1 modifiers.
+ size_t pair_count = integers[int_index++];
+ comparands.reserve(comparands.size() + pair_count);
+
+ for(size_t k=0; k<pair_count; k++)
+ {
+ comparand_sbc next_comparand = {};
+ next_comparand.operation = operation;
+
+ const cblc_field_t *id3 = params[cblc_index].field;
+ size_t id3_o = params[cblc_index].offset;
+ size_t id3_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ const cblc_field_t *id5 = params[cblc_index].field;
+ size_t id5_o = params[cblc_index].offset;
+ size_t id5_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ const cblc_field_t *id4_before = params[cblc_index].field;
+ size_t id4_before_o = params[cblc_index].offset;
+ size_t id4_before_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ const cblc_field_t *id4_after = params[cblc_index].field;
+ size_t id4_after_o = params[cblc_index].offset;
+ size_t id4_after_s = params[cblc_index].size;
+ cblc_index += 1;
+
+ next_comparand.identifier_3
+ = normalize_id_sbc(id3, id3_o, id3_s, id1->encoding);
+ next_comparand.identifier_5
+ = normalize_id_sbc(id5, id5_o, id5_s, id1->encoding);
+
+ if( id3->attr & FIGCONST_MASK )
+ {
+ match_lengths_sbc(next_comparand.identifier_3,
+ next_comparand.identifier_5);
+ }
+ else if( id5->attr & FIGCONST_MASK )
+ {
+ match_lengths_sbc(next_comparand.identifier_5,
+ next_comparand.identifier_3);
+ }
+
+ std::string normalized_id_4_before
+ = normalize_id_sbc(id4_before,
+ id4_before_o,
+ id4_before_s,
+ id1->encoding);
+ std::string normalized_id_4_after
+ = normalize_id_sbc(id4_after,
+ id4_after_o,
+ id4_after_s,
+ id1->encoding);
+
+ if( backward )
+ {
+ the_alpha_and_omega_backward_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+ else
+ {
+ the_alpha_and_omega_sbc(normalized_id_4_before,
+ normalized_id_4_after,
+ normalized_id_1,
+ next_comparand.alpha,
+ next_comparand.omega);
+ }
+
+ next_comparand.leading = true;
+ next_comparand.leading_count = 0;
+ next_comparand.first = true;
+ comparands.push_back(next_comparand);
+ }
+ break;
+ }
+ }
+ }
+
+ set_trailing_bounds_sbc(comparands, normalized_id_1, backward);
+
+ if( backward )
+ {
+ size_t rightmost = normalized_id_1.length();
+ size_t the_end_of_the_world = rightmost;
+
+ while( rightmost > 0 )
+ {
+ size_t rightmost_delta = 0;
+ rightmost -= 1;
+
+ for(size_t k=0; k<comparands.size(); k++)
+ {
+ size_t length = comparands[k].identifier_3.length();
+
+ if( rightmost < comparands[k].alpha )
+ {
+ continue;
+ }
+ if( rightmost + length > comparands[k].omega )
+ {
+ continue;
+ }
+ if( rightmost + length > the_end_of_the_world )
+ {
+ continue;
+ }
+
+ bool possible_match = true;
+ if( comparands[k].operation != bound_characters_e )
+ {
+ possible_match = matches_sbc(normalized_id_1,
+ rightmost,
+ comparands[k].identifier_3,
+ length);
+ }
+
+ if( possible_match )
+ {
+ bool match = false;
+
+ switch( comparands[k].operation )
+ {
+ case bound_first_e:
+ warnx("The compiler goofed: "
+ "INSPECT FORMAT 2 "
+ "shouldn't have "
+ "bound_first_e");
+ abort();
+ break;
+
+ case bound_characters_e:
+ case bound_all_e:
+ match = true;
+ break;
+
+ case bound_leading_e:
+ if( comparands[k].leading
+ && rightmost
+ + length * (comparands[k].leading_count + 1)
+ == comparands[k].omega )
+ {
+ comparands[k].leading_count += 1;
+ match = true;
+ rightmost_delta = length - 1;
+ }
+ break;
+
+ case bound_trailing_e:
+ match = rightmost + length <= comparands[k].trailing_bound
+ && (rightmost - comparands[k].alpha) % length == 0;
+ break;
+ }
+
+ if( match )
+ {
+ memcpy(&normalized_id_1[rightmost],
+ comparands[k].identifier_5.data(),
+ comparands[k].identifier_5.length());
+ the_end_of_the_world = rightmost;
+ if( rightmost_delta > rightmost )
+ {
+ rightmost = 0;
+ }
+ else
+ {
+ rightmost -= rightmost_delta;
+ }
+ break;
+ }
+ }
+ else
+ {
+ comparands[k].leading = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ size_t leftmost = 0;
+ size_t rightmost = normalized_id_1.length();
+
+ while( leftmost < rightmost )
+ {
+ for(size_t k=0; k<comparands.size(); k++)
+ {
+ size_t length = comparands[k].identifier_3.length();
+
+ if( leftmost < comparands[k].alpha )
+ {
+ continue;
+ }
+ if( leftmost + length > comparands[k].omega )
+ {
+ continue;
+ }
+
+ bool possible_match = true;
+ if( comparands[k].operation != bound_characters_e )
+ {
+ possible_match = matches_sbc(normalized_id_1,
+ leftmost,
+ comparands[k].identifier_3,
+ length);
+ }
+
+ if( possible_match )
+ {
+ bool match = false;
+
+ switch( comparands[k].operation )
+ {
+ case bound_characters_e:
+ case bound_all_e:
+ match = true;
+ break;
+
+ case bound_first_e:
+ if( comparands[k].first )
+ {
+ match = true;
+ comparands[k].first = false;
+ }
+ break;
+
+ case bound_leading_e:
+ if( comparands[k].leading )
+ {
+ size_t count = (leftmost - comparands[k].alpha) / length;
+ if( count == comparands[k].leading_count )
+ {
+ comparands[k].leading_count += 1;
+ match = true;
+ }
+ }
+ break;
+
+ case bound_trailing_e:
+ match = leftmost >= comparands[k].trailing_bound
+ && (comparands[k].omega - leftmost) % length == 0;
+ break;
+ }
+
+ if( match )
+ {
+ memcpy(&normalized_id_1[leftmost],
+ comparands[k].identifier_5.data(),
+ comparands[k].identifier_5.length());
+ leftmost += length - 1;
+ break;
+ }
+ }
+ else
+ {
+ comparands[k].leading = false;
+ }
+ }
+ leftmost += 1;
+ }
+ }
+ charmap_t *charmap = __gg__get_charmap(id1->encoding);
+ unsigned char *id1_data = id1->data + id1_o;
+ charmap->memset(id1_data, charmap->mapped_character(ascii_space),
id1_s);
+ memcpy(id1_data,
+ normalized_id_1.data(),
+ std::min(normalized_id_1.length(), id1_s));
+ }
+
+extern "C"
+void
+__gg__inspect_format_4_sbc( int backward,
+ cblc_field_t *input,
+ size_t input_offset,
+ size_t input_size,
+ const cblc_field_t *original,
+ size_t original_offset,
+ size_t original_size,
+ const cblc_field_t *replacement,
+ size_t replacement_offset,
+ size_t replacement_size,
+ const cblc_field_t *after,
+ size_t after_offset,
+ size_t after_size,
+ const cblc_field_t *before,
+ size_t before_offset,
+ size_t before_size)
+ {
+ // When this routine is called, we know we are working in a
single-byte-coded
+ // codeset like ASCII or EBCDIC.
+ cbl_figconst_t figconst_original
+ = static_cast<cbl_figconst_t>(original->attr & FIGCONST_MASK);
+ cbl_figconst_t figconst_replacement
+ = static_cast<cbl_figconst_t>(replacement->attr & FIGCONST_MASK);
+ int figswitch = (figconst_original ? 2 : 0)
+ + (figconst_replacement ? 1 : 0);
+
+ switch( figswitch )
+ {
+ case 0:
+ break;
+ case 1:
+ replacement_size = (size_t)(-1LL);
+ break;
+ case 2:
+ original_size = 1;
+ break;
+ case 3:
+ replacement_size = original_size = 1;
+ break;
+ }
+
+ if( before && before_size && before->attr & FIGCONST_MASK )
+ {
+ before_size = 1;
+ }
+ if( after && after_size && after->attr & FIGCONST_MASK )
+ {
+ after_size = 1;
+ }
+
+ bool all = replacement_size == (size_t)(-1LL);
+ if( all )
+ {
+ replacement_size = 1;
+ }
+
+ std::string str_input
+ = normalize_id_sbc(input,
+ input_offset,
+ input_size,
+ input->encoding);
+ std::string str_original
+ = normalize_id_sbc(original,
+ original_offset,
+ original_size,
+ input->encoding);
+ std::string str_replacement
+ = normalize_id_sbc(replacement,
+ replacement_offset,
+ replacement_size,
+ input->encoding);
+ std::string str_after
+ = normalize_id_sbc(after,
+ after_offset,
+ after_size,
+ input->encoding);
+ std::string str_before
+ = normalize_id_sbc(before,
+ before_offset,
+ before_size,
+ input->encoding);
+
+ if( all )
+ {
+ str_replacement.assign(str_original.length(), str_replacement[0]);
+ }
+
+ size_t leftmost;
+ size_t rightmost;
+
+ if( backward )
+ {
+ if( str_after.empty() )
+ {
+ rightmost = str_input.length();
+ }
+ else
+ {
+ size_t found = str_input.rfind(str_after, str_input.length());
+ rightmost = found == std::string::npos ? 0 : found;
+ }
+
+ if( str_before.empty() )
+ {
+ leftmost = 0;
+ }
+ else
+ {
+ size_t found = str_input.rfind(str_before, rightmost);
+ leftmost = found == std::string::npos
+ ? 0
+ : found + str_before.length();
+ }
+ }
+ else
+ {
+ if( str_after.empty() )
+ {
+ leftmost = 0;
+ }
+ else
+ {
+ size_t found = str_input.find(str_after);
+ leftmost = found == std::string::npos
+ ? str_input.length()
+ : found + str_after.length();
+ }
+
+ if( str_before.empty() )
+ {
+ rightmost = str_input.length();
+ }
+ else
+ {
+ size_t found = str_input.find(str_before, leftmost);
+ rightmost = found == std::string::npos ? str_input.length() :
found;
+ }
+ }
+
+ if( leftmost < rightmost )
+ {
+ unsigned char conversion[256];
+ for(size_t i=0; i<256; i++)
+ {
+ conversion[i] = static_cast<unsigned char>(i);
+ }
+
+ // Construct the table backwards so that the first occurrence of a
+ // repeated original character supplies its replacement.
+ for(size_t i=str_original.length(); i>0; i--)
+ {
+ unsigned char from = static_cast<unsigned char>(str_original[i-1]);
+ conversion[from] = static_cast<unsigned
char>(str_replacement[i-1]);
+ }
+
+ for(size_t i=leftmost; i<rightmost; i++)
+ {
+ unsigned char from = static_cast<unsigned char>(str_input[i]);
+ str_input[i] = static_cast<char>(conversion[from]);
+ }
+ }
+
+ memcpy(input->data + input_offset,
+ str_input.data(),
+ std::min(str_input.length(), input_size));
+ }
--
2.34.1