Affiliation Platform: start earning Money with your Blog today!
 
 
 
0

How Many Lines of ABAP Code In Your System?

I ran into a curious post by Sergio Ferrari which allows us to calculate how many lines of ABAP code we have in our systems. More than a curiosity, this simple tool can help us determine if our system is too overloaded with custom code or not.

The author excluded ABAP generated by special frameworks, like Report writer, SAP Query, Web Dynpro, LSMW,  and so on. He opted to do the filtering by Source System, Owner and Package. The release covered by this tool is ECC 6.0 an the following are also out of scope of this tool:

  • BSP’s
  • Adobe Forms, Smartforms and SAPScript
  • XSLT/Web Services

This utility was named ZSDN_simple_ABAP_SLOC_COUNT, and aims to be an an indicator. The author didn’t want to give it too much relevance, the idea is solely to be an useful tool and help us estimate the upgrade effort or to evaluate the amount of work allocated for each of our packages.

As a curiosity, the post also includes the following information, related to lines of code in known software systems:

  • Windows XP:      45 million lines of code
  • Windows Vista:  50 million lines of code
  • Mac OS:              86 million lines of code
  • SAP (ABAP):      238 million lines of ABAP

Copy the code from the textearea below and paste it in a new report in transaction code SE38.

*&---------------------------------------------------------------------*
*& Report  ZSDN_SIMPLE_ABAP_SLOC_COUNT
*& Author: Andrea Olivieri, Sergio Ferrari
*&         Techedge SpA
*& Version: 1.0  - 2009/01/20
*& Title   How many lines of custom ABAP code are inside your system?
*&---------------------------------------------------------------------*
REPORT  zsdn_simple_abap_sloc_count_n LINE-SIZE 255.

* Global Data Type [ GDT ;-)  ]
TYPES: BEGIN OF ty_repository,
         devclass  TYPE tadir-devclass,
         name      TYPE trdir-name,
         object    TYPE tadir-object,
         srcsystem TYPE tadir-srcsystem,
         author    TYPE tadir-author,
         subc      TYPE trdir-subc,
         sloc      TYPE i,
       END OF ty_repository.
DATA: l_repository TYPE ty_repository.
DATA: t_repository TYPE STANDARD TABLE OF ty_repository.

* defining the selection-screen
TABLES: tadir.
SELECT-OPTIONS: xpack   FOR tadir-devclass,
                xobject FOR tadir-object,
                xauthor FOR tadir-obj_name.

INITIALIZATION.
  PERFORM init_select_options.

START-OF-SELECTION.
  PERFORM get_obj_set.
  PERFORM upd_obj_set_count_class_sloc.
  PERFORM count_prog_sloc.

END-OF-SELECTION.
  PERFORM alv.

*&---------------------------------------------------------------------*
*&      Form  init_select_options
*&---------------------------------------------------------------------*
*       INCLUDE OBJECTS:  PROG, FUGR and CLAS
*       EXCLUDE PACKAGES: $TMP and from A to W
*       EXCLUDE USERS:    SAP, SAP*, DDIC
*----------------------------------------------------------------------*
FORM init_select_options.

* Include objects: PROG, FUGR and CLAS
  IF xobject[] IS INITIAL.
    xobject-sign   = 'I'. xobject-option = 'EQ'. xobject-low = 'PROG'.
APPEND xobject.
    xobject-sign   = 'I'. xobject-option = 'EQ'. xobject-low = 'FUGR'.
APPEND xobject.
    xobject-sign   = 'I'. xobject-option = 'EQ'. xobject-low = 'CLAS'.
APPEND xobject.
  ENDIF.

* Exclude packages: $TMP and from A to W
  IF xpack[] IS INITIAL.
    xpack-sign   = 'E'. xpack-option = 'BT'. xpack-low = 'A'. xpack-high
= 'WZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'. APPEND xpack.
    xpack-sign   = 'E'. xpack-option = 'EQ'. xpack-low = '$TMP'. APPEND
