PRTLN Initial Commit
This commit is contained in:
parent
ac6d360199
commit
454036cc98
6
Copy_Mbrs/PRT_P.RPGLE
Normal file
6
Copy_Mbrs/PRT_P.RPGLE
Normal file
@ -0,0 +1,6 @@
|
||||
**FREE
|
||||
// Prototype for PRT program
|
||||
dcl-pr PRT extpgm('PRT');
|
||||
line char(132) const;
|
||||
ctl char(10) const options(*nopass);
|
||||
end-pr;
|
||||
27
PRT_CL/DEMO_CL1.CLLE
Normal file
27
PRT_CL/DEMO_CL1.CLLE
Normal file
@ -0,0 +1,27 @@
|
||||
/*=== Demo a simple report =================================*/
|
||||
PGM
|
||||
DCL (&LC) (*DEC) LEN(5 0) VALUE(1)
|
||||
DCL (&UNDER) (*CHAR) LEN(20) VALUE('____________________')
|
||||
/* Define print line and columns */
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
DCL (&COUNT) (*CHAR) STG(*DEFINED) LEN(5) DEFVAR(&LINE 5)
|
||||
DCL (&STAMP) (*CHAR) STG(*DEFINED) LEN(20) DEFVAR(&LINE 20)
|
||||
/* Define heading 1 */
|
||||
PRTLN LINE('Really Simple Report') HEADING(Y) HEAD(1 Y)
|
||||
/* Define heading 2 */
|
||||
CHGVAR &COUNT 'COUNT'
|
||||
CHGVAR &STAMP 'TIMESTAMP'
|
||||
PRTLN LINE(&LINE) HEADING(Y) HEAD(2)
|
||||
/* Define hading 3 Underscoring heading 2 */
|
||||
CHGVAR &COUNT &UNDER
|
||||
CHGVAR &STAMP &UNDER
|
||||
PRTLN LINE(&LINE) SPACE(S0) HEADING(Y) HEAD(3)
|
||||
/* Print a report showing count and timestamp */
|
||||
DOWHILE COND(&LC *LT 70)
|
||||
CHGVAR &COUNT %CHAR(&LC)
|
||||
RTVSYSVAL SYSVAL(QDATETIME) RTNVAR(&STAMP)
|
||||
PRTLN LINE(&LINE)
|
||||
CHGVAR VAR(&LC) VALUE(&LC + 1)
|
||||
ENDDO
|
||||
PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
50
PRT_CL/DEMO_CL2.CLP
Normal file
50
PRT_CL/DEMO_CL2.CLP
Normal file
@ -0,0 +1,50 @@
|
||||
/*=== Demo a complex report ================================*/
|
||||
/* List files & members with record count and description. */
|
||||
/* Has heading lines, an underscored heading & page number. */
|
||||
PGM
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
/* Define data columns in &LINE */
|
||||
DCL (&LIB) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE)
|
||||
DCL (&FILE) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 12)
|
||||
DCL (&MBR) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 33)
|
||||
DCL (&RCDS) (*CHAR) STG(*DEFINED) LEN(8) DEFVAR(&LINE 44)
|
||||
DCL (&TEXT) (*CHAR) STG(*DEFINED) LEN(50) DEFVAR(&LINE 53)
|
||||
DCL (&UNDER) (*CHAR) LEN(60) +
|
||||
VALUe('____________________________________________________________')
|
||||
/* Create some data */
|
||||
DCLF FILE(QAFDMBRL)
|
||||
DSPFD FILE(*CURLIB/Q*) TYPE(*MBRLIST) +
|
||||
OUTPUT(*OUTFILE) FILEATR(*PF) +
|
||||
OUTFILE(QTEMP/MBRLIST)
|
||||
OVRDBF FILE(QAFDMBRL) TOFILE(QTEMP/MBRLIST)
|
||||
|
||||
/* Define heading lines. Second heading is underscored */
|
||||
PRTLN LINE('Member List') HEADING(Y) HEAD(1 Y)
|
||||
|
||||
CHGVAR (&LIB) ('Library')
|
||||
CHGVAR (&FILE) ('File')
|
||||
CHGVAR (&MBR) ('Member')
|
||||
CHGVAR (&RCDS) ('#Records')
|
||||
CHGVAR (&TEXT) ('Description')
|
||||
PRTLN LINE(&LINE) HEADING(Y) HEAD(2)
|
||||
|
||||
CHGVAR (&LIB) (&UNDER)
|
||||
CHGVAR (&FILE) (&UNDER)
|
||||
CHGVAR (&MBR) (&UNDER)
|
||||
CHGVAR (&RCDS) (&UNDER)
|
||||
CHGVAR (&TEXT) (&UNDER)
|
||||
PRTLN LINE(&LINE) SPACE(S0) HEADING(Y) HEAD(3)
|
||||
|
||||
/* Loop thru the data and print */
|
||||
LOOP:
|
||||
RCVF RCDFMT(QWHFDML)
|
||||
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EOF))
|
||||
CHGVAR (&LIB) (&MLLIB)
|
||||
CHGVAR (&FILE) (&MLFILE)
|
||||
CHGVAR (&MBR) (&MLNAME)
|
||||
CHGVAR (&RCDS) (%CHAR(&MLNRCD))
|
||||
CHGVAR (&TEXT) (&MLMTXT)
|
||||
PRTLN LINE(&LINE)
|
||||
GOTO CMDLBL(LOOP)
|
||||
EOF: PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
58
PRT_CL/DEMO_CL3.CLLE
Normal file
58
PRT_CL/DEMO_CL3.CLLE
Normal file
@ -0,0 +1,58 @@
|
||||
/*=== Demo a complex report with breaks ============================*/
|
||||
/* Contains heading lines and underscored headings & page number */
|
||||
/* - Library is in the heading line */
|
||||
/* - File prints only when it changes */
|
||||
PGM
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
/* Define data columns in &LINE */
|
||||
DCL (&FILE) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE)
|
||||
DCL (&MBR) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 13)
|
||||
DCL (&RCDS) (*CHAR) STG(*DEFINED) LEN(8) DEFVAR(&LINE 24)
|
||||
DCL (&TEXT) (*CHAR) STG(*DEFINED) LEN(50) DEFVAR(&LINE 33)
|
||||
DCL (&UNDER) (*CHAR) LEN(60) +
|
||||
VALUe('____________________________________________________________')
|
||||
DCL (&THELIB) (*CHAR) LEN(10) VALUE('LENNONS1')
|
||||
DCL (&LAST_FILE) (*CHAR) LEN(10) VALUE(' ')
|
||||
DCL (&LINE_SPACE) (*CHAR) LEN(2)
|
||||
/* Create some data */
|
||||
DCLF FILE(QAFDMBRL)
|
||||
DSPFD FILE(&THELIB/*ALL) TYPE(*MBRLIST) +
|
||||
OUTPUT(*OUTFILE) FILEATR(*PF) +
|
||||
OUTFILE(QTEMP/MBRLIST)
|
||||
OVRDBF FILE(QAFDMBRL) TOFILE(QTEMP/MBRLIST)
|
||||
|
||||
/* Define heading lines. Second is underscored */
|
||||
PRTLN LINE('File Member List - Library:' *BCAT &THELIB) HEADING(Y) HEAD(1 Y)
|
||||
CHGVAR (&FILE) ('File')
|
||||
CHGVAR (&MBR) ('Member')
|
||||
CHGVAR (&RCDS) ('#Records')
|
||||
CHGVAR (&TEXT) ('Description')
|
||||
PRTLN LINE(&LINE) SPACE(S2) HEADING(Y) HEAD(2)
|
||||
CHGVAR (&FILE) (&UNDER)
|
||||
CHGVAR (&MBR) (&UNDER)
|
||||
CHGVAR (&RCDS) (&UNDER)
|
||||
CHGVAR (&TEXT) (&UNDER)
|
||||
PRTLN LINE(&LINE) SPACE(S0) HEADING(Y) HEAD(3)
|
||||
|
||||
/* Loop thru the data and print */
|
||||
LOOP:
|
||||
RCVF RCDFMT(QWHFDML)
|
||||
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EOF))
|
||||
/* Print file just once */
|
||||
IF (&MLFILE *NE &LAST_FILE) DO
|
||||
CHGVAR (&LAST_FILE) &MLFILE
|
||||
CHGVAR (&FILE) (&LAST_FILE)
|
||||
CHGVAR (&LINE_SPACE) 'S2'
|
||||
ENDDO
|
||||
ELSE DO
|
||||
CHGVAR (&FILE) ' '
|
||||
ENDDO
|
||||
CHGVAR (&MBR) (&MLNAME)
|
||||
CHGVAR (&RCDS) (%CHAR(&MLNRCD))
|
||||
CHGVAR (&TEXT) (&MLMTXT)
|
||||
PRTLN LINE(&LINE) SPACE(&LINE_SPACE)
|
||||
CHGVAR (&LINE_SPACE) 'S1'
|
||||
GOTO CMDLBL(LOOP)
|
||||
|
||||
EOF: PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
208
PRT_CL/DEMO_RPG1.SQLRPGLE
Normal file
208
PRT_CL/DEMO_RPG1.SQLRPGLE
Normal file
@ -0,0 +1,208 @@
|
||||
**free
|
||||
// ==============================================================
|
||||
// RPG demo of the PRT program: Printing a file format listing.
|
||||
// ==============================================================
|
||||
// - Uses SQL input from QSYS2.SYSCOLUMNS2 and QSYS.TABLES.
|
||||
// - Specify a single file or generic. Source files are omitted.
|
||||
// - Each file starts on a new page.
|
||||
// - Report is sorted by file and either field name or sequence.
|
||||
// Parms
|
||||
// 1 Library: Char 10.
|
||||
// 2 File name: Char 10.
|
||||
// For generic, append *, e.g., LINE* will print all
|
||||
// all files that start with LINE.
|
||||
// 3 Order Char(1)
|
||||
// N: sort by field name (default)
|
||||
// S: sort by ordinal sequence of fields
|
||||
// Sample call:
|
||||
// CALL PGM(DEMO_RPG1) PARM((LENNONS1) (BOMMASPF) (S))
|
||||
// If you plan to use this, creating a command is recommended.
|
||||
ctl-opt option(*srcstmt: *nodebugio)
|
||||
bnddir('SQL_BND')
|
||||
actgrp(*new) main(Main);
|
||||
/COPY copy_mbrs,prt_p
|
||||
/COPY copy_mbrs,srv_sql_p
|
||||
|
||||
dcl-proc Main;
|
||||
dcl-pi Main;
|
||||
pi_library char(10);
|
||||
pi_filelike char(10);
|
||||
pi_order char(1);
|
||||
end-pi;
|
||||
dcl-c SQLSUCCESS '00000';
|
||||
dcl-c SQLNODATA '02000';
|
||||
dcl-c SQLNOMOREDATA '02000';
|
||||
|
||||
dcl-s theLibrary varchar(10) ;
|
||||
dcl-s theFile varchar(10);
|
||||
dcl-s theSeq char(1) inz('N');
|
||||
dcl-s lastFile char(10) inz(' ');
|
||||
dcl-s eofSW ind inz(*off);
|
||||
|
||||
dcl-ds inSQL qualified ; // SQL data returned here
|
||||
library char(10);
|
||||
file char(10);
|
||||
file_desc char(50);
|
||||
field_name char(10);
|
||||
type char(8);
|
||||
length int(10);
|
||||
decimals int(10);
|
||||
field_desc char(50);
|
||||
col_head char(60);
|
||||
seq int(10);
|
||||
end-ds;
|
||||
|
||||
dcl-ds line len(132) qualified; // Line layout
|
||||
seq char(4);
|
||||
*n char(2);
|
||||
field_name char(10);
|
||||
*n char(2);
|
||||
type char(8);
|
||||
*n char(2);
|
||||
length char(10);
|
||||
*n char(2);
|
||||
decimal char(3);
|
||||
*n char(2);
|
||||
text char(50);
|
||||
end-ds;
|
||||
|
||||
dcl-ds h1 qualified; // Header 1
|
||||
*n char(15) inz('Field Listing: ');
|
||||
lib_file char(21);
|
||||
file_desc char(50);
|
||||
end-ds;
|
||||
|
||||
dcl-ds h2 likeds(line); // Header 2 layout.
|
||||
|
||||
exsr init;
|
||||
|
||||
// Set up second heading line
|
||||
h2.seq = ' Seq';
|
||||
h2.field_name = 'Field Name';
|
||||
h2.type = 'Type';
|
||||
h2.length = 'Length';
|
||||
h2.decimal = 'Dec';
|
||||
h2.text = 'Description';
|
||||
PRT(h2 : '*H2: S2');
|
||||
|
||||
// Underline second heading line
|
||||
h2.seq = *all'_';
|
||||
h2.field_name = *all'_';
|
||||
h2.type = *all'_';
|
||||
h2.length = *all'_';
|
||||
h2.decimal = *ALL'_';
|
||||
h2.text = *all'_';
|
||||
PRT(h2 : '*H3: S0');
|
||||
|
||||
// === Loop through the data and print lines
|
||||
// === Skip to new page if library changes
|
||||
exsr fetch;
|
||||
dow (eofSW = *off);
|
||||
if (inSQL.file <> lastFile);
|
||||
PRT(' ' : '*NEWPAGE');
|
||||
h1.lib_file = %trim(inSQL.library) + '/' + inSQL.file;
|
||||
h1.file_desc = inSQL.file_desc;
|
||||
PRT(h1 : '*H1: *P');
|
||||
lastFile = inSQL.file;
|
||||
endif;
|
||||
// Fill line with the rest of the data
|
||||
evalr line.seq = %trim(%char(inSQL.seq));
|
||||
line.field_name = inSQL.field_name;
|
||||
line.type = inSQL.type;
|
||||
evalr line.length = %trim(%char(inSQL.length));
|
||||
if (inSQL.decimals >=0);
|
||||
evalr line.decimal = %trim(%char(inSQL.decimals));
|
||||
else;
|
||||
line.decimal = ' ';
|
||||
endif;
|
||||
line.text = inSQL.field_desc;
|
||||
|
||||
PRT(line);
|
||||
exsr fetch;
|
||||
enddo;
|
||||
PRT(' ' : '*NEWPAGE');
|
||||
PRT('SQL parms: Library-' + theLibrary +
|
||||
' File-' + theFile + ' Order-' + theSeq: 'S2');
|
||||
PRT('** End of Report **' : 'S2');
|
||||
PRT(' ' : '*CLOSE');
|
||||
return;
|
||||
|
||||
// ==============================================================
|
||||
// === Initial Paramets and SQL setup ===========================
|
||||
begsr init;
|
||||
// === Process paramters
|
||||
if (%parms = 0); //no parms, set defaults for testing
|
||||
theLibrary = 'LENNONS1';
|
||||
theFile = 'ECL*';
|
||||
theSeq = 'S';
|
||||
endif;
|
||||
if (%parms = 1 ) ;
|
||||
theLibrary = %upper(%trim(pi_library));
|
||||
theFile = 'ECL*';
|
||||
theSeq = 'S';
|
||||
endif;
|
||||
if (%parms = 2);
|
||||
theLibrary = %upper(%trim(pi_library));
|
||||
theFile = %upper(%trim(pi_filelike));
|
||||
theSeq = 'S';
|
||||
endif;
|
||||
if (%parms = 3);
|
||||
theLibrary = %upper(%trim(pi_library));
|
||||
theFile = %upper(%trim(pi_filelike));
|
||||
theSeq = %upper(pi_order);
|
||||
endif;
|
||||
|
||||
// === Handle generic file
|
||||
theFile = %xlate('*' : '%' : theFile);
|
||||
|
||||
exec sql set option datfmt=*iso,
|
||||
closqlcsr=*endmod,
|
||||
commit=*none;
|
||||
|
||||
// === Cursor to get the data
|
||||
exec sql declare data_cursor cursor for
|
||||
SELECT TABLE_SCHEMA as library
|
||||
,cols.SYSTEM_TABLE_NAME AS file_name
|
||||
,char(tbls.TABLE_TEXT, 50) as file_desc
|
||||
,cols.SYSTEM_COLUMN_NAME AS field_name
|
||||
,char(cols.DATA_TYPE, 8) AS type
|
||||
,cols.LENGTH
|
||||
,cOALESCE(cols.NUMERIC_SCALE, -1) AS decimals
|
||||
,char(coalesce(cols.COLUMN_TEXT, ' '), 50) as field_desc
|
||||
,cHAR(COALESCE(cols.COLUMN_HEADING, ' '), 60) AS col_head
|
||||
,cols.ORDINAL_POSITION AS seq
|
||||
FROM QSYS2.SYSTABLES tbls
|
||||
JOIN QSYS2.SYSCOLUMNS2 cols
|
||||
using (TABLE_SCHEMA, TABLE_NAME)
|
||||
WHERE TABLE_SCHEMA = :theLibrary
|
||||
AND tbls.FILE_TYPE <> 'S' // omit source files
|
||||
AND trim(cols.SYSTEM_TABLE_NAME) like :theFile
|
||||
ORDER BY cols.SYSTEM_TABLE_NAME,
|
||||
case :theSeq
|
||||
when 'N' then cols.SYSTEM_COLUMN_NAME
|
||||
else digits(cols.ORDINAL_POSITION)
|
||||
end
|
||||
;
|
||||
//== Open cursor
|
||||
exec sql open data_cursor;
|
||||
if (sqlstate <> SQLSUCCESS);
|
||||
SQLProblem('Open failed');
|
||||
endif;
|
||||
endsr;
|
||||
|
||||
// === Fetch next row from cursor ===============================
|
||||
begsr fetch;
|
||||
exec sql fetch data_cursor into :inSQL;
|
||||
if (sqlstate = SQLNOMOREDATA);
|
||||
eofSW = *on;
|
||||
leavesr;
|
||||
endif;
|
||||
if (sqlstate = SQLSUCCESS);
|
||||
eofSW = *off;
|
||||
leavesr;
|
||||
else;
|
||||
SQLProblem('Fetch failed');
|
||||
endif;
|
||||
endsr;
|
||||
|
||||
end-proc main;
|
||||
7
PRT_CL/MYPRT.CLLE
Normal file
7
PRT_CL/MYPRT.CLLE
Normal file
@ -0,0 +1,7 @@
|
||||
/* Create program described printer file used by PRT RPG program */
|
||||
PGM
|
||||
CRTPRTF FILE(LENNONS1/MYPRT) DEVTYPE(*SCS) +
|
||||
PAGESIZE(66 133) LPI(6) CPI(10) +
|
||||
OVRFLW(60) CTLCHAR(*FCFC) CHLVAL((1 (6))) +
|
||||
FONT(*CPI)
|
||||
ENDPGM
|
||||
292
PRT_CL/PRT.RPGLE
Normal file
292
PRT_CL/PRT.RPGLE
Normal file
@ -0,0 +1,292 @@
|
||||
**free
|
||||
// ==================================================================
|
||||
// PRT: A program that prints a report by printing a line at a time.
|
||||
// A convenience routine for simple reports, since O-SPECs are not
|
||||
// supported in **FREE RPG programs. It avoids having to create an
|
||||
// externally defined printer file.
|
||||
// ==================================================================
|
||||
// Parms:
|
||||
//
|
||||
// 1) Char(132) Line text. (Or blank for certain control cases.)
|
||||
//
|
||||
// 2) Char(10) Control field. Optional.
|
||||
// blank Parm 1 contains the line to be printed with
|
||||
// single spacing.
|
||||
// Line control: How to print Parm 1:
|
||||
// S1 Space one line and print.
|
||||
// Omitted or blank is the same as S1.
|
||||
// S2 Space two lines and print.
|
||||
// S3 Space three lines and print.
|
||||
// S0 Overprint current line.
|
||||
//
|
||||
// Definitions - no line are printed with this call.
|
||||
// *Hn Define heading line "n", where n is 1 to 9
|
||||
// Parm 1 can be all blanks to print a blank line
|
||||
// heading line.
|
||||
// *Hn:Sx Define heading line "n", where n is 1 to 9 and
|
||||
// "x" is the number of lines to space, where
|
||||
// x is 0 to 3. S0 will overprint prior line.
|
||||
// *Hn:*P:Sx Page number will be printed at the end of this
|
||||
// header line.
|
||||
//
|
||||
// Special control funtions - no line is printed.
|
||||
// *NEWPAGE Next line will print on a new page.
|
||||
// Parm 1 is ignored.
|
||||
|
||||
// *CLOSE Close the print file.
|
||||
// Parm 1 is ignored.
|
||||
|
||||
// ==================================================================
|
||||
ctl-opt option(*srcstmt: *nodebugio)
|
||||
actgrp(*caller)
|
||||
main(Prt);
|
||||
|
||||
// ==================================================================
|
||||
// === Program defined print file. ==================================
|
||||
dcl-f MYPRT printer(133) usropn oflind(*in99) extfile('MYPRT');
|
||||
// Change extfile above to use another *FCFC print file.
|
||||
|
||||
// === Global Constants =============================================
|
||||
dcl-c SP0 'S0'; // Overprint
|
||||
dcl-c SP1 'S1'; // Space 1 & print
|
||||
dcl-c SP2 'S2'; // Space &2 print
|
||||
dcl-c SP3 'S3'; // Space 3 and print
|
||||
dcl-c TOP 'SK1'; // Skip to top and print
|
||||
dcl-c PAGELINE '*P'; // Header line has page #
|
||||
|
||||
// ==================================================================
|
||||
// ===Prt procedure =================================================
|
||||
dcl-proc Prt;
|
||||
dcl-pi Prt;
|
||||
pi_line char(132); // Line text
|
||||
pi_ctl char(10); // Control
|
||||
end-pi;
|
||||
|
||||
// Data structure template for write to printer file
|
||||
dcl-ds lines qualified template;
|
||||
line char(132) inz;
|
||||
isHdr ind inz;
|
||||
isPage ind inz;
|
||||
Ctl char(2) inz(SP1);
|
||||
end-ds;
|
||||
|
||||
dcl-s j int(10);
|
||||
dcl-s pageNumC char(8);
|
||||
dcl-s wk_Ctl like(pi_ctl);
|
||||
dcl-ds wkLn likeds(lines); // header line with page num
|
||||
dcl-s headerSkip ind;
|
||||
dcl-s gotHeaders ind;
|
||||
dcl-s ctlValues varchar(4) dim(*auto : 3); // Values split from Ctl
|
||||
|
||||
// Array of Valid Spacing control chars.
|
||||
dcl-ds vs qualified;
|
||||
s1 char(3) inz(' ');
|
||||
*n char(3) inz(SP0);
|
||||
*n char(3) inZ(SP1);
|
||||
*n char(3) inZ(SP2);
|
||||
*n char(3) inZ(SP3);
|
||||
validSpaces char(3) dim(5) samepos(s1);
|
||||
end-ds;
|
||||
|
||||
// Static fields: These need to be retained across calls
|
||||
dcl-ds hdrs likeds(lines) dim(9) static; // Up to 9 header lines
|
||||
dcl-s newPage ind inz(*on) static; // First page is a new page
|
||||
dcl-s pageNum packed(5) static inz(1);
|
||||
|
||||
// === Open printer file ===
|
||||
if (not %open(MYPRT));
|
||||
open MYPRT;
|
||||
endif;
|
||||
|
||||
// ================================================================
|
||||
// === Main processing logic ======================================
|
||||
select;
|
||||
// A non-printing control function
|
||||
when (%parms = 2 and %subst(pi_ctl :1 :1) = '*');
|
||||
exsr doControl;
|
||||
// Print with a control
|
||||
when (%parms = 2);
|
||||
wk_Ctl = pi_ctl;
|
||||
exsr doPrint;
|
||||
// Print without a control - default space 1
|
||||
when (%parms = 1);
|
||||
wk_Ctl = SP1;
|
||||
exsr doPrint;
|
||||
other;
|
||||
PrtLn('>>1>>>>>> Error: Called with missing/incorrect parmaters':SP1);
|
||||
endsl;
|
||||
return;
|
||||
|
||||
// ================================================================
|
||||
// === Non-printing control functions =============================
|
||||
begsr doControl;
|
||||
wk_Ctl = %upper(pi_ctl);
|
||||
select;
|
||||
// Force a new page if next line won't be a new page
|
||||
when (pi_ctl = '*NEWPAGE');
|
||||
newPage = *on;
|
||||
|
||||
// Handle closing the report
|
||||
when (pi_ctl = '*CLOSE');
|
||||
if (%open(MYPRT));
|
||||
close MYPRT;
|
||||
endif;
|
||||
// Reset static in case called again from same activation group
|
||||
reset newPage;
|
||||
reset pageNum;
|
||||
reset hdrs;
|
||||
*inlr =*on;
|
||||
|
||||
// Save head line definitions
|
||||
when (%subst(wk_Ctl :1 :2) = '*H');
|
||||
// Split up the control function par,
|
||||
%elem(ctlValues) = 0;
|
||||
ctlValues = %split(wk_Ctl :':');
|
||||
// first one is *Hn, where n is 1=9
|
||||
if (%len(%trim(ctlValues(1))) > 3);
|
||||
PrtLn('>>2>>>>>> *Hn value too long: ' + %trim(pi_ctl)
|
||||
+ '. Missing ":" maybe?' : SP1);
|
||||
endif;
|
||||
j = %int(%subst(ctlValues(1) : 3 :1));
|
||||
hdrs(j).isHdr = *on;
|
||||
hdrs(j).line = pi_line;
|
||||
// Process 2nd and/or 3rd parms
|
||||
select;
|
||||
// If it is page control
|
||||
when (%elem(ctlValues) = 2);
|
||||
if (%trim(ctlValues(2)) = PAGELINE);
|
||||
hdrs(j).isPage = *on;
|
||||
else;
|
||||
// If no, should be spacing
|
||||
if (%trim(ctlValues(2)) in vs.validSpaces);
|
||||
hdrs(j).Ctl = %trim(ctlValues(2));
|
||||
else;
|
||||
PrtLn('>>3>>>>>> Space or page value is not valid: ' + %trim(pi_ctl) : SP1);
|
||||
endif;
|
||||
endif;
|
||||
// Process 2nd and 3rd parms
|
||||
when (%elem(ctlValues) = 3);
|
||||
// second must be paging
|
||||
if (%trim(ctlValues(2)) = PAGELINE);
|
||||
hdrs(j).isPage = *on;
|
||||
else;
|
||||
PrtLn('>>4>>>>>> Paging value is not valid: ' + %trim(pi_ctl) : SP1);
|
||||
endif;
|
||||
// 3rd is spacing
|
||||
if (%trim(ctlValues(3)) in vs.validSpaces);
|
||||
hdrs(j).Ctl = %trim(ctlValues(3));
|
||||
else;
|
||||
PrtLn('>5>>>>>>> Space value is not valid: ' + %trim(pi_ctl) : SP1);
|
||||
endif;
|
||||
endsl;
|
||||
|
||||
other;
|
||||
PrtLn('>>7>>>>> Calling error. Control value not supported: ' + pi_ctl :SP1);
|
||||
endsl;
|
||||
|
||||
endsr;
|
||||
|
||||
// ================================================================
|
||||
// === Print the line =============================================
|
||||
begsr doPrint;
|
||||
select;
|
||||
// Need new page
|
||||
when (newPage);
|
||||
exsr doHeaders;
|
||||
// If heading lines were printed, then print the line with
|
||||
// the specified spacing, else skip to a new page and print.
|
||||
If (gotHeaders);
|
||||
PrtLn(pi_Line : wk_Ctl);
|
||||
else;
|
||||
PrtLn(pi_line : TOP);
|
||||
newPage = *off;
|
||||
endif;
|
||||
// Just print the line
|
||||
other;
|
||||
PrtLn(pi_Line : wk_Ctl);
|
||||
endsl;
|
||||
|
||||
// === If overflow, remember for next line ===
|
||||
if (*in99 = *on);
|
||||
newPage = *on;
|
||||
*in99 = *off;
|
||||
endif;
|
||||
|
||||
endsr ;
|
||||
|
||||
// ================================================================
|
||||
// === Print Headers ==============================================
|
||||
begsr doHeaders;
|
||||
if (newPage);
|
||||
// Print the Heading lines and page number.
|
||||
|
||||
// No defined headers is possible.
|
||||
gotHeaders = *off;
|
||||
// Set up character page number
|
||||
pageNumC = 'Page +++';
|
||||
if (pageNum <= 999);
|
||||
pageNumC = 'Page ' + %char(pageNum);
|
||||
endif;
|
||||
// Loop through header definitions, printing those defined
|
||||
for j = 1 to 9;
|
||||
if (hdrs(j).isHdr);
|
||||
gotHeaders = *on;
|
||||
wkLn.line = hdrs(j).line;
|
||||
if (hdrs(j).isPage);
|
||||
%subst(wkLn.line :%len(wkLn.line) - %len(pageNumC) ) = pageNumC;
|
||||
endif;
|
||||
// First header line, and only the first, has to be a skip to top
|
||||
if (headerSkip = *off);
|
||||
PrtLn(wkLn.line : TOP);
|
||||
headerSkip = *on;
|
||||
else;
|
||||
PrtLn(wkLn.line : hdrs(j).Ctl);
|
||||
endif;
|
||||
endif;
|
||||
endfor;
|
||||
|
||||
headerSkip = *off;
|
||||
newPage = *off;
|
||||
pageNum += 1;
|
||||
endif;
|
||||
endsr ;
|
||||
|
||||
end-proc Prt;
|
||||
|
||||
// ==================================================================
|
||||
// === Procedure to print a line ====================================
|
||||
dcl-proc PrtLn;
|
||||
dcl-pi PrtLn;
|
||||
pi_Line char(132) const;
|
||||
pi_Ctl char(10) const;
|
||||
end-pi;
|
||||
dcl-ds line len(133) qualified;
|
||||
end-ds;
|
||||
// FCFC Definitions for printer file
|
||||
dcl-s SK1 char(1) inz('1'); // skip to channel 1
|
||||
dcl-s S1 char(1) inz(' '); // space 1 and print
|
||||
dcl-s S2 char(1) inz('0'); // spacw 2 and print
|
||||
dcl-s S3 char(1) inz('-'); // Space 3 and print
|
||||
dcl-s S0 char(1) inz('+'); // Overprint (space 0)
|
||||
|
||||
dcl-s fcFC char(1);
|
||||
|
||||
select;
|
||||
when (pi_Ctl = SP1 or pi_Ctl = ' ');
|
||||
fcFC = S1;
|
||||
when (pi_Ctl = SP2);
|
||||
fcFC = S2;
|
||||
when (pi_Ctl = SP3);
|
||||
fcFC = S3;
|
||||
when (pi_Ctl = SP0);
|
||||
fcFC = S0;
|
||||
when (pi_Ctl = TOP);
|
||||
fcFC = SK1;
|
||||
other;
|
||||
PrtLn('>>>>>>>> Invalid spacing control: ' + pi_Ctl :SP1);
|
||||
endsl;
|
||||
|
||||
// Write must be from a data structure
|
||||
line = fcFC + pi_Line;
|
||||
write MYPRT line;
|
||||
end-proc PrtLn;
|
||||
33
PRT_CL/PRTLN.CMD
Normal file
33
PRT_CL/PRTLN.CMD
Normal file
@ -0,0 +1,33 @@
|
||||
PRTLN: CMD PROMPT('Print a line ')
|
||||
/* ================================================================*/
|
||||
/* PRTLNC is the command processing program */
|
||||
/* CRTCMD CMD(PRTLN) PGM(*LIBL/PRTLNC) SRCFILE(PRT_CL) */
|
||||
/* VLDCKR(*LIBL/PRTLNCV) */
|
||||
/* ALLOW(*IPGM *BPGM *IMOD *IPGM *INTERACT) */
|
||||
/* HLPPNLGRP(PRTLNP) HLPID(*CMD) */
|
||||
/* ================================================================*/
|
||||
PARM KWD(LINE) TYPE(*CHAR) LEN(132) MIN(0) +
|
||||
EXPR(*YES) PROMPT('Line text')
|
||||
|
||||
PARM KWD(SPACE) TYPE(*CHAR) LEN(2) RSTD(*YES) +
|
||||
DFT(S1) VALUES('S1' 'S2' 'S3' 'S0') +
|
||||
MIN(0) PROMPT('Line spacing')
|
||||
|
||||
PARM KWD(HEADING) TYPE(*CHAR) LEN(1) RSTD(*YES) +
|
||||
DFT(N) VALUES(Y N) PROMPT('Defining +
|
||||
heading line?')
|
||||
|
||||
PARM KWD(HEAD) TYPE(HDEF) PMTCTL(HEAD) +
|
||||
PROMPT('Heading definitions')
|
||||
PARM KWD(CONTROL) TYPE(*CHAR) LEN(10) RSTD(*YES) +
|
||||
VALUES(*NEWPAGE *CLOSE) PMTCTL(CTRL) +
|
||||
PROMPT('Non-printing control functions')
|
||||
|
||||
HDEF: ELEM TYPE(*CHAR) LEN(1) DFT(1) RANGE(1 9) MIN(0) +
|
||||
PROMPT('Header line number')
|
||||
ELEM TYPE(*CHAR) LEN(1) RSTD(*YES) DFT(N) +
|
||||
VALUES(N Y) PROMPT('Include page number')
|
||||
|
||||
HEAD: PMTCTL CTL(HEADING) COND((*EQ 'Y'))
|
||||
CTRL: PMTCTL CTL(LINE) COND((*EQ ' '))
|
||||
|
||||
47
PRT_CL/PRTLNC.CLLE
Normal file
47
PRT_CL/PRTLNC.CLLE
Normal file
@ -0,0 +1,47 @@
|
||||
PRTLNC: PGM PARM(&P_LINE &P_SPACE &P_DEFHEAD &P_HEAD +
|
||||
&P_CONTROL)
|
||||
/* ================================================================*/
|
||||
/* CPP for the PRTLN command. */
|
||||
/* Maps the command parameters to what the PRT program expects */
|
||||
/* then calls PRT to print or process the line. */
|
||||
/* ================================================================*/
|
||||
/* For RPG convenient usage, PRT has only two parms. PRTLN cmd */
|
||||
/* has more parms for more meaningful usage. */
|
||||
/* ================================================================*/
|
||||
|
||||
DCL (&P_LINE) TYPE(*CHAR) LEN(132) /* Line text */
|
||||
DCL (&P_SPACE) TYPE(*CHAR) LEN(2) /* Spacing */
|
||||
DCL (&P_DEFHEAD) TYPE(*CHAR) LEN(1) /* Defining Heading? */
|
||||
DCL (&P_HEAD) TYPE(*CHAR) LEN(4) /* Heading definition */
|
||||
DCL (&P_CONTROL) TYPE(*CHAR) LEN(10) /* Control field */
|
||||
|
||||
DCL (&PRT_PARM2) TYPE(*CHAR) LEN(10) /* Parm 2 for PRT pgm */
|
||||
DCL (&HLINE_NUM) TYPE(*CHAR) LEN(1)
|
||||
DCL (&HEADPAGE) TYPE(*CHAR) LEN(1)
|
||||
|
||||
/* PHEAD is a list of 2 elements. Just ignore the 2 byte length. */
|
||||
CHGVAR (&HLINE_NUM) VALUE(%SST(&P_HEAD 3 1))
|
||||
CHGVAR (&HEADPAGE) VALUE(%SST(&P_HEAD 4 1))
|
||||
|
||||
/* If defining headings */
|
||||
IF (&P_DEFHEAD = 'Y') DO
|
||||
/* Building either "*Hn:*P:Sn" or "*Hn:Sn" */
|
||||
CHGVAR VAR(&PRT_PARM2) VALUE('*H' *TCAT &HLINE_NUM)
|
||||
IF (&HEADPAGE = 'Y') DO
|
||||
CHGVAR VAR(&PRT_PARM2) VALUE(&PRT_PARM2 *TCAT ':*P')
|
||||
ENDDO
|
||||
CHGVAR VAR(&PRT_PARM2) VALUE(&PRT_PARM2 *TCAT ':' *TCAT &P_SPACE)
|
||||
/* Define the header and return */
|
||||
CALL PGM(PRT) PARM(&P_LINE &PRT_PARM2)
|
||||
RETURN
|
||||
ENDDO
|
||||
/* Handle other special control fields & return: *CLOSE & *NEWPAGE */
|
||||
IF (&P_CONTROL *NE ' ') DO
|
||||
CALL PGM(PRT) PARM(&P_LINE &P_CONTROL)
|
||||
RETURN
|
||||
ENDDO
|
||||
/* Else print the line and return */
|
||||
CHGVAR (&P_CONTROL) (&P_SPACE)
|
||||
CALL PGM(PRT) PARM(&P_LINE &P_CONTROL)
|
||||
RETURN
|
||||
ENDPGM
|
||||
41
PRT_CL/PRTLNCV.CLLE
Normal file
41
PRT_CL/PRTLNCV.CLLE
Normal file
@ -0,0 +1,41 @@
|
||||
PRTLNC: PGM PARM(&P_LINE &P_SPACE &P_DEFHEAD &P_HEAD +
|
||||
&P_CONTROL)
|
||||
/* ================================================================*/
|
||||
/* VCP for the PRTLN command. */
|
||||
/* Checks consistency of paremeters: */
|
||||
/* If doing a CONTROL function, LINE must be blank. */
|
||||
/* If doing a CONTROL function, you can't be defining headings. */
|
||||
/* ================================================================*/
|
||||
|
||||
DCL (&P_LINE) TYPE(*CHAR) LEN(132) /* Line text */
|
||||
DCL (&P_SPACE) TYPE(*CHAR) LEN(2) /* Spacing */
|
||||
DCL (&P_DEFHEAD) TYPE(*CHAR) LEN(1) /* Defining Heading? */
|
||||
DCL (&P_HEAD) TYPE(*CHAR) LEN(4) /* Heading definition */
|
||||
DCL (&P_CONTROL) TYPE(*CHAR) LEN(10) /* Control field */
|
||||
|
||||
DCL (&ERR_MSG) TYPE(*CHAR) LEN(200)
|
||||
|
||||
IF (&P_CONTROL *NE ' ') DO
|
||||
SELECT
|
||||
WHEN (&P_LINE *NE ' ') DO
|
||||
CHGVAR &ERR_MSG +
|
||||
('If "CONTROL" is specified "LINE" should be blank')
|
||||
GOTO SEND_ERR
|
||||
ENDDO
|
||||
WHEN (&P_DEFHEAD = 'Y') DO
|
||||
CHGVAR &ERR_MSG +
|
||||
('If "CONTROL" is specified "HEADING" should be "N"')
|
||||
GOTO SEND_ERR
|
||||
ENDDO
|
||||
ENDSELECT
|
||||
ENDDO
|
||||
|
||||
RETURN /* All Consistent */
|
||||
|
||||
/* Send the error back to the command */
|
||||
/* Note the definition of CPD0006 is a bit funky. 1234 below is */
|
||||
/* needed but is ignored when the message is sent. */
|
||||
SEND_ERR: SNDPGMMSG MSGID(CPD0006) MSGF(QCPFMSG) +
|
||||
MSGDTA('1234' *CAT &ERR_MSG) MSGTYPE(*DIAG)
|
||||
SNDPGMMSG MSGID(CPF0002) MSGF(QCPFMSG) MSGTYPE(*ESCAPE)
|
||||
ENDPGM
|
||||
221
PRT_CL/PRTLNP.PNLGRP
Normal file
221
PRT_CL/PRTLNP.PNLGRP
Normal file
@ -0,0 +1,221 @@
|
||||
:pnlgrp.
|
||||
.************************************************************************
|
||||
.* Help for command PRTLN
|
||||
.************************************************************************
|
||||
:help name='PRTLN'.
|
||||
Print a line - Help
|
||||
:p.The Print a line (PRTLN) command provides report printing capabilities
|
||||
in a CLP or CLLE program. Heading lines may be defined and print when
|
||||
overflow occurs. A page number can also be printed in the headings.
|
||||
:ehelp.
|
||||
.*******************************************
|
||||
.* Help for parameter LINE
|
||||
.*******************************************
|
||||
:help name='PRTLN/LINE'.
|
||||
Line text (LINE) - Help
|
||||
:xh3.Line text (LINE)
|
||||
:p.Specifies the text to print on this line, or if defining a header line,
|
||||
specifies the text of that header line.
|
||||
.* Describe the function provided by the parameter.
|
||||
:parml.
|
||||
:pt.:pv.character-value:epv.
|
||||
:pd.
|
||||
May be blank.
|
||||
.* Describe the function provided by the user-defined parameter value.
|
||||
:eparml.
|
||||
:ehelp.
|
||||
.*******************************************
|
||||
.* Help for parameter SPACE
|
||||
.*******************************************
|
||||
:help name='PRTLN/SPACE'.
|
||||
Line spacing (SPACE) - Help
|
||||
:xh3.Line spacing (SPACE)
|
||||
:p.Specifies the spacing of the printed line or the header line.
|
||||
:parml.
|
||||
:pt.:pk def.S1:epk.
|
||||
:pd.
|
||||
Space 1 line and print.
|
||||
:pt.:pk.S2:epk.
|
||||
:pd.
|
||||
Space 2 lines and print.
|
||||
:pt.:pk.S3:epk.
|
||||
:pd.
|
||||
Space 3 lines and print.
|
||||
:pt.:pk.S0:epk.
|
||||
:pd.
|
||||
Overprint previous line.
|
||||
:eparml.
|
||||
:ehelp.
|
||||
.*******************************************
|
||||
.* Help for parameter HEADING
|
||||
.*******************************************
|
||||
:help name='PRTLN/HEADING'.
|
||||
Defining heading line? (HEADING) - Help
|
||||
:xh3.Defining heading line? (HEADING)
|
||||
:p.Specifies if this execution is defining a heading line. No
|
||||
printing occurs.
|
||||
:parml.
|
||||
:pt.:pk.Y:epk.
|
||||
:pd.
|
||||
This is a header line definition. Additional fields open up
|
||||
to speicify which header line and if it should include a page number.
|
||||
:pt.:pk def.N:epk.
|
||||
:pd.
|
||||
This is not defining a heading.
|
||||
:eparml.
|
||||
:ehelp.
|
||||
.*******************************************
|
||||
.* Help for parameter HEAD
|
||||
.*******************************************
|
||||
:help name='PRTLN/HEAD'.
|
||||
Heading definitions (HEAD) - Help
|
||||
:xh3.Heading definitions (HEAD)
|
||||
:p.:hp2.Element 1: Header line number:ehp2.
|
||||
:parml.
|
||||
:pt.:pv.1-9:epv.
|
||||
:pd.
|
||||
Which heading line is being defined.
|
||||
:ul.
|
||||
:li.
|
||||
Heading lines can be defined in any sequence. For example, you can define
|
||||
heading 9 then define heading 1, then define heading 3, etc.
|
||||
:li.
|
||||
Heading lines always print in ordinal order, not the order in which
|
||||
they were defined.
|
||||
:li.
|
||||
A heading line that is not defined does not print.
|
||||
:li.
|
||||
A heading line may be defined with blank text and will print a blank
|
||||
heading line.
|
||||
:li.
|
||||
Once defined, a heading line cannot be undefined.
|
||||
:li.
|
||||
A heading line may be redefined at any time and will take effect at the next
|
||||
page break. Normally you would force a page break after redefining a heading line.
|
||||
:eul.
|
||||
:eparml.
|
||||
:p.:hp2.Element 2: Include page number:ehp2.
|
||||
:parml.
|
||||
:pt.:pk def.N:epk.
|
||||
:pd.
|
||||
Do not print a page number on this header line.
|
||||
:pt.:pk.Y:epk.
|
||||
:pd.
|
||||
Print a page number in the rightmost 8 positions of this header line.
|
||||
:eparml.
|
||||
:ehelp.
|
||||
.*******************************************
|
||||
.* Help for parameter CONTROL
|
||||
.*******************************************
|
||||
:help name='PRTLN/CONTROL'.
|
||||
Non-printing control functions (CONTROL) - Help
|
||||
:xh3.Non-printing control functions (CONTROL)
|
||||
:p.Operations which are not related to printing a line or defining headings.
|
||||
:parml.
|
||||
:pt.:pk.*NEWPAGE:epk.
|
||||
:pd.
|
||||
Force a new page when the next line prints. (Page overflow and header printing is
|
||||
handled automatically, so you need to use this only if you have
|
||||
break handing logic in your program.)
|
||||
:pt.:pk.*CLOSE:epk.
|
||||
:pd.
|
||||
Close the print file. Normally you do this at the end of the program.
|
||||
:eparml.
|
||||
:ehelp.
|
||||
.**************************************************
|
||||
.* Examples for PRTLN
|
||||
.**************************************************
|
||||
:help name='PRTLN/COMMAND/EXAMPLES'.
|
||||
Examples for PRTLN - Help
|
||||
:xh3.Examples for PRTLN
|
||||
:p.:hp2.Example 1: Simple Command Example:ehp2.
|
||||
:xmp.
|
||||
/* Demo a mimimal report - no headings */
|
||||
PGM
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
DCL VAR(&LC) TYPE(*DEC) LEN(5 0) VALUE(1)
|
||||
/* Loop thru the data and print */
|
||||
DOWHILE COND(&LC *LT 70)
|
||||
CHGVAR VAR(&LINE) +
|
||||
VALUE('Loop control =' *BCAT %CHAR(&LC))
|
||||
PRTLN LINE(&LINE)
|
||||
CHGVAR VAR(&LC) VALUE(&LC + 1)
|
||||
ENDDO
|
||||
PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
:exmp.
|
||||
.*
|
||||
:p.:hp2.Example 2: More Complex Command Example:ehp2.
|
||||
:xmp.
|
||||
/* List files & members with record count and description. */
|
||||
/* Has heading lines, an underscored heading & page number. */
|
||||
PGM
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
/* Define data columns in &LINE */
|
||||
DCL (&LIB) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE)
|
||||
DCL (&FILE) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 12)
|
||||
DCL (&MBR) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 33)
|
||||
DCL (&RCDS) (*CHAR) STG(*DEFINED) LEN(8) DEFVAR(&LINE 44)
|
||||
DCL (&TEXT) (*CHAR) STG(*DEFINED) LEN(50) DEFVAR(&LINE 53)
|
||||
DCL (&UNDER) (*CHAR) LEN(60) +
|
||||
VALUe('____________________________________________________________')
|
||||
/* Create some data */
|
||||
DCLF FILE(QAFDMBRL)
|
||||
DSPFD FILE(*CURLIB/Q*) TYPE(*MBRLIST) +
|
||||
OUTPUT(*OUTFILE) FILEATR(*PF) +
|
||||
OUTFILE(QTEMP/MBRLIST)
|
||||
OVRDBF FILE(QAFDMBRL) TOFILE(QTEMP/MBRLIST)
|
||||
|
||||
/* Define heading lines. Second heading is underscored */
|
||||
PRTLN LINE('Member List') HEADING(Y) HEAD(1 Y)
|
||||
|
||||
CHGVAR (&LIB) ('Library')
|
||||
CHGVAR (&FILE) ('File')
|
||||
CHGVAR (&MBR) ('Member')
|
||||
CHGVAR (&RCDS) ('#Records')
|
||||
CHGVAR (&TEXT) ('Description')
|
||||
PRTLN LINE(&LINE) HEADING(Y) HEAD(2)
|
||||
|
||||
CHGVAR (&LIB) (&UNDER)
|
||||
CHGVAR (&FILE) (&UNDER)
|
||||
CHGVAR (&MBR) (&UNDER)
|
||||
CHGVAR (&RCDS) (&UNDER)
|
||||
CHGVAR (&TEXT) (&UNDER)
|
||||
PRTLN LINE(&LINE) SPACE(S0) HEADING(Y) HEAD(3)
|
||||
|
||||
/* Loop thru the data and print */
|
||||
LOOP:
|
||||
RCVF RCDFMT(QWHFDML)
|
||||
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EOF))
|
||||
CHGVAR (&LIB) (&MLLIB)
|
||||
CHGVAR (&FILE) (&MLFILE)
|
||||
CHGVAR (&MBR) (&MLNAME)
|
||||
CHGVAR (&RCDS) (%CHAR(&MLNRCD))
|
||||
CHGVAR (&TEXT) (&MLMTXT)
|
||||
PRTLN LINE(&LINE)
|
||||
GOTO CMDLBL(LOOP)
|
||||
EOF: PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
:exmp.
|
||||
:ehelp.
|
||||
.**************************************************
|
||||
.*
|
||||
.* Error messages for PRTLN
|
||||
.*
|
||||
.**************************************************
|
||||
:help name='PRTLN/ERROR/MESSAGES'.
|
||||
&msg(CPX0005,QCPFMSG). PRTLN - Help
|
||||
:xh3.&msg(CPX0005,QCPFMSG). PRTLN
|
||||
:p.:hp3.*ESCAPE &msg(CPX0006,QCPFMSG).:ehp3.
|
||||
.************************************************************************
|
||||
.* List the *ESCAPE, *STATUS, and *NOTIFY messages signalled from the command.
|
||||
.* The following are generic messages defined in message file QCPFMSG.
|
||||
.* Modify this list to match the list of error messages for the command.
|
||||
.************************************************************************
|
||||
:DL COMPACT.
|
||||
.*:DT.CPF9801
|
||||
.*:DD.&MSG(CPF9801,QCPFMSG,*LIBL,nosub).
|
||||
:EDL.
|
||||
:ehelp.
|
||||
:epnlgrp.
|
||||
|
||||
221
PRT_CL/PRT_T.RPGLE
Normal file
221
PRT_CL/PRT_T.RPGLE
Normal file
@ -0,0 +1,221 @@
|
||||
**free
|
||||
// === Test program to exercise the PRT program =====================
|
||||
ctl-opt option(*srcstmt: *nodebugio) actgrp(*new) main(Main);
|
||||
/COPY copy_mbrs,prt_p
|
||||
dcl-proc Main;
|
||||
dcl-pi Main;
|
||||
// pi_head char(132);
|
||||
end-pi;
|
||||
dcl-s myLine char(132);
|
||||
dcl-s j int(10);
|
||||
|
||||
|
||||
// === Test without a heading
|
||||
for j = 1 to 121;
|
||||
myLine = %char(j);
|
||||
%subst(myLine :20) = %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// === Test with a 4 line heading
|
||||
PRT('*** Test with 4 heading lines ***' : '*H1');
|
||||
PRT(' Indented header line 2':'*H2');
|
||||
PRT('Non-Indented header line 3 with page # & 2 spaces':'*H3:*P:S2');
|
||||
for j = 1 to 120;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ';
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test with two headings
|
||||
PRT('<< Test with two header lines >>' : '*H1');
|
||||
PRT('++ Here is a second header(As H9!) with page # ++' : '*H9:*P');
|
||||
for j = 1 to 60;
|
||||
myLine = '<<< ' + %char(j);
|
||||
%subst(myLine :130 :3) = '>>>';
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// === Test with a single heading
|
||||
PRT('One header line: This is quite a long single heading line w/ page #' : '*H1:*P');
|
||||
for j = 1 to 190;
|
||||
myLine = %char(j);
|
||||
%subst(myLine :20) = %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// === Test with a 4 line heading, 2nd blank; 3rd under scored, with page num
|
||||
PRT('Test with 2nd blank, 3rd line underlined with page #, 4th blank' : '*H1');
|
||||
PRT('ABCDEFGH ZXY ' : '*H2:s2');
|
||||
PRT('________ ___ ' : '*H5:*p:s0');
|
||||
PRT(' ':'*h8');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%time());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test with a 3 line heading, line 3 blank
|
||||
PRT('Test with line 3 blank' : '*H1');
|
||||
PRT('Blank header line should follow. Page # on this line. ' : '*H2:*P');
|
||||
PRT(' ' : '*H3');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE
|
||||
PRT('Testing a new page at line 80' : '*H1:*P');
|
||||
PRT('Section starting at line 1' : '*H2');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=80);
|
||||
PRT(' ':'*NEWPAGE');
|
||||
PRT('New Section - Line 80 is the start' :'*H2');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE - Break at overflow - 2
|
||||
PRT('Testing a new page at line 52 (overflow -2)' : '*H1:*P');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=52);
|
||||
PRT('*********** ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE - Break at overflow - 1
|
||||
PRT('Testing a new page at line 53 (overflow -1)' : '*H1:*P');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=53);
|
||||
PRT(' ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE - Break at overflow
|
||||
PRT('Testing a new page at line 54 (overflow)' : '*H1:*P');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=54);
|
||||
PRT(' ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE - Break at overflow + 1
|
||||
PRT('Testing a new page at line 55 (overflow +1)' : '*H1:*P');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=55);
|
||||
PRT(' ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test a *NEWPAGE - Break at overflow + 2
|
||||
PRT('Testing a new page at line 56 (overflow +2)' : '*H1:*P');
|
||||
for j = 1 to 150;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
if (j=56);
|
||||
PRT(' ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Test without a heading, double spaced
|
||||
for j = 1 to 121;
|
||||
myLine = %char(j);
|
||||
%subst(myLine :20) = %char(%timestamp());
|
||||
PRT(myLine : 'S2');
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// === Test with a heading, double spaced
|
||||
PRT('Double spaced test with heading and page #':'*H1:*P');
|
||||
for j = 1 to 121;
|
||||
myLine = %char(j);
|
||||
%subst(myLine :20) = %char(%timestamp());
|
||||
PRT(myLine : 'S2');
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// === Test with a heading, triple spaced
|
||||
PRT('Triple spaced test with heading and page #':'*H1:*P');
|
||||
PRT('Header line 2':'*H2');
|
||||
for j = 1 to 121;
|
||||
myLine = %char(j);
|
||||
%subst(myLine :20) = %char(%timestamp());
|
||||
if (j = 75);
|
||||
PRT('>>>>>> *** New header line 2':'*H2');
|
||||
PRT(' ':'*NEWPAGE');
|
||||
endif;
|
||||
PRT(myLine : 'S3');
|
||||
endfor;
|
||||
PRT(' ' : '*CLOSE');
|
||||
|
||||
// ==== Testing errors ============================================
|
||||
// === Bad spacing contol value om H2, paging not specified
|
||||
PRT('!-!-! Bad SP value specified in header 2, paging not specified !-!-!' : '*H1');
|
||||
PRT('Bad SP value specified in header 2 ' : '*H2:s7');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Bad spacing contol value om H2, paging specified
|
||||
PRT('!-!-! Bad spacing contol value on H2, paging specified !-!-!' : '*H1');
|
||||
PRT('Bad SP value specified in header 2 specified ' : '*H2:*P:s7');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Bad paging control value on H2
|
||||
PRT('!-!-! Bad paging control value on H2 !-!-!' : '*H1');
|
||||
PRT('Bad paging value specified in header 2 ' : '*H2:*xX');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
// === Missing : after *Hn
|
||||
PRT('!-!-! Bad paging control value on H2 !-!-!' : '*H1');
|
||||
PRT('*** Missing : in H2 *** ' : '*H2*P');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + ' ABCDEFGHIHJKLMNOPQRSTUVWXYZ ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
PRT('++++ Testing Bad Contol values ++++' : '*H1');
|
||||
PRT('Bad contol after line 30' : '*H2');
|
||||
for j = 1 to 70;
|
||||
myLine = %char(j) + '-ABCDEFGHIHJK- ' + %char(%timestamp());
|
||||
PRT(myLine);
|
||||
if (j=30);
|
||||
PRT(' ':'*Bad');
|
||||
endif;
|
||||
endfor;
|
||||
PRT(' ' :'*CLOSE');
|
||||
|
||||
*inlr = *on;
|
||||
|
||||
|
||||
end-proc;
|
||||
189
PRT_CL/README.MD
Normal file
189
PRT_CL/README.MD
Normal file
@ -0,0 +1,189 @@
|
||||
# Printing from a CL program (The PRTLN command)
|
||||
# (Under Construction)
|
||||
Generating a report from an IBM i CL program isn’t straight forward, because in CL there is no direct way to write to a spool file. Here I provide the CL PRTLN command, which allows simple, direct printing from a CL or CLLE program, including page control and headings.
|
||||
|
||||
(Note: I'm not suggesting you should do your payroll checks or month-end general ledger from CL--use RPG for that. But sometimes it is just convenient to print from CL without bothering with extra objects, like Query/400, or STRQMQRY or an RPG program.)
|
||||
|
||||
## The PRTLN Command
|
||||
|
||||
The PRTLN command allows you to:
|
||||
|
||||
- Print a line to a spool file with single, double, or triple spacing, or overprinting.
|
||||
|
||||
- Define zero to nine heading lines that print on overflow.
|
||||
|
||||
- Print a page number in a heading line.
|
||||
|
||||
- Force a new page if you want break handlling.
|
||||
|
||||
Fully prompted, the PRTLN command looks like this:
|
||||
|
||||

|
||||
|
||||
### Line text
|
||||
|
||||
Specifies the text to print on this line, or if defining a header line, specifies the text of that header line.
|
||||
|
||||
### Line spacing
|
||||
|
||||
Specifies the spacing of the printed line or the header line. (S1: Space 1 line and print; S2: Space 2 lines and print; S3: Space 3 lines and print; S0: Overprint previous line.)
|
||||
|
||||
### Defining heading line?
|
||||
|
||||
Y means this is a header line definition.
|
||||
|
||||
### Header line number
|
||||
|
||||
Specifies which heading line is being defined, 1 through 9.
|
||||
|
||||
- Heading lines can be defined in any order. For example, you can define heading 9, then define heading 1, then define heading 3, etc.
|
||||
|
||||
- Heading lines always print in ordinal order, not the order in which they were defined.
|
||||
|
||||
- A heading line that is not defined does not print.
|
||||
|
||||
- A heading line may be defined with blank text and will print a blank heading line.
|
||||
|
||||
- Once defined, a heading line cannot be undefined.
|
||||
|
||||
- A heading line may be redefined at any time and will take effect at the next page break. Normally you would force a page break after redefining a heading line.
|
||||
|
||||
### Include page number
|
||||
Y to print a page number in the rightmost 8 positions of this header line.
|
||||
|
||||
### Non-printing control functions
|
||||
|
||||
These are operations which are not related to printing a line or defining headings.
|
||||
|
||||
- *NEWPAGE forces a new page when the next line prints. (Page overflow and header printing is handled automatically, so you need to use this only if you have break handing logic in your program.)
|
||||
|
||||
- *CLOSE closes the print file. Normally you do this at the end of the report, but you can use it to create a new spool file..
|
||||
|
||||
## Formatting the Print Line
|
||||
|
||||
In [Printing Techniques in RPG/**FREE](https://github.com/SJLennon/IBM-i-RPG-Free-CLP-Code/tree/master/Printing) I showed how easily RPG can format print line columns using a data structure. CL doesn't have data structures, but they can be simulated using the STG(*DEFINED) and DEFVAR parameters of the DCL command. This is much simpler than building the print line through concatenation.
|
||||
|
||||
As an example, you can define a print line with 3 columns like this:
|
||||
```
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
DCL (&LIB) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE)
|
||||
DCL (&FILE) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 12)
|
||||
DCL (&MBR) (*CHAR) STG(*DEFINED) LEN(10) DEFVAR(&LINE 33)
|
||||
|
||||
```
|
||||
|
||||
Then you just need to populate the line using the column names.
|
||||
|
||||
## PRTLN Example
|
||||
|
||||
Here's a simple program to demonstrate the concepts.
|
||||
|
||||
```PGM
|
||||
DCL (&LC) (*DEC) LEN(5 0) VALUE(1)
|
||||
DCL (&UNDER) (*CHAR) LEN(20) VALUE('____________________')
|
||||
/* Define print line and columns */
|
||||
DCL (&LINE) (*CHAR) LEN(132)
|
||||
DCL (&COUNT) (*CHAR) STG(*DEFINED) LEN(5) DEFVAR(&LINE 5)
|
||||
DCL (&STAMP) (*CHAR) STG(*DEFINED) LEN(20) DEFVAR(&LINE 20)
|
||||
/* Define heading 1 */
|
||||
PRTLN LINE('Really Simple Report') HEADING(Y) HEAD(1 Y)
|
||||
/* Define heading 2 */
|
||||
CHGVAR &COUNT 'COUNT'
|
||||
CHGVAR &STAMP 'TIMESTAMP'
|
||||
PRTLN LINE(&LINE) HEADING(Y) HEAD(2)
|
||||
/* Define hading 3 Underscoring heading 2 */
|
||||
CHGVAR &COUNT &UNDER
|
||||
CHGVAR &STAMP &UNDER
|
||||
PRTLN LINE(&LINE) SPACE(S0) HEADING(Y) HEAD(3)
|
||||
/* Print a report showing count and timestamp */
|
||||
DOWHILE COND(&LC *LT 70)
|
||||
CHGVAR &COUNT %CHAR(&LC)
|
||||
RTVSYSVAL SYSVAL(QDATETIME) RTNVAR(&STAMP)
|
||||
PRTLN LINE(&LINE)
|
||||
CHGVAR VAR(&LC) VALUE(&LC + 1)
|
||||
ENDDO
|
||||
PRTLN CONTROL(*CLOSE)
|
||||
ENDPGM
|
||||
```
|
||||
|
||||
It produces a two page report like this:
|
||||
|
||||

|
||||

|
||||
|
||||
## The Code
|
||||
|
||||
### PRTLN.CMD
|
||||
|
||||
This is the source for the PRTLN command.
|
||||
|
||||
### PRTLNCV.CLLE
|
||||
|
||||
This is the VCP (Validity Checking Program) for the PRTLN command. A VCP is optional and can be used to do parameter validity checking that is difficult or impossible in standard command definition source. When used, it receives the same parameters as the CCP and can pass back error messages to the command.
|
||||
|
||||
It is used here to ensure that non-printing CONTOL functions don't also try to print a line or define a heading.
|
||||
|
||||
### PRTLNC.CLLE
|
||||
|
||||
This is the CPP (Command Processing Program). A CPP is called when there are no errors in the command.
|
||||
|
||||
Here it reformats the parameter from the command to pass to the PRT program.
|
||||
|
||||
### PRTLNP.PNLGRP
|
||||
This is the UIM help text for the PRTLN command. I created a skeleton using the IBM GENCMDDOC command, then edited it with the [Code for IBM i](https://github.com/halcyon-tech/vscode-ibmi) extension to VS Code.
|
||||
|
||||
|
||||
### PRT.RPGLE
|
||||
This is a RPG/FREE program that does the heavy lifting. It saves heading lines in an array, takes care of opening and closing the print file and prints headings on overflow.
|
||||
|
||||
It writes to the MYPRINT printer file which is defined like this:
|
||||
```
|
||||
CRTPRTF FILE(LENNONS1/MYPRT) DEVTYPE(*SCS)
|
||||
PAGESIZE(66 133) LPI(6) CPI(10)
|
||||
OVRFLW(60) CTLCHAR(*FCFC) CHLVAL((1 (6)))
|
||||
FONT(*CPI)
|
||||
```
|
||||
Adjust the overflow or top of form line to suit your needs.
|
||||
|
||||
MYPRT.CLLE is a simple CL program to create MYPRT.
|
||||
|
||||
### DEMO_CL1.CLLE, DEMO2_CL2.CLP and DEMO_CL3.CLLE
|
||||
|
||||
Demonstartion programs of PRTLN in use.
|
||||
|
||||
### DEMO_RPG1.SQLRPGLE
|
||||
|
||||
A demonstration RPG/**FREE program calling the PRT program directly to print a a file layout. It produces a report like this:
|
||||
|
||||

|
||||
|
||||
### More on PRT.RPGLE
|
||||
|
||||
I also wanted PRT to be easily called from RPG as well as from the PRTLN command. While RPG parameters can be omitted or optional, they are still positional and not quite a flexible as defining and defaulting parameters in a command. So I opted for just two parameters, the second being optional.
|
||||
|
||||
Parm 1 is the line text, either to print or to define a heading.
|
||||
|
||||
Parm 2 is a multipart control parameter that qualifies Parm 1.
|
||||
- If blank or omitted. the line text in Parm 1 is printed with single spacing.
|
||||
- Spacing Control when printing Parm 1
|
||||
- __S1__ Space one line and print. (Omitted or blank is the same as S1.
|
||||
- __S2__ Space two lines and print.
|
||||
- __S3__ Space three lines and print.
|
||||
- __S0__ Overprint current line.
|
||||
- Defining - no lines are printed with this call.
|
||||
- __*Hn__ Define heading line "n", where n is 1 to 9. Parm 1 can be all blanks to print a blank heading line.
|
||||
- __*Hn:Sx__ Define heading line "n", where n is 1 to 9 and "x" is the number of lines to space, where
|
||||
x is 0 to 3. S0 will overprint prior line.
|
||||
- __*Hn:*P:Sx__ Page number will be printed at the end of this header line.
|
||||
|
||||
- Non Printing functions -
|
||||
- __*CLOSE__ Close the print file. Must be done at the end of the report. Parm 1 is ignored.
|
||||
- __*NEWPAGE__ Next line will print on a new page. Parm 1 is ignored.
|
||||
|
||||
Parm 2 values are separated by a "__:__" as in RPG. I used the new %SPLIT BIF to take apart Parm2 and put it into a variable length autosized array.
|
||||
```
|
||||
dcl-s ctlValues varchar(4) dim(*auto : 3);
|
||||
%elem(ctlValues) = 0;
|
||||
ctlValues = %split(wk_Ctl :':');
|
||||
```
|
||||
It is very easy to split up parms this way. You do need to be aware that and leading and trailing blanks are included in the array elements and you need to %TRIM them.
|
||||
BIN
PRT_CL/images/DemoRpt_1.png
Normal file
BIN
PRT_CL/images/DemoRpt_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
PRT_CL/images/DemoRpt_2.png
Normal file
BIN
PRT_CL/images/DemoRpt_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
PRT_CL/images/PRTLN_command.png
Normal file
BIN
PRT_CL/images/PRTLN_command.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
BIN
PRT_CL/images/PRT_Demo_Rept.png
Normal file
BIN
PRT_CL/images/PRT_Demo_Rept.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@ -1,9 +1,8 @@
|
||||
# Printing Techniques, from RPG and CL.
|
||||
# (Under construction)
|
||||
# Printing Techniques in RPG/**FREE
|
||||
## Printing without O-Specs or Externally Defined Printer Files
|
||||
IBM has made just about everything in free format RPG truly free format. Except O-specs. Instead of adding free format support for O-specs, IBM expects you to use a separately externally defined printer file. This can can do everything O-specs can, but is an extra object.
|
||||
|
||||
But you can print without needing an externally defined printer file.
|
||||
But you can easily print without needing an externally defined printer file. Following is an explanation and two demonstration programs.
|
||||
|
||||
It turns out to be easy in free form RPG, writing from a data structure, with code like this:
|
||||
```
|
||||
|
||||
@ -46,6 +46,10 @@ Commands, with CLP and RPG programs, calling IBM i APis.
|
||||
|
||||
Commands, CLLE, SQLRPGLE using SQL access to APIs.
|
||||
|
||||
## Printing Techniques in RPG/**FREE
|
||||
|
||||
Printing without O-Specs or Externally Defined Printer Files
|
||||
|
||||
## GRP_JOB
|
||||
|
||||
Sets up group jobs suitable for an IBM i developer.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user