EMBOSS allows for very flexible descriptions of an application's command line interface via the ACD language. In this section we'll take a slightly deeper look at writing ACD files and the code required to process them. You'll be introduced to new ACD datatypes and attributes.
Consider this simple task:
Modify helloworld to print any user-defined string a user-defined number of times to the screen.
To replace the hard-coded string "Hello World!" with a user-defined string you must:
Add a new data definition to the ACD file. The ACD datatype you need is, unsurprisingly, a string
. Many others are available (Section 4.3, “Data Definition”).
Give your data definition an appropriate label.
Give the string a default value. You'll need to add a default:
attribute to the string definition with a sensible default value of "Hello World!"
(or something else).
Your ACD file should now look something like this:
application: helloworld [ documentation: "Prints 'Hello World!' to the screen." ] string: printme [ default: "Hello World!" ]
To modify your C source code to support the user-defined string you need to:
Define an appropriate AJAX object, i.e. to hold an ACD string
datatype.
Add an appropriate ajAcdGet*
function (in this case ajAcdGetString
) to retrieve the value of your new ACD data item. The argument to ajAcdGetString
must be the same as the data label in the ACD file.
Call a function to print the string to screen.
Comment out (or remove) the existing hard-coded ajFmtPrint
statement.
Exit cleanly; remembering to free the string object (by calling ajStrDel
) that will have been allocated (indirectly) by ajAcdGetString
.
Your source code will now look something like:
#include <stdio.h> int main(void) { AjPStr printme=NULL; printme = ajAcdGetString("printme"); ajFmtPrint("%S\n", printme); ajStrDel(&printme); embExit(); return 0; }
You can see that ajFmtPrint
is used with a conversion specifier (%S
) to print an EMBOSS string.
Both ajFmtPrint
and the C equivalent (printf()
) functions use conversion specifiers which control how the arguments to the function are interpreted when they are printed out. The conversion specifiers are given by a single character preceded by a percentage symbol (%
). For example, a signed decimal integer variable is converted for printing with the conversion %d
and a character string is formatted correctly with the conversion %s
. ajFmtPrint
supports additional AJAX datatypes including booleans (%B
),date (%D
) and AJAX strings (%S
) etc. (see Section 5.1, “Basic Datatypes”)
When you run the program, you should get output that looks like this:
%
helloworld
My first EMBOSS program Hello World!
It should be obvious that it's using the default value. However, the string can be user-defined, you just have to specify the appropriate qualifier (the label of the data item, printme
in this example) and an associated string value on the command line when you invoke the program:
%
helloworld -printme "Hello Sailor!"
My first EMBOSS program Hello Sailor!
As a finishing touch, add a groups:
attribute to the application definition to assign your application to a functional group. See the list of valid group names (Section 4.2.4.1, “Application Group Names File (groups.standard
)”). This will make it easier to find by end-users.
Also, add a comment line (beginning with #
) giving the date your ACD file was last edited.
The application:
definition should now look something like this:
application: helloworld [ documentation: "Prints 'Hello World!' to the screen." groups: "Test" # Last edited 2007. ]
Having to use the -printme
option is a bit cumbersome, it would be nice if you could specify the text to print without having to know the label name. For this you use the parameter:
attribute. If a data item is defined with parameter:
, using the flag on the command line is not mandatory, i.e. you can just type:
helloworld "Hello Sailor!" |
To define your string as a parameter, add the following to the ACD string definition:
parameter: "Y" |
You can still use the qualifier name if you want to, but it's not mandatory.
The next task is to add an integer data item to the ACD file to control how many times the user-defined string is printed to the screen. To add the integer, you repeat the steps you went through for adding the string.
Your ACD file will include the following data definition:
integer: n [ default: "1" ]
The C code will need modifying to look something like this:
#include "emboss.h" int main(void) { AjPStr printme = NULL; ajint n = 0; printme = ajAcdGetString("printme"); n = ajAcdGetInt("n"); while(n) { ajFmtPrint("%S\n", printme); n--; } ajStrDel(&printme); embExit(); return 0; }
You'll notice a destructor function is not called for the new integer. This is because ajint
is a fundamental AJAX datatype, not an object (C data structure), and therefore does not require explicit memory management. See elsewhere for further information on programming for fundamental types (Section 5.1, “Basic Datatypes”) and objects (Section 5.3, “Objects (C Data Structures)”).
Do not make the integer a parameter just yet - experiment by calling helloworld with different command lines. You should notice that it doesn't matter whether the parameter comes before or after the qualifier for your new integer. In other words you can call the application like this:
helloworld -n 10 "Hello Sailor!" |
Or like this:
helloworld "Hello Sailor!" -n 10 |
Now make the integer a parameter in your ACD file. Experiment again with calling helloworld. You will see for yourself that the order of parameters is important - they have to match the order used in the ACD file!
If, for example, your ACD file looked this:
application: helloworld [ documentation: "Prints a user-defined string to the screen." ] string: printme [ parameter: "Y" default: "Hello World!" ] integer: n [ parameter: "Y" default: "1" ]
You could invoke the program like this:
helloworld "Hello Sailor!" 10 |
But not like this:
helloworld 10 "Hello Sailor!" |
Parameters have to appear on the command line in the order in which they are defined in the ACD file.