xpack.
  ENDIF.

* Exclude objects belonging to users: SAP* and DDIC
  IF xauthor[] IS INITIAL.
    xauthor-sign   = 'E'. xauthor-option = 'EQ'.     xauthor-low =
'SAP'.  APPEND xauthor.
    xauthor-sign   = 'E'. xauthor-option = 'EQ'.     xauthor-low =
'SAP*'. APPEND xauthor.
    xauthor-sign   = 'E'. xauthor-option = 'EQ'.     xauthor-low =
'DDIC'. APPEND xauthor.
  ENDIF.
ENDFORM.                    "init_select_options

*&---------------------------------------------------------------------*
*&      Form  get_obj_set
*&---------------------------------------------------------------------*
*       Get from TADIR
*----------------------------------------------------------------------*
FORM get_obj_set.
  DATA: l_tadir TYPE tadir.

  SELECT * FROM tadir INTO l_tadir
           WHERE pgmid      EQ 'R3TR'
           AND   obj_name   IN xauthor
           AND   object     IN xobject
           AND   devclass   IN xpack
            AND srcsystem   NE 'SAP'
           AND   author     IN xauthor.               "#EC CI_SGLSELECT
    IF NOT l_tadir-obj_name CP '_______________________________*'.
      MOVE-CORRESPONDING l_tadir TO l_repository.
      l_repository-name     = l_tadir-obj_name.
      l_repository-devclass = l_tadir-devclass.
      APPEND l_repository TO t_repository.
    ENDIF.
  ENDSELECT.
*
  SORT t_repository BY devclass name.

ENDFORM.                    "get_obj_set

*&---------------------------------------------------------------------*
*&      Form  upd_obj_set_count_class_sloc
*&---------------------------------------------------------------------*
*       ...and Compute SLOC for CLAS
*----------------------------------------------------------------------*
FORM upd_obj_set_count_class_sloc.
  TYPE-POOLS: sedi.
  TYPES: BEGIN OF ty_irdir,
          name LIKE trdir-name,
          devc    LIKE tadir-devclass,
        END OF ty_irdir,
        BEGIN OF ty_itab,
          repname LIKE sy-repid,
          devc    LIKE tadir-devclass,
        END OF ty_itab,
        BEGIN OF ty_crdir,
          name LIKE trdir-name,
          subc LIKE trdir-subc,
          devc    LIKE tadir-devclass,
        END OF ty_crdir.

  DATA: save_tabix      TYPE sy-tabix,
        l_class         TYPE sobj_name,
        l_pgmid         TYPE pgmid,
        l_object        TYPE trobjtype,
        class_name      TYPE programm,
        class_pool_name TYPE programm,
        lclskey         TYPE seoclskey.
  DATA: sourceline      TYPE string.
  DATA: l_1st_char      TYPE c.

  DATA: l_irdir         TYPE ty_irdir,
        l_itab          TYPE ty_itab,
        l_itab1         TYPE ty_itab,
        l_crdir         TYPE ty_crdir.
  DATA: t_irdir TYPE STANDARD TABLE OF ty_irdir,
        t_itab  TYPE STANDARD TABLE OF ty_itab,
        t_itab1 TYPE STANDARD TABLE OF ty_itab,
        t_crdir TYPE STANDARD TABLE OF ty_crdir.

  DATA: l_sloc          TYPE i.

  LOOP AT t_repository INTO l_repository.
    save_tabix = sy-tabix.
    CASE l_repository-object.
      WHEN 'PROG'.
        SELECT SINGLE subc FROM trdir INTO l_repository-subc WHERE  name
= l_repository-name.
        IF sy-subrc = 0.
          MODIFY t_repository FROM l_repository INDEX save_tabix
TRANSPORTING subc .
        ENDIF.
      WHEN 'FUGR'.
        CONCATENATE 'SAPL' l_repository-name INTO l_irdir-name.
        l_irdir-devc = l_repository-devclass.
        APPEND l_irdir TO t_irdir.
        l_repository-name   = l_irdir-name.
        l_repository-object = 'PROG'.
        SELECT SINGLE subc FROM trdir INTO l_repository-subc WHERE  name
