This topic has no sources yet.
SAS VIEWTABLE Custom Command Manager
Richard A. DeVeneziahttp://www.devenezia.com
The EXECCMD argument of the VIEWTABLE command installs an SCL method that processes custom commands issued to the VIEWTABLE window. This argument is beneficial, however there are limitations when a user desires several independently developed custom command parsers be active.
EXECCMD is only available at VIEWTABLE invocation, there is no VIEWTABLE EXECCMD command. (Ingenious SCL coders can mimic EXECCMD at run-time by using the MODELSCL command to run code that installs method overrides from the DFINIT: section of an SCL entry)
Custom commands can be issued from the command window, menu choices or programmed keys.
Goal
Develop a custom command processing environment which an end user can easily install and configure. Advance coding practices that prefer self-relative or self-evident structure. Reliance on hardcoded paths or class names is to be minimized or entirely eliminated. Implementation of custom commands is not considered end-user territory and should be attempted by those with SAS/AF experience.
Overall scheme
- top level manager
- registers custom command classes
- dispatches control to custom command classes
- class based custom command processing
- classes must implement a command processing method with signature (CNC)V
- develop a sample custom command class to guide development of new custom command classes
The manager is installed at VIEWTABLE start-up by using the EXECCMD argument. The manager can not be installed after a VIEWTABLE window has started. Each VIEWTABLE window is independent, custom commands installed for one window are not available to another.
Future versions could address the desire for class registration to be permanent (aka persistent) or session global and in affect for all VIEWTABLE windows.
Top level manager
In this project, the manager will be Common.Viewtable.CustomCommand.scl, method Manager. It will be installed using VIEWTABLE argument EXECCMD=Common.Viewtable.CustomCommand.scl:Manager. In reality, the manager can be any method of any scl entry.
The manager reserves two custom commands for itself:
- ccRegister </u> class <class> ... <class>
- ccUnload
ccRegister
This custom command is used to register a method of a SAS/AF class for dispatching. An instance of the class is added to a dispatch list.
The class
value is of the form [catalog.]class[:method]
catalog
is of the form libname.memname
. If [catalog.]
is not present, it will default to the same catalog that the custom command manager was loaded from. If [:method]
is not present, it will default to commandParser
.
Thus, for this project, the default is Common.Viewtable.class:commandParser
The method must be of signature (CNC)V
(see below for more details). If the method sets the return code argument to 1, then the command will not be dispatched to any additional classes. This prevents
collisions between two classes designed to process the same custom command.
Different methods of the same class can be registered.
ccRegister /u
This custom command is used to remove a class method from the dispatch list. If only a class is indicated, all methods of that class are removed.
ccUnload
This custom command unregisters all methods and uninstalls the Manager.
Dispatcher main loop
- test for manager reserved commands
- ccRegister
- parse for /u and class arguments
- instantiate class and check method signature
- /u remove matching items from dispatch list, _term() classes with no remaining methods registered
- ccUnload
- unregister all classes
- remove _self_ override of _execCommand
- ccRegister
- loop through dispatch list
- invoke command processing method of class
Custom command classes
At a minimum, a custom command class should be a subclass of sashelp.fsp.object
and contain one method of signature (CNC)V. Example:
commandParser: Public Method inCmd:I:Char retCode:U:Num outCmd:I:Char ;
You may want to develop a class hierarchy to make common command processing tasks easily reusable.
Parsing the command line
The default scheme provided by _execCommand override is simple. The documentation does not discuss processing multi word commands, however empirical study shows these facts:
- First token of the command line is in
inCmd
- Second token of the command line is in
outCmd
- Third and subsequent tokens of the command line are obtained by this pattern:
token = word(1); do while (token ne ''); call nextword(); token = word(1); end;
call nextword()
works on a tokenizing level that is too fine for word-based command line parsing. Single non-alphabetic characters are tokens (or words), even when directly adjacent to other non-tokenized characters, e.g.A.B.C.D
is tokenized intoA
.
B
.
C
.
D
Double or single quoting is the only way to ensure complexly valued arguments of a command line are processed as a single word by nextword(), e.g."A.B.C.D"
is tokenized intoA.B.C.D
SCL code to infer user intuited arguments of a command line from highly tokenized unquoted arguments is possible and encouraged to reduce frustration on the users part. (E.g. Why the heck to I have to quote everything all the time?) The source of the manager will demonstrate the technique.