APPENDIX J Dynamically Changing Report OPTIONs


Question:

How do you handle changing the report OUTPUT parameters at runtime (PAGE LENGTH, TOP MARGIN, BOTTOM MARGIN, etc.)? What I'd like to be able to do is to pass it a page length/width into a subroutine and then be able to calculate a reasonable PAGE LENGTH, and MARGINs.

Answer:

There is not yet any Informix-supported way to dynamically size reports in Informix-4GL. However, there is an alternative solution which is, I believe, in the FTP archives at ftp.iiug.org. It is also reproduced in Appendix J.

I developed the c-code version; Marlin Prowell took what I'd produced, did some detective work and adapted it to work with the p-code runners. The major deficiency of the solution is that you cannot change the top margin on the first page of the report. The attached shell archive contains a manual page as well as the necessary code. Despite the disclaimer at the bottom of the manual page, there is no version of I4GL where the code would break that I know of. That, however, cannot be construed as saying it will definitely always work everywhere -- for example, I have not tested it on any 64-bit machines, and I'd not be surprised to find that the padding in the p-code report structure changed size on 64-bit machines.

Yours,

Jonathan Leffler (johnl@informix.com) #include <disclaimer.h>


:	"@(#)shar.sh	1.8"
#! /bin/sh
#
#	This is a shell archive.
#	Remove everything above this line and run sh on the resulting file.
#	If this archive is complete, you will see this message at the end:
#	"All files extracted"
#
#	Created: Fri Jul 24 11:43:14 GMT 1992 by johnl at Informix Software Ltd.
#	Files archived in this archive:
#	report.man
#	report.c
#	rejig.4gl
#
#--------------------
if [ -f report.man -a "$1" != "-c" ]
then echo shar: report.man already exists
else
echo 'x - report.man (4043 characters)'
sed -e 's/^X//' >report.man <<'SHAR-EOF'
X'\" @(#)report.man	1.4 92/07/24
<'SHAR-EOF'
X'\" @(#)report.man	1.4 92/07/24
X'\" @(#)Manual page: General Library -- Report Configuration
X.ds fC "report.man 1.4 92/07/24
X.TH REPORT 3S "JLSS Informix Tools"
X.SH NAME
Xset_output \(em Dynamically reconfigure dimensions of I4GL report
X.SH SYNOPSIS
X.ft B
Xfunction set_plength(i)
X.br
Xdefine i integer
X.sp
Xfunction set_tmargin(i)
X.br
Xdefine i integer
X.sp
Xfunction set_bmargin(i)
X.br
Xdefine i integer
X.sp
Xfunction set_lmargin(i)
X.br
Xdefine i integer
X.sp
Xfunction set_rmargin(i)
X.br
Xdefine i integer
X.sp
Xfunction set_output()
X.ft R
X.ft B
Xfunction get_plength()
X.sp
Xfunction get_tmargin()
X.sp
Xfunction get_bmargin()
X.sp
Xfunction get_lmargin()
X.sp
Xfunction get_rmargin()
X.ft R
X.SH DESCRIPTION
XThese functions can be used to dynamically reconfigure the layout
Xof the page of an Informix 4GL report.
XThe example program shown below illustrates how they should be used.
X.br
X.ft CW
X.ps 10
X.vs 12
X.nf
X.so rejig.4gl
X.br
X.fi
X.ft
X.ps
X.vs
XThe functions \fIset_plength\fP, \fIset_tmargin\fP,
X\fIset_bmargin\fP, \fIset_lmargin\fP and \fIset_rmargin\fP may be called
Xanywhere inside an I4GL program.
XThe function \fIset_output\fP will have no effect except within a report.
XIt is recommended that \fIset_output\fP be used in the \s-2FIRST
XPAGE HEADER\s0 control block, but it may be used in any control block.
X.P
XAfter the function \fIset_output\fP is called, it invalidates all the settings;
Xto change the settings in a second report, you must call the
Xset-routines again.
XThere is no requirement that all the routines are called (or even any of them).
X.P
XThe functions \fIget_plength\fP, \fIget_tmargin\fP,
X\fIget_bmargin\fP, \fIget_lmargin\fP and \fIget_rmargin\fP may be called
Xanywhere inside an I4GL program.
XIf page dimensions have been set using the set-routines, then the corresponding
Xvalue is returned; otherwise, the corresponding default value is returned.
XAfter \fIset_output\fP has been called, the values returned will be
Xthe default values again; if your report needs to know what its dimensions will
Xbe, it should use the get-routines before calling \fIset_output\fP.
X.SH COMPILATION
XIf compiling for use with compiled Informix-4GL, no special flags are needed.
XIf compiling for use with I4GL-RDS, include -DI4GL_RDS on the command line.
XThe details of building the functions into the \*Cfglgo\*D
Xand \*Cfgldb\*D are given in the corresponding Informix manuals.
XThe necessary definitions for \*cfgiusr.c\*d are:
X.br
X.ft CW
X.ps 10
X.vs 12
X.nf
X#ifdef SET_REPORT
Xextern  int set_output();   /* 0 */
Xextern  int get_rmargin();  /* 0 */
Xextern  int get_tmargin();  /* 0 */
Xextern  int get_bmargin();  /* 0 */
Xextern  int get_lmargin();  /* 0 */
Xextern  int get_plength();  /* 0 */
Xextern  int set_rmargin();  /* 1 */
Xextern  int set_tmargin();  /* 1 */
Xextern  int set_bmargin();  /* 1 */
Xextern  int set_lmargin();  /* 1 */
Xextern  int set_plength();  /* 1 */
X#endif /* SET_REPORT */
X
X#ifdef SET_REPORT
X    { "set_output",     set_output,     0   },
X    { "get_rmargin",    get_rmargin,    0   },
X    { "get_tmargin",    get_tmargin,    0   },
X    { "get_bmargin",    get_bmargin,    0   },
X    { "get_lmargin",    get_lmargin,    0   },
X    { "get_plength",    get_plength,    0   },
X    { "set_rmargin",    set_rmargin,    1   },
X    { "set_tmargin",    set_tmargin,    1   },
X    { "set_bmargin",    set_bmargin,    1   },
X    { "set_lmargin",    set_lmargin,    1   },
X    { "set_plength",    set_plength,    1   },
X#endif /* SET_REPORT */
X.br
X.fi
X.ft
X.ps
X.vs
X.SH WARNINGS
XThis code was designed and tested on an ATT&T 3B2/400 running 
XUNIX System V Release 3.0 using Informix-4GL version 1.10.00C.
XIt has since been tested on a number of other environments (including Versions
X1.10.03, 4.00 and 4.10) on a number of platforms, and has been found to work.
XHowever, the code cannot be guaranteed on any platform or version of I4GL.
XIt is completely unsupported code.
X.SH BUGS
XThe top margin set by \fBset_tmargin\fP does not take effect
Xuntil the second page of output.
X.SH AUTHOR
XJonathan Leffler
X.br
XMarlin Prowell
X.br
XJLSS
X.br
X24th July 1992
SHAR-EOF
chmod 444 report.man
if [ `wc -c <report.man` -ne 4043 ]
then echo shar: report.man unpacked with wrong size
fi
# end of overwriting check
fi
#--------------------
if [ -f report.c -a "$1" != "-c" ]
then echo shar: report.c already exists
else
echo 'x - report.c (7529 characters)'
sed -e 's/^X//' >report.c <<'SHAR-EOF'
X/*
X@(#) File:           report.c
X@(#) Version:        2.1
X@(#) Last changed:   92/07/24
X@(#) Purpose:        I4GL: Reset report output parameters (RDS & C4GL)
X@(#) Author:         J Leffler / M Prowell
X*/
X
X/*TABSTOP=4*/
X
X/*
X** INFORMIX-4GL Dynamic Report Output Parameters Version 2
X** C4GL code (and interface) by J Leffler.
X** RDS interface by M Prowell.
X**
X** Compilation: 
X** C4GL: cc -c report.c
X** RDS:  cc -c -DI4GL_RDS report.c
X*/
X
X/*
X** Addendum to Marlin's comments.
X** -- tested on SUNOS 4.1.1 and I4GL-RDS 4.10.UC1 and it seems to work
X**    correctly, but it is still unsupported code.
X*/
X
X/*
X** From: uunet!nyssa.wa7ipx.ampr.org!mbp (Marlin Prowell)
X** Subject: Changing report output params in RDS (code enclosed)
X** Date: 29 Apr 92 04:30:46 GMT
X** To: informix-list@rmy.emory.edu
X** X-Informix-List-Id: <news.1132>
X** 
X** A few days ago, Jonathan Leffler posted some code for I4GL that would
X** change report output parameters on the fly.  The code he posted works
X** only for the C compiler version, and I only have the RDS version of
X** Informix.  Since an Informix employee said he was unable to figure out
X** a RDS version, I took that as a challenge.
X** 
X** Below is a modified version of his report.c that works when linked into
X** a customized runner.  I leave the details to building the runner as an
X** exercise for the reader.
X** 
X** I used Jonathan's code as a hint on how reports work in Informix.  I
X** found the equivalent report pointer, and inferred the report structure
X** that the interpreter uses.  Since this code diddles with internal
X** interpreter variables, use this code at your own risk.  I use it now to
X** reset the page length when output is going to the screen, and it
X** *appears* to work correctly.  Your mileage may vary.
X** 
X** BTW, I am using Informix 4.00 on SCO Xenix.  I haven't tested this
X** anywhere else.  Of course, the size of the junk variable in the repdesc
X** structure may change on other machine architectures.  You could write
X** another C function that gets called in the ON EVERY ROW section, and
X** have it print out the values in the repdesc structure.  You can then
X** verify that the structure definition is correct on your machine.
X** 
X** I've wanted to do this, but after I had previously poked around in the
X** interpreter for awhile, I had also given up.  Thanks for the hints, Jonathan.
X** 
X**  -------------------------------------------------------------------------- 
X** | Marlin Prowell            | There is a very thin line between ignorance  |
X** | (206) 676-1554            | and arrogance and I have totally obliterated |
X** | mbp@nyssa.wa7ipx.ampr.org | that line.             -- Dr. Science        |
X**  -------------------------------------------------------------------------- 
X*/
X
X#include <stdio.h>
X
X#ifndef lint
Xstatic  char    sccs[] = "@(#)report.c	2.1 92/07/24";
X#endif
X
X#ifdef I4GL_RDS
X
X/* Structure inferred from RDS */
Xtypedef struct repdesc
X{
X	short junk[42];     /* unknown       */
X	short ln;           /* Line number?  */
X	short pagenumber;   /* Pge number    */
X	short plength;      /* Page length */
X	short tmargin;      /* Top margin    */
X	short bmargin;      /* Bottom margin */
X	short lmargin;      /* Left margin   */
X	short rmargin;      /* Right margin  */
X	short fphlines;     /* Lines in first page header */
X	short phlines;      /* Lines in page header */
X	short ptlines;      /* Lines in page trailer */
X	short junktoo;      /* unknown       */
X	short tot;
X}  Report;
X
Xextern  Report *currep;   /* Parameters of current report */
X
X#else
X
X/* Structure copied from C code generated by I4GL */
Xtypedef struct repdesc
X{
X	long rrecordnum;    /* Record number */
X	short pagenumber;   /* Pge number    */
X	short ln;           /* Line number?  */
X	short tmargin;      /* Top margin    */
X	short rmargin;      /* Right margin  */
X	short lmargin;      /* Left margin   */
X	short bmargin;      /* Bottom margin */
X	short phlines;      /* Lines in page header */
X	short fphlines;     /* Lines in first page header */
X	short colcount;
X	short tot;
X	short oktoinc;
X	FILE *outfp;        /* Output channel */
X	short oftype;
X	short plength;      /* Page length */
X	short ptlines;      /* Lines in page trailer */
X	struct aggdesc *_paggdesc;
X	struct value *_paggvals;
X	struct sortdesc *p_sortdesc;
X	short gotoindx;
X	short gotostk[5];
X	short needlmarg;
X}  Report;
X
Xextern  Report *c_rp;   /* Parameters of current report */
X
X#endif	/* I4GL_RDS */
X
Xstatic  Report set;     /* Newly set report parameters  */
Xstatic  int newset = 0; /* Mask of newly set parameters */
X
X#define TMARGIN 0x01
X#define BMARGIN 0x02
X#define LMARGIN 0x04
X#define PLENGTH 0x08
X#define RMARGIN 0x10
X
X#define DEF_TMARGIN   3
X#define DEF_BMARGIN   3
X#define DEF_LMARGIN   5
X#define DEF_PLENGTH  66
X#define DEF_RMARGIN 132
X
X/* Redefine page length */
Xint set_plength(i)
Xint i;
X{
X	if (i == 1)
X	{
X		popint(&i);
X		if (i > 0)
X		{
X			set.plength = i;
X			newset |= PLENGTH;
X		}
X	}
X	return(0);
X}
X
X/* Reset top margin */
X/* This will not reset the top margin on the first page */
Xint set_tmargin(i)
Xint i;
X{
X	if (i == 1)
X	{
X		popint(&i);
X		if (i >= 0)
X		{
X			set.tmargin = i;
X			newset |= TMARGIN;
X		}
X	}
X	return(0);
X}
X
X/* Reset bottom margin */
Xint set_bmargin(i)
Xint i;
X{
X	if (i == 1)
X	{
X		popint(&i);
X		if (i >= 0)
X		{
X			set.bmargin = i;
X			newset |= BMARGIN;
X		}
X	}
X	return(0);
X}
X
X/* Reset left margin */
Xint set_lmargin(i)
Xint i;
X{
X	if (i == 1)
X	{
X		popint(&i);
X		if (i >= 0)
X		{
X			set.lmargin = i;
X			newset |= LMARGIN;
X		}
X	}
X	return(0);
X}
X
X/* Reset right margin */
Xint set_rmargin(i)
Xint i;
X{
X	if (i == 1)
X	{
X		popint(&i);
X		if (i >= 0)
X		{
X			set.rmargin = i;
X			newset |= RMARGIN;
X		}
X	}
X	return(0);
X}
X
X/* Copy reset output list into report configuration */
X/* Call in first page header block */
Xint set_output(i)
Xint i;
X{
X	int newlen;
X	Report	*report;
X
X#ifdef I4GL_RDS
X	report = currep;
X#else
X	report = c_rp;
X#endif	/* I4GL_RDS */
X
X	if (i == 0 && newset && report != (Report *)0)
X	{
X		if (newset & PLENGTH)
X		{
X			report->plength = set.plength;
X		}
X		if (newset & TMARGIN)
X		{
X			newlen  = report->plength
X					- report->ptlines
X					- report->phlines
X					- report->bmargin
X					- report->tmargin
X					- 1;
X			if (set.tmargin < newlen)
X			{
X				report->tmargin = set.tmargin;
X			}
X		}
X		if (newset & LMARGIN)
X		{
X			report->lmargin = set.lmargin;
X		}
X		if (newset & BMARGIN)
X		{
X			newlen  = report->plength
X					- report->ptlines
X					- report->phlines
X					- report->tmargin
X					- report->bmargin
X					- 1;
X			if (set.bmargin < newlen)
X			{
X				report->bmargin = set.bmargin;
X			}
X		}
X		/* Adding report->phlines leaves the report     */
X		/* title at the top of the terminal screen.  MP */
X		report->tot = report->plength - (report->bmargin + report->ptlines
X						+ report->phlines);
X		newset = 0;
X	}
X	return(0);
X}
X
X/* Return page length */
Xint get_plength(i)
Xint i;
X{
X	if (newset & PLENGTH)
X		i = set.plength;
X	else
X		i = DEF_PLENGTH;
X	retint(i);
X	return(1);
X}
X
X/* Return top margin */
Xint get_tmargin(i)
Xint i;
X{
X	if (newset & TMARGIN)
X		i = set.tmargin;
X	else
X		i = DEF_TMARGIN;
X	retint(i);
X	return(1);
X}
X
X/* Return bottom margin */
Xint get_bmargin(i)
Xint i;
X{
X	if (newset & BMARGIN)
X		i = set.bmargin;
X	else
X		i = DEF_BMARGIN;
X	retint(i);
X	return(1);
X}
X
X/* Return left margin */
Xint get_lmargin(i)
Xint i;
X{
X	if (newset & LMARGIN)
X		i = set.lmargin;
X	else
X		i = DEF_LMARGIN;
X	retint(i);
X	return(1);
X}
X
X/* Return right margin */
Xint get_rmargin(i)
Xint i;
X{
X	if (newset & RMARGIN)
X		i = set.rmargin;
X	else
X		i = DEF_RMARGIN;
X	retint(i);
X	return(1);
X}
SHAR-EOF
chmod 444 report.c
if [ `wc -c <report.c` -ne 7529 ]
then echo shar: report.c unpacked with wrong size
fi
# end of overwriting check
fi
#--------------------
if [ -f rejig.4gl -a "$1" != "-c" ]
then echo shar: rejig.4gl already exists
else
echo 'x - rejig.4gl (1226 characters)'
sed -e 's/^X//' >rejig.4gl <<'SHAR-EOF'
X{
X    @(#)rejig.4gl 1.2 89/08/02 15:46:15
X    @(#)Sphinx Informix Tools
X    @(#)Example: Set output parameters of I4GL report dynamically
X    @(#)J Leffler
X    @(#)(C) Copyright 1989 Sphinx Ltd.
X}
X
XMAIN
X
X    DEFINE i INTEGER
X
X    START REPORT rf_rejig
X
X    { Adjust report parameters dynamically }
X    CALL set_tmargin(1)     # Top margin
X    CALL set_bmargin(1)     # Bottom margin
X    CALL set_plength(23)    # Page length
X    CALL set_lmargin(0)     # Left margin
X
X    FOR i = 1 TO 30
X        OUTPUT TO REPORT rf_rejig(i)
X    END FOR
X
X    FINISH REPORT rf_rejig
X
XEND MAIN
X
XREPORT rf_rejig(i)
X
X    DEFINE i INTEGER
X
X    OUTPUT
X        { Unusual and distinctive settings }
X        TOP MARGIN 4
X        BOTTOM MARGIN 4
X        LEFT MARGIN 15
X        PAGE LENGTH 63
X
X    FORMAT
X
X    FIRST PAGE HEADER
X        { Reset report parameters }
X		{ Top margin of first page already printed }
X        CALL set_output()
X        PRINT "First Page Header"
X
X    PAGE HEADER
X        PRINT "Other Page Header"
X
X    PAGE TRAILER
X        PRINT "Page Trailer"
X        PAUSE "Hit return to continue"
X
X    ON EVERY ROW
X        PRINT "i = ", i
X
X    ON LAST ROW
X        SKIP 1 LINE
X        PRINT "Number of rows = ", COUNT(*)
X
XEND REPORT {rf_rejig}
SHAR-EOF
chmod 444 rejig.4gl
if [ `wc -c <rejig.4gl` -ne 1226 ]
then echo shar: rejig.4gl unpacked with wrong size
fi
# end of overwriting check
fi
echo All files extracted
exit 0