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   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:


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:


    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:


    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.


    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.


    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.


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

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

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

  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.

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

  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)

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

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

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

  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..

  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 )

    Chris Ringer

  12. Errata:
    ctl-opt alwnull(*input) ;

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

    Chris Ringer

  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)
    dftactgrp(*no) actgrp(*new) or dftactgrp(*no) actgrp(*caller)

  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)
    H dftactgrp(*no)
    H actgrp('QILE')


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

    Really helpfull...

  17. The following is my CTL-OPT specs:
    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.


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.