• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Enhancing CGIDEV2

    November 4, 2009 Paul Tuohy

    Maybe “enhancing” is too strong a word, but “Add-Ons for CGIDEV2” doesn’t have the same ring to it. I have always been (and still am) a big fan of CGIDEV2. A tool, such as CGIDDEV2, must be flexible enough to cater for all tastes. But when you have nailed down your own standards and working methods it is sometimes easier to have add-on procedures to implement those standards and working methods.

    With that in mind, I want to share a few of the subprocedures I have written that make CGIDEV2 a little easier to use in my development environment. All of these subprocedures are coded in a single module: UTILCGI. Although this article deals specifically with CGIDEV2, it also contains examples of how you can wrap functionality around existing subprocedures.

    Loading HTML Documents

    When it comes to the HTML documents that I use in a Web application, there are a number of points worth noting:

    • Each document must have the content type text/html entry at the start of the document.
    • The header and footer section of each Web page is the same.
    • The use of buttons (add, change, delete, etc.) is the same throughout my application.
    • I prefer not to use the default identifiers for section names and variable names. Instead I use <!– $section$ –> instead of /$section and <!– %variable% –> instead of %variable%.
    • I maintain the identity of the directory containing the CGIDEV2 template documents in a data area.

    CGIDEV2 provides two main subprocedures for loading HTML documents: getHTMLIFS() and getHTMLIFSMult(). The getHTMLIFSMult() subprocedure allows an easy means of loading multiple HTML documents to be processed as one. This is the equivalent of having copy members in DDS. Example Code 1 below shows the content of the template document StdMaintHead.html. This document contains a standard header that is common to all Web pages created interactively by an RPG program in my application. The main points to note are:

    • The content type text/html entry is at the start of the document. This means that the content type is defined in only one template document in my application.
    • There are two sections in the document, in case a program needs to insert additional heading information.
    • There are entries to include a standard CSS document and a standard Javascript document.
    • Documents make copious use of divisions and CSS classes. I leave it up to you to decide on your own style.

    Code 1: The StdMaintHead.html template document

    <!-- $top$ -->
    Content-type: text/html
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
    <html lang="en">
    <head>
       <meta http-equiv="Content-Type" content="text/html; 
        charset=ISO-8859-1">
       <title>My Application</title>
    
       <script language="javascript" src="https://itjungle.wpenginepowered.com/js/entryRoutines.js"
         type="text/javascript" />
       <link rel="stylesheet" href="https://itjungle.wpenginepowered.com/css/main.css" type="text/css" >
    
    <!-- $top2$ -->
    </head>
    <body">
    <div id="container">
    
    
       <div class="logo">My Logo
       </div>
    
       <div class="pageHeading"> My Common Headings
       </div>
    

    Code 2 shows the content of the template document StdMaintFoot.html. This document simply contains a section that completes the Web page.

    Code 2: The StdMaintFoot.html template document

    <!-- $end$ -->
      
    </div>
    
    </body>
    </html>
    

    Code 3 shows the content of the template document StdButtons.html. This document contains sections for each permutation and combination of submit buttons used throughout an application.

    Code 3: The StdButtons.html template document

    <!-- $changebutton$ -->
    <div class="buttons">
    <input type="submit" name="cgioption" id="CheckButton" value="Change">
    <input type="submit" name="cgioption" value="Delete" onClick=
    "return confirmDelete()">
    <input type="submit" name="cgioption" value="Cancel">
    </div>
    
    <!-- $addbutton$ -->
    <div class="buttons">
    <input type="submit" name="cgioption" id="CheckButton" value="Add">
    <input type="submit" name="cgioption" value="Cancel">
    </div>
    </pre>
    
    <!-- $changeCancelButton$ -->
    <div class="buttons">
    <input type="submit" name="cgioption" id="CheckButton" value="Change">
    <input type="submit" name="cgioption" value="Cancel">
    </div>
    

    Finally, Code 4 shows the content of the template document StdCGI.html. This is a very simple template containing a standard section name and variable name that is used in the generation of standard drop-down boxes, radio buttons, and check boxes. But more about that later in the article.

    Code 4: The StdCGI.html template document

    <!-- $SIDCGISection$ -->
    	  <!-- %SIDCGIVar% -->
    

    Assuming that all of these templates are stored in a directory named MyTemplates in the IFS, I will have a 512-byte data area named CGIROOT, in the library containing my CGIDEV2 programs, with a value of ‘/MyTemplates/’.

    I have wrapped the getHTMLIFSMult() subprocedure in another subprocedure, loadHTMLDocs(), which allows for less coding required in the template document being processed. Code 5 shows the relevant portion of the global D specs in UTILCGI along with the subprocedure loadHTMLDocs(). The main points to note are:

    • The subprocedure accepts up to five document names. Only the first is required.
    • If the list of standard templates has not been set, the identity of the template directory is retrieved from the data area and the variable HTMLDocs is set to identify the list of standard documents. Note that each standard document has the template directory appended and that HTMLDocs is a static variable so it does not need to be reset ob each call.
    • The variable HTMLDocsIn is set to identify the list of documents passed as parameters. Again, each document has the template directory appended.
    • Finally, the getHTMLIFS() subprocedure is used to retrieve the documents.

    Code 5: The subprocedure loadHTMLDocs()

    D CGIRoot         s            512a   DtaAra(CGIROOT)
    D CGIRootDone     s               n
    D thisRoot        s            512a   Varying
          
    P loadHTMLDocs    B                   Export
    D                 PI
    D  doc01                        50a   Varying Const
    D  doc02                        50a   Varying Const
    D                                     Options(*NoPass)
    D  doc03                        50a   Varying Const 
    D                                     Options(*NoPass)
    D  doc04                        50a   Varying Const 
    D                                     Options(*NoPass)
    D  doc05                        50a   Varying Const
    D                                     Options(*NoPass)
    
    D HTMLDocs        s          32767a   Varying Static
    D HTMLDocsIn      s           1000a   Varying
    
     /free
      if not CGIRootDone;
         in(E) CGIRoot;
         thisRoot = %Trim(CGIRoot);
         HTMLDocs = thisRoot + 'StdMaintHead.html '  +
                    thisRoot + 'StdButtons.html '    +
                    thisRoot + 'stdCGI.html '        +
                    thisRoot + 'StdMaintFoot.html ';
         CGIRootDone = *On;
      endIf;
    
      HTMLDOcsIn = thisRoot + doc01;
      if %Parms()> 1;
         HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc02 + ' ';
      endIf;
      if %Parms()> 2;
         HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc03 + ' ';
      endIf;
      if %Parms()> 3;
         HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc04 + ' ';
      endIf;
      if %Parms()> 4;
         HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc05 + ' ';
      endIf;
    
      getHTMLIFSMult(HTMLDocs + HTMLDocsIn :
                     '<!-- $':'$ -->':'<!-- %':'% -->');
      return;
    
     /end-Free
    P                 E
    

    The existing ability in CGIDEV2 to load multiple documents eases the requirement to repeat standard definitions in multiple HTML documents. Encapsulating the loading of these standard documents, along with the processing of an externally defined template directory, further eases the processing requirements in a CGI program.

    Selection Lists, Radio Buttons, and Check Boxes

    Some of the other items that can be tricky to handle with CGIDEV2 are selection lists, radio buttons, and check boxes. Of course CGIDEV2 has the crtTagOpt() subprocedure, which makes the generation of selection lists much easier and which I make use of in the following subprocedures: setCGIMultiple(), writeCGIMultiple(), and endCGIMultiple().

    Let’s have a look at these subprocedures at work. These subprocedures make use of the standard document shown back in Code 4. Code 6 shows the relevant portion of a programs template document and Code 7 shows the corresponding program code that uses the template.

    Code 6: Template code

    <span class="entryQuestion">In List? </span>
    
    <!-- $afterInList$ -->
    </p>
    
    <p>
    <span class="entryQuestion">Check These</span>
    
    <!-- $afterCheckThese$ -->
    </p>
    
    <p>
    <span class="entryQuestion">Size</span>
    
    <!-- $afterSize$ -->
    </p>
    

    Code 7: Corresponding program code for Template code in Code 6

    setCGIMultiple('R': 'InList' : inList :
                   *Omit : *Omit : 2);
    writeCGIMultiple('Y' : 'Yes');
    writeCGIMultiple('N' : 'No');
    
    wrtsection('afterInList');
    
    setCGIMultiple('C': 'CheckThis');
    writeCGIMultiple('W' : 'Watch' : checkW);
    writeCGIMultiple('L' : 'Wallet' : checkL);
    writeCGIMultiple('G' : 'Glasses' : checkG);
    
    wrtsection('afterCheckThese');
    
    setCGIMultiple('S': 'Size' : size);
    writeCGIMultiple('S' : 'Small');
    writeCGIMultiple('M' : 'Medium');
    writeCGIMultiple('L' : 'Large');
    endCGIMultiple();
    
    wrtsection('afterAllowRpt');
    

    Assuming that program fields have the following values, inList=’Y’, checkW=’W’, checkL=’ ‘, checkG=’G’, and size=’M’, the above bit of jiggery-pokery will result in the html shown in Code 8.

    Code 8: HTML generated from code in Figure 6 and Figure 7

    < span class="entryQuestion">In List?</span>
    
       <input type="radio" name="InList"  
        class="entry" value="Y" checked> Yes
          
       <input type="radio" name="InList" 
        class="entry" value="N"  > No
    
    </p>
    
    <p>
    <span class="entryQuestion">Check These</span>
    
       <input type="checkbox" name="CheckThis" 
        class="entry" value="W" checked> Watch
       <br />
       <input type="checkbox" name="CheckThis" 
        class="entry" value="L" > Wallet
       <br />
       <input type="checkbox" name="CheckThis" 
        class="entry" value="G" checked> Glasses
     
    </p>
    
    <p>
    <span class="entryQuestion">Size</span>
    
       <select name="size" class="entry" >
       <option value="S">Small</option>
       <option value="M" SELECTED>Medium</option>
       <option value="L">Large</option>
       </selected>
    
    </p>
    

    I know that one of the major benefits of CGIDEV2 is that HTML is externally defined in a template and that these subprocedures are diverting from that by generating the HTML internally. But remember that the generation of the HTML is to a standard and it is still external to the program that is generating the page.

    The subprocedures act as follows:

    • setCGIMultiple() constructs the required element.
    • writeCGIMultiple() places an individual entry.
    • endCGIMultiple() finishes the element (only required for selection lists).

    Code 9 shows the base data structure and work fields (defined in the global D specs in UTILCGI) used by the subprocedures.

    Code 9: Work fields used by the subprocedures

    D base            Ds                  Qualified Inz
    D  type                          1a
    D  currValue                    50a   Varying
    D  tabIndex                     10i 0
    D  accross                      10i 0 Inz(1)
    D  i                            10i 0
    
    D data            s           1000a   Varying
    D dataOut         s           1000a   Varying
    
    D VARNAME         C                   'SIDCGIVar'
    D SECTIONNAME     C                   'SIDCGISection'
    

    Let’s have a look at the subprocedures, starting with setCGIMultiple(), shown in Code 10. The main points to note are:

    • The first parameter identifies the required element as a radio button (R), check box (C), or selection list (S).
    • The second parameter identifies the name of the variable.
    • The third optional parameter identifies the current value for the variable. This is used to set the checked or selected option for the element.
    • The fourth optional parameter may be used to set a tab index.
    • The fifth optional parameter may be used to set a CSS class attribute–if not specified this defaults to a value of “entry.”
    • The sixth optional parameter identifies how many elements should be on a line.
    • The final option parameter identifies any other attributes that should be assigned to an element, e.g., to call a JavaScript function.
    • The subprocedure constructs an element tag based on the value of the first parameter.
    • The name attribute is assigned and other attributes are stored or assigned based on whether or not relevant parameters were passed.
    • Finally, if the element is a selection list the element is written. If the element is for a radio button or check box, the element is completed with the value and checked options being identified by entries of %vl% and %ch% (these will be replaced in the writeCGIMultiple() subprocedure).

    Code 10: The setCGIMultiple() subprocedure

    p setCGIMultiple  B                   Export
    D                 PI
    D  type                          1a   Const
    D  variable                     50a   Varying Const
    D  currValue                    50a   Varying Const
    D                                     Options(*NoPass : *Omit)
    D  tabIndex                     10i 0 Const Options(*NoPass : *Omit)
    D  class                        50a   Varying Const
    D                                     Options(*NoPass : *Omit)
    D  accross                      10i 0 Const Options(*NoPass : *Omit)
    D  other                       500a   Varying Const Options(*NoPass)
    
    D classDft        s             50a   Varying
    D                                     Inz('class="entry" ')
     /free
      reset Base;
      base.type = type;
    
      select;
         when base.type = 'S';
            data = '<select ';
         when base.type = 'R';
            data = '<input type="radio" ';
         when base.type = 'C';
            data = '<input type="checkbox" ';
         other;
            return;
      endSl;
    
      data = data + 'name="' + %trim(Variable) + '" ';
    
      if %Parms() > 2;
         if (%Addr(currValue) <> *null);
            base.currValue = %Trim(currValue);
         endIf;
      endIf;
    
      if %Parms() > 3;
         if (%Addr(tabIndex) <> *null);
            base.tabIndex = tabIndex;
            data = data+'tabIndex="' + %char(tabIndex) + '" ';
         endIf;
      endIf;
    
      if (%Parms() > 4);
         if (%Addr(class) <> *null);
            classDft = %Trim(class);
         endIf;
      endIf;
      data = data + classDft;
    
      if %Parms() > 5;
         if (%Addr(Accross) <>  *null);
            base.accross = accross;
         endIf;
      endIf;
    
      if (%Parms() > 6);
         data = data + %Trim(other);
      endIf;
    
      if base.type = 'S';
         data = data + '>';
         updHTMLVar(VARNAME : data);
         wrtSection(SECTIONNAME);
      else;
         data = data + 'value="%vl%" %ch%>';
      endIf;
    
      return;
     /end-Free
    P                 E
    

    Code 11 shows the writeCGIMultiple() subprocedure. The main points to note are:

    • The first parameter identifies the value to be assigned to the element.
    • The second parameter identifies the descriptive text for the element.
    • The third optional parameter identifies the current value for the element (this should only be required for check boxes).
    • If the element is a selection list then the crtTagOpt() subprocedure is used to create the <option> element otherwise.
    • The number of entries per line is calculated and either spacing or a line break is placed on the page. Then, the %Replace BIF is used to replace %vl% and %ch% entries with the required values and the element is written.

    Code 11: The writeCGIMultiple() subprocedure

    P writeCGIMultiple...
    P                 B                   Export
    D                 PI
    D  value                        50a   Varying Const
    D  desc                        100a   Varying Const
    D  currValue                    50a   Varying Const Options(*Nopass)
    
    D workValue       s                   Like(Value)
    D workDesc        s                   Like(Desc)
    D workCurrValue   s                   Like(currValue)
    
     /free
      workValue = %trim(value);
      workDesc = %trim(desc);
      if (base.type = 'S');
         updHTMLvar(VARNAME:CrtTagopt(workValue :
                                      workDesc :
                                      base.currValue));
         wrtsection(SECTIONNAME);
      else;
         base.i += 1;
         if (base.i > 1);
            if %Rem( base.i - 1 : base.accross) = 0;
               updHTMLVar(VARNAME : '<br/>');
            else;
               updHTMLVar(VARNAME : '   ');
            endIf;
            wrtSection(SECTIONNAME);
         endIf;
    
         dataOut = %Replace(workValue:data:%Scan('%vl%':data):4);
         workCurrValue = base.currValue;
         if (base.type = 'C' and %Parms() > 2);
            workCurrValue = currValue;
         endIf;
         if (workValue = workCurrValue);
            dataOut = %Replace('checked':dataOut:%Scan('%ch%':dataOut):4);
         else;
            dataOut = %Replace(' ':dataOut:%Scan('%ch%':dataOut):4);
         EndIf;
         dataOut = dataOut + ' ' + workDesc;
         updHTMLVar(VARNAME : dataOut);
         wrtSection(SECTIONNAME);
    
      endIf;
     /end-Free
    P                 E
    

    Finally, Code 12 shows the endCGIMultiple() subprocedure. This subprocedure only needs to be called to complete a selection list (but no harm is done if called for any of the other elements). The subprocedure simply writes the required ending </select> element.

    Code 12: The endCGIMultiple() subprocedure

    P endCGIMultiple  B                   Export
    D                 PI
    
     /free
      if (base.Type = 'S');
         updHTMLVar(VARNAME : '</select>');
         wrtSection(SECTIONNAME);
      endIf;
     /end-Free
    P                 E
    

    There You Have It

    Hopefully this has gotten your creative juices floating and, even if the code is of no direct or immediate use, it might give you some idea of how you can go about adding functionality to existing subprocedures without having to re-write or change them.

    If you like this approach to CGIDEV2, you might want to go the full hog and have a look at Rennaisance, which is an open source (i.e., free) framework built around CGIDEV2.

    Paul Tuohy is CEO of ComCon, an iSeries consulting company, and is one of the co-founders of System i Developer, which hosts the RPG & DB2 Summit conferences. He is an award-winning speaker who also speaks regularly at COMMON conferences, and is the author of “Re-engineering RPG Legacy Applications,” “The Programmers Guide to iSeries Navigator,” and the self-study course called “iSeries Navigator for Programmers.” Send your questions or comments for Paul to Ted Holt via the IT Jungle Contact page.



                         Post this story to del.icio.us
                   Post this story to Digg
        Post this story to Slashdot

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    New Generation Software

    FREE Webinar:

    Creating Great Data for Enterprise AI

    Enterprise AI relies on many data sources and types, but every AI project needs a data quality, governance, and security plan.

    Wherever and however you want to analyze your data, adopting modern ETL and BI software like NGS-IQ is a great way to support your effort.

    Webinar: June 26, 2025

    RSVP today.

    www.ngsi.com – 800-824-1220

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    looksoftware:  Get your FREE copy of the hottest product of the year!
    Computer Keyes:  KeyesOverlay rapidly converts standard *SCS printer files into PDF documents
    Manta Technologies:  Your complete source for IBM i training

    IT Jungle Store Top Book Picks

    Easy Steps to Internet Programming for AS/400, iSeries, and System i: List Price, $49.95
    The iSeries Express Web Implementer's Guide: List Price, $49.95
    The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
    The System i Pocket RPG & RPG IV Guide: List Price, $69.95
    The iSeries Pocket Database Guide: List Price, $59.00
    The iSeries Pocket SQL Guide: List Price, $59.00
    The iSeries Pocket Query Guide: List Price, $49.00
    The iSeries Pocket WebFacing Primer: List Price, $39.00
    Migrating to WebSphere Express for iSeries: List Price, $49.00
    Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
    Getting Started with WebSphere Express for iSeries: List Price, $49.00
    Can the AS/400 Survive IBM?: List Price, $49.00
    Chip Wars: List Price, $29.95

    Carpet Maker Finds a Comfy Spot with S2K 5.0 JDA Software Takes Another Run at i2 Technologies

    Leave a Reply Cancel reply

Volume 9, Number 35 -- November 4, 2009
THIS ISSUE SPONSORED BY:

Help/Systems
WorksRight Software
Halcyon Software

Table of Contents

  • Enable Row Set Paging in a Client/Server Environment Using SQL
  • The Case of the Used Unused Object: A Mystery
  • Some Questions on Adopted Authority Programs
  • Enhancing CGIDEV2
  • A Quick-and-Easy Way to Convert Case in RPG Programs
  • Admin Alert: Keeping i5/OS Ethernet Lines Connected

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Public Preview For Watson Code Assistant for i Available Soon
  • COMMON Youth Movement Continues at POWERUp 2025
  • IBM Preserves Memory Investments Across Power10 And Power11
  • Eradani Uses AI For New EDI And API Service
  • Picking Apart IBM’s $150 Billion In US Manufacturing And R&D
  • FAX/400 And CICS For i Are Dead. What Will IBM Kill Next?
  • Fresche Overhauls X-Analysis With Web UI, AI Smarts
  • Is It Time To Add The Rust Programming Language To IBM i?
  • Is IBM Going To Raise Prices On Power10 Expert Care?
  • IBM i PTF Guide, Volume 27, Number 20

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle