|
- Written and documented by David Deley
Introduction to CMac Chapter 10: ARRAYS & STRUCTURES
Test code is provided below as an attachment.)
Arrays of integers and real numbers can only be defined within a structure. First a review of structures:
| Code: |
struct tstruct1
{
int i;
real j;
str s1;
}
void test1
{
struct tstruct1 m;
m.i = 10;
m.j = 3.14;
m.s1 = "This is a test";
make_message( 'm.i=' + str(m.i)
+ ' m.j=' + rstr(m.j,7,4)
+ ' m.s1="' + m.s1 + '"');
}
|
ARRAYS INSIDE A STRUCTURE
| Code: |
struct tstruct2
{
int i[4];
real j[4];
str s1;
}
void test2
{
struct tstruct2 m;
m.i[0] = 10;
m.i[1] = 12;
m.i[2] = 123;
m.i[3] = 988;
m.j[0] = 3.14;
m.j[1] = 2.718;
m.j[2] = 1.1213;
m.j[3] = 9.876;
m.s1 = "This is another test";
make_message( 'm.i[3]=' + str(m.i[3])
+ ' m.j[2]=' + rstr(m.j[2],7,4)
+ ' m.s1="' + m.s1 + '"');
}
|
HOW TO STORE A STRUCTURE IN A GLOBAL STRING VARIABLE
using Struct_to_Str and Str_to_Struct:
| Code: |
global
{
//See CMAC help on "Global Variables"
//for explanation of @,!,~,#
str g_MyGlobalStr "@MyGlobalStr";
}
struct tstruct3
{
int i[4];
}
void test3()
{
struct tstruct3 m;
str tempstr;
m.i[0] = 10;
m.i[1] = 12;
m.i[2] = 123;
m.i[3] = 988;
Struct_to_Str(tempstr, m);
g_MyGlobalStr = tempstr;
make_message("Structure m stored in global string g_MyGlobalStr");
}
void test4()
{
struct tstruct3 m;
str tempstr;
tempstr = g_MyGlobalStr;
Str_to_Struct(m, tempstr);
make_message( 'm.i[3]=' + str(m.i[3]));
}
|
Above first run test3, then run test4.
Notice the use of local variable 'tempstr'. Struct_to_Str and Str_to_Struct require local variables.
For another example see:
http://www.multieditsoftware.com/forums/viewtopic.php?p=2162#2162
ARRAY OF STRINGS
CMAC does not directly support "an array of strings". However, here are two methods of emulating an array of strings.
1. Array of fixed length strings in one long string:
| Code: |
void test5()
{
str month_names = "January " + // 1
"February " + // 2
"March " + // 3
"April " + // 4
"May " + // 5
"June " + // 6
"July " + // 7
"August " + // 8
"September" + // 9
"October " + // 10
"November " + // 11
"December "; // 12
int month_name_length = 9;
str month;
int month_number = 7; //Select "July "
//EXTRACT OUR STRING
month = copy( month_names,
(1 + ((month_number-1) * month_name_length)),
month_name_length);
//TRIM TRAILING SPACES (Also see "Remove_Space" function)
month = shorten_str(month);
Make_Message('month="' + month + '"');
}
|
NOTE: Strings, both global and local, are limited to MAX_LINE_LENGTH,
currently 16,383 characters. (This restriction may change in Multi-Edit
10.)
For another example see
http://www.multieditsoftware.com/forums/viewtopic.php?p=1537#1537
2. A Multi-Edit window can be an array of strings. Here's an
example of creating a hidden Multi-Edit window and using it as an array
of strings.
| Code: |
macro_file test6;
#include MEW.sh //Defines _wa_SystemHidden
prototype test6
{
void Create_Str_Array( int &win_id );
void Clear_Str_Array( int win_id );
void Put_Str_Array( int index, str elem, int win_id );
str Get_Str_Array( int index, int win_id );
void Delete_Str_Array( int win_id );
}
//-------------------------------------------------------------
// NOTE: Notice the ampersand &win_id, we are returning a
// value in win_id so ampersand says pass argument by
// reference instead of by value so we can return the value.
void Create_Str_Array( int &win_id )
{
int start_win_id = Window_ID;
int save_refresh = Refresh;
Refresh = FALSE;
//CREATE NEW WINDOW FOR STRING ARRAY
Create_Window;
if (Error_Level > 0) {
RM('MEERROR');
goto EXIT;
}
win_id = window_id; //Window ID of new window
Window_Attr = _wa_SystemHidden;
Switch_Win_Id(start_win_id); //Go back to original window
EXIT:
Refresh = save_refresh;
}
//-------------------------------------------------------------
void Clear_Str_Array( int win_id )
{
int start_win_id = Window_ID;
int save_refresh = Refresh;
Refresh = FALSE;
if (!Switch_Win_Id(win_id)) {goto EXIT;}
RM('block^selectall');
Delete_Block;
Switch_Win_Id(start_win_id); //Go back to original window
EXIT:
Refresh = save_refresh;
}
//-------------------------------------------------------------
void Put_Str_Array( int index, str elem, int win_id )
{
Put_Line_To_Win(elem, index, TranslateWindowID(win_id), FALSE);
}
//-------------------------------------------------------------
str Get_Str_Array( int index, int win_id )
{
return (Get_Line_From_Win(index, TranslateWindowID(win_id)));
}
//-------------------------------------------------------------
void Delete_Str_Array( int win_id )
{
int start_win_id = Window_ID;
int save_refresh = Refresh;
Refresh = FALSE;
if ( Switch_Win_Id(win_id) )
{
delete_window;
Switch_Win_Id(start_win_id); //Go back to original window
}
Refresh = save_refresh;
}
//-------------------------------------------------------------
//Now test it out:
void test6()
{
int MyStrWinID;
Create_Str_Array( MyStrWinID );
Put_Str_Array( 1, "This is a test line #1", MyStrWinID );
Put_Str_Array( 2, "This is a test line #2", MyStrWinID );
Put_Str_Array( 3, "This is a test line #3", MyStrWinID );
Put_Str_Array( 4, "This is a test line #4", MyStrWinID );
Put_Str_Array( 5, "This is a test line #5", MyStrWinID );
Make_Message( Get_Str_Array( 3, MyStrWinID ));
Delete_Str_Array(MyStrWinID);
}
|
The above is a bit complicated, so here are a few notes:
macro_file test6; - The compiled output file will be test6.mac
prototype test6 - test6 here should match test6 in macro_file test6; above.
void Create_Str_Array( int &win_id )
- The & here means the caller should pass the variable by reference
instead of by value so we can return a value in it. See CMAC help on
"Reference parameters". (An interesting caveat is the caller does not
need to change anything. The CMAC compiler takes care of the rest from
here.)
Refresh = FALSE; - This cuts down on
screen flickering. Notice we save the initial setting of system
variable 'Refresh' and restore it when returning.
Window_Attr = _wa_SystemHidden; -
Setting the newly created window attributes to _wa_SystemHidden means
the window won't show up as a user window when you do a WINDOW ->
LIST, and you don't have to give it a filename.
void Clear_Str_Array( int win_id ) -
Although not actually used in the above example, this is how to erase a
window if you ever wanted to. (A caveat of the system function
'Erase_Window' is that it erases not only the contents of the window
but also the File_Name associated with the window.)
Put_Line_To_Win - This replaces the
current line with the new line you specify. If the current line is
beyond the [EOF] it still inserts the new line at the proper line
number and [EOF] gets moved to the new end of file.
TranslateWindowID(win_id) - There's a difference between a window number and a window ID. A window number is a number between 1 - 127 (assuming that's the highest number of windows we can have. The limit might be 255.) A window ID is something different. It's a very large number. Some system functions ask for a window ID while other system functions ask for a window number. 'TranslateWindowID' converts a window ID to a window number. Tech
note: A window's number may change as windows are added and deleted. A
window's ID will not change. Window numbers are useful when you want to
cycle through all existing windows.)
For testing the above macro you could comment out the call to
'Delete_Str_Array'. Then to view the newly created window and its
contents do MACRO -> RUN (or click the
button) and enter the command "SWITWIN /SYSTEM=2" (there has to be a
space before the /SYSTEM=2). Your window should be the one at the
bottom called "?No-File?". You can switch to it and view it. You can
delete this window manually. Be careful not to mess up the contents of
other system windows. Also be careful not to create too many windows.
The limit I think is 127. (If
you view a system window, when you're done with the window right click
the button for that window or right-click the window's title bar and
select "Hide". We don't want to close a system window.)
You could expand the above code to save your window as a file, and to
load the saved file next time you run Multi-Edit. (That's a bit more
complicated. Maybe someday I'll create an example of that.)
The above example is a modified version of that given by gwhite at
http://www.multieditsoftware.com/forums/viewtopic.php?p=1560#1560 |