Contents
The purpose of this document is to present an overview of the Mumps/II Compiler implementation of the Mumps/II language. This package consists of source code for compilers and support libraries for various operating systems for a dialect of the Mumps language. Mumps/II is a simple, easy to learn string and hierarchical data base scripting language originally developed for medical computing applications but is now used in many other settings. Related documentation is available at:
Mumps/II Manual
Mumps (also referred to as 'M') is a general purpose programming language that supports a native hierarchical data base facility. It is supported by a large user community (mainly biomedical), and a diversified installed application software base. The language originated in the mid-60's at the Massachusetts General Hospital and it became widely used in both clinical and commercial settings. A dwindling number of implementations exist for the language. There were ANSI, ISO (ISO/IEC 11756:1992) and DOD approved standards for Mumps although these have mainly lapsed in recent years. As originally conceived, Mumps differed from other mini-computer based languages of the late 1960's by providing: 1) an easily manipulated hierarchical (multi-dimensional) data base that was well suited to representing medical records; 2) flexible string handling support; and (3) multiple concurrent tasks in limited memory on very small machines. Syntactically, Mumps is based on an earlier language named JOSS and has an appearance that is similar to early versions of Basic that were also based on JOSS. This software package includes both a compiler and interpreter for Mumps/II The Mumps/II Compiler is a translator that converts Mumps/II to C++. The compiler implements much of the most recent Mumps standard (see the manual). Mumps/II programs are translated to standard C++ programs and subsequently compiled to binary executables. The compiler distribution contains the compiler source code, the manual, the run-time functions source code, all written in C/C++, and examples, written in Mumps/II. The compiler works under Linux and Cygwin (for Windows) with the 'gcc/g++' compilers and Microsoft Visual C++ 2005 under Windows. The Mumps/II Interpreter is a compiled Mumps/II program that permits direct execution (interpretation) of Mumps/II programs. It is available under Linux, Cygwin and Microsoft Windows. The MDH (Multi-Dimensional and Hierarchical Data Base Toolkit) is a Linux-based, open sourced, toolkit of portable software that supports Mumps/II-compatible, very fast, flexible, multi-dimensional and hierarchical storage, retrieval and manipulation of data bases ranging in size up to 256 terabytes. The package is written in C and C++ and is available under the GNU GPL/LGPL licenses in source code form. You must install the Mumps/II Compiler in order to use the MDH.
Introduction The purpose of this section is to provide you with an introduction to the Mumps language in general and the Mumps compiler. The Mumps language originated in the mid-60's at the Massachusetts General Hospital. The acronym stands for "Massachusetts General Hospital Utility Multi-Programming System". It is a language which is similar in some respects to BASIC but it contains many additional features not found in BASIC, or for that matter, in most other languages. In its full form, Mumps is an interpretive language. In fact, parts of the language specification require that it can never fully become a "compiled" language such as FORTRAN, COBOL or PL/I. In the compiler, some features, therefore, mainly those involving run time interpretation and symbol table binding, are removed. See above for details. Among the features which make Mumps attractive for both bio-medical and general scientific applications are: Hierarchical data base facility. Mumps data sets are not only organized along traditional sequential and direct access methods, but also as hierarchical trees whose data nodes are addressed as path descriptions in a manner which is easy for a programmer to master in a relatively short time. Flexible and powerful string manipulation facilities. Mumps built-in string manipulation operators and functions provide programmer's with access to efficient means to effect complex string manipulation and pattern matching operations. Transportability to widely different systems Mumps presently runs under a large number of operating systems on many machine architectures. These systems range in size from small home micro-computers to the largest central time sharing systems. Through efforts that have taken place by the Mumps Development Committee over the years, a well organized language definition has been written and formally published. This standard provides for a far tighter specification for system performance and linguistic definition than is normally the case. As a result, programs written under a Mumps system can be moved with relatively little effort from one system to another. Full numeric data handling facilities Mumps provides, in addition to string handling facilities, a full range of fixed and floating point computational facilities. Basically, Mumps has only one data type: string, although it does allow integer and floating point computations as well as logical expressions. The values in a string may be any ASCII code from 32 to 126 (decimal) inclusive. The Mumps Compiler does not permit usage of the ASCII zero character (<NULL>). Ordinarily, strings will contain ASCII printable characters. String constants are enclosed in double quote marks ("). A double quote mark can be included with two adjacent quote marks (""). A constant containing only numerics (and, optionally, plus, minus and decimal point), need not be enclosed by quotes (although doing so has no effect). The following are examples of valid Mumps character string constants:
When a string is being used as a number (e.g., in addition), the numeric portion must be 20 characters or less in length. Numeric constants are restricted to integer or decimal values (positive or negative). If a string begins with a number but ends with non-numeric characters, only the numeric leading portion will participate in operations requiring numeric operands (e.g., add, subtract, etc.); the trailing non-numeric portion is lost. On the other hand, if a string begins with non-numeric characters, its value will be interpreted as 0. The following are examples:
Only one plus or minus sign is permitted at the beginning of a string or the value will be interpreted as 0. Although "string" is the basic data type, Mumps converts strings internally to floating point values (double) for calculations. Consequently, numbers are of approximately 15 digit precision. Internally, integers are stored as C++ language "long" and floating point numbers as "double." Logical values in Mumps are special cases of the numerics. A numeric value of zero is interpreted as false while a non-zero value is interpreted as true. Logical operators yield either zero or one and their results can be treated like any other numeric. Similarly, the numeric result of any numeric operator can be used as a logical operand. The results of string operators are interpreted either as zero (leading characters non-numeric) or some value (leading characters numeric). Strings and the results of string operations can therefore participate as the operands of logical operators. Variables are named in Mumps in much the same manner they are named in other languages. A Mumps variable name must begin with a letter (A through Z) or percent sign (%) and may be followed by either letters or numbers. Both upper and lower case letters may be used for variables names. Mumps, in effect has only one data type so any variable name may be any value. All Mumps variables are varying length strings. The maximum string length permitted is determined when the compiler is installed. This number is usaullyat least 1024. In Mumps there are no data declaration statements. Variables come into existence through the set or the read command and pass from existence through the kill command. In the Mumps, there are two kinds of arrays: internal arrays and global arrays. The following pertains to internal arrays: arrays are not dimensioned. A name used as an array variable may also, at the same time, be used as a scalar. Array values are created by assignment or appearance in a read statement. If you create an element of an array, let us say element 10, it does not mean that Mumps has created any other elements: that is, it does not imply that there exist elements 1 through 9. You may specifically create these or not. Array indices may be positive or negative numbers or character strings. Arrays in Mumps may have multiple dimensions. The following are some examples of arrays:
Global arrays may be viewed either as multi-dimensional matrices or as tree structured hierarchies. For example, the following is taken from the MeSH Hierarchy. Note the original tree-like organization of the data and see the corresponding Mumps commands to represent the data in the data base. The codes used in the lines of Mumps code are the codes used by Mesh:
As matrices, data may be stored not only at fully subscripted matrix elements but also at other levels. For example, given a three dimensional matrix mat1, you could initialize it as follows:
In this example, all the elements of a three dimensional matrix of 100 rows, 100 columns and 100 planes are initialized to zero. Unlike other programming languages, however, there are additional nodes of the matrix which could have been initialized such as indicated by the following example:
In effect, this means that mat1 can also be a single dimensional vector, a two dimensional matrix and a three dimensional matrix simultaneously. Furthermore, not all elements of a matrix need exist. That is, the matrix can be sparse. For example:
In the above, only index values 0, 10, 20, 30, 40, 50, 60, 70, 80, and 90 are used to create each of the dimensions of the array and only those elements of the matrix are created. The omitted elements do not exist. Global arrays are unique to Mumps. As a programmer, you will work with them as though they were arrays. The system, however, interprets them as tree path descriptions for the system's external data files. A global array is distinguished by beginning with the circumflex character (^). The remainder of the specification is the same as an internal array. global arrays are not dimensioned and they may appear anywhere an ordinary variable may appear (except in certain forms of the "kill" command). A typical global array specification consists of the array name followed by some number of indices (indices may be constants, variables [including internal or global arrays] or expressions of string, numeric or mixed type). For example:
The system files are viewed as trees. Each global array name ("A", "SHIP", "CAPTAIN", and "HOME" in the above) is the root of a tree. The indices are thought of as path descriptions to leaves. For example, out of the root "^a" there may be many branches, the above specifies to take the branch labeled "1" (note: this does not mean the "first" branch out of the node - it means the branch with label "1"). At the second level the specification says to take the branch labeled "43" (note: this does not imply that branches 1 through 42 necessarily exist). The path description is followed (or, possibly, created if the global array specification appears on the left hand side of an assignment statement or in a read command) to a final node. The value at the node is either retrieved or a new value stored depending upon the context in which the global array specification was used. The indices of global arrays may be numeric or character strings. The second sequence of examples above illustrates this usage. Both string and character indices may be mixed in the same path description. A value may be stored at any position in the tree. For example:
Mumps arrays are not pre-declared and they are sparse. That is, only those elements which you explicitly create actually exist. For example, if you create element ^A(10), it does not necessarily mean that elements ^A(1) through ^A(9) exist. Global arrays are often interpreted as trees where each successive index describes the path through a multi-way tree. At each node, data can be stored (or not). The path from the root to a node is given by the sequence of indices of an array reference. The data base can store many trees, each distinguished by their array name. The Mumps global array facility is due to the early uses of Mumps in medical data bases which are basically hierarchical in nature. The Mumps global arrays were a solution to the problem of how to represent the tree-like structure of patient data in a simple and easily manipulated data structure. For example, consider a basic patient record. At the top level is the patient's id node at which is stored the patient's name. At the second level, are nodes for demographic (address, gender, phone number, etc.) data and the main entry node for clinical data. Clinical data is organized by diagnostic or problem category and each problem or diagnostic code is divided into episodes of the problem organized by onset date. For a given problem and onset, the data are divided by category (medications, lab tests, orders, notes, etc.) which are further subdivided by, for example, in the case of lab tests, test, date, time and result. For example:
Here, the tree is named patient which is also the name of the global array (notice that global arrays always have a circumflex (^) preceding their name). The Mumps code to populate the above might look like:
Notice that the empty string can be stored at a node. In these cases, the actual data (the lab test result) is the value of the final index. Also note that each intermediate node need not be created. The nodes representing ""Demographics", "lab", "Dx", HCT, and others are not explicityly created. Their creation is implicit in constructing the longer paths of which they are intermediates. Mumps was originally conceived as a language to be executed by interpreters. Consequently, the syntax and structure of commands tend to be line oriented and simple to parse. Each command in Mumps begins with a key word. The keyword may be abbreviated, in many cases to a single letter (this was to save storage and time on the early interpreters but has no effect on efficiency in the Mumps Compiler). A command is followed optionally be a post-conditional expression and then, in most cases by one or more arguments. The blank character is a terminator in Mumps so the placement of blanks is important. A blank is used to separate a command keyword from its arguments and to terminate the list of arguments. If a command has no arguments and there are others commands following on the line, the command (or, the command and its post-conditional) are followed by at least two blanks. Blanks may not be embedded in expressions except in quoted fields. A post-conditional is an expression that will be evaluated prior to executing the arguments of a command. If the expression is true, the arguments will be executed. If the expression is false, the arguments will not be executed and control will move to the next command. Some commands, such as the if and the else may not be post-conditionalized. Other commands, such as the do and the goto may not only be post-conditionalized at the command level, but also at the argument level. Most commands are only post-conditionalized at the command level. Here are some valid commands with and without post-conditionals (";" causes the remainder of the line to be interpreted as a comment):
The basic assignment statement in Mumps is the set statement. It may have one or more arguments. The left hand side is evaluated and the result is assigned to the variable on the left hand side. Expressions in Mumps are evaluated strictly left-to right without precedence. If you want a different ordering of the evaluation, you must use parentheses. This is true in any Mumps expression in any Mumps command. It is a common source of error, especially in if commands with compound predicates. Variable in Mumps, as noted above, can be local, that is, present only during the execution of the program, or global, which is to say, disk resident and persistent from one execution of the program to the next. Both local and global variables may be either scalar or arrays although most local variables tend to be scalar and most global variables tend to be arrays in practice. A variable, either global or local, is created by appearing on the right hand side of a set statement (or as an argument in a read statement). The Mumps symbol table is dynamic and variables are created as needed. They may also be destroyed (kill). Expressions may involve both local and global variables, operators (see below) and constants. Constants may be either numeric or string. String constants are enclosed in double quits (use two immediately adjacent double quotes to create a single double quote in a quoted string). Strings are converted to numerics as needed and back again. The basic internal data type is string. For example (in each of these, the item written is followed by a <new-line> character due to the "!"):
The last four examples use global and local scalars, respectively. The input/output commands are read and write. They may each use formatting codes. The formatting codes are:
The read command may contain out put codes and string constants along with the variable names to be read. This permits prompts to be embedded in the read (note: this only applies when reading from the console). For example:
This will cause the prompt "enter name:" to be written at the beginning of a new line (!) and then the cursor will tab to column 20 and await the user's input which will be stored in variable "x". Examples of the write command:
The first example above writes "hello world" followed by a new-line. The second does the same. The third writes "hello" and "world" on separate lines. The fourth writes 1, 2, 3, and 4 in columns 10, 20,30 and 40, respectively followed by two new-lines. The argumented form of theif statement Mumps tests one or more expressions for true and does or does not execute the remainder of the line depending upon the result. A value is considered to be "true" if it is non-zero and "false" if zero. If there are multiple arguments, each argument must be true. Note that the if command has as its scope the entire remainder of the line on which it appears, not just the next command. As a side effect, the if statement sets the system built-in variable $test to "true". And's ("&") and or's ("|") may be used in expressions along with not's ("'"). The relational operators are cited below. Examples:
Note the multiple arguments on line 4 above. This effectively constitutes an "and" operation. Also note line 5. Due to strict left-to-right, non-precedence parse, the expression is interpreted as though it had been written "(((i<j)&k)>j)". The "i<j" is true (1); "1&k" is true (1) but "1>j" is false so the expression is false. The expression on line 6 is probably what was wanted. It is very important to include parentheses in compound expressions to express precedence. The argumentless form of the if statement (which is followed by two or more blanks) tests the current value of $test and does or does not execute the remainder of the line depending upon if $test is true (1) or false (0). For example:
The above will write "yes" and "yes again" because the first if sets $test to true. A negative side effect of this is that $test can be reset to false in the scope of the first if:
The above will write "yes" only. The second if on the second line sets $test to false. For compiled code, $test is restored to its previous value upon exit from a block:
The false if expression sets $test only within the block. The previous value is restored on exit. Note: $test is not restore from block exit in the interpreter. The principle iterative command is the for command. It has the syntax of a local, scalar index variable followed by an equals sign followed by one or more arguments. The arguments may either be specific values the index variable should have or a range specification. A range specification is either two numbers separated by a colon or three numbers separated by two colons. In both cases, the first number is the initial value for the index variable, and the second is the increment (or decrement if negative). The third number, if present, is the limit value. If no third number is specified, there is no upper limit and some other mechanism must terminate the loop. For example:
An argumentless for loops forever until stopped by another command. The quit command will terminate the nearest command on the current line:
If there are multiple for commands, the quit terminates the nearest:
the above will write 1 through 5 a total of 10 times. The for is often used with the argumentless form of the do command. The argumentless form of the do assumes there will be a block of code immediately following the current command line. The block will be executed. For example:
The above will write the numbers 1 through 10 followed by the square of the number. In the compiled code, when you enter a block by means of an argumentless do, the value of $test is stored and restored on normal exit from the block. If you exit the block by means of a goto, the value of $test is not restored. $test is not restored under any circumstances in the interpreter. In the context of a block, the quit command means to quit the block, not the for. For example:
The above will write 5 lines with numbers and their squares and 5 lines with just the numbers (6 through 10). The quit terminates the block but not the for. A break (this is a non-standard feature of the Mumps Compiler) may be used to exit a block:
The above will only write 5 lines. The break terminates the block and the for. A break may only be used in a block. Alternatively, the quit could be used as follows:
The above will write 5 lines, 4 of which have the number and its square. Note the two blanks after the argumentless do. Another form would be:
The above will write 10 lines, each with two numbers. Blocks may be nested but the break only applies to the block in which it appears:
The above will write ten lines, each with 11 numbers (1 number for the outer loop and 10 numbers due to the inner loop). The do command is also used to invoke subfunctions. See the discussion and examples below under the do command. For input/output, Mumps uses a scheme based on unit number. The Mumps compiler permits 10 unit numbers. By default, your program begins using unit 5, the console screen and keyboard (stdin and stdout in Linux terminology). You may open files and associate them with unit numbers through the open command and disassociate files from unit numbers with the close command. It is important that you close files that you have used for output as this will insure that the buffers have been written to disk. The use command tells the system which I/O unit to use. This unit remains in effect until changed. For example, the following copies the contents of file "aaa.dat" to file "bbb.dat" which is created if it did not previously exist:
Each read command sets $test to true is successful. On end of file, $test is set to false and the loop terminates. the ",old" and ",new" markers indicate if the file is being opened for input (",old") or output (",new"). Mumps is a very simple but powerful string manipulation and data base scripting language. It is similar in structure to early forms of BASIC and can generally be learned in a few hours. The following are a series of examples of Mumps programs and explanations of the code.
Each statement in Mumps begins with a unique command word. Often the command word is abbreviated to a single character. The single character abbreviations are unique for all commands except those which begin with the letter "Z". For commands not beginning with the letter "Z", Mumps does not check the spelling of the command word if more than one character of the spelling is given. Generally speaking, only the first letter is used to determine the command. Thus "write", "W", and "WRIGHT" all have the same meaning. The format of a command normally consists the command word or letter followed (optionally) by a post-conditional, followed by exactly one blank followed by the arguments to the command. Most commands can have multiple arguments. Multiple arguments are delimited by commas. If a line is to have more than one command, the first command is delimited by exactly one blank and the next command word or letter follows immediately. Blanks are very significant in Mumps. As noted above, most commands may be "post-conditionalized". A post-conditional is a logical expression which is used to determine if the command (and all its arguments) should be executed. It is like a small "if" statement. A post-conditional appears as a colon followed by an expression. If the expression evaluates to 0 (false), the command (or argument) is not executed. If the expression evaluates non-zero, the command or argument is executed. The following are examples of the above: an ordinary assignment statement:
same as above with command word abbreviation:
an assignment statement with multiple arguments:
an assignment statement post-conditionalized:
a multiple command line:
Table of Commands
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Write your Mumps programs with any standard ASCII editor such as vi or emacs. If you use a word processor, be certain that you save the file as ordinary text, without embedded control characters. Note: some word processors embed non-printing ASCII characters in the saved text. These will cause problems. Be sure to save the file in a form that does not contain embedded non-printing characters.
The format of a line of Mumps code is: an optional label followed by one or more blanks followed by the first command word of the line. Labels must begin in column 1, if one is present. For compiled code, blanks are preferred to tab characters but both may be used. For interpreted code, blanks are required (that is, tab will not work). If you need to have the interpreter recognize tab characters at the beginning of a line instead of blanks, change the TAB defined symbol in interp.h to \t and and recompile. Your program may include blank lines which are ignored.
The file extension of your Mumps source programs should be .mps.
To compile a Mumps program named myprog.mps, type the following:
Use of the Berkeley DB in standalone mode can be explicitly stated with one of the following commands:
To compile for the native globals, use one of the following commands:
The "n" or "native" option uses the large file system capable version of the native globals. This version must be run on a file system that supports files larger than 2 gigabytes (for example, ext3, xfs and several others).
In "native" mode the data base is stored in two files: "key.dat" and "data.dat". These may reside on different drives. The file "key.dat" contains the btree of globals and "data.dat" holds any associated data strings. The "key.dat" file can grow to multiple terabytes terabytes bytes and the "data.dat" file can grow to 2**64 bytes (64 bit addressing). Key.dat contains the b-tree and data.dat contains stored data.
The compiler (named mumps2c) may generate a few local header files that will be used during the C++ program compilation. They are generally of the form xxx.m. They may be safely deleted after compilation.
There are, since version 4, two forms of global arrays: those based on the original Btree package developed as part of this project and those based on the Berkeley Data Base (http://www.sleepcat.com). The former will be called the native global arrays and the later, the BDB global array data base in this document. Native globals are the current default.
Full documentation concerning the BDB is available from http://www.sleepycat.com. The BDB is licensed separately from its distributor. The BDB license is similar to the GPL but has important differences. You should read the license to see if it suits your application.
Mumps programs may be compiled for the BDB with one of the scripts listed above. If you use the BerkeleyDB, you must also install the Berkeley DB libraries on your machine, version 3.1.17 or later.
The BDB will create a file named Mumps.DB and several files with the prefix "__db." in the directory from which the Mumps program is run unless they already exist. The name and location of this file can be altered in the global.h header file.
Native global arrays can be either permanent or temporary. If temporary, they are created when a translated Mumps program first accesses them and destroyed upon program termination. The global arrays are temporary if the NEW_TREE preprocessor variable is set to 1 in sysparms.h. Temporary global arrays are useful if your data are loaded each time you run your program or if your permanent data base resides on server. Temporary global file names are constructed with a value based on the program's process id.
Permanent global arrays, the default, continue to exist after a program terminates. Global arrays will be permanent if the NEW_TREE preprocessor variable in sysparms.h is set to 0. Only permanent global arrays are possible with the BDB.
Native global arrays reside in two files. The names of these files can be set at compile time or run time by altering the values in the C++ variables "cfgdata" and "cfgkey". The filenames in these, including path names, will be used to open the global array files. The default names are are "data.dat" and "key.dat". The default names are in "btree.h" in the defined variables "UDAT" and "UKEY".
To change the native global array file names at run time, you must change them prior to any global array access. You do this by including two embedded lines of C++ code in your Mumps program. The following is an example of how to change the file names at run time:
The C++ function strcpy is used to change the values in the C++ variables svPtr->cfgdata and svPtr->cfgkey. The pointer svPtr contains the address of your program's state vector and is used whenever access to the state vector is required. The state vector is ordinarily not accessed but its definition is in include/mumpsc/stateVector.h. The above must be done before the first reference to a global array. You may select any names supported by your system. You must include these lines prior to the first usage of the global arrays. The global array handler uses the contents of these variables when it opens the files.
You may want to place the files on different disks to improve performance. One ("key.dat") contains the btree and the other ("data.dat") contains data stored at nodes. In MS Windows, you may include disk name information. Be certain that your compiled program has read/write permissions the directory in which you place the files.
The BerkeleyDB global arrays normally reside in a file named "Mumps.DB". The Berkeley DB will also create some files whose names begin with "__db." - these are part of the environment. The data base, however, is resident in "Mumps.DB". The name of the "Mumps.DB" file may be changed in "globals.h".
For Mumps programs, the global arrays are initialized if they do not exist and you access them for the first time. Compiled programs that neither reference nor open global arrays will neither open, create nor initialize the global arrays. The global arrays are automatically opened the first time they are used. If you are using the native globals and they are already in use by another Mumps program, your Mumps program will wait. If you do not use the global arrays, they will not be opened. If you use the Berkeley DB, multiple programs may concurrently access the data base.
If you use the native globals and if your program has a main routine, the globals will be automatically closed at termination. Otherwise, you must explicitly close them with a "zclose" command. Failure to close the globals may result in data and file integrity loss.
Global array references may contain string subscripts. Only printable ASCII characters are permitted as values for global array subscripts. The default collating sequence is ASCII for all indices (including numeric indices).
The global array file(s) will grow in size as elements are added. These file(s) may be copied for backups. Note: there are also builtin functions "$zcd" and "$zcl" that will dump and restore the globals to/from a flat ASCII file (see below).
Global array indices may consist of printable ASCII characters in the range 32 through 126. Normally, subscripts are stored as ordinary ASCII text (note: the BDB has an option to store all index data in an encrypted format).
The Berkeley DB arrays can be used concurrently by multiple programs on the same machine.
To configure the native global arrays, see the file "btree.h.in". The file "btree.h" is automatically generated by "configure" from "btree.h.in" when "configure" is run. Most of the values below can and should be set by "configure" however, they can be set manually such as when working with non-standard, proprietary systems such as MS Windows. The main configuration options are:
| ADSIZE | set to 4 if your file system supports only 32 bit file offset addressing; set to 8 if your file system supports 64 bit file offset addressing. |
| UDAT UKEY | The names of the data and key files respectively. The defaults are: "data.dat" and "key.dat". |
|
SEED NBR_ITERATIONS | The random number generator seed used in system testing and the number of test iterations. |
| BLOCK | The size of each btree block in bytes. The default is 8192. This number must be a power of 2 from 1024 to 262144. The default value appears to be optimal in testing. |
| PAGE_SHIFT | The number of bits to shift when storing file offsets. File offsets are stored in 4 bytes with trailing zeros removed. The number of zeros is determined by the BLOCK size. A BLOCK size of 8192 corresponds to a PAGE_SHIFT of 13 and a maximum file size of 16 terabytes. This value is set automatically depending on the value of BLOCK. |
| GBLBUF | The number of internally cached btree blocks. The number should be appropriate to your memory size. The total memory required is roughly GBLBUF*BLOCK. The default BLOCK is 8192 and the default GBLBUF is 4097 and these require 33,562,624 bytes. GBLBUF must be a power of 2 plus 1. examples: 9, 17, 33, 65, 1025, 2049, 4097. The value of AMASK is dependent on the value of GBLBUF. |
| AMASK |
Associative cache mask. This value is dependent
upon GBLBUF. It is used to mask out the high bits
of an address to produce an associative array
address. The value of the mask should equal (in hex)
GBLBUF-2.
For example:
if GBLBUF==9 define AMASK 0x7 |
If your program crashes after opening and updating the global arrays, the global array file(s) may be corrupt and may need to be deleted and restored. The reason for this has to do with the buffering of global array I/O requests. If the program is terminated and the buffers are not written, the B-tree on disk is invalid. For the Linux versions, SIGINT interrupts are normally trapped and the global array buffers are written to disk. With the Berkeley DB, if the data base is corrupt, your program may hang upon start up. Delete the files "Mumps.DB" and the files that begin "__db" and reload the data base.
The cache size for the BDB is set to 1,000,000 bytes. This may be altered. The maximum cache size supported is 4 gb and the minimum is 20,000. The cache size may be changed in "globals.h" through the "CACHE_GIGS" and "CACHE_BYTES" defined symbols. The BDB page size ranges between 512 and 65536 and may be set with the "PAGE_SIZE" symbol. The default is 1024. The cache size may be overridden at run time if you include a file in the directory in which the Mumps program runs named "DB_CONFIG" and include in that file a line to the effect:
set_cachesize 1 0 0
where the parameters are: number of gigabytes, number of bytes and number of contiguous caches (0 or 1 means one cache, more than 1 means the cache will be broken into multiple parts).
If you have an application that used a large cache size, you must delete the files named __db* before setting the cache to a new size. The __db* files may be safely deleted when no program is accessing them. The data base is actually in "Mumps.DB".
The cache and block sizes for the native globals are set by "configure" - see above. The native array cache is a one-way associative cache. It should be set to as large a value as is practical for the physical memory facilities of your machine. Note: if you have large block and cache sizes, you will notice delays on startup and termination. During startup, the global array buffers are allocated and initialized and during termination, the internal buffers are written to disk. These activities may be time consuming, depending upon your system.
The native global array file system is distributed under provisions of the LGPL license and may be more appropriate for proprietary applications. At present, however, it lacks, however, many of the failsafe and transaction processing features of the BDB.
The native globals underlying btree processor may also be used standalone as a C++ routine. See documentation in "btree.c"
To use a Mumps program with a web server, compile the Mumps program with the cgi.h header file. To do this, place the following line after the zmain:
This header file contains the code necessary to access the Web server QUERY_STRING environment variable.
Place the Mumps program in the Web server's cgi-bin (or other appropriate directory). From HTML documents, you reference Mumps programs with lines of the form:
Here, the name of the compiled (binary) Mumps program is taken to be yourprogram.cgibut in some systems the file extension may need be other than .cgi. Check your web server documentation to determine if executable files require a specific extension other than .cgi. An executable Mumps program must be given adequate permissions to be executed by the web server. Also, the web server must have permission to read and write files in the directory in which the global arrays are placed. Incorrect permissions and file ownership will result in failure. Temporary global arrays are placed in the directory that contains the program being executed. The web server must have permission to write files in this directory, too.
Upon initialization of the Mumps compiled program (if the cgi.h file was included during compilation), the variables appearing in the HREF (var1 and var2 in the above) will exist in the Mumps symbol table and have the values provided by the browser (11111 and 123, in this case). The web server extracts the parameters from the HREF and places them in an operating system environment variable namedQUERY_STRING. The software in cgi.h looks for QUERY_STRING and decodes it (non alphabetic and non- numeric values are encoded). It takes each parm=value expression and creates a Mumps variable named parm and sets its value to value. If cgi.h is omitted, you will not have access to web server passed values. The total length of the parameter string in QUERY_STRING may not exceed 1024 bytes. The full value of QUERY_STRING is also contained in the Mumps variable %QS during execution. The executing Mumps program may determine that is was invoked by the web server by testing for the existence of %QS. The environment variable REMOTE_ADDR is also captured by cgi.h and stored as the Mumps runtime variable %RA However, you may invoke a Mumps program in simulated Web server mode by calling it from a shell script such as the following (for the Linux Bash Shell):
Be certain to Halt at the end of a program in order to terminate the program. If you do not correctly terminate the Mumps program, the web server may hang.
When using temporary global arrays, the global array names are constructed from the process id and are therefore unique. For programs with permanent native globals not using the server option, Mumps compiled programs insure that only one program is running at any given time on any given database files. Non-server native global Mumps programs open the database files for exclusive access. Thus, non-server native globals Mumps programs should be short, transaction oriented jobs that do not delay the system. When a non-server native globals Mumps program attempts to execute and the files it wants are in use, it waits. Note: since only one copy of a non-server native globals Mumps application is ever running for a given database, all file accesses are also exclusive and thus the Lock command has no meaning. The Berkeley Data Base permits multiple programs to concurrently read from the data base but only one program to update the data base at any one time.
Mumps programs can now become Apache modules under late versions of Linux and Apache 2. This means that your Mumps program can be directly executed as a loadable shared object by the Apache server. In the distribution, there is a code module, mod_mumps.c, that builds a Mumps module that will permit the native Mumps Compiler interpreter facility to execute as an Apache 2 dynamically loadable object. The following are the details to install this facility:
A quick script to to most of what is listed below is in
MakeApacheModule. Note: this script does not add the
To install this module, you must have Apache installed with the
development tools and the Mumps compiler package, as well as a
standard C++ compiler (which is required by the previous tools).
From within the directory of your module source, you need
privileges to install modules into the Apache directory.
You should be logged in as root to do this.
To compile the module:
/usr/local/apache2/bin/apxs -c -a -i mod_mumps.c -lmumps -lmpsglobal_bdb -ldb -lpcre -lapr-0 -laprutil-0
This will create the module files and install them into the default module
directory created by Apache. Then it will edit the httpd.conf file located
within the configuration directory of your Apache installation.
The default installation directory if you build and install with the
download from www.apache.org will be /usr/local/apache2. We assume
this directory in our code.
After you compile and install the module you need to edit the httpd.conf
to ensure that the correct settings are installed. This file is
in /usr/local/apache2/conf.
Under the Dynamic Shared Object Support in the httpd.conf file. You should
see the following line in the section under the description.
This should have been placed by the apxs tool when you create the module, if
it is not there search for it in the document and make sure its there.
After you verify that line exists in the configuration file, you must then
tell Apache to give every request for a mumps file to the correct module.
This next set of lines accomplishes this goal for every file with the
extension of .mps
If you have any other extensions associated with Mumps source files you can also add
their extensions in the same fashion.
After you install the module and edit the config file, you will need to start or
restart the Apache web server in order for the module to work properly.
typically:
/usr/local/apache2/bin/apachectl start
or
/usr/local/apache2/bin/apachectl restart
Congratulations, your installation of a Mumps module is complete.
Now you can access Mumps source files directly through the interpreter rather
than using CGI on executables.
You may place the *.mps file in any directory but the file
must be world readable.
Then there is the issue of the data base files. These
need to be readable AND writable by the web server.
Generally speaking, this means they need to be created
prior to their first access by the web server.
You can create them (Mumps.DB, and __db.001, __db.002
and _db.003 - sometimes a few more, or key.dat and data.dat, with a dummy
Mumps program:
(use some other variable name if ^a is needed in your app).
You can now do one of two things:
Either technique will work but the first is
risky in an unsecure system. The second will
generally require system privs.
The file "mod-mumps.so" is a binary Mumps module
that was compiled on a Mandrake 9.1 system.
It may or may not work on your system, depending
on libraries and other factors. Place it in
your modules directory and make the noted changes
to httpd.conf It may work. Otherwise, build
from scratch.
When running with a web server, it is critical
that your Mumps program have sufficient file access permissions to be executed
by the web server. This applies not only to executable programs
but also to any associated directories and files.
Further, all non-server global array files must
also be read/write accessible to the web server.
On some systems, you must place your web server executables into
a specially named directory, such as cgi-bin.
Execution of programs by the web server requires
complete compliance with these instructions.
Uncontrolled Program Termination
If you halt a non-server compiled program with a control-C or other external Kill command, the native globals global array data base may be corrupted. For temporary files, this means that the temporary files may not be correctly deleted. For non-server permanent globals, the files may be corrupt. Back-up copies of critical data should be maintained. A dump function exists ("$zcd") that copies the global arrays to an ASCII text file which can be used to reload the data base. Generally speaking, programs that do not access the globals or access them only to read their contents, do not corrupt the global arrays if forcibly terminated. Compiled Mumps programs attempt to intercept control-C (SIGINT) signals and terminate without error but this is not always possible.
Program Formats and Error Messages
Mumps programs may be created with any standard system editor which does not introduce embedded control codes into the program. Be careful here. Many word processors embed invisible control codes into your program.
If you invoke the interpreter (by the "@" operator or the xecute command), errors may be detected. Normally, error messages will be printed and the program will terminate.
You may trap errors by using the try command and the InterpreterException catch option. If you trap errors from the interpreter, you may also suppress error message printing by means of the NoMessages control word in the try command. Examples:
set a="2+2+" // an invalid expression that will trigger an interpreter error write @a,! The interpreter will generate error messages and the program will halt.set a="2+2+" // an invalid expression that will trigger an interpreter error try write @a,! catch Interpreter Exception write "interpreter error",! The interpreter will generate error messages and return to the Mumps program which will write the error message and continue execution.set a="2+2+" // an invalid expression that will trigger an interpreter error try NoMessages write @a,! catch Interpreter Exception write "interpreter error",! The interpreter will return to the Mumps program which will generate the error message and continue execution. The interpreter will not generate error messages.
The following is a lsit of exceptions that may be detected with the 'try' command:
The list of basic system runtime error messages is as follows:
1 Multiple adjacent operators
2 Unmatched quotes
3 Global not found
4 Missing comma
5 Argument not permitted
6 Bad character after post-conditional
7 Invalid quote
8 Label not found
9 Too many/few fcn arguments
10 Invalid number
11 Missing operator
12 Unrecognized operator
13 Keyword
14 Argument list
15 Divide by zero
16 Invalid expression
17 Variable not found
18 Invalid reference
19 Logical table space overflow
23 Symbol table full
24 Function argument error
25 Global not permitted
26 File error
27 $N error
29 <break> at line:
30 Function not found
31 Program space exceeded
32 Stack overflow
Compiler Implementation Overview
This compiler does not implement the full 1995 Mumps (M) standard. It implements many of the features of the 1995 standard with both omissions and extensions. Work is on-going so the list of features will grow.
The compiled modules execute between 1.5 and 6 times faster than the same code executing on an interpreter. The lower multiplier reflects benchmark programs which are very global array intensive while the higher multiple is for programs that are less global array intensive.
The C++ code generated by the compiler has comments which are the original Mumps program's line and line number. The compiler also interjects its own comments in places to explain what it is doing. The C++ code should be fairly easy to follow. Naturally, you may alter the C++ code to add your own features.
This effort arose out of work to use Mumps as a server-side web scripting language. For this purpose, it is amazingly well suited (see the patient record system examples). To work in in the web server environment, changes and extensions were made on an interpreter written by this author in the early 80's. One set of changes involved the ability to extract from the server environment data passed from browser forms. These data, in the form of name=value pairs, partly encoded, are automatically translated by the interpreter to Mumps variables with initialized values. Also, the need was recognized to be able to embed HTML code in Mumps programs and have the interpreter scan the HTML and substitute any expressions found in it with their results. Example: < title > &~^patient(ptid)~ < /title >
Here, the global array reference is replaced by its value. The &~ and ~ are delimiters. This works very well.
The key to this was the old Mumps interpreter which was very small (about 60,000 bytes under Linux) and quite efficient. It was a single user environment and had no major O/S issues inhibiting its interface. Since web transactions are very brief, serial locking of the data base works very well. A data base stand-alone daemon was written which took queries from a web server invoked database-less version of interpreter but it was actually slower and had many more integrity and security issues. The serial lock version works better. Tests show that a small, quick transaction oriented interpreter works very well.
In order to improve the performance even more, it was decided in November of 1998 to try compiling Mumps by modifying the Mumps interpreter written by this author to generate C++ code and then compiling the C++ code to binary.
One advantage of full compilation is interoperability with other languages and with the host operating system. This is achieved in by compiling to C++ which has full access to all system features.
Be very careful of required syntax in Z commands. See the examples below and in checkout.mps. Error messages derive from both the Mumps compiler and the C++ compiler. Error messages, sometimes many, from the C++ compiler are not be helpful and can cause considerable frustration. You can, however, look in the C++ code to see what original line of Mumps may have generated the error.
The following lists some important changes that have been made. Mainly
these center around added commands to adjust to the C++ environment. Mainly,
these take the form of program and function structuring commands and data
declaration.
Writing Programs, Functions and Calling Conventions
All programs must have a 'main' function. Because Mumps programs can be used with C++ programs, the 'main' function may be in the C++ routines.
However, if there is no 'main' C++ routine, you must designate a Mumps routine as 'main'. This is done by means of the "zmain" command which tells the compiler that the code following it should be the 'main' function. The "zmain" command must be the only command on the line on which it appears. It may not have a label.
If you attempt to compile and link Mumps code that has no "zmain" or C++ "main" function, you will receive error messages from the compiler and the link editor.
Alternatively, you may compile one or more Mumps functions, none of which contain "zmain" if they are linked to either a Mumps or C++ module that contains a main function. See the section below on "Main programs and Functions"
The "zmain" command takes no arguments and should be the only command on the line. The line begins with one or more blanks. No label is permitted. The command generates a C++ 'main' program prologue. The prologue contains many definitions required by the generated C++ code. When a main program ends, the epilogue automatically closes the global arrays. On the other hand, global arrays are not automatically closed on conclusion of a sub-function.
When you compile your Mumps program, one or more C++ routines will be created. These, in turn, are compiled into binary executable code. The mumpsc compiler produces C++, not binary executables or assembly language.
There are three ways to introduce functions into a Mumps program environment:
The simplest of these are the first: internal Mumps functions. These take the following forms:
This form of subroutine was the original form in Mumps. No prarmeters were permitted to be passed to the subroutine. The subroutine shares the same namespace as the calling program hence the values of the variables i, j, and k are accessible to the subroutine and changes to them are relected in the main program.
zmain
set i=10
set j=20
set k=30
write "main program: ",i," ",j," ",k,!
do test
write "main program: ",i," ",j," ",k,!
halt
test
write "sub-program: ",i," ",j," ",k,!
set i=11
set j=22
set k=33
quit
which produces the following output:
main program: 10 20 30
sub-program: 10 20 30
main program: 11 22 33
This form of subroutine call was introduced later. It permits parameters to be passed to the subroutine but the subroutine and calling program have different namespaces. That is, variables in the calling program are not visible to the called program and variables created in the called program are deallocated upon return and are thus not visible to the calling program. Changes to parameters in the called program do not change the corresponding arguments in the calling program.
zmain
set i=10
set j=20
set k=30
write "main program: ",i," ",j," ",k,!
do test(i,j,k)
write "main program: ",i," ",j," ",k,!
halt
test(a,b,c)
write "sub-program: ",a," ",b," ",c,!
set a=11
set b=22
set c=33
quit
which produces the following output:
main program: 10 20 30
sub-program: 10 20 30
main program: 10 20 30
Same as the above but 'call be reference' permitted. That is, changes to parameters made by the called program cause changes to the corresponding arguments in the calling program. Note the "." in front of the variables in the 'do' command that are to be passed by reference. Both call by reference and call by value arguments may be mixed in the same 'do' statement.
zmain
set i=10
set j=20
set k=30
write "main program: ",i," ",j," ",k,!
do test(.i,.j,.k)
write "main program: ",i," ",j," ",k,!
halt
test(a,b,c)
write "sub-program: ",a," ",b," ",c,!
set a=11
set b=22
set c=33
quit
which produces the following output:
main program: 10 20 30
sub-program: 10 20 30
main program: 11 22 33
In each of the above examples, the subroutine and calling program are actually part of the same C++ function. In effect, subroutines of the type shown above as similar to the old Basic 'gosub' facility. Functions such as shown above may also return values:
Example recursive factorial computation:
zmain
set i=$$factorial(5)
write "factorial=",i,!
halt
factorial(a)
write "sub-program: ",a,!
if a<2 quit 1
quit a*$$factorial(a-1)
which produces the following output:
sub-program: 5
sub-program: 4
sub-program: 3
sub-program: 2
sub-program: 1
factorial=120
Note: while inline functions that do not take arguments may return values, because they share the same namespace with the calling program, an example such as the above is impractical.
In addition to inline functions created by the mumpsc compiler, you may compile separate, non-inline Mumps functions in eithe Mumps or C++. Non-inline functions are compiled to separate C++ functions and may be stored in object libraries and linked into executables at independently.
If you write your own C++ routines that are either called by a Mumps routine or call a Mumps routine, they must obey the Mumps calling conventions.
A non-inline function is invoked differently that an inline function. For exampe, the may be invoked as functions returning a value:
set i=$$^MyFunction(a,b,c)
or by means of the "do" command such as:
do ^MyFunction(a,b,c)
where "MyFunction", when written in Mumps, is usually something of the form:
^MyFunction(a,b,c) write a+b+c,! quit a+b+c
Non-inline functions should normally be placed at the beginning of your source code file with any other functions prior to "zmain" and any other invocations. Example:
^MyFunction(a,b,c)
set i=a+b+c
quit i
zmain
write $$^MyFunction(1,2,3),!
halt
(The above will write "6".) Note that non-inline functions begin with a "^". function if you do not place non-inline functions prior to their first reference, you will need a C++ code function header. For example, the above program could have been re-written with the non-in;ine function appearing at the end if a header for the function appeared at the beginning:
+char * MyFunction(struct MSV *, char *, const char *, const char *, const char *); zmain write $$^MuFunction(1,2,3),! halt ^MyFunction(a,b,c) set i=a+b+c quit iNote the C++ function header. The first two arguments reflect internal structure and are always present while the remaining three arguments reflect the parameters actually passed to the function. The initial argument is the address of the runtime state vector and the second argument is a character string giving the label of the line in the subroutine where execution is to begin (rather than at the beginning). Normally, the second argument is the empty string ("") and subroutines begin execution on their first line. Generally speaking, it is easier to place functions prior to their first use, if possible.
All functions beginning with the "^" character are generated as separate C++ functions and are called using C++ calling conventions. These functions may recursively call themselves and may be called by other C++ programs. Functions beginning with the the "^" symbol push the runtime symbol table on entry and pop the table on exit. Thus, local variables created during subroutine execution are lost upon exit except for those passed as arguments with the "." operator.
Additionally, functions may be in-line parts of your current program. These are not actual C functions but local groups of code that may be invoked by means of "do" or "$$"-type function invocations. These need not appear prior to their first use. An example of this is as follows:
zmain set a=2 do abc write "a=",a,! set a=2 set x=$$abc write "a=",a," x=",x,! set a=2 set b=9 write $$xyx(a,b),! write "a=",a,! halt abc write "hello world a=",a,! set a=22 quit "999" xyx(a,b) write "in sub x=",x,! set a=a*b quit a output: hello world a=2 a=22 hello world a=2 a=22 x=999 in sub x=999 18 a=2 Note that when calling inline functions, the ""^" is omitted. Also note the differences in symbol table use. For compatibility with earlier standards, when the invocation of "abc" is made, the symbol table is not pushed. Thus, the setting of variable "a" in the subroutine has the effect of creating and setting the variable in the calling program too. On the other hand, invoking a subroutine with arguments ("xyx"), results in a symbol table push/pop on entry/exit and changes made to the variable "a" in the subroutine are not effective in the calling program.
In general, the symbol table rules are:
- Variables from calling programs are visible to called programs except when the variable name is otherwise reused as in the case of formal parameters or the new command.
- If a subroutine is invoked with arguments, any changes made to a variable will be lost on exit. If a subroutine is not invoked with arguments, changes to variables will visible to the calling program.
- Inline subroutines are not recursive. Thus the following will not work:
^aaa(a) write a,! if a=0 quit 0 quit a+$$^aaa(a-1) zmain set x=$$^aaa(5) write "x=",x,!but the following does work (non-inline functions):
^aaa(a) write a,! if a=0 quit 0 quit a+$$^aaa(a-1) zmain set x=$$^aaa(5) write "x=",x,! output: 5 4 3 2 1 0 x=15Note that the "$$" figure is used when the function is being invoked with anticipation of a return value. The "$$" is omited when a function is referenced by a "goto" or "do" command. The "^" is present only when calling separate C++ functions.
Functions are compiled in one of two ways:
If the Mumps function name begins with a circumflex ("^"), the Mumps function becomes a C++ function separate from the C++ program "main" function. This is called a "separately compiled function." If the Mumps function name does not begin with a circumflex, the Mumps function becomes an inline section of code within the C++ function in which it appears. Only separately compiled functions may be called recursively.
A new namespace is created on entry into a Mumps separately compiled function (called with a "^" prefix) and deleted upon exit. Variables passed to the function are copied to the new namespace but they are not copied back to the restored namespace on exit unless passed by the call-by-reference feature. The function may return a value to the calling program through the "quit" command.
When calling a separately compiled function, variables created in the function are lost when the function exits. Variables known to the calling program are available to the called program unless the called program receives a variable in its argument list with the same name. For example:
^test(abc) set x=1 write y,! write abc,! quit abc*2 zmain set abc=888 set y=999 write $$^test(222),! write abc,! write x,! halt The above will print:
999 (from the "write y,!" in the subroutine)
888 (from the "write abc,!" in the subroutine)
444 (from the "write $$^test(222),!" in the main program)
888 (from the "write abc,!" in the main program)
*** Variable not found in or near line 11The error at the end is from the "write x,!" in the main program - there is no value for "x" at this point - the value from the function was deleted on function exit.
If your function calls itself either directly or indirectly (that is, it is a recursive function), it must be compiled as a separately compiled function (^).
Please review the notes below under the new command for details concerning symbold table manipulation in functions.
If the result of a function is the argument to another function, it will be invoked regardless of the function called. Thus, the function "$$abc(1,2,3)" in the following is always invoked even though the "select" terminates after the first operand:
set i=$select(1:1,0:$$abc(1,2,3)) Separately compiled functions must appear before they are first referenced or there must be a C++ function header appearing prior the the first use of the function. A C++ function prototype for a function is of the form:
+ char* fcnName(struct MSV * svPtr, char* ep, const char* arg1 ...); alternatively, the built-in define symbol "StateVector" may be used: + char* fcnName(StateVector svPtr, char* ep, const char* arg1 ...); "StateVector" is defined in "mumpsc/stateVector.h" as "struct MSV *" and may be used to simplify the code.
Place as many constructs of the form "char* arg1" as there are formal parameters. The "ep" argument must be present and is separate from the formal parameters. The pointer "svPtr" points to the runtime state vector which contains many parameters concerning the running program. Normally, when calling a Mumps function from a C++ program, the "ep" parameter will be the empty string.
If you call a Mumps function from a C++ program, you must provide a state vector address. You can do this by calling the built-in function "AllocSV()" as follows:
#include StateVector svPtr=AllocSV(); char *mpsFcnCall(StateVector,char *,const char *,const char *,const char *); . . . mpsFcnCall(svPtr,"",arg1,arg2,arg3); free (svPtr); . . . Thus, if you have a Mumps function whose entry point is:
Fcn(a,b,c)its prototype will be:
+ char * Fcn(StateVector svPtr, char * ep, const char *, const char *, const char *);Inline functions must contain a quit command. A source code end of file is interpreted as a halt command.
Examples:
^subFunction(a,b,c) write "subFunction() main entry ",a," ",b," ",c,! quit a+b+c ep write "subFunction() ep entry ",a," ",b," ",c,! quit 123 ^test3() write "test3() entered",! quit "test3 returns" zmain write $$^subFunction(1,2,3),!! write $$ep^subFunction(1,2,3),!! do ^subFunction(9,8,7) do ep^subFunction(10,20,30) do ^test3 write $$^test3,!! write $$test1,!! do test1 write $$test2(1,2,3),! do test2(90,80,70) halt test1 write "test1 entered",! quit "test1 returns" test2(a,b,c) write "test2 entered ",a," ",b," ",c,! quit a+b+c In the above examples, subFunction() and test3() are compiled as separate C++ functions. These may be called by either Mumps programs or C++ programs. Alternatively, test1 and test2() are compiled as part of the Mumps main routine and these may only be called by Mumps code that is also part of the main routine. test1 and test2() may not be called by C++ programs or Mumps programs compiled as separate C++ functions. Inline functions may not call themselves. Use separately compiled functions for recursive calls.
Please note the Mumps calling structure. The separately compiled functions may be entered either by the do command, a goto command or as function references. A separately compiled function is a function linked into the executable module as a subroutine. Such a subroutine may be compiled either at the same time or separately from the main ("zmain") routine but it is linked into the final resulting module. All these routines begin with the "^" character. If entered by the "do" command, separately compiled function names are prefixed by the "^" character. If entered as function references, their names are always prefixed by "$$^".
Internal or inline functions ("test1" and "test2") may be entered by the "do" or "goto" commands or by means of function references if and only if the entry point has parameters. If invoked by "do" or "goto", the name is the same. If entered as a result of a function reference, the name is preceded by 2 dollar signs ("$$").
You may call separately compiled external functions from C. The function prototype for the Mumps function will be of the form:
char * FunctionName(struct MSV * svPtr, char * ep, const char * arg1, const char * arg2, ... ); The parameter "ep" is either the empty string ("") or a string containing the name of a label. If not empty, "ep" contains a string with the name of a label. Execution will begin at that label. If there are arguments, they are passed as character strings. The function returns pointer to character string. The pointer "svPtr" gives the address of the system state vector and is used to access system parameters.
You may create a separate function in C, either in the same file as the Mumps program or in a separate file by following the format of the prototype given above: it must return a pointer to string, you will receive at least two arguments, the "ep", a pointer to strings, and "svPtr", a pointer to the system state vector. Following these, you will receive the actual arguments in successive pointers to string. Be certain that the pointer you return is not pointing at an automatic variable that will expire upon function exit.
For example, the following is a C++ function embedded in a Mumps program. It appears at the beginning, before the "zmain" command (all inline C functions should appear prior to any Mumps functions):
+ #include + #include + char* Bounds (struct MSV * svPtr, char* ep, const char* p, const char* MinFreq, + const char* MaxFreq, + char* pp, char* MinDocs) { + long a,b,c,d,e; + a=atol(p); + b=atol(MinFreq); + c=atol(MaxFreq); + if (a c) return "1"; + d=atol(pp); + e=atol(MinDocs); + if (d It is invoked by the following from the Mumps program:
if ($$^Bounds(%,MinFreq,MaxFreq,%%,MinDocs)) do ... Because Mumps is slow when performing arithmetic, it may be desirable to write short C functions to do the arithmetic as the example shows. (The example is taken from the program "reader.mps" contained in "doc/examples/ISR" in the distribution.)
If your program contains no Mumps "zmain", but does contain Mumps sub-functions followed by C++ code, you must have a "zexit" command to indicate to the Mumps compiler the end of your function or functions. If you elect to disregard this requirement, errors will result. For example:
# a C++ subroutine called by Mumps + char* Cfcn(struct MSV * svPtr, char * ep, const char * gbl) { + printf("%s ",gbl); + return ""; + } # a Mumps subroutine ^subFunction(a,b,c) write "Main Sub function entry point Entered",! xecute "for i=1:1:10 set ^a(i)=i" write "a=",a," b=",b," c=",c,! quit a+b+c ep write "ep Sub function entry point entered",! for i=1:1:10 set %=$$^Cfcn(^a(i)) write ! quit a*b*c zexit # the C++ main program + int main() { + unsigned char *p1,*p2; + struct MSV *svPtr=AllocSV(); + printf("hello world\n"); + p1=subFunction(svPtr,"","2","3","4"); + printf("First call returned: %s\n",p1); + p2=subFunction(svPtr,"ep","2","3","4"); + printf("Secnd call returned: %s\n",p2); + return 0; + } This example contains a C++ main program and sub-function ("Cfcn") and a Mumps sub-function ("subFunction"). The "zexit" command is required after the last Mumps sub-function in order to indicate to the compiler that it has finished the Mumps routines and needs to install the epilogue code. If the "zexit" is missing, the compiler will assume the C++ main routine is part of the preceding Mumps sub-function.
The "zexit" is not needed if all the C++ functions appear prior to the first line of Mumps code.
The following is an exhaustive list of examples:
+char * ddd (struct MSV *svPtr, const char *ep, const char * i) { + /* c functions should appear first */ + printf("ddd entered %s\n",i); + return ""; + } ^aaa() write "^aaa entered",! quit ^bbb(i) write "^bbb entered ",i,! quit ^ccc(i) write "^ccc entered ",i,! quit ^eee() quit "hello world" ^fff() quit "hello other worlds" zmain write "main entered",! do ^aaa do aaa do bbb(456) do ^bbb(777) do ccc do ^ccc(123) do ^ccc(321) do ^ddd(333) do ^ddd(444) write $$^eee,! write $$^fff,! goto ^aaa write "main exits",! halt aaa() write "aaa entered",! quit bbb(i) write "bbb entered ",i,! quit ccc write "ccc entered",! quit The out of the above is:
main sub 1 1 2 sub 2 1 2 main return [root@neamh mumpsc]# cd doc [root@neamh doc]# vi compiler.html [root@neamh doc]# cd .. [root@neamh mumpsc]# xxx.cgi main entered ^aaa entered aaa entered bbb entered 456 ^bbb entered 777 ccc entered ^ccc entered 123 ^ccc entered 321 ddd entered 333 ddd entered 444 hello world hello other worlds ^aaa entered
- Linking from C++ Programs
C++ programs can call upon Mumps methods. See the following example:
hct.mps ^MaxHct(ptid) if $data(^pat(ptid)) quit "0" set i=-1 set max=0 for do . set i=$next(^ptHct(ptid)) . if i<0 break . if i>max set max=i quit max ^MinHct(ptid) if $data(^pat(ptid)) quit "0" set i=$next(^ptHct(ptid,-1)) if i<0 quit 0 set min=i for do . set i=$next(^ptHct(ptid)) . if i<0 break . if i
patient.cpp #include char * MaxHct(struct MSV *, char*, const char*); char * MinHct(struct MSV *, char*, const char*); char * AvgHct(struct MSV *, char*, const char*); char * CountHct(struct MSV *, char*, const char*); char * HctValue(struct MSV *, char*, const char*, const char*); char * findPatient(struct MSV *, char*, const char*); class PatientHct { public: PatientHct(); double Max(); double Min(); double Avg(); bool Exists(char*); long Count(); double Value(); private: char ptid[32]; char current[32]; char hctVal[32]; struct MSV * svPtr; }; PatientHct::PatientHct() { strcpy(ptid,""); strcpy(current,"-1"); svPtr=AllocSV(); } double PatientHct::Max() { return atof(MaxHct(svPtr,"",ptid)); } double PatientHct::Min() { return atof(MinHct(svPtr,"",ptid)); } double PatientHct::Avg() { return atof(AvgHct(svPtr,"",ptid)); } long PatientHct::Count() { return atol(CountHct(svPtr,"",ptid)); } double PatientHct::Value() { strcpy(current,HctValue(svPtr,"",ptid,current)); return atof(current); } bool PatientHct::Exists(char *ptnbr){ if (findPatient(svPtr,"",ptnbr)=="1") { strcpy( ptid, ptnbr); return true; } strcpy (ptid, ""); return false; } int main() { double val; char ptnbr[32]; PatientHct pHct; while (1) { cout << "enter ptid "; cin.getline(ptnbr,32); if (!pHct.Exists(ptnbr)) { cout << ptnbr << " not found. Exiting." << endl; break; } if ( pHct.Count() > 0 ) while ( (val = pHct.Value()) > 0) cout << val << endl; else cout << "Sorry, not Hct's for " << ptnbr << endl; } return 0; } To compile and link the above, use commands of the form:
mumps2c hct.mps g++ -c hct.cpp g++ patient.cpp hct.o -lmpscpp -lmumps -lmpsglobal_native -lpcre
- Creating and Linking Multiple Mumps Object Files Together
Mumps functions that are separate C++ functions (i.e., their names begin with two circumflexes), may be separately compiled and linked together from object code modules. For example, if you have a main Mumps function in a file named main.mps that calls upon a function contained in the file test.mps, you may first translate the functions to C++ and then compile them to object code, then link them as follows:
mumps2c test.mps g++ -c test.cpp mumpsc main.mps test.o This assumes that the main function is in main.mps Likewise, test.cpp contains the subroutine also created by the mumps compiler. Only one zmain command is permitted in any final binary executable.
Be careful not to use the underscore character in function names. In Mumps this means concatenate. Be careful not to use the names of functions already known to the C++ environment, including those names found in "bifs.c" in the distribution.
- Applications with Many Program Modules
Some applications consiste of literally thousands of individual Mumps code modules. These are invoked by one another by constructs such as "do ^xxx" or "do ^@xxx". In interpretive based Mumps systems, these constructs do not create probles as the modules are executed directly from source code or from compressed bytes code representations of the modules.
In a compiled environment, however, these constructs are more problematic. In particular, the mocules must be pre-compiled and they must be available to be dynamically loaded at run time.
If all modules in a large system, such as the VA Vista, were compiled into one, large single executable, it would be too large to load on even the largest machines. Consequently, we have developed the dynamically linked shared object facility described Parameters to Subroutines
From Version 6, the compiler supports both call by value and call by reference forms of parameter passing for compiled code. This option is not presently supported in the interpreter.
Arguments are passed by reference if their names are preceded in the calling routine by a decimal point. Otherwise, they are call by value.
Call by reference variable that are altered in a called routine are altered in the calling routine whereas call by value variables are not affected by changes made to them in subroutines. The decimal point precede variable names to be called by reference only in the calling routine.
Example:
^tst(a,b) set a=100 set b=200 quit zmain set a=0 set b=0 do ^tst(.a,b) write a," ",b,! halt The above will write "100 0". If a calling parameter other than the first or last is omitted, a zero will be inserted in its place. For example:
^abc(a,b,c,d) write a,b,c,d,! quit zmain do ^abc(1,,,,4) will be understood as though you had written: do ^a(1,0,0,4) You may not omit the first or final parameter.
- C++ style language comments
You may place a comment on a line of Mumps (in compiled code only - this feature is not available in the interpreter) by beginning the comment with "//". One or more blanks should precede the comment except following argumentless commands in which case 2 or more blanks must precede the "//". The "//" may also be used at the beginning of a line starting in column 1.
- The "do" and "goto" commands
The "do" and "goto" commands in the compiler may reference function names and it may pass parameters if the functions are compiled into the executable module or are local to the program. See the examples in checkout.mps. This means that constructions of the form: "do ^abc.mps" require that "abc.mps" be precompiled either as part of the current source code module or linked into the final executable by means of object modules included with the link edit or by means of shared object libraries. The same restriction applies to the "goto" command.
In the interpreter, however, the construction "do ^abc.mps" dynamically invokes the source code program "abc.mps" and interprets it directly. This mode of operation, however, is much less efficient as interpretation is about 5 times slower than compilation.
- Compiling Programs
The command to compile, link and execute the demo program (under Linux) is:
mumpsc checkout.mps where mumpsc is the name of the Linux shell script provided with the distribution. The script compiles your Mumps program (checkout.mps) to C++ and then compiles the C++ program to an executable that will be named checkout.cgi.
Some C++ compilers check for error/warning conditions that others do not. The code generated by this compiler compiles and executes correctly on the MS Visual C++ 6,0 and Linux C++ compilers. If you have problems, please send me mail giving the type of compiler and the error. Some DOS compilers do not provide all required library functions. If this is so, you will need to write the missing functions. See any standard Linux system for any needed definitions.
The Mumps Compiler will generate error messages which are self explanatory. In rare cases, some errors will be detected by the C++ compiler or the loader. Loader messages usually refer to subroutines you have named but not included. C++ compiler messages will contain a line number. See the C++ module for your program at the line number given. Look on the preceding lines and you will see, perhaps several lines above, a line showing the original Mumps code in your program that caused the error.
With version 8, the Mumps Compiler produces C++ translations of Mumps source programs and these translations, in conjunction the the MDH (Multi-Dimensional and Hierarchical) Library (also distributed with the Mumps Compiler) may be integrated into larger C++ applications. This, for example, permits C++ programs and class libraries to directly access Mumps global arrays and to manipulate and navigate the arrays in the same manner as in Mumps. It also permits C++ programs and classes to directly invoke Mumps routines, including routines which use indirection. For the first time, Mumps and C++ programs can share the same variables.
For example, consider the following hybrid C++/Mumps program:
|
|
Where "mstring" is an MDH data type that mimics the typeless varaibles in Mumps. Instances of class "global" are global arrays which can be accessed by either Mumps or C++ routines. For example, the above could have been expressed entirely in C++ as follows:
^FindNext(test,max)
for do
. set id=$order(^Labs(id))
. if id="" break
. set name=""
. for do
.. set name=$order(^Labs(id,name))
.. if name="" break
.. set date=""
.. for do
... set date=$order(^Labs(id,name,date))
... if date="" break;
... if ^Labs(id,name,date)>max goto exit
quit 0
export name,id;
exit quit 1
zexit
+ int main() {
+ mstring name("name");
+ mstring id("id");
+ mstring date;
+ mstring test;
+ mstring result;
+ mstring avg;
+ mstring max;
+ global Labs("Labs");
+
+ cin >> test >> max;
+ id="";
+ while (1) {
+ result=FindNext(svPtr, "", test, max);
+ if (result == 1) cout << id << " " << name << endl;
+ }
+ return 0;
+ }
Note that "mstring" variables "name" and "id" in the C++
program are declared with string constants. These are the
Mumps runtime symbol table names for these variables.
When the Mumps function is run, these variables are
availble to the Mumps program. The "export" command
is similar to the "export" shell command in Linux:
it causes the named variables to be exported from the
current level of the symbol table to the outer layers.
Otherwise, all local variables would be lost on exit.
On entry to the Mumps routine, any variable ("id" in
this case) not found in the current symbol table
layer is sought in outer layers.
The Mumps Compiler now generates C++ code and thus supports the C++ based MDH Toolkit. The MDH Toolkit not only includes classes and methods that provide a Mumps personality to C++ programming, but also a large number of specialized functions to manipulate matrices, genomic and text data.
A line with a pound sign in column one is taken as a comment.
A line beginning with a percent sign (+) is taken as in-line C++ code.
No label may have the same name as a variable. Use of labels and variable names that are the same can cause unpredictable behaviour.
After the last Mumps argument or command on a line, two adjacent forward slash characters (//) are permitted. The remainder of the line will be interpreted as a comment. Note: if the last Mumps command on the line takes no arguments (for example, the argumentless DO), there MUST be at least two spaces between the argumentless command and the // (if present). Otherwise, one or more blank must precede the //.
Line execution level codes may be inserted in a line as the first item following the blank character. The line level codes are from one to ten decimal points followed by exactly one blank. Lines with line levels greater than the current line exception level are skipped. Only ten levels are permitted.
Commands may be abbreviated or fully spelled out. As this is a compiler, not an interpreter, there is no penalty for writing readable code. If more than one character is used in a command name, it must be fully spelled out.
In the first of these, the file will be created and only output (write) operations are permitted. In the second, the file is presumed to exist and only input operations will be permitted. If the new option is given, any previous generation of the file is deleted.
for i=$fcn(i) for i=1:$fcn(i):10 for $fcn(i)
Compiled Mumps source programs may be of any length. Interpreted programs may not exceed the maximum size of the "ibuf" cache set by "configure". This number may not exceed 32,367 and it would not be prudent to lower it below 4,096.
You may substitute your own global array processor. The routine Mglobal(...) is the global array handler. Details below. At present, if you want to run with no global arrays, substitute a dummy routine for Mglobal(...).
If a line begins with a percent sign (%) or plus sign (+) in column 1, the remainder of the line is treated as an inline C++ statement. If a parameter to a Mumps subroutine begins with a plus sign (+), it is interpreted as a C++ data item. C++ statements can access Mumps variables by means of the sym_() function. It is found in sym.c and is documented both there and above under functions. The following is an example of mixing C++ and Mumps:
If you write inline C++ functions, place them at the beginning of the source code prior to any Mumps code.
The Mumps symbol table can be accessed from inline C++ code by calls to the symbol table routine sym_(int, unsigned char*, unsigned char*). The first argument is the operation: 0 for retrieve and 1 to store or create. The second argument contains the name of the variable and the third is the returned value or the value to be stored, depending on the operation. A NULL pointer is returned on error.
Inline C++ code placed immediately after a dotted indent is considered to be part of the dotted indent block.
Some C++ compilers produce erroneous results for some of the Z-type date functions. Please verify on your configuration.
Arithmetic operations are carried out by routines in arith.c. These are: "add()", "sub()", "mult()", "divx()", "numcomp()", and "expx()". These functions perform arithmetic in double precision floating point or "long" as appropriate and convert the result back to string. Thus, integers may range between approximately +/- 2 billion. Floating point arithmetic is carried to approximately 15 digits of precision. You may change the data types to longer types, such as "long double" or "long long" if your application requires the additional digits of accuracy. Be certain to change the parameters to the converting routine ("gcvt()") as well. Using longer arithmetic data types will slow execution. You may substitute your own routines here if you want another style of calculation (for example, BCD). Values are passed to these functions as character strings and the callers expect a character string in return.
The modulo operator follows the C++ language conventions and the Mumps expression x#y is implemented as the C++ code x%y. Mumps and C++ calculate modulo differently for reasons unknown to me. This affects the results when one of the operands is negative and the other is positive.
If you use indirection ("@" operator) or the "xecute" command, the run-time interpreter will be incorporated into your executable. It will add about 50k to the final size of your program.
Both forms of indirection, the "@" operator and the "xecute" command require the run-time interpreter. Indirection should be avoided, if possible, as interpretation if considerably slower than direct execution.
Indirection is implemented by run-time interpreter routines that directly execute Mumps code. The run-time interpreter is invoked by the "@" operator and by the Xecute command. If a command contains an instance of the "@" operator, the entire command will be interpreted by the run-time interpreter.
The run-time interpreter permits some language constructs not supported by the compiler and, alternatively, there are some compiler supported constructs not supported by the run-time interpreter. Please test your code thoroughly. Because the run-time interpreter does not examine a line of code or expression until actually called upon to interpret it, it is possible for erroneous code to remain undetected until run-time.
The builtin interpreter that handles indirection does not presently support arguments to functions or expressions of the form "@xxx@(abc)".
The run-time interpreter uses the same symbol table and global arrays as the compiler. Thus, data may be exchanged between compiled and interpreted routines.
Errors detected by the interpreter will generally halt the program you are unning. You may, however, trap errors from teh interpreter. This is discussed in Error Messages.
Global arrays can be manipulated as relations using a set of provided relational algebra programs. The functions to do these are in the file libmpsrdbms.mps in mumpsc/Mumps in the standard distribution. In the following examples, the names of global arrays to be manipulated are enclosed in double quotes without the leading circumflex(^) character:
The rows of global arrays global1 and global2 are merged into the global array global3 with duplicate rows collapsed. Both input arrays must be of the same number of columns and corresponding columns should be from the same domain of values. The resulting array will be of the same number of columns. For example:
set ^a("apple","$0.95")=""
set ^a("pear","$1.25")=""
set ^a("orange","$1.50")=""
set ^b("apple","$0.95")=""
set ^b("banana","$0.80")=""
set ^b("peach","$1.00")=""
do ^Union("a","b","c")
yields:
^c("apple","$0.95")
^c("banana","$0.80")
^c("orange","$1.50")
^c("peach","$1.00")
^c("pear","$1.25")
Columns specified by the string cols from the input array in are copied to the out array. The string cols is one or more numbers in the range 1 through 9 with no embedded blanks or other delimiters. Only the first 9 columns of a relation may be projected at this time. The list of digits specifies in order the columns in the output array to be taken from the source array. A given column number may bre present more than once, in which case, that column will be reproduced more than once. Example:
set ^a("apple","$0.95")=""
set ^a("pear","$1.25")=""
set ^a("orange","$1.50")=""
do ^Project("a","b","1")
yields:
^b("apple")
^b("pear")
^b("orange")
do ^Project("a","c","21")
yields:
^c("$0.95","apple")
^c("$1.25","pear")
^c("$1.50","orange")
Copies global array in to global array out except those rows that are also in sub. That is, out consists of rows from in minus those rows of sub. Example:
set ^a("apple","$0.95")=""
set ^a("pear","$1.25")=""
set ^a("orange","$1.50")=""
set ^b("apple","$0.95")=""
set ^b("banana","$0.80")=""
set ^b("peach","$1.00")=""
do ^Subtract("a","b","c")
yields:
^c("pear","$1.25")
^c("orange","$1.50")
The array out will consist of those rows common to a1 and a2. Example:
set ^a("apple","$0.95")=""
set ^a("pear","$1.25")=""
set ^a("orange","$1.50")=""
set ^b("apple","$0.95")=""
set ^b("banana","$0.80")=""
set ^b("peach","$1.00")=""
do ^Intersect("a","b","c")
yields:
^c("apple","$0.95")
Rows from a are copied to b if the expression in exp is true. The expression must be a valid Mumps expression with care taken to fully parenthesize complex sub-expressions. The expression is not checked until runtime. Column elements of the a array may be addressed as a(1), a(2), .... Example:
set ^a("apple","$0.95")=""
set ^a("orange","$1.50")=""
set ^a("pear","$1.25")=""
do ^Select("a","b","a(2)>1.00")
yields:
^b("orange","$1.50")
^b("pear","$1.25")
The output array out is constrcuted by concatenating rows from a1 with rows from a2 if the expression in exp is true. Column elements of the first array are addressed as a(1),a(2),... and column elements of the second array are addressed as b(1),b(2),.... The expression must be a valid Mumps expression. Joins can be costly interms of computer time. Example:
set ^a("apple","$0.95")=""
set ^a("pear","$1.25")=""
set ^a("orange","$1.50")=""
set ^b("apple","$0.95")=""
set ^b("banana","$0.80")=""
set ^b("peach","$1.00")=""
do ^Join("a","b","c","a(1)=b(1)")
yields:
^c("apple","$0.95","apple","$0.95")
Prints the global array in tablular form. The parameter "indt" is the number of positions between columns whereas "indtchr" is the character repeated between columns.
Glade is a "drag and drop" graphical user interface builder that uses the Gtk graphics library. Glade performs many of the same functions as Power Builder and other related systems and permits you to quickly build GUI interfaces for your programs
While most Mumps implementations are not compatible with GUI builder software, the output of the Mumps Compiler is. This section gives an example of how to build a simple GUI interface for a Mumps program that extracts data from the global array data base.
In this example, the user will type in a name and the program will do a lookup on the name and reply with the phone number associated with the name. The data base consists of a global array called "name" whose indices are names and whose values are phone numbers:
First, start glade. If not installed, you may need to install it or download a free copy from:
http://www.gtk.org
Glade is released under the GNU GPL/LGPL licenses. Once glade is installed, type "glade" to your command prompt. This will cause three windows to appear on your screen (note: you will need the jpeg files associated with the Mumps Compiler Programmers' Guide in order to see the screen shots used in this section):
In the left window is a collection of widgets that you may drag and drop into your application. In the middle window are the controls and a list of resources and in the right window are the controls used to set the properties of the widgets. The beach in the background is where you'll be with all the free time you have because this is so quick...
Next, click File | New Project in the middle window. Now click File | Project Options in the middle window and see a display like:
The default settings are correct except you may or may not want to edit the project name and the directory into which it will be placed. Shown in the image are defaults from the author's system.
Click "OK" when done. Next, go to the left window and click on the Gnome button. A new group of icons will appear. Place your mouse over the upper left ("Gnome Application Window"), click the mouse and a new window will appear - a skeletal application window. At the same time, the project window (the original middle window) will indicate "app1":
In the new window, click over tab (docking tab) that appears to the left of the "File Edit View..." box. Note that an outline will appear. Right click the mouse and select "Delete". The menu bar will disappear. Do the same for the bar of buttons. These are not needed for this example. Note that no boxes remain. If they do, click on them, then right click and delete. your screen should look like this:
Click on the "Gtk+ Basic" button in the left most window. Click on the "Vertical Box" icon (row 8, column 2). Click in the cross-hatch area of the GUI window. You will see a pop-up box asking how many rows - select "2" and click "OK". Click on the "Horizontal Box" in the left most window (row 8, column 1) and click in the upper frame of the GUI window. Select 2 columns and "OK". Select "Text box" (row 2, column 4) from the left most box and click into the lower from of the GUI. Click on "Text Entry" (row 2, column 2) and click in the right frame of the top frame of the GUI window. Click on the "Button" (row 3, column 1) of the left most window and click in the upper right frame of the GUI window. Your screen should now look like (you may have different proportions to you boxes. These can be adjusted) this:
Now click the upper right window (the "Button" window) of the GUI. Note the Properties window repainted. Now click the "Signals" tab in the "Properties" window. Click the button to the far right of the entry "Signal:" (near the middle of the screen, not the one near the top). A new window will appear with signals. Under "Gtk Button Signals" click "clicked":
Click the "Add" button at the bottom of the "Properties" window. The signal will now appear in the top "Properties" window.
Now in the main project (center) window, click on "app1". This will cause the properties window to re-draw. In the Properties window, click on "Signals". Click the button to the right of the "Signal:" entry mid-way down the window. In the pop-up list of signals, scroll to the bottom and select "Destroy". Click "OK". Click "Add". This adds a handler to handle the case when the user clicks on the window's "X" box (destroy) on the upper right hand corner of the window.
Now in the main project window, click "File | Build Source Code" and then "File | Save"
Now you are ready to write your Mumps programs. Move to the projects "src" directory. Enter the following Mumps program:
The above program assumes the existence of the "^name(i)" array as shown at the beginning of this section. You need to create this array separately in the directory from which you will run your GUI application.
The program is simple but sufficient to demonstrate the principles involved. Actual applications will be considerably longer and may involve multiple subroutines. Program details:
Next, compile the Mumps program to C++ (but not to an executable binary) by typing to the command prompt:
mumps2c getphone.mps
(where "getphone.mps" is the file name for the Mumps subroutine.
Next, move the directory above the "src" directory and execute file "autogen.sh" which will build the configuration files. When done, return to the "src" directory.
Next, insert the call to "getphone()" into the GUI "callbacks.c" routine. When you clicked "Build Source Code" above, several files were created in the project "src" directory. One of these is "callbacks.c" which will contain the modules that will be called by the GUI for certain events. Modify "callbacks.c" to look like the following:
The modifications are (marked with "// *****" in the above):
Insert the body of the function "on_button_clicked()" This is mainly "boiler-plate" code. It is invoked when the "Lookup" button is clicked on the GUI. It gets the pointer to the output text box ("p1") and a pointer to the input text ("text") and then invokes your Mumpsc subroutine ("getphone()"). The arguments to "getphone()" are:
Next you need to modify the "Makefile" to include Mumps linkage. Edit Makefile (in "src") and find the section that looks like (search for "LINK"):
and replace the "LINK" line with the following:
$(LINK) $(project2_LDFLAGS) $(project2_OBJECTS) $(project2_LDADD) -ldb -lmumps -lmpsglobal_bdb $(LIBS) -lpcre
The added link edit references are to Mumps libraries needed by the Mumps program. Note the "-ldb" loads the Berkeley DB libraries. By default, Glade loads the db1 version. The "-ldb" should point to db3 or higher. Placement of "-ldb" prior to "LIBS" is important as it causes the db3 libraries to be preferred.
Next, you need to build the project. From the "src" directory, type:
make
This will compile and build your application. You may get some warning messages regarding unused variables. This is mainly because the Mumps code only consists of a subroutine and some symbols are not being used. When done, the executable will be in the "src" directory and named after your project. If you permitted the project name to default, it will be called something like "project1" or "project2" and so forth. You may run this program which should look something like this (a search string has been inserted and the "LookUp" button clicked):

How To Write CGI Mumps Scripts
Writing Mumps scripts for CGI execution is relatively simple. The main difference between writing ordinary console based Mumps programs and those to be executed in the CGI interface of a web server concerns input/output.
Output
Normally in a Mumps program, you use the write statement to generate program output that appears as generated on the console running the Mumps program. When running under a web server, however, all your output will be captured by the web server and sent to the web browser. The web browser will format and place your output on the browser's screen.
In order to control the placement, font size, color and other factors concerning the display of your output, you must embed in your output HTML codes. The browser will use these in determining the manner in which to display your output.
Any output you write to the default output device (unit 5) will be sent to the browser by the web server. You may use the write statement to send both text to be displayed as well as HTML codes. For example, given that the variable ptid contains "1234":
to the browser and this will cause the text to be centered on the browser's screen.
In order to speed the development process, this Mumps also supports another form of output that allows easier mixing of HTML and Mumps code.
In html commands, the following substitutions will take place:
< center > Patient &~ptid~ < /center >
|
|
This program creates a listbox containing the names of patients:
Note the following:
The collection of builin functions is noted in the files builtins.cpp and mumpsc/builtin.h. The file builtin.h has a list of initialized names in the char * array BuiltIn and a list of function headers. Normally, when Mumps calls a separately compiled function, all the user parameters are evaluated and only their values are passed. If a function name appears in mumpsc/builtin.h in the array BuiltIn[], global arrays will not be passed as the value of the array node reference but, rather as the array reference. For example, if the global array node is ^A(aples,oranges,pears) and if apples=10, oranges=20 and pears=30, and the value stored at ^A(10,20,30) is "fruit", a normal call to a separately compiled function:
set i=$$^function(^A(apples,oranges,pears))
would pass the value "fruit" to the function. If, however, the name of the function is in BuiltIn[], the same function call will pass a string whose contents are:
^A\x0110\x0120\x0130\x01
where x\01 stands for a byte containing the value 1. This permits the global array reference itself, with to be passed however with indices evaluated. This is needed in order to permit access to some MDH functions which require the actual global array reference as oppossed to the value stored at the global array.
Normally, the collating sequence for global and local arrays will be ASCII. This is for efficiency reasons. Any technique which will cause the collating sequence to become that of "standard" Mumps will significantly increase overhead.
There are two ways to change the collating sequence. One is to modify the comparison function used by the Berkeley DB (set_db_compare()). This function is called each time the data base system compares keys in the data base. The default function is an ASCII compare. Any other function can be used but they would all increase overhead on all data base activity.
The other approach, which we have used here, is a bit of a kludge but it is functional and adds no significant overhead to processing non-numeric keys. This approach converts all numeric indices into a format of:
sscanf(tmpf,"%lf",&x);
sprintf(tmpf,GPADFMT,'\x1f',x);
where "tmpf" initially contains the original character string of the numeric format. "GPADFMT" is "%c%+040.20lf" and this value is set in "sysparms.h". The net effect is to convert all numeric indices to 41 byte strings that can be compared with the ASCII comparison function. The first byte (x1f) causes all numeric indices to be collated before all non-numeric indices, as per the Mumps "standard". The second byte is set to "0" for negative numbers and "1" for positive numbers. Decoding routines in "global.a"c and "sym.c" reverse the process. The format controls "GPADFMT" and "GPADWIDTH" in "sysparms.h" control the size of the conversion of strings to numbers.
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. <> GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) <> These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. <> 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. <> 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS <> How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
GNU Free Documentation License Version 1.1, March 2000 Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five). C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. In any section entitled "Acknowledgements" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections entitled "History" in the various original documents, forming one section entitled "History"; likewise combine any sections entitled "Acknowledgements", and any sections entitled "Dedications". You must delete all sections entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document, on account of their being thus compiled, if they are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have no Invariant Sections, write "with no Invariant Sections" instead of saying which ones are invariant. If you have no Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for Back-Cover Texts. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. -------------------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!
Mumps 95 compliant pattern matching (the '?' operator) is implemented in this compiler as given by the following grammar:
pattern ::= {pattern_atom}
pattern_atom ::= count pattern_element
count ::= int | '.' | '.' int
| int '.' | int '.' int
pattern_element ::= pattern_code {pattern_code} | string | alternation
pattern_code ::= 'A' | 'C' | 'E' | 'L' | 'N' | 'P' | 'U'
alternation ::= '(' pattern_atom {',' pattern_atom} ')'
The largest difference between the current and previous standard is the introduction of the alternation construct, an extension that works as in other popular regular expressions implementations. It allows for one of many possible pattern fragments to match a given portion of subject text.
A string literal must be quoted. Also note that alternations are only allowed to contain pattern atoms and not full patterns; while this is a possible shortcoming, it is in accordance with the standard. It is a trivial matter to extend alternations to the ability to contain full patterns, and this may be implemented upon sufficient demand.
Pattern matching is supported by the Perl-Compatible Regular Expressions
library (PCRE). Mumps patterns are translated via a recursive-descent parser
in the Mumps library into a form consistent with Perl regular expressions,
where PCRE then does the actual work of matching. Internally, much of this
translation is simple character-level transliteration (substituting '|'
for the comma in alternation lists, for example). Pattern code sequences
are supported using the POSIX character classes supported in PCRE and are
mostly intuitive, with the possible exception of 'E', which
is substituted with [[:print][:cntrl:]]. Currently, this construct
should cover the ASCII 7-bit character set (lower ASCII).
Due to the heavy string-handling requirements of the pattern translation process, this module uses a separate set of string-handling functions built on top of the C standard string functions, using no dynamic memory allocation and fixed-length buffers for all operations whose length is given by the constant STR_MAX in sysparms.h. If an operation overflows during the execution of a Mumps compiled binary, a diagnostic is output to stderr and the program terminates. If such termination occurs too frequently, simply increase the value of STR_MAX.
In addition to Mumps 95 pattern matching using the '?' operator, it is also possible to perform pattern matching against Perl regular expressions via the perlmatch function. Support for this functionality is provided by the Perl-Compatible Regular Expressions library (PCRE), which supports a majority of the functionality found in Perl's regular expression engine.
The perlmatch function works in a somewhat similar fashion to the '?' operator. It is provided with a subject string and a Perl pattern against which to match the subject. The result of the function is boolean and may be used in boolean expression contexts such as the "If" statement.
Some subtleties that differ significantly from Mumps pattern matching should be noted:A Mumps match expects that the pattern will match against the entire subject string, in that successful matching implies that no characters are left unmatched even if the pattern matched against an initial segment of the subject string. Using perlmatch, it is sufficient that the entire Perl pattern matches an initial segment of the subject string to return a successful match.
This program asks the user to input a telephone number. If the data entered looks like a valid telephone number, it extracts and prints the area code portion using a backreference; otherwise, it prints a failure message and exits.
Zmain
Write "Please enter a telephone number:",!
Read phonenum
If $$^perlmatch(phonenum,"^(1-)?(\(?\d{3}\)?)?(-| )?\d{3}-?\d{4}$") Do
. Write "+++ This looks like a phone number.",!
. Write "The area code is: ",$2,!
Else Do
. Write "--- This didn't look like a phone number.",!
Halt
The output of several sample runs of the program follows:
Please enter a telephone number: 1-123-555-4567 +++ This looks like a phone number. The area code is: 123 Please enter a telephone number: (123)-555-1234 +++ This looks like a phone number. The area code is: (123) Please enter a telephone number: (123) 555-0987 +++ This looks like a phone number. The area code is: (123)
As in Perl, sections of the regular expression contained in parentheses define what is contained in the backreferences following a match operation. The backreference variables are named in a left-to-right order with respect to the expression, meaning that $1 is assigned the portion matched against the leftmost parenthesized section of the regular expression, with further references assigned names in increasing order. For a much more in-depth treatment of the subject of Perl regular expressions, refer to the perlre manpage distributed with the Perl language (also widely available online).
mumpsc(1) mumpsc(1)
NAME
mumpsc - Mumps compiler
SYNOPSIS
mumpsc [-n|--native|-b|--berke
ley|-s[T|U|S]|--server=[udp|tcp|ssl]]
[-g|--debug] [-d<IP>|--default_ip=<IP>] filename
DESCRIPTION
This manual page explains the mumpsc program. This program
translates a source file written in the Mumps language
into a C source file, which is then compiled into an exe
cutable.
mumpsc is actually a shell script and wrapper to mumps2c,
the Mumps to C translator. It also calls cc if a source
file is successfully generated.
"filename" is of the form "progname.mps" followed by zero or
more "progs.o". The ".mps" extension is required.
OPTIONS
-n [ --native ]
Use the native database implementation for global
array handling.
-b [ --berkeley ]
Use Berkeley DB to manage global array storage.
(This is the default)
-g [ --debug ]
Compile the generated C code with debugging sym
bols, to allow for the use of a debugger on the
resulting binaries.
BUGS
Please e-mail bug reports to the authors. You should
include a Mumps source file that can reproduce the error,
and the version number (found in the name of the source
tarball the compiler is installed from).
AUTHOR
Most of the source code for this Mumps compiler was writ
ten by Kevin O'Kane, <okane@cs.uni.edu>, at the University
of Northern Iowa. The Berkeley-DB based global array
library was written by Matthew Lockner, <lock
ner@cns.uni.edu>.
SEE ALSO
The full documentation of this compiler, including a full
reference on the Mumps language and the dialect supported
by this compiler, may be found in
/usr/share/doc/mumpsc/compiler.html
Also in that area are included a few sample Mumps pro
grams.
MUMPSC January 8, 2002 2
PCRE LICENSE ------------ PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip HazelUniversity of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2001 University of Cambridge Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ should also be given in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), then the terms of that licence shall supersede any condition above with which it is incompatible. The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself. End
INSTALLING MUMPS ON MAC OS 10.2
Chris Johnson (chris.johnson@myrealbox.com)
Mumps can now be installed on OS X, thanks to Apple's migration to its
BSD-like core operating system called Darwin. A typical installation
of OS X does not provide many of the standard development packages,
but the instructions below will help you set up an environment suitable
for most Mumps programs.
Mumps for OS X does not at this time handle network connections. If you
do not have OpenSSL installed, you may ignore any SSL errors encountered
while installing Mumps.
Apart from installing missing software, installing Mumps on OS X should
differ little from installing Mumps on other Unix-family machines. Please
consult INSTALL for other configuration directions.
1. Make sure you have Mac OS X installed with the BSD subsystem. Mumps
is designed to run on the Unix family of operating systems, and access
to a command line and certain system binaries is essential.
2. Download and install the latest Developer Tools for Mac OS X from
http://developer.apple.com. This package contains g++ and other
development tools.
3. Download the latest version of Fink from http://fink.sourceforge.net.
Follow the directions to install and set up your shell environment
variables. (Note the alternate directions for bash users.)
Fink is similar to Debian's package manager and makes for easy install-
ation of applications. Anything installed with Fink will be placed
in the /sw hierarchy by default -- this location is not conventional
but should pose no problem for your Mumps installation. (You may need
to identify /sw as an additional directory to search for application
includes and libraries.)
3. Install the Perl Compatible Regular Expression (PCRE) library using
Fink.
$ sudo fink install pcre
At the time of this writing, a manual, non-Fink installation of PCRE
failed on a two-level namespace error. The following link describes
the problem in greater detail.
http://developer.apple.com/techpubs/macosx/ReleaseNotes/TwoLevelNamespaces.html
We recommend using Fink to bypass this error.
4. Install the Berkeley Database using Fink.
$ sudo fink install db4
It is probable that you have a version of db already installed on your
system. Mumps requires a late version 3 or greater. If you install a
newer version of db from the source files or using Fink, please note which
directory you install into. You will have to provide the path during
the Mumps installation.
5. Install readline using Fink.
$ sudo fink install readline
7. Download and decompress Mumps v5.11 or later.
$ wget http://www.cs.uni.edu/~okane/source/mumpscompiler-5.11.src.tar.gz
$ tar xvpfz mumpscompiler-5.10.src.tar.gz
8. Install Mumps.
$ cd mumpsc
$ ./configure --with-libraries=/sw/lib:/usr/local/pgsql/lib \
--with-includes=/sw/include:/sw/include/db4:/usr/local/pgsql/lib
$ make
$ make install
You can specify nonstandard locations of include and library files using
the --with-includes and --with-libraries options. If you installed all
software using the directions provided here, the above example should
work fine. Consult INSTALL for more general Mumps installation inform-
ation. This will place the Mumps Compiler in ~/mumps_compiler. The
compilation script is in ~/mumps_compiler/bin/mumpsc. To do a system
install, login as root, and in step 8, add prefix=/usr to the command
line arguments of the "configure" command. This will insert the Mumps
Compiler code in /usr/bin/mumpsc, /usr/include/mumpsc, and /usr/lib/mumpsc.