*&---------------------------------------------------------------------*
*&  Include           ZUTIL_SRC_WITHOUT_INCLUDES                       *
*&                                                                     *
*&---------------------------------------------------------------------*
*&                                                                     *
*& This file is part of ZUTIL.                                         *
*&                                                                     *
*& ZUTIL is free software: you can redistribute it and/or modify       *
*& it under the terms of the GNU General Public License as published   *
*& by the Free Software Foundation, either version 3 of the License,   *
*& or any later version.                                               *
*&                                                                     *
*& ZUTIL is distributed in the hope that it will be useful,            *
*& but WITHOUT ANY WARRANTY; without even the implied warranty of      *
*& MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       *
*& GNU General Public License for more details.                        *
*&                                                                     *
*& You should have received a copy of the GNU General Public License   *
*& along with ZUTIL. If not, see <http://www.gnu.org/licenses/>.       *
*&                                                                     *
*&---------------------------------------------------------------------*
*&                                                                     *
*&  Author:     Ruediger von Creytz     ruediger.creytz@globalbit.net  *
*&  Copyright:  globalBIT, LLC          http://www.globalbit.net       *
*&                                                                     *
*&---------------------------------------------------------------------*


TYPES:
  BEGIN OF st_level,
    level TYPE syindex,
  END OF st_level,
  it_level TYPE STANDARD TABLE OF st_level,
  BEGIN OF st_offset,
    index  typE syindex,
    length typE syindex,
  END OF st_offset,
  it_offset type standard table of st_offset,
  BEGIN OF st_src_include_index,
    include   TYPE progname,
    line_from TYPE syindex,
    line_to   TYPE syindex,
    level     TYPE syindex,
  END OF st_src_include_index,
  it_src_include_index TYPE STANDARD TABLE OF st_src_include_index.


