Operating System - OpenVMS
1827721 Members
2636 Online
109968 Solutions
New Discussion

Capturing spooled output

 
SOLVED
Go to solution
Jack Trachtman
Super Advisor

Capturing spooled output

We have an old application that we cannot modify, which uses what I'll call the old LAT style of printing. We create a LAT device and set it spooled to a print que. When the app wants to print, it opens the LAT device and wirtes to it. VMS captures the output to a temporary file which it creates. When the app close the file, VMS creates an entry in the print que associated with the LAT device. The temporary file then gets printed and deleted.

We need to capture these files after they are closed so that we can reformat them with added printer control information. But VMS creates these files with only a FID entry but no file name, making it impossible to directly find them.

How can I (preferably with DCL only) get to these files so that I can open them and read through them to them to create new versions with the changes I want to add?

TIA
25 REPLIES 25
Ian Miller.
Honored Contributor

Re: Capturing spooled output

you need a server symboint. See the freeware on the hp vms site for examples
____________________
Purely Personal Opinion
Volker Halle
Honored Contributor

Re: Capturing spooled output

Jack,

don't think you could do this from DCL.

But there exists some freeware tool called EXECSYMB, which may be able to help (from reading the documentation).

Volker.
Uwe Zessin
Honored Contributor

Re: Capturing spooled output

Correct, I have done it in the past, but I used 'CTLSMB' (on VAX, only). For today's use it would need some work, because it uses a little Macro code to alter things like the process' username cell.

The server symbionts (at least CTLSMB) can be set up so that they start a separate process with DCL access for each job.

I am afraid that even if you use a different workaround:
- keep the queue stopped
- make a copy of each entry's data
- move the job into the real output queue

you cannot do this with DCL alone, because a spooled file, as you have already discovered, is not entered into a directory. You would need at least a little image that knows how to open a file by device name and FID to make a copy of the data.
.
John Gillings
Honored Contributor

Re: Capturing spooled output

Jack,

A rather ugly alternative is to use spare serial ports and a short patch cable. Send the jobs out one port, and just loop it back into another. Start a process that listens for input on the second port. Hopfully you can distinguish the beginning and end of the job. Use a reset module with an unique string if necessary.

Your reader could be in DCL if there are no other options. Make sure flow control is enabled and resist the temptation to crank the speed up too high. Many systems have unused ports, or you could use LAT terminal server ports if there aren't any on the host.
A crucible of informative mistakes
Tom O'Toole
Respected Contributor

Re: Capturing spooled output

You could also do periodic anal/disk/rep on your spool disk, which would move those files into [syslost], where you can manipulate them. If you can allocate a small volume for use strictly as spool, this might not be too bad.
Can you imagine if we used PCs to manage our enterprise systems? ... oops.
Jack Trachtman
Super Advisor

Re: Capturing spooled output

Looks like EXECSYMB might be the way to go for me.

I'm curious to hear from people who are using it: for what purpose(s), and any problems they've had (on doing a WEB search for EXECSYMB I see that someone posted a problem with the SET USER function.)

Thanks
Jan van den Ende
Honored Contributor

Re: Capturing spooled output

Jack,

maybe off-topic, but from your profile:

"I have assigned points to 26 of 124 responses to my questions."

Would you please find some time to catch up somewhat?

Look, I am __NOT__ saying that you should award more points, but just asking to get rid of the UNassigned.
If there are answers that __YOU__ feel (and on your questions you are the only one who decides) merit NO points, it is simply possible to assign ZERO points.
At least it tell the person trying to answer, that that answer HAS been evaluated, but was considered irrelevant.

It is considered forum-etiquette.

If you want quick access to the questions in case, click your own name to get your statistics, and at the bottom choose "questions or topics with unassigned points"


Proost ( = Cheers!)

Have one (or more) on me.

Jan

Don't rust yours pelled jacker to fine doll missed aches.
Robert Gezelter
Honored Contributor

Re: Capturing spooled output

Jack,

Three options, one that I will admit that I have not investigated, and one that I know from experience should work.

- Stop the queue, use a command file to scan the queue, and then copy the files to somewhere else (and remove them from the queue). As was said in a movie, "Crude but effective". This should be implementable using nothing but DCL.

- Without doing any programming, I would take a look at the possibility of using C-Kermit and its scripting language to manage an incomming LAT port.

- A clean (well cleaner) implementation would be to write a program which uses the incomming LAT connection support on a VMS system to fake a printer.

For cleanliness, I would probably chose option 3, otherwise my first choice might very well be option 1.

In both cases, they guarantee that you will only process files that are in that queue, no accidental inclusions of other files.

I hope that the above is helpful.

