Converting Your MSM Application
It is strongly recommended that you convert any MSM-specific language features to native Caché code, even though the Caché MSM language compatibility mode may allow you to run your MSM application with fewer changes. Conversion will be the first step in taking advantage of Caché-specific features such as ObjectScript.
This chapter discusses the following topics:
How Routines Differ
Working with routines is slightly different in Caché than in MSM.
The MSM approach:
A programmer works with routine source code, ZSaves it (implicitly or explicitly) and it is compiled implicitly into object code, regardless of how it is modified.
Both source and object code are stored on disk together in routine blocks.
At runtime the object code is loaded into generic buffers in the buffer pool.
The Caché approach:
A programmer works with either INT (intermediate) or MAC (macro) code, or possibly INC (include) code. These are actually extensions to the routine name. I.e. A123.mac.
The Caché equivalent to MSM source is INT code. Macro code is useful when embedding macro statements such as embedded SQL directly into your code.
A programmer edits a routine using the Studio, but routines require explicit compilation to generate the OBJ object code files (the equivalent to MSM p-code).
Compiling MAC code in Caché automatically generates both INT and OBJ code. Compiling INT code automatically generates the OBJ code as well.
All code is stored in globals (^rMAC, ^rINV, ^rOBJ and ^ROUTINE).
At runtime, only the OBJ code is loaded into special routine buffers that are separate from the main global buffer pool, with the obvious advantages that this brings.
Porting MSM Routines
Use the following procedure to migrate MSM routines that are less than 64KB in size:
Save your MSM routines in MSM format using the ^%RS utility.
Restore your code into Caché using ^%SYS.RI in the destination namespace.
From the destination namespace, use ^%RCOMPIL recompile your code in Caché and check for syntax errors. Once you find which routines have generated <SYNTAX> errors, you should look to the Caché ObjectScript Reference to familiarize yourself with Caché’s language syntax.
Although MSM can support as large a routine as the current stack and partitions sizes will allow (tested as high as 200 KB), Caché routines must compile to less than 64KB in size. You can use MSM’s ^%RSIZE utility to check your routine’s size before importing into Caché. To figure out how large a routine is, multiply the number of Text Blocks, as reported by ^%RSIZE, by 1 KB.
Any MSM routines larger than 64KB can be addressed in one of two ways:
Split the routines in MSM first so that no routine is larger than 64KB, then import into Caché.
Import the routines into Caché first, with Syntax Checking and Compile options off. Once in Caché, split the routines and then use ^%RCOMPIL to compile them.
You cannot migrate an MSM routine that is only stored as p-code (known as object code in Caché). If you need to migrate a routine that was only supplied as p-code, you will need to contact your application supplier to get the routine’s source code before proceeding.
MSM Language Compatibility Mode
Caché operates in MSM language mode when working with a MSM routine that has been ported. A language mode can be set individually for each routine, and a routine compiled in one language mode can call or be called by a routine compiled in another mode. Thus, for instance, an MSM mode routine could call a Caché mode routine which could in turn call another MSM mode routine.
Use $ZU(55, mode) to switch language modes, where mode is the number of the language mode. The relevant settings are:
Switch to MSM mode:
Set x=$ZU(55,8)Copy code to clipboard
Switch to native Caché mode:
Set x=$ZU(55,0)Copy code to clipboard
Return the current language mode:
Set x=$ZU(55)Copy code to clipboard
After an MSM application is compiled in the correct language mode, it can be installed and run on any Caché system, no matter what other applications or language modes are used on that system. Almost all language mode processing occurs at compile time, not runtime. As a result, using a language mode such as MSM will generally deliver the same high performance as the Caché native language mode.
Native Caché mode is the default for each process. To change this default for specific process types, you will need to modify the appropriate line tag within the ^%ZSTART routine.
From within any of these modes, you can add your own commands, functions, or special variables, allowing you to convert your MSM %ZZCMNDS, %ZZFUNCS, and %ZZSVARS MSM routines. Depending on the current language mode, corresponding Caché routines will be searched for these added features.
|Original (native MSM) routines||%ZZCMNDS||%ZZFUNCS||%ZZSVARS|
|Native Caché mode routines||^%ZLANGC00||^%ZLANGF00||^%ZLANGV00|
|MSM mode routines||^%ZLANGC008||^%ZLANGF008||^%ZLANGV008|
The line tags you enter in these routines will be the names of your new commands, functions, or special variables. The line tags entered must begin with a “Z” and must be all capital letters. Actual execution of the command, function, or special variable is not case-sensitive.
Adding code to ^%ZLANGC* creates a new command, such as ZSS:
%ZLANGC008 ZSS ; do a System Status Do ^%SS QuitCopy code to clipboard
Adding code to ^%ZLANGF* creates a new function, such as $ZRTN(x):
%ZLANGF008 ZRTN(x) ; find out what routine a process is currently running Quit $Print($View(-1,x),"^",6)Copy code to clipboard
Adding code to ^%ZLANGV* creates a new special variable, such as $ZTIME:
%ZLANGV008 ZTIME ; return the current time Do INT^%T Quit %TIMCopy code to clipboard
Here is an example of custom code that calls the routines defined above:
MyRtn ; Call the code added to the ^%ZLANG* routines ; New pid,rtn,x Set x=$ZU(55,8) ; Change to MSM mode ZSS Read !,"Enter a process ID: ",pid Set rtn=$ZRTN(pid) If rtn="" Set rtn="no routine" Write !,"At "_$ZTIME_", process #"_pid_" was running "_rtn_"." Set x=$ZU(55,0) ; Return to native mode Quit
Converting Nonstandard Functions and Features
Converting MSM’s implementation-specific functions and features will be the most intricate part of your conversion. Issues to keep in mind include:
Many MSM commands such as ZUSE, functions such as $ZOS, and special variables such as $SYSTEM will need to be handled differently for Caché.
Any VIEW commands or $VIEW functions which access MSM memory structures will need to be removed or modified.
Any references to MSM utilities may need to be converted.
Caché does not support the hex operator #. However, support for $ZHEX is identical and so this function should be used in its place.
Caché does not support printer mnemonics.
In some cases, the ^%RCHANGE utility can be used to make some simple syntax changes, but you should use this method with care, as blind modifications to a routine can make unwanted changes to your code. Most code changes should be done interactively by a programmer.
Here are a few suggested actions that you can take to get a rough idea of how much effort will be involved in an MSM to Caché conversion.
Load all your MSM routines into Caché and run %RCOMPIL and analyze the syntax errors
Most of the open and use commands should appear here.
Extraneous whitespace is a common problem. You might run into cases where MSM successfully compiles a routine, but Caché generates a <SYNTAX> error upon compiling due to extra whitespace. Whitespace issues are best corrected interactively by a programmer. A good example of this is less than two spaces between a QUIT command and a semicolon.
Duplicate line tag names in routines are not supported in Caché. Compiling such a routine will give you a <LABELREDEF> error. You will need to eliminate or change one of the line tags, and make any necessary code changes to maintain the same application logic.
Use %RFIND to search for the following character strings:
$Z (system functions generally)
^ ( ; note space between the “^” and the “(“ (SPACE operator!)
O 51, O 52, O 53 or O 54 (Open number rather than name)
See the appendix “MSM and Caché Utilities Catalog” for a list of MSM commands, functions, operators, preprocessor directives, special variables, and structured system variables, and their Caché equivalents.
XCALL functions allow the use of external programs, such as C or Assembler, to be called from within M. For backward compatibility support, MSM also supports a ZCALL interface. Both XCALLs and ZCALLs are similar in concept and in implementation to Caché’s $ZF() Callout interface (see Using the Caché Callout Gateway). XCALL and ZCALL functions must be converted to Caché $ZF() functions.
OS Functions via %OS and $ZOS
MSM’s %OS utility and $ZOS function allow many OS-related functions to be performed from within M. There are no direct equivalents to %OS or $ZOS in Caché, although through the use of $ZF(-1), $ZF(-2), or a pipe to an OS command (using the "Q" parameter to the OPEN command), you can easily execute any OS functions you wish.
Generally speaking, any file related operations (as used in $ZOS for example) should be replaced with method calls to the %Library.File class. For example, to delete a file:
Caché’s $ZF(-1) function allows you to run OS commands from a Caché programmer’s prompt. On Windows platforms, these commands will hang if they expect user input. For more details see “Issuing Operating System Commands” in Using the Caché Callout Gateway.
Converting ZWINTERM Calls
MSM allows you to use pop-up windows to display messages via the ZWINTERM interface. With Caché, you have several options to gain this same character-based windowing functionality.
Use mnemonic spaces to create pop-up windows .
Use the $ZF(-1) function to issue an operating system level command to open a new terminal window.
Keep MSM as a network client to Caché so that your existing character windowing functions can be used. This is a good short-term goal while your migration to Caché is in progress.
MSM Preprocessor Directives
Both MSM and Caché provide mechanisms by which you can use preprocessor directives to perform tasks such as defining macros, defining macro libraries, and including source code from another routine.
Caché stores its directives in .MAC and .INC code. The MSM globals ^ZMSMMAC and ^ZMSMSRC, which store the preprocessor directives and source code respectively, have conceptual equivalents in Caché’s ^rMAC and ^ROUTINE globals.
While MSM and Caché have similar facilities conceptually, the syntax varies between the two systems. For example, in MSM you can use one of two mechanisms to build formal parameter lists for your macros:
Through the use of enumerated variables, such as $1, $2, ... $N, as the arguments’ formal names:
#define copyright() Copyright $1-$2Copy code to clipboard
Through alphanumeric names as the arguments’ formal names:
#define copyright(from,to) Copyright from-toCopy code to clipboard
Caché does not support the use of enumerated variables for macro preprocessing. Instead, you will need to adopt Caché’s method of referencing alphanumeric names. The MSM examples above would look like this in Caché:
#define copyright(%var1,%var2) "Copyright ",%var1,"-",%var2
Arguments of the formal parameter list in Caché must begin with a % sign. Caché does not support MSM’s $0 variable, which stores the number of arguments passed to a given macro.
MSM and Caché also differ in the way that macros are referenced from within the application. Using the above macro definition, in MSM you could reference the copyright macro using one of two methods:
Passing arguments in a parenthesized parameter list
%%copyright(1997,1998)Copy code to clipboard
Passing arguments as a comma-delimited list
#%copyright 1997,1998Copy code to clipboard
In Caché, the %% and #% syntax for referencing macros is not supported. You would call the copyright macro using this syntax:
Extended References for Globals and Routines
As mentioned earlier, Caché relies on namespaces to access data from the actual physical database volumes. It is strongly recommended that you adopt Caché’s namespaces from within your application. In some cases however, changing every hard-coded extended reference in the application will be a difficult short-term goal.
Caché supports several forms of extended references:
^["namespace"]global ^["namespace",""]global (this is useful if piecing apart an MSM UVI/VOL string) ^["directory","system"]global ^|"namespace"|global ^|"^system^directory"|global
DO ^|"namespace"|routine DO ^|"^system^directory"|routine JOB ^routine["namespace"] JOB ^routine["namespace",""] JOB ^routine["directory","system"] JOB ^routine["^system^directory"]
You might want to create a Caché namespace called MGR that uses the CACHESYS database as the default location for globals and routines. Extended references that expect MGR to contain system globals and routines will not need modification.
Handling End-of-file Situations in Caché
MSM uses the special variable $ZC to store status information from the last device access. In particular, MSM applications made wide use of $ZC to check if the READ command reached the end of a sequential file ($ZC returns -1 in this case). Caché, unlike MSM, triggers an <ENDOFFILE> error in this situation. To handle an End-Of-File situation in Caché, you will need to create a custom error trap in your application using $ZTRAP.
Caché also supports the $ZC (if used in MSM language compatibility mode) as well as the $ZEOF (native Caché language mode) special variables.
MSM and Cache Database Networking (DDP)
There are a number of differences between MSM database networking (DDP) and Caché database networking (DSM-DDP/DCP/ECP).
MSM can communicate with Caché only using DSM-DDP over a raw Ethernet (sometimes referred to as a MSM Data Link) link. This link will have different performance characteristics than a MSMV3 link. For MSM it will be slower.
Caché networking does not support the MSM RVG concept. The Caché ECP protocol uses similar net traffic optimizations as the MSM RVG on all connections, but it is not compatible with MSM.
Only the MSM DDP protocol supports jobbing with parameter passing.
When communicating with Caché using DSM-DDP, you can only access data sets (databases) and not namespaces. This means that namespace mapping in Caché cannot be used by MSM.
When starting remote jobs on Caché from MSM, you cannot start jobs that will make global access from a namespace. MSM can only start jobs that have a default data set (database). This means that there is no namespace mapping in Cache by default for jobs started from MSM.