Thursday, April 3, 2008

GTM write to text file

This post is about creating a text file using a mumps routine and writing some characters to it.
There are 3 main commands that you need to know about.


  1. Open - This opens the file
  2. Use - this tells the mumps environment that write commands should be directed to the given file.
  3. Close - When you have finished close the file.



Set dev="/home/user/testtextfile.txt"


For clarity and usability I like to put the file name in a variable like 'dev'.
If a file is still open when some bad logic in a routine causes it to bomb. Its useful to be able to write 'Close dev' at the command prompt. Before restarting.




Open dev::2

The Open syntax is: the word 'Open' followed by a space, then device name or variable containing the device name. Don't worry about the two colons at the moment. They only serve here to delimit that number 2 at the end. The 2 signifies that the mumps environment should wait up to 2 seconds trying to open a file with the given filename.




If '$Test Write !,"Unable to open file ",dev Quit


When a file is opened sucessfully the system variable $Test is set to a value of 1.
If the file fails to open then $Test is set to 0.
The above line tests for 'not $Test' - so if it can't open the file a useful output will be written to the terminal an the routine / sub-routine exits.



Use dev
W !,"This is some text written to a file"
W !,"This is some more text"


After opening a device you instruct the mumps environment to use it before writing to the file.
Writing to the file is just like writing output to the terminal.
When you have finished close the device.




Close dev


Here is the full routine listing:




Set dev="/home/user/testtextfile.txt"
Open dev::2
If '$Test Write !,"Unable to open file ",dev Quit
Use dev
W !,"This is some text written to a file"
W !,"This is some more text"
Close dev

GT.M and the number 31

A variable is a convenient local memory storage location during the execution of a routine.
A Global is a persistent on disk storage location set, killed or changed during the execution of a routine.
A routine is a text file on disk that is compiled into a program.


These all share one thing in common. They can only have names of up to 31 characters long. Any longer and the mumps environment silently truncates the names for globals and variables.

GTM>Set testdatadata1231231231231231231=123

GTM>Set testdatadata12312312312312312319999=456

GTM>Write testdatadata1231231231231231231
456
GTM>

As you can see above there is actually only one variable "testdatadata1231231231231231231".
The same truncation behavior can be noted for globals



GTM>Set ^testdatadata1231231231231231231("a")=123

GTM>Set ^testdatadata12312312312312312319999("a")=456

GTM>Write ^testdatadata1231231231231231231("a")
456
GTM>

Above there is only one global defined "^testdatadata1231231231231231231("a")".
To demonstrate the truncation behaviour on routines. Create a routine called "testroutine12312312312312312312" with the following content:



T1
Write "123"
Quit

Create a second routine called "testroutine123123123123123123129999" with the following content:



T2
Write "456"
Quit

Now when you run either routine from the command line you will get the same response. Also note that only the line label "T1" is found:



GTM>D ^testroutine12312312312312312312

123
GTM>D ^testroutine123123123123123123129999

123
GTM>D T1^testroutine123123123123123123129999

123
GTM>D T2^testroutine123123123123123123129999
%GTM-E-LABELMISSING, Label referenced but not defined: T2

GTM>


Also in a given routine, a line label can only be distinguished up to 31 characters. Another factor of this line label name limit is that the compiler will not allow duplicate line labels to be defined within a single routine. So if two line labels do not differ in their first 31 characters they will be seen by the compiler to be a duplicate line labels.



GTM>D L234567891012345678910123456789^L234567891012345678910123456789
L2345678910123456789101234567890
^-----
At column 0, line 86, source module /gtm/rou/L234567891012345678910123456789.m
%GTM-E-MULTLAB, This label has been previously defined


31 characters is quite generous. In the days of MSM mumps the magic number was actually just 8.
... In the days when an expert used to be the person that remembered the difference between "HAD2^PS217Hgg" and "MAD2^PS217Hgg". :)

Wednesday, April 2, 2008

Create a new routine on GT.M

The way to write programmatic functionality against storage in a GT.M database is to implement routines. For this purpose I've created a folder '/gtm/rou' to accommodate new routines.
For convenience I've opened up access to create routines at this location.


user@machine:~$ sudo chmod 777 /gtm/rou

user@machine:~$ ls -l /gtm
total 12
drwxr-xr-x 3 root root 4096 2008-04-01 21:13 dist
drwxr-xr-x 2 root root 4096 2008-04-02 06:09 gbl
drwxrwxrwx 2 root root 4096 2008-03-30 21:52 rou


The editor environment variable was previously defined in the user profile.



user@machine:~$ printenv | grep -e EDITOR
EDITOR=/usr/bin/vim

The mumps prompt is started with the 'gtm' alias defined in an earlier post.



user@machine:~$ gtm

GTM>


The utility ZEDIT is invoked on the mumps prompt with a quoted string containing the path to a mumps routine you wish to edit.



GTM>ZEDIT "/gtm/rou/testroutine"


Note that the full path was specified. By default the editor will use the $gtm_dist location. It would seem that this is because the program mumps is located in $gtm_dist directory.
Using VIM the following routine test routine was entered



testroutine
Write !,"hello world from testroutine"
Quit
T1
Write !,"At line label T1^testroutine"
Quit

After saving the routine one quits the mumps prompt with the Halt command.

It is also OK to create the routine outside of the mumps command line, for example with gedit:



user@machine:~$ gedit /gtm/rou/testroutine.m


Note that we have to specify the file type '.m' in the path syntax.


If the routine is run interactively from the mumps prompt and it has not yet been compiled (or has been edited), the environment compiles the routine before running it. If the routine is already compiled (from a previous run) then the mumps environment runs the compiled version straight away.
The routine can be started by the 'Do Linelabel' syntax at the mumps prompt.
For example:


user@machine:~$ gtm

GTM>D ^testroutine

This is the test routine
GTM>Do T1^testroutine

This is line label T1 of testroutine
GTM>halt
user@machine:~$

Quick GT.M create a usable database

Using GT.M on Ubuntu.
I just wanted to have a usable database to experiment with.
The location of my new database is going to be '/gtm/gbl/'.
Basically I need to create 2 new files:

  • /gtm/gbl/mumps.gld
  • /gtm/gbl/mumps.dat

First it is important that the environment vaiable 'gtmgbldir' is equal to the global directory file path ('gtm/gbl/mumps.gld').
It can be mannualy set for the purposes of this session using:

user@machine:~$ gtmgbldir=/gtm/gbl/mumps.gld
user@machine:~$ export gtmgbldir
user@machine:~$


The directory '/gtm/gbl' was created by root via sudo:


user@machine:~$ sudo mkdir /gtm/gbl

This means only root can create new files in this directory. This means that the commands to create new files in this directory must also run via sudo.
Change directory to /gtm/gbl;


cd /gtm/gbl/

start the mumps prompt in root:



user@machine:/gtm/gbl$ sudo $gtm_dist/mumps -direct

Start GDE



GTM>D ^GDE
%GDE-I-GDUSEDEFS, Using defaults for Global Directory
/gtm/gbl/mumps.gld

GDE command adapted from manual:



GDE> change -segment default -allocation=1000 -file=/gtm/gbl/mumps.dat


Note that the the file spec contains the full path to the 'dat' file.
This stops mupip later from creating the dat file in your $gtm_dist directory, in the next part.
Now exit GDE:



GDE> exit
%GDE-I-VERIFY, Verification OK

%GDE-I-GDCREATE, Creating Global Directory file
/gtm/gbl/mumps.gld
user@machine:/gtm/gbl$

OK now create the 'dat' file in root mode:



user@machine:/gtm/gbl$ sudo $gtm_dist/mupip create
Created file /gtm/gbl/mumps.dat
user@machine:/gtm/gbl$

List the contents and permissions of the gbl directory:



user@machine:/gtm/gbl$ ls -l
total 60
-rw-rw-rw- 1 root root 1092096 2008-04-02 06:09 mumps.dat
-rw-r--r-- 1 root root 1024 2008-04-02 06:07 mumps.gld
user@machine:/gtm/gbl$

