• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru: Quick And Handy RPG Output, Take 2

    October 25, 2021 Ted Holt

    I am pleased today to revisit a topic I wrote about just over seven and a half years ago. I do so for two reasons. First, I’ve made a slight improvement to my routine. Second, I’d like to provide more examples of this routine in action. My previous article suffered from a paucity of examples. I can’t believe I let that happen.

    I’m talking about the writeln subprocedure, a handy routine that I use to write unstructured text to a spooled file. I derived the inspiration for this routine from Pascal, a programming language I used heavily when I was working on my computer science degree. It’s not a substitute for record output (think DDS and O specs), but a different tool for different situations. If you have not read my first article on this subject, please do so before continuing.

    First, the improvement. Sometimes I like to indent certain lines of output for purposes of legibility, e.g. to align data in columns or to present the output in the form of an outline. When I found myself prepending inordinate numbers of blanks to the output string, I decided to add a second, optional parameter to indicate the starting position of the string in the output line. The default value is 1.

    Now, the examples. One of the ways I most use my writeln routine is for batch debugging. “Batch debugging?” I hear you ask. “What’s that?” Very simply this: Rather than running a program interactively under the control of a debugger, endlessly clicking a button or pressing some command key to step through the program, and endlessly repeating some other action to examine the values of variables, I make the program build a spooled file of the same sort of information. When the program finishes, I can read the spooled file to determine how the program behaved and why the program behaved as it did. Batch debugging does not replace the interactive debugger. I use each one as it makes sense.

    Let’s see an example. I’ve thrown together a short piece of nonsensical code that you can run on your own system if you like. Just make sure that library QIWS is in your library list.

    **free
    ctl-opt option(*srcstmt: *nodebugio) actgrp(*new) main(WL01R);
    
    //undefine debugging
    /define debugging
    
    dcl-f  qcustcdt  usage(*input) qualified usropn;
    
    /if defined(debugging)
    dcl-f qsysprt printer(132)  usropn;
    /endif
    
    dcl-proc  WL01R;
    
       dcl-pi *n;
          inState         char  ( 2   )    const;
          ouTotalDue      packed( 7: 2);
       end-pi;
    
       dcl-ds  CustomerRec    likerec(qcustcdt.cusrec);
       dcl-s   Name           varchar(24);
    
    /if defined(debugging)
       open qsysprt;
       writeln ('Enter ' + %proc() + ' ' + %char(%timestamp));
       writeln ('> Selected state =/' + inState + '/');
    /endif
    
       clear ouTotalDue;
    
       open qcustcdt;
    
       dow '1';
          read  qcustcdt.CusRec  CustomerRec;
          if %eof();
             leave;
          endif;
    
          if CustomerRec.State = inState;
             ouTotalDue += CustomerRec.BalDue;
             Name = ReformatName (CustomerRec.LstNam: CustomerRec.Init);
    /if defined(debugging)
             writeln ('Selected customer ' +
                       %editc(CustomerRec.CusNum: '4') +
                       '  Balance = ' +
                       %editc(CustomerRec.BalDue: 'L') : 3);
             writeln ('Name=/' + Name + '/': 3);
    /endif
          endif;
    
    
       enddo;
    
    /if defined(debugging)
       writeln ('> Total due = ' + %editc(ouTotalDue: 'L'));
       writeln ('Leave ' + %proc() + ' ' + %char(%timestamp));
    /endif
    
       close *all;
       return;
    end-proc  WL01R;
    
    dcl-proc  ReformatName;
    
       dcl-pi *n          varchar(24);
          inLastName      varchar(16)    const;
          inInitials      varchar( 3)    const;
       end-pi;
    
    /if defined(debugging)
       writeln ('Enter ' + %proc() : 3);
       writeln ('> Last=/' + inLastName +
                '/ Init=/' + inInitials + '/' : 3);
    /endif
    
       return %subst(inInitials: 1: 1) + '. ' +
              %subst(inInitials: 3: 1) + '. ' +
              %trim(inLastName);
    
    end-proc  ReformatName;
    
    /if defined(debugging)
    dcl-proc writeln;
       dcl-pi *n;
          inString   varchar(132)   const;
          inPosition uns(3)         const   options(*nopass);
       end-pi;
    
       dcl-ds   ReportLine   len(132)   end-ds;
       dcl-s    Position     uns(3);
    
       if %parms() >= %ParmNum(inPosition);
          Position = inPosition;
       else;
          Position = 1;
       endif;
    
       %subst(ReportLine: Position) = inString;
       write qsysprt ReportLine;
    
    end-proc writeln;
    /endif
    

    Notice the code that is conditioned to the debugging compiler condition. When I am working on the program, I /define the debugging condition. When the debugging condition is defined, I get a report like this one:

    Enter WL01R 2021-10-25-10.46.45.798914
    > Selected state =/NY/
      Enter REFORMATNAME
      > Last=/Jones   / Init=/B D/
      Selected customer 839283  Balance =  100.00
      Name=/B. D. Jones/
      Enter REFORMATNAME
      > Last=/Tyron   / Init=/W E/
      Selected customer 397267  Balance =     .00
      Name=/W. E. Tyron/
      Enter REFORMATNAME
      > Last=/Lee     / Init=/F L/
      Selected customer 192837  Balance =  489.50
      Name=/F. L. Lee/
    > Total due =   589.50
    Leave WL01R 2021-10-25-10.46.45.799561
    

    What you print is up to you. I find myself adding, removing, and modifying writeln commands as I work on the program.

    When I am ready to put the program into production, I /undefine the debugging condition. The debugging code is still there for the next time I work on the program if I should need it.

    Another way I commonly use the writeln routine is to log the progress of a program as it works through step after step. I’ll use the same illogical program to illustrate.

    **free
    ctl-opt option(*srcstmt: *nodebugio) actgrp(*new) main(WL02R);
    
    dcl-f  qcustcdt  usage(*input) qualified usropn;
    
    dcl-f qsysprt printer(132)  usropn;
    
    dcl-proc  WL02R;
    
       dcl-pi *n;
          inState     char  (  2   )  const;
          ouTotalDue  packed(  7: 2);
          inOptions   char  ( 80   )  const options(*nopass);
       end-pi;
    
       dcl-s   Logging        ind;
       dcl-ds  CustomerRec    likerec(qcustcdt.cusrec);
       dcl-s   Name           varchar(24);
    
       if %parms() >= %parmnum(inOptions)
       and %scan('NOLOG': inOptions) = *zero
       and %scan('LOG'  : inOptions) > *zero;
          Logging = *on;
       endif;
    
       if Logging;
          open qsysprt;
          writeln ('Enter ' + %proc() + ' ' + %char(%timestamp));
          writeln ('> Selected state =/' + inState + '/');
       endif;
    
       clear ouTotalDue;
    
       open qcustcdt;
    
       dow '1';
          read  qcustcdt.CusRec  CustomerRec;
          if %eof();
             leave;
          endif;
    
          if CustomerRec.State = inState;
             ouTotalDue += CustomerRec.BalDue;
             Name = ReformatName (CustomerRec.LstNam: CustomerRec.Init:
                                  Logging);
             if Logging;
                writeln ('Selected customer ' +
                          %editc(CustomerRec.CusNum: '4') +
                          '  Balance = ' +
                          %editc(CustomerRec.BalDue: 'L') : 3);
                writeln ('Name=/' + Name + '/': 3);
             endif;
          endif;
    
       enddo;
    
       if Logging;
          writeln ('> Total due = ' + %editc(ouTotalDue: 'L'));
          writeln ('Leave ' + %proc() + ' ' + %char(%timestamp));
       endif;
    
       close *all;
       return;
    end-proc  WL02R;
    
    dcl-proc  ReformatName;
    
       dcl-pi *n          varchar(24);
          inLastName      varchar(16)    const;
          inInitials      varchar( 3)    const;
          inLogging       ind            const;
       end-pi;
    
       if inLogging;
          writeln ('Enter ' + %proc() : 3);
          writeln ('> Last=/' + inLastName +
                   '/ Init=/' + inInitials + '/' : 3);
       endif;
    
       return %subst(inInitials: 1: 1) + '. ' +
              %subst(inInitials: 3: 1) + '. ' +
              %trim(inLastName);
    
    end-proc  ReformatName;
    
    dcl-proc writeln;
       dcl-pi *n;
          inString   varchar(132)   const;
          inPosition uns(3)         const   options(*nopass);
       end-pi;
    
       dcl-ds   ReportLine   len(132)   end-ds;
       dcl-s    Position     uns(3);
    
       if %parms() >= %ParmNum(inPosition);
          Position = inPosition;
       else;
          Position = 1;
       endif;
    
       %subst(ReportLine: Position) = inString;
       write qsysprt ReportLine;
    
    end-proc writeln;
    

    The debugging compiler condition is gone. The printer file, the writeln routine, all the writeln calls, and the printer file open are compiled into the object code and are controlled by a variable named LOGGING in the main subprocedure. Whether the report is produced or not is controlled through an optional options parameter.

    I can put the word LOG or NOLOG in the options parameter when I call the program. If I specify LOG, the program produces the same report shown above. I can easily enable and disable the report by changing the command string in the job scheduler.

    The way I interpret the options parameter in this example is not foolproof, but it’s robust enough for my purposes, as I know that I will not put a value like FLOG or APOLOGY or HYDROBIOLOGICAL into the parameter string.

    What we do now is no different from what people have been doing since the earliest days of business computing. We process input to create output. Output can be formal or informal. Both types have their place. My writeln routine has been invaluable to me in producing both types of output. If you can improve my routine, please do so and let me know about it.

    RELATED STORY

    Quick And Handy RPG Output

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: 400guru, FHG, Four Hundred Guru, IBM i, RPG

    Sponsored by
    Connectria

    Comprehensive Support with Connectria

    Connectria is the largest IBM i (AS/400) cloud provider in the world. With remote administration or monitoring, our team can deliver full administration or simply keep an eye on your environment.

    Connectria also has experts in managing mission critical workloads in the top public clouds. Need a mix of on-premises, public cloud, and private cloud? Connectria delivers solutions for any environment on any cloud.

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    HelpSystems Goes Phishing For Cyber Threat Hunter Talking Power Systems Deals With The Boss

    2 thoughts on “Guru: Quick And Handy RPG Output, Take 2”

    • Dale Janus says:
      October 25, 2021 at 11:42 am

      how should WriteLn be compiled? I get error no open, among other errors

      Reply
    • Ted Holt says:
      November 3, 2021 at 11:18 am

      Hi, Dale. You’ll have to open the printer file yourself.

      I include writeln in every source member where I use it. Someday I may turn it into a standalone module that you’ll just link to, and if I do, the module will handle the open on the first call to writeln.

      Reply

    Leave a Reply Cancel reply

TFH Volume: 31 Issue: 70

This Issue Sponsored By

  • Fresche Solutions
  • UCG Technologies
  • Connectria
  • Raz-Lee Security
  • WorksRight Software

Table of Contents

  • A Proper Accounting Of The Power Business
  • Talking Power Systems Deals With The Boss
  • Guru: Quick And Handy RPG Output, Take 2
  • HelpSystems Goes Phishing For Cyber Threat Hunter
  • Various Power Systems Updates And Tweaks

Content archive

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

Recent Posts

  • How Committed Is Big Blue To The IBM Cloud?
  • Immutable Copies Are Only As Good As Your Validation
  • Guru: IBM i *USRPRF Security
  • ERP Transitions Loom for SAP on IBM i Customers
  • Inflation Pumps Up Global IT Spending, Supply Chain Deflates It
  • COMMON Set for First Annual Conference in Three Years
  • API Operations Management for Safe, Powerful, and High Performance APIs
  • What’s New in IBM i Services and Networking
  • Four Hundred Monitor, May 18
  • IBM i PTF Guide, Volume 24, 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 © 2022 IT Jungle

loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.