*-----------------------------------------------------------------------
* get_src_without_includes
*-----------------------------------------------------------------------
FORM get_src_without_includes
  USING
    it_src TYPE rswsourcet
    value(i_src_name) TYPE progname
    value(i_check) TYPE flag
    value(i_progname) TYPE progname
    value(i_replace) TYPE progname
  CHANGING
    ct_src_no_includes TYPE rswsourcet
    ct_index TYPE it_src_include_index.

  DATA BEGIN OF lh_tk OCCURS 5000.
         INCLUDE STRUCTURE stokex.
  DATA END OF lh_tk.
  DATA BEGIN OF stm OCCURS 1000.
         INCLUDE STRUCTURE sstmnt.
  DATA END OF stm.
  DATA BEGIN OF lv OCCURS 100.
         INCLUDE STRUCTURE slevel.
  DATA END OF lv.

  DATA:
    ls_index TYPE st_src_include_index,
    ls_index_t TYPE st_src_include_index,
    ls_offset type st_offset,
    ls_old_level TYPE st_level,
    ls_source TYPE abapsource,
    lt_include TYPE rswsourcet,
    lt_offset type it_offset,
    lt_old_level TYPE it_level,
    lt_source TYPE STANDARD TABLE OF abapsource,
    l_diff_end TYPE syindex,
    l_diff_new TYPE syindex,
    l_dollar_include TYPE progname,
    l_function TYPE flag,
    l_function_include TYPE progname,
    l_i TYPE syindex,
    l_include_count TYPE syindex,
    l_include_index TYPE sytabix,
    l_include_lines TYPE syindex,
    l_index_lines TYPE syindex,
    l_index_old_line_to TYPE syindex,
    l_level_dif TYPE syindex,
    l_level_t TYPE sytabix,
    l_lv_level_new TYPE level_levl,
    l_lv_level_old TYPE level_levl,
    l_msg(256),
    l_next TYPE syindex,
    l_next_level TYPE syindex,
    l_offset_lines TYPE syindex,
    l_offset_old_incl_anw TYPE syindex,
    l_old_level_lines TYPE sytabix,
    l_old_next_level TYPE sytabix,
    l_overflow_area(65535),
    l_source_lines TYPE syindex,
    l_stm_from TYPE stmnt_from,
    l_stm_index TYPE sytabix,
    l_stm_level TYPE stmnt_levl,
    l_str(255),
    l_tabix TYPE sytabix.

  FIELD-SYMBOLS:
    <l_fs>,
    <ls_offset> type st_offset.


  CALL FUNCTION 'RS_WORKING_AREA_INIT'.
  IF i_src_name NE space AND i_progname NE space.
    READ REPORT i_progname INTO lt_source.
    SCAN ABAP-SOURCE lt_source
      TOKENS INTO lh_tk
      STATEMENTS INTO stm
      LEVELS INTO lv
      OVERFLOW INTO l_overflow_area
      PROGRAM FROM i_progname
      MESSAGE INTO l_msg
      WITH INCLUDES
      WITHOUT TRMAC
      WITH ANALYSIS.
  ELSE.
    lt_source[] = it_src[].
    SCAN ABAP-SOURCE lt_source
      TOKENS INTO lh_tk
      STATEMENTS INTO stm
      LEVELS INTO lv
      OVERFLOW INTO l_overflow_area
      PROGRAM FROM i_src_name
      MESSAGE INTO l_msg
      WITH INCLUDES
      WITHOUT TRMAC
      WITH ANALYSIS.
  ENDIF.
  CLEAR:
    l_lv_level_new,
    l_lv_level_old.
  DESCRIBE TABLE lt_source LINES l_source_lines.
  l_tabix = 1.
  DO.     "LOOP AT stm.
    READ TABLE stm INDEX l_tabix.
    IF sy-subrc NE 0.
      EXIT.
    ENDIF.
    l_stm_index = l_tabix.
    l_tabix = l_tabix + 1.
    l_stm_from = stm-from.
    l_stm_level = stm-level.
    CLEAR:
      l_diff_new,
      l_diff_end.
    READ TABLE lh_tk INDEX l_stm_from.
    IF  sy-subrc = 0
    AND ( lh_tk-str = 'INCLUDE' OR lh_tk-str = 'FUNCTION' ).
      IF lh_tk-str = 'FUNCTION'.
        l_function = abap_true.
        l_function_include = ls_index-include.
        l_dollar_include = ls_index-include.
        l_i = strlen( l_dollar_include ) - 3.
        ASSIGN l_dollar_include+l_i(1) TO <l_fs>.
        IF <l_fs> = 'U'.
          <l_fs> = '$'.
        ELSE.
          l_function = abap_false.
          CLEAR l_dollar_include.
        ENDIF.
      ELSE.
        l_function = abap_false.
      ENDIF.
      l_next = l_stm_from + 1.
      READ TABLE lh_tk INDEX l_next.
      IF  sy-subrc = 0
      AND lh_tk-str NE 'STRUCTURE'
      AND lh_tk-str NE 'TYPE'
      AND lh_tk-str NE '='
      AND lh_tk-str NE '$$UNIT$$'.
        IF l_function = abap_true.
          ls_index-include = l_dollar_include.
        ELSE.
          CASE lh_tk-ovfl.
            WHEN space.
              ASSIGN lh_tk-str TO <l_fs>.
            WHEN 'X'.
              ASSIGN l_overflow_area TO <l_fs>.
            WHEN 'O'.
