Link Files and Device Drivers
What’s a Link File ?
A Link File is just a PVX file to make an ‘ALIAS’-name for a certain ‘device’ or ‘file’, and to connect a Device Driver to it.
A PxPLUS Link File is just a very simple little file, with three components.
– The header that defines it as a PxPLUS Link File.
– The name of some other file to open.
– The name of a Device Driver (call-program) that will be executed when PxPLUS opens that other file. (see Device Driver below)
That’s it… Link Files are just that, little files that exist on your hard disk. Like any other file, they live by the same rules. Meaning that under UNIX a Link File has a filename that is just as case sensitive as any other. Under DOS/Windows the case of the filename is irrelevant.
There are three kinds of Link Files in PxPLUS . Each has a slightly different header, [PVXLNK], [PVXDEV], and [PVXAPR]. Internally PxPLUS will deal with each slightly differently.
Lets talk about the Header for a second.
All PxPLUS Files have a header. Keyed files have [PVXKEY] and Indexed files have [PVXIND].
When PxPLUS opens any and every file, it reads up to 512 bytes out of that file right away. It then checks if it has one of these special headers that begin with “[PVX”. If it finds that the file has one of these headers, then PxPLUS knows that its one of its own files, if it doesn’t… then it’s someone elses, and all of these “other” files get treated as operating system files… like c:\autoexec.bat or win.com or whatever it is.
If its a Keyed file, then PxPLUS treats it like one. The interpreter knows how to read its own file formats.
In the case of a Link File, PxPLUS does something a little different, than it would do with say… an indexed file.
Since the interpreter has read enough bytes (up to 512 right), it has the entire Link File in memory. It then pulls the other 2 characteristics out of this Link File.
#1 – The name of some other file to open. (pos 9,60)
#2 – The name of a program to call (Device Driver). (pos 69,12)
Internally, PxPLUS closes the Link File. Then it opens the ‘other file to open’ and makes sure the name stays the same as the Link File. When it has opened that file, it calls the program (Device Driver). PxPLUS puts a ‘*dev/’ in front of it. So the program named is always called from the ‘lib/_dev’ directory.
Thats all a Link File is and does.
It doesn’t care what its name is… it doesn’t care what the name of the ‘other’ file to open is… it doesn’t care what program it is that you want to call, nor does it care what that program does. When the called program exits, PxPLUS continues running your program at the end of the OPEN()
The only thing PxPLUS cares about is that:
#1 – The ‘other’ file name actually exists and can be opened,
#2 – The program exists in the ‘*dev’ directory and can be read.
You can think of a Link File as an ‘ALIAS’ to another file with a supporting called program if you like.
There is a utility in PxPLUS that helps you to create these Link File, called *UCL.
You can use it to create these files and associate the ‘other’ file name to open and a program with it. Or you can write the file out to the hard disk yourself. Link Files are just little plain text files.
Keep something else in mind. When you open a file and it doesn’t matter what it is, PxPLUS searches for it, opens it, and checks to see if it is one of it’s own files.
When you do: OPEN(1)”SALES” PxPLUS doesn’t care if its a keyed file, or an indexed file or a Link File. It’ll check the header, and take whatever action is appropriate to the info it finds in the header of the file you opened.
I mentioned that there are three kinds of Link Files. [PvxLnk] [PvxDev] & [PvxApr]. These headers cause PxPLUS to take a slightly different action.
The [PVXLNK] is used when you just want the link to point to the ‘other’ file, without calling a program. So you could do something like: move a SALES file to another directory or drive, and create a Link File with the original name (SALES) and with the ‘other’ file name portion of the link, pointing to the new location of the actual file, ie F:\DATA\SALES
The [PVXDEV] header is used, when you want to open some other file, and call a program. Commonly used for printers etc.
The [PVXAPR] header is used for attached printers on the auxilary ports of terminals. PxPLUS opens the ‘other’ file name, calls the program in question, and prints the ‘PS’ mnemonic to the printer. It will also issue a ‘PE’ mnemonic when its attempts to close the file.
Keep in mind. PxPLUS could care less about any ‘type’ of info you think it is… it just does the few simple things.
The easiest way to create these Link Files, is to use the *ucl utility. Just answer the questions. Keep in mind that when it asks for the Link File name, its going to be a REAL file, one you must be able to OPEN in PxPLUS . That means you may need to put it in a specific directory, or make sure that the file can be found using your PREFIX rules.
A few examples of Link Files to Printers would be:
(see also Techtip Windows Printing)
Name of link file |
LP |
Name of file/device |
*windev*;\\texas\HP on Ne01: |
Selected driver |
HPLASER |
Name of link file |
LP |
Name of file/device |
\\server_name\shared_printer_name\ |
Selected driver |
OKI24 |
Name of link file |
/MYAPP/P1 |
Name of file/device |
>lp -d queuename -c -s 2>/dev/null |
Selected driver |
EPSON |
Name of link file |
SPOOL |
Name of file/device |
/tmp |
Selected driver |
spooler |
Name of link file |
WINDOWS |
Name of file/device |
[wdx]*winprt* |
Selected driver |
myprog |
The name of the link is entirely up to you.
The name of the file being opened, is anything you could and must be able to open with a standard OPEN() statement. Physical ports, spooler queues, the windows printer subsytem, TCP/IP ports, ODBC links, anything.
The program is whatever you want, from the ‘*dev’ directory…
Feel free to make your own.
What’s a Device Driver ?
A PxPLUS Device Driver is just a ‘CALL’-program to initialize and preparate a device or file, opened on a channel.
ie.:
Name of ‘link’ file: LP
Name of file/dev.: /dev/lp0
Selected driver: OKI
OPEN(1)”LP”
They have the same effect of you doing:
OPEN(1)”/dev/lp0″
CALL “*dev/OKI”
SETFID (1)”LP”
Here’s the thing that everyone forgets. ‘OKI’ is just a called program. Anything and everything can be done inside them. You can open other files, you can ask for input from the user, you can call other programs if you want… they are just called programs… whatever you can or would code can be put in them.
If you load a Device Driver and look at it, such as HPLASER, or SPOOLER, you can see that there is nothing special about them.
At the top of the Device Driver you’ll see:
DEFTTY (LFO) cols,rows or DEFPRT (LFO) cols,rows.
DEFTTY and DEFPRT tell PxPLUS that the file opened is either a terminal or a printer, without this, PxPLUS thinks is just a simple file. When you do use these, then PxPLUS knows to give you the FIN() information back in either TERMINAL format or PRINTER format. It uses the cols and rows to give you some starting values to use, if you query the FIN() or the MXC(), MXL() functions.
LFO and LFA are two PxPLUS variables, just like DAY or SSN are variables.
LFO stands for the Last File Open number and LFA stands for the Last File Accessed number.
A simple Device Driver such as the ‘*dev/epson’ or ‘*dev/hplaser’, show you that you can define mnemonics to channels, and how to go about doing that. Remember that mnemonics are defined for a specific channel, and only exist as long as that channel is opened. You can invent and define your own mnemonics if you like !
Mnemonics are defined ‘to’ a channel, meaning there are only available when used on that specific channel. The MNM() function can be used to re-use mnemonics from OTHER channels. For example, you could define the ‘PS’ and ‘PE’ mnemonics for starting and stopping the aux port on a terminal, in the terminal driver. Then in your printer driver, you can re-use them from channel 0 (your terminal) and apply them to the printer channel…. good for the life of the channel and no more.
There are also a couple of special mnemonics, that you can define for when a file is closed. ‘*C’ is a mnemonic that you can set for PRINT’d escape sequences (or other PRINT style commands) to send to the channel when it is closed. ‘*R’ is an operating system command to issue when you close the channel. One of the items currently on the wish list, is a mnemonic that can be defined that will CALL a program name given in a mnemonic, when a channel is closed. The calling of a program automatically at the time of closing is not yet available but will be soon.
Then there is ‘*I’ and ‘*O’. If you know what ‘mapchan’ is, then you understand what these two mnemonics will do for you.
‘*I’ is an ‘input’-table and ‘*O’ is an output table.
You can remap any character to another character if you want.
ie: MNEMONIC ‘*O’=$00 01 02 03.. .. ..1C 1D 1E 1F 2E 21 22 .. .. .. .. .. FE FF$
This table will print a ‘space’ as a ‘dot’. (The hex-value of a ‘space’ is $20$ and this is replaced by $2E$, a ‘dot’ )
There is nothing that says that your called program can’t close the ‘file to be opened’ and change it to something else. The best thing to do if you wish to do this sort of thing is to save the FID() name of the original file and the channel to variables. Then set the name back to the original using the SETFID() command.
I also mentioned that you can call other programs. You can do anything you want.
An example of a more complex Device Driver would be:
! My driver
PCHAN=LFO, PNAME$=FID(PCHAN)
CLOSE(PCHAN)
[ code to check for the existance of a lock file ]
[ if a lock file exists do an EXIT ERR so that the err code gets sent back to the err= in the open statement ]
[ code to create a lock file ]
[ code to create a temporary file: ‘MYOUTPUT’ ]
OPEN(PCHAN)”MYOUTPUT”
[ call to a program with the mnemonic defs ]
SETFID (PCHAN) PNAME$ ( yes, SETFID works on files also !)
EXIT
You can do anything you want. You could build a Device Driver that reads a file to get all of the printer characteristics from … like the config.bbx you’re used to, then read the record in, parse and set the mnemonics, create lockfiles, put up a dialogue box and ask the user how many copies they want.
Another element of PxPLUS that you can use is the OPT= in an open, and the OPT() function.
The OPT(channel) function, will return the string used in the OPT= from the open clause of any channel. You can use the OPT= in your opens, then use the OPT() function to get those parameters in your driver, parse them and put the code in the responds to whatever you want. Example:
Say you have a Link File name ‘LP’, with the ‘other’ filename to open as ‘/dev/lp0’ and the program name is ‘myprog’
OPEN(1,OPT=”Check the paperform”) “LP”
<PxPLUS Internally>
[PxPLUS reads the LP Link File]
[Closes the file LP]
[Opens the file: /dev/lp0]
[Uses SETFID to change the name from /dev/lp0 back to LP]
[Calls *dev/myprog]
<Inside *dev/myprog>
options$=OPT(LFO)
[options$ is now ‘Check the paperform’]
IF NOT(NUL(OPTIONS$)) MSGBOX OPTION$,”Message”
[called program EXITS]
<PxPLUS Internally>
[If called program exits with an error, then send that error back in the OPEN() statement and take the err= branch if there is one]
<Processing continues>
Another function that few people realize is SETDEV TSK() string
This directive can load entries into the TSK() function, the string can be anything you want. The only problem with it is that you can’t erase the entries and start over. The string can be anything, formatted however you like. Whatever you put in you’ll get back.
SETDEV TSK() $0100$+”LP”+$00$+”>lp -dqueue %COPIES% -s 2> /dev/null” +$00$
SETDEV TSK() $0100$+”P1″+$00$+”/dev/lp1″+$00$
They’ll return in TSK(0) and TSK(1)
Or you can simply make an entry in a file, then in your Device Driver you could open that file, retrieve the record that matches it, parse the %COPIES% out of the string, if it exists, substitue ‘-n numcopies’ with it.
The trick is there are no limits. You could open 100 files while in your called program, each on its own channel if you want… anything goes.
If you look at the ‘*dev/spool’ driver, it wants the ‘other’ file to open, to be a directory name. It then captures this directory name, closes it, builds a filename for a temporary file, and uses that original directory name from the link as the place to store those temporary spooler files. Then at the end of the driver, it builds an >lp command line, and sets the mnemonic ‘*R’ to that os command. You can have more than one command in the *R, just separate them with a ‘;’ just like any other os command you would do.
I used this approach to create a temp file, send it to the spooler, ensuring that the spooler made its own copy of the file, and then did an ‘rm’ of my original temp file. The *R got run when the channel was closed, so at that time, the file was sent to the spooler, and the temp was erased.
I would likely create a keyed file, with records of LP P1 P2 etc, where one of the fields was the spooler command, or physical port name to open, another field would be a called program to set the mnemonics for the printer type. Then I would create Link Files of LP P1 P2 etc, using the name of my keyed file as the ‘other’ name to open. I would have only one Device Driver program.
In that Device Driver, I would save the channel number (lfo) and the name of the channel (fid(lfo)), read the record from my keyed file, and close the channel.
I would parse any options into the spooler command as necessary, then open that final command on the original channel, set the name back to its original using the SETFID command.
A special Device Driver is ‘*dev/windows’. This one is used with PVX for Windows.
Don’t change anything to this driver. As a matter of fact, you better make copies of any driver you wish to modify, because if you install a new version of PxPLUS , they get overwritten. If you want to do something specific, you can do it in a special directory ‘lib/_udev’. (Create it, if it doesn’t exists.)
PxPLUS will search in this directory for your own terminaldriver and if it finds the right one, it will be executed.
ie.: You want blue characters on a white background in PVX for Windows.
Make a program called ‘*udev/windows’
0010 ! Windows
0020 print ‘blue’,’_white’,’df’,’cs’,
0030 exit
>save”*udev/windows”
>start
The biggest thing is, it’s just terminology, the whole idea of Link Files and Device Drivers is really quite simple, because anything goes… it’s as powerful as you could ever want it to be. You can do anything you can imagine inside a Device Driver… ’cause its just a called program… just like any other called program.
Link Files are just a way of associating some ‘other’ file name and a program, to an ALIAS name.
(Original text from Gord Davey, edited and adjusted by Tino Vanholst)