Studying the “mycas” example |
The best way to start implementing a new interface with TeXmacs is to take a look at the sample “computer algebra system” mycas, which can be found in the directory $TEXMACS_PATH/misc/mycas. The file mycas.cpp, which is listed at the end of this section, contains a very simple program which can be interfaced with TeXmacs. In order to test the program, you should compile it using:
g++ mycas.cpp -o mycas
and move the binary mycas to some location in your
path. When starting up TeXmacs, you should then have a
Let us study the source code of mycas step by step. First, all communication takes place via standard input and output, using pipes. In order to make it possible for TeXmacs to know when the output from your system has finished, all output needs to be encapsulated in blocks, using three special control characters:
#define DATA_BEGIN ((char) 2)
#define DATA_END ((char) 5)
#define DATA_ESCAPE ((char) 27)
The DATA_ESCAPE character followed by any other character c may be used to produce c, even if c is one of the three control characters. An illustration of how to use DATA_BEGIN and DATA_END is given by the startup banner:
int
main () {
cout << DATA_BEGIN << "verbatim:";
cout << "–––––––––––––––––––––––––––\n";
cout << "Welcome to my test computer algebra system for TeXmacs\n";
cout << "This software comes with no warranty whatsoever\n";
cout << "(c) 2001 by Joris van der Hoeven\n";
cout << "–––––––––––––––––––––––––––\n";
next_input ();
cout << DATA_END;
fflush (stdout);
The first line of main says that the startup banner will be printed in the “verbatim” format. The next_input function, which is called after outputting the banner, is used for printing a prompt and will be detailed later. The final DATA_END closes the startup banner block and tells TeXmacs that mycas is waiting for input. Don't forget to flush the standard output, so that TeXmacs will receive the whole message.
The main loop starts by asking for input from the standard input:
while (1) {
char buffer[100];
cin >> buffer;
if (strcmp (buffer, "quit") == 0) break;
The output which is send back should again be enclosed in a DATA_BEGIN-DATA_END block.
cout << DATA_BEGIN << "verbatim:";
cout << "You typed " << buffer << "\n";
Inside such a block you may recursively send other blocks, which may be specified in different formats. For instance, the following code will send a LaTeX formula:
cout << "And now a LaTeX formula: ";
cout << DATA_BEGIN << "latex:" << "$x^2+y^2=z^2$" << DATA_END;
cout << "\n";
For certain purposes, it may be useful to directly send output in
TeXmacs format using a
cout << "And finally a fraction ";
cout << DATA_BEGIN << "scheme:" << "(frac \"a\" \"b\")" << DATA_END;
cout << ".\n";
In order to finish, we should again output the matching DATA_END and flush the standard output:
next_input ();
cout << DATA_END;
fflush (stdout);
}
return 0;
}
Notice that you should never output more than one DATA_BEGIN-DATA_END block. As soon as the first DATA_BEGIN-DATA_END block has been received by TeXmacs, it is assumed that your system is waiting for input. If you want to send several DATA_BEGIN-DATA_END blocks, then they should be enclosed in one main block.
A special “channel” is used in order to send the input prompt. Channels are specified as special DATA_BEGIN-DATA_END blocks:
static int counter= 0;
void
next_input () {
counter++;
cout << DATA_BEGIN << "channel:prompt" << DATA_END;
cout << "Input " << counter << "] ";
}
Inside the prompt channel, you may again use DATA_BEGIN-DATA_END blocks in a nested way. This allows you for instance to use a formula as a prompt. There are three standard channels:
It is possible to send postscript graphics as output. Assume for instance that you have a picture picture.ps in your home directory. Then inserting the lines:
cout << "A little picture:\n";
cout << DATA_BEGIN << "ps:";
fflush (stdout);
system ("cat $HOME/picture.ps");
cout << DATA_END;
cout << "\n";
at the appropriate place in the main loop will display your image in the middle of the output.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
#define DATA_BEGIN ((char) 2)
#define DATA_END ((char) 5)
#define DATA_ESCAPE ((char) 27)
static int counter= 0;
void
next_input () {
counter++;
cout << DATA_BEGIN << "channel:prompt" << DATA_END;
cout << "Input " << counter << "] ";
}
int
main () {
cout << DATA_BEGIN << "verbatim:";
cout << "–––––––––––––––––––––––––––\n";
cout << "Welcome to my test computer algebra system for TeXmacs\n";
cout << "This software comes with no warranty whatsoever\n";
cout << "(c) 2001 by Joris van der Hoeven\n";
cout << "–––––––––––––––––––––––––––\n";
next_input ();
cout << DATA_END;
fflush (stdout);
while (1) {
char buffer[100];
cin >> buffer;
if (strcmp (buffer, "quit") == 0) break;
cout << DATA_BEGIN << "verbatim:";
cout << "You typed " << buffer << "\n";
cout << "And now a LaTeX formula: ";
cout << DATA_BEGIN << "latex:" << "$x^2+y^2=z^2$" << DATA_END;
cout << "\n";
cout << "And finally a fraction ";
cout << DATA_BEGIN << "scheme:" << "(frac \"a\" \"b\")" << DATA_END;
cout << ".\n";
next_input ();
cout << DATA_END;
fflush (stdout);
}
return 0;
}