= l_repository-name.
        IF sy-subrc = 0.
          MODIFY t_repository FROM l_repository INDEX save_tabix
TRANSPORTING name object subc.
        ENDIF.
        CLEAR l_irdir.
      WHEN 'CLAS'.
        DATA source_new TYPE sedi_source.
        DATA l_inctype(5).

        class_name = l_repository-name.
        l_pgmid = 'R3TR'.
        l_object = l_repository-object.
        l_class = class_name.
        CALL FUNCTION 'SEO_CLASS_GET_CP_NAME'
          EXPORTING
            pgmid                 = l_pgmid
            object                = l_object
            obj_name              = l_class
          IMPORTING
            progname              = class_pool_name
          EXCEPTIONS
            no_class_or_interface = 1.

        IF sy-subrc = 0.
          SELECT SINGLE subc FROM trdir INTO l_repository-subc WHERE name
= class_pool_name.
        ENDIF.

        lclskey-clsname = cl_oo_classname_service=>get_clsname_by_include(
class_name ).

        CLEAR l_class.
        CONCATENATE l_repository-name '%' INTO l_class.

        SELECT name FROM  trdir INTO TABLE t_crdir WHERE  name  LIKE
l_class.
        IF NOT t_crdir[] IS INITIAL.
          LOOP AT t_crdir INTO l_crdir.
            l_inctype = l_crdir-name+30(5) .
            REFRESH source_new.
            CALL FUNCTION 'SEO_CLASS_GET_INCLUDE_SOURCE'
              EXPORTING
                clskey                       = lclskey
                inctype                      = l_inctype
              IMPORTING
                source_expanded              = source_new
              EXCEPTIONS
                _internal_class_not_existing = 1
                not_existing                 = 2
                OTHERS                       = 3.
            CHECK sy-subrc = 0.

*           Compute SLOC !
            LOOP AT source_new INTO sourceline.
              l_1st_char = sourceline.
              IF    sourceline IS INITIAL
                 OR l_1st_char = '*'.
                DELETE source_new INDEX sy-tabix.
              ENDIF.
            ENDLOOP.
            l_sloc = LINES( source_new ).
            ADD l_sloc TO l_repository-sloc.
          ENDLOOP.
          MODIFY t_repository FROM l_repository INDEX save_tabix
TRANSPORTING sloc subc.
        ENDIF.
      WHEN OTHERS. CONTINUE.
    ENDCASE.

  ENDLOOP.

  IF t_irdir[] IS NOT INITIAL.
    LOOP AT t_irdir INTO l_irdir.
      REFRESH t_itab1.
      CALL FUNCTION 'GET_INCLUDES'
        EXPORTING
          progname = l_irdir-name
        TABLES
          incltab  = t_itab1.

*     append lines of t_itab1 to itab.
      LOOP AT t_itab1 INTO l_itab1.
        l_itab-repname = l_itab1-repname.
        l_itab-devc    = l_irdir-devc.    "Sometimes it's false
        APPEND l_itab TO t_itab.
        CLEAR l_itab.
      ENDLOOP.
    ENDLOOP.
  ENDIF.

  DATA: l_trdir TYPE trdir.

  LOOP AT t_itab INTO l_itab.
    SELECT SINGLE * FROM  trdir INTO l_trdir
           WHERE  name  = l_itab-repname
            AND    cnam  NOT LIKE 'SAP%'
            AND    cnam  <> 'DDIC'.
    CHECK sy-subrc = 0.

    MOVE-CORRESPONDING l_trdir TO l_repository.
    l_repository-devclass = l_itab-devc.
    l_repository-object   = 'PROG'.
    APPEND l_repository TO t_repository.

  ENDLOOP.

  SORT t_repository BY name object devclass.
  DELETE ADJACENT DUPLICATES FROM t_repository COMPARING name object
