src/ifdefs.cc
/* For each #if in the file, look up its associated #elif/#else/#endif chain.
 * If every directive in the range has exactly the same mask, and every
 * source line in the range is included in a subset of that mask, then we
 * don't need to do anything. Otherwise, we'll fall back on the guaranteed
 * solution: split out N copies of the entire range, one for each version.
 */
For each #if in the file, look up its associated #elif/#else/#endif chain.
If every directive in the range has exactly the same mask, and every
source line in the range is included in a subset of that mask, then we
don't need to do anything. Otherwise, we'll fall back on the guaranteed
solution: split out N copies of the entire range, one for each version.
For each #if in the file look up its associated #elif / #else / #endif chain . If every directive in the range has exactly the same mask and every source line in the range is included in a subset of that mask then we don ' t need to do anything . Otherwise we ' ll fall back on the guaranteed solution : split out N copies of the entire range one for each version .
static void split_if_elif_ranges_by_version(Difdef::Diff &diff)
{
    for (size_t i=0; i < diff.lines.size(); ++i) {
        const std::string &text = *diff.lines[i].text;
        CStateMachine state_machine(text);
        if (!matches_if_directive(text) && !state_machine.in_something())
            continue;
        size_t end_of_initial_multiline_construct =
            (state_machine.in_something() ? diff.lines.size() : i);
        bool need_to_split = false;
        size_t end_of_range = diff.lines.size();
        mask_t desired_mask = diff.lines[i].mask;
        std::vector<std::stack<char> > nest(diff.dimension);
        std::vector<CStateMachine> state_machines(diff.dimension);
        for (size_t j = i; j < diff.lines.size(); ++j) {
            if (!contains(desired_mask, diff.lines[j].mask)) {
                need_to_split = true;
            }
            const std::string &text = *diff.lines[j].text;
            const bool is_if = matches_if_directive(text);
            const bool is_elif = matches_pp_directive(text, "elif");
            const bool is_else = matches_pp_directive(text, "else");
            const bool is_endif = matches_pp_directive(text, "endif");
            const bool is_any_pp = is_if || is_elif || is_else || is_endif;
            for (int v=0; v < diff.dimension; ++v) {
                if (!diff.lines[j].in_file(v)) continue;
                if (!state_machines[v].in_something()) {
                    if (is_any_pp && (diff.lines[j].mask != desired_mask)) {
                        if (nest[v].size() == (is_if ? 0 : 1))
                            need_to_split = true;
                    }
                    if (is_if) {
                        nest[v].push('i');
                    } else if (is_else) {
                        assert(nest[v].top() == 'i');
                        nest[v].top() = 'e';
                    } else if (is_endif) {
                        assert(!nest[v].empty());
                        nest[v].pop();
                    }
                }
                state_machines[v].update(text);
            }
            bool someone_is_in_pp_nest = false;
            bool someone_is_in_multiline_construct = false;
            for (int v=0; v < diff.dimension; ++v) {
                if (state_machines[v].in_something())
                    someone_is_in_multiline_construct = true;
                if (!nest[v].empty())
                    someone_is_in_pp_nest = true;
            }
            if (someone_is_in_multiline_construct) {
                if (j < diff.lines.size() &&
                        diff.lines[j].mask != diff.lines[j+1].mask) {
                    need_to_split = true;
                }
            } else {
                end_of_initial_multiline_construct =
                    std::min(end_of_initial_multiline_construct, j);
                if (!someone_is_in_pp_nest) {
                    end_of_range = j+1;
                    break;
                }
            }
        }
        assert(i+1 < end_of_range && end_of_range <= diff.lines.size());
        if (need_to_split) {
            std::vector<std::vector<const std::string *> > split_versions(diff.dimension);
            for (size_t j = i; j < end_of_range; ++j) {
                for (int v=0; v < diff.dimension; ++v) {
                    if (!diff.lines[j].in_file(v)) continue;
                    split_versions[v].push_back(diff.lines[j].text);
                }
            }
            Difdef::Diff split_merge = Difdef::simply_concatenate(split_versions);
            diff.lines.erase(diff.lines.begin()+i, diff.lines.begin()+end_of_range);
            diff.lines.insert(diff.lines.begin()+i, split_merge.lines.begin(), split_merge.lines.end());
            i += split_merge.lines.size()-1;
        } else {
            i = end_of_initial_multiline_construct;
        }
    }
}
static void split_if_elif_ranges_by_version ( Difdef :: Diff & diff ) { for ( size_t i = 0 ; i < diff . lines . size ( ) ; ++ i ) { const std :: string & text = * diff . lines [ i ] . text ; CStateMachine state_machine ( text ) ; if ( ! matches_if_directive ( text ) && ! state_machine . in_something ( ) ) continue ; size_t end_of_initial_multiline_construct = ( state_machine . in_something ( ) ? diff . lines . size ( ) : i ) ; bool need_to_split = false ; size_t end_of_range = diff . lines . size ( ) ; mask_t desired_mask = diff . lines [ i ] . mask ; std :: vector < std :: stack < char > > nest ( diff . dimension ) ; std :: vector < CStateMachine > state_machines ( diff . dimension ) ; for ( size_t j = i ; j < diff . lines . size ( ) ; ++ j ) { if ( ! contains ( desired_mask , diff . lines [ j ] . mask ) ) { need_to_split = true ; } const std :: string & text = * diff . lines [ j ] . text ; const bool is_if = matches_if_directive ( text ) ; const bool is_elif = matches_pp_directive ( text , " " ) ; const bool is_else = matches_pp_directive ( text , " " ) ; const bool is_endif = matches_pp_directive ( text , " " ) ; const bool is_any_pp = is_if || is_elif || is_else || is_endif ; for ( int v = 0 ; v < diff . dimension ; ++ v ) { if ( ! diff . lines [ j ] . in_file ( v ) ) continue ; if ( ! state_machines [ v ] . in_something ( ) ) { if ( is_any_pp && ( diff . lines [ j ] . mask != desired_mask ) ) { if ( nest [ v ] . size ( ) == ( is_if ? 0 : 1 ) ) need_to_split = true ; } if ( is_if ) { nest [ v ] . push ( ' ' ) ; } else if ( is_else ) { assert ( nest [ v ] . top ( ) == ' ' ) ; nest [ v ] . top ( ) = ' ' ; } else if ( is_endif ) { assert ( ! nest [ v ] . empty ( ) ) ; nest [ v ] . pop ( ) ; } } state_machines [ v ] . update ( text ) ; } bool someone_is_in_pp_nest = false ; bool someone_is_in_multiline_construct = false ; for ( int v = 0 ; v < diff . dimension ; ++ v ) { if ( state_machines [ v ] . in_something ( ) ) someone_is_in_multiline_construct = true ; if ( ! nest [ v ] . empty ( ) ) someone_is_in_pp_nest = true ; } if ( someone_is_in_multiline_construct ) { if ( j < diff . lines . size ( ) && diff . lines [ j ] . mask != diff . lines [ j + 1 ] . mask ) { need_to_split = true ; } } else { end_of_initial_multiline_construct = std :: min ( end_of_initial_multiline_construct , j ) ; if ( ! someone_is_in_pp_nest ) { end_of_range = j + 1 ; break ; } } } assert ( i + 1 < end_of_range && end_of_range <= diff . lines . size ( ) ) ; if ( need_to_split ) { std :: vector < std :: vector < const std :: string * > > split_versions ( diff . dimension ) ; for ( size_t j = i ; j < end_of_range ; ++ j ) { for ( int v = 0 ; v < diff . dimension ; ++ v ) { if ( ! diff . lines [ j ] . in_file ( v ) ) continue ; split_versions [ v ] . push_back ( diff . lines [ j ] . text ) ; } } Difdef :: Diff split_merge = Difdef :: simply_concatenate ( split_versions ) ; diff . lines . erase ( diff . lines . begin ( ) + i , diff . lines . begin ( ) + end_of_range ) ; diff . lines . insert ( diff . lines . begin ( ) + i , split_merge . lines . begin ( ) , split_merge . lines . end ( ) ) ; i += split_merge . lines . size ( ) - 1 ; } else { i = end_of_initial_multiline_construct ; } } }
For each #if in the file, look up its associated #elif/#else/#endif chain.
For each #if in the file look up its associated #elif / #else / #endif chain .
/* We have an #if, or a comment. See if its range is all under
         * the same mask. */ /* All top-level pp-directives in the range must have the same mask. */ /* The range must contain at least two lines. */