*            MESSAGE S116.
              EXIT.
          ENDCASE.
          IF lh_tk-len1 > 0.
            ASSIGN <l_fs>+lh_tk-off1(lh_tk-len1) TO <l_fs>.
          ENDIF.
          l_str = <l_fs>.
          IF l_str(1) = ''''.
            SHIFT l_str BY 1 PLACES.
          ENDIF.
          ls_index-include = l_str.
        ENDIF.
        IF  i_src_name NE space
        AND i_src_name =  l_function_include
        AND l_function =  abap_true.
          CONTINUE.
        ENDIF.
        IF ls_index-include = i_replace.
          CONTINUE.
        ENDIF.
        IF l_stm_level NE 0.
          READ TABLE lv INDEX l_stm_level.
          l_lv_level_new = lv-level + 1.
          DESCRIBE TABLE ct_index LINES l_index_lines.
          IF lv-level = 0 AND l_index_lines = 0.
            IF lv-stmnt = 0.
            ELSE.
              READ TABLE stm INDEX lv-stmnt.
            ENDIF.
            READ TABLE lh_tk INDEX stm-from.
            DESCRIBE TABLE ct_index LINES l_index_lines.
            IF i_src_name NE space AND
               i_src_name = ls_index-include AND
               i_progname NE i_src_name.
              lt_include[] = it_src[].
            ELSE.
              READ REPORT ls_index-include INTO lt_include.
            ENDIF.
            DESCRIBE TABLE lt_include LINES l_include_lines.
            DESCRIBE TABLE lt_source LINES l_source_lines.
            IF stm-level = 1 AND l_index_lines = 0..
              IF i_src_name NE space.
                ls_index_t-include = i_progname.
              ELSE.
                ls_index_t-include = i_src_name.
              ENDIF.
              ls_index_t-line_to = l_include_lines
                                   + l_source_lines - 1.
              ls_index_t-line_from = 1.
              ls_index_t-level = 0.
              APPEND ls_index_t TO ct_index.
              ls_index-level = lv-level + 1.
              ls_index-line_to = l_include_lines + lh_tk-row - 1.
              ls_index-line_from = lh_tk-row.
              ls_offset-index = lh_tk-row.
              ls_offset-length = l_source_lines.
              APPEND ls_offset to lt_offset.
              l_offset_old_incl_anw = lh_tk-row.
            ELSEIF stm-level > 1 AND l_index_lines = 0.
              IF i_src_name NE space.
                ls_index_t-include = i_progname.
              ELSE.
                ls_index_t-include = i_src_name.
              ENDIF.
              ls_index_t-line_to = ls_index-line_to + lh_tk-row..
              ls_index_t-line_from = 1.
              ls_index_t-level = 0.
              APPEND ls_index_t TO ct_index.
              ls_index-level = lv-level + 1.
              ls_index-line_to = ls_index-line_to + lh_tk-row.
              ls_index-line_from = ls_index-line_from + lh_tk-row.
              l_offset_old_incl_anw = lh_tk-row.
            ELSE.
              ls_index-level = lv-level + 1.
              IF l_lv_level_new < l_lv_level_old.
                READ TABLE lt_offset into ls_offset
                  INDEX l_lv_level_new.
                l_next_level = l_lv_level_new - 1.
                l_diff_end = ls_offset-length
                           - ls_offset-index - 1.
                READ TABLE lt_offset into ls_offset
                  INDEX l_next_level.
                l_offset_old_incl_anw = ls_offset-index.
                l_diff_new = lh_tk-row - l_offset_old_incl_anw.

                l_index_old_line_to = ls_index-line_to.
                ls_index-line_to = ls_index-line_to
                                 + l_include_lines + l_diff_new
                                 + l_diff_end - 1 .
                LOOP AT ct_index INTO ls_index_t.
                  IF ls_index_t-level < l_lv_level_new.
                    ls_index_t-line_to = ls_index_t-line_to
                             + l_include_lines
                             + l_diff_new
                             + l_diff_end.
                    MODIFY ct_index FROM ls_index_t .
                  ENDIF.
                ENDLOOP.
              ELSE.
                l_next_level = l_lv_level_new.
                READ TABLE lt_offset assigning <ls_offset>
                  INDEX l_next_level.
                IF sy-subrc = 0.
                  <ls_offset>-index = lh_tk-row.
                ENDIF.
                l_index_old_line_to = ls_index-line_to.
                ls_index-line_to = ls_index-line_to
                                 + lh_tk-row
                                 + l_include_lines.
                ls_index-line_from = ls_index-line_from + lh_tk-row.
                LOOP AT ct_index INTO ls_index_t.
                  IF ls_index_t-level < l_lv_level_new.
                    ls_index_t-line_to = ls_index_t-line_to
                                       + l_include_lines
                                       + lh_tk-row.
                    MODIFY ct_index FROM ls_index_t .
                  ENDIF.
                ENDLOOP.
              ENDIF.
              IF l_lv_level_new > l_lv_level_old.
                ls_index-line_from = ls_index-line_from
                                   + lh_tk-row.
              ELSEIF l_lv_level_new < l_lv_level_old.
                ls_index-line_from = l_index_old_line_to
                                   + l_diff_new
                                   + l_diff_end.
              ELSE.
                l_diff_new = lh_tk-row - l_offset_old_incl_anw.
                l_offset_old_incl_anw = lh_tk-row.
                ls_index-line_from = l_index_old_line_to
                                   + l_diff_new.
              ENDIF.
            ENDIF.
            IF lv-stmnt = 0.
              READ TABLE stm INDEX l_stm_index.
            ELSE.
              READ TABLE stm INDEX lv-stmnt.
            ENDIF.
            READ TABLE lh_tk INDEX stm-from.
            IF lh_tk-str = 'INCLUDE'.
              IF lv-stmnt = 0.
                l_include_index = lh_tk-row.
              ELSE.
                l_include_index = ls_index-line_from
                                + lh_tk-row - 1.
              ENDIF.
              DELETE lt_source INDEX l_include_index.
              INSERT LINES OF lt_include INTO lt_source
                     INDEX l_include_index.
            ENDIF.
            l_lv_level_old = l_lv_level_new.
          ELSE.

            ls_index-level = lv-level + 1.
            IF l_lv_level_new > l_lv_level_old.
              l_source_lines = l_include_lines.
            ENDIF.
            IF i_src_name NE space AND
               i_src_name = ls_index-include AND
               i_progname NE i_src_name.
              lt_include[] = it_src[].
            ELSE.
              READ REPORT ls_index-include INTO lt_include.
            ENDIF.
            DESCRIBE TABLE lt_include LINES l_include_lines.
            READ TABLE lh_tk INDEX l_stm_from.

            IF l_lv_level_new > l_lv_level_old.
              l_next_level = l_lv_level_new.
              READ TABLE lt_offset assigning <ls_offset>
                INDEX l_next_level.
              IF sy-subrc = 0.
                l_offset_old_incl_anw = lh_tk-row.
                <ls_offset>-index = l_offset_old_incl_anw.
                <ls_offset>-length = l_source_lines.
              ELSE.
                DESCRIBE TABLE lt_offset LINES l_offset_lines.
                l_level_dif = l_next_level - l_offset_lines - 1.
                IF l_level_dif > 0.
                  CLEAR ls_offset.  "and/or lt_offset ???
                  WHILE l_level_dif > 0.
                    APPEND ls_offset to lt_offset.
                    SUBTRACT 1 FROM l_level_dif.
                  ENDWHILE.
                ENDIF.
                l_offset_old_incl_anw = lh_tk-row.
                ls_offset-index = l_offset_old_incl_anw.
                ls_offset-length = l_source_lines.
                APPEND ls_offset to lt_offset.
              ENDIF.
              ls_index-line_to = ls_index-line_from
                               + l_include_lines
                               + lh_tk-row - 2.
              SORT ct_index BY line_from DESCENDING line_to ASCENDING.
              REFRESH lt_old_level.
              CLEAR l_old_level_lines.
              LOOP AT ct_index INTO ls_index_t.
                CLEAR ls_old_level.
                IF ls_index_t-level < l_lv_level_new.
                  IF l_old_level_lines > 0.
                    READ TABLE lt_old_level INTO ls_old_level
                      WITH KEY level = ls_index_t-level.
                    IF sy-subrc NE 0.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      l_old_level_lines = l_old_level_lines + 1.
                      ls_index_t-line_to = ls_index_t-line_to
                           + l_include_lines - 1.     " + tk-row.
                      MODIFY ct_index FROM ls_index_t.
                    ENDIF.
                  ELSE.
                    ls_old_level-level = ls_index_t-level.
                    APPEND ls_old_level TO lt_old_level.
                    l_old_level_lines = l_old_level_lines + 1.
                    ls_index_t-line_to = ls_index_t-line_to
                                       + l_include_lines - 1.
                    MODIFY ct_index FROM ls_index_t.
                  ENDIF.
                ENDIF.
              ENDLOOP.
              SORT ct_index BY line_from ASCENDING line_to DESCENDING.
            ELSEIF l_lv_level_new < l_lv_level_old.
              READ TABLE lh_tk INDEX l_stm_from.
              CLEAR ls_offset.
              READ TABLE lt_offset into ls_offset
                INDEX l_lv_level_old.

              CLEAR:
                l_diff_end,
                l_diff_new.
              l_next_level = l_lv_level_old.
              WHILE l_next_level > l_lv_level_new.
                l_old_next_level = l_next_level.
                l_next_level = l_next_level - 1.
                l_diff_end = l_diff_end
                           + ls_offset-length
                           - ls_offset-index.
                CLEAR ls_offset.
                MODIFY lt_offset from ls_offset
                  INDEX l_old_next_level.
                READ TABLE lt_offset into ls_offset
                  INDEX l_next_level.
                IF sy-subrc = 0.
                  l_offset_old_incl_anw = ls_offset-index.
                ELSE.
                  CLEAR ls_offset.
                ENDIF.
              ENDWHILE.
              READ TABLE lt_offset assigning <ls_offset>
                INDEX l_next_level.
              IF sy-subrc = 0.
                <ls_offset>-index = lh_tk-row.
              ENDIF.
              l_diff_new = l_diff_new + lh_tk-row
                         - l_offset_old_incl_anw.
              l_offset_old_incl_anw = lh_tk-row.
              l_index_old_line_to = ls_index-line_to.
              ls_index-line_to = ls_index-line_to
                               + l_include_lines
                               + l_diff_new
                               + l_diff_end - 1.
              SORT ct_index BY line_from DESCENDING.
              REFRESH lt_old_level.
              CLEAR l_old_level_lines.
              READ TABLE stm INDEX lv-stmnt.
              LOOP AT ct_index INTO ls_index_t.
                IF ls_index_t-level < l_lv_level_new.
                  IF l_old_level_lines > 0.
                    READ TABLE lt_old_level INTO ls_old_level
                      WITH KEY level = ls_index_t-level.
                    IF sy-subrc NE 0.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      ADD 1 TO l_old_level_lines.
                      ls_index_t-line_to = ls_index_t-line_to
                                         + l_include_lines  - 1.
                      MODIFY ct_index FROM ls_index_t .
                    ENDIF.
                  ELSE.
                    IF ls_index_t-level < l_lv_level_new.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      l_old_level_lines = l_old_level_lines + 1.
                      ls_index_t-line_to = ls_index_t-line_to
                                         + l_include_lines  - 1.
                    ELSE.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      l_old_level_lines = l_old_level_lines + 1.
                      ls_index_t-line_to = ls_index_t-line_to.
                    ENDIF.
                    MODIFY ct_index FROM ls_index_t .
                  ENDIF.
                ENDIF.
              ENDLOOP.
              SORT ct_index BY line_from ASCENDING.
            ELSE.
              READ TABLE lh_tk INDEX l_stm_from.
              l_diff_new = lh_tk-row - l_offset_old_incl_anw.
              l_offset_old_incl_anw = lh_tk-row.
              l_next_level = l_lv_level_new.
              READ TABLE lt_offset assigning <ls_offset>
                INDEX l_next_level.
              IF sy-subrc = 0.
                <ls_offset>-index = lh_tk-row.
              ENDIF.
              l_index_old_line_to = ls_index-line_to.
              ls_index-line_to = ls_index-line_to
                               + l_include_lines
                               + l_diff_new - 1.
              SORT ct_index BY line_from DESCENDING.
              REFRESH lt_old_level.
              CLEAR l_old_level_lines.
              LOOP AT ct_index INTO ls_index_t.
                l_level_t = l_lv_level_new - 1.
                IF ls_index_t-level = l_level_t.
                  IF ls_index_t-level < l_lv_level_new.
                    IF l_old_level_lines > 0.
                      READ TABLE lt_old_level INTO ls_old_level
                        WITH KEY level = ls_index_t-level.
                      IF sy-subrc NE 0.
                        ls_old_level-level = ls_index_t-level.
                        APPEND ls_old_level TO lt_old_level.
                        ADD 1 TO l_old_level_lines.
                        ls_index_t-line_to = ls_index_t-line_to
                                           + l_include_lines - 1.
                        MODIFY ct_index FROM ls_index_t .
                      ENDIF.
                    ELSE.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      ADD 1 TO l_old_level_lines.
                      ls_index_t-line_to = ls_index_t-line_to
                              + l_include_lines - 1.
                      MODIFY ct_index FROM ls_index_t .
                    ENDIF.
                  ENDIF.
                ELSE.
                  IF ls_index_t-level < l_lv_level_new.
                    IF l_old_level_lines > 0.
                      READ TABLE lt_old_level INTO ls_old_level
                        WITH KEY level = ls_index_t-level.
                      IF sy-subrc NE 0.
                        ls_old_level-level = ls_index_t-level.
                        APPEND ls_old_level TO lt_old_level.
                        ADD 1 TO l_old_level_lines.
                        ls_index_t-line_to = ls_index_t-line_to
                              + l_include_lines - 1.
                        MODIFY ct_index FROM ls_index_t .
                      ENDIF.
                    ELSE.
                      ls_old_level-level = ls_index_t-level.
                      APPEND ls_old_level TO lt_old_level.
                      ADD 1 TO l_old_level_lines.
                      ls_index_t-line_to = ls_index_t-line_to
                                         + l_include_lines - 1.
                      MODIFY ct_index FROM ls_index_t .
                    ENDIF.
                  ENDIF.
                ENDIF.
              ENDLOOP.
              SORT ct_index BY line_from ASCENDING.
            ENDIF.
            IF l_lv_level_new > l_lv_level_old.
              ls_index-line_from = ls_index-line_from
                                 + lh_tk-row - 1.
            ELSEIF l_lv_level_new < l_lv_level_old.
              ls_index-line_from = l_index_old_line_to
                                 + l_diff_new
                                 + l_diff_end.
            ELSE.
              l_offset_old_incl_anw = lh_tk-row.
              ls_index-line_from = l_index_old_line_to
                                 + l_diff_new.
            ENDIF.
            READ TABLE lh_tk INDEX stm-from.
            IF lh_tk-str = 'INCLUDE'
            OR lh_tk-str = 'FUNCTION'.
              l_include_index = ls_index-line_from.
              READ TABLE lt_source INTO ls_source INDEX l_include_index.
              IF sy-subrc = 0.
                IF ( ls_source-line CS 'INCLUDE'
                    AND ls_source-line CS ls_index-include )
                OR ( ls_source-line CS 'FUNCTION'
                    AND ls_source-line NS '$$UNIT$$' ).
                  DELETE lt_source INDEX l_include_index.
                  INSERT LINES OF lt_include INTO lt_source INDEX
                                 l_include_index.
*                ELSE.
*                  WRITE: 'Auflösungsfehler'(011). EXIT.
                ENDIF.
              ENDIF.
            ENDIF.
            l_lv_level_old = l_lv_level_new.
          ENDIF.
        ELSE.
          READ TABLE lh_tk INDEX l_stm_from.
          ls_index-line_from = lh_tk-row.
        ENDIF.
        APPEND ls_index TO ct_index.
      ENDIF.
    ENDIF.
  ENDDO.
  SORT ct_index BY line_from ASCENDING line_to DESCENDING.
  ct_src_no_includes[] = lt_source[].


ENDFORM.                    "get_src_without_includes
