Introduction to CMac: 10. ARRAYS & STRUCTURES
(Sample code for tests 1 to 6 below can be downloaded here.)
Arrays of integers and real numbers can only be defined within a structure. First a review of structures:
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
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
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
1. Array of fixed length strings in one long string:
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
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.
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 would not 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 Image 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