scanutil is a collection of tools to assit in printing and scanning 'scanner sheets'. A reasonable level of effort has gone into making these routines be able to mask the intricacies of different scanner models (and a great deal of that is stored in the 'scanner-model' and 'form-bldg' files).
DEFINE {NEW}
Define a new instance of scanutil
CLEAN_UP
Release scanutil context. You *MUST* do this before exiting your program,
regardless of why you are exiting your program!!!
SET BLDG (buff)
Pass a 'building' buffer to associate a building with the scanner utilities.
This clears most everything in scanutil out upon success.
SET FORM (buff) (flag)
Pass a 'form-bldg' buffer to associate a form and scanner with the scanutil
context. If the form-bldg buffer is OK, then 'flag' is passed back TRUE. You
must have set the building with 'SET BLDG' before using SET FORM. If the
building of the form and the previously set building do not match, FALSE is
returned.
SET SCAN_DEVICE (device-id) (flag)
Used after you've set the building and form to associate the scanner
device to be used for reading (not needed if printing sheets). Pass
the 'scanner-device.scanner-device-id' of the device to use for
scanning. If it is compatibile with the selected forms, then 'flag'
is returned TRUE. Otherwise, it's FALSE.
VERIFY_PRINTER
This will register a callback with the prntutil routines to make sure
the user selects only a printer that is capable of handle the printing
of the scan forms. If you are not printing scan forms, do not register
this callback.
CREATE BATCH (desc) (sdate) (edate) (buff)
This will create a new scanner batch entry and set it up for subsequent
use. 'desc' is a textual, unique description of this batch. 'sdate'
and 'edate' are date ranges the batch is for and should be as appropriate
as possible. 'buff' is a scan-form-batch buffer that is passed back
to you for an additional needs. Nothing is expected to be passed to
CREATE BATCH through this buffer.
CREATE SHEET (buff)
This will create a new scan sheet entry for the previously selected
batch. You should use this before you being printing a new sheet.
'buff' is passed back with a scan-form-sheet buffer loaded with the
sheet entry just created. Nothing is expected to be passed to this
method via 'buff'. You must have previously used either the
'CREATE BATCH' or 'LOAD BATCH' method before using CREATE SHEET.
After creating a sheet, you'll want to set some identification data into the sheet. This is useful for you as well as the user. If each sheet represents a student, set the stu-seq value into the buffer. If each sheet represents a course, set the course-id into the buffer. If each sheet represents a course from the master schedule, then set the course-id and section-id into the buffer. If it represents something else, there are MISC-NAME and MISC-ID fields, but you should consult with the architect before using this (to insure proper support gets built into the sheet lister).
CREATE LINE (student) (line#)
This will create a new data line for the most recently created/loaded
scan sheet. You must pass a 'stu-seq' value in 'student'. If you
are not using students, then pass an appropriate identifying value or
'?'. 'line#' is passed back with the line # created for this
dataline. You can use this to help determine when a sheet is full
(check the scan-form-sheet.data-line-cnt to see the max # of datalines per
sheet). You must have previously wither used the 'CREATE SHEET'
method or a combination of the 'LOAD SHEET and LOAD DATASET' methods
before using CREATE LINE.
Note: If you decide to manipulate the scan-form-line records, be aware there may be multiple entries per data line. This is because there is one entry per dataset.
LOAD BATCH (batchid) (flag)
Load a previously created batch. The batch must match the previously
set form. 'batchid' is the ID of the batch to load. 'flag' is
passed back TRUE if the batch is successfully loaded and matches
the form.
LOAD SHEET (sheetseq) (flag)
Load a previous created sheet. The sheet must be part of the previously
set batch. 'sheetseq' is the sheet seq# of the sheet to load. 'flag' is
passed back TRUE if the sheet is successfully loaded and matches
the batch.
LOAD DATASET (set#) (flag)
Load a dataset of the previously loaded sheet. Set# is the set to load
and 'flag' is returned TRUE if the dataset is in range and loaded
OK.
LOAD LINE (line#) (flag)
Load a line of a dataset using a previously loaded dataset. Line # is the
line to load and 'flag' is returned TRUE if the line is in range and
loaded.
GET BATCH (batchbuff)
Load the passed 'scan-form-batch' buffer with what we beleive to be
the current scan batch. This call is usually used when scanning
data in.
GET SHEET (sheetbuff)
Load the passed 'scan-form-sheet' buffer with what we beleive to be
the current sheet. This call is usually used when scanning data
in and needing to extract info from the sheet read.
GET DATASET (datasetbuff)
Load the passed 'scan-form-dataset' buffer with that we beleive to be
the current dataset for the scan batch. This call is ususally used
when scanning data in.
GET LINE (linebuff)
Load the passed 'scan-form-line' buffer with what we beleive to be gte
current line. Usually used when scanning data
GET FORM (formbldg-buff)
Load the passed 'for-bldg' buffer with the form last set into
SCANUTIL via the SET FORM directive.
SLUGS INITIALIZE (prtseq)
Returns an initialization string that should be fed to the printer
that will eventually print slug marks. This could be an empty string
if there is no initialization for the printer.
The resultant string should be printed using the PUT-CONTROL service of 'prntutil' as it may have escaped control characters in it.
If you will be printing slugs on an HP laser form, you must pass two form parameters to the form. [LASER] specifies that this is a laser form, and [ORIGIN:x,y] specifies the starting location for the slug marks. Using the offset of PRINT_ALIGNMENT or PRINT_LINE will not work for HP printers.
You must use this service *BEFORE* using PRINT_ALIGNMENT or PRINT_LINE.
SLUGS PRINT_ALIGNMENT (line) (offset) (prtseq)
This works the same way the 'PRINT_LINE' work, but instead of needing a
sheet, it will produce an 'alignment' pattern of slugs to print.
This will not disturb any previously loaded sheets. Other than printing
an alignment pattern, this works exactly like 'PRINT_LINE'
You must call and print SLUGS INITIALIZE before using this service.
SLUGS PRINT_LINE (line) (offset) (prtseq)
Generates the necessary characters to print a graphic slug or slugs
for identifying the sheet. Each scan sheets identification area is
described in the 'form-bldg' record as a rectangle of a given number
of rows by a given number of columns.
'line' specifies which line in the slug box you are printing. 'offset' is the horizontal position on the sheet where the first character of the identification slug box should appear (measured in the appropriate CPI for the form (usually 10 CPI)). 'prtseq' is a character variable that will be filled with an escape sequence used to print the slugs for the passed line at the passed horizontal offset. You should use the 'PUT-CONTROL' service in 'prntutil' to write this out since it may contain specially quoted escape characters.
The 'prtseq' doesn't depend on the print header being anywhere and the location of the print head after printing is undefined. You should print any textual data that will appear on the line *BEFORE* printing the 'prtseq' variable. In addition, it is your responsibility to move the printhead to the next line when you printed all the slug marks you intend on printing (using a PUT .... SKIP perhaps).
You can 'optimize' things a bit by checking the length of 'prtseq' on return. If it's 0, then you do not need to print anything for the current line.
After the last slug line is returned, the 'prtseq' is returned with the value "DONE" in the string.
You must call and print SLUGS INITIALIZE before using this service.
LIST BATCH (batchid) LIST SHEET (sheetid) LIST SHEET makes an attempt to provide useful information about
each sheet. The validity and usefullness of the data is highly
dependent on you setting the appropriate values into the 'scan-form-sheet'
buffer after the sheet was created.
LIST SCAN_DEVICE (deviceid) SCANNER OPEN (status) SCANNER CLOSE (status) SCANNER READ_SHEET (readstat) (sheetid) (dataset#) (sheetdata) 'readstat' is a character and can be returned with one of the following:
sheetid is the ID of the sheet associated with this sheet or ? if
a valid sheet wasn't read.
dataset# is the dataset number associated with the form. If the
sheet doesn't have datasets, this will be returned as 0.
'sheetdata' is a character with the data returned from the scanner,
less the sheet identification (which has been stripped off). No
other processing is done to the line.
SHEET_PRINTED SHEET_SCANNED LINE_SCANNED (mark) (mark#) (flush) You should do each LINE_SCANNED before using SHEET_SCANNED. You must
has previoustly loaded a line with either LOAD LINE or CREATE LINE.
scanutil will do quite a bit of work for you, but should be aware of
how it expects to deal with the various scanner-device.device-types:
Of all the options outlined below, the only required module is the
scannner-device.device-read-spec field.
There are two types of 'helpers' in a filter - O/S modules and
Progress modules. All O/S module definition fields end in '-spec' and
all Progress module definition fields end in '-mod'.
The basic calling order during an open is
Sheets are read via form-bldg.scanner-read-mod.
The basic calling order during a close is
All modules, except the 'scanner-device.device-read-spec' and the
'form-bldg.form-read-sheet-mod' are optional.
O/S modules receive the following parameters on the command line
The device-parm and form-parm are quoted to preserve any spaces. All
O/S modules are expected to echo a 'OKAY' to stdout if they are OK. All
O/S modules, except the scanner-device.device-read-spec, are expected
to complete their work and return 'OKAY' (or an error description if
there was an error) immediatly.
scanner-device.device-read-spec has a special form when responding.
When done initializing, it should send an 'OKAY' out and then, on the
next line, some combination of these flags:
If neither are present, the default is a non-interactive scanner that
cannot be stopped except by the user pressing the end of batch key.
When at all possible, you want your scanner to support interactive
and cancel facilities.
Progress modules receive the following parameters
ReadProcedure, WriteProcedure and Procedure handle provide you
with the tools to read/write from a stream. This is because you
cannot pass/share streams. Their calling format is:
ReadProcedure will return one line at a time. WriteProcedure will
write the text out and will not append any line terminators.
WriteProcedure uses the 'prntutil.i PUT-CONTROL' mehtod to handle
the need to write NUL characters to the stream (see prntutil for
more info).
If ReadProcedure encounters an error trying to read data from the
scanner, the string '*** READ ERROR ***' is returned.
The form-bldg, scanner-model and scanner-device buffers just serve
as references that a program can use.
The module is expected to return 'OKAY' in 'ReturnStatus' on
completion or an explanation if there was an error.
Device scanner types are not currently supported and will always
return a 'BAD_DEVICE' status if called. (3/25/95)
Note: scanutil.i depends on the scanner being able to some limited
forms processing. This should involve interpretting marks and sending
back ASCII, human readable results. This pretty much outs old scanners
like ScanTron 5200 and earlier, but should work great with ScanTron
8200's, NCS's OpScan line and any other scanner designed within the last
few years.
Note: mark resolution should be as follows. A field with illegal
multiple marks should have a '*' as the multiple-mark character. A
field with no mark, even if it's required, should send a space back.
Scanner Form header
The scanner form header consists of space delimited fields. They
are (in order):
The numeric strings can be zero filled or not (i.e. "000123" is as good
as "123"). There must be at least one field after each field (more than
that is OK as well) except the last field.
This header information is processed by scanutil itself before returning
wether a sheet is OK or not. This data is stripped from the received
data string before being returned to you so there is no additional
processing needed before beginig the processing of the scanned info.
The actual scan data begins immediatly after this last field with
no intervening spaces or other characters.
If your scanner puts things in fron of each record (like NCS OpScans), then
use the scanner-model.sheet-preamble-len field to say how many characters
should be stripped off.
Received data:
When the sheet is read, the ID, check sum and dataset numbers
(and terminating spaces) are removed from the string and the remainder
of it is passed back to the caller for final interpretation. No trimming
or cleanup on the string is done at all.
Presents the user with a listing of the various batches for the
previously selected form. 'batchid' is the ID (not RECID) of the
batch to start the lister on. If passed as '?', then an attempt
is made to find the best starting point in the batches (using
dates). On return, 'batchid' is the ID of the batch the user
selected or "?" if the user hit
Presents the user with a lsiting of the various sheets for the
previously selected form/batch. 'sheetid' is the ID (form-seq, not
RECID) of the sheet to start the lister at. On return, it is either
the form-seq of the sheet selected or ? if the user pressed
Present the user with a list of the various scanner devices. We'll
make sure the user selects a scanner the is compatible with the selected
form. You must have 'SET FORM' before calling this lister. If the
user successfully chooses a scanner, the device-id of it is returned.
If the user cancels, then ? is returned.
This will open the selected scanner, initialize it and prepare it to
read the sheets from the scanner. You must have previously set the
building, form and scanner device in place. If the open is successful,
'status' is passed back with 'OKAY' in it. Consult the discussion on
interface modules for list of supported failure codes.
as TRUE.
This will close the previously opened scanner device and cleanup
any working files and/or OS dependencies. 'status' will have 'OKAY'
in it if the close was successful, or one of the listed failure types
if not.
This will attempt to read a sheet from the previously opened scanner
device. This will attempt to read the sheet header and find the
form identification. If that is succesfull, the sheet is loaded
internally and the ID of the sheet is returned, along with the scan
data.
Marks the last sheets loaded/created as printed. This sets the printed
flags for the sheet and batch. You should do this only AFTER you have
actually printed the sheet. You cannot work with the scan sheet after
this call (think of it as 'releasing' the sheet.
Marks the last sheet read from the scanner as actually being read. This
is used becuse a sheet may prove to be 'unread' if it seemed OK but
contained invalid data. You should mark a sheet read only AFTER you
have journal the sheet data to the database. You cannot access the
scan sheet data after this call (it 'releases' the data).
Marks the last line read from the scanner as actually read and sets the
raw scanner marks into the record. 'mark' is the text of the raw mark
to save for the line. This should be exactly what you received from
the scanner, don't "cook" it!. 'mark#' is the mark on the sheet to record
(1-64). Most sheets only use mark #1 (grade sheets may use more, for
example). 'flush' should be set on the last LINE_SCANNED call for a
given line. Since multiple marks may need to be recorded, we can't
auto-flush it.
Scanner Protocol for support mods
Scanning is a complex area. There all types of operating system issues,
scanner issues and communications issues. This doesn't even touch on
the vaugaries or interpretting data.
File
Files are very simple. The device specification in the scanner-device.
device-read-spec is checked to see if it's an O/S file and if so, it
is opened for additional input. Eventually, a token will be allowed
in the 'device-read-spec' to allow interactive prompting. File types
are intended for folks who do the scanning on a PC and the xfer the
resultant file over the the system for importation.
Filter
Filter's are only available on Unix and heavily use the O/S pipe facility.
They give you a great deal of power, but can be harder to work with.
Device
Devices are intended for systems without pipes that still need to
be able to directly interface with a scanner. This is generally
much less flexible than a 'Filter' reader, but the only option for
other systems.
Return Status values
The interface routines can expect to return a status code as a character
variable. These codes are eventually returned to the user so they can
apprise the end-user why something worked or didn't. This is the list
of supported codes:
Notes on scanner form design
In order for a scanner sheet to be compatible with the scanutil
services, the output from the scanner must follow some basic guidelines.
Last update: October 31, 1995