Change the permissions on the 2 new files to open read and write



user@machine:/gtm/gbl$ sudo chmod 666 mumps.*
user@machine:/gtm/gbl$

This will allow mumps to be run under the normal user account and facilitate reading from and updating the database file.
A small test of the new database.


user@machine:/gtm/gbl$ gtm

GTM>Write $Data(^TEST(123))
0
GTM>Write $Data(^TEST(123))
0
GTM>Set ^TEST(123)="abc"

GTM>Write $Get(^TEST(123))
abc
GTM>Halt
user@machine:/gtm/gbl$

Note - Because the environment variable 'gtmgbldir' is set to '/gtm/gbl/mumps.gld' in the user local profile, whenever a mumps direct session is started, it will be using the above new database.

GT.M environment variables with alias 'gtm?'

All gtm envrionment variables start with the prefix 'gtm'.
Use the following to dump them to the terminal:



user@machine:~$ printenv | grep -e gtm
gtmgbldir=/gtm/gbl/mumps.gld
gtmroutines=. /gtm/dist/ /gtm/rou/
gtm_dist=/gtm/dist/
gtm_principal=/gtm/filename
user@machine:~$


If you like you can create an alias for this in your bash_aliases file


user@machine:~$ sudo vim ~/.bash_aliases


Add the following line:

alias gtm?='printenv | grep -e gtm'

Now run the command 'bash'.
This picks up the new settings.



user@machine:~$ bash
user@machine:~$

Now you can display the environment using the alias 'gtm?'



user@machine:~$ gtm?
gtmgbldir=/gtm/gbl/mumps.gld
gtmroutines=. /gtm/dist/ /gtm/rou/
gtm_dist=/gtm/dist/
gtm_principal=/gtm/filename
user@machine:~$

Tuesday, April 1, 2008

gtm environment variables

I'm using GT.M on Ubuntu.
Just been setting up the environment variables.
I've unzipped / untared the distro to a new folder called '/gtm/dist'.
I have a new empty directory set aside for globals at '/gtm/gbl'.
I have a new empty directory set aside for routines at '/gtm/rou'.
Basically I don't want to have to setup the 4 GT.M environment variables from a terminal before launching a mumps prompt.
Instead I've defined them in my user profile.
At a termial I've open my profile:


user@machine:~$ vim ~/.profile


At the bottom of the file I added the following lines:



gtm_dist=/gtm/dist/
export gtm_dist
gtmgbldir=/gtm/gbl/mumps.gld
export gtmgbldir
gtm_principal=/gtm/filename
export gtm_principal
gtmroutines=". $gtm_dist /gtm/rou/"
export gtmroutines
EDITOR=/usr/bin/vim
export EDITOR


Save the file. Logout of Ubuntu and log back in.


    *** Warning ***
The first time I did this I missed out the closing quotation character.
This prevented my normal logon from working as my profile was then broken.
However if you get the same issue choose the emergency / safe mode startup option in Ubuntu and you can then edit the specific profile for example:


root@machine:~$ vim /home/[username]/.profile

NB: In the above substitute '[username]' with your normal Ubuntu login name.
Correct the profile.
Save and restart Ubuntu.

gtm alias for mumps prompt

I'm using the GT.M database on Ubuntu.
I'd like to start a mumps prompt with the keyword gtm



user@machine:$ gtm

GTM>

... instead of having to type:



user@machine:$ $gtm_dist/mumps -direct

GTM>

First I edited the main bash profile:



user@machine:$ vim ~/.bashrc


uncomment out the following lines from:



#if [ -f ~/.bash_aliases ]; then
# . ~/.bash_aliases
#fi

...to:



if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi

Then I open the bash_aliases file



user@machine:$ vim ~/.bash_aliases


... and added the following line:



alias gtm='$gtm_dist/mumps -direct'


After logging out and then logging back in again I was able to start a mumps prompt from a terminal with the word 'gtm'.



user@machine:$ gtm

GTM>W !,"Hello aliased gtm!"

"Hello aliased gtm!"
GTM>