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.

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)+
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
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:
  1. the name of the service;
  2. the result of the invocation;
  3. a list which describes the implementation of the service used for this invocation;
  4. 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: 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 : 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::validateImpChoicemode, 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:
  1. a list which describes the implementation of the XSERV used for this invocation;
  2. the list of paramaters of the invocation.
  3. 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: 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