External application interface in AlphaTcl
Name: | Xserv |
Version: | 2.2 |
Last update: | 2020-10-21 07:12:05 |
This file constitutes the programming guide for the xserv extension
of AlphaTcl. This extension allows the definition of interfaces for
external services, and the declaration of implementations of these services
with other applications.
For more basic information about the xserv system, see the
Xserv Help.
The implementation
Known problems
License and Disclaimer
Index
Introduction
The xserv extension provides the minimal features that
allow AlphaTcl to drive external applications through well
defined interfaces. Each interface defines a standard way to ask
for a service, no matter which application is used to provide it.
Since these services are provided by applications other than
Alpha, we call them "external services" or XSERVs.
An XSERV describes a service which may depend on parameters. For
instance, we can consider a openURL
service which displays an URL.
Its behavior depends obviously on the URL we want to display, so this
service will have a url
parameter.
There are generally several means to provide the service described by
an XSERV: we can use any browser to display an URL. However, each
browser has its own syntax for performing the requested action.
For each possible implementation of a service, we need to describe
how to build the request for the application from the parameters of
the XSERV. This task is handled be a "driver" script and depends on
the invocation mode of the implementation. The current version of
xserv supports the following implementation modes:
- App
- a Mac OS application is launched, and the driver communicates with it by
Apple Events to provide the service;
- Shell
- a program is launched with the output of the driver as its standard input;
- InSh
- a program is launched, and the output of the driver is written to its
standard input. A window displays the output of the program and acts as a
console. The interactive run of the program in the window relies on the
InSh
Alpha mode;
- Exec
- the driver returns a command line which is executed by the [exec] Tcl command;
- Alpha
- the driver uses AlphaTcl commands to provide the service (not
really an external service, but sometime useful).
Once an XSERV has been declared and implementations of this service have
been registered, we should be able to choose an implementation and to
invoke the service. The choice of an implementation may be driven by
personal taste or by the availability of some applications on a given
platform.
Usage
Basic functionalities
An XSERV is declared with the proc xserv::declare:
xserv::declare xserv_name description param*
where xserv name is the name of the new service, description
is a textual description of the role of the service, and each param
is either the name of a parameter or a list containing the name of a
parameter and its default value.
xserv::declare
returns 0 if it fails to declare the service (for
instance if the service is already declared), and 1 if the service
declaration was successful.
For instance, the following code:
xserv::declare viewURL {Display an URL} url
declares an XSERV named viewURL
which takes a url
parameter and
provides a service described by the sentence "Display an URL";
while:
xserv::declare TeX "Typeset a file with TeX" file {format latex}
declares an XSERV named TeX
which takes a file
and a format
and
provides a service described by the sentence
"Typeset a file with TeX". If the format
parameter is not
given a value when the service is invoked, latex
will be used as its
default value.
Once a service has been declared, we can register applications that implement
this service with the proc xserv::register:
xserv::register xserv_name impl name (key value)+
- xserv name is the name of the service which is implemented by the
application;
- impl name is the name of the implementation of the service. This is
a symbolic name which is only meant to be used by human beings and may be
different from the real program name;
The list of key-value pairs defines how this implementation provides
the service. Any key is allowed, but the current version interprets
only the following keys:
- -bund
- the associated value is the bundle identifier of the Mac OS
application used to provide the service;
- -path
- the associated value is the path to the program used to provide the
service;
- -shell
- the associated value is the name of the program which will receive the
value returned by the driver script on its standard input;
- -driver
- the associated value is the Tcl script which will drive the external
program according to the parameters. This script will find the value of the
parameters in the
params
array. The params
name is the only
"reserved" name in the context of the driver script. If the XSERV has a file
parameter, the driver script will find the value of this parameter
in $params(file)
.
The xservTarget
parameter is added to the parameter array in the
App
invocation mode. Its value is the target process to which
Apple Events should be sent.
The xservInteraction
parameter is added to the parameter array in
all invocation modes. Its value is 0
when the user should not
interact with the application (background invocation) and 1
when
the user should be able to interact with the application (foreground
invocation).
All parameter names beginning with xserv
are reserved for future
extensions of xserv.
For the Exec
and Shell
invocation modes, the driver
should return a list of words. xserv will take care of escaping
spaces within these words so that the shell or the exec command receive a
command line containing the words of the list.
For the App
and Alpha
invocation modes, the driver should
execute the AlphaTcl commands required to obtain the desired
result.
- -mode
- the associated value is the invocation mode of the implementation, as seen
above. It may be omitted, in which case it will be set to
App
if
the bund
or the sig
key is present, to Shell
if the
shell
key is present, and to Exec
in the other cases.
- -progs
- the associated value is a list of command-line programs which are needed by
the driver script. When using this implementation of the service,
xserv
will find where these programs are, asking the user if several copies
are available or if no such program can be found in the command path. For
each program named prog in this list, a variable named xserv-prog will be available to the driver script, and its value will
be the full path to the prog program to use.
To register Internet Explorer as an implementation of the viewURL
service on Mac OS, we could write:
xserv::register viewURL "Firefox" \
-bund [app::getID Firefox] \
-driver {
tclAE::send $params(xservTarget) WWW! OURL ---- \
[tclAE::build::utf8 $params(url)]
}
Internet Explorer is identified by its MSIE
creator code.
The script uses the OURL
Apple Event from the WWW!
suite to ask
Internet Explorer to display the URL. $params(url)
will expand to the
value of the url
parameter of the XSERV when it is invoked.
$params(xservTarget)
will expand to the name of the Internet
Explorer application. This application will be found by asking the
system for an application with creator code MSIE
, or by asking
the user to locate it if the system cannot find it.
Of course, it is possible to register several applications for one
service. If we want to use Safari for viewURL
, we can write:
xserv::register viewURL "Safari" \
-bund [app::getID Safari] \
-driver {
tclAE::send $params(xservTarget) GURL GURL ---- \
[tclAE::build::utf8 $params(url)]
}
If several applications with the same bundle identifier exist, it is
possible to choose which one to register as an implementation of a
service by giving a path to the application:
xserv::register viewURL "Firefox" \
-bund [app::getID Firefox] \
-path {/Applications/Firefox} -driver {
-driver {
tclAE::send $params(xservTarget) WWW! OURL ---- \
[tclAE::build::utf8 $params(url)]
}
When a path is given, the signature can be omitted because it is not
needed to find the application. However, if you omit the
signature, you should set the invocation mode to App
because it will
no longer default to this value. Moreover, if the signature is given,
xserv
will be able to find the application if it is not in the
expected folder.
If two or more applications with the same creator code and the same
base name exist on your Macintosh, xserv will be able to
launch the right one if you gave a path when you registered the
application. However, if one of these applications is already
running, xserv won't be able to distinguish it from the
one you want to use. This is because the processes
Alpha command
gives only the base name of the running applications, not their full
path.
To choose an implementation among the declared ones for a service, we
use the proc xserv::chooseImplementationFor:
xserv::chooseImplementationFor xserv_name impl name group?
where xserv name is the name of the service, and impl name is
the name of the implementation, as given to xserv::register
. The
optional group allows to choose different implementations of
a service in different contexts. For instance, you could define a
View HTML Help group and a Edit HTML group, and choose the Apple Help
Viewer for the View HTML Help group and Internet Explorer for the
Edit HTML group. When you invoke a service for a group, the
settings for this group are used. If you don't specify a group, the
default group (whose name is the empty string) is used.
For instance, to choose Internet Explorer as the implementation of
viewURL
for the default group, write:
xserv::chooseImplementationFor viewURL Explorer
To choose Apple Help Viewer as the implementation of
viewURL
for the View HTML Help group, write:
xserv::chooseImplementationFor viewURL Explorer {View HTML Help}
When an implementation is chosen for a service, it is validated by
xserv
. The validation ensures that everything needed by the
implementation is available.
To request a service from an XSERV, use the proc xserv::invoke:
xserv::invoke interaction xserv_name args
- interaction tells whether we want the user to be able to interact
with the application or not.
-foreground
indicates a possible
interaction, and the application will be brought to front. -background
denies the possibility to interact with the application, which will be
launched in the background;
- xserv name is the name of the service to invoke;
- args is a list of key-value pairs, the keys being the parameter
names (with an optional leading '-' to make it clear that they are
parameter names), and the values being the values of the corresponding
parameters for this invocation.
Thus, to display the http://wwwsi.supelec.fr/ URL with the current
implementation of viewURL
, write:
xserv::invoke -foreground viewURL -url http://wwwsi.supelec.fr/
To request a service from an XSERV in the context of a particular
group, use the proc xserv::invokeForGroup:
xserv::invokeForGroup group interaction xserv_name args
which does the same as xserv::invoke
but uses the current settings
for the group instead of the settings for the default group.
If no implementation has been chosen when a service is invoked, a
dialog allows the user to choose an implementation among the
registered implementations of the service. If an implementation has
been chosen for the default group, it will be pre-selected in the list.
Invocation hooks
From version 1.2, xserv can call procedures after a service has
been invoked. These procedures receive four arguments:
- the name of the service;
- the result of the invocation;
- a list which describes the implementation of the service used
for this invocation;
- the list of paramaters of the invocation.
The last two parameters are key-value lists suitable for use with [array set].
To add a procedure to the list of procedures which will be called
after a service has been invoked, use
the proc xserv::addEndExecHook:
xserv::addEndExecHook xserv_name proc
xserv name is the name of the service, and proc is the name
of the procedure to call. This procedure must take four parameters as
described above.
To remove a procedure from the list of procedures which will be called
after a service has been invoked, use
the proc xserv::removeEndExecHook:
xserv::removeEndExecHook xserv_name proc?
xserv name is the name of the service, and proc is the
name of the procedure to remove. If proc is omitted, all the
procedures in the list will be removed.
If the list is empty or does not contain proc,
removeEndExecHook
will do nothing.
Categories
From version 1.3, xserv can group services into categories.
The only purpose of categories is to help the user navigate the list
of services. A service may belong to several categories if this
helps the user find the service. For instance, the dvips
service
which is used to produce a PostScript file from a DVI file may
belong to the DVI
and PS
categories.
To add services to a category, use
the proc xserv::addToCategory:
xserv::addToCategory category name xserv_name+
category name is the name of the category (which will be
created if it doesn't exist), and xserv name+ are the
names of the services to add to the category. A service may be added
several times to the same category.
To remove services from a category, use
the proc xserv::removeFromCategory:
xserv::removeFromCategory category name xserv_name+
category name is the name of the category, and
xserv name+ are the names of the services to remove
from the category. It is not an error to remove a service from a
category it doesn't belong to.
To get the categories a service belongs to, use
the proc xserv::getCategoriesOf:
xserv::getCategoriesOf xserv_name
xserv name is the name of a service. The result is the list
of the names of all categories the service belongs to. If the service
does not belong to a category, the list is empty.
Categories are used to group services when the user wants to choose
an implementation for a service using the
Alpha ↣ Global Setup ↣ Helper Applications
menu item. First, the list of all
categories is displayed (including the special category
* no category * which contains all services that do not belong to
a category). When the user chooses a category, the list of all
services in this category is displayed. Then, when is selects a
service, the list of all registered implementations of this service
is displayed. If the service has only one mandatory argument, the
special item labeled * Other * allows to build a generic
implementation of the service.
If there is only one category, the first dialog is skipped.
Bundles
From version 1.3, xserv can group services into bundles.
A bundle is a set of services that are always provided by the same
application, so chosing an implementation for one of the services
of the bundle selects the same implementation for all other services
in the bundle. When a service is part of a bundle, it is hidden to
the end-user who may only choose an implementation for the whole
bundle.
To declare a bundle, use
the proc xserv::declareBundle:
xserv::declareBundle bundle name desc xserv+
bundle name is the name of the bundle. This name will appear
as a service name to the end-user. desc is the textual
description of the bundle, and xserv+ are the services
which are part of the bundle.
Bundles are intended to group the services provided by applications
which have a notion of 'session'. Opening the session, performing
some operations and closing the session must obviously be performed
with the same application, so it doesn't make sense to select
different implementations for each of those services. Grouping the
services into a bundle hides them to the end-user and makes them
appear as a single bundled service.
Generic implementations
Since version 1.3, xserv allows the creation of generic
implementations for services which have only one mandatory argument.
Implementing such services generally amounts to sending an Apple
Event to an application, with the argument as direct object, or to
execute a command-line containing the name of the program and the
value of the argument. So, if the end-user wants to use an
application which is not registered as an implementation of such a
single-argument service, xserv can build a generic driver
for this application quite easily.
Generic implementations of a service can be created from any dialog
which allows to choose an implementation for a single-argument
service. In the list of registered implementations of the service,
a special item named * Other * appears if the service has only one
mandatory argument. When this item is chosen, a two-page dialog
appears: the first page is for building a generic driver for
Apple Event applications, the other page is for building a generic
driver for command-line programs.
Building a generic Apple Event driver
For a generic Apple Event driver, the user must enter the name of the
application in the "Application" text field. It is also possible to
give the signature or creator code of the application between single
quotes. For instance, on a Macintosh, using 'ttxt' will select the
TextEdit or the SimpleText application, depending on the version of
Mac OS. Using TextEdit
will select the TextEdit application, and
the user will be asked to locate it on the disk.
Then, the user must choose the class and the code of the Apple Event
that will be sent to the application. These fields default to aevt
and odoc
since this is the most frequent choice. odoc
may be
replaced by pdoc
if the service is for printing a document.
Last, the type used for the parameter in the Apple Event must be
chosen in a pop-up menu between file
and text
. The default is
file
since it is the required type for an odoc
event.
Building a generic command-line driver
For a generic command-line driver, the user must enter the name of
the program in the "Program field". This can be the short name of
the program or its full path name.
Then, the user must choose the invocation mode among InSh
, the
interactive shell mode, Shell
, the non-interactive shell mode, and
Exec
, the raw subprocess execution mode. The default is InSh
since it is the most user-friendly mode for command line tools.
Last, the user must give the general form of the command line for
this program in the "Command line" field. The default value is:
<prog> $params(name)
<prog> will be replaced by the full path to the program when the
service is invoked. name is the name of the only mandatory
argument of the service, so $params(name)
is the value
of this argument.
This field can be edited to make the command line suit the syntax
required by the program or to add options. For instance, if the
argument must be preceded by -input= and if we want to use the
-verbose
option of the program, we can write:
<prog> -verbose -input=$params(name)
More about XSERVs
The xserv code defines other commands to work with
services. It is possible to suppress a service or a bundle with
the proc xserv::forget:
xserv::forget xserv_name
which suppresses the service or bundle named xserv name and
all its implementations.
Forgetting a service that does not exist causes no harm. Forgetting
a bundle does not forget its members but makes them available as
individual services.
The declaration of a service works only if the service is not already
declared. This is necessary to avoid that former implementations be
invoked and try to use parameters that do not exist any longer in the
new service. So, before declaring a service, you can safely use
xserv::forget
to make sure your declaration will be successful.
To know which application currently implements a service, use
the proc xserv::getCurrentImplementationsFor:
xserv::getCurrentImplementationsFor xserv_name
which returns a list of group-implementation pairs.
This list can be used with [array set] to set an array containing the
current implementation of the service for each group. Each value in
this array is itself a list which describes the implementation.
This list is suitable for use with [array set] and contains the name
of the implementation (as given to xserv::register
) under the
-name
key. From version 1.3, xserv uses other keys such
as -path
to store the path to the program or application, and
-progs
to store the absolute path to any command-line program
needed by the implementation.
Describing the implementation choice with a list allows for future
extensions like setting default values for parameters or for the
interaction mode when chosing an implementation.
You can get the list of all known services with
the proc xserv::listOfServices:
xserv::listOfServices which?
which returns an alphabeticaly sorted list of the declared services.
The which argument may take one of the following values:
- all
- asks for the list of all services, including bundles
and bundle parts;
- bundles
- is the default value and asks for the list of all
services, excluding bundle parts (this is what
should be used when presenting the list of services
to the end-user);
- nobundle
- asks for the list of all services, excluding
bundles (but including their parts). This is the
list of all "real" services.
To get the list of the registered implementations of a service, use
the proc xserv::getImplementationsOf:
xserv::getImplementationsOf xserv_name
which returns an alphabeticaly sorted list of all registered
implementations of xserv name.
From the name of a service, you can get its description with
the proc xserv::describe:
xserv::describe xserv_name
which returns a key-value list describing the service
named xserv name. The possible keys in this list are:
- desc
- the description of the service, as given to
xserv::declare
;
- args
- the argument list of the service, as given to
xserv::declare
;
- implementations
- the list of the registered implementations of this service. This is a
key-value list, and each key is the name of an implementation of the
service as given to
xserv::register
, while the associated value is
a list which describes the implementation (it is the key-value list given
to xserv::register
).
The implementation
xserv is an extension for AlphaTcl. It inserts the
Alpha ↣ Global Setup ↣ Helper Applications
menu item which allows to choose the external applications used to
implement the declared services.
The quitHook
is used to save the service declarations,
implementation registrations and per group implementation choices
in Alpha's preference folder.
xserv adds the search paths set for the "Exec search
path" in the miscellaneous package preferences, to the env(PATH)
global variable so that exec
finds executables along these paths.
the "Exec search path" can also be set in the dialog displayed by
the Helper Applications... item of the
Alpha ↣ Global Setup menu.
Last, xserv reads its preferences which were stored in
the arrdefs.tcl file the last time Alpha has quit.
Proc xserv::nameFromAppl
The xserv::nameFromAppl
procedure fixes a problem with
nameFromAppl
on Mac OS X where the /Volumes mount point
is missing for applications stored on another volume than
the startup volume. This fix may no longer be necessary when the
problem is fixed in AlphaTcl.
Proc xserv::fixExecSearchPath
The xserv::fixExecSearchPath
proc adds the paths in the global
variable execSearchPath
to the env(PATH) variable which is used
by exec
to look for executables. The value of the execSearchPath
variable can be set in the "Miscellaneous packages" package
preference dialog. It is set to some arbitrary value in
alphaDefinitions.tcl, but the updateExecSearchPath
procedure seems
not to be called when the pref is changed.
Managing categories
Categories are used to group services so that it is easier for the
end-user to navigate the list of services.
Proc xserv::addToCategory
The proc xserv::addToCategory
adds services to a category. The
category is created if it doesn't exists. The services added to the
category may not be declared yet (only their names are used).
cat is the name of the category. All remaining arguments are
considered as the names of the services that should be added to the
category. A service may be added several times to a category, it
will appear only once in this category.
The services in the different categories are stored in the ::xserv::categories
global array which is indexed by the name of the category.
Services are added to a category only if they do not already belong
to it.
Proc xserv::removeFromCategory
The proc xserv::removeFromCategory
removes services from a category.
cat is the name of the category. All remaining arguments are
considered as the names of the services that should be removed from
the category. A service may be removed from a category even if it
does not belong to it.
Proc xserv::getCategoriesOf
xserv::getCategoriesOf
returns the list of all categories to which
a service belongs (a service may belong to several categories).
Declaring and forgetting XSERVs
Proc xserv::declare
The xserv::declare
procedure declares a new XSERV. Each XSERV has a
name, a textual description and a set of formal parameter names.
xservname is the name of the new XSERV, desc is
some text that describes what this XSERV is for, and the remaining
arguments args are the names of the parameters of the XSERV.
Each item in args may be either a single parameter name
or a two item list {"parameter name" "default value"}.
The XSERVs are stored in the ::xserv::services
global array which is indexed by the name of the XSERV.
If the XSERV already exists, it cannot be declared again (it must be
forgotten first). In this case, xserv::declare
returns 0
to
indicate the failure.
If the XSERV does not exist, we store its declaration in the ::xserv::services
array. This declaration is a list in a form suitable for use with [array set].
Proc xserv::declareBundle
The xserv::declareBundle
procedure declares a bundle of services.
All the services in a bundle use the same implementation and are
therefore presented to the end-user as a unique bundled service instead of
several apparently unrelated distinct services.
bundleName is the name of the bundle. It plays the same role
as the name of a service. desc is a textual description of
the bundle which may help the user understand what this "bundled"
service is for. The remaining arguments are the services which are
part of the bundle.
Proc xserv::forget
The xserv::forget
procedure suppresses a service and all its
implementations. It is not an error to use it for a non-existent
service.
When used on a bundle, xserv::forget
suppresses only the bundle,
not the services that were part of it.
Saving and reading settings
Proc xserv::saveXservDeclarations
The xserv::saveXservDeclarations
procedure saves the declarations of
the XSERVs to a file so that they can be reloaded later.
Proc xserv::saveXservCategories
The xserv::saveXservCategories
procedure saves the definitions of
the categories of services to a file so that they can be reloaded later.
Proc xserv::saveXservImplementations
The xserv::saveXservImplementations
procedure saves the declarations of
the XSERV implementations to a file so that they can be reloaded later.
Proc xserv::saveXservSettings
The xserv::saveXservSettings
procedure saves the group choices of
the currently selected implementation for XSERVs, so that these settings
can be restored later.
Proc xserv::saveAll
The xserv::saveAll
procedure saves the whole state of the XSERV
package: XSERV declarations, categories, implementation declarations
and chosen implementations (per group) for each XSERV.
Proc xserv::saveToPrefs
The xserv::saveToPrefs
procedure saves the whole state of the XSERV
package into the arrdefs.tcl file in the preference folder.
Proc xserv::readPrefs
The xserv::readPrefs
procedure restores the state of the XSERV package
to the state saved in the arrdefs.tcl file in the preference folder.
Getting information about the XSERVs
Proc xserv::listOfServices
The xserv::listOfServices
procedure returns the list of all declared XSERVs.
It builds this list from the names in the ::xserv::services
array. The list is sorted so that it can be used to let the user pick
an XSERV in a dialog.
which tells which services we want in the list. It can take
one of the following values:
- all
- asks for all services, including bundles and their parts;
- bundles
- asks for all services, excluding bundle parts
(this the list an end-user should see);
- nobundle
- asks for all services, excluding bundles (this is
the list of all "real" services).
Proc xserv::describe
The xserv::describe
procedure returns the description of an XSERV in
the form of an empty list if the XSERV does not exist or a list
suitable for use with [array set] containing the following entries:
desc
: the textual description of the XSERV;
params
: the list of the parameters of the XSERV, with default value
when applicable (the parameter is then a two element list, the first
element being the name of the parameter and second its default value);
implementations
: the list of all registered implementations of
the service. This is a key-value list, and the entries are the registered names
of the implementations. The associated values are [array set]-like lists with as
many entries as necessary to describe the corresponding implementation.
Usual entries are:
-mode
: gives the invocation mode (App for a MacOS
application, Exec for a Unix application, Shell for a
command line to be interpreted by a shell, Alpha for a Tcl script
to be evaluated by Alpha);
-bund
: the bundle identifier of the application, if applicable;
-path
: the path to the application, if applicable;
-driver
: the script that drives the application according to
the parameters of the XSERV.
The ::xserv::services
global array contains the declarations of the
XSERVs, as seen in the
Proc xserv::declare
section.
The description is an empty list if the XSERV does not exists.
If the XSERV exists, we just return its description:
Proc xserv::getBundleName
xserv::getBundleName
returns the name of the bundle thah contains
a service, or an empty string if the service is not part of a bundle.
Proc xserv::isBundle
xserv::isBundle
tells if a service is a bundle or a "real"
service.
Proc xserv::getImplementationsOf
The xserv::getImplementationsOf
procedure returns the list of the
names of all registered implementations of the XSERV xservname
.
This list is sorted so that it can be used to let the user pick an
implementation in a dialog.
Proc xserv::getCurrentImplementationsFor
The xserv::getCurrentImplementationsFor
procedure returns the name of the
implementations that are used as current implementations of an XSERV.
The result is a key-value list (suitable for use with [array set])
with the groups as keys and the current implementation for the group
as value. The current implementation for a group is a key-value list.
The only mandatory key for now is -name
which identifies the name of the
implementation, as given to xserv::register
. Other keys may be used
to extend the notion of "current implementation".
As of version 1.3, the -path
key identifies the absolute path of
the application or program used for the implementation, and the
-progs
key identifies the list of the absolute paths of the
command-line programs needed by the implementation.
It is an error to call this procedure on an XSERV that does not
exist. If the XSERV exists and no application has been chosen for it
yet, we return an empty list:
Working with implementations
Proc xserv::register
The xserv::register
procedure registers an implementation of
an xserv.
xservname is the name of the implemented XSERV.
implName is the name we want to use to refer to the
implementing application.
args is a [array get]-like list which describes the implementation.
For instance, if application CMacTeX of signature *XeT
supports the
"tex" XSERV, it can be registered with the following call:
::xserv::register pfa2pfb CMacTeX \
-bund [app::getID CMacTeX_t1utils] \
-driver {
[snip...]
}
The -bund argument indicates that this implementation is identified
by a MacOS bundle identifier here). The -driver argument says that
to implement the "tex" XSERV with CMacTeX, one should execute
buildNewCMacTeXAE ....
The driver script can retrieve the values of the arguments to the
service invocation in the params
array. params
is the only
special name introduced by xserv in the context where the
script is executed.
Two additional arguments are always added to the params
array :
xservTarget
contains the value of the Apple Event target
when the implementation is a Mac OS application (App
invocation
mode);
xservInteraction
indicates whether the implementation
should be put to the foreground (1) or let in the background (0).
To allow future extensions of xserv, all parameter names
beginning with xserv
are reserved.
From version 1.3, when an implementation is registered with a list
of programs (using the -prog
key), the absolute path to each
program prog of the list is available in the
xserv-
prog entry of the params
array.
Proc xserv::forgetImplementation
The xserv::forgetImplementation
procedure unregisters an implementation
of an xserv. This procedure cannot be used with bundles since the
implementations of a bundled service are "virtual" (they are the
implementations which are common to all the members of the bundle).
Proc xserv::chooseImplementationFor
The xserv::chooseImplementationFor
procedure allows to choose the
implementation to use for an XSERV, among the registered implementations.
Several settings may be remembered for different groups of users,
or clients of the service. A default group is used when no group is
specified.
For instance: ::xserv::chooseImplementationFor tex CMacTeX chooses
CMacTeX to implement the tex
service for the default group, while
::xserv::chooseImplementationFor tex teTeX docgen chooses teTeX
to implement the tex
service for the docgen
group. This
implementation will be used when the tex
service is invoked for
the docgen
group, while CMacTeX will be used when no particular
group is specified.
The implName
argument may be a single item, in which case it is
considered as the name of the chosen implementation. It may also be
a key-value list if data other than the name of the implementation
must be associated to the choice. This key-value list must contain a
-name
key with the name of the implementation as its value.
The special implementation name * Other * is used to build generic
implementations for services which have only one mandatory argument.
For instance
::xserv::chooseImplementationFor tex {-name CMacTeX -format hlatex}
may be used to choose CMacTeX as the implementation of the tex
service and to give hlatex
as the default format to use.
In the current version of xserv, only the -name
, -path
and -progs
keys may be interpreted, but the list structure of
the implName
argument allows for future extensions.
If the name of the implementation is * Other *, build a generic
implementation and return it.
If the service is a bundle, we must set the implementations of
all the members of the bundle.
When the implementation of a service is changed, we call the
global implementation-change hooks and the implementation-change
hooks which are specific of this service.
Proc xserv::chooseImplementationForBundle
The xserv::chooseImplementationForBundle
procedure is used to choose
an implementation for a bundle of services. This amounts to choose
the same implementation for each member of the bundle.
Working with generic implementations
Generic implementations allow the end-user to implement a service
with an application or a program which is not registered as an
implementation of this service. Generic implementations are
restricted to services which have only one mandatory argument, so
that the driver of the implementation uses a simple 'aevt'/'odoc'
apple event or a "prog argument" command line.
Proc xserv::addGenericImplementation
The xserv::addGenericImplementation
procedure displays the dialog
used to create a generic implementation of a service. This dialog
has two pages, one for Apple Event driven applications, the other
for command-line programs.
Generic implementation for services with more than one mandatory argument
are too complex and too error prone, so they are not supported.
Proc xserv::mandatoryArgsOf
xserv::mandatoryArgsOf
returns the list of all mandatory
arguments of a service (the arguments which don't have a default
value).
Proc xserv::addGenericCommandLine
xserv::addGenericCommandLine
processes the data from the "command
line" page of the generic-implementation dialog to register a generic
command-line implementation.
Generic implementations are tagged with a -generic
key so that they
van be distinguished from "supported" implementations. The value associated
to this key is the registration date of the implementation in ISO format.
Proc xserv::addGenericAppleEvents
xserv::addGenericAppleEvents
processes the data from the "Apple
Event" page of the generic-implementation dialog to register a generic
Apple Event implementation.
Proc xserv::getGenericImplementationsOf
xserv::getGenericImplementationsOf
returns the list of all generic
implementations of a service. Generic implementations are identified
by the presence of a -generic
key in their definition.
Proc xserv::deleteGenerics
xserv::deleteGenerics
displays a dialog to let the user select
a generic implementation and delete it.
From the list of services, we build the list of services which have
at least one generic implementation.
Then, we sort these implementations according to the
category of the service they implement.
We remove the categorized implementations from the noCat
list
of the implementations with no category.
If there are implementations with no category, we add a special
* no category * category for them.
We ask the user to confirm the deletion of the implementation.
Proc xserv::deleteGenericImplementation
The procedure deleteGenericImplementation
is a wrapper around
xserv::deleteGenerics
, and is used as the callback for the
"Delete generic implementation" menu item.
Validating implementation choices
Since version 1.3 of xserv, an implementation is
validated when the user chooses it, and before it is invoked.
The validation process should ensure that everything needed by the
implementation is available. Information gathered during validation
and which will be used at invocation time should be stored in the
implementation choice, which is a key-value list.
A validation procedure is called automatically if it exists. When
an implementation is selected or is about to be invoked,
xserv looks for a procedure named
xserv::validateImpChoice
mode, where mode is the
invocation mode of the implementation. If no such procedure exists,
the implementation is considered to be valid. If the procdure
exists, it is called with two arguments: the implementation choice
and the registered implementation.
The procedure should return an empty list if the implementation
could not be validated, or a key-value list containing all
necessary information for an invocation to succeed.
Proc xserv::validateImpChoiceApp
The procedure xserv::validateImpChoiceApp
validates an
implementation choice for the App
invocation mode. It checks that
the application exists and adds its absolute path to the
implementation choice under the -path
key.
If choice
has a -path
key which leads to an existing file with
type 'APPL' (or with no type on Mac OS X), we consider it as a valid
implementation.
If choice
has no -path
key, we must look into the registered
implementation for either a path or a signature. The first piece
of information which leads to an existing application is used.
If we couldn't find an application (the path is wrong, or the Finder
data base couldn't give a path from the signature), ask the user to
locate the application. Remove a possible ".app" extension on
Mac OS X.
Proc xserv::validateImpChoiceExec
The procedure xserv::validateImpChoiceExec
validates an
implementation choice for the Exec
invocation mode. It checks that
the program exists and adds its absolute path to the implementation
choice under the -path
key. It also checks that all the programs
listed under the -progs
key exists and adds their absolute paths to
the implementation choice under the -progs
key.
For each program name under the -progs
key in the implementation
registration, check that a valid program is available in the
key-value list under the -progs
key in the implementation choice.
Proc xserv::validateImpChoiceShell
The procedure xserv::validateImpChoiceShell
validates an
implementation choice for the Shell
invocation mode. After
checking that the shell to use exists, it calls
validateImpChoiceExec
to validate the -progs
aspect.
Proc xserv::validateImpChoiceInSh
The procedure xserv::validateImpChoiceInSh
validates an
implementation choice for the InSh
interactive invocation mode.
This is just the same as vaidating for Shell
mode.
Proc xserv::validateProg
The procedure xserv::validateProg
validates a program path against
a program name. It returns the absolute path to the program or an
empty string if the program could not be found.
prog is the path to the program, name is the program
to find.
If prog is executable, assume it is a good choice for
name.
Look for programs named name in the command path. If none are
found, ask the user to locate the program. If only one is found,
return it. If more than one are found, ask the user to choose among
them.
Proc xserv::findProg
The procedure xserv::findProg
searches a program in a list of
directories.
prog is the program to find. pathlist is the list of
the directories in which to search. exact tells if prog
is the exact name of the program to find. When exact is 1, we
must just check that prog is executable. When exact is
0, we can look for another program with the same tail name.
End user interface
Proc xserv::selectImplementationFor
The xserv::selectImplementationFor
procedure asks the user which
implementation of an XSERV he wants to use. This procedure is called
when an XSERV is invoked but no implementation has been chosen for it
yet, or when the user selects the Set external helpers menu
item to choose an implementation for a service.
If an implementation has already been chosen for the XSERV,
xserv::selectImplementationFor
makes it the default selection in the
list of implementations.
If the service has only one mandatory argument, a special
implementation labelled * Other * is added to the list of
implementations and allows the creation of a generic implementation.
If the service is part of a bundle, the user is asked to chose an
implementation for the bundle (end-users should not see services
which are part of a bundle).
Proc xserv::editHelpers
The xserv::editHelpers
procedure allows the user to choose an XSERV and
then an implementation of this XSERV. It can be used to let the user
configure all declared XSERVs (like in Preferences->Helper Applications).
If there is more than one category of services, this procedure
first asks the user to choose a category of services, and then
displays only the services in this category.
Services which belong to no category are put in a virtual
* no category * category.
group is the group for which the implementation of a service
will be chosen. It defaults to "", the default group.
First, all services are put in the list of services with no
category, and the list of all categories which contain services
is built.
Then, services which belong to a category are removed from the
list of uncategorized services.
If there are services with no category, we add a special category
for them in the list, labelled * no category *.
If there is more than one category, let the user choose a category
If there is only one category, don't show the category dialog
Proc xserv::setExternalHelpers
The setExternalHelpers
procedure is just a wrapper around xserv::editHelpers
which is the callback of the Helper Applications
item added to the Alpha ↣ Global Setup menu.
Invoking XSERVs
Proc xserv::invoke
The xserv::invoke
procedure asks an XSERV to perform its task through
its current implementation (as chosen by the default group).
The interact parameter should be set to -foreground
if the
user is expected to interact with the application, or to
-background
if the application should operate silently.
The arguments of the XSERV must be in the form
-key value, where key is the name of a formal
parameter of the XSERV, and value is the actual value of the
parameter. For instance, to typeset the file hello.tex with the
latex
format, passing option --src
to the TeX implementation,
we can write:
xserv::invoke -foreground tex -filename hello.tex -format latex -options --src
From version 1.3, the leading -
in front of the keys can no longer be omitted.
If a parameter is not set, its default value (as declared in the XSERV) is
used. If no default value is declared, this is an error (just like for a
Tcl proc).
Proc xserv::invokeForGroup
The xserv::invokeForGroup
procedure asks an XSERV to perform its task through
the current implementation chosen by a group.
If a validation procedure exists for this invocation mode, call
it to validate the chosen implementation.
Proc xserv::execEndExecHooks
The xserv::execEndExecHooks
procedure calls all end of execution
hooks registered for the service. Its code has been factored out
of xserv::invokeForGroup
so that it can be reused by different
execution procedure as new invocation modes are added to
xserv.
imp is a key-value list which describes the implementation.
effectiveargs is a key-value list which gives the values of
the arguments of the invocation. result contains the result
of the invocation of the service.
Proc xserv::addEndExecHook
The xserv::addEndExecHook
procedure adds a procedure to the list of
procedures to call after each invocation of an XSERV.
xservname
is the name of the XSERV, and proc
is the name
of the procedure to call. This procedure will be called with
four arguments:
- a list which describes the implementation of the XSERV used
for this invocation;
- the list of paramaters of the invocation.
- the result of the invocation;
The first two parameters are key-value lists suitable for use with
[array set].
Proc xserv::removeEndExecHook
The xserv::removeEndExecHook
procedure removes a procedure from the list of
procedures to call after each invocation of an XSERV.
xservname
is the name of the XSERV, and proc
is the name
of the procedure to remove. If proc
is omitted, the list of procedures
to call will be made empty.
If the list is empty or does not contain proc
, removeEndExecHook
will do nothing.
Proc xserv::executeApp
The xserv::executeApp
procedure executes an application. This is one of the
possible final steps in the invocation of an XSERV. It is used when
the incocation mode is App
.
implArray
is the array-set like list which describes the
implementation to use.
paramArray
is the array-set like list which contains the values
of the parameters of the invocation.
Proc xserv::executeShell
The xserv::executeShell
procedure executes a shell and sends the
result of the driver script to its standard input. This is one of the
possible final steps in the invocation of an XSERV. It is used when
the incocation mode is Shell
.
The result of the driver script is interpreted as a list of words.
Each word in this list is processed to escape the spaces it may
contain before sending it to the standard input of the shell.
implArray
is the array-set like list which describes the
implementation to use.
paramArray
is the array-set like list which contains the values
of the parameters of the invocation.
Proc xserv::executeInSh
The xserv::executeInSh
procedure executes a shell and writes the
result of the driver script to its standard input.
A window in InSh
Alpha mode is used to let the user interact
with the shell.
This is one of the possible final steps in the invocation of an
XSERV. It is used when the incocation mode is InSh
.
The result of the driver script is interpreted as a list of words.
Each word in this list is processed to escape the spaces it may
contain before sending it to the standard input of the shell.
implArray
is the array-set like list which describes the
implementation to use.
paramArray
is the array-set like list which contains the values
of the parameters of the invocation.
Proc xserv::executeExec
The xserv::executeExec
procedure executes the result of the driver
script with the Tcl exec
command. This is one of the
possible final steps in the invocation of an XSERV. It is used when
the incocation mode is Exec
.
The result of the driver script is interpreted as a list of words.
Each word in this list is processed to escape the spaces it may
contain before passing it to the exec
command.
implArray
is the array-set like list which describes the
implementation to use.
paramArray
is the array-set like list which contains the values
of the parameters of the invocation.
Proc xserv::executeAlpha
The xserv::executeAlpha
procedure executes the result of the driver
script with the Tcl interpreter of Alpha. This is one of the
possible final steps in the invocation of an XSERV. It is used when
the incocation mode is Alpha
.
The driver script is interpreted by Alpha in its own context, as if
it was the body of a procedure.
implArray
is the array-set like list which describes the
implementation to use.
paramArray
is the array-set like list which contains the values
of the parameters of the invocation.
Known problems
Please report any problem or bug you encounter in
Alpha's Bug Tracker.
License and Disclaimer
Original Author: Frédéric Boulanger.
Copyright (c) 2002-2020, Frédéric Boulanger and Contributors.
Contributors: Joachim Kock, Bernard Desgraupes.
All rights reserved.
The xserv package is free software and distributed under
the terms of the new BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Frédéric Boulanger nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FRÉDÉRIC BOULANGER OR THE CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Index
- xserv::addEndExecHook 1
- xserv::addGenericAppleEvents 1
- xserv::addGenericCommandLine 1
- xserv::addGenericImplementation 1
- xserv::addToCategory 1
- xserv::categories 1
- xserv::chooseImplementationFor 1
- xserv::chooseImplementationForBundle 1
- xserv::declare 1
- xserv::declareBundle 1
- xserv::deleteGenericImplementation 1
- xserv::deleteGenerics 1
- xserv::describe 1
- xserv::editHelpers 1
- xserv::execEndExecHooks 1
- xserv::executeAlpha 1
- xserv::executeApp 1
- xserv::executeExec 1
- xserv::executeInSh 1
- xserv::executeShell 1
- xserv::findProg 1
- xserv::fixExecSearchPath 1
- xserv::forget 1
- xserv::forgetImplementation 1
- xserv::getBundleName 1
- xserv::getCategoriesOf 1
- xserv::getCurrentImplementationsFor 1
- xserv::getGenericImplementationsOf 1
- xserv::getImplementationsOf 1
- xserv::invoke 1
- xserv::invokeForGroup 1
- xserv::isBundle 1
- xserv::listOfServices 1
- xserv::mandatoryArgsOf 1
- xserv::nameFromAppl 1
- xserv::readPrefs 1
- xserv::register 1
- xserv::removeEndExecHook 1
- xserv::removeFromCategory 1
- xserv::saveAll 1
- xserv::saveToPrefs 1
- xserv::saveXservCategories 1
- xserv::saveXservDeclarations 1
- xserv::saveXservImplementations 1
- xserv::saveXservSettings 1
- xserv::selectImplementationFor 1
- xserv::services 1
- xserv::setExternalHelpers 1
- xserv::validateImpChoiceApp 1
- xserv::validateImpChoiceExec 1
- xserv::validateImpChoiceInSh 1
- xserv::validateImpChoiceShell 1
- xserv::validateProg 1