ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Printing from one program to 2 spool

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Printing from one program to 2 spool

    Hello everyone.
    I have a C program and I needed to write data via printf from this program to 2 different spool files. I did OVRPRTF stdout and called printf. Everything worked great! Next, I removed the override via DTLOVR, made OVRPRTF stdout again, but this time to a different printer file and set a different spool name. However, a subsequent call to printf did print to the first spool.
    Explain what is happening and how to solve it?

  • #2
    I'm not a C programmer, but it sounds like the STDOUT file is still open when you do the second override. The file has to be closed and then reopened for the new override to take effect.

    Comment


    • #3
      It is not difficult to close stdout, as it simply needs to use the fclose function. But how do you open stdout again? After all, when you start the program, it is already open and you cannot see the code that opens it.

      Comment


      • #4
        Have you considered writing directly to a print file instead of writing to stdout and overriding it to a print file?

        Comment


        • #5
          Originally posted by Scott Klement View Post
          Have you considered writing directly to a print file instead of writing to stdout and overriding it to a print file?
          Yes, I tried opening the print file and sending messages to it via the fprintf function:
          Code:
          FILE * out = fopen("QPRINT", "w");
          fprintf(out, "Hello");
          However, in this case, I don't know how to set the spool file name, print parameters (page size, for example) and other options. I configured all of the above through OVTPRTF.

          Comment


          • #6
            You would still use OVRPRTF for that, just with a different printer file name. The sequence of events should be:
            1. OVRPRTF FILE(QPRINT) PAGESIZE(xx xxx) OUTQ(outq1) SPLFNAME(spoolfilename1) etc.
            2. Open QPRINT
            3. Write to QPRINT
            4. Close QPRINT
            5. OVRPRTF FILE(QPRINT) PAGESIZE(xx xxx) OUTQ(outq2) SPLFNAME(spoolfilename2) etc.
            6. Open QPRINT
            7. Write to QPRINT
            8. Close QPRINT
            9. DLTOVR FILE(QPRINT)

            Another alternative would be to create 2 printer files with the attributes that you want and use them in your program, eliminating the need for one of the overrides and simplifying the other.
            CRTPRTF FILE(library/PRTFILE1) PAGESIZE(xx xxx) OUTQ(outq1) SPLFNAME(spoolfilename1) etc.
            CRTPRTF FILE(library/PRTFILE2) PAGESIZE(xx xxx) OUTQ(outq2) SPLFNAME(spoolfilename2) etc.

            Then the sequence would be:
            1. Open PRTFILE1
            2. Write to PRTFILE1
            3. Close PRTFILE1
            4. OVRPRTF FILE(PRTFILE1) TOFILE(PRTFILE2)
            5. Open PRTFILE1
            6. Write to PRTFILE1
            7. Close PRTFILE1
            8. DLTOVR FILE(PRTFILE1)

            You only need PRTFILE1 in your program because the second time through, PRTFILE1 will use the attributes of PRTFILE2 because of the override.

            Comment


            • #7
              Personally, I prefer to create an externally-defined print file (like Brian's second example).

              Here's an old example that I had lying around... It prints a list of modules in a library (so has no dependency on any of my database tables, et al, so you should be able to load/compile/run it.) The first part is a print file named PRTMOD.

              Load the above into a member named PRTMOD in a source file like QDDSSRC and compile it. Below is the minimal compile command, but you should also set things like the output queue, page size, and any other features you want. This is similar-ish to the printer settings dialog that you would have in a windows environment, you can set up all the appropriate settings for your printer in the print file command:

              CRTPRTF FILE(your-lib/PRTMOD) SRCFILE(your-lib/QDDSSRC)

              You can change these at runtime with OVRPRTF as well if you wish... But, I don't usually need to do that in my environment.

              here's the source code for the print file:

              Code:
                   A* PRINT FILE FOR ILE PROGRAMS/MODULES REPORT
                   A*
                   A* TO COMPILE:
                   A*     CRTPRTF FILE(PRTMOD) SRCFILE(xxx/QDDSSRC)
                   A*---------------------------------------------------------
                   A          R HEADING01                 SKIPB(3) SPACEA(2)
                   A                                     1DATE EDTCDE(Y)
                   A                                    13'List of Modules Used by -
                   A                                      Programs in Library'
                   A            LIBRARY       10A       +1
                   A                                    69'PAGE'
                   A                                    +0PAGNBR EDTCDE(Z)
                   A*---------------------------------------------------------
                   A          R HEADING02                 SPACEA(1)
                   A                                     1'Program'
                   A                                      UNDERLINE
                   A                                    13'Module'
                   A                                      UNDERLINE
                   A                                    25'Src Lib'
                   A                                      UNDERLINE
                   A                                    37'Src File'
                   A                                      UNDERLINE
                   A                                    49'Src Mbr'
                   A                                      UNDERLINE
                   A*---------------------------------------------------------
                   A          R DETAIL                    SPACEA(1)
                   A            PROGRAM       10A        1
                   A            MODULE        10A       13
                   A            SRCLIB        10A       25
                   A            SRCFILE       10A       37
                   A            SRCMBR        10A       49
              Then in C, I usually print to it using the _Ropen, _Rwrite, et al APIs. I must admit, I haven't tried using fopen() and friends, only the _Ropen set... not sure if it'd work the other way or not?

              Here's the C program.. the printing part is pretty simple. The more complex stuff is calling the APIs to get the list of modules. Anyway... you can compile it with CRTBNDC PGM(yourlib/LISTMOD) SRCFILE(yourlib/QCSRC)

              Code:
              #include <stdio.h>
              #include <stdlib.h>
              #include <recio.h>
              #include <string.h>
              #include <errno.h>
              #include <qusec.h>
              #include <qusgen.h>
              #include <quscrtus.h>
              #include <qusptrus.h>
              #include <qusdltus.h>
              #include <qbnlpgmi.h>
              
              #pragma mapinc ("prtmod","*libl/PRTMOD(*ALL)", \
                              "output","_P","","PRTMOD" )
              #include "prtmod"
              
              static int get_overflow_line(_RFILE*);
              static int get_current_line(_RFILE *f);
              static void print_headings(_RFILE*, char*);
              static void print_detail(_RFILE*, char*, char*, char*, char*, char*);
              
              struct ErrCode {
                 Qus_EC_t info;
                 char data[8000];
              };
              
              /*               12345678901234567890 */
              #define SPCNAME "MODLIST   QTEMP     "
              #define SPCATTR "SCKLISTMOD"
              #define SPCAUT  "*ALL      "
              #define FORMAT  "PGML0100  "
              #define REPLACE "*YES      "
              
              int main(int argc, char **argv) {
              
                 char msgid[8], pgm[20], text[50], *library;
                 struct ErrCode ec;
                 Qus_Generic_Header_0100_t *pHdr;
                 Qbn_LPGMI_PGML0100_t *pDta;
                 _RFILE *prtf;
                 int x, ovrflw;
              
                 /*************************************************************
                  * There should be one parameter containing the library name.
                  * It needs to go into a 20 char field, where chars 1-10
                  * are the name of the ILE program(s) to list (*ALL is used)
                  * and positions 11-20 is the library name.  Both parts are
                  * padded with blanks to make the data exactly 20 chars long.
                  *************************************************************/
              
                   if (argc != 2) {
                       fprintf(stderr, "Usage: CALL %s PARM(my-library)\n",
                                       argv[0]);
                       exit(1);
                   }
              
                   library = argv[1];
                   if (strlen(library) > 10) {
                       library[10] = '\0';
                   }
              
                   memset(pgm, ' ', sizeof(pgm));
                   memcpy(pgm, "*ALL" , 4);
                   memcpy(pgm+10, library, strlen(library));
              
              
                 /*************************************************************
                  * Open printer file (PRTMOD) and print heading
                  ************************************************************/
              
                   prtf = _Ropen("*LIBL/PRTMOD", "wr");
                   if (!prtf) {
                       fprintf(stderr, "Unable to open PRTMOD: %s\n",
                                       strerror(errno));
                       exit(1);
                   }
              
                   ovrflw = get_overflow_line(prtf);
              
              
                 /*************************************************************
                  *  Create a user space in QTEMP library.
                  *************************************************************/
              
                   memset(text, ' ', sizeof(text));
                   memset(&ec, 0, sizeof(ec));
                   ec.info.Bytes_Provided = sizeof(ec);
              
                   QUSCRTUS( SPCNAME,SPCATTR, 64*1024, "\0", SPCAUT, text,
                             REPLACE, &ec );
              
                   if (ec.info.Bytes_Available > 0) {
                       memset(msgid, 0, sizeof(msgid));
                       memcpy(msgid, &ec.info.Exception_Id, 7);
                       fprintf(stderr, "Error %s when creating user space.",
                                        msgid);
                       _Rclose(prtf);
                       exit(1);
                   }
              
              
                 /*************************************************************
                  * Dump all ILE program/module info into the user space
                  ************************************************************/
              
                   memset(&ec, 0, sizeof(ec));
                   ec.info.Bytes_Provided = sizeof(ec);
              
                   QBNLPGMI( SPCNAME, FORMAT, pgm, &ec);
              
                   if (ec.info.Bytes_Available > 0) {
                       memset(msgid, 0, sizeof(msgid));
                       memcpy(msgid, &ec.info.Exception_Id, 7);
                       fprintf(stderr, "Error %s when creating user space.",
                                        msgid);
                       memset(&ec, 0, sizeof(ec));
                       QUSDLTUS( SPCNAME, &ec );
                       _Rclose(prtf);
                       exit(1);
                   }
              
              
                 /*************************************************************
                  * Get a pointer to the header of the user space.  This
                  * tells us the offset to the list data, as well as the
                  * number of returned entries.
                  ************************************************************/
              
                   QUSPTRUS( SPCNAME, &pHdr );
              
              
                 /************************************************************
                  * Calculate the position of each entry in the user space
                  * based on the starting offset, and the size of each entry.
                  *
                  * Then, copy the data from the user space to the print buffer
                  * and write it to the print file.
                  ************************************************************/
              
                   print_headings(prtf, library);
              
                   for (x=0; x<pHdr->Number_List_Entries; x++) {
              
                       pDta = (Qbn_LPGMI_PGML0100_t *)
                              ((char *)pHdr + pHdr->Offset_List_Data
                              + (x * pHdr->Size_Each_Entry));
              
                       if (get_current_line(prtf) > ovrflw)
                            print_headings(prtf, library);
              
                       print_detail(prtf, pDta->Program_Name,
                                          pDta->Bound_Module_Name,
                                          pDta->Source_File_Library_Name,
                                          pDta->Source_File_Name,
                                          pDta->Source_File_Member );
              
                   }
              
              
                 /************************************************************
                  *  Yay! All done!  Close the print file and delete the
                  *  user space.
                  ************************************************************/
              
                   _Rclose(prtf);
                   memset(&ec, 0, sizeof(ec));
                   QUSDLTUS( SPCNAME, &ec );
              
                 return 0;
              }
              
              static int get_overflow_line(_RFILE *f) {
                  _XXOPFB_T *o;
                  o = _Ropnfbk(f);
                  return o->overflow_line_num;
              }
              
              static int get_current_line(_RFILE *f) {
                  _XXIOFB_T *io;
                  _XXIOFB_PRT_T *pio;
              
                  io = _Riofbk(f);
                  pio = (_XXIOFB_PRT_T *)
                        ((char *)io + io->file_dep_fb_offset);
              
                  return pio->cur_page_line_num;
              }
              
              
              static void print_headings(_RFILE *f, char *lib) {
              
                  PRTMOD_HEADING01_o_t printHdr;
              
                  memset(&printHdr, ' ', sizeof(printHdr));
                  memcpy(printHdr.LIBRARY, lib, strlen(lib));
              
                  _Rformat(f, "HEADING01");
                  _Rwrite(f, &printHdr, sizeof(printHdr));
              
                  _Rformat(f, "HEADING02");
                  _Rwrite(f, "", 0);
              }
              
              
              static void print_detail(_RFILE *f,
                                       char *program,
                                       char *module,
                                       char *srclib,
                                       char *srcfile,
                                       char *srcmbr ) {
                 PRTMOD_DETAIL_o_t printDet;
              
                 memset(&printDet, ' ', sizeof(printDet));
                 memcpy(printDet.PROGRAM, program, 10);
                 memcpy(printDet.MODULE,  module,  10);
                 memcpy(printDet.SRCLIB,  srclib,  10);
                 memcpy(printDet.SRCFILE, srcfile, 10);
                 memcpy(printDet.SRCMBR,  srcmbr,  10);
              
                 _Rformat(f, "DETAIL");
                 _Rwrite(f, &printDet, sizeof(printDet));
              }
              This code uses #pragma mapinc to get the definitions from the DDS into the C program. You can learn more about that, here:


              Granted, this program only creates one spooled file, but I'm hoping you'll be able to see that if you created two print files and opened them with separate _Ropen() statements, and printed to them separately, you'd get two spooled files without any problems.

              Comment


              • #8
                Scott, Brian, thanks for the examples! I used Brian's first approach, since I don't want to create a printer file for simple spool printing.

                However, at that time my program was in C. Now I have a C++ project. I took the code from a previous project, compiled it, ran it and... did not find the spool file in the job... It turned out that the spool was written to my folder on IFS! After looking for information, I found that there is a SYSIFCOPT compilation option, which is set to *IFS64IO. Changing it to *NOIFSIO I got a compilation error in the FSTREAM file: "CZP0859: #error directive: ***ERROR: SYSIFCOPT (*IFS64IO) MUST BE SPECIFIED WITH CRTCPPMOD OR CRTBNDCPP COMMAND."

                Is there some way to "just" write to spool from C++?

                Comment

                Working...
                X