devclass.

ENDFORM.                    "upd_obj_set_count_class_sloc
*&---------------------------------------------------------------------*
*&      Form  count_prog_sloc
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM count_prog_sloc.
  DATA: l_prog     TYPE c LENGTH 30.
  DATA: isource    TYPE TABLE OF string.
  DATA: l_1st_char TYPE c.

  LOOP AT t_repository INTO l_repository WHERE object = 'PROG'.
*   Compute SLOC !
    l_prog = l_repository-name.
    READ REPORT l_prog INTO isource.
    DATA: l_source_line TYPE string.
    LOOP AT isource INTO l_source_line.
      l_1st_char = l_source_line.
      IF    l_source_line IS INITIAL     "Empty
         OR l_1st_char = '*'.            "Comment
        DELETE isource INDEX sy-tabix.
      ENDIF.
    ENDLOOP.
    l_repository-sloc = LINES( isource ).

*   Update SLOC into t_repository
    READ TABLE t_repository WITH TABLE KEY name     = l_repository-name
                                       devclass = l_repository-devclass
                                       object   = l_repository-object
                                       srcsystem = l_repository-srcsystem
                                       author    = l_repository-author
                                       subc      = l_repository-subc
                        TRANSPORTING NO FIELDS.
    IF sy-subrc = 0.
      MODIFY t_repository FROM l_repository INDEX sy-tabix TRANSPORTING
sloc.
    ENDIF.
  ENDLOOP.
ENDFORM.                    "count_prog_sloc

*&---------------------------------------------------------------------*
*&      Form  alv
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM alv.
  DATA: gr_table     TYPE REF TO cl_salv_table,
        gr_display   TYPE REF TO cl_salv_display_settings,
        gr_functions TYPE REF TO cl_salv_functions,
        gr_sorts     TYPE REF TO cl_salv_sorts,
        gr_agg       TYPE REF TO cl_salv_aggregations.
  TRY.
*     Create ALV table
      cl_salv_table=>factory( IMPORTING r_salv_table = gr_table CHANGING
t_table = t_repository ).
*     Set zebra layout
      gr_display = gr_table->get_display_settings( ).
      gr_display->set_striped_pattern( cl_salv_display_settings=>true ).
*     Display all standard function
      gr_functions = gr_table->get_functions( ).
      gr_functions->set_all( abap_true ).
*     Sort
      gr_sorts = gr_table->get_sorts( ).
      gr_sorts->add_sort( columnname = 'DEVCLASS' subtotal = abap_true ).
      gr_sorts->add_sort( columnname = 'NAME'     subtotal = abap_false ).
*     Totals
      gr_agg = gr_table->get_aggregations( ).
      gr_agg->add_aggregation( 'SLOC' ).
*     Display table
      gr_table->display( ).
    CATCH cx_salv_msg.
      WRITE: / 'Exception CX_SALV_MSG'.
    CATCH cx_salv_not_found.
      WRITE: / 'Exception CX_SALV_NOT_FOUND'.
    CATCH cx_salv_data_error.
      WRITE: / 'Exception CX_SALV_DATA_ERROR'.
    CATCH cx_salv_existing.
      WRITE: / 'Exception CX_SALV_EXISTING'.
  ENDTRY.
ENDFORM.                    "alv

Additional links and resources:

Author : webmaster

Author's Website | Articles from webmaster

Working as an Information Systems Consultant for over 10 years now, I've found that working with SAP brought me added value on how to deal and manage IT and Information Systems Projects. More than a hobby, this blog is aimed to propagate SAP knowledge exchange and help other SAP technology or functional Consultants finding any piece of useful information. Please participate with your comments and opinions, it will help enrich the SAP community. Thanks!

Like this post? Share it!

  • Tweet
  • Facebook
  • Diggit
  • Delicious
  • Diggit
  • Diggit
  • Diggit
  • Diggit
  • Diggit

Related Posts





Community Feeds

Submit More
;;