- Bob Gezelter, http://www.rlgsc.com

-
Jan van den Ende
Honored Contributor

Re: Capturing spooled output

Jack,

another possibility, which (as far as I can see now :-) ) even less potential timeing problems, would be to simply STOP the target queue.

Then have a batch job periodically scan the queue for jobs, and test for the file being closed. Get the file info, do whatever required manipulations, and actually PRINT them on another queue.

Hope this helps.

Proost.

Have one on me.

Jan
Don't rust yours pelled jacker to fine doll missed aches.
Uwe Zessin
Honored Contributor

Re: Capturing spooled output

Robert,
how do you copy a spooled file, which is not entered into a directory "using nothing but DCL" ?
.
Robert Gezelter
Honored Contributor

Re: Capturing spooled output

Uwe,

Yes, copying data from the file that does not have a name is a trick.

Unfortunately, the SET FILE/ENTER command needs a filename. I don't at the moment have the time to dig into the RMS manual, but you need a fairly simple program to enter a filename using an explicit FILE ID.

One should use caution, however. Carefully check the behavior when print jobs entered in this way are deleted from the pending list. I suspect (I don't have the time at this point to check) that the file is at that point deleted.

Thus, you must do the following:
- use a small program to enter a filename for the file that is in the queue by FILE ID
- use BACKUP or COPY to make a copy of the file
- then delete the queue file entry using the DELETE/ENTRY command

- Bob Gezelter, http://www.rlgsc.com
Bojan Nemec
Honored Contributor

Re: Capturing spooled output

Jack,

I know, you write preferably with DCL only, but in yours case the PSM Routines are a great solution. With this routines you are not expected to write the whole print symbiont, but only replace or add some parts (in yours case a n input or output filter). Please see the documentation:
http://h71000.www7.hp.com/doc/731FINAL/4493/4493pro_contents_003.html#toc_chapter_17

Bojan
Jan van den Ende
Honored Contributor

Re: Capturing spooled output

Jack,

I do not know how much patience you can afford but:

http://h71000.www7.hp.com/openvms/integrity/v82features.html

one of the new features of 8.2 is F$FID_TO_NAME, which I _GUESS_ (I did not see the specs yet) is the missing link in this discussion...

Proost.

Have one on me.

Jan
Don't rust yours pelled jacker to fine doll missed aches.
Uwe Zessin
Honored Contributor

Re: Capturing spooled output

I have not tried it, but I guess it will just give you a file specification like "[]BLA.DAT;1". As there can be multiple file with that name in the file header, but without a directory entry, I am afraid that you still need an image to open the file by FID.
.
John Gillings
Honored Contributor

Re: Capturing spooled output

Jan and Uew,

F$FID_TO_NAME is only useful if the file has a name. A file that isn't entered in a directory cannot be opened by name, so, in some senses it doesn't have a name.

For these files, the best F$FID_TO_NAME can do for you is verify that the FID is valid and the file exists.

F$FID_TO_NAME locates the header pointed to by the FID, extracts the filename field, then follows the back links to reconstruct the directory path.
A crucible of informative mistakes
Jan van den Ende
Honored Contributor

Re: Capturing spooled output

Uwe, John,

like before in

http://forums1.itrc.hp.com/service/forums/questionanswer.do?threadId=746158

it looks like we have identified another 'hole' in DCL.


Guy Peleg, can anything be done about that?


Proost.

Have one on me.

Seasonal wishes to all!

Jan
Don't rust yours pelled jacker to fine doll missed aches.
Ian Miller.
Honored Contributor

Re: Capturing spooled output

Jan, dcl suggestions can be emailed to dcl at hp dot com where they will be read by the ever helpful Guy. There is always the advocacy web site too.
____________________
Purely Personal Opinion
Hein van den Heuvel
Honored Contributor

Re: Capturing spooled output

First observation is that you would probably NOT be happy with having the file name for the FID, because the file to be printed is still identified by ID, so if you change if with a 'normal' editor style approach you'll create a new file with a new ID. Of course you COULD open the file by ID (trivial), and do an in-place update: Suck ALL lines into memory, apply changes and write with TPT (Truncate on PuT) or after a $truncate.

Writing up a symbiont to do the job sounds like the cleanest solution, but a bit of work in uncharted teritory.

Next best I like the stopped queue approach.
A DCL script could readily query the stopped queue for file to be printed. It gets the file id. It could then open the file by id, process, create new output, remove from queue which will delete the temp file.

Or... it could enter the file in a directory.
Now there is UNFORTUNATELY! (since the demise of RSX PIP) no more SET FILE/ENTER/FID
So below please find a C program which can do this for you. I'll attach it as well.

That C program can also be used as an example of how to access a file by file ID, for the process and delete from queue suggestion.

hth,
Hein.


/*
** enter.C create directory entry for a file ID.
**
** Have fun, Hein van den Heuvel, HP 6/4/2002
*/
#include ssdef
#include rms
#include stdio
#include string
#include stdlib

main(int argc, char *argv[])
{
int i, status, sys$parse(), sys$enter();
char *p, expanded_name[256], resultand_name[256];
struct FAB fab;
struct NAM nam;

if (argc < 4) {
printf ("Usage $%s [x] [x] \n", argv[0]);
return 268435456;
} else {

fab = cc$rms_fab;
fab.fab$l_fop = FAB$M_NAM;
fab.fab$l_dna = ".DAT";
fab.fab$b_dns = strlen(fab.fab$l_dna);
fab.fab$l_fna = argv[3];
fab.fab$b_fns = strlen (argv[3]);
fab.fab$l_nam = &nam;

nam = cc$rms_nam;
nam.nam$b_nop = NAM$M_NOCONCEAL;
nam.nam$l_rsa = resultand_name;
nam.nam$b_rss = 255;
nam.nam$l_esa = expanded_name;
nam.nam$b_ess = 255;


status = sys$parse( &fab );
if (status & 1) {
i = atoi (argv[1]);
nam.nam$w_fid_num = (short) i;
nam.nam$b_fid_nmx = (unsigned char) (i >> 16);
nam.nam$w_fid_seq = (short) atoi ( argv[2] );
status = sys$enter ( &fab );
}
return status;
}
}

Hein van den Heuvel
Honored Contributor

Re: Capturing spooled output


The ENTER.C that I posted above should probably be rewritten as .MAR for those that do not have a C compiler.
Or... if you want to go silly... you can do it all in DCL.

Below a HACK which will essentially implement a SET FILE/ENTR in 'pure' DCL.
It's a little rough around the edges, but should provoke a smile or two from the initiated.

Sample:
$ create test.dat
hello world
$ dir /file/nohead/notrail/wid=file=30 test.*
U$1:[HEIN.TMP]TEST.DAT;1 (2347,89,0)
$ @[hein]enter 2347,89,0 [hein.tmp]test.tmp
%SET-I-ENTERED, U$1:[TMP]$$$.$$$;1 entered as U$1:[HEIN.TMP]TEST.TMP;
$ @[hein]enter 2347,89,0 [hein.tmp]test.tmp
%SET-I-ENTERED, U$1:[TMP]$$$.$$$;1 entered as U$1:[HEIN.TMP]TEST.TMP;
$ dir /file/nohead/notrail/wid=file=30 test.*
U$1:[HEIN.TMP]TEST.DAT;1 (2347,89,0)
U$1:[HEIN.TMP]TEST.TMP;2 (2347,89,0)
U$1:[HEIN.TMP]TEST.TMP;1 (2347,89,0)
$ typ test.tmp;2
hello world

grins,
Hein.
-------------------------- enter.com --------

$if "".eqs.p2
$then
$TYPE sys$input

Provide file ID in NN,NN,NN format as first argument
And provide desired file name (with directory) as second argument

$EXIT
$ENDIF
$tmpnam = "[TMP]$$$.$$$;1"
$dirnam = "[000000]TMP.DIR"
$tmpdir = F$PARS(tmpnam,,,"DIRECTORY")
$IF "".eqs.f$search(dirnam) THEN CREATE/DIR/LOG 'tmpdir
$IF "".eqs.f$search(tmpnam) THEN SET FILE/LOG/ENTER='tmpnam' 'dirnam'
$OPEN/READ/WRITE dir 'dirnam
$READ dir record
$fid = 8 * ( 2+1+1+(-2.AND.(1+F$CVSI(3*8,8,record)))+2) !ver+flg+cnt+len+version
$record[fid,16] = 'F$ELEM(0,",",p1) ! num
$record[fid+16,16] = 'F$ELEM(1,",",p1) ! seq
$record[fid+32,8] = 'F$ELEM(2,",",p1) ! rvn
$record[fid+40,8] = 'F$ELEM(0,",",p1)/65536 ! nmx
$WRITE/UPDATE/SYMBOL dir record
$CLOSE dir
$SET FILE/LOG 'tmpnam /ENTER='p2
$EXIT
Hein van den Heuvel
Honored Contributor

Re: Capturing spooled output

Oh... I realize this is bad style, but one more thing (for Guy? :-)....

The prior example can actually be solved directly with VMS using ODS-5:

$SET PROC/PARS=EXTEN
$SET FILE/ENTE=test.tmp ~[2347,89,0]

However...
The above only works IF the file to be entered can be found in the specified directory (here defaulted).
So it does not work for temp files which are not in a directory.
Close, but no cigar!

DIDding directories works on ODS-2 and ODS-5
but FIDding files requires ODS-5 and an entry. :-(.

See "Guide to OpenVMS File Applications"
chapter:
6.4 "DID-Abbreviated Directories (Alpha Only)"
6.5 "FID-Abbreviated Names (Alpha Only)


Hein.
Jack Trachtman
Super Advisor

Re: Capturing spooled output

So I can use the DCL lexical F$GETQUI to get the file's FID.

Hmmm - what's the easiest way to now copy the file (giving it a real filename)?
Hein van den Heuvel
Honored Contributor

Re: Capturing spooled output

Yes, F$GETQUI has an FILE_IDENTIFICATION.
For example:

$ show entr
Entry Jobname Username Blocks Status
----- ------- -------- ------ ------
312 TMP HEIN 1 Pending
On paused printer queue ASEPS3
$ dir/file tmp.tmp
TMP.TMP;9 (63864,15,0)
$
$ queue_name = F$GETQUI("DISPLAY_QUEUE","QUEUE_NAME","ASEPS3","wildcard")
$ show symbol queue_name
QUEUE_NAME = "ASEPS3"
$ queue_name = F$GETQUI("DISPLAY_QUEUE","QUEUE_NAME","ASEPS3","wildcard,device")
$ ent_num = F$GETQUI("DISPLAY_JOB", "entry_number",,"all_jobs,wildcard")
$ show symb ent_num
ENT_NUM = 312 Hex = 00000138 Octal = 00000000470
$ x= f$GETQUI("DISPLAY_FILE","FILE_IDENTIFICATION",,"FREEZE_CONTEXT")
$ show symb x
X = "(63864,15,0)"

So then I modified that enter.c program to replace the $ENTER call will $OPEN, $CONNECT and $GET in a loop to process the file, given an id as argument.

Code below, and attached.
You can replace the 'printf' by your real processing, and/or a copy to an other file.

Merry Xmass,

Hein.



/*
** type_by_id.c print records from file where file passed by id.
** Based on: enter.C create directory entry for a file ID.
**
** Merry Xmass, Hein van den Heuvel, HP 12/2004
*/
#include ssdef
#include rms
#include stdio
#include string
#include stdlib

main(int argc, char *argv[])
{
int i, status, sys$parse(), sys$open(), sys$connect(), sys$get();
char *p, expanded_name[256], resultand_name[256], buf[32768];
struct FAB fab;
struct NAM nam;
struct RAB rab;

if (argc < 3) {
printf ("Usage $%s \n", argv[0]);
return 268435456;
} else {

fab = cc$rms_fab;
fab.fab$l_fop = FAB$M_NAM;
fab.fab$l_nam = &nam;

nam = cc$rms_nam;
nam.nam$b_nop = NAM$M_NOCONCEAL;
nam.nam$l_rsa = resultand_name;
nam.nam$b_rss = 255;
nam.nam$l_esa = expanded_name;
nam.nam$b_ess = 255;

rab = cc$rms_rab;
rab.rab$l_fab = &fab;
rab.rab$l_ubf = buf;
rab.rab$w_usz = 32767;

status = sys$parse( &fab );
if (status & 1) {
i = atoi (argv[1]);
nam.nam$w_fid_num = (short) i;
nam.nam$b_fid_nmx = (unsigned char) (i >> 16);
nam.nam$w_fid_seq = (short) atoi ( argv[2] );
status = sys$open ( &fab );
if (status & 1) status = sys$connect ( &rab );
if (status & 1) status = sys$get ( &rab );
}
while (status & 1) {
buf[rab.rab$w_rsz]=0;
printf ("%s\n", buf);
status = sys$get ( &rab );
}
if (status == RMS$_EOF) status = 1;
return status;
}
}



Jack Trachtman
Super Advisor

Re: Capturing spooled output

Great!!!

I've got your pgm compiled and working.

Now - what's the best way to redirect the
output to a file? Do I need to use:

$ PIPE .... > newfilename

or is there a more efficient way?
Hein van den Heuvel
Honored Contributor
Solution

Re: Capturing spooled output

Well, you can still use that prior example to ENTER the file, and then copy.

Or you can modify my second program to open an output file and print on that with plain C file Io (or RMS $PUTs if you like.

Or you can use the program as is and DEFINE/USER SYS$OUTPUT capture.dat

Or the pipe you suggest.

I would encourage you to modify the program to do the processing you really wanted to do and print the result on a selected output.
The program, or the job it is run from can then delete the queue entry when all done.

Hein.