Link Files and
Device Drivers
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.
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 |