Wednesday, January 7, 2015

Which Control options/H-specs do you use?

rpg control specification

In my many years of experience working for various companies I have found that just a few programmers define Control specifications in their RPG programs. The Control specification is commonly known as the Header specification, or H-spec, as in fixed format RPG the specification character, in the sixth position of the line, is 'H'. In all free RPG the Control specification was replaced by the Control options, 'CTL-OPT'.

In my opinion this was the most cryptic of the specifications in RPG III as you had to know what each column stood for, as it would only reveal its meaning when F4 was pressed to prompt the line.

 H........1..CDYI....S..............1.F...............................Pgm-id
 H        1   Y-                                                      ERPA01
     Prompt type . . .    H      Sequence number . . .  0000.01

                              Date      Date       Invert      Alternate
     Debug     Currency      Format     Edit       Print       Sequence
       1          _            Y         -            _           _
     1P Forms        File         Program
     Position     Translation       Name
        _             _            ERPA01

It became easier when RPGLE was introduced as the Control specifications became free format. The equivalent of the above example would be:

 HKeywords++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 H DEBUG DFTNAME(ERPA01) DATEDIT(*YMD-)

I do use Control specifications in all my RPG programs. So which ones do I use?

I put the following into all of my programs:

  H OPTION(*NODEBUGIO:*SRCSTMT:*NOUNREF)

    ctl-opt option(*nodebugio:*srcstmt:*nounref) ;

*NODEBUGIO: If this is not given when I start debug (STRDBG) break points are generated for each field in the file. This means if I am stepping through the program I have to press F10 for each field in the file before I proceed to the next statement. By using *NODEBUGIO no break points are generated for the fields, so with one press of the F10 key I advance to the next statement.

*SRCSTMT: The source statement line numbers are used for the line numbers in the generated program or module. Therefore, when I receive an error message about line 223.00 I can go straight to that line number in the source. Without using this option the line numbers are determined sequentially and will not match the source line numbers.

*NOUNREF: The unreferenced fields and variables are not generated, unless they are used by some other module. On the plus side: this makes your program smaller. On the minus side: the unreferenced fields cannot be used in debug.

These are others I do use on a regular basis, just when circumstances need them:

  H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('*LIBL/BNDDIRNAME')

    ctl-opt dftactgrp(*no) actgrp(*new) bnddir('*LIBL/BNDDIRNAME') ;

DFTACTGRP(*NO): The program will be associated with the activation group given in the ACTGRP.

ACTGRP(*NEW): This is only valid when the program is created using the CRTBNDRPG command. I just use *NEW as I am yet to encounter a reason why I need to name the activation group the program will be running in.

BNDDIR('*LIBL/BNDDIRNAME'): If you are binding modules and service programs to other programs then, in my opinion, you should be using a binding directory. I always name mine the same name of the program that will use it.

  H NOMAIN

    ctl-opt nomain ;

NOMAIN: I use this in all of the source code of my modules. It denotes that the code does not have main procedure, and does not use the RPG cycle.

  H MAIN(MainPrcedure)

    ctl-opt main(MainProcedure) ;

MAIN(MainProcedure): In a "linear" program that does not use the RPG cycle this gives the name of the main line procedure. This is something I will discuss in a future post.

  H ALWNULL(*INPUTONLY)

    ctl-opt alwnull(*inputonly) ;

ALWNULL(*USRCTL): At times I do have to work with a file that comes from a different server or database. These tables/files do contain columns/fields that contain nulls. By specifying ALWNULL(*USRCTL) I can read these files without the program erroring as a field contains null, and handle the nulls using the null indicator.

If I use ALWNULL(*INPUTONLY) if a field containing null is encountered in the input operation, READ, CHAIN, etc., it is transformed into the field's default, blank, zero, etc.

 

I would like to hear from you what Control specifications/options you use? And why? Let me know by either posting a comment, below, or use the Contact form on the right and I will include your feedback in this post.

 

You can learn more about the Control specification on the IBM website here.

 

This article was written for IBM i 7.2, and it should work with other releases too.

26 comments:

  1. Really nice explanation of the used control options. +1

    ReplyDelete
  2. Good what and why article. Some times we need more than how.

    ReplyDelete
  3. Good Article, looking forward to understanding the keyword MAIN :)

    ReplyDelete
  4. I use a standard h-spec in all my mainline programs via /copy:
    h dftactgrp(*no) actgrp('QILE') option(*srcstmt: *nodebugio: *nounref)
    h alwnull(*usrctl)
    h debug
    h bnddir('PROCEDURES')

    More than 90% of my source members are MAIN programs; very few are service programs. All the MAIN programs are compiled with CRTBNDRPG and all of my service programs are in one binding directory.

    ReplyDelete
  5. nice article, anything dealing with coding in "all-free" is greatly appreciated, look forward to future posts

    ReplyDelete
  6. These are the h specs I use. Helps with debugging. I actually have these in a source file and then use /Include at the top of my program.

    h option(*srcstmt : *noDebugIO)
    h decPrec(63)
    h copyright('name')
    h dftactgrp(*no)
    h actgrp(*caller)

    ReplyDelete
  7. dftactgrp (*NO) actgrp (*CALLER) option (*SRCSTMT:*NODEBUGIO:*NOSHOWCPY)

    ReplyDelete
  8. Mostly I use what you have shown. I use actgrp( *caller ) more then *new, I have also used thread( *serialize ) several times.

    ReplyDelete
  9. Mainly I use *NOBEBUGIO. We do som Security related ones lke dftactgrp, actgrp, urprf, at also.

    ReplyDelete
  10. This is what I currently use

    CTL-OPT BndDir('************');
    CTL-Opt Debug(*Yes);
    CTL-Opt ExtBinInt(*YES);
    CTL-Opt Indent('|');
    CTL-Opt OpenOPT(*INZOFL);
    CTL-Opt Option(*SrcStmt : *NoDebugIO : *NoShowCpy);
    CTL-Opt Copyright('************************');

    I also found out recently that as of V6.1 IBM has merged QC2LE with the default binding directory and includes it in every compile. So it is not necessary to specify it anymore..

    ReplyDelete
  11. FWIW, my typical H-Specs:

    H Aut( *Exclude )
    H BndDir( 'PROCS1':'PROCS2' )
    H Copyright( '(C) Company Name 2015' )
    H DatEdit( *YMD )
    H DatFmt( *ISO )
    H ExprOpts( *ResDecPos )
    H ExtBinInt( *Yes )
    H Indent( '|' )
    H Option( *NoDebugIO : *SrcStmt : *NoShowCpy : *NoUnref )
    /If Defined( *CRTBNDRPG )
    H ActGrp( *Caller )
    H DftActGrp( *No )
    H UsrPrf( *Owner )
    /EndIf

    Chris Ringer

    ReplyDelete
  12. Errata:
    H ALWNULL(*INPUT)
    ctl-opt alwnull(*input) ;

    You got it right later... "If I use ALWNULL(*INPUTONLY)"

    Chris Ringer

    ReplyDelete
    Replies
    1. Hi Simon: Is there any way that I could use the compile option DBGVIEW(*SOURCE) inside my RPG program. It would be very useful specially when we are testing an application. Thanks. Carlos. Carlosir@bellsouth.net

      Delete
    2. Simon, the link you provided above doesn't work. Can you please check. I too, want to include compile time option DBGVIEW(*SOURCE) inside my RPGLE program.

      Delete
    3. IBM keeps changing the URLs in the KnowledgeCenter without redirecting the old URL to the new.

      I have updated the link to go to the relevant page in the current KnowledgeCanter.

      Delete
  13. Always:
    h copyright('xxx')
    h decedit('0,')
    h indent(' ')
    h option(*nodebugio: *srcstmt)
    h expropts(*resdecpos)
    and in according to hhe specific situations I can add:
    datedit(*YMD) or datedit(*DMY)
    and
    dftactgrp(*no) actgrp(*new) or dftactgrp(*no) actgrp(*caller)

    ReplyDelete
  14. Ours looks like this. It's in a copy member, and I add a define before the copy as needed.
    H bnddir('UMEDBNDDIR':'QC2LE')
    H copyright('xxxx')
    H debug(*yes) option(*srcstmt:*nodebugio:*showcpy:*expdds)
    /if defined(#CALLER)
    H dftactgrp(*no)
    H actgrp(*CALLER)
    /elseif defined(#new)
    H dftactgrp(*no)
    H actgrp(*new)
    /elseif defined(#service)
    H Nomain
    /elseif defined(#sql)
    /else
    H dftactgrp(*no)
    H actgrp('QILE')
    /endif

    ReplyDelete
  15. H DEBUG OPTION(*NODEBUGIO : *SRCSTMT)

    ReplyDelete
  16. Mario Alexis Salgado MontenegroFebruary 21, 2015 at 11:05 PM

    Really helpfull...

    ReplyDelete
  17. The following is my CTL-OPT specs:
    /IF DEFINED(*CRTBNDRPG)
    CTL-OPT DFTACTGRP(*NO) ACTGRP('CCGOV');
    /ENDIF
    CTL-OPT Option(*NoDebugIO);

    This came about because I used to use *CALLER and when I posted some code for help in a forum, Scott Klement and numerous others... how shall I say it... quite emphatic that is a not a good idea and that I should provide a name... so I use CCGOV (I work for Campbell County GOVernment) - turns out to be good advise - there have been a few times that I needed to do a RCLACTGRP CCGOV - if you use *CALLER and the program is called from a non-ILE program (a CLP or RPG/400 program) there's no way to reclaim that activation group outside of ending the job.

    ReplyDelete
  18. We have used ACTGRP(name) a lot because it means you can have your menu do RCLACTGRP (name) to release all programs left open. GM.

    ReplyDelete
  19. Hi Mr. Hutchinson, I always use this especifications.

    H OPTION(*SRCSTMT:*NODEBUGIO) DFTACTGRP(*NO)
    H FIXNBR(*ZONED:*INPUTPACKED)
    H DEBUG(*YES) ACTGRP(*CALLER) BNDDIR('QC2LE')
    H COPYRIGHT('Company's name')

    Regards

    ReplyDelete
  20. Presence any one or more of ACTGRP, BNDDIR, STGMDL keyword(s) will cause the DFTACTGRP keyword to default to *NO.Hence, one can knock off dftactgrp(*no) in most cases
    To reduce coding and to standardize pgms across applications, ctl-opt's KWs can be stored externally either in /COPY or in dtaara and be referred in the pgm.

    /COPY lib/SRC,mbr
    (add additional ctl-opt specific to this pgm)

    -AnandX

    ReplyDelete
  21. H-SPECs define and Document how the Program should be compiled for your team and those that come after you - Behavior and DEBUG.
    Document FULLY do not depend on Defaults or System Behaviors - they come back to BUG you/and your code - SPECIFY DFTACTGRP(*NO) so that future maintenance developers see how you intended this to work (Communicate to your TEAM).
    Never Use a /COPYBOOK for H-SPECs, use of a /COPYBOOK is a failure to understand ILE.
    Each program needs to have the H-Specs Documented with the source (use a SNIPPET or TEMPLATE Approach) and Adjust as needed. Each program should be tuned for ILE Use.
    NEVER USE *SRCSTMT - Works for RPGLE but not good for SQLRPGLE Debugging or any other pre-compilers.

    Conditional Compiler Directives - I recommend them but your team may not understand it is a more advanced topic.

    MINIMUM ILE H-SPECs - Specify them LINE by LINE not all Jumbled together
    Remember you are documenting for your TEAM/Maintenance not a compiler
    The Comments below document them and explains to team why used.
    For ILE Programs - I personally vary the ACTIVATION Group based on purpose and ILE behavior needed from the Program or Service Program.

    // Generate Debug Information - *** REQUIRED H-Spec ***
    H DEBUG(*YES)
    // OPTION - *** REQUIRED H-Spec ***
    // Debug mode ignores IO and eliminate unused variables from compiled object
    // The OPTION(*SRCSTMT) prevents the compiler from renumbering the statements
    // Do NOT USE *SRCSTMT!, it is a problem if using Embedded SQL or other
    // Precompiler
    H OPTION(*NODEBUGIO :*NOUNREF)

    // ILE ACTIVATION GROUP - *** REQUIRED H-Specs INSEPARABLE ***
    // Activation Group Definition *CALLER - General Rule works with existing
    // Overrides, OPNQRYF
    // DO NOT USE NAMED OR *NEW Unless you know how your program is USED
    H DFTACTGRP(*NO)
    H ACTGRP(*CALLER)

    // Handle Database Table Integer Data types correctly - *** REQUIRED IF TRUE H EXTBININT(*YES)

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.