home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / ME494-6.ZIP / USERIN.SRC < prev    next >
Encoding:
Text File  |  1990-06-14  |  147.5 KB  |  5,347 lines

  1. $MACRO_FILE USERIN;
  2. {*******************************MULTI-EDIT MACRO*******************************
  3.  
  4. Name:    USERIN
  5.  
  6. Description:    Most of the general purpose user input routines.
  7.  
  8. TOPMENU - Macro to create a top level menu
  9. SUBMENU - Creates a sub level menu
  10. XMENU - Replaces the V_Menu and Bar_Menu macro commands
  11. QUERYBOX - A general purpose boxed string input prompt
  12. CHECKFILE - A verify for files.
  13. VERIFY - Are you sure?
  14. MAINHELP - Accesses the main ME help screen
  15. DATA_IN - A general purpose Boxed Data entry menu
  16. DVMENU - A variable-length menu generator
  17. SPECCHAR - Changes untypeable character into the |xx convention
  18. VALCHAR - Changes the |xx back to a character
  19. STRSRC - Formats strings to be used in macro source code generators like install
  20. DBLPAREN - Takes occurances of ( and changes them to (( for menus
  21. CHNGPARM - Changes a single slash type parameter(/) in a global string.
  22. USERSTR - Replaces the macro command STRING_IN
  23. GLOBALVARLIST - Creates a list of global array elements
  24. DELETEITEM - Shuffles global variable arrays
  25. WMENU    - Low level scrolling menu routine.  Is called by DVMENU
  26. CHECKEVENTS - Mouse and Key event handler
  27. DB - General purpose Database manager.
  28. EDITWINDOW - File editing/examining macro.
  29.  
  30.                              (C) Copyright 1989 by American Cybernetics, Inc.
  31. ******************************************************************************}
  32.  
  33. $MACRO TOPMENU FROM ALL;
  34. {*******************************MULTI-EDIT MACRO*******************************
  35.  
  36. Name:    TOPMENU
  37.  
  38. Description:    Creates the top bar menu.
  39.  
  40. Parameters:        /#=nn            The number of menu selections.
  41.                             /S=nn            The starting menu selection number.
  42.                             /G=str        The prefix used to find the global strings containing
  43.                                                     the individual menu selection parameters.
  44.                             /M=str    The prefix used to find the actual menu name strings.
  45.                                                     If this parameter is used then TOPMENU assumes that
  46.                                                     the menu item names will be contained in seperate
  47.                                                     globals instead of being part of the selection
  48.                                                     parameters.
  49.                             /X=nn            The starting column.
  50.                             /Y=nn            The starting row.
  51.                             /L=str        The label for the menu
  52.                             /B=nn            0 = Create a box for the menu
  53.                                                 1 = Don't create the box.
  54.                             /GCLR=1        Clear all globals on exit;
  55.  
  56.                             The individual menu items are passed via global strings defined
  57.                             as the string passed via /G= plus the number of the menu item.
  58.                             If "/G=MSTR" then menu item one would be "MSTR1", item two would
  59.                             be "MSTR2" and so on.
  60.  
  61.                             Each menu item parametr string may contain the following:
  62.  
  63.                             /N=str        The name of the menu item.  Use only if /M (above)
  64.                                                     is NOT used.
  65.                             /S=nn            0 = The item has a sub-menu.
  66.  
  67.                                                 1 = The item does not have a sub-menu, but do not
  68.                                                         delete this menu and return to this menu with
  69.                                                         the following action according to Return_Int
  70.                                                             Return_Int = 0 - Return to this menu and process the
  71.                                                                 last keystroke.  In this case, right and left
  72.                                                                 arrow keys will cause    the choice to the left or
  73.                                                                 right of the current choice to be selected, and
  74.                                                                 <ESC> will cause an exit from this menu.
  75.                                                             Return_Int = -1 - Return to this menu only.  Do not
  76.                                                                 Process the last keystroke.
  77.                                                             Return_Int > 1 - Immediately after returning to
  78.                                                                 this menu, exit this menu.
  79.  
  80.                                                 2 = The item does not have a sub-menu.  Delete this
  81.                                                         menu from the screen, execute the macro, do
  82.                                                         not return to this menu.
  83.                             /H=str        Help index string for this menu item.
  84.                             /M=str        Macro to run upon selection of this menu item.
  85.                                                 This must be the last parameter in the menu string
  86.                                                 because everything after the /M= is passed to the
  87.                                                 macro as its parameters.  /X=, /Y= and /BC= are also
  88.                                                 passed to the macro.  /BC= is the box number above
  89.                                                 which all boxes are to be removed.
  90.  
  91.  
  92.                              (C) Copyright 1989 by American Cybernetics, Inc.
  93. ******************************************************************************}
  94.  
  95.     Def_Str(
  96.                     Mstr,
  97.                     Label_Str[80]
  98.                     );
  99.  
  100.     Def_Str( GStr[20], gstr2[20] );
  101.  
  102.     Def_Int(x1,y1,jx,start,bc, t_ex, t_box_count, res, first_time, old_x, old_y );
  103.     Def_Int( menu_type, sub_col );
  104.     Def_Int( start_box_count,
  105.                         select_stat,
  106.                         select_mode, Count, cur_item );
  107.  
  108.     old_x := wherex;
  109.     old_y := wherey;
  110.  
  111.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  112.  
  113.     menu_type := 1;
  114.     gstr2 := Parse_Str('/M=', mparm_str);
  115.     if gstr2 = '' then
  116.         gstr2 := '@#$X' + str( global_int('MENU_LEVEL') );
  117.         menu_type := 0;
  118.     end;
  119.     refresh := false;
  120.     gstr := Parse_Str('/G=', mparm_str );
  121.     label_str := parse_str('/L=', mparm_str);
  122.     x1 := Parse_Int('/X=',MPARM_STR);
  123.     y1 := Parse_Int('/Y=',MPARM_STR);
  124.     if x1 = 0 then
  125.         x1 := 2;
  126.     end;
  127.     if y1 = 0 then
  128.         y1 := 2;
  129.     end;
  130.     if (y1 + 4) > (screen_length) then
  131.         y1 := (screen_length - 4);
  132.     end;
  133.  
  134.     if y1 <= 0 then
  135.         y1 := 2;
  136.     end;
  137.     bc := (Parse_Int('/B=',MPARM_STR) = 0);
  138.     count := Parse_Int('/#=', MParm_Str );
  139.     Start := Parse_Int('/S=',MPARM_STR);
  140.     if start < 1 then
  141.         start := 1;
  142.     end;
  143.  
  144.     start_box_count := box_count;
  145.  
  146.     Select_Stat := 0;
  147.  
  148.     if menu_type = 0 then
  149.         JX := 0;
  150.         While jx < Count do
  151.             ++jx;
  152.             create_global_str( gstr2 + str(jx), parse_str('/N=', Global_Str(gstr + str(jx))) );
  153.         end;
  154.     end;
  155.  
  156.     t_box_count := box_count;
  157.  
  158.     cur_item := Start;
  159.  
  160.     cur_item := 0;
  161.     while cur_item < count do
  162.         ++cur_item;
  163.         call draw_item;
  164.     end;
  165.  
  166.     cur_item := start;
  167.     first_time := 0;
  168.   update_status_line;
  169. main_loop:
  170.     xmenu(gstr2, count,x1 + first_time, y1 + first_time, (bc shl 4) or (first_time shl 8), bc - first_time , label_str, cur_item, res, sub_col );
  171.     set_global_str( gstr + '0', str(cur_item) );
  172.     t_box_count := box_count;
  173.     first_time := bc;
  174.     call draw_item;
  175.     select_mode := Parse_int('/S=',mstr);
  176.  
  177.     if res = -4 then
  178.         IF (Mou_Last_Y = Fkey_Row) THEN
  179.             RM( 'MOUSE^MouseFkey' );
  180.         ELSE
  181.             push_key(key1,key2);
  182.             return_int := 0;
  183.             goto exit;
  184.         END;
  185.     elsif res = -2 then
  186.         if key1 = 0 then
  187.             if key2 = 59 then
  188.                 Jx := Cur_Item;
  189. SEEK_HELP:
  190.                 IF ((Jx > 1) and (parse_str('/H=',Global_Str(gstr + str(Jx))) = '')) THEN
  191.                     --Jx;
  192.                     Goto SEEK_HELP;
  193.                 END;
  194.                 help( parse_str('/H=', Global_Str(gstr + str(Jx))) );
  195.             end;
  196.         end;
  197.     elsif res = 0 then
  198.         return_int := 0;
  199.         goto exit;
  200.     end;
  201.     if res > 0  then
  202.         select_stat := true;
  203.         if select_mode then
  204.             goto do_select;
  205.         end;
  206.     end;
  207.  
  208.     if select_stat and not(select_mode) then
  209. do_select:
  210.         if (select_mode = 2) then
  211.       hmenu_stat := FALSE;
  212.             if bc then
  213.                 kill_box;
  214.             end;
  215.         end;
  216.         mstr := Global_Str(gstr + str(cur_item));
  217.         jx := Xpos('/M=', mstr, 1);
  218.         if jx = 0 then
  219.             goto nomstr;
  220.         end;
  221.         mstr := copy(mstr,jx + 3, 200);
  222.         if mstr <> '' then
  223.             RM( mstr +
  224.                 ' /BC=' + str(start_box_count) + '/X=' + str(sub_col) + '/Y=' + str(y1 + 2 - (bc = 0)));
  225.       update_status_line;
  226.         else
  227.     nomstr:
  228.             return_int := cur_item;
  229.         end;
  230.     hmenu_stat := FALSE;
  231.         if select_mode = 2 then
  232.             goto exit;
  233.         end;
  234.  
  235.         while box_count > t_box_count do
  236.             kill_box;
  237.         end;
  238.  
  239.         if return_int = -2 then
  240.             select_stat := 0;
  241.         elsif return_int = -1 then
  242.             select_stat := 0;
  243.             goto exit;
  244.         elsif return_int = 0 then
  245.             select_stat := 1;
  246.             push_key( key1, key2 );
  247.         elsif return_int > 0 then
  248.             goto exit;
  249.         end;
  250.     end;
  251.  
  252.     goto main_loop;
  253.  
  254. draw_item:
  255.     mstr :=  Global_Str(gstr + str(cur_item));
  256.     ret;
  257.  
  258. exit:
  259.   hmenu_stat := FALSE;
  260.     while box_count > t_box_count do
  261.         kill_box;
  262.     end;
  263.  
  264.     if bc then
  265.         if box_count = t_box_count then
  266.             kill_box;
  267.         end;
  268.     end;
  269.  
  270.     jx := 0;
  271.     while jx < count do
  272.         ++jx;
  273.         set_global_str(gstr + str(jx), '');
  274.         set_global_str(gstr2 + str(jx), '');
  275.     end;
  276.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  277.     if mode <> edit then
  278.         gotoxy( old_x, old_y);
  279.     end;
  280. exitx:
  281. END_MACRO;
  282.  
  283.  
  284. $MACRO SUBMENU FROM ALL;
  285. {*******************************MULTI-EDIT MACRO*******************************
  286.  
  287. Name:    SUBMENU
  288.  
  289. Description:    Creates a boxed vertical menu.  Used by DATA_IN.
  290.  
  291. Returns:        Return_Int = -1 if <ESC> was pressed.
  292.                                                     0 if the <LEFT> or <RIGHT> keys were pressed.
  293.                                                  >0 if an item was selected.
  294.  
  295. Parameters:        /#=nn            The number of menu selections.
  296.                             /S=nn            The starting menu selection number.
  297.                             /G=str        The prefix used to find the global strings containing
  298.                                                     the individual menu selections.
  299.                             /M=str    The prefix used to find the actual menu name strings.
  300.                                                     If this parameter is used then SUBMENU assumes that
  301.                                                     the menu item names will be contained in seperate
  302.                                                     globals instead of being part of the selection
  303.                                                     parameters.
  304.                             /X=nn            The starting column.
  305.                             /Y=nn            The starting row.
  306.                             /L=str        The label for the menu
  307.                             /A=nn            0 = Exit if the left or right arrow keys are pressed.
  308.                                                 1 = Ignore left and right arrow keys.
  309.                             /B=nn            0 = Create a box for the menu
  310.                                                 1 = Don't create the box.
  311.                             /BC=nn    The Box number above which all boxes will be removed
  312.                                                 if a menu item with /S=2 (as a parameter) is selected.
  313.                                                 0 if all boxes are to be removed.
  314.                             /GCLR=1        Clear all globals on exit;
  315.                             /BO=      Box offset.  Normally used with /B=1.  Will offset
  316.                                                 The menu as though a box was there.  Good for multiple
  317.                                                 calls without kill the box in between.
  318.  
  319.                             The individual menu items are passed via global strings defined
  320.                             as the string passed via /G= plus the number of the menu item.
  321.                             If "/G=MSTR" then menu item one would be "MSTR1", item two would
  322.                             be "MSTR2" and so on.
  323.  
  324.                             Each menu item may contain the following:
  325.  
  326.                             /N=str        The name of the menu item.  Use only if /M (above)
  327.                                                     is NOT used.
  328.                             /S=nn            0 = The item has a sub-menu.
  329.                                                 1 = The item does not have a sub-menu, but do not
  330.                                                         delete this menu and return to this menu
  331.                                                         selection if the macro returns 0.
  332.                                                 2 = The item does not have a sub-menu.  Delete this
  333.                                                         menu from the screen, execute the macro, do
  334.                                                         not return to this menu.
  335.                                                 3 = Run the sub-menu.  Exit this menu with return_int
  336.                                                         equal to the menu selection.  Don't kill box.
  337.                             /H=str        Help index string for this menu item.
  338.                             /M=str        Macro to run upon selection of this menu item.
  339.                                                 This must be the last parameter in the menu string
  340.                                                 because everything after the /M= is passed to the
  341.                                                 macro as its parameters.  /X=, /Y= and /BC= are also
  342.                                                 passed to the macro.
  343.  
  344.  
  345.  
  346.                              (C) Copyright 1989 by American Cybernetics, Inc.
  347. ******************************************************************************}
  348.  
  349.     Def_Str( Mstr, Label_Str[80] );
  350.     Def_Str( gstr[20], gstr2[20] );
  351.   def_int( first_time, res, sub_col );
  352.  
  353.     Def_Int( bc, t_box_count, kill_count, arrow_stat );
  354.     Def_Int( x1,y1,jx,start, select_mode);
  355.     Def_Int( Count, cur_item, menu_type, bo, old_x, old_y  );
  356.  
  357.     old_x := wherex;
  358.     old_y := wherey;
  359.     menu_type := 1;
  360.     gstr2 := Parse_Str('/M=', mparm_str);
  361.     if gstr2 = '' then
  362.         gstr2 := '@#$Z' + str( global_int('MENU_LEVEL') );
  363.         menu_type := 0;
  364.     end;
  365.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  366.     gstr := Parse_Str('/G=', mparm_str );
  367.     label_str := Parse_Str('/L=', mparm_str );
  368.     x1 := Parse_Int('/X=',MPARM_STR);
  369.     y1 := Parse_Int('/Y=',MPARM_STR);
  370.     if x1 = 0 then
  371.         x1 := 2;
  372.     end;
  373.     if y1 = 0 then
  374.         y1 := 2;
  375.     end;
  376.     count := Parse_Int('/#=', MParm_Str );
  377.     Start := Parse_Int('/S=',MPARM_STR);
  378.  
  379.     bo := parse_int('/BO=', mparm_str);
  380.  
  381.     if start < 1 then
  382.         start := 1;
  383.     end;
  384.     kill_count := parse_int('/BC=', mparm_str );
  385.     bc := (Parse_Int('/B=', mparm_str) = 0);
  386.     arrow_stat := Parse_Int('/A=', mparm_str);
  387.  
  388.     if menu_type = 0 then
  389.         JX := 0;
  390.         While jx < Count do
  391.             ++jx;
  392.             create_global_str( gstr2 + str(jx), parse_str('/N=', Global_Str(gstr + str(jx))) );
  393.         end;
  394.     end;
  395.  
  396.     if (y1 + count + 2) > (screen_length) then
  397.         y1 := (screen_length - count - 3);
  398.     end;
  399.  
  400.     if y1 <= 0 then
  401.         y1 := 2;
  402.     end;
  403.  
  404.  
  405.     cur_item := start;
  406.     first_time := 0;
  407. main_loop:
  408.   update_status_line;
  409.   xmenu(gstr2, count,x1 + first_time + bo, y1 + first_time + bo,((bc AND $01) shl 4) + 1 , bc - first_time , label_str, cur_item, res, sub_col );
  410.     set_global_str( gstr + '0', str(cur_item) );
  411.     t_box_count := box_count;
  412.     first_time := bc;
  413.     select_mode := Parse_Int('/S=', Global_Str(gstr + str(cur_item)));
  414.  
  415.     if res = -4 then
  416.         IF (Mou_Last_Y = Fkey_Row) THEN
  417.             RM( 'MOUSE^MouseFkey' );
  418.         ELSE
  419.             push_key(key1,key2);
  420.             if bc then
  421.                 kill_box;
  422.             end;
  423.             return_int := -2;
  424.             goto exit;
  425.         END;
  426.     elsif res = -2 then
  427.         if key1 = 0 then
  428.             if key2 = 59 then
  429.                 Jx := Cur_Item;
  430.                 mstr := parse_str('/H=', Global_Str(gstr + str(Jx)) );
  431.                 IF mstr = '' THEN
  432.                     mstr := parse_str('/H=', mparm_str);
  433.                     IF mstr = '' THEN
  434. SEEK_HELP:
  435.                         IF ((Jx > 1) and (parse_str('/H=',Global_Str(gstr + str(Jx))) = '')) THEN
  436.                             --Jx;
  437.                             Goto SEEK_HELP;
  438.                         END;
  439.                         mstr := parse_str('/H=', Global_Str(gstr + str(Jx)) );
  440.                     END;
  441.                 END;
  442.                 help( mstr );
  443.                 goto main_loop;
  444.             end;
  445.         end;
  446.         if arrow_stat = 0 then
  447.             if bc then
  448.                 kill_box;
  449.             end;
  450.             return_int := 0;
  451.             goto exit;
  452.         end;
  453.         goto main_loop;
  454.     elsif res = 0 then
  455.         return_int := -1;
  456.         if bc then
  457.             kill_box;
  458.         end;
  459.         goto exit;
  460.     end;
  461.  
  462.     if res > 0 then
  463.         goto do_select;
  464.     end;
  465.  
  466.     goto main_loop;
  467.  
  468. do_select:
  469.         if select_mode = 2 then
  470.             while box_count > kill_count do
  471.                 kill_box;
  472.             end;
  473.         end;
  474.         mstr := Global_Str(gstr + str(cur_item));
  475.         jx := Xpos('/M=', mstr, 1);
  476.         if jx = 0 then
  477.             return_int := cur_item;
  478.             goto exit;
  479.         end;
  480.         mstr := copy(mstr,jx + 3, 200);
  481.         RM( mstr + ' /BC=' + str(kill_count) +
  482.                 '/X=' + str(x1 + 1) + '/Y=' + str(y1 + 1 + count));
  483.         if (select_mode = 2) or (select_mode = 3) then
  484.             return_int := cur_item;
  485.             goto exit;
  486.         end;
  487.  
  488.         if return_int > 0 then
  489.             while box_count > t_box_count do
  490.                 kill_box;
  491.             end;
  492.             if bc then
  493.                 if box_count = t_box_count then
  494.                     kill_box;
  495.                 end;
  496.             end;
  497.             if not(select_mode) then
  498.                 while box_count > kill_count do
  499.                     kill_box;
  500.                 end;
  501.             end;
  502.             return_int := res;
  503.             goto exit;
  504.         end;
  505.  
  506.         goto main_loop;
  507.  
  508. exit:
  509.     if (parse_int('/GCLR=', mparm_str) = true) or (menu_type = 0) then
  510.         jx := 0;
  511.         while jx < count do
  512.             ++jx;
  513.             set_global_str(gstr + str(jx), '');
  514.             set_global_str(gstr2 + str(jx), '');
  515.         end;
  516.     end;
  517.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  518.     if mode <> edit then
  519.         gotoxy( old_x, old_y);
  520.     end;
  521.  
  522. END_MACRO;
  523.  
  524.  
  525. $MACRO XMENU FROM ALL;
  526. {*******************************MULTI-EDIT MACRO******************************
  527.  
  528. Name: XMENU
  529.  
  530. Description: Generates a vertical or horizontal menu.  Meant to be a replacement
  531.                             for the macro functions V_MENU and BAR_MENU.
  532.  
  533. Returns:            Return_Int = 0 if <ESC> was pressed
  534.                                                  > 0 then return_int is the number of the select
  535.                                                          menu item.
  536.  
  537. Parameters:     /X=nn  Starting column coordinate
  538.                          /Y=nn  Starting row coordinate
  539.                          /B=nn  0 = No box
  540.                                         1 = Create box.
  541.                          /T=nn  0 = Horizontal menu
  542.                                         1 = Vertical menu
  543.                          /S=nn  Start menu item.
  544.                          /L=str Label for box
  545.              /M=str The menu string.
  546.  
  547.                     The format is as follows:
  548.  
  549.                     Off(INDENT)Auto()Smart()
  550.  
  551.                     Menu titles are seperated by ()'s
  552.                     Inside the ()'s are the help indexes
  553.                     If the help index is the same for all menu
  554.                     options you can just specify the first.
  555.  
  556.                                         Must be the LAST parameter passed.
  557.  
  558.                          /M1= - M3= The names of global strings to be added to /M= in case
  559.                                         you need more menu choices than will fit on the 254
  560.                                         character macro command line.
  561.  
  562.                              (C) Copyright 1989 by American Cybernetics, Inc.
  563. ******************************************************************************}
  564.  
  565.     def_str( gstr[20], bstr[4] );
  566.     def_int( start,x1,y1,box,jx, jx2, jy, count );
  567.     def_str( mstr, tstr[40] );
  568.  
  569.     x1 := parse_int( '/X=', mparm_str );
  570.     y1 := parse_int( '/Y=', mparm_str );
  571.     box := parse_int( '/B=', mparm_str );
  572.     if box then
  573.         bstr := '';
  574.     else
  575.         bstr := '/B=1';
  576.     end;
  577.     start := parse_int( '/S=', mparm_str );
  578.  
  579.     set_global_int('MENU_LEVEL', global_int('MENU_LEVEL') + 1);
  580.  
  581.     gstr := Str(global_int('MENU_LEVEL')) + 'MSTR_';
  582.     jx := xpos( '/M=', mparm_str , 1);
  583.     mstr := copy( mparm_str, jx + 3, 254 );
  584.     count := 0;
  585.  
  586.     call get_menus;
  587.     mstr := global_str( parse_str( '/M1=', mparm_str ) );
  588.     call get_menus;
  589.     mstr := copy(mstr, jx2, 254) + global_str( parse_str( '/M2=', mparm_str ) );
  590.     call get_menus;
  591.     mstr := copy(mstr, jx2, 254) + global_str( parse_str( '/M3=', mparm_str ) );
  592.     call get_menus;
  593.     goto do_menu;
  594.  
  595. get_menus:
  596.     jx := 1;
  597.     jx2 := 1;
  598. loop:
  599.     jx := xpos( '(', mstr, jx + 1 );
  600.     if jx <> 0 then
  601.         if copy(mstr, jx + 1, 1) = '(' then
  602.             mstr := str_del( mstr, jx, 1);
  603.             goto loop;
  604.         end;
  605.         ++count;
  606.         jy := xpos( ')', mstr, jx + 1);
  607.  
  608.         create_global_str( gstr + str(count), '/S=2/H=' + copy( mstr, jx + 1, jy - jx - 1 ));
  609.         create_global_str( gstr + 'X' + str(count), copy( mstr, jx2, jx - jx2 ));
  610.         jx2 := jy + 1;
  611.         goto loop;
  612.     end;
  613.     ret;
  614.  
  615. do_menu:
  616.     if parse_int('/T=',mparm_str) = 0 then
  617.         RM('TOPMENU /GCLR=1/X=' + str(x1) +
  618.                                             '/Y=' + str(y1) +
  619.                                             '/M=' + gstr + 'X' +
  620.                                             '/#=' + str(count) +
  621.                                             '/S=' + str(start) +
  622.                                             '/G=' + gstr + bstr +
  623.                                             '/BC=' + str(box_count) +
  624.                                             '/L=' + parse_str('/L=', mparm_str)
  625.                         );
  626.     else
  627.         RM('SUBMENU /GCLR=1/A=1/X=' + str(x1) +
  628.                                             '/Y=' + str(y1) +
  629.                                             '/#=' + str(count) +
  630.                                             '/M=' + gstr + 'X' +
  631.                                             '/S=' + str(start) +
  632.                                             '/G=' + gstr + bstr +
  633.                                             '/BC=' + str(box_count) +
  634.                                             '/L=' + parse_str('/L=', mparm_str)
  635.                         );
  636.     end;
  637.     IF (Return_Int < 0) THEN
  638.         Return_Int := 0;
  639.     END;
  640.     set_global_int('MENU_LEVEL', global_int('MENU_LEVEL') - 1);
  641. END_MACRO;
  642.  
  643.  
  644. $MACRO QUERYBOX FROM ALL;
  645. {*******************************MULTI-EDIT MACRO*******************************
  646. Name:        QUERYBOX /C=n /L=n /W=n /T=str /H=str
  647.  
  648. Description:    Creates a simple text input box.
  649.  
  650. Parameters:        Return_Str is initialized the default input string value.
  651.                             /C=n        The column position
  652.                             /L=n        The line number
  653.                             /W=n        The maximum width of the string in the box
  654.                             /ML=n        The maximum length of the string.
  655.                             /T=str    The box title
  656.                             /H=str    The help index
  657.                             /F2=str F2 label if one is desired.  If this parm is passed,
  658.                                             and F2 is pressed, Return_Int will return -1;
  659.                             /N=1      Numeric input.  If Numeric input then Return_Int
  660.                                                 should be initialized to the default value.
  661.                             /P=str  Prompt.
  662.                             /NK=n   1 = don't kill the box when exiting.  0 = normal.
  663.                             /NB=n        1 = don't make a box.  0 = normal.  Offsets for prompt
  664.                                             position will still be in effect even if a box is not made.
  665.                                             This facilitates reentering the macro without redrawing the
  666.                                             box after not killing the box.
  667.                             /MIN=n    For numeric only.  n = minimum legal response value.
  668.                             /MAX=n    For numeric only.  n = maximum legal response value.
  669.                             /HISTORY= The history global name.
  670.  
  671. Returns:            If NOT Numeric input then
  672.                                 Return_Int = 1 if <ENTER> was pressed to accept the input.
  673.                                 Return_Int = 0 if <ESC> was pressed.
  674.                                 Return_Str = the inputted string.  Unchanged if Return_Int = 0.
  675.                             ELSE
  676.                                 Return_Str = 'TRUE' if <ENTER> was pressed.
  677.                                 Return_Str = 'FALSE' if <ESC> was pressed.
  678.                                 Return_Int = The numeric result.  Unchanged if Return_Str = false.
  679.  
  680.                              (C) Copyright 1989 by American Cybernetics, Inc.
  681. ******************************************************************************}
  682.  
  683.     Def_Int(
  684.                     texp, x, y, jx,
  685.                     numeric, Tint,
  686.                     tbc,
  687.                     old_refresh,
  688.                     box
  689.                     );
  690.  
  691.     Def_Str( Temp_Str,
  692.                      f2[20]
  693.                     );
  694.  
  695.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  696.     old_refresh := refresh;
  697.     texp := explosions;
  698.     explosions := false;
  699.     refresh := false;
  700.     x := Parse_Int('/C=',MParm_Str);
  701.     y := Parse_Int('/L=',MParm_Str);
  702.     f2 := Parse_Str('/F2=',MParm_Str);
  703.     numeric := Parse_Int('/N=', MParm_Str);
  704.     if f2 <> '' THEN
  705.         f2 := '/F2=' + f2;
  706.     end;
  707.     IF (Parse_Str('/F5=',MParm_Str) <> '') THEN
  708.         f2 := f2 + '/F5=' + Parse_Str('/F5=',MParm_Str);
  709.     END;
  710.     box := (Parse_Int('/NB=', MParm_Str) <> 1);
  711.  
  712.     Temp_Str := Return_Str;
  713.     If Numeric Then
  714.         Temp_Str := Str(Return_Int);
  715.         Tint := Return_Int;
  716.     END;
  717.     tbc := box_count;
  718.  
  719. ql1:
  720.     while box_count > tbc do
  721.         kill_box;
  722.     END;
  723.     Return_Str := Temp_Str;
  724.     RM(
  725.                         'USERSTR ' + f2 +
  726.                             '/NK=1/B=' + Str(box) +
  727.                             '/BL=' + Parse_Str('/T=',MParm_Str) +
  728.                             '/P=' + Parse_Str('/P=',MParm_Str) +
  729.                             '/W=' + Parse_Str('/W=',MParm_Str) +
  730.                             '/L=' + parse_str('/ML=', mparm_str) +
  731.                             '/X=' + str( x + (box = 0)) +
  732.                             '/Y=' + str( y + (box = 0)) +
  733.                             '/H=' +Parse_Str('/H=',MParm_Str) +
  734.                             '/HISTORY=' + parse_str('/HISTORY=' , mparm_str)
  735.                         );
  736.     Temp_Str := Return_Str;
  737.     If Return_Int then
  738.         If Numeric THEN
  739.             If VAL(jx,temp_str) <> 0 THEN
  740.                 error_level := 1006;
  741.                 RM('MEERROR');
  742.                 error_level := 0;
  743.                 Goto QL1;
  744.             END;
  745.             IF (Parse_Str('/MIN=', MParm_Str) <> '') THEN
  746.                 IF (Jx < Parse_Int('/MIN=', MParm_Str)) THEN
  747.                     RM('MEERROR^Beeps /C=1');
  748.                     Goto QL1;
  749.                 END;
  750.             END;
  751.             IF (Parse_Str('/MAX=', MParm_Str) <> '') THEN
  752.                 IF (Jx > Parse_Int('/MAX=', MParm_Str)) THEN
  753.                     RM('MEERROR^Beeps /C=1');
  754.                     Goto QL1;
  755.                 END;
  756.             END;
  757.             Return_Str := 'TRUE';
  758.             Return_Int := jx;
  759.         END;
  760.     ELSE
  761.         If Numeric THEN
  762.             Return_Str := 'FALSE';
  763.             Return_Int := Tint;
  764.         END;
  765.     END;
  766.  
  767.     IF parse_int('/NK=', mparm_str) = 0 THEN
  768.         while box_count > tbc do
  769.             kill_box;
  770.         END;
  771.     END;
  772.     refresh := old_refresh;
  773.     explosions := texp;
  774.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  775. END_MACRO;
  776.  
  777. $MACRO VERIFY FROM ALL;
  778. {*******************************MULTI-EDIT MACRO******************************
  779.  
  780. Name:  VERIFY
  781.  
  782. Description:  Creats a simple CONFIRM YES/NO box.
  783.  
  784. Parameters:        /C=nn      column number to put box.
  785.                             /L=nn        line number to put box.
  786.                             /H=str  help string.
  787.                             /T=str  convirm message
  788.                             /BL=str Box label
  789.                             /S=nn   default selection 1 or 2.  Defaults to 1.
  790.  
  791. Returns:            RETURN_INT = True if YES was selected,
  792.                                                      False if NO was selected or ESC was pressed.
  793.  
  794.                              (C) Copyright 1989 by American Cybernetics, Inc.
  795. ******************************************************************************}
  796.     Def_Int(x,y,w,s);
  797.     Def_Str(Temp_Str[132], ts2[80] );
  798.     x := Parse_Int('/C=',MParm_Str);
  799.     y := Parse_Int('/L=',MParm_Str);
  800.     if x = 0 then
  801.         x := 2;
  802.     end;
  803.     if y = 0 then
  804.         y := 4;
  805.     end;
  806.     s := Parse_Int('/S=',MParm_Str);
  807.     IF ((s > 2) or (S < 1)) THEN
  808.         S := 1;
  809.     END;
  810.     ts2 := parse_str('/BL=',mparm_str);
  811.     if ts2 = '' THEN
  812.         ts2 := 'CONFIRM';
  813.     END;
  814.     Temp_Str := Parse_Str('/T=',MParm_Str);
  815.     w := svl(temp_str);
  816.     IF w < svl( ts2 ) THEN
  817.         w := svl(ts2);
  818.     END;
  819.     Put_Box(x,y,x+w+11,y+3,0,m_b_Color,ts2,True);
  820.     Write(Temp_Str,x+1,y+1,0,m_s_Color);
  821.     RM('USERIN^XMENU /T=0 /X=' + str(x+3+Length(Temp_Str)) +
  822.                                              '/Y=' + str(y+1) +
  823.                                              '/S=' + Str(S) + '/M=' +
  824.         'No('+Parse_Str('/H=',MParm_Str) + ')Yes(' + Parse_Str('/H=',MParm_Str) + ')');
  825.     Return_Int := Return_Int > 1;
  826.     Kill_Box;
  827. END_MACRO;
  828.  
  829. $MACRO CHECKFILE;
  830. {*******************************MULTI-EDIT MACRO******************************
  831.  
  832. Name: CHECKFILE
  833.  
  834. Description:    Checks to see if a file has been saved and prompts the user if
  835.                             he wants to save before the window gets erased or deleted.  Will
  836.                             save the file, if he so chooses.
  837.  
  838. Parameters:
  839.                             /X=    The X coordinate for the prompt box
  840.                             /Y=    The Y coordinate for the prompt box
  841.  
  842. Returns:
  843.                             Return_Int
  844.                                 0 - Don't destroy the data.
  845.                                 1 - O.K. to blast it.
  846.  
  847.                              (C) Copyright 1989 by American Cybernetics, Inc.
  848. ******************************************************************************}
  849.  
  850.     Def_Int(w);
  851.     Def_Str(Temp_Str[20]);
  852.  
  853.     If (File_Changed) and (link_stat = 0) then
  854.         temp_str := parse_str('/H=', mparm_str);
  855.         RM('USERIN^XMENU /T=0/B=1/L=CURRENT FILE NOT SAVED - CONTINUE?/X=' +
  856.                 Parse_Str('/X=',MParm_Str) + '/Y=' + Parse_Str('/Y=',MParm_Str) +
  857.                 '/S=1/M=' +
  858.             'No('+temp_str + ')Yes-((abandon changes)(' + temp_str + ')Save-file-and-continue(' + temp_str + ')');
  859.         If return_int = 3 then
  860.             Error_Level := 0;
  861.             save_file;
  862.             return_int := 1;
  863.             if error_level <> 0 then
  864.                 RM('MEERROR');
  865.                 return_int := 0;
  866.             end;
  867.         else
  868.             return_int := (return_int > 1);
  869.         end;
  870.     else
  871.         return_int := 1;
  872.     end;
  873. END_MACRO;
  874.  
  875.  
  876. $MACRO MAINHELP FROM ALL;
  877. {*******************************MULTI-EDIT MACRO******************************
  878.  
  879. Name:  MAINHELP
  880.  
  881. Description:  Brings up the main help screen ME.HLP or ME.HLC.
  882.  
  883.                              (C) Copyright 1989 by American Cybernetics, Inc.
  884. ******************************************************************************}
  885.     RM('MEHELP /F=ME/LK=*/CX=' + str(mode = EDIT));
  886. END_MACRO;
  887.  
  888. $MACRO DATA_IN FROM ALL;
  889. {******************************************************************************
  890.                                                         MULTI-EDIT MACRO
  891.  
  892. Name:  DATA_IN
  893.  
  894. Description: Builds a screen of editable fields.  Each field has its own
  895.     column and line setting, as well as its own help and type attributes.
  896.     Will build a box around the fields if /X and /Y are specified.  If the
  897.     height (/H) or the width (/W) are not specified then they will be calculated.
  898.  
  899. Parameters:  /#=count  {the number of fields}
  900.                          /S=start_field {the starting field number}
  901.                          /PRE=str {The prefix to use for the global var names}
  902.                          /X=nn  {The Upper Right hand column, or x coordinate}
  903.                          /Y=nn  {The Upper Right hand row, or y coordinate}
  904.                          /H=str  {help string}
  905.                          /HT=nn  {The height of the box, automatically calculated if not
  906.                                          present}
  907.                          /W=nn  {The width of the box, automatically calculated as above}
  908.                          /T=title  {The title of the box}
  909.                          /A=nn  Accept type.
  910.                                         0 = Accept no matter what.
  911.                                         1 = Accept no matter what.
  912.                                         2 = Accept no matter what.
  913.                                         3 = Use ACCEPT field defined by type 6 or via /GO=1 in IPARM_x.
  914.                          /NC=nn 1 = NO Cleanup.  Don't erase global variables when done.
  915.  
  916. Returns:    RETURN_INT = 0 if the <ESC> key was pressed.
  917.                         Else RETURN_INT = Then item that <ENTER> was pressed on.
  918.  
  919. Global Vars:
  920.                 ISTR_1 .. ISTR_x   {field string, x = count}
  921.                 IPARM_1 .. IPARM_x  {parmaeter string,x = count}
  922.                     /C=                column
  923.                     /L=                line
  924.                     /W=                displayable width of field
  925.                     /ML=            max length if max length is 0 then max length =    width.
  926.                     /H=                 help_link.
  927.                     /T=                Field title
  928.                     /GO=            If <enter> pressed on this field, treat like accept field.
  929.                     /HISTORY=    name of history_list globals
  930.                     /PROTECT=    1 prevents a field from being changed.
  931.                     /MIN=            Minimum numeric value if a numeric type
  932.                     /MAX=            Maximum numeric value if a numeric type
  933.                     /TP=            type
  934.                                  type of 0 = string (default)
  935.                                                  1 = integer
  936.                                                  2 = real number
  937.                                                  3 = Multiple Choice with vertical menu.
  938.                                                          ISTR_x contains the menu.
  939.                                                          IINT_x contains the choice number.
  940.                                                  4 = Hex - same as integer, except display and
  941.                                                                      user input in hex.
  942.                                                  5 = toggle true or false.
  943.                                                             ISTR_x = '/T=YES/F=NO'
  944.                                                             IINT_x = boolean value.
  945.                                                  6 = Accept field.
  946.                                                  7 = Run macro, return integer.
  947.                                                          IPARM=x /M=macro (must be last parameter)
  948.                                                          The following parameters get passed to the
  949.                                                          macro:
  950.                                                                 /X=nn
  951.                                                                 /Y=nn
  952.                                                                 /STR=str (the string in ISTR_x)
  953.                                                  8 = Run macro, return string(or return global, see below).
  954.                                                          IPARM=x /M=macro (must be last parameter)
  955.                                                                 /X=nn
  956.                                                                 /Y=nn
  957.                                                                 /INT=nn (the integer in IINT_x)
  958.                                                  /RGS= Return global string.  Used only with /TP=8.
  959.                                                              Due to the 255 character limit on Return_Str, if
  960.                                                              you specify the name of a global string, it will
  961.                                                              use that instead.
  962.  
  963.                                                  9 = Keycode field.  It is stored in IINT as an integer
  964.                                                          lower byte is primary scan code, upper byte is
  965.                                                          extended scan code.  Field will be displayed as in
  966.                                                          the example below:
  967.                                                              SET_GLOBAL_INT('IINT_1',7181);
  968.                                                              Displays <ENTER>
  969.                                                          User will be prompted for a keystroke when he presses
  970.                                                          <ENTER> a type 9 field.
  971.  
  972.                 IINT_x = value for integer or multiple choice.
  973.                 IHELP1  the help string when no field is being edited.
  974.                 IHELP1 = '/C=column/L=Line/H=help_str'
  975.                 IHELP2  the help string when a field is being edited.
  976.                 IHELP2 = '/C=column/L=Line/H=help_str'
  977.  
  978.         Note that if an X and Y coordinate was specified in the parameter line
  979.         then, the column and line numbers will be offsets from the X and Y
  980.         coordinates.
  981.  
  982.  
  983. Example:    {Setup multi-file search}
  984.  
  985.         Set_Global_Str('IHELP1','/C=13/L=8/H= to select,   <ESC> to exit,   <F3> to edit.');
  986.         Set_Global_Str('IHELP2','/C=13/L=8/H=<ENTER> to accept input, <ESC> to abort input.');
  987.         Set_Global_Str('ISTR_1',filespec);
  988.         Set_Global_Str('IPARM_1','/T=Filespec:/C=1/W=60/ML=80/H=SR/L=1');
  989.         Set_Global_Str('ISTR_2',Search_Str);
  990.         Set_Global_Str('IPARM_2','/T=Search For:/C=1/W=63/ML=128/H=SR/L=2');
  991.     Set_Global_Str('IPARM_3','/T=>>>>/C=1/H=SR/L=3/TP=6/W=17');
  992.     Set_Global_Str('ISTR_3','START FILE SEARCH');
  993.  
  994.         Set_Global_Int('IINT_4',search_dirs);
  995.         Set_Global_Str('ISTR_4','/T=YES/F=NO');
  996.         Set_Global_Str('IPARM_4','/T=Search Subdirectories..../C=1/W=3/H=SR/L=4/TP=5');
  997.         Set_Global_Str('ISTR_5',global_str('FSEARCH_PATH'));
  998.         Set_Global_Str('IPARM_5','/T=Starting path............/C=1/W=40/H=SR/L=5');
  999.         Set_Global_Int('IINT_6',case_sensitive);
  1000.         Set_Global_Str('ISTR_6','/T=YES/F=NO');
  1001.         Set_Global_Str('IPARM_6','/T=Case Sensitivity........./C=1/W=3/H=SR/L=6/TP=5');
  1002.         Set_Global_Int('IINT_7',use_reg_exp);
  1003.         Set_Global_Str('ISTR_7','/T=YES/F=NO');
  1004.         Set_Global_Str('IPARM_7','/T=Use Regular Expressions../C=1/W=3/H=SR/L=7/TP=5');
  1005.  
  1006.         RM('UserIn^Data_In /S=1/A=3/#=7/X=1/T=SEARCH FILES/Y=' + str(y1));
  1007.  
  1008.  
  1009.                              (C) Copyright 1989 by American Cybernetics, Inc.
  1010. ******************************************************************************}
  1011.  
  1012.     Def_Str( MStr,
  1013.                      Prefix[10],
  1014.                      iint[20], iparm[20], istr[20],
  1015.                      Label_Str[132],
  1016.                      c_str1[20],
  1017.                      c_str2[20],
  1018.                      history_str[20],
  1019.                      event_str[20],
  1020.                      tstr[80],
  1021.                      RGS[20]
  1022.                  );                   {General purpose string}
  1023.     Def_Int(  tcp,
  1024.                         t_refresh,
  1025.                         field_count,       {The number of fields}
  1026.                         fc, bc,                {Foreground and background colors}
  1027.                         X1, Y1, Height,
  1028.                         Width, jx, jy, jz, old_x, old_y,
  1029.                         c_choice,
  1030.                         tc, tl, tw,tt,    {Temp col, line, and width, type}
  1031.                         ll,             {Temp label length}
  1032.                         protect,        {field protect status}
  1033.                         hc, hl,               {Help line and column}
  1034.                         C_Parm,               {The parm string being worked on}
  1035.                         old_c, old_l,    {The old cursor position}
  1036.                         accept_mode,
  1037.                         history_stat,
  1038.                         min_num,
  1039.                         tmw,
  1040.                         full_write,
  1041.                         mouse_result,
  1042.                         event_count,
  1043.                         count,
  1044.                         Edit_Enable,
  1045.                         go_accept, t_parm
  1046.                  );
  1047.  
  1048.     t_refresh := refresh;
  1049.     refresh := false;
  1050.     working;
  1051.     Edit_Enable := False;
  1052.     RGS := Parse_Str('/RGS=',MParm_Str);
  1053.     go_accept := False;
  1054.  
  1055.     old_c := WhereX;          {Save the cursor position for later restoration}
  1056.     Old_l := WhereY;
  1057.  
  1058.     Return_Int := False;
  1059.     field_count := 0;
  1060.     Push_Labels;
  1061.  
  1062.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  1063.  
  1064.         {Get the count of the fields}
  1065.     field_count := Parse_Int('/#=', MParm_Str);
  1066.     X1 := Parse_Int('/X=', MParm_Str);
  1067.     Y1 := Parse_Int('/Y=', MParm_Str);
  1068.  
  1069.     prefix := parse_str( '/PRE=', mparm_str );
  1070.     iint := prefix + 'IINT_';
  1071.     istr := prefix + 'ISTR_';
  1072.     iparm := prefix + 'IPARM_';
  1073.  
  1074.     Height := Parse_Int('/HT=', MParm_Str);
  1075.     Width := Parse_Int('/W=', MParm_Str);
  1076.     accept_mode := Parse_Int('/A=', MParm_Str);
  1077.     min_num := 1;
  1078.     full_write := false;
  1079.  
  1080.         {If no height or width then calculate then by going through the
  1081.          entire list of fields and determining the maximun column and
  1082.          row needed.}
  1083.     IF (X1 <> 0) and ((Height = 0) or (Width = 0)) THEN
  1084.         C_Parm := min_num;
  1085.         While (C_Parm <= field_count) DO
  1086.             MStr := Global_Str( iparm + Str( C_Parm ) );
  1087.             jx := length( Parse_Str('/T=',MStr) );
  1088.       Jx := Jx + Parse_Int('/C=',MStr) + Parse_Int('/W=',MStr) + 1;
  1089.       tt := parse_int( '/TP=', mstr );
  1090.       IF (tt = 3) OR (TT > 4) THEN
  1091.         ++jx;
  1092.         ++jx;
  1093.       END;
  1094.             If Jx > Width THEN
  1095.                 Width := JX;
  1096.             END;
  1097.             jx := Parse_Int('/L=',MStr);
  1098.             if jx = 0 then
  1099.                 jx := height + 1;
  1100.                 mstr := '/L=' + str(jx) + mstr;
  1101.                 set_global_str( iparm + str(c_parm), mstr);
  1102.             end;
  1103.             If jx > Height THEN
  1104.                 Height := JX;
  1105.             END;
  1106.             ++C_Parm;
  1107.         END;
  1108.         Height := Height + 2;
  1109.         Width := Width + 2;
  1110.     END;
  1111.  
  1112.     if (x1 + width) > screen_width then
  1113.         x1 := (screen_width - width) - 1;
  1114.     end;
  1115.     IF X1 <= 0 THEN
  1116.         X1 := 1;
  1117.     END;
  1118.     if (y1 + height) > (screen_length - (fkey_row <> 0)) then
  1119.         y1 := (screen_length - (fkey_row <> 0)) - height;
  1120.     end;
  1121.     IF Y1 <= 0 THEN
  1122.         Y1 := 3;
  1123.     END;
  1124.  
  1125.     event_count := 0;
  1126.     event_str :=  '@EV' + Str(Global_Int( 'MENU_LEVEL' )) + '#';
  1127.     If (field_count < min_num) THEN
  1128.         GOTO EXIT2;
  1129.     END;
  1130.  
  1131.     set_virtual_display;
  1132.         {If an x coordinate was specified then build a box}
  1133.     If X1 <> 0 THEN
  1134.         Put_Box(X1,Y1,X1+Width,Y1+Height,0,m_b_color,
  1135.                         Parse_Str('/T=',MParm_Str),true);
  1136.         event_count := 2;
  1137.         IF accept_mode = 3 THEN
  1138.             mstr := 'Cancel';
  1139.         ELSE
  1140.             mstr := 'Done';
  1141.         END;
  1142.         Set_Global_Str(event_str + '1',
  1143.                 '/T=' + mstr + '/KC=<ESC>/K1=27/K2=1/R=0');
  1144.         Set_Global_Str(event_str + '2',
  1145.                 '/T=Next/KC=<TAB>/W=9/K1=9/K2=15/R=1');
  1146.         RM('CheckEvents /M=4/G=' + event_str + '/#=' + str(event_count) + '/X=' + str(x1) + '/Y=' + str(y1 + height - 1) + '/W=' + str(width - 2));
  1147.         RM('CheckEvents /M=2/G=' + event_str + '/#=' + str(event_count));
  1148.     END;
  1149.  
  1150.  
  1151.  
  1152.         {Write all of the fields on the screen}
  1153.     IF (Global_Str(prefix + 'IHELP3') <> '') THEN
  1154.         Call HELP_LINE3;
  1155.     END;
  1156.     call draw_all_fields;
  1157.     full_write := true;
  1158.         {Put up the Function key labels}
  1159.     FLabel('Help',1,$FF);
  1160.     Flabel('Edit',3,$FF);
  1161.  
  1162.     C_Parm := Parse_Int('/S=',MParm_Str);  {Get the starting field number}
  1163.     If (C_Parm < min_num) THEN
  1164.         C_Parm := min_num;
  1165.     END;
  1166.     update_status_line;
  1167.     update_virtual_display;
  1168.     reset_virtual_display;
  1169. Main_Loop:
  1170.  
  1171.     IF (Go_accept) THEN
  1172.         Return_Int := T_Parm;
  1173.         Goto Exit;
  1174.     END;
  1175.  
  1176.     Call Help_Line1;
  1177.     If C_Parm < min_num then
  1178.         C_Parm := field_count;
  1179.     END;
  1180.     If C_Parm > field_count then
  1181.         C_Parm := min_num;
  1182.     END;
  1183.     T_Parm := C_Parm;
  1184.     Call Mark_Item;
  1185.     if svl(history_str) <> 0 then
  1186.         flabel('List', 4, -1);
  1187.     else
  1188.         flabel('', 4, -1);
  1189.     end;
  1190.     old_x := 0;
  1191.     old_y := 0;
  1192.     WHILE NOT(Check_Key) DO
  1193.         Mou_Check_Status;
  1194.         IF ((Mou_Last_Status AND 1) <> 0) AND ((old_x <> Mou_Last_X) OR (old_y <> Mou_last_Y)) THEN
  1195.             old_x := Mou_Last_X;
  1196.             old_y := Mou_Last_Y;
  1197.             call find_mouse;
  1198.         END;
  1199.     END;
  1200.     jx := INQ_KEY( key1, key2, 5, tstr );
  1201.     IF jx = 1 THEN
  1202.         RM( tstr );
  1203.         goto main_loop;
  1204.     end;
  1205.     If Key1 = 0 THEN
  1206.             {don't allow the F2 key}
  1207.         If (Key2 = 60) THEN
  1208.             Goto Main_Loop;
  1209.             {If F1 then run help}
  1210.         ELSIf (Key2 = 59) THEN
  1211.             mstr := Parse_Str('/H=',Global_Str( iparm + Str( C_Parm ) ));
  1212.             IF mstr = '' THEN
  1213.                 mstr := parse_str('/H=', mparm_str);
  1214.             END;
  1215.             help(mstr);
  1216.             Goto Main_Loop;
  1217.         ELSif (key2 = 62) then
  1218.             if svl(history_str) <> 0 then
  1219.                 goto input_data;
  1220.             end;
  1221.             goto main_loop;
  1222.             {If Up arrow key or up mouse then move bar up}
  1223.         ELSIf (key2 = 242) then
  1224.             goto main_loop;
  1225.         ELSIf (key2 = 243) then
  1226.             goto main_loop;
  1227.         ELSIf (key2 = 244) then
  1228.             goto go_cr;
  1229.         ELSIf (key2 = 245) then
  1230.             goto go_esc;
  1231.         ELSIF (key2 = 250) THEN
  1232.             IF (Mou_Last_Y = Fkey_Row) THEN
  1233.                 RM( 'MOUSE^MouseFkey' );
  1234.                 Goto Main_Loop;
  1235.             ELSIF (Mou_Last_X < x1) OR (Mou_Last_X > (x1 + width)) OR
  1236.                  (Mou_Last_Y < y1) OR (Mou_Last_Y > (y1 + height + 1)) THEN
  1237.                 Push_Key( 0, 250 );
  1238.                 Goto go_esc;
  1239.             END;
  1240.             RM('CheckEvents /M=1/G=' + event_str + '/#=' + str(event_count));
  1241.             RM('CheckEvents /M=2/G=' + event_str + '/#=' + str(event_count));
  1242.             IF RETURN_INT <> 0 THEN
  1243.                 Return_Int := Parse_Int('/R=', return_str);
  1244.                 IF return_int = 1 THEN
  1245.                     goto go_right;
  1246.                 ELSE
  1247.                     goto go_esc;
  1248.                 END;
  1249.             END;
  1250.             call find_mouse;
  1251.             IF (mouse_result <> 0) AND
  1252.                  (tt > 2) AND (tt <> 4) THEN
  1253.                 goto go_cr;
  1254.             ELSE
  1255.                 Goto Main_Loop;
  1256.             END;
  1257.         ELSIf (Key2 = 71) then
  1258.             Call UnMark_Item;
  1259.             C_Parm := min_num;
  1260.             goto main_loop;
  1261.         ELSIf (Key2 = 79) then
  1262.             Call UnMark_Item;
  1263.             C_Parm := field_count;
  1264.             goto main_loop;
  1265.         ELSIf (Key2 = 72) or (Key2 = 240) THEN
  1266.             Call UnMark_Item;
  1267.             Call Find_Up;
  1268.             Goto Main_Loop;
  1269.         ELSIf {(key2 = 77) or} (key2 = 243) THEN
  1270. go_right:
  1271.             Call UnMark_Item;
  1272.             ++C_Parm;
  1273.             Goto Main_Loop;
  1274.         ELSIf (key2 = 242) or (key2 = 15) THEN
  1275.             Call UnMark_Item;
  1276.             --C_Parm;
  1277.             Goto Main_Loop;
  1278.         ELSIf (Key2 = 80) or (Key2 = 241) THEN
  1279.             Call UnMark_Item;
  1280.             Call Find_Down;
  1281.             Goto Main_Loop;
  1282.         END;
  1283.     END;
  1284.         {If <ESC> or the right mouse button the exit with false}
  1285.     IF (Key1 = 27) THEN
  1286. go_esc:
  1287.         if accept_mode = 3 then
  1288.             Return_Int := False;
  1289.         else
  1290.             return_int := 1;
  1291.         end;
  1292.         Goto Exit;
  1293.     END;
  1294.     If (Key1 = 9) THEN
  1295.         Goto Go_Right;
  1296.     END;
  1297.     IF (Key1 = 13) THEN
  1298. go_cr:
  1299.         IF (Accept_Mode = 0) or (C_Parm = 0) THEN
  1300.             Return_Int := C_Parm;
  1301.             If Accept_Mode = 1 then
  1302.                 Return_Int := 1;
  1303.             end;
  1304.             Goto Exit;
  1305.         ELSE
  1306.             IF (TT = 7) THEN
  1307.                 Return_Int := XPos('/M=',Global_Str(iparm + Str( C_Parm )),1);
  1308.                 IF (Return_Int) THEN
  1309.                     Return_Str := Copy(Global_Str(iparm + Str( C_Parm )),Return_Int + 3,
  1310.                         255);
  1311.                     IF (XPos(' ',Return_Str,1) = 0) THEN
  1312.                         Return_Str := Return_Str + ' ';
  1313.                     END;
  1314.                     return_int := Global_Int(iint + Str( C_Parm ));
  1315.                     RM(Return_Str + '/X=' + Str(X1) + '/Y=' + Str(Y1) +
  1316.                         '/INT=' + Str(Global_Int(iint + Str( C_Parm ))) + '/PRE=' + prefix);
  1317.                     Set_Global_Int(iint + Str( C_Parm ),Return_Int);
  1318.                 END;
  1319.                 call draw_all_Fields;
  1320.             END;
  1321.             IF (TT = 8) THEN
  1322.                 Return_Int := XPos('/M=',Global_Str(iparm + Str( C_Parm )),1);
  1323.                 IF (Return_Int) THEN
  1324. {Check to see if command line parameters already exist in the macro name.  If
  1325. so, don't add a space between macro name and the params we are adding}
  1326.                     MStr := Copy(Global_Str(iparm + Str( C_Parm )),Return_Int + 3,
  1327.                         255);
  1328.                     IF (XPos(' ',MStr,1) = 0) THEN
  1329.                         MStr := MStr + ' ';
  1330.                     END;
  1331.                     Return_Str := Global_Str(istr + str( c_parm ) );
  1332.                     IF (RGS <> '') THEN
  1333.                         Set_Global_Str(RGS,Global_Str(istr + str( c_parm )));
  1334.                     END;
  1335.                     RM(MStr + '/X=' + Str(X1) + '/Y=' + Str(Y1) +
  1336.                         '/STR=' + Global_Str(istr + Str( C_Parm )) + '/PRE=' + prefix);
  1337.                     IF return_int > 0 THEN
  1338.                         Set_Global_Str(istr + Str( C_Parm ),return_str);
  1339.                         IF (RGS <> '') THEN
  1340.                             Set_Global_Str(istr + Str( C_Parm ),Global_str(RGS));
  1341.                         END;
  1342.                     END;
  1343.                     call draw_all_Fields;
  1344.                 END;
  1345.             END;
  1346.             IF (TT = 9) THEN
  1347.                 Put_Box(X1,Y1,X1 + 25,Y1 + 3,0,M_B_Color,'EDIT QUICKSTROKE',true);
  1348.                 Write('Press the desired key.',X1 + 1,Y1 + 1,0,M_B_Color);
  1349.                 Read_Key;
  1350.                 Kill_Box;
  1351.                 Set_Global_Int(iint + Str( C_Parm ), (key2 * 256) + key1);
  1352.             END;
  1353.  
  1354.             If (tt = 6) then
  1355.                 Return_Int := c_parm;
  1356.                 goto exit;
  1357.             end;
  1358.             If (C_Parm > 0) and (Accept_Mode <> 0) and (TT = 3) THEN
  1359.                 RM('USERIN^XMENU /T=1/B=1/X=' + Str(X1 + 2) + '/Y=' + Str(Y1 + 2) + '/L=' + Shorten_Str(Label_Str) +
  1360.                                         '/S=' + Str(C_Choice) + '/M=' + Global_Str(istr + Str( C_Parm ) ));
  1361.  
  1362.                 If Return_Int > 0 THEN
  1363.                     Set_Global_Int(iint + Str( C_Parm ), Return_Int);
  1364.                 END;
  1365.                 Call UnMark_Item;
  1366.                 ++C_Parm;
  1367.             ELSE
  1368.                 If tt = 5 then
  1369.                     Set_Global_Int(iint + str(c_parm),
  1370.                             NOT(Global_Int(iint + str(c_parm))));
  1371.                 else
  1372.                     Call UnMark_Item;
  1373.                     ++C_Parm;
  1374.                 end;
  1375.             END;
  1376.         END;
  1377.         go_accept := parse_int('/GO=', Global_Str( iparm + str(t_parm) ));
  1378.         Goto Main_Loop;
  1379.     END;
  1380.  
  1381.     IF (tt = 5) THEN
  1382. {Force true or false using T for true and F for false}
  1383.         IF ((Key1 = 84) or (Key1 = 116)) THEN
  1384.             Set_Global_Int(iint + str(c_parm),True);
  1385.         END;
  1386.         IF ((Key1 = 70) or (Key1 = 102)) THEN
  1387.             Set_Global_Int(iint + str(c_parm),False);
  1388.         END;
  1389.         go_accept := parse_int('/GO=', Global_Str( iparm + str(t_parm) ));
  1390.         Goto MAIN_LOOP;
  1391.     END;
  1392.  
  1393.     IF (accept_mode = 1) and (C_Parm = 0)  THEN
  1394.         Goto Main_Loop;
  1395.     END;
  1396.     If ((tt <> 3) and ((tt < 5) or (TT > 9))) AND NOT(protect) then
  1397. input_data:
  1398.         Push_Key(key1,key2);
  1399.         Call Help_Line2;
  1400. loopb:
  1401.         Mstr := Global_Str(istr + Str(C_PARM));
  1402.         IF TT = 1 THEN
  1403.             MStr := Str(Global_Int(iint + Str( C_Parm )));
  1404.         END;
  1405.         if tmw = 0 then
  1406.             tmw := tw;
  1407.         end;
  1408.         Return_Str := Mstr;
  1409.         RM('USERSTR /A=1/X=' + str(x1 + tc + ll + 1) +
  1410.                                             '/Y=' + str(y1 + tl) +
  1411.                                             '/W=' + str(tw) +
  1412.                                             '/L=' + str(tmw) +
  1413.                                             '/H=' + Parse_Str('/H=',Global_Str( iparm + Str( C_Parm ) )) +
  1414.                                             '/HISTORY=' + Parse_Str('/HISTORY=',Global_Str( iparm + Str( C_Parm ) ))
  1415.                                         );
  1416.         Mstr := Return_Str;
  1417.         If (return_int > 0) or (return_int = -2) then
  1418.             IF TT = 1 THEN
  1419.                 IF Val( jx, MStr) <> 0 THEN
  1420.                     error_level := 1006;
  1421.                     RM('MEERROR');
  1422.                     error_level := 0;
  1423.                     goto loopb;
  1424.                 END;
  1425.                 IF xpos( '/MIN=', Global_Str( iparm + str(c_parm) ),1) <> 0 THEN
  1426.                     jy := parse_int('/MIN=', Global_Str( iparm + str(c_parm) ));
  1427.                     IF jx < jy THEN
  1428.                         error_level := 1006;
  1429.                         RM('MEERROR');
  1430.                         error_level := 0;
  1431.                         goto loopb;
  1432.                     END;
  1433.                 END;
  1434.                 IF xpos( '/MAX=', Global_Str( iparm + str(c_parm) ),1) <> 0 THEN
  1435.                     jy := parse_int('/MAX=', Global_Str( iparm + str(c_parm) ));
  1436.                     IF jx > jy THEN
  1437.                         error_level := 1006;
  1438.                         RM('MEERROR');
  1439.                         error_level := 0;
  1440.                         goto loopb;
  1441.                     END;
  1442.                 END;
  1443.                 Set_Global_Int(iint + Str(C_Parm),jx);
  1444.             ELSE
  1445.                 IF (TT = 4) THEN
  1446.                     {Process hex input}
  1447.                     MStr := Caps(MStr);
  1448.                     Jy := svl(MStr);
  1449.                     if val(jx, '$' + mstr) <> 0 then
  1450.                         RM('MEERROR^Beeps /C=1');
  1451.                         goto loopb;
  1452.                     end;
  1453.                     Set_Global_Int(iint + Str(C_Parm),jx);
  1454.                 ELSE
  1455.                     Set_Global_Str(istr + Str(C_Parm),MStr);
  1456.                 END;
  1457.             END;
  1458.             Call UnMark_Item;
  1459.             if return_int = -2 then
  1460.                 push_key(key1,key2);
  1461.             else
  1462.                 ++C_Parm;
  1463.             end;
  1464.         END;
  1465.     END;
  1466.     go_accept := parse_int('/GO=', Global_Str( iparm + str(t_parm) ));
  1467.     Goto Main_Loop;
  1468.  
  1469. draw_all_fields:
  1470.     tcp := c_parm;
  1471.     C_Parm := min_num - 1;
  1472.     fc := m_s_Color;
  1473.     bc := 0;
  1474.     While (C_Parm < field_count) DO
  1475.         ++C_Parm;
  1476.         Call Write_ISTR;
  1477.     END;
  1478.     c_parm := tcp;
  1479.     ret;
  1480.  
  1481. Mark_Item:
  1482.     fc := m_h_color;
  1483.     bc := 0;
  1484.     Call Write_ISTR;
  1485.     GotoXy(X1 + TC + LL + 1,Y1 + TL);
  1486.     Ret;
  1487.  
  1488. UnMark_Item:
  1489.     fc := m_s_Color;
  1490.     bc := 0;
  1491.     Call Write_ISTR;
  1492.     Ret;
  1493.  
  1494.     def_int( xx, yy );
  1495. Write_ISTR:
  1496.     c_str1 := str(c_parm);
  1497.     MStr := Global_Str( iparm + c_str1 );
  1498.     c_str2 := istr + c_str1;
  1499.     c_str1 := iint + c_str1;
  1500.  
  1501.     TC := Parse_Int('/C=',Mstr);
  1502.     TL := Parse_Int('/L=',Mstr);
  1503.     TW := Parse_Int('/W=',Mstr);
  1504.     TMW := Parse_Int('/ML=',Mstr);
  1505.     TT := Parse_Int('/TP=',MSTR);
  1506.     PROTECT := Parse_Int( '/PROTECT=', mstr );
  1507.     history_str := parse_str( '/HISTORY=', mstr );
  1508.     Label_Str := Parse_Str('/T=',MStr);
  1509.     LL := svl( Label_Str );
  1510.     xx := tc + x1;
  1511.     yy := tl + y1;
  1512.     Write( Label_Str, xx, yy, 0, m_t_Color);
  1513.     xx := xx + ll;
  1514.     IF (tt = 3) OR (TT > 4) THEN
  1515.         ++xx;
  1516.         draw_char( 91, xx, yy, m_t_color, 1 );
  1517.         ++xx;
  1518.         draw_char( 93, xx + tw, yy, m_t_color, 1 );
  1519.     ELSE
  1520.         ++xx;
  1521.     END;
  1522.     If (TT = 1) or (TT = 7) THEN
  1523.         MStr := Str(Global_Int(c_str1));
  1524.         goto gowrite;
  1525.   ELSIF (TT = 9) THEN
  1526.     RM('SETUP^MAKEKEY /K1=' + Str(Global_Int(c_str1) and $FF) + '/K2=' +
  1527.             Str((Global_Int(c_str1) shr 8) and $FF));
  1528.         MStr := Return_Str;
  1529.         goto gowrite;
  1530.     END;
  1531.  
  1532.     MStr := Global_Str(c_str2);
  1533.     if tt = 0 then
  1534.         goto gowrite;
  1535.   Elsif tt = 5 then
  1536.         if Global_Int(c_str1) = 0 then
  1537.             mstr := parse_str('/F=', mstr );
  1538.         else
  1539.             mstr := parse_str('/T=', mstr );
  1540.         end;
  1541.         goto gowrite;
  1542.   ELSIF (TT = 4) THEN  {Process HEX}
  1543.         Mstr := Hex_Str( Global_Int(c_str1) );
  1544.         IF (svl(mstr) mod 2) <> 0 then
  1545.             mstr := '0' + mstr;
  1546.         end;
  1547.   ELSIF TT = 3 THEN  {Process Menu}
  1548.         c_choice := Global_Int(c_str1);
  1549.         IF (C_Choice < 1) THEN
  1550.             C_Choice := 1;
  1551.         END;
  1552.         Count := 0;
  1553.         jx := 1;
  1554.         jz := 1;
  1555. Menu_loop:
  1556.         jx := xpos( '(', mstr, jx + 1 );
  1557.         if jx <> 0 then
  1558.             if copy(mstr, jx + 1, 1) = '(' then
  1559.                 mstr := str_del( mstr, jx, 1);
  1560.                 goto MENU_loop;
  1561.             end;
  1562.             ++count;
  1563.             jy := xpos( ')', mstr, jx + 1);
  1564.             IF (Count < C_Choice) THEN
  1565.                 jz := jy + 1;
  1566.                 goto MENU_loop;
  1567.             END;
  1568.         end;
  1569.     MStr := copy( mstr, jz, jx - jz );
  1570.     END;
  1571. gowrite:
  1572.     if full_write then
  1573.         Draw_char(32, xx, yy,fc,tw);
  1574.     end;
  1575.     if tw = 0 then
  1576.         tw := svl(mstr);
  1577.     end;
  1578.   IF svl(mstr) > TW THEN
  1579.     Write(copy(MStr, 1, tw),xx, Yy,BC,FC);
  1580.   ELSE
  1581.     Write(mstr, xx, yy, bc, fc );
  1582.   END;
  1583.     Ret;
  1584.  
  1585. Help_Line1:
  1586.     MStr := Global_Str( prefix + 'IHELP1' );
  1587. Help_Parse:
  1588.     HC := Parse_Int('/C=',MStr);
  1589.     HL := Parse_Int('/L=',MStr);
  1590.     if hl = 0 then
  1591.         hl := height - 1;
  1592.     end;
  1593.     MStr := Parse_Str('/H=',MStr);
  1594.     Write(MStr,X1+HC,Y1+HL,0,M_B_Color);
  1595.     Ret;
  1596.  
  1597. Help_Line2:
  1598.     MStr := Global_Str( prefix + 'IHELP2' );
  1599.     Goto Help_Parse;
  1600.  
  1601. Help_Line3:
  1602.     MStr := Global_Str( prefix + 'IHELP3' );
  1603.     Goto Help_Parse;
  1604.  
  1605.  
  1606. Find_Down:
  1607.     jx := c_parm;
  1608.     jy := tl;
  1609.     while (jx < field_count) do
  1610.         ++jx;
  1611.         mstr := global_str(iparm + str(jx));
  1612.         jy := Parse_Int('/L=', mstr);
  1613.         if (jy - tl) > 1 then
  1614.             goto fd_exit;
  1615.         end;
  1616.         if jy > tl and
  1617.              (Parse_Int('/C=', mstr) = tc) then
  1618.             c_parm := jx;
  1619.             ret;
  1620.         end;
  1621.     end;
  1622.     fd_exit:
  1623.     ++c_parm
  1624.     ret;
  1625.  
  1626. Find_Up:
  1627.     jx := c_parm;
  1628.     jy := tl;
  1629.     while (jx > min_num) do
  1630.         --jx;
  1631.         mstr := global_str(iparm + str(jx));
  1632.         jy := Parse_Int('/L=', mstr);
  1633.         if (tl - jy) > 1 then
  1634.             goto fu_exit;
  1635.         end;
  1636.         if (jy < tl) and (Parse_Int('/C=', mstr) = tc) then
  1637.             c_parm := jx;
  1638.             ret;
  1639.         end;
  1640.     end;
  1641.     fu_exit:
  1642.     --c_parm
  1643.     ret;
  1644.  
  1645.     def_int( fjx );
  1646. find_mouse:
  1647.     mouse_result := FALSE;
  1648.     jx := min_num;
  1649.     while (jx <= field_count) do
  1650.         mstr := global_str(iparm + str(jx));
  1651.         TC := Parse_Int('/C=',Mstr);
  1652.         TL := Parse_Int('/L=',Mstr);
  1653.         TW := Parse_Int('/W=',Mstr);
  1654.         IF tw = 0 THEN
  1655.             tw := LENGTH( global_str( istr+str(jx)));
  1656.         END;
  1657.         Label_Str := Parse_Str('/T=',MStr);
  1658.         LL := svl( Label_Str );
  1659.     xx := x1 + tc + ll;
  1660.     tt := parse_int('/TP=', mstr );
  1661.     IF (tt = 3) OR (TT > 4) THEN
  1662.       ++xx;
  1663.     END;
  1664.  
  1665.         IF ((tl + y1) = Mou_Last_Y) AND
  1666.       (Mou_Last_X >= (xx)) AND
  1667.       (Mou_Last_X <= (xx + tw)) THEN
  1668.             IF c_parm <> jx THEN
  1669.                 fjx := jx;
  1670.                 call UnMark_Item;
  1671.                 c_parm := fjx;
  1672.                 Call Mark_Item;
  1673.             END;
  1674.             jx := field_count;
  1675.             mouse_result := true;
  1676.         end;
  1677.         ++jx;
  1678.     end;
  1679.     ret;
  1680.  
  1681. EXIT:
  1682.     If X1 <> 0 THEN
  1683.         Kill_Box;
  1684.     END;
  1685. EXIT2:
  1686.     Pop_Labels;
  1687.     GotoXY(Old_c,Old_l);
  1688.  
  1689.         {free up as much garbage as possible}
  1690.     if parse_int('/NC=', mparm_str) = 0 then
  1691.         Tc := 0;
  1692.         While (Tc < field_count) Do
  1693.             ++Tc;
  1694.             Set_Global_Str(iparm + Str(TC),'');
  1695.         END;
  1696.         Set_Global_Str(prefix + 'IHELP1','');
  1697.         Set_Global_Str(prefix + 'IHELP2','');
  1698.         Set_Global_Str(prefix + 'IHELP3','');
  1699.     end;
  1700.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  1701.     RM('CheckEvents /M=3/G=' + event_str + '/#=' + str(event_count));
  1702.     refresh := t_refresh;
  1703. END_MACRO;
  1704.  
  1705.  
  1706. $MACRO DVMENU FROM ALL;
  1707. {******************************************************************************
  1708.                                                              MULTI-EDIT MACRO
  1709.  
  1710. NAME:  DVMENU (Dynamic Vertical Menu)
  1711.  
  1712. DESCRIPTION:  This is a general purpose vertical menu generator that creates
  1713. a box just the right size to fit the menu, and returns both the number of the
  1714. menu element that was picked, and the string of the menu element in Return_Int
  1715. and Return_Str respectively.  The menu is scrollable if the menu is larger than
  1716. will fit on the screen.
  1717. You must initialize global variables with the menu strings.  If one global
  1718. will not hold the entire menu, use as many as you wish.  The format for the
  1719. global variable names is:
  1720.     Name1
  1721.     Name2
  1722.     Name3
  1723.     etc.
  1724. Where name is any name you wish, which is supplied to the program via a
  1725. parameter called Menu_Prefix.  The amount of globals is supplied via the /#=
  1726. parameter.
  1727. Although, for the sake of compatibility, the format of each menu string is
  1728. identical to that expected for V_MENU and H_MENU, the 2 character help strings
  1729. are not actually used.  Instead you must provide the 2 character help string
  1730. via the /H= parameter.
  1731.  
  1732. This menu does not have the "Press the highlighted character to select" feature,
  1733. however, there is an incremental search feature which, if an alphanumeric
  1734. character is pressed, it will invoke and all subsequent characters will be
  1735. appended to the search expression.  Pressing the backspace will right-truncate
  1736. the search expression.
  1737.  
  1738.                 Parameters expected:
  1739.                 /P=     Menu_Prefix   string   the "prefix" of the 3 global variables
  1740.                                                                             defining the 3 menu strings for the
  1741.                                                                             vertical menu
  1742.                 /H=     Help_Str      string   the 2 character help string for prompts
  1743.                 /T=     Title         string   the title of the box
  1744.                 /S=     Choice_Str    string   the string of the defualt selection
  1745.                 /SN=                  integer  instead of using /S= for default, use
  1746.                                                                              this.
  1747.                 /X=     Menu_X        integer  the upper left X coordinate of the box
  1748.                 /Y=     Menu_Y        integer  the upper left Y coordinate of the box
  1749.                 /B=     Make_Box      integer  1=create a box 0=don't
  1750.                 /K=     Box_Kill      integer  1=kill the box before exiting 0=don't
  1751.                 /O=     Menu_Modify   integer  1=display modify choice 0=don't
  1752.                 /C=     Menu_Create   integer  1=display create choice 0=don't
  1753.                 /CT=    Create_Title  string   If present, will replace the defalult
  1754.                                                                              title on the create box prompt.
  1755.                 /D=     Menu_Delete   integer  1=display delete choice 0=don't
  1756.                 /MH=                                                    Menu Height override
  1757.                 /#=     Menu_Index    integer  The number of globals used for menu
  1758.                 /W=     Max_Width         integer    The maximum allowable string length
  1759.                                                                             for when a user adds a menu item.
  1760.                 /F1 - 10=                                            Support for function key labels 1 - 10
  1761.              /PRE=                                 char     This one was created primarily for the
  1762.                                                                             macro EXTENS.  If present, and the user
  1763.                                                                             creates a new menu item, the item he
  1764.                                                                             enters MUST be preceeded by the defined
  1765.                                                                             character.  In EXTENS, the extension menu
  1766.                                                                             items must be preceeded by a period(.).
  1767.              /U=                   integer  1=Force upper case on menu item
  1768.                                                                             additions.  0= Normal.
  1769.              /EC=                  integer  1=exit this macro upon addition of a new
  1770.                                                                             menu item.  Primarily intended for
  1771.                                                                             situations where processing other than
  1772.                                                                             merely adding to the menu it'self is
  1773.                                                                             neccesary.
  1774.              /ED=                  integer  1=exit this macro upon deletion of a menu
  1775.                                                                             item. Primarily intended for situations
  1776.                                                                             where processing other than merely
  1777.                                                                             deleting from the menu it'self is
  1778.                                                                             neccesary.
  1779.              /ND=                  string   A series of strings, separated by spaces,
  1780.                                                                             that tell DVMENU to disallow deletion of
  1781.                                                                             the contained strings.  Only valid and
  1782.                                                                             neccesary if /D=1
  1783.              /NM=                  string   A series of strings, separated by spaces,
  1784.                                                                             that tell DVMENU to disallow modification
  1785.                                                                             of the contained strings.  Only valid and
  1786.                                                                             neccesary if /O=1
  1787.              /NR=                  integer    No rebuild.  If 1, then DVMENU will not
  1788.                                                                             alter the global menu strings in the event
  1789.                                                                             of a create or delete.
  1790.              /I=                                     string   A string expression to preceed the
  1791.                                                                             incremental search string.  Under normal
  1792.                                                                             circumstances, it should be % to match
  1793.                                                                             the beginning of line.
  1794.              /WIN=nn                                                The window # to use if we do NOT want
  1795.                                                                             a window created.
  1796.              /WW=nn           window width  Desired width only active when using
  1797.                                                                             /WIN.  If not present, /W will be used
  1798.                                                                             instead.
  1799.  
  1800.              /OCPG=                        One Choice Per Global -     When adding or deleting from
  1801.                                                                             a    menu, there will be only one menu
  1802.                                                                             choice per global string and the help
  1803.                                                                             index will not be    appended to each choice.
  1804.  
  1805.              /ROW=            Init_Row      This one is currently only used for KEYMAP.
  1806.                                                                             Used to pass a row number to highlite on
  1807.                                                                             recursive calls to DVMENU so that the menu
  1808.                                                                             doesn't shift positions.
  1809.  
  1810.              Returns                     Return_Int        0 = Escape was pressed.
  1811.                                                                             1 = Return was pressed.
  1812.                                                                             2 = A menu item was added(only if /EC=1).
  1813.                                                                             3 = A menu item was deleted(only if /ED=1).
  1814.                                                                             4 = Modify item was selected.
  1815.                                                                             5 = Add item was selected.
  1816.                                                  Return_Str        If Return_Int = 0, = /S=.
  1817.                                                                             If Return_Int = 1, = The selected item.
  1818.                                                                             If Return_Int = 2, = The added item.
  1819.                                                                             If Return_Int = 3, = The deleted item.
  1820.                                                                             If Return_Int = 4, = The selected item.
  1821.  
  1822.                              (C) Copyright 1989 by American Cybernetics, Inc.
  1823. ******************************************************************************}
  1824.     Def_Str(Menu_Prefix[19],Choice_Str[77],Temp_String,Help_Str[40],Create_Title[77], Event_Str[20]);
  1825.  
  1826.     Def_Int(Temp_Integer,jx,jy,Make_Box,Menu_X,Menu_Y,Choice_Int,Temp_Choice,
  1827.                     Active_Window,Menu_Window,Temp_Refresh,Temp_Ignore_Case,Temp_Messages,
  1828.                     Temp_Reg_Exp_Stat,Temp_Explosions,Menu_Index,Menu_Mode,Menu_Width,
  1829.                     Skip_Count,Temp_Insert_Mode,Menu_Changed,skip_win,temp_mode,
  1830.                     Extra_Index,OCPG,No_Choices,Ev_Count);
  1831.  
  1832.     Def_Char(Temp_Char);
  1833.  
  1834.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  1835.  
  1836.     Temp_Refresh := Refresh;
  1837.     Refresh := False;
  1838.  
  1839.     Push_Labels;
  1840.     Menu_Changed := False;
  1841.     No_Choices := False;
  1842.     Temp_Messages := Messages;
  1843.     Temp_Insert_Mode := Insert_Mode;
  1844.     Insert_Mode := True;
  1845.     Temp_Explosions := Explosions;
  1846.     Explosions := False;
  1847.     Menu_Prefix := Parse_Str('/P=',MParm_Str);
  1848.     Help_Str := Parse_Str('/H=',MParm_Str);
  1849.     Choice_Str := Parse_Str('/S=',MParm_Str);
  1850.     OCPG := Parse_Int('/OCPG=',MParm_Str);
  1851.     Menu_X := Parse_Int('/X=',MParm_Str);
  1852.     Menu_Y := Parse_Int('/Y=',MParm_Str);
  1853.     menu_width := Parse_Int('/WW=',MParm_Str);
  1854.     Make_Box := Parse_Int('/B=',MParm_Str);
  1855.     Active_Window := Cur_Window;
  1856.     Menu_Window := 0;
  1857.     temp_mode := mode;
  1858.     mode := edit;
  1859.     Temp_Ignore_Case := Ignore_Case;
  1860.     Ignore_Case := True;
  1861.     Temp_Reg_Exp_Stat := Reg_Exp_Stat;
  1862.     Reg_Exp_Stat := True;
  1863.     Menu_Index := Parse_Int('/#=',MParm_Str) + 1;
  1864.     IF (Menu_Index < 1) THEN
  1865.         Menu_Index := 4;
  1866.     END;
  1867.     Menu_Mode := 0;
  1868.  
  1869.     temp_integer := 0;
  1870.     while temp_integer < 10 do
  1871.         ++temp_integer;
  1872.         temp_string := parse_str('/F' + str(temp_integer) + '=', mparm_str);
  1873.         jx := temp_integer;
  1874.         if jx < 11 then
  1875.             if (jx = 1) and (temp_string = '') then
  1876.                 temp_string := 'Help';
  1877.             end;
  1878.             if temp_string <> '' then
  1879.                 flabel( temp_string,jx, -1);
  1880.             end;
  1881.         end;
  1882.     end;
  1883.  
  1884. {if a window is already defined then skip the build process}
  1885.     skip_win := false;
  1886.     if parse_int( '/WIN=', mparm_str) <> 0 then
  1887.         skip_win := true;
  1888.         menu_window := parse_int( '/WIN=', mparm_str);
  1889.         switch_window( menu_window );
  1890.         eof;
  1891.         if c_col <> 1 then
  1892.             down;
  1893.         end;
  1894.     else
  1895.         Switch_Window(Window_Count);
  1896.         Create_Window;
  1897.     end;
  1898.     window_attr := window_attr or $86;
  1899.     Menu_Window := Cur_Window;
  1900.     Extra_Index := 0;
  1901.     Temp_Integer := 0;
  1902.  
  1903. {create the additional menu choices as outlined in the passed parameter string}
  1904.     IF (Parse_Int('/C=',MParm_Str)) THEN
  1905.         ++ Extra_Index;
  1906.         Temp_Integer := 15;
  1907.     END;
  1908.     IF (Parse_Int('/D=',MParm_Str)) THEN
  1909.         ++ Extra_Index;
  1910.         Temp_Integer := 15;
  1911.     END;
  1912.     IF (Parse_Int('/O=',MParm_Str)) THEN
  1913.         ++ Extra_Index;
  1914.         IF (Temp_Integer < 9) THEN
  1915.             Temp_Integer := 9;
  1916.         END;
  1917.     END;
  1918.  
  1919.     IF (Extra_Index) THEN
  1920.         ++Extra_Index;
  1921.     END;
  1922.  
  1923. {set the minmum width according to the presence or absence of the "extras"}
  1924.     if (menu_width = 0) then
  1925.         IF (Extra_Index) THEN
  1926.             Menu_Width := Temp_Integer;
  1927.         ELSE
  1928.             Menu_Width := 7;
  1929.         END;
  1930.     end;
  1931. {If the width of the title is more than the current width of the menu, make it
  1932. bigger so it will fit}
  1933.     IF (Length(Parse_Str('/T=',MParm_Str)) > Menu_Width) THEN
  1934.         Menu_Width := Length(Parse_Str('/T=',MParm_Str));
  1935.     END;
  1936.     Temp_Integer := 1;
  1937.     Choice_Int := 1;
  1938.  
  1939.     Temp_Choice := Parse_Int('/SN=',MParm_Str);
  1940.     if skip_win then
  1941.         if (temp_choice = 0) and (choice_str <> '') then
  1942.             reg_exp_stat := false;
  1943.             tof;
  1944.             if search_fwd( choice_str , 0 ) then
  1945.                 temp_choice := c_line;
  1946.             end;
  1947.             reg_exp_stat := true;
  1948.             eof;
  1949.         end;
  1950.         goto skip_build;
  1951.     end;
  1952. {Determing how long the menu will be to determine box size}
  1953.     While (Temp_Integer < Menu_Index) Do
  1954.         Jx := 1;
  1955.         Temp_String := Global_Str(Menu_Prefix + Str(Temp_Integer));
  1956.  
  1957. BUILD_MENU:
  1958.         Jy := XPos('(',Temp_String,Jx);
  1959.  
  1960.         IF (Jy = 0) THEN
  1961.             Jy := Svl(Temp_String) + 1;
  1962.         END;
  1963.  
  1964.         If (Jy) Then
  1965. DOUBLE_PARENS:
  1966.             IF (XPos('((',Temp_String,Jy) = Jy) THEN
  1967.                 Temp_String := Str_Del(Temp_String,Jy,1);
  1968.                 Jy := XPos('(',Temp_String,JY + 1);
  1969.                 IF (Jy = 0) THEN
  1970.                     Jy := Svl(Temp_String) + 1;
  1971.                 END;
  1972.                 Goto DOUBLE_PARENS;
  1973.             END;
  1974.             Put_Line(Copy(Temp_String,Jx,Jy - Jx));
  1975.             IF (Get_Line = Choice_Str) THEN
  1976.                 Temp_Choice := C_Line;
  1977.             END;
  1978.             IF (Get_Line <> '') THEN
  1979.                 Down;
  1980.             END;
  1981.             IF (((Jy - Jx) > Menu_Width) and (Parse_Int('/WW=',MParm_Str) = 0)) THEN
  1982.                 Menu_Width := Jy - Jx;
  1983.             END;
  1984. {Move pointer beyond closing paren}
  1985.             Jx := XPos(')',Temp_String,Jy + 1);
  1986.             IF (Jx < SVL(Temp_String) and (Jx > 0)) THEN
  1987.                 ++Jx
  1988.                 Goto BUILD_MENU;
  1989.             END;
  1990.         End;
  1991.  
  1992.         ++Temp_Integer;
  1993.     End;
  1994.  
  1995. skip_build:
  1996.     if (menu_width + menu_x) > (screen_width - 3) then
  1997.         menu_width := (screen_width - 3 - menu_x);
  1998.     end;
  1999.     eof;
  2000. skiploop:
  2001.     eol;
  2002.     if (c_col = 1) and (c_line > 1) then
  2003.         up;
  2004.         goto skiploop;
  2005.     end;
  2006.     File_Changed := False;
  2007.  
  2008. REDO_MENU:
  2009.     Tof;
  2010.     IF (At_Eof) THEN
  2011. {If this menu is empty, alert the user.}
  2012.         No_Choices := True;
  2013.         IF (Menu_Width < 23) THEN
  2014.             Menu_Width := 23;
  2015.         END;
  2016.         Put_Line('No choices in this menu');
  2017.     END;
  2018.  
  2019. CHOICE_LOOP:
  2020.     Ev_Count := 2;
  2021.     event_str :=  '@EV' + Str(Global_Int( 'MENU_LEVEL' )) + '#';
  2022.     Set_Global_Str(Event_Str + '1', '/T=Select/K1=13/K2=28/R=1/LL=1');
  2023.     Set_Global_Str(Event_Str + '2', '/T=Cancel/K1=27/K2=1/R=0/LL=1');
  2024.  
  2025.     IF (Extra_Index > 1) THEN
  2026.         ++Ev_Count;
  2027.         Set_Global_Str(Event_Str  + Str(Ev_Count), '/T=Create/K1=0/K2=82/R=2');
  2028.     END;
  2029.  
  2030.     IF (Extra_Index > 2) THEN
  2031.         ++Ev_Count;
  2032.         Set_Global_Str(Event_Str  + Str(Ev_Count), '/T=Delete/K1=0/K2=83/R=3');
  2033.     END;
  2034.  
  2035.     IF (Extra_Index > 3) THEN
  2036.         ++Ev_Count;
  2037.         Set_Global_Str(Event_Str  + Str(Ev_Count), '/T=Modify/K1=0/K2=61/R=4');
  2038.     END;
  2039.  
  2040.     ++Ev_Count;
  2041.     Set_Global_Str(Event_Str  + Str(Ev_Count), '/K1=0/K2=75/R=100/ND=1');
  2042.     ++Ev_Count;
  2043.     Set_Global_Str(Event_Str  + Str(Ev_Count), '/K1=0/K2=77/R=100/ND=1');
  2044.     IF temp_choice = 0 THEN
  2045.         temp_choice := 1;
  2046.     END;
  2047.     RM('WMENU /DBL=1/X=' + Str(Menu_X) + '/Y=' + Str(Menu_Y) + '/S=' +
  2048.         Str(Temp_Choice) + '/MH=' + parse_str('/MH=',mparm_str) +
  2049.         '/NK=1/OR=5/EV=' + event_str + '/EV#=' + Str(Ev_Count) + '/T=' +
  2050.         Parse_Str('/T=',MParm_Str) + '/W=' + Str(Menu_Width) + '/SP=' +
  2051.         Parse_Str('/I=',MParm_Str) + '/NB=' + Str(Not(Make_Box)));
  2052. {
  2053. Make_Message('[' + Str(Return_Int) + ']');
  2054. Read_Key;
  2055. }
  2056.     if ((Return_Int = 0) or (Return_Int = 1)) then
  2057.         Set_Global_Int('DVINT',C_Line);
  2058.         IF (Return_Int = 1) THEN
  2059.             Return_Str := Get_Line;
  2060.         END;
  2061.         Refresh := True;
  2062.         IF ((Return_Int = 0) and (Menu_Mode = 0)) THEN
  2063.             Return_Str := Choice_Str;
  2064.             Return_Int := 0;
  2065.             Goto SPECIAL_EXIT;
  2066.         END;
  2067.         IF (Menu_Mode = 0) THEN
  2068.             Goto CHOICE_MADE;
  2069.         END;
  2070.         Menu_Mode := 0;
  2071.     Goto CHOICE_MADE;
  2072.     end;
  2073.  
  2074.     IF (Return_Int = 2) THEN
  2075.         Call ADD_TO_MENU;
  2076.         IF (Return_Int) THEN
  2077.             Menu_Mode := 1;
  2078.             IF (Parse_Int('/EC=',MParm_Str) = 1) THEN
  2079.                 Goto CHOICE_MADE;
  2080.             END;
  2081.             refresh := false;
  2082.             Kill_Box;
  2083.             Goto REDO_MENU;
  2084.         ELSE
  2085.             Goto CHOICE_LOOP;
  2086.         END;
  2087.     END;
  2088.  
  2089.     IF (Return_Int = 3) THEN
  2090.         Menu_Mode := 2;
  2091.         Refresh := False;
  2092.         Call CHECK_DELETE;
  2093.         IF (Return_Int) THEN
  2094.             Goto SKIP_DELETE;
  2095.         END;
  2096.         RM('VERIFY /T=Are you sure you want to delete this menu item?/C=1/L=' +
  2097.         Str(Menu_Y + Extra_Index + 1));
  2098.         IF (Return_Int = 0) THEN
  2099. SKIP_DELETE:
  2100.             Menu_Mode := 0;
  2101.             Goto CHOICE_LOOP;
  2102.         END;
  2103.         Return_Str := Get_Line;
  2104.         Set_Global_Int('DVINT',C_Line);
  2105.         Del_Line;
  2106.         Up;
  2107.         Menu_Changed := True;
  2108.         IF (Parse_Int('/ED=',MParm_Str) = 1) THEN
  2109.             Goto CHOICE_DELETED;
  2110.         END;
  2111.     {If we deleted the default menu choice, we must change it to something else
  2112.     just in case the user presses <ESC>.  The obvious choice is item above}
  2113.         IF (Return_Str = Choice_Str) THEN
  2114.             Choice_Str := Get_Line;
  2115.         END;
  2116.         Kill_Box;
  2117.         Goto REDO_MENU;
  2118.     END;
  2119.  
  2120.     IF (Return_Int = 4) THEN
  2121.         Call CHECK_MODIFY;
  2122.         IF (Return_Int) THEN
  2123.             Goto CHOICE_LOOP;
  2124.         END;
  2125.         Menu_Mode := 3;
  2126.         Return_Str := Get_Line;
  2127.         Goto CHOICE_MADE;
  2128.     END;
  2129.  
  2130.     GOTO CHOICE_LOOP;
  2131.  
  2132. CHOICE_MADE:
  2133. {Put the menu choice integer into a global, so the calling macro can retrieve
  2134. it}
  2135.     Set_Global_Int('DVINT',C_Line);
  2136. CHOICE_DELETED:
  2137.     Refresh := False;
  2138. {This is a very special case for the macro EXTENS}
  2139.     Jx := C_Line;
  2140.     Jy := C_Row;
  2141.     IF (C_Line > 1) THEN
  2142.         Up;
  2143.         Call SKIP_SEEK_UP;
  2144.         Goto GET_BACK;
  2145.     ELSE
  2146. GET_BACK:
  2147.         Set_Global_Str('DVSTR',Get_Line);
  2148.         WHILE (C_Row < Jy) DO
  2149.             Down;
  2150.         END;
  2151.         Goto_Line(Jx);
  2152.     END;
  2153.     Return_Int := Menu_Mode + 1;
  2154. SPECIAL_EXIT:
  2155. ERROR_EXIT:
  2156.     Refresh := False;
  2157.     if skip_win = false then
  2158.         IF ((Parse_Int('/NR=',MParm_Str) = 0) and (Menu_Changed = True)) THEN
  2159.             Call REBUILD_MENU;
  2160.         END;
  2161.         Delete_Window;
  2162.     end;
  2163.     Switch_Window(Active_Window);
  2164.     GOTO EXIT;
  2165.  
  2166. {********************************** SUBROUTINES ******************************}
  2167.  
  2168. SKIP_SEEK_UP:
  2169.     Skip_Count := 1;
  2170.     IF (XPos('|254',Get_Line,1) = Length(Get_Line)) THEN
  2171.         IF (C_Line > 1) THEN
  2172.             ++Skip_Count;
  2173.             Up;
  2174.         ELSE
  2175.             WHILE (Skip_Count) DO
  2176.                 Down;
  2177.                 --Skip_Count;
  2178.             END;
  2179.             Ret;
  2180.         END;
  2181.         Goto SKIP_SEEK_UP;
  2182.     END;
  2183.     RET;
  2184.  
  2185. ADD_TO_MENU:
  2186. {Querybox is a general purpose "boxed" prompt.}
  2187.         Create_Title := Parse_Str('/CT=',MParm_Str);
  2188.         IF (Create_Title = '') THEN
  2189.             Create_Title := 'CREATE NEW MENU ITEM';
  2190.         END;
  2191.         Return_Str := '';
  2192.         RM('QUERYBOX /H=IN/C=' + Str(Menu_X) + '/L=' + Str(Menu_Y + Extra_Index + 1) +
  2193.         '/W=' + str( Parse_int('/W=',MParm_Str) - length(Parse_Str('/PRE=',MParm_Str)))
  2194.          + '/T=' + Create_Title + '/P='
  2195.          + Parse_Str('/PRE=',MParm_Str));
  2196.  
  2197.         IF (Return_Int = True) and (Return_Str <> '') THEN
  2198.             return_str := Parse_Str('/PRE=',MParm_Str) + return_str;
  2199.             IF (Parse_Int('/U=',MParm_Str) = 1) THEN
  2200.                 Return_Str := Caps(Return_Str);
  2201.             END;
  2202. {First, see if the new addition already exists, if so, prevent redundant
  2203. entries by assuming the user merely wants to select this menu choice}
  2204.             Temp_Integer := C_Line;
  2205.             Refresh := False;
  2206.             Tof;
  2207.             IF (Search_Fwd('%' + Return_Str + '$',0)) THEN
  2208.                 Return_Int := 0;
  2209.                 RET;
  2210.             ELSE
  2211.                 Goto_Line(Temp_Integer);
  2212.             END;
  2213.             IF (No_Choices = False) THEN
  2214.                 Eol;
  2215.                 Cr;
  2216.                 Goto_Col(1);
  2217.             END;
  2218.             Put_Line(Return_Str);
  2219.             Menu_Changed := True;
  2220.             No_Choices := False;
  2221.         ELSE
  2222.             Return_Int := 0;
  2223.  
  2224.         END;
  2225.         RET;
  2226.  
  2227. REBUILD_MENU:
  2228.     Temp_String := Return_Str;
  2229.     Refresh := False;
  2230.     Tof;
  2231.     Menu_Index := 1;
  2232.     Set_Global_Str(Menu_Prefix + '1','');
  2233.  
  2234.     WHILE (Not(At_Eof)) DO
  2235.         RM('DBLPAREN ' + Get_Line);
  2236.         IF (OCPG) THEN
  2237.             Set_Global_Str(Menu_Prefix + Str(Menu_Index),Return_Str);
  2238.             ++Menu_Index;
  2239.         ELSE
  2240.             IF ((Length(Global_Str(Menu_Prefix + Str(Menu_Index))) + Length(Return_Str))
  2241.                 > 196) THEN
  2242.                 ++ Menu_Index;
  2243.                 Set_Global_Str(Menu_Prefix + Str(Menu_Index),'');
  2244.             END;
  2245.             Set_Global_Str(Menu_Prefix + Str(Menu_Index),Global_Str(Menu_Prefix + Str(Menu_Index)) + Return_Str + '(' + Help_Str + ')');
  2246.         END;
  2247.         Down;
  2248.     END;
  2249.     Temp_Integer := Menu_Index;
  2250. {If there are globals beyond the current index, deallocate them}
  2251.     WHILE (Temp_Integer < Parse_Int('/#=',MParm_Str)) DO
  2252.         ++Temp_Integer;
  2253.         Set_Global_Str(Menu_Prefix + Str(Temp_Integer),'');
  2254.     END;
  2255.     ++Menu_Index;
  2256.     Return_Str := Temp_String;
  2257.     RET;
  2258.  
  2259. CHECK_DELETE:
  2260.     Return_Int := 0;
  2261.     IF (Parse_Str('/ND=',MParm_Str) <> '') THEN
  2262.         IF (XPos( ' ' + Get_Line + ' ',' ' + Parse_Str('/ND=',MParm_Str) + ' ',1)) THEN
  2263.             RM('MEERROR^Beeps /C=1');
  2264.             Return_Int := 1;
  2265.         END;
  2266.     END;
  2267.     RET;
  2268.  
  2269. CHECK_MODIFY:
  2270.     Return_Int := 0;
  2271.     IF (Parse_Str('/NM=',MParm_Str) <> '') THEN
  2272.         IF (XPos(Get_Line,Parse_Str('/NM=',MParm_Str),1)) THEN
  2273.             RM('MEERROR^Beeps /C=1');
  2274.             Return_Int := 1;
  2275.         END;
  2276.     END;
  2277.     RET;
  2278. {*****************************************************************************}
  2279.  
  2280. EXIT:
  2281.     If ((Make_Box > 0) and (Parse_Int('/K=',MParm_Str) > 0)) Then
  2282.         Kill_Box;
  2283.     End;
  2284.     mode := temp_mode;
  2285.     Refresh := Temp_Refresh;
  2286.     Ignore_Case := Temp_Ignore_Case;
  2287.     Reg_Exp_Stat := Temp_Reg_Exp_Stat;
  2288.     Explosions := Temp_Explosions;
  2289.     Insert_Mode := Temp_Insert_Mode;
  2290.     Messages := Temp_Messages;
  2291.     pop_labels;
  2292.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  2293. {
  2294. RM('MEERROR^Beeps /C=1');
  2295. Make_Message('[' + Str(Global_Int('DVINT')) + '][' + Return_Str + ']');
  2296. Read_Key;
  2297. }
  2298. END_MACRO;
  2299.  
  2300. $MACRO SPECCHAR FROM ALL;
  2301. {******************************************************************************
  2302.                                                              MULTI-EDIT MACRO
  2303.  
  2304. NAME:  SPECCHAR
  2305.  
  2306. DESCRIPTION:  This is a general purpose string manipulator that changes
  2307. certain "unprintable" characters to the Multi-Edit macro language ASCII
  2308. Character representation for the purpose of displaying them in prompts.  The
  2309. string is passed to this macro via the standard ME parameter passing
  2310. convention, and the result is returned in Return_Str
  2311.  
  2312.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2313. ******************************************************************************}
  2314.     Def_Str(TStr, TChars[40]);
  2315.     Def_Char(TChar);
  2316.     Def_Int(JX,Jy);
  2317.  
  2318.     Tchars := '|26|0|9|255|13|27';
  2319.     TStr := MParm_Str;
  2320.  
  2321.     Jy := 1;
  2322.     While (Jy < 7) Do
  2323.         jx := 1;
  2324.         While (Jx > 0) Do
  2325.             jx := XPOS(Copy(TChars,Jy,1),TStr,jx);
  2326.             IF jx <> 0 THEN
  2327.                 TStr := Str_Del(TStr,jx,1);
  2328.                 TStr := Str_Ins('||' + Str(Ascii(Copy(TChars,Jy,1))),TStr,jx);
  2329.                 jx := jx + 3 + (Jy = 4) - (Jy = 2);
  2330. {Special instance of numeric characters following altered string}
  2331. SPECIAL_CASE:
  2332.                 IF (Length(Tstr) >= Jx) THEN
  2333.                     TChar := Copy(TStr,Jx,1);
  2334.                     IF (XPos(TChar,'0123456789',1)) THEN
  2335.                         TStr := Str_Del(TStr,jx,1);
  2336.                         TStr := Str_Ins('||' + Str(Ascii(Tchar)),TStr,Jx);
  2337.                         Jx := Jx + 3;
  2338.                         Goto SPECIAL_CASE;
  2339.                     END;
  2340.                 END;
  2341.             END;
  2342.         End;
  2343.         ++Jy;
  2344.     End;
  2345.     Return_Str := Tstr;
  2346. END_MACRO;
  2347.  
  2348. $MACRO VALCHAR FROM ALL;
  2349. {******************************************************************************
  2350.                                                              MULTI-EDIT MACRO
  2351.  
  2352. NAME:  VALCHAR
  2353.  
  2354. DESCRIPTION:  This is a general purpose string manipulator that changes
  2355. any occurance of the '|' character, indicating the presence of a numeric
  2356. representation of an ASCII character and converting it to that character.
  2357. The string is passed to this macro via the standard ME parameter passing
  2358. convention, and the result is returned in Return_Str
  2359.  
  2360.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2361. ******************************************************************************}
  2362.     Def_Str(Tstr,Tstr2[60]);
  2363.     Def_Int(JX,Jy);
  2364.     Def_Char( TChar );
  2365.     TStr := MParm_Str;
  2366.     {Get bar characters}
  2367.     JX := 1;
  2368. CHECKQ2:
  2369.     jx := XPOS('||',TStr,jx);
  2370.     IF jx <> 0 THEN
  2371.         IF (JX < Length(TStr)) and
  2372.              (XPOS(Copy(TStr,jx+1,1),'0123456789',1) <> 0) THEN
  2373.             jy := jx + 1;
  2374.             TStr2 := '';
  2375. Next_Char:
  2376.             TChar := Copy(Tstr,jy,1);
  2377.             If XPOS(TChar,'0123456789',1) THEN
  2378.                 TStr2 := TStr2 + TChar;
  2379.                 ++jy;
  2380.                 Goto Next_Char;
  2381.             END;
  2382.             If VAL(jy,Tstr2) = 0 THEN
  2383.                 TStr := Str_Del(TStr,jx,Length(Tstr2) + 1);
  2384.                 TStr := Str_Ins(Char(Jy),TStr,jx);
  2385.             END;
  2386.             ++jx;
  2387.         ELSE
  2388.             jx := jx + 2;
  2389.         END;
  2390.         goto CHECKQ2;
  2391.     END;
  2392.     Return_Str := TStr;
  2393. END_MACRO;
  2394.  
  2395. $MACRO STRSRC FROM ALL;
  2396. {******************************************************************************
  2397.                                                              MULTI-EDIT MACRO
  2398.  
  2399. NAME:  STRSRC
  2400.  
  2401. DESCRIPTION:  This is a general purpose string manipulator that changes
  2402. any occurance of a "|" or a "'" character, which was entered by a user in a
  2403. prompt, so that the part of the setup that saves the settings by generating
  2404. macro source code will be able to generate string literals properly.
  2405. The string is passed to this macro via the standard ME parameter passing
  2406. convention, and the result is returned in Return_Str
  2407.  
  2408.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2409. ******************************************************************************}
  2410.     Def_Str(Tstr);
  2411.     Def_Int(JX,Jy);
  2412.     TStr := MParm_Str;
  2413.     jx := 1;
  2414. CHECKQ:
  2415.     jx := XPOS('''',TStr,jx);
  2416.     IF jx <> 0 THEN
  2417.         TStr := Str_Ins('''',TStr,jx);
  2418.         jx := jx + 2;
  2419.         goto CHECKQ;
  2420.     END;
  2421.  
  2422.     {Create double bars}
  2423.     jx := 1;
  2424. CHECKQ2:
  2425.     jx := XPOS('||',TStr,jx);
  2426.     IF jx <> 0 THEN
  2427.         IF (JX = Length(TStr)) or
  2428.              (XPOS(Copy(TStr,jx+1,1),'0123456789|',1) = 0) THEN
  2429.             TStr := Str_Ins('||',TStr,jx);
  2430.         END;
  2431.         jx := jx + 2;
  2432.         goto CHECKQ2;
  2433.     END;
  2434.     Return_Str := Tstr;
  2435.     RM('SPECCHAR '+ Return_Str);
  2436. END_MACRO;
  2437.  
  2438. $MACRO DBLPAREN FROM ALL;
  2439. {******************************************************************************
  2440.                                                              MULTI-EDIT MACRO
  2441.  
  2442. NAME:  DBLPAREN
  2443.  
  2444. DESCRIPTION:  This is a general purpose string manipulator that changes
  2445. any occurance of a "(" to "((", which was entered by a user in a prompt, so
  2446. that it may be used to create a menu without screwing up.
  2447. The string is passed to this macro via the standard ME parameter passing
  2448. convention, and the result is returned in Return_Str
  2449.  
  2450.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2451. ******************************************************************************}
  2452.     Def_Str(Tstr);
  2453.     Def_Int(JX);
  2454.     TStr := MParm_Str;
  2455.     jx := 1;
  2456. CHECKQ:
  2457.     jx := XPOS('(',TStr,jx);
  2458.     IF jx <> 0 THEN
  2459.         TStr := Str_Ins('(',TStr,jx);
  2460.         jx := jx + 2;
  2461.         goto CHECKQ;
  2462.     END;
  2463.     Return_Str := Tstr;
  2464. END_MACRO;
  2465.  
  2466. $MACRO CHNGPARM;
  2467. {******************************************************************************
  2468.                                                              MULTI-EDIT MACRO
  2469.  
  2470.  
  2471. DESCRIPTION:
  2472. This macro is designed to change any "/X=" type parameter in any global string.
  2473. It should work for any parameter delimiters.  If the parameter does not exist
  2474. in the string, it will add it to the end of the string.
  2475.  
  2476. /G=                        The global string name
  2477. Return_Str        The parameter syntax(Because this is a "/x=" type of parameter,
  2478. it cannot be a part of MParm_Str(it would be impossible to parse out unless we
  2479. used different parameter delimiters, which would be inconsistent)
  2480. /P=                        The new parameter
  2481.  
  2482. Example:
  2483.  
  2484.     Set_Global_Str('TEST','/X=1/Y=2/Z=3');
  2485.     Return_Str := '/Y=';
  2486.     RM('CHNGPARM /G=TEST/P=10');
  2487.  
  2488. Global_Str('TEST') will now be: '/X=1/Y=10/Z=3'
  2489.  
  2490. As this macro is not particularly efficient, it should only be used in cases
  2491. of extremely long strings of parameters where only one parameter is being
  2492. changed and complete rebuilding of the string would take longer.
  2493.  
  2494.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2495. ******************************************************************************}
  2496.  
  2497.     Return_Int := XPos(Return_Str,Global_Str(Parse_Str('/G=',MParm_Str)),1);
  2498.     IF (Return_Int = 0) THEN
  2499.         Return_Int := Length(Global_Str(Parse_Str('/G=',MParm_Str))) + 1;
  2500.         Set_Global_Str(Parse_Str('/G=',MParm_Str),
  2501.             Global_Str(Parse_Str('/G=',MParm_Str)) + Return_Str);
  2502.     END;
  2503.     Set_Global_Str(Parse_Str('/G=',MParm_Str),Copy(Global_Str(Parse_Str('/G=',
  2504.         MParm_Str)),1,Length(Return_Str) + Return_Int - 1) + Parse_Str('/P=',
  2505.         MParm_Str) + Copy(Global_Str(Parse_Str('/G=',MParm_Str)),Return_Int +
  2506.         Length(Parse_Str(Return_Str,Global_Str(Parse_Str('/G=',MParm_Str)))) +
  2507.         Length(Return_Str),254));
  2508.  
  2509. END_MACRO;
  2510.  
  2511. $MACRO USERSTR FROM ALL;
  2512. {******************************************************************************
  2513.                                                              MULTI-EDIT MACRO
  2514.  
  2515. NAME:  USERSTR
  2516.  
  2517. DESCRIPTION:  This macro creates a scrollable prompt.  Functionally equivalent
  2518. to the macro function String_In, except allows scrolling.  Allows user inputs
  2519. of up to 254 characters.
  2520.  
  2521. System variables and parameters:
  2522.  
  2523. Return_Str -  Returns user input if enter is pressed, or default if ESC is
  2524.                             pressed.
  2525. Return_Int -  Returns 1 if enter is pressed, 0 if ESC is pressed, -1 if
  2526.                             a enabled function key was press.
  2527.  
  2528. Names of parameters are similar to arguments for String_In.
  2529. /P=   Prompt string.  If omitted, same as above.
  2530. /F1 - F12 =str  Enables F2.  Assigns str as the label;  Now works for F1 - F12
  2531. /L=   Length.  Maximum length of input.
  2532. /X=   Col.  Left Column of prompt.
  2533. /Y=   Row.  Row of Prompt.
  2534. /H=   Help string.  2 character index for help system.
  2535. /W=   Input Width.  Width of visable portion of input.
  2536. /B=   1 = Create Box;
  2537. /BL=    Box Label;
  2538. /NK=    1 = don't kill box when done.
  2539. /A=        1 = Exit on use of up or down arrow keys with return_int = 1 and
  2540.             push the key back on the keyboard stack.
  2541. /HISTORY=    Name of history list globals
  2542. /EV=    Name of mouse event globals
  2543. /EV#=    Number of mouse event globals
  2544.  
  2545.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2546. ******************************************************************************}
  2547.  
  2548.     Def_Int(Active_Window,Temp_Refresh,Input_Width,Len,Col,Row, t_mode, t_display_tabs,
  2549.                     Temp_Message_Row, t_undo_stat, first_time, t_trunc,t_tab_expand, history_stat,
  2550.                     jx, Temp_Integer, Box, box_width, ps_width, T_EOL_CHAR, arrow_stat,
  2551.                     texp, event_count,Center_Offset);
  2552.  
  2553.     Def_Str( fstr[100], t_page_str[20], history_str[20], event_str[20] );
  2554.  
  2555. {We are using a window to create the input field, therefore, we have to turn
  2556. all status lines off in order to take advantage of the windows natural
  2557. refreshing, yet not screw up the display}
  2558.  
  2559.     Temp_Refresh := Refresh;
  2560.     Refresh := False;
  2561.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  2562.     texp := explosions;
  2563.     explosions := false;
  2564.     t_mode := mode;
  2565.     t_tab_expand := tab_expand;
  2566.     T_trunc := truncate_spaces;
  2567.     T_Undo_Stat := Undo_Stat;
  2568.     t_eol_char := eol_char;
  2569.     t_page_str := page_str;
  2570.     t_display_tabs := display_tabs;
  2571.     eol_char := 177;
  2572.     Temp_Message_Row := Message_Row;
  2573.  
  2574.  
  2575.     Push_Labels;
  2576.  
  2577.     IF (Mparm_Str = '') THEN
  2578.         RM('MEERROR^Beeps /C=1');
  2579.         Goto EXIT;
  2580.     END;
  2581.  
  2582.  
  2583.     event_str :=  '@EV' + Str(Global_Int( 'MENU_LEVEL' )) + '#';
  2584.     event_count := 0;
  2585.     display_tabs := true;
  2586.     tab_expand := true;
  2587.     truncate_spaces := false;
  2588.     Undo_Stat := false;
  2589.     first_time := true;
  2590.     page_str := '';
  2591.     temp_integer := 0;
  2592.     history_stat := 0;
  2593.  
  2594.     history_str := parse_str('/HISTORY=', mparm_str);
  2595.     if history_str <> '' then
  2596.         history_stat := 1;
  2597.         flabel( 'List', 4, -1 );
  2598.     end;
  2599.     flabel( 'Edit', 3, -1 );
  2600.     while temp_integer < 10 do
  2601.         ++temp_integer;
  2602.         fstr := parse_str('/F' + str(temp_integer) + '=', mparm_str);
  2603.         jx := temp_integer;
  2604.         if jx < 11 then
  2605.             if (jx = 1) and (fstr = '') then
  2606.                 fstr := 'Help';
  2607.             end;
  2608.             if fstr <> '' then
  2609.                 flabel( fstr,jx, -1);
  2610.             end;
  2611.         end;
  2612.     end;
  2613.  
  2614.  
  2615.     Message_Row := 0;
  2616.     Col := Parse_Int('/X=',MParm_Str){ + Length(Parse_Str('/P=',MParm_Str))};
  2617.     if col <= 0 then
  2618.         col := 2;
  2619.     end;
  2620.     Row := Parse_Int('/Y=',MParm_Str);
  2621.     if row <= 0 then
  2622.         row := 3;
  2623.     end;
  2624.     Len := Parse_Int('/L=',MParm_Str);
  2625.     Box := (Parse_Int('/B=',MParm_Str) <> 0);
  2626.     arrow_stat := parse_int( '/A=', mparm_str );
  2627.  
  2628.     Input_Width := Parse_Int('/W=',MParm_Str);
  2629.  
  2630.     IF (row + (box * 3)) >= screen_length THEN
  2631.         row := screen_length - (box * 3) - 1;
  2632.     END;
  2633.  
  2634.     if len = 0 then
  2635.         len := input_width;
  2636.     end;
  2637.     IF (Input_Width > Len) THEN
  2638.         Input_Width := Len;
  2639.     END;
  2640.  
  2641.     ps_width := Length(Parse_Str('/P=',MParm_Str));
  2642. {If the Left X coordinate is too far to the right to accommodate the prompt and
  2643. data field, move it over to the left}
  2644.     if (col + ps_width + input_width) > screen_width then
  2645.         Col := (screen_width - ps_width - Input_Width - 2);
  2646.     end;
  2647.     IF (Col < 1) THEN
  2648.         Col := 1;
  2649.     END;
  2650.  
  2651. {If it still won't fit, shorten the visable field width}
  2652.     if (col + ps_width + input_width) > screen_width then
  2653.         input_width := (screen_width - ps_width - col - 2);
  2654.     end;
  2655.  
  2656.     set_virtual_display;
  2657.     if box then
  2658.         box_width := ps_width + input_width + 3;
  2659.         if box_width < length(parse_str('/BL=',MParm_Str)) then
  2660.             box_width := length(parse_str('/BL=', mparm_str));
  2661.         end;
  2662.         if box_width < 25 THEN
  2663.             box_width := 25;
  2664.         END;
  2665.         put_box(col, row, col + box_width, row + 3, 0, m_b_color, parse_str('/BL=', mparm_str),
  2666.                         true);
  2667.         IF Parse_Int('/EV#=', mparm_str) = 0 THEN
  2668.             event_count := 2;
  2669.             temp_integer := 0;
  2670.             Set_Global_Str(event_str + '1',
  2671.                     '/T=OK/KC=<ENTER>/W=9/K1=13/K2=28/R=1');
  2672.             Set_Global_Str(event_str + '2',
  2673.                     '/T=Cancel/KC=<ESC>/W=11/K1=27/K2=1/R=0');
  2674.         END;
  2675.     end;
  2676.  
  2677.     IF Parse_Int('/EV#=', mparm_str) <> 0 THEN
  2678.         event_count := Parse_Int('/EV#=', mparm_str);
  2679.         event_str := Parse_Str('/EV=', mparm_str);
  2680.     END;
  2681.     RM('CheckEvents /M=4/G=' + event_str + '/#=' + str(event_count) + '/X=' + str(col) + '/Y=' + str(row + 2) + '/W=' + str( box_width - 1));
  2682.     RM('CheckEvents /M=2/G=' + event_str + '/#=' + str(event_count));
  2683.  
  2684.     Set_Global_Str('@UIDEFAULT@', return_str );
  2685.     Active_Window := Window_Id;
  2686. {Create the window for user input}
  2687.     switch_window(window_count);
  2688.     Create_Window;
  2689.     t_color := m_h_color;
  2690.     c_color := m_h_color;
  2691.     eof_color := m_h_color and $F0;
  2692.  
  2693.     Window_Attr := $86;
  2694. {
  2695. This is some stuff I'm playing with to try create automatic centering of the
  2696. prompt inside the box.
  2697. Write('[' + Str(input_width) + '][' + Str(Box_width) + ']',2,2,0,M_T_Color);
  2698. Read_Key;
  2699.     Center_Offset := 0;
  2700.  
  2701.     IF (Box) THEN
  2702.         IF (Parse_Int('',)) THEN
  2703.  
  2704.         END;
  2705.         IF (Box_Width > (Input_Width + 3)) THEN
  2706.             Center_Offset := (Box_Width - (Input_Width + 3)) / 2;
  2707.         END;
  2708.     END;
  2709.     Size_Window(Col - 1 + ps_width + box + Center_Offset,Row - 1 + box,Col + ps_width + Input_Width + Box + Center_Offset,Row + 1 + box);
  2710. }
  2711.     Size_Window(Col - 1 + ps_width + box,Row - 1 + box,Col + ps_width + Input_Width + Box,Row + 1 + box);
  2712.  
  2713.     Put_Line( return_str );
  2714.     mode := edit;
  2715.     Refresh := True;
  2716.     Redraw;
  2717.     IF (Parse_Str
  2718.         ('/P=',MParm_Str) <> '') THEN
  2719.         Write(Parse_Str('/P=',MParm_Str),Col + box, Row + box, 0,m_t_color);
  2720.     END;
  2721.  
  2722.     update_virtual_display;
  2723.     reset_virtual_display;
  2724.  
  2725.     Goto Read_Key_Loop2;
  2726. READ_KEY_LOOP:
  2727.  
  2728.     first_time := false;
  2729.  
  2730. READ_KEY_LOOP2:
  2731.     Read_Key;
  2732.     jx := INQ_KEY( key1, key2, 5, fstr );
  2733.     if jx = 1 then
  2734.         RM(fstr);
  2735.         goto read_key_loop2;
  2736.     end;
  2737.  
  2738. {We will allow entry of the escape character via ALT keypad which returns key2
  2739. as 0, but catch pressing the escape key as a user abort}
  2740.     IF ((Key1 = 13) and (Key2 <> 0) and (key2 <> 56)) then {13/0 on XT for ALT13}
  2741. CR_EXIT:                                                 {13/56 on AT for ALT13}
  2742.         if history_stat then
  2743.             call add_to_history;
  2744.         end;
  2745.         Return_Int := 1;
  2746.         Goto EXIT;
  2747.     end;
  2748.     IF ((Key1 = 27) and (Key2 <> 0) and (key2 <> 56)) THEN
  2749. ESC_EXIT:
  2750.         Return_Int := 0;
  2751.         Goto EXIT;
  2752.     END;
  2753.     If (Key1 = 8) and (key2 = 14 ) Then
  2754.         if first_time then
  2755.             put_line('');
  2756.             redraw;
  2757.         else
  2758.             IF ((C_Col = Len) and (Not(At_Eol))) THEN
  2759.                 Del_Char;
  2760.             ELSE
  2761.                 Back_Space;
  2762.             END;
  2763.         end;
  2764.         Goto READ_KEY_LOOP;
  2765.     End;
  2766.  
  2767.     If (Key1 = 0) Then
  2768.         IF (key2 = 250) THEN {Mouse event}
  2769.             RM('MOUSE^MouseInWindow');
  2770.             IF RETURN_INT = 0 THEN
  2771.                 IF (Mou_Last_Y = Fkey_Row) THEN
  2772.                     RM( 'MOUSE^MouseFkey' );
  2773.                 ELSE
  2774.                     RM('CheckEvents /M=1/G=' + event_str + '/#=' + str(event_count));
  2775.                     IF RETURN_INT <> 0 THEN
  2776.                         Return_Int := Parse_Int('/R=', return_str);
  2777.                         IF (Return_Int = 1) THEN
  2778. {We jump to CR_EXIT so the history list is added to}
  2779.                             Goto CR_EXIT;
  2780.                         END;
  2781.                         Goto EXIT;
  2782.                     ELSE
  2783.                         IF ((Mou_Last_X < col) OR (Mou_Last_X > (col + box_width)) OR
  2784.                                 (Mou_Last_Y < row) OR (Mou_Last_Y > (row + 3)))
  2785.                                 THEN
  2786.                             return_int := 0;
  2787.                             Push_Key(0,250);
  2788.                             Goto EXIT;
  2789.                         ELSIF ((return_int = 0) AND NOT(BOX)) THEN
  2790.                             Push_Key( 0,250 );
  2791.                             Return_Int := 1;
  2792.                             Goto EXIT;
  2793.                         END;
  2794.                     END;
  2795.                 END;
  2796.             END;
  2797.         END;
  2798.         IF (Key2 = 244) THEN
  2799.             Goto CR_EXIT;
  2800.         END;
  2801.         IF (Key2 = 245) THEN
  2802.             Goto ESC_EXIT;
  2803.         END;
  2804.         IF (Key2 = 3) THEN
  2805. {This is <CTRL@> which is a synonym for the null character.  This, unlike
  2806. String_In, will allow entry of null chars via this method}
  2807.             Goto INSERT_NULL;
  2808.         END;
  2809.         IF (Key2 = 75) Then
  2810.             Left;
  2811.         END;
  2812.         IF (Key2 = 77) Then
  2813.             IF (C_Col < Len) THEN
  2814.                 Right;
  2815.             END;
  2816.         END;
  2817.         IF (Key2 = 71) Then
  2818.             Home;
  2819.         END;
  2820.         IF (Key2 = 79) Then
  2821. {END key}
  2822.             IF (Length(Get_Line) < Len) THEN
  2823.                 eol;
  2824.             ELSE
  2825.                 Goto_Col(Len);
  2826.                 Redraw;
  2827.             END;
  2828.         END;
  2829.         IF (Key2 = 82) Then
  2830.             Insert_Mode := Not(Insert_Mode);
  2831.         END;
  2832.         IF NOT(At_EOL) and (Key2 = 83) Then
  2833. {Del key}
  2834.             Del_Char;
  2835.         END;
  2836.         IF (key2 = 116) and (c_col < len) and NOT(at_eol) then
  2837.             word_right;
  2838.         END;
  2839.         IF (key2 = 115) and (c_col > 1) then
  2840.             word_left;
  2841.         END;
  2842.         IF ((key2 = 80) or (key2 = 72)) and (arrow_stat) then
  2843.             return_int := - 2;
  2844.             return_str := get_line;
  2845.             goto exit;
  2846.         END;
  2847.         IF (key2 >= 59) and (key2 <= 68) then
  2848.             if parse_str('/F' + str(key2 - 58) + '=', mparm_str) <> '' then
  2849.          freturn:
  2850.                 return_int := -1;
  2851.                 return_str := get_line;
  2852.                 goto exit;
  2853.             end;
  2854.         END;
  2855.         IF (key2 = 59) then
  2856.             help(parse_str('/H=', mparm_str));
  2857.         END;
  2858.         IF (key2 = 62) and (history_stat) then
  2859.             call list_history;
  2860.             goto read_key_loop2;
  2861.         end;
  2862.     ELSE
  2863. INSERT_NULL:
  2864.         IF (C_Col <= Len) THEN
  2865.             if first_time then
  2866.                 put_line('');
  2867.                 redraw;
  2868.             end;
  2869.             IF (C_Col = Len) THEN
  2870.                 Put_Line(Copy(Get_Line,1,Len - 1) + char(key1) );
  2871.                 Redraw;
  2872.             ELSE
  2873.                 text( char(key1) );
  2874.                 put_line( copy(get_line,1, len) );
  2875.             END;
  2876.         END;
  2877.     End;
  2878.     Goto READ_KEY_LOOP;
  2879.  
  2880. list_history:
  2881.     eol_char := t_eol_char;
  2882.     RM('GlobalVarList /REV=1/G=' + history_str +
  2883.             '/X=' + str(col) + '/Y=' + str(row + 1) +
  2884.             '/S=1/T=HISTORY/H=XX/#=' + parse_str( '/#=' , global_str(history_str)) );
  2885.     eol_char := 177;
  2886.     if return_int = 1 then
  2887.         put_line(return_str);
  2888.     end;
  2889.     redraw;
  2890.     ret;
  2891.  
  2892. add_to_history:
  2893.     IF (History_Str = 'FILE_HISTORY') THEN
  2894.         return_str := caps(get_line);
  2895.     else
  2896.         return_str := Get_Line;
  2897.     end;
  2898.     IF return_str <> '' THEN
  2899.         jx := parse_int('/#=', global_str(history_str));
  2900.         temp_integer := 0;
  2901.         while temp_integer < jx do
  2902.             ++temp_integer;
  2903.             if global_str( history_str + str(temp_integer) ) = return_str then
  2904.                 return_int := temp_integer;
  2905.                 RM('deleteitem /G=' + history_str  + '/#=' + str(jx));
  2906.                 --jx;
  2907.                 temp_integer := jx;
  2908.             end;
  2909.         end;
  2910.         if jx > 15 then
  2911.             return_int := 0;
  2912.             RM('deleteitem /G=' + history_str  + '/#=' + str(jx));
  2913.         else
  2914.             ++jx;
  2915.         end;
  2916.         set_global_str( history_str + str(jx), return_str);
  2917.         set_global_str( history_str, '/#=' + str(jx));
  2918.     END;
  2919.     ret;
  2920.  
  2921. EXIT:
  2922. {Restore all altered system variables and clean up}
  2923.     IF return_int <> 0 THEN
  2924.         Return_Str := Get_Line;
  2925.     ELSE
  2926.         Return_Str := Global_Str('@UIDEFAULT@');
  2927.     END;
  2928.     Set_Global_Str('@UIDEFAULT@','');
  2929.  
  2930.     if box then
  2931.         if parse_int('/NK=', mparm_str) = 0 then
  2932.             kill_box;
  2933.         end;
  2934.     end;
  2935.     Refresh := False;
  2936.     page_str := t_page_str;
  2937.     mode := t_mode;
  2938.     eol_char := t_eol_char;
  2939.     truncate_spaces := t_trunc;
  2940.     tab_expand := t_tab_expand;
  2941.     display_tabs := t_display_tabs;
  2942.     Message_Row := Temp_Message_Row;
  2943.     Delete_Window;
  2944.     Switch_Win_Id(Active_Window);
  2945.     Undo_Stat := T_Undo_Stat;
  2946.     Pop_Labels;
  2947.     explosions := texp;
  2948.     RM('CheckEvents /M=3/G=' + event_str + '/#=' + str(event_count));
  2949.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  2950.     Refresh := Temp_Refresh;
  2951. END_MACRO;
  2952.  
  2953. $MACRO GLOBALVARLIST;
  2954. {******************************************************************************
  2955.                                                              MULTI-EDIT MACRO
  2956.  
  2957. NAME:  GLOBALVARLIST
  2958.  
  2959. DESCRIPTION:    Creates a menu of global string "array elements".  This is
  2960.                             assuming the use of globals as pseudo arrays by having the last
  2961.                             part of the global name numeric characters and therefore can be
  2962.                             referenced sequentially using a counter.
  2963.                                 Example:
  2964.                                     Global_Str('TEST1');
  2965.                                     Global_Str('TEST2');
  2966.                                     Global_Str('TEST3');
  2967.                             In the above example, "TEST" would be considered the base, and 1,
  2968.                             2, and 3 would be the value of the index to reference each element.
  2969.  
  2970. PARAMETERS:
  2971.                             /G=    The base name of the globals
  2972.                             /#=    The amount of elements
  2973.  
  2974.                              (C) Copyright 1989 by American Cybernetics, Inc.
  2975. ******************************************************************************}
  2976.  
  2977.     def_int( old_win, jx, old_refresh, count, reverse );
  2978.     def_str( gstr[20], event_str[20] );
  2979.  
  2980.     old_win := window_id;
  2981.     old_refresh := refresh;
  2982.         refresh := FALSE;
  2983.     switch_window( window_count );
  2984.     create_window;
  2985.     window_attr := $80;
  2986.     count := parse_int('/#=', mparm_str);
  2987.     gstr := parse_str('/G=',mparm_str);
  2988.     reverse := parse_int('/REV=', mparm_str);
  2989.     IF reverse THEN
  2990.         jx := count;
  2991.     ELSE
  2992.         jx := 1;
  2993.     END;
  2994.     WHILE c_line <= count DO
  2995.         put_line( global_str( gstr + str(jx) ) );
  2996.         IF reverse THEN
  2997.             --jx;
  2998.         ELSE
  2999.             ++jx;
  3000.         END;
  3001.         down;
  3002.     END;
  3003.     tof;
  3004.     event_str :=  '@GLEV' + Str(Global_Int( 'MENU_LEVEL' )) + '#';
  3005.     Set_Global_Str(Event_Str + '1', '/T=Select/K1=13/K2=28/R=1/LL=1');
  3006.     Set_Global_Str(Event_Str + '2', '/T=Cancel/K1=27/K2=1/R=0/LL=1');
  3007.     RM('WMENU /EV#=2/EV=' + event_str + mparm_str );
  3008.     refresh := false;
  3009.     return_str := get_line;
  3010.     delete_window;
  3011.     switch_win_id( old_win );
  3012.     refresh := old_refresh;
  3013. END_MACRO;
  3014.  
  3015.  
  3016. $MACRO DELETEITEM;
  3017. {******************************************************************************
  3018.                                                              MULTI-EDIT MACRO
  3019.  
  3020. NAME:  DELETEITEM
  3021.  
  3022. DESCRIPTION: Performs a "shuffle" of global variables used as arrays to fill
  3023. in the gap caused by the deletion of a single element.
  3024.  
  3025. PARAMETERS:
  3026.                         /G= The name of the "base" of the global variable.
  3027.                         /#= The total amount of array elements.
  3028.                         /T= The type of global 0=string 1=integer.
  3029.                         Return_Int the starting point to begin shuffling.
  3030.  
  3031.                              (C) Copyright 1989 by American Cybernetics, Inc.
  3032. ******************************************************************************}
  3033.     def_int( jx, count, type );
  3034.     def_str( gstr[20] );
  3035.     gstr := parse_str('/G=', mparm_str);
  3036.     count := parse_int('/#=', mparm_str);
  3037.     type := parse_int('/T=', mparm_str);
  3038.     jx := return_int;
  3039.     while jx <= count do
  3040.         if type = 0 then
  3041.             set_global_str( gstr + str(jx), global_str( gstr + str(jx + 1)));
  3042.         else
  3043.             set_global_int( gstr + str(jx), global_int( gstr + str(jx + 1)));
  3044.         end;
  3045.         ++jx;
  3046.     end;
  3047.     return_int := count - 1;
  3048. END_MACRO;
  3049.  
  3050.  
  3051. $MACRO WMENU FROM ALL;
  3052. {*******************************MULTI-EDIT MACRO******************************
  3053.  
  3054. Name:  WMENU
  3055.  
  3056. Description: Builds a scrollable menu out of the current window.
  3057.  
  3058. Parameters:
  3059.                             /T=n                Menu title
  3060.                             /X=n                X coordinate
  3061.                             /Y=n                Y coordinate
  3062.                             /W=n                The width override
  3063.                             /MH=                Height override
  3064.                             /S=n                Starting line number
  3065.                             /A=n                1 = Enable use of right and left error keys.
  3066.                             /OR=n                Starting (old) row number
  3067.                             /SP=str            Search prefix
  3068.                             /SM=n                Search_Mode, if 1, search keys off of first char only
  3069.                                                     and starts over with each keystroke.  Primarily added
  3070.                                                     for the switch window list.
  3071.                             /NB=n                1 = no box
  3072.                             /NK=n                1 = don't kill box on exit
  3073.                             /H=str            Help string
  3074.                             /MARK=n            Enable item marking.
  3075.                             /NCR=n            1 = Disable CR from exiting.
  3076.                             /DBL=n            1 = Require double click of mouse for selection.
  3077.                             /CL#=n            Number of columns to display.  Default is 1.
  3078.                             /CLW=n            Column width.
  3079.                             /CLC=n            Current column #.
  3080.  
  3081.                             /EV#=n            Number of events.
  3082.                             /EV=str            Global string prefix for events
  3083.                                                     The event globals are cleared upon exit.
  3084.                                                         The event string format is as follows:
  3085.                                                     /T=str        title
  3086.                                                     /K1=n            Keycode 1
  3087.                                                     /K2=n            Keycode 2
  3088.                                                     /R=n            Result code
  3089.                                                     /ND=1            No display
  3090.                                                     /LL=1            Put event on bottom line of window
  3091.  
  3092. NOTE:
  3093. This macro changes the window attribute(WINDOW_ATTR) to make the window
  3094. non-switchable via the normal user interface.  Be aware of this should you
  3095. wonder why your window "dissapeared".  This is of no concern if you deal
  3096. with the window only in your macro and get rid of it before exiting to edit
  3097. mode.  If you need to deal with the window in the edit mode, before exiting
  3098. your macro do something like:
  3099. Window_Attr := 0;
  3100.  
  3101. Returns:            Return_Int = 1        Item was selected.
  3102.                                                      0        ESC was pressed.
  3103.                                                     All other values corrispond to event results.
  3104.  
  3105.                              (C) Copyright 1989 by American Cybernetics, Inc.
  3106. ******************************************************************************}
  3107.     DEF_INT( x, y, menu_width, menu_length, menu_count,
  3108.                     jx, jy, jz,   {Temporary variables}
  3109.                     event_count, event_lines, tbc, t_undo,
  3110.                     cl, scroll_bar, t_ins,
  3111.                     ll_col,ll2, u_col,
  3112.                     marking_enabled, ll, mdl, t_mode,
  3113.                     column_count, column_width, current_column, search_mode );
  3114.  
  3115.     DEF_STR( event_str[20], tstr, tstr2, inc_search_str[20], inc_search_prefix[20] );
  3116.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  3117.  
  3118.     Refresh := FALSE;
  3119.     t_mode := mode;
  3120.     mode := edit;
  3121.     Search_Mode := Parse_Int('/SM=',MParm_Str);
  3122.  
  3123.     Push_Labels;
  3124.     t_undo := undo_stat;
  3125.     undo_stat := false;
  3126.     t_ins := insert_mode;
  3127.     insert_mode := true;
  3128.     TOF;
  3129.     jx := Parse_Int('/W=', mparm_str);
  3130.     IF jx > 0 THEN
  3131.         menu_width := jx;
  3132.         eof;
  3133.         goto_col(1);
  3134.         IF not(at_eof) THEN
  3135.             menu_count := c_line;
  3136.         ELSE
  3137.             menu_count := c_line - 1;
  3138.         END;
  3139.     ELSE
  3140.         menu_width := 0;
  3141.         WHILE NOT(at_eof) DO
  3142.             tstr := Get_Line;
  3143.             jx := svl(tstr);
  3144.             IF str_char(tstr, jx) <> '|254' THEN
  3145.                 IF jx > menu_width THEN
  3146.                     menu_width := jx;
  3147.                 END;
  3148.             END;
  3149.             DOWN;
  3150.         END;
  3151.         menu_count := c_line - 1;
  3152.     END;
  3153.  
  3154.     IF menu_count = 0 THEN
  3155.         Put_Line('No Items In Menu');
  3156.         menu_width := Length( get_line );
  3157.     END;
  3158.  
  3159.     marking_enabled := Parse_Int('/MARK=', mparm_str);
  3160.  
  3161.     x := Parse_Int('/X=', mparm_str);
  3162.     y := Parse_Int('/Y=', mparm_str);
  3163.     IF x <= 0 THEN
  3164.         x := 2;
  3165.     END;
  3166.     IF y <= 0 THEN
  3167.         y := 3;
  3168.     END;
  3169.  
  3170.  
  3171.     current_column := parse_int('/CLC=', mparm_str);
  3172.     IF current_column < 1 THEN
  3173.         current_column := 1;
  3174.     END;
  3175.     column_width := parse_int('/CLW=', mparm_str);
  3176.     column_count := parse_int('/CL#=', mparm_str);
  3177.     if column_count = 0 THEN
  3178.         column_count := 1;
  3179.     END;
  3180.  
  3181.     if menu_width < (column_count * column_width) THEN
  3182.         menu_width := column_count * column_width;
  3183.     end;
  3184.  
  3185.         {Now process keystroke/mouse event list}
  3186.     event_count := Parse_Int('/EV#=', MParm_Str);
  3187.     event_str := Parse_Str('/EV=', MParm_Str);
  3188.     IF (marking_enabled) AND (event_count > 0) THEN
  3189.         ++event_count;
  3190.             Set_Global_Str(Event_Str + str(event_count), '/T=Mark item/KC=<SpaceBar>/K1=32/K2=57/R=0/PK=1');
  3191.     END;
  3192.     jx := 0;
  3193.     jy := 1000;
  3194.     ll_col := 0;
  3195.     event_lines := 0;
  3196.     mdl := 1;
  3197.     WHILE jx < event_count DO
  3198.         ++jx;
  3199.         tstr := Global_Str( event_str + str(jx));
  3200.         IF parse_int('/ND=',tstr) = 0 THEN
  3201.             key1 := Parse_Int('/K1=', tstr);
  3202.             key2 := Parse_Int('/K2=', tstr);
  3203.             return_str := parse_str('/KC=', tstr);
  3204.             IF key1 = 0 THEN
  3205.                 IF (key2 > 58) AND (key2 < 114) THEN
  3206.                     flabel(Parse_Str('/FL=', tstr), key2 - 58, -1);
  3207.                 END;
  3208.             END;
  3209.             IF return_str = '' THEN
  3210.                 RM( 'SETUP^MAKEKEY /K1=' + Str(key1) +
  3211.                                                         '/K2=' + Str(key2));
  3212.             END;
  3213.             jz := Length(return_str) + Length( Parse_Str('/T=', tstr)) + 1;
  3214.             ll := Parse_Int('/LL=', tstr);
  3215.             IF ll = 1 THEN
  3216.                 tstr := tstr + '/C=' + str( ll_col );
  3217.                 ll_col := ll_col + jz + 1;
  3218.                 IF (menu_width < (ll_col - 2)) THEN
  3219.                     menu_width := ll_col - 3;
  3220.                 END;
  3221.             ELSIF ll = 2 THEN
  3222.                 tstr := tstr + '/C=' + str( mdl + 1 );
  3223.                 mdl := mdl + jz{ + 1};
  3224.             ELSE
  3225.                 IF (menu_width - jy) < jz THEN
  3226.                     IF (event_lines > 0) THEN
  3227.                         set_global_int('@EVL#' + str( event_lines ), jy - 3);
  3228.                     END;
  3229.                     jy := 0;
  3230.                     ++event_lines;
  3231.                 END;
  3232.                 IF (menu_width < (jy + jz)) THEN
  3233.                     menu_width := jy + jz;
  3234.                 END;
  3235.                 tstr := tstr + '/EL=' + str( event_lines ) + '/C=' + str( jy );
  3236.                 jy := jy + jz + 1;
  3237.             END;
  3238.             tstr := tstr + '/KC=' + return_str  + '/W=' + str(jz - 1);
  3239.             Set_Global_Str( event_str + str(jx), tstr );
  3240.         END;
  3241.     END;
  3242.     IF (event_lines > 0) THEN
  3243.         set_global_int('@EVL#' + str( event_lines ), jy - 3);
  3244.     END;
  3245.  
  3246.     IF (menu_width > (Screen_Width - 3)) THEN
  3247.         menu_width := Screen_Width - 3;
  3248.     END;
  3249.  
  3250.     IF ((x + menu_width) > (Screen_Width - 2)) THEN
  3251.         x := Screen_Width - menu_width - 2;
  3252.     END;
  3253.  
  3254.     menu_length := menu_count;
  3255.     IF menu_count = 0 THEN
  3256.         menu_length := 1;
  3257.     END;
  3258.     jx := parse_int('/MH=', mparm_str);
  3259.     IF jx <> 0 THEN
  3260.         menu_length := jx;
  3261.     END;
  3262.     IF (y + menu_length + event_lines + 3 + (event_lines > 0)) > Screen_length THEN
  3263.         menu_length := ((screen_length - y) - event_lines - 3 - (event_lines > 0));
  3264.     END;
  3265.  
  3266.  
  3267.     set_virtual_display;
  3268.     tbc := box_count;
  3269.     IF Parse_Int('/NB=',mparm_str) = 0 THEN
  3270.         Put_Box( x, y, x + menu_width + 3, y + event_lines + menu_length + 2 + (event_lines > 0),
  3271.                         0, m_b_color, Parse_Str('/T=', mparm_str), TRUE );
  3272.     END;
  3273.  
  3274.  
  3275.     tof;
  3276.     t_color := m_t_color;
  3277.     b_color := m_b_color;
  3278.     s_color := m_s_color;
  3279.     h_color := m_h_color;
  3280.     c_color := m_t_color;
  3281.     eof_color := (m_t_color AND $F0) OR ((m_t_color AND $70) SHR 4);
  3282.     window_attr := $86;
  3283.     Size_Window( x , y + event_lines + (event_lines > 0),
  3284.                              x + menu_width + 1, y + menu_length + event_lines + 1 + (event_lines > 0) );
  3285.  
  3286.  
  3287.     IF event_count > 0 THEN
  3288.         IF event_lines > 0 THEN
  3289.             Draw_Char(196, x + 1, y + event_lines + 1, m_b_color, menu_width );
  3290.         END;
  3291.         jx := 0;
  3292.         WHILE jx < event_lines DO
  3293.             ++jx;
  3294.             Set_Global_Int('@EVL#' + str(jx),
  3295.                  x + 1 + ((menu_width / 2) - (Global_Int('@EVL#' + str(jx)) / 2)));
  3296.         END;
  3297.  
  3298.         IF ll_col > 0 THEN
  3299.             ll_col := ll_col - 3;
  3300.         END;
  3301.         ll_col := x + 1 + ((menu_width / 2) - (ll_col / 2));
  3302.         ll2 := 0;
  3303.         u_col := 0;
  3304.         jx := 0;
  3305.         WHILE jx < event_count DO
  3306.             ++jx;
  3307.             tstr := Global_Str( event_str + str(jx));
  3308.             IF (parse_int('/ND=', tstr) = 0) THEN
  3309.                 ll := Parse_Int('/LL=', tstr);
  3310.                 IF ll = 1 THEN
  3311.                     jz := win_y2;
  3312.                     jy := ll_col + ll2;
  3313.                     ll_col := ll_col + parse_int('/W=', tstr) + 1;
  3314.                 ELSIF ll = 2 THEN
  3315.                     jz := (y + event_lines + 1) * (event_lines <> 0);
  3316.                     jy := parse_int('/C=',tstr) + x;
  3317.                 ELSE
  3318.                     jz := Parse_Int('/EL=', tstr);
  3319.                     jy := Global_Int('@EVL#' + str(jz)) +
  3320.                                                         Parse_Int('/C=', tstr);
  3321.                     jz := y + jz;
  3322.                 END;
  3323.                 Set_Global_Str( event_str + str(jx), tstr + '/X=' + str(jy) +
  3324.                                                             '/Y=' + str(jz));
  3325.                 tstr2 := Parse_Str('/T=', tstr );
  3326.                 write( tstr2, jy, jz, 0, m_t_color );
  3327.                 jy := jy + svl(tstr2);
  3328.                 tstr2 := Parse_Str('/KC=', tstr);
  3329.                 write( tstr2, jy, jz, 0, m_s_color );
  3330.             END;
  3331.         END;
  3332.      {RM('CheckEvents /M=2/G=' + event_str + '/#=' + str(event_count));}
  3333.  
  3334.     END;
  3335.  
  3336.  
  3337.  
  3338.     jy := parse_int('/S=', mparm_str );
  3339.     IF jy = 0 THEN
  3340.         jy := 1;
  3341.     END;
  3342.     jx := parse_int('/OR=', mparm_str);
  3343.     IF jy > menu_count THEN
  3344.         jy := menu_count;
  3345.     END;
  3346.     IF (menu_count - (jy - jx)) < menu_length THEN
  3347.         jx := menu_length;
  3348.     END;
  3349.     WHILE (c_row < jx) AND (c_row < menu_length) DO
  3350.         DOWN;
  3351.     END;
  3352.     Goto_Line(jy);
  3353.  
  3354.  
  3355.     Scroll_Bar := (menu_length > 2) AND (menu_count > menu_length);
  3356.     IF scroll_bar = 0 THEN
  3357.         window_attr := window_attr OR $08;
  3358.     END;
  3359.     call skip_up;
  3360.     call skip_down;
  3361.  
  3362.     REFRESH := true;
  3363.     redraw;
  3364.  
  3365.     update_virtual_display;
  3366.     reset_virtual_display;
  3367.  
  3368.     inc_search_str := '';
  3369.     inc_search_prefix := Parse_Str('/SP=',mparm_str);
  3370.     IF inc_search_prefix = '' THEN
  3371.         if marking_enabled then
  3372.             inc_search_prefix := '%?';
  3373.         ELSE
  3374.             inc_search_prefix := '%';
  3375.         END;
  3376.     END;
  3377.  
  3378.     If column_width = 0 THEN
  3379.         column_width := menu_width;
  3380.     end;
  3381.  
  3382. main_loop:
  3383.     goto_col( (column_width * (current_column - 1))
  3384.                                     + svl(inc_search_str) + 1 + marking_enabled);
  3385.     IF (at_eof) AND (current_column > 1) THEN
  3386.         goto go_left;
  3387.     END;
  3388.     call Hi_Line;
  3389.     read_key;
  3390.     draw_attr( x + 1, wherey, m_t_color, menu_width );
  3391. pass_key_through:
  3392.     IF key1 = 0 THEN
  3393.         inc_search_str := '';
  3394.         IF (key2 = 59) THEN
  3395.             Help( Parse_Str('/H=', mparm_str ) );
  3396.             Goto Main_Loop;
  3397.         ELSIF (key2 = 77) OR (key2 = 242) THEN
  3398.             ++current_column;
  3399.             IF (current_column > column_count) THEN
  3400.                 current_column := 1;
  3401.                 goto go_down;
  3402.             END;
  3403.         ELSIF (key2 = 75) OR (key2 = 243) THEN
  3404.             go_left:
  3405.             --current_column;
  3406.             IF (current_column < 1) THEN
  3407.                 current_column := column_count;
  3408.                 goto go_up;
  3409.             END;
  3410.         ELSIF (key2 = 80) OR (key2 = 241) THEN
  3411.          go_down:
  3412.             IF (c_line < menu_count) THEN
  3413.                 DOWN;
  3414.             END;
  3415.             Call Skip_Down; Call Skip_Up;
  3416.         ELSIF (key2 = 72) OR (key2 = 240) THEN
  3417.         go_up:
  3418.             UP;
  3419.             Call Skip_Up; Call Skip_Down;
  3420.         ELSIF (key2 = 73) THEN
  3421.             Page_Up;
  3422.             Call Skip_Up; Call Skip_Down;
  3423.         ELSIF (key2 = 81) THEN
  3424.             IF (c_line + Menu_Length - C_row) > (menu_count  - Menu_Length + 1) THEN
  3425.                 goto goto_eof;
  3426.             END;
  3427.             Page_Down;
  3428.             Call Skip_Down; Call Skip_Up;
  3429.         ELSIF (key2 = 79) THEN
  3430.      goto_eof:
  3431.             refresh := false;
  3432.             EOF;
  3433.             goto_col(1);
  3434.             goto_line(c_line - 1);
  3435.             down;
  3436.             Call Skip_Up; Call Skip_Down;
  3437.          {WHILE c_line < menu_count DO
  3438.                 DOWN;
  3439.             END;}
  3440.             current_column := column_count;
  3441.             refresh := true;
  3442.             redraw;
  3443.         ELSIF (key2 = 71) THEN
  3444.      goto_tof:
  3445.             current_column := 1;
  3446.             tof;
  3447.             Call Skip_Down; Call Skip_Up;
  3448.         ELSIF (key2 = 244) THEN
  3449.             Goto go_cr;
  3450.         ELSIF (key2 = 245) THEN
  3451.             Goto go_esc;
  3452.         ELSIF (key2 = 250) THEN  {process mouse event}
  3453.             Goto do_mouse_event;
  3454.         ELSIF (key2 = 251) AND (marking_enabled) THEN
  3455.             Mark_Pos;
  3456.             RM('MOUSE^MouseInWindow');
  3457.             IF at_eof THEN
  3458.                 goto_mark;
  3459.             ELSE
  3460.                 pop_mark;
  3461.                 current_column := ((c_col - 1) / column_width) + 1;
  3462.                 IF (return_int = 1) AND (xpos('|254', get_line,1) = 0) THEN
  3463.                     call toggle_mark;
  3464.                 END;
  3465.             end;
  3466.         ELSE
  3467.             call Process_Key_Event;
  3468.             IF jx <> 0 THEN
  3469.                 goto exit;
  3470.             END;
  3471.         END;
  3472.     ELSE
  3473.         call process_key_event;
  3474.         IF jx <> 0 THEN
  3475.             goto exit;
  3476.         END;
  3477.         IF (key1 = 27) THEN
  3478.         go_esc:
  3479.             RETURN_INT := 0;
  3480.             Goto EXIT;
  3481.         ELSIF (key1 = 13) THEN
  3482.         go_cr:
  3483.             IF Parse_Int('/NCR=', mparm_str) = 0 THEN
  3484.                 RETURN_INT := 1;
  3485.                 Goto EXIT;
  3486.             END;
  3487.         ELSIF (key1 = 43) AND (marking_enabled) THEN
  3488.         do_mark:
  3489.             call toggle_mark;
  3490.         ELSIF( key1 = 08 ) THEN
  3491.             IF svl(inc_search_str) > 0 THEN
  3492.                 refresh := false;
  3493.                 TOF;
  3494.                 inc_search_str := str_del( inc_search_str, svl(inc_search_str), 1 );
  3495.                 GOTO inc_search;
  3496.         END;
  3497.         ELSE
  3498.         inc_search:
  3499.             {tstr := inc_search_prefix + inc_search_str;}
  3500.             IF (Search_Mode) THEN
  3501.                 inc_search_str := '';
  3502.                 if key1 <> 08 THEN
  3503.                     tstr := CAPS(char(key1));
  3504.                 END;
  3505.             ELSE
  3506.                 tstr := CAPS(inc_search_str);
  3507.                 if key1 <> 08 THEN
  3508.                     tstr := tstr + CAPS(char(key1));
  3509.                 END;
  3510.             END;
  3511.  
  3512.             refresh := false;
  3513.             mark_pos;
  3514.             IF (inc_search_str = '') THEN
  3515.                 tof;
  3516.             END;
  3517.             jy := 0;
  3518.         search_loop:
  3519.             ++jy;
  3520.             IF (jy > column_count) THEN
  3521.                 down;
  3522.                 jy := 1;
  3523.             END;
  3524.             IF (c_line > menu_count) THEN
  3525.                 goto search_exit;
  3526.             END;
  3527.             goto_col( (column_width * (jy - 1)) + 1 + marking_enabled );
  3528.             IF caps(copy(get_line, c_col, svl(tstr))) = tstr THEN
  3529.                 if key1 <> 08 THEN
  3530.                     inc_search_str := inc_search_str + char(key1);
  3531.                 END;
  3532.                 pop_mark;
  3533.                 refresh := true;
  3534.                 current_column := jy;
  3535.                 GOTO main_loop;
  3536.             END;
  3537.             goto search_loop;
  3538.     search_exit:
  3539.             goto_mark;
  3540.             refresh := true;
  3541.         END;
  3542.     END;
  3543.     GOTO main_loop;
  3544.  
  3545. Toggle_Mark:
  3546.     insert_mode := false;
  3547.     goto_col( (column_width * (current_column - 1)) + 1 );
  3548.     IF (cur_char = '|16') THEN
  3549.         text(' ');
  3550.     ELSE
  3551.         text('|16');
  3552.     END;
  3553.     insert_mode := true;
  3554.     ret;
  3555.  
  3556. {Returns with jx = 0, no action;  jx > 0, goto exit}
  3557. Process_Key_Event:
  3558.     jx := 0;
  3559.     RM('CheckEvents /G=' + event_str + '/#=' + str(event_count));
  3560.     IF RETURN_INT <> 0 THEN
  3561.         JX := RETURN_INT;
  3562.         RETURN_INT := Parse_Int('/R=', Return_Str );
  3563.     END;
  3564.     RET;
  3565.  
  3566.  
  3567. Skip_Down:
  3568.     While (Xpos('|254',get_line,1) <> 0) AND (c_line < menu_count) DO
  3569.         DOWN;
  3570.     END;
  3571.     RET;
  3572.  
  3573. Skip_UP:
  3574.     While (Xpos('|254',get_line,1) <> 0) AND (C_Line > 1) DO
  3575.         UP;
  3576.     END;
  3577.     RET;
  3578.  
  3579. Hi_Line:
  3580.     draw_attr( x + 1 + ((current_column - 1) * column_width), wherey, m_h_color, column_width );
  3581.     RET;
  3582.  
  3583. Do_Mouse_Event:
  3584.     Mark_pos;
  3585.     jy := c_line;
  3586.     jx := current_column;
  3587.     RM('MOUSE^MouseInWindow');
  3588.     IF (return_int = 1) AND (xpos('|254', get_line,1) = 0) AND (not(at_eof)) THEN
  3589.         pop_mark;
  3590.         current_column := ((c_col - 1) / column_width) + 1;
  3591.         goto_col( (column_width * (current_column - 1)) + 1 );
  3592.         call Hi_Line;
  3593.         IF (Parse_Int('/DBL=', mparm_str) = 0) OR
  3594.                 ((jy = c_line) AND (jx = current_column )) THEN
  3595.             return_int := 1;
  3596.             goto exit;
  3597.         END;
  3598.     ELSE
  3599.         goto_mark;
  3600.         IF (Mou_Last_Y = Fkey_Row) THEN
  3601.             RM( 'MOUSE^MouseFkey' );
  3602.             GOTO Main_Loop;
  3603.         ELSIF (Mou_Last_X = Win_X2) THEN
  3604.             RM('MOUSE^HandleScrollBar /EOF=1/L=' + str(menu_count));
  3605.             IF return_int = 1 THEN
  3606.                 call skip_down;
  3607.             ELSIF return_int = 2 THEN
  3608.         call skip_up;
  3609.             END;
  3610.         ELSIF (Mou_Last_X > X) AND (Mou_Last_Y <= (X + Menu_Width)) THEN
  3611.             RM('CheckEvents /M=1/G=' + event_str + '/#=' + str(event_count));
  3612.             IF RETURN_INT <> 0 THEN
  3613.                 RETURN_INT := Parse_Int('/R=', Return_Str );
  3614.                 IF parse_int('/PK=', mparm_str) THEN
  3615.                     key1 := parse_int('/K1=', mparm_str);
  3616.                     key2 := parse_int('/K2=', mparm_str);
  3617.                     goto pass_key_through;
  3618.                 END;
  3619.                 Goto Exit;
  3620.             END;
  3621.         END;
  3622.     END;
  3623.     IF (Mou_Last_X < X) OR (Mou_Last_X > (X + Menu_Width + 3))
  3624.             OR (Mou_Last_Y < Y) OR (Mou_Last_Y > (WIN_Y2 + 1)) THEN
  3625.         Push_Key(0,250);
  3626.         RETURN_INT := 0;
  3627.         goto exit;
  3628.     END;
  3629.     goto main_loop;
  3630.  
  3631. exit:
  3632.     refresh := false;
  3633.     call hi_line;
  3634.     if menu_count = 0 THEN
  3635.         IF ((return_int = 1) and (Parse_Int('/OEM=',MParm_Str) = 0)) THEN
  3636.             return_int := 0;
  3637.         END;
  3638.         del_line;
  3639.     END;
  3640.     IF Parse_Int('/NK=',mparm_str) = 0 THEN
  3641.         WHILE (box_count > tbc) DO
  3642.             kill_box;
  3643.         END;
  3644.     END;
  3645.  
  3646.     jx := 0;
  3647.     WHILE (jx < Event_Count) DO
  3648.         ++jx;
  3649.         Set_Global_Str( event_str + str(jx), '');
  3650.     END;
  3651.     goto_col( (column_width * (current_column - 1)) + 1 );
  3652.     Pop_Labels;
  3653.     undo_stat := t_undo;
  3654.     insert_mode := t_ins;
  3655.     mode := t_mode;
  3656.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  3657. END_MACRO;
  3658.  
  3659. $MACRO CHECKEVENTS FROM ALL;
  3660. {*******************************MULTI-EDIT MACRO******************************
  3661.  
  3662. Name:  CheckEvents
  3663.  
  3664. Description:    Checks to see if a keyboard or mouse event occurred.
  3665.  
  3666.  
  3667. Parameters:  /G=str                    Global string prefix for event variables.
  3668.                          /#=n                        Number of events
  3669.                          /M=n                        0 = Check keyboard
  3670.                                                         1 = Check mouse
  3671.                                                         2 = Redraw events
  3672.                                                             /F=1    Update function key labels
  3673.                                                         3 = Clear events
  3674.                                                         4 = Center events on line.  IF you use this
  3675.                                                                 DO NOT put /X= and /Y= coordinates in your
  3676.                                                                 event globals, as this function will take
  3677.                                                                 care of that for you.
  3678.  
  3679.                                                                 /X=n    x coordinate
  3680.                                                                 /Y=n  y coordinate
  3681.                                                                 /W=n    width
  3682.  
  3683. RETURNS:
  3684.                         FOR /M=0 or 1
  3685.                             Return_Int = 0 IF NO EVENT FOUND
  3686.                             ELSE Return_Int = EVENT #.
  3687.                             RETURN_STR = The event string.
  3688.  
  3689.                         FOR /M=4
  3690.                             Return_Int = Total width the events took up.
  3691.  
  3692. Global String Format:
  3693.                         /T=str        title
  3694.                         /X=n            X coordinate
  3695.                         /Y=n            Y coordinate
  3696.                         /W=n            Total event width.
  3697.                         /K1=n            Keycode 1
  3698.                         /K2=n            Keycode 2
  3699.                         /KC=str        Keycode name
  3700.                         /R=n            Result code
  3701.                         /ND=1            No display
  3702.                         /FL=            Function key label.  Will only work if /K1= and /K2=
  3703.                                             define a function key.
  3704.  
  3705.                              (C) Copyright 1989 by American Cybernetics, Inc.
  3706. ******************************************************************************}
  3707.     Def_Str( event_str[80], tstr[100], tstr2[100] );
  3708.     Def_Int( k1, k2, jj, jx, jy, jz, tint, Event_Count, check_mode, fkeyl );
  3709.  
  3710.     event_count := Parse_Int('/#=', mparm_str);
  3711.     event_str := Parse_Str('/G=', mparm_str );
  3712.     jx := 0;
  3713.  
  3714.     check_mode := parse_int('/M=', mparm_str);
  3715.     IF check_mode = 1 THEN
  3716.         RETURN_INT := 0;
  3717.         WHILE (jx < Event_Count) DO
  3718.             ++jx;
  3719.             tstr := Global_Str( event_str + str(jx) );
  3720.             IF (Mou_Last_Y = Parse_Int('/Y=', tstr)) THEN
  3721.                 jy := Parse_Int('/X=', tstr);
  3722.                 IF (Mou_Last_X >= jy) AND (Mou_Last_X < (jy + Parse_Int('/W=',tstr))) THEN
  3723.                     goto Hi_Event;
  3724.                 END;
  3725.             END;
  3726.         END;
  3727.     ELSIF check_mode = 2 THEN
  3728.         fkeyl := parse_int('/F=', mparm_str);
  3729.         WHILE (jx < Event_Count) DO
  3730.             ++jx;
  3731.             tstr := Global_Str( event_str + str(jx));
  3732.             jy := Parse_Int('/X=', tstr);
  3733.             jz := Parse_Int('/Y=', tstr);
  3734.             tstr2 := Parse_Str('/T=', tstr);
  3735.             jj := svl(tstr2);
  3736.             IF jj <> 0 THEN
  3737.                 WRITE( tstr2, jy, jz, 0, m_t_color );
  3738.                 jy := jy + jj;
  3739.             END;
  3740.             tstr2 := Parse_Str('/KC=', tstr);
  3741.             WRITE( tstr2, jy, jz, 0, m_s_color );
  3742.             IF fkeyl THEN
  3743.                 k1 := parse_int('/K1=', tstr);
  3744.               IF k1 = 0 THEN
  3745.                     k2 := parse_int('/K2=', tstr);
  3746.                     IF (k2 > 58) AND (k2 < 114) THEN
  3747.                         flabel(Parse_Str('/FL=', tstr), k2 - 58, -1);
  3748.                     END;
  3749.                 END;
  3750.             END;
  3751.         END;
  3752.     ELSIF check_mode = 0 THEN
  3753.         RETURN_INT := 0;
  3754.         WHILE (jx < Event_Count) DO
  3755.             ++jx;
  3756.             tstr := Global_Str( event_str + str(jx));
  3757.             IF (Parse_Int('/K1=', tstr) = key1) AND (Parse_Int('/K2=', tstr) = key2) THEN
  3758.                 RETURN_INT := Parse_Int('/R=', tstr);
  3759.                 goto hi_event;
  3760.             END;
  3761.         END;
  3762.     ELSIF check_mode = 3 THEN
  3763.         WHILE (jx < Event_Count) DO
  3764.             ++jx;
  3765.             Set_Global_Str( event_str + str(jx), '');
  3766.         END;
  3767.     ELSIF check_mode = 4 THEN
  3768.         jy := 1;
  3769.         WHILE (jx < event_count) DO
  3770.             ++jx;
  3771.             tstr := Global_Str( event_str + str(jx));
  3772.                 jj := parse_int('/W=', tstr );
  3773.             IF jj = 0 THEN
  3774.                 jj := Length(parse_str('/KC=', tstr)) + Length(parse_str('/T=', tstr) );
  3775.                 tstr := tstr + '/W=' + str( jj );
  3776.                 Set_Global_Str( event_str + str(jx), tstr);
  3777.             END;
  3778.                 jy := jy + jj + 1;
  3779.         END;
  3780.         jy := jy - 2;
  3781.         tint := parse_int('/Y=', mparm_str);
  3782.         return_int := jy;
  3783.  
  3784.         jx := parse_int('/X=', mparm_str);
  3785.         jy := jx + (((parse_int('/W=', mparm_str) / 2)) - (jy / 2));
  3786.         IF jy < jx THEN
  3787.             jy := jx;
  3788.         END;
  3789.         jx := 0;
  3790.         WHILE (jx < event_count) DO
  3791.             ++jx;
  3792.             tstr := Global_Str( event_str + str(jx));
  3793.             jj := parse_int('/W=', tstr );
  3794.             IF jj = 0 THEN
  3795.                 jj := Length(parse_str('/KC=', tstr)) + Length(parse_str('/T=', tstr) );
  3796.                 tstr := tstr + '/W=' + str( jj );
  3797.                 Set_Global_Str( event_str + str(jx), tstr);
  3798.             END;
  3799.             tstr := tstr + '/X=' + str(jy) + '/Y=' + str(tint);
  3800.             Set_Global_Str( event_str + str(jx), tstr);
  3801.             jy := jy + jj + 1;
  3802.         END;
  3803.     END;
  3804.     goto exit;
  3805.  
  3806. Hi_Event:
  3807.     RETURN_INT := jx;
  3808.     RETURN_STR := tstr;
  3809.     Draw_Attr( parse_int('/X=', tstr), parse_int('/Y=', tstr), m_h_color,
  3810.                             parse_int('/W=', tstr));
  3811.  
  3812. exit:
  3813. END_MACRO;
  3814.  
  3815.  
  3816. $MACRO DB;
  3817. {*******************************MULTI-EDIT MACRO******************************
  3818.  
  3819. Name: DB
  3820.  
  3821. Description:  A text database manager, capable of considerable versatility.
  3822.                             Can be used as for such simple things as establishing a pop-up
  3823.                             phone list, to much more sophisticated uses as managing the
  3824.                             filename extension setup parameters.  This macro can actually
  3825.                             be nested so that editing a field can bring up yet another
  3826.                             database.
  3827.  
  3828. File Format:  The header is composed of one field definition per line as
  3829.                             follows (except for /DBF, the format is the same as individual
  3830.                             string fields in DATA_IN):
  3831.  
  3832.         /TP=field_type/T=field_name/L=line/C=col/W=field_width/ML=max_field_length/DBF=field_designator
  3833.         (any number of repeats of the above line)
  3834.         ****START****
  3835.         (data records)
  3836.  
  3837.                             The /DBF field designator must be unique, and represents the
  3838.                             identifier in each record for that field.
  3839.  
  3840.                             See PHONE.DB for a sample note card file.
  3841.  
  3842. Parameters:
  3843.                         /X=        X coordinate for the menu box.
  3844.                         /Y=        Y coordinate for the menu box.
  3845.                         /F=  The file name of the database file.  If no path is
  3846.                                  specified, then:
  3847.                                         A.  the ME_PATH is used if no USER_ID is in use
  3848.                                         B.    the USER_ID directory is used.
  3849.                         /CP=    Create Prompt.  If present, will be the prompt when user
  3850.                                     creates a new record.
  3851.  
  3852.                         /LD= Leading delimiter for each field.  MUST be the last parameter
  3853.                                  on the command line.  Default is "".
  3854.  
  3855.                         /TT= Title type.
  3856.                                     0 = File name with extension
  3857.                                     1 = File name without extension
  3858.  
  3859.                         /LT=  List title  If present, /LT= will replace the file name
  3860.  
  3861.                         /DT=  Data title  If present, /DT= will be used in the DATA_IN
  3862.                                     title instead of the list title.
  3863.  
  3864.                         /NOALPHA=  If 1, No alphabetic sorting will take place.
  3865.  
  3866.                         /LO= 1 : List only.  Select with <ENTER>.  No DATA_IN screen.
  3867.                                  2 : Same as 1 but adds the Modify option.
  3868.  
  3869.                         /NL= No list.  If 1, the DVMENU of records is bypassed.  Display
  3870.                                 /FV= record.
  3871.                         /FV=  Field value first field of record to be displayed.  Only
  3872.                                     used if /NL=1 or /C=1.  If /FV is null, the first record will
  3873.                                     be displayed.
  3874.  
  3875.                         /PROTECT1 - nn=  Set of first field values of records to protect against
  3876.                                                             deletion.
  3877.  
  3878.                         /C=  Immediately create a new record if /FV= is not found.  Can be
  3879.                                  used only with /NL=.
  3880.  
  3881.                         /HF=str  Specifies a header file.  This allows you to use
  3882.                                 a seperate file for your field definitions.
  3883.                         /PRE=str Prefix for the ISTR, IPARM and IINT.  Use when nesting
  3884.                                 DB.
  3885.  
  3886.                         /RR=1 Return record only /FV= and store into /GLO=.  Will not create
  3887.                             a list or data screen.
  3888.  
  3889.                         /GLO= Name of global string to store a found record.  Can be used
  3890.                             with or without /RR=.
  3891.  
  3892.                         /DS=str Display string global var name.
  3893.                                     The display string global should be formatted as follows:
  3894.                                         /field_name=length /field_name=length...
  3895.                                     ("/" should be replaced by the /LD= delimit)
  3896.  
  3897.                      /PR=  Print records.  Will, instead of displaying the menu,
  3898.                                  send it to the currently defined printer device.
  3899.  
  3900.                      /NC=  If 1, disables Copy record function.
  3901.  
  3902.                      /NE=  If 1, disables Edit record function.
  3903.  
  3904.                      /NDF=1   Do NOT delete file window when done.
  3905.                      /NDH=1   Do NOT delete header window when done.
  3906.                      /ENC=1        Exit if no records are found.
  3907.                      /MACRO=str  Name of macro to be run both BEFORE and AFTER
  3908.                             a record is modified.  The record will be in the global
  3909.                             variable specified by /GLO=.  The following parameters
  3910.                             will be passed to the macro:
  3911.  
  3912.                                     /P=nn            nn = 0  Macro was run before modification.
  3913.                                                              = 1  Macro was run AFTER modification.
  3914.  
  3915.                                     /GLO=str            name of the global variable containing the
  3916.                                                                 record.
  3917.  
  3918.                     /DPT=str     Name of the page to use for the data in multiple page
  3919.                                             db files.
  3920.                     /HPT=str  Name of the page to use for the header in multiple page
  3921.                                             db files.
  3922.  
  3923.                     /SRP=n        1 = Allow search.
  3924.  
  3925.                     /S=                Starting choice.  This will be the hilited choice if <> 0
  3926.                     /NSF=            Don't save the DB file even if a change is made.  Rarely
  3927.                                         used.
  3928.  
  3929.  
  3930. Global Variables Returned:
  3931.                         Global_Int( '@DB_FILE_CHANGED' )  will be TRUE if any changes
  3932.                         were made to the file.
  3933.  
  3934.                              (C) Copyright 1989 by American Cybernetics, Inc.
  3935. ******************************************************************************}
  3936.  
  3937.     def_int( x, y,             {Display coordinates}
  3938.                     field_count, {The # of fields in the database}
  3939.                     tp,                    {current record type}
  3940.                     No_List,
  3941.                     t_refresh,
  3942.                     Create,
  3943.                     List_Only,
  3944.                     Search_result,
  3945.                     record_count, {The # of records in the database}
  3946.                     jx, jy, jz,      {Temp vars}
  3947.                     need_rebuild, {1 = Need new list of records}
  3948.                     new_box,
  3949.                     end_field,         {The line number of the last field in the header.
  3950.                                                  end_field will be 0 if a seperate header file is used}
  3951.                     tbc,                 {The box count we started witch}
  3952.                     header_win, {The database header window}
  3953.                     old_win,         {The window we started with}
  3954.                     db_win,            {The database data window}
  3955.                     build_win,    {The window to build the database menu in}
  3956.                     db_win_num,
  3957.                     build_win_num,
  3958.                     max_width,    {The length of the biggest record}
  3959.                     Return_Record,
  3960.                     use_ds,
  3961.                     cur_item, cur_row,
  3962.                     No_Alpha,
  3963.                     old_width,
  3964.                     first_display,
  3965.                     Print_Records,
  3966.                     Use_Ps,
  3967.                     Handle,
  3968.                     T_Insert_Mode,
  3969.                     T_Truncate_Spaces,
  3970.                     Ev_Count,
  3971.           header_page_line, data_page_line,
  3972.           db_exists, header_exists,
  3973.                     temp_use_ds,
  3974.                     old_backups
  3975.                     );
  3976. {Used for parse_ds}
  3977.     def_int( tint, tint2 );
  3978.  
  3979. Def_Int(Ticks);
  3980.  
  3981.     def_str( tstr[2000],
  3982.                      tstr2[80],
  3983.                      tstr3,
  3984.                      header_file[80],
  3985.                      Prefix[10],
  3986.                      List_Title[78],
  3987.                      Data_Title[78],
  3988.                      mac_str,
  3989.                      glo_str[16],
  3990.                      PP_Str[10],
  3991.                      DSG_Name[20],
  3992.                      DSG_Ints[30],
  3993.                      TP_STR
  3994.                     );
  3995.  
  3996.     def_int( ds_count );
  3997.  
  3998.     Def_Char(Delimit);
  3999.  
  4000.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  4001.  
  4002.     Error_Level := 0;
  4003.     reg_exp_stat := TRUE;
  4004.     T_Insert_Mode := Insert_Mode;
  4005.     T_Truncate_Spaces := Truncate_Spaces;
  4006.     Truncate_Spaces := False;
  4007.     Old_Backups := Backups;
  4008.     Backups := FALSE;
  4009.     Use_Ps := 0;
  4010.     Return_Int := XPos('/LD=',MParm_Str,1);
  4011.     IF (Return_Int) THEN
  4012.         Delimit := Copy(MParm_Str,Return_Int + 4,1);
  4013.     ELSE
  4014.         Delimit := '';
  4015.     END;
  4016.     Return_Record := FALSE;
  4017.     glo_str := Parse_Str('/GLO=',MParm_Str);
  4018.     No_Alpha := Parse_Int('/NOALPHA=',MParm_Str);
  4019.     No_List := Parse_Int('/NL=',MParm_Str);
  4020.     IF (No_List = 0) THEN
  4021.         IF (Parse_Int('/RR=',MParm_Str)) THEN
  4022.             Return_Record := True;
  4023.             Return_Int := 1;
  4024.             No_List := True;
  4025.             Set_Global_Str(glo_str,'');
  4026.         END;
  4027.     END;
  4028.     Create := Parse_Int('/C=',MParm_Str);
  4029.     Jx := XPos('/MACRO=',MParm_Str,1);
  4030.     IF (Jx) THEN
  4031.         mac_str := Copy(Mparm_str,Jx + 7,254);
  4032.         IF (XPos(' ',Mac_Str,1) = 0) THEN
  4033.             Mac_Str := Mac_Str + ' ';
  4034.         END;
  4035.     END;
  4036.     Print_Records := False;
  4037.     List_Title := Parse_Str('/LT=',MParm_Str);
  4038.     IF (List_Title = '') THEN
  4039.         List_Title := Truncate_Path(Parse_Str('/DPT=',MParm_Str));
  4040.         IF (List_Title = '') THEN
  4041.             List_Title := Truncate_Path(Parse_Str('/F=',MParm_Str));
  4042.         END;
  4043.         IF (Parse_Int('/TT=',MParm_Str) = 1) THEN
  4044.             List_Title := Truncate_Extension(List_Title);
  4045.         END;
  4046.     END;
  4047.  
  4048.     Data_Title := Parse_Str('/DT=',MParm_Str);
  4049.     IF (Data_Title = '') THEN
  4050.         Data_Title := List_Title;
  4051.     END;
  4052.  
  4053.     List_Only := Parse_Int('/LO=',MParm_Str);
  4054.     Search_Result := 1;
  4055.     t_refresh := refresh;
  4056.     refresh := false;
  4057.  
  4058.     old_win := window_id;
  4059.     build_win := 0;
  4060.     build_win_num := 0;
  4061.     Prefix := Parse_Str('/PRE=',MParm_Str);
  4062.     IF prefix = '' THEN
  4063.         prefix := str(global_int('MENU_LEVEL'));
  4064.     END;
  4065.  
  4066.     field_count := 0;
  4067.     tbc := box_count;
  4068.  
  4069.     {Calculate position of box}
  4070.     x := parse_int('/X=', mparm_str);
  4071.     y := parse_int('/Y=', mparm_str);
  4072.     if x <= 0 then
  4073.         x := 2;
  4074.     end;
  4075.     if y <= 0 then
  4076.         y := 3;
  4077.     end;
  4078.     Ds_Count := 0;
  4079.     Use_Ds := 0;
  4080.     new_box := TRUE;
  4081.  
  4082.     {Get file name.  If no path is specified, then assume the ME directory}
  4083.     tstr := parse_str('/F=', mparm_str);
  4084.     if get_path(tstr) = '' then
  4085.         IF user_id = '' THEN
  4086.             tstr := CAPS(me_path + tstr);
  4087.         ELSE
  4088.             tstr := CAPS(me_path + user_id + '.USR\' + tstr);
  4089.         END;
  4090.         IF switch_file( tstr ) = FALSE THEN
  4091.             return_str := Truncate_Path(tstr);
  4092.             RM('MakeUserPath /DF=1');
  4093.             tstr := return_str;
  4094.         END;
  4095.     end;
  4096.     tstr := CAPS(fexpand(tstr));
  4097.   error_level := 0;
  4098.   db_exists := Switch_File(Tstr);
  4099.   IF NOT(db_exists) THEN
  4100.         create_window;
  4101.         load_file( tstr );
  4102.         window_attr := $80;
  4103.         if error_level <> 0 then
  4104.             error_level := 0;
  4105.             file_name := tstr;
  4106.         end;
  4107.         IF parse_int('/NDF=', mparm_str) <> 0 THEN
  4108.             db_exists := TRUE;
  4109.         END;
  4110.   END;
  4111.     window_attr := $81;
  4112.     db_win := window_id;
  4113.     db_win_num := cur_window;
  4114.     header_win := window_id;
  4115.  
  4116.     {Check for a seperate header file}
  4117.     header_file := parse_str( '/HF=', mparm_str );
  4118.     if (header_file <> '') then
  4119.         if get_path(header_file) = '' then
  4120.             return_str := header_file;
  4121.             RM('MakeUserPath /DF=1');
  4122.             header_file := return_str;
  4123.         end;
  4124.         header_file := CAPS(fexpand(header_file));
  4125.         {If the header_file is not the same as the db file then load the header
  4126.             file}
  4127.         if header_file <> tstr then
  4128.       header_exists := Switch_File( header_file );
  4129.       IF NOT(header_exists) THEN
  4130.                 create_window;
  4131.                 load_file(header_file);
  4132.                 window_attr := $80;
  4133.                 if error_level <> 0 then
  4134.                     RM('MEERROR^Beeps /C=1');
  4135.                     goto exit2;
  4136.                 end;
  4137.             END;
  4138.             header_win := window_id;
  4139.         end;
  4140.     end;
  4141.  
  4142.   CALL find_page_lines;
  4143.  
  4144. {Parse out the Display String array}
  4145.     IF (Use_ds = false) THEN
  4146.         tstr := global_str( parse_str('/DS=', mparm_str ) );
  4147.         use_ds := tstr <> '';
  4148.         IF use_ds THEN
  4149.             DSG_Name := '#DBDS';
  4150.             Call BUILD_DS;
  4151.             DS_Count := Jz;
  4152.         END;
  4153.     END;
  4154.     need_rebuild := true;
  4155.     call build_fields;
  4156.  
  4157.     IF (Field_Count < 1) THEN
  4158.         goto exit2;
  4159.     END;
  4160.     tstr := global_str( 'DB#' + truncate_path(truncate_extension(file_name)) +
  4161.                                                             '^' + truncate_extension(parse_str('/DPT=', mparm_str)) );
  4162.  
  4163. {If the calling macro specified a starting choice, use that instead.}
  4164.     cur_item := parse_int('/S=',MParm_str);
  4165.     IF (Cur_Item < 1) THEN
  4166.         cur_item := parse_int('/S=',tstr);
  4167.     END;
  4168.     cur_row := parse_int('/OR=', tstr );
  4169.     if switch_win_id( db_win ) then
  4170.     end;
  4171.     first_display := FALSE;
  4172.  
  4173. main_loop:
  4174.     {Display the list of all of the fields}
  4175.  
  4176.     IF (No_List) THEN
  4177.         Goto NO_LIST;
  4178.     END;
  4179.     first_display := TRUE;
  4180.     call build_record_list;
  4181.     IF (Record_Count = 0) THEN
  4182.         IF (Parse_Int('/ENC=',MParm_Str)) THEN
  4183.             Search_Result := 0;
  4184.             Goto EXIT;
  4185.         END;
  4186.     END;
  4187.  
  4188.  
  4189.     {Exit from DB}
  4190.     if return_int = 0 then
  4191. NO_LIST_EXIT:
  4192.         IF switch_win_id( db_win ) THEN
  4193.         END;
  4194.         call set_db_global;
  4195.         goto exit2;
  4196.  
  4197.     {Modify was selected}
  4198.     elsif return_int = 4 THEN
  4199.         goto SKIP_NO_LIST;
  4200.  
  4201.     {Display selected record}
  4202.     elsif return_int = 1 then
  4203.         IF (List_Only) THEN
  4204.             IF parse_int( '/2TOP=', mparm_str ) AND NOT(read_only) THEN
  4205.                 call move_item_to_top;
  4206.             END;
  4207.             IF glo_str = '' THEN
  4208.                 Goto NO_LIST_EXIT;
  4209.             END;
  4210.         END;
  4211.  
  4212. NO_LIST:
  4213.         IF (No_List) THEN
  4214.             Return_Str := Parse_Str('/FV=',MParm_Str);
  4215.             call find_data;
  4216.             IF ((No_List = 1) and (Search_Result = 0)) THEN
  4217.                 IF ((Return_Record = True) or (List_Only = true)) THEN
  4218.                     Set_Global_Str(glo_str,Get_Line);
  4219.                     Goto EXIT;
  4220.                 END;
  4221.                 IF (Create = 0) THEN
  4222.                     IF (Parse_Str('/FV=',MParm_Str) = '') THEN
  4223.                         Goto DISPLAY_FIELDS;
  4224.                     END;
  4225.                     Goto EXIT2;
  4226.                 ELSE
  4227.                     Goto NO_LIST_CREATE;
  4228.                 END;
  4229.             END;
  4230.         END;
  4231. SKIP_NO_LIST:
  4232.         goto_line( end_field + cur_item );
  4233.  
  4234. display_fields:
  4235.         IF (return_int = 1) AND ((Return_Record = True) or (List_Only > 0)) THEN
  4236.             call set_db_global;
  4237.             Set_Global_Str(glo_str,Get_Line);
  4238.             Goto EXIT2;
  4239.         END;
  4240.  
  4241. display_fields2:
  4242.         IF mac_str <> '' THEN
  4243.             Set_Global_Str( glo_str, get_line );
  4244.             RM( mac_str + '/GLO=' + glo_str );
  4245.             IF global_str( glo_str ) <> get_line THEN
  4246.                 put_line( global_str( glo_str ) );
  4247.             END;
  4248.         END;
  4249.  
  4250.         call get_data;
  4251.  
  4252. {This stuff here will guarantee we will be able to compensate if lines in
  4253. a shared DB file are inserted or deleted while nested under DATA_IN}
  4254.         Mark_Pos;
  4255.         Set_Mark(1);
  4256.         IF (Header_Win = Db_Win) THEN
  4257.             Goto_Line(Header_Page_Line);
  4258.             Jy := C_Line;
  4259.             Mark_Pos;
  4260.         END;
  4261.         Get_Mark(1);
  4262.         Jx := C_Line;
  4263.  
  4264.         RM('USERIN^DATA_IN /X=' + str(x + 2) + '/Y=' + str(y + 2) +
  4265.             '/NC=1/T=' + Data_Title + '/A=2' +
  4266.             '/#=' + str(field_count) + '/PRE=' + Prefix + '/RGS=' +
  4267.             Parse_Str('/RGS=',MParm_Str));
  4268. {Relocate the file position in case anything has changed}
  4269.    { call Find_Page_Lines; }
  4270.  
  4271. {If, while in DATA_IN, lines above this line were inserted or deleted, this
  4272. will compensate}
  4273.         IF (Header_Win = DB_Win) THEN
  4274.             Goto_Mark;
  4275.             Header_Page_Line := Header_Page_Line + (c_line - Jy);
  4276.         END;
  4277.         Goto_Mark;
  4278.         End_Field := End_Field + (c_line - Jx);
  4279.         Data_Page_Line := Data_Page_Line + (c_line - Jx);
  4280.  
  4281.     call Set_Data_Page_Line;
  4282.         call set_data;
  4283.         return_str := global_str(Prefix + 'ISTR_1');
  4284.         IF (No_List) THEN
  4285.             Goto NO_LIST_EXIT;
  4286.         END;
  4287.  
  4288.     {Copy a record}
  4289.     elsif return_int = 5 THEN
  4290.         call check_read_only;
  4291.         IF read_only THEN
  4292.             goto main_loop;
  4293.         END;
  4294.         if (switch_win_id( db_win ) ) THEN
  4295.             goto_line(cur_item + end_field);
  4296.             Return_Str := parse_str(Delimit + parse_str('/DBF=',global_str(Prefix + 'IPARM_1')) + '=',Get_Line);
  4297.     END;
  4298.         RM('QUERYBOX /T=COPY A RECORD/P=' + Shorten_Str(parse_str('/T=' ,global_str(Prefix + 'IPARM_1'))) + ' /C=' + str(x + 2) +
  4299.                     '/L=' + str( y + 2 ) + '/W=' + parse_str('/W=' ,global_str(Prefix + 'IPARM_1')) +
  4300.                     '/ML=' + parse_str('/ML=' ,global_str(Prefix + 'IPARM_1')));
  4301.         IF return_int = 0 THEN
  4302.             goto main_loop;
  4303.     END;
  4304.         call copy_record;
  4305.         goto display_fields2;
  4306.  
  4307.     {Create new record.  Put it in the file in alphabetical order}
  4308.     elsif return_int = 2 then
  4309.         call check_read_only;
  4310.         IF read_only THEN
  4311.             goto main_loop;
  4312.         END;
  4313.         return_str := '';
  4314.         tstr3 := parse_str('/CP=', mparm_str);
  4315.         IF tstr3 <> '' THEN
  4316.             RM('QUERYBOX /T=CREATE NEW RECORD/P=' + tstr3 + '/C=' + str(x + 2) +
  4317.                         '/L=' + str( y + 2 ) + '/W=' + parse_str('/W=' ,global_str(Prefix + 'IPARM_1')) +
  4318.                         '/ML=' + parse_str('/ML=' ,global_str(Prefix + 'IPARM_1')));
  4319.             IF return_int = 0 THEN
  4320.                 goto main_loop;
  4321.             END;
  4322.         END;
  4323. NO_LIST_CREATE:
  4324.         tstr := Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1')) + '=' + return_str;
  4325. create2:
  4326.         call insert_record;
  4327.         goto display_fields2;
  4328.  
  4329. {Delete selected record}
  4330.     elsif return_int = 3 then
  4331.         IF (Record_Count = 0) THEN
  4332.                 Goto MAIN_LOOP;
  4333.         END;
  4334. {Check to see if this record is protected}
  4335.         IF (XPos('/PROTECT',MParm_Str,1)) THEN
  4336.             if (switch_win_id( db_win ) ) THEN
  4337.                 call check_read_only;
  4338.                 IF read_only THEN
  4339.                     goto main_loop;
  4340.                 END;
  4341.                 goto_line(cur_item + end_field);
  4342.                 Tstr := Caps(Parse_Str(Delimit + parse_str('/DBF=',global_str(Prefix + 'IPARM_1')) + '=',Get_Line));
  4343.                 Jx := 1;
  4344. CHECK_PROTECT:
  4345.                 Tstr3 := Caps(Parse_Str('/PROTECT' + Str(Jx) + '=',MParm_Str));
  4346.                 IF (Tstr3 <> '') THEN
  4347.                     IF (Tstr = Tstr3) THEN
  4348.                         RM('MEERROR^MessageBox /B=1/T=/M=This record is protected against deletion!');
  4349.                         Goto Main_loop;
  4350.                     ELSE
  4351.                         ++Jx;
  4352.                         Goto CHECK_PROTECT;
  4353.                     END;
  4354.                 END;
  4355.             end;
  4356.         END;
  4357.         RM('USERIN^VERIFY /T=Delete this record ?/H=' + Parse_Str('/H=',MParm_Str) +
  4358.                         '/C=' + str(x + 2 ) + '/L=' + str(y + 2) );
  4359.         IF return_int THEN
  4360.             call delete_record;
  4361.         END;
  4362. {print the list}
  4363.     elsif return_int = 6 then
  4364.         Print_Records := True;
  4365.         call build_record_list;
  4366. {search}
  4367.     elsif return_int = 20 then
  4368.  
  4369.     end;
  4370.  
  4371.     goto main_loop;
  4372.  
  4373.  
  4374. check_read_only:
  4375.     IF (read_only) THEN
  4376.         RM('MEERROR^MessageBox /B=1/T="' + file_name + '" IS LOCKED!/M=DB File is locked, no modifications will be allowed.');
  4377.     END;
  4378.     RET;
  4379.  
  4380. BUILD_DS:
  4381.     Jz := 0;
  4382.     jx := 0;
  4383.     DSG_Ints := '';
  4384. pd_loop:
  4385.     jx := xpos( delimit, tstr, jx + 1);
  4386.     if jx <> 0 THEN
  4387.         ++Jz;
  4388.         jy := xpos('=', tstr, jx + 1 );
  4389.         tstr2 := copy( tstr, jx, jy - jx + 1 );
  4390.         Set_Global_Str( str(Jz) + DSG_Name, tstr2 );
  4391.         jx := jy;
  4392.         DSG_Ints := DSG_Ints + CHAR( parse_int( tstr2, tstr ) );
  4393.         {Set_Global_Int( str(Jz) + DSG_Name, parse_int( tstr2, tstr ));}
  4394.         goto pd_loop;
  4395.     END;
  4396.     RET;
  4397.  
  4398. {Searches for the specified record, according to field 1}
  4399. find_data:
  4400.     if switch_win_id( db_win ) then
  4401.     end;
  4402.     goto_line(end_field);
  4403.     goto_col(1);
  4404. search_again:
  4405.     Search_Result := search_fwd(Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1')) + '=' + return_str, 0);
  4406.     IF (search_result <> 0) AND (caps(
  4407.             parse_str( Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1')) + '=', get_line ))
  4408.                     <> caps( return_str )) THEN
  4409.         eol;
  4410.         Goto search_again;
  4411.     END;
  4412.     if (Search_Result = 0) then
  4413.         Goto_line(end_field + 1);
  4414.     end;
  4415.     cur_item := c_line - end_field;
  4416.     ret;
  4417.  
  4418. {Retrieves the data in the current record and puts it into a DATA_IN compatible
  4419.  globals}
  4420. get_data:
  4421.     jx := 0;
  4422.     tstr := get_line;
  4423.     while jx < field_count do
  4424.         ++jx;
  4425.         TStr3 := global_str(Prefix + 'IPARM_' + str(jx));
  4426.         tp := parse_int('/TP=', Tstr3);
  4427. {Assign to a special global if one exists for this field.  Originally created
  4428. for format line initialization.}
  4429.         IF (XPos('/GSTR=',Tstr3,1)) THEN
  4430.             IF ((parse_str(Delimit + parse_str('/DBF=', Tstr3) +
  4431.                 '=',tstr ) <> '') or (Parse_Int('/GSET=',Tstr3) > 0)) THEN
  4432.                 Set_Global_Str( Parse_Str('/GSTR=',Tstr3),
  4433.                     parse_str(Delimit + parse_str('/DBF=',TStr3) + '=',TStr));
  4434.             END;
  4435.         END;
  4436.         if ((tp = 0) or (Tp = 6) or ((tp = 8) and (Parse_Str('/ISTR=',TStr3) = ''))) then
  4437.                 set_global_str(Prefix + 'ISTR_' + str(jx),
  4438.                     parse_str(Delimit + parse_str('/DBF=',Tstr3) + '=',
  4439.                     tstr ));
  4440.         elsif (tp = 1) or (tp = 3) or (tp = 4) or (tp = 5) or (tp = 7) or (tp = 9) then
  4441.                 set_global_int(Prefix + 'IINT_' + str(jx),
  4442.                     parse_int(Delimit + parse_str('/DBF=',TStr3) + '=',
  4443.                     tstr ));
  4444.         end;
  4445.     end;
  4446.     ret;
  4447.  
  4448. delete_record:
  4449.     if switch_win_id( db_win ) then
  4450.         call check_read_only;
  4451.         IF read_only THEN
  4452.             ret;
  4453.         END;
  4454.         goto_line( cur_item + end_field );
  4455.         del_line;
  4456.         --record_count;
  4457.         if switch_win_id( build_win ) THEN
  4458.             del_line;
  4459.             call set_max_width;
  4460.         END;
  4461.         if switch_win_id( db_win ) THEN
  4462.         END;
  4463.         if AT_EOF then
  4464.             --cur_item;
  4465.         end;
  4466.         IF record_count < (screen_length - 3) THEN
  4467.             new_box := TRUE;
  4468.         END;
  4469.     end;
  4470.     ret;
  4471.  
  4472. copy_record:
  4473.     if (switch_win_id( db_win ) ) THEN
  4474.         call check_read_only;
  4475.         IF read_only THEN
  4476.             ret;
  4477.         END;
  4478.         goto_line(cur_item + end_field);
  4479.         tstr := get_line;
  4480. {Place the prompted for first field value in place of the original for the copy}
  4481.         Tstr3 := Delimit + parse_str('/DBF=',global_str(Prefix + 'IPARM_1')) + '=';
  4482.         Tstr := Tstr3 + Return_Str + Copy(Tstr,
  4483.                         Length(parse_str(Tstr3,tstr )) + Svl(Tstr3) + 1,2048);
  4484.         call insert_record;
  4485.     end;
  4486.     ret;
  4487.  
  4488.     {Inserts the record contained in tstr into the file at the current position}
  4489. insert_record:
  4490.     if (switch_win_id( db_win ) ) THEN
  4491.         call check_read_only;
  4492.         IF read_only THEN
  4493.             ret;
  4494.         END;
  4495.         goto_line(cur_item + end_field);
  4496.         goto_col(1);
  4497.         IF NOT(AT_EOF) THEN
  4498.             eol;
  4499.             Insert_Mode := True;
  4500.             cr;
  4501.         END;
  4502.         ++record_count;
  4503.         call Put_Line_Here;
  4504.         IF record_count < (screen_length - 3) THEN
  4505.             new_box := TRUE;
  4506.         END;
  4507.     END;
  4508.     ret;
  4509.  
  4510. {Takes the current record out of the DATA_IN globals and puts it in the file}
  4511. set_data:
  4512.     call check_read_only;
  4513.     IF read_only THEN
  4514.         ret;
  4515.     END;
  4516.     jx := 0;
  4517.     tstr := '';
  4518.     while jx < field_count do
  4519.         ++jx;
  4520.         TStr3 := global_str(Prefix + 'IPARM_' + str(jx));
  4521.         tp := parse_int('/TP=', Tstr3);
  4522.  
  4523. {If we are supposed to use a special global instead of the ISTR, do that}
  4524.         IF (XPos('/GSTR=',Tstr3,1)) THEN
  4525.             IF (Global_Str( Parse_Str('/GSTR=',Tstr3)) <> '') THEN
  4526.                 tstr := tstr + Delimit + parse_str('/DBF=',Tstr3) + '=' +
  4527.                             Global_Str(Parse_Str('/GSTR=',Tstr3));
  4528.             END;
  4529.             Goto BYPASS_SET;
  4530.         END;
  4531.         if (tp = 0) or (Tp = 6) or (tp = 8) then
  4532.             if global_str(Prefix + 'ISTR_' + str(jx)) <> '' then
  4533.                 tstr := tstr + Delimit + parse_str('/DBF=', tstr3 ) + '=' +
  4534.                             global_str(Prefix + 'ISTR_' + str(jx));
  4535.             end;
  4536.         end;
  4537.         IF (tp = 3) THEN
  4538.             IF global_int( prefix + 'IINT_' + str(jx)) = 0 THEN
  4539.                 set_global_int( prefix + 'IINT_' + str(jx), 1);
  4540.             END;
  4541.         END;
  4542.         if (tp = 1) or (tp = 3) or (tp = 4) or (tp = 5) or (tp = 7) or (tp = 9) then
  4543.             if global_int(Prefix + 'IINT_' + str(jx)) <> 0 then
  4544.                 tstr := tstr + Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_' + str(jx))) + '=' +
  4545.                             str(global_int(Prefix + 'IINT_' + str(jx)));
  4546.             end;
  4547.         end;
  4548. BYPASS_SET:
  4549.     end;
  4550.     IF mac_str <> '' THEN
  4551.         Set_Global_Str( glo_str, tstr );
  4552.         Set_Global_Int('@DB_NEED_REBUILD!',0);
  4553.         RM( mac_str + '/P=1/GLO=' + glo_str );
  4554.         tstr := global_str( glo_str );
  4555.         Need_Rebuild := Global_Int('@DB_NEED_REBUILD!');
  4556.     END;
  4557.     if (tstr <> get_line) then
  4558.         del_line;
  4559.  
  4560. {This entry point is only used by CREATE}
  4561. set_data2:
  4562.         if switch_win_id( build_win ) THEN
  4563.             goto_line( cur_item );
  4564.             del_line;
  4565.         END;
  4566. set_data3:
  4567.         switch_win_id( db_win );
  4568.         Goto_Col(1);
  4569.         IF (No_Alpha) THEN
  4570.             Goto_Line(End_Field + Cur_Item);
  4571.         ELSE
  4572.             goto_line(end_field+1);
  4573.             goto_col(1);
  4574.             tstr2 := Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1')) + '=';
  4575.             tstr3 := caps(parse_str(tstr2,tstr));
  4576.             while not(at_eof) and (caps(parse_str(tstr2,get_line)) < tstr3) AND
  4577.                 (Cur_Char <> '|12') do
  4578.                 down;
  4579.             end;
  4580.         END;
  4581.         if not(at_eof) then
  4582.             Insert_Mode := True;
  4583.             cr;
  4584.             up;
  4585.         end;
  4586.  
  4587. put_line_here:
  4588.         call check_read_only;
  4589.         IF read_only THEN
  4590.             ret;
  4591.         END;
  4592.  
  4593.         put_line(tstr);
  4594.         cur_item := c_line - end_field;
  4595.         tstr := Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1') ) + '=';
  4596.         DSG_Name := '#DBDS';
  4597.         call parse_ds;
  4598.         if switch_win_id( build_win ) THEN
  4599.             goto_line( cur_item );
  4600.             goto_col( 1 );  set_indent_level;
  4601.             Insert_Mode := True;
  4602.             cr;
  4603.             up;
  4604.             put_line( tstr3 );
  4605.             IF svl( tstr3 ) > max_width THEN
  4606.                 max_width := svl( tstr3 );
  4607.                 new_box := true;
  4608.             END;
  4609.         END;
  4610.         if switch_win_id( db_win ) THEN
  4611.         END;
  4612.  
  4613.      {need_rebuild := true;}
  4614.     end;
  4615.     ret;
  4616.  
  4617. {Takes the file header that defines the fields and builds DATA_IN compatible
  4618.  global parameter variables.}
  4619. build_fields:
  4620.     Set_Global_Str(Prefix + 'IHELP1','');
  4621.     Set_Global_Str(Prefix + 'IHELP2','');
  4622.     Set_Global_Str(Prefix + 'IHELP3','');
  4623.     tp_str := '';
  4624.     if switch_win_id( header_win ) then
  4625.         field_count := 0;
  4626.         Goto_Line( header_page_line + 1);
  4627.     floop:
  4628.         tstr := get_line;
  4629.         if (tstr = '****START****') or (At_Eof) then
  4630.             end_field := c_line;
  4631.             goto floop_exit;
  4632.         end;
  4633.         IF str_char(tstr,1) = '|12' THEN
  4634.             IF svl(tstr) > 0 THEN
  4635.                 end_field := c_line;
  4636.                 goto floop_exit;
  4637.             END;
  4638.         END;
  4639.  
  4640. {This is for the new stuff for printer string and display string being in the
  4641.  header}
  4642.         IF (XPos('@',TStr,1) = 1) THEN
  4643.             IF (XPos('@DISPLAY_STRING=',TStr,1) = 1) THEN
  4644.                 IF NOT( use_ds ) THEN
  4645.                     Set_Global_Str('#DBDS@' + Str(Global_Int('MENU_LEVEL')),
  4646.                                                     Copy(TStr,17,2048));
  4647.                     TStr := Copy(TStr,17,2048);
  4648.                     DSG_Name := '#DBDS';
  4649.                     Call BUILD_DS;
  4650.                     Ds_Count := Jz;
  4651.                     use_ds := true;
  4652.                 END;
  4653.             ELSIF (XPos('@PRINTER_STRING=',TStr,1) = 1) THEN
  4654.                 Set_Global_Str('#DBPS@' + Str(Global_Int('MENU_LEVEL')),
  4655.                                                 Copy(TStr,17,2048));
  4656.                 use_Ps := true;
  4657.             ELSIF (XPos('@IHELP',TStr,1) = 1) THEN
  4658.                 Set_Global_Str(Prefix + Copy(Tstr,2,6),Copy(TStr,9,2048));
  4659.             END;
  4660.             Goto other_data;
  4661.         END;
  4662.  
  4663.         ++field_count;
  4664.         set_global_str(Prefix + 'IPARM_' + str(field_count), tstr);
  4665.  
  4666.         IF (Parse_Int('/TP=',Tstr) = 5) THEN
  4667. {This is to accomodate the type 5 true/false.}
  4668.                 set_global_str(Prefix + 'ISTR_' + str(field_count), Copy(tstr,XPos('/ISTR=',Tstr,1) + 6,255));
  4669.         ELSE
  4670.                 set_global_str(Prefix + 'ISTR_' + str(field_count), parse_str('/ISTR=', tstr));
  4671.         END;
  4672.  
  4673.         set_global_int(Prefix + 'IINT_' + str(field_count), parse_int('/IINT=', tstr));
  4674. {Save a special string which ties the /TP= with the /DBF= for use by PARSE_DS}
  4675.         tp_str := tp_str + Delimit + Parse_Str('/DBF=', tstr) + '=' + Parse_Str('/TP=',Tstr);
  4676. other_data:
  4677.         down;
  4678.         goto floop;
  4679.  
  4680.     floop_exit:
  4681.     end;
  4682.  
  4683. set_data_page_line:
  4684.     if (db_win <> header_win) OR (data_page_line <> 0) then
  4685.         IF (data_page_line = header_page_line) AND (db_win = header_win) THEN
  4686.             data_page_line := end_field;
  4687.         END;
  4688.         end_field := data_page_line;
  4689.     end;
  4690.     IF (Field_Count < 1) THEN
  4691.         RM('MEERROR^Beeps /C=1');
  4692.         RM('MEERROR^MessageBox /B=1/T=NO HEADER/M=Header in "' + file_name + '" or file not found!  Cannot display menu.');
  4693.     END;
  4694.     switch_win_id( db_win );
  4695.     ret;
  4696.  
  4697. {Builds the Variable Length Menu that lists all of the records by their
  4698.  first field}
  4699. build_record_list:
  4700.  
  4701.     IF (Print_Records) THEN
  4702. {Open the printer device/file}
  4703.         IF use_ps THEN
  4704.             temp_use_ds := use_ds;
  4705.             use_ds := true;
  4706.             tstr := Global_Str('#DBPS@' + Str(Global_Int('MENU_LEVEL')));
  4707.             Call BUILD_DS;
  4708.             DS_Count := Jz;
  4709.         END;
  4710.         RM('MEUTIL3^OPEN_CLOSE_FILE /M=1/FN=' + Global_Str('PRINTER_DEVICE'));
  4711.         IF (Error_Level) THEN
  4712.             RM('MEERROR');
  4713.             RET;
  4714.         ELSE
  4715.             Handle := Return_Int;
  4716.         END;
  4717.         PP_Str := ' /S=1';
  4718.         switch_win_id( build_win );
  4719.         Jx := Cur_Window;
  4720.         Goto print_it;
  4721.     END;
  4722.  
  4723.     if build_win = 0 then
  4724.         switch_window(window_count);
  4725.         create_window;
  4726.         window_attr := $80;
  4727.         build_win := window_id;
  4728.         build_win_num := cur_window;
  4729.     end;
  4730.  
  4731.     if switch_win_id( build_win ) then
  4732.         jx := cur_window;
  4733.         old_width := max_width;
  4734.         if (need_rebuild) then
  4735.             working;
  4736.             need_rebuild := FALSE;
  4737.             erase_window;
  4738.             max_width := 13;
  4739. print_it:
  4740.             if switch_win_id( db_win ) then
  4741.                 jy := cur_window;
  4742.                 goto_col(1);
  4743.                 goto_line(end_field + 1);
  4744.                 tstr := Delimit + parse_str('/DBF=', global_str(Prefix + 'IPARM_1') ) + '=';
  4745.  
  4746.                 record_count := 0;
  4747.  
  4748. {        Ticks := MemP($46C);  }
  4749.  
  4750.                 DSG_Name := '#DBDS';
  4751.                 while not(at_eof) AND (cur_char <> '|12') do
  4752.  
  4753.                         ++record_count;
  4754.  
  4755. {This will detect a "Skip_Over" situation}
  4756.                     IF (XPos(Delimit + '@|254=',Get_Line,1)) THEN
  4757.                         TStr3 := Parse_Str(Delimit + '@|254=',Get_Line) + '|254';
  4758.                         jz := svl(tstr3) - 1;
  4759.                     ELSE
  4760.                         call parse_ds;
  4761.                         jz := svl(tstr3);
  4762.                     END;
  4763.  
  4764.                     IF (Print_Records) THEN
  4765.                         Return_Str := TStr3 + '|13|10';
  4766.                         RM('MEUTIL3^PRINTSTR' + PP_Str + '/H=' + Str(Handle));
  4767.                         PP_Str := ' ';
  4768.                         IF (Error_Level) THEN
  4769.                             RM('MEERROR');
  4770.                             RET;
  4771.                         END;
  4772.                     ELSE
  4773.                         put_line_to_win( tstr3, record_count, build_win_num, false );
  4774.                     END;
  4775.                     down;
  4776.                     IF Not(Print_Records) THEN
  4777.                         if jz > max_width then
  4778.                             max_width := jz;
  4779.                         end;
  4780.                     END;
  4781.                 end;
  4782.  
  4783. {Make_Message('[' + Str(Memp($46C) - Ticks) + ']' + str(ticks));}
  4784.  
  4785.                 IF (Print_Records) THEN
  4786.             {Close the printer device/file}
  4787.           RM('MEUTIL3^OPEN_CLOSE_FILE /H=' + Str(Handle));
  4788.                     IF (Error_Level) THEN
  4789.                         RM('MEERROR');
  4790.                     END;
  4791.                     Print_Records := False;
  4792.                     use_ds := TEMP_USE_DS;
  4793.                     IF use_ds THEN
  4794.                         tstr := Global_Str('#DBDS@' + Str(Global_Int('MENU_LEVEL')));
  4795.                         Call BUILD_DS;
  4796.                         DS_Count := Jz;
  4797.                     END;
  4798.                     Need_Rebuild := TRUE;
  4799.                     RET;
  4800.                 END;
  4801.             end;
  4802.         end;
  4803.         IF max_width < 20 THEN
  4804.             max_width := 20;
  4805.             new_box := true;
  4806.         END;
  4807.         IF old_width <> max_width THEN
  4808.             new_box := true;
  4809.         END;
  4810.         IF cur_item > record_count then
  4811.             cur_item := 1;
  4812.         END;
  4813.         IF new_box THEN
  4814.             while (box_count > tbc) do
  4815.                 kill_box;
  4816.             end;
  4817.         end;
  4818.         switch_window(jx);
  4819.         IF (Record_Count = 0) THEN
  4820.             IF (Parse_Int('/ENC=',MParm_Str)) THEN
  4821.                 Ret;
  4822.             END;
  4823.         END;
  4824.         update_status_line;
  4825.         IF ((list_only > 0) and (list_only < 3)) THEN
  4826.             Set_Global_Str('@DBEV1', '/T=Select/K1=13/K2=28/R=1/LL=1');
  4827.             Set_Global_Str('@DBEV2', '/T=Cancel/K1=27/K2=1/R=0/LL=1');
  4828.         ELSE
  4829.             Set_Global_Str('@DBEV1', '/T=Select/K1=13/K2=28/R=1/LL=1');
  4830.             Set_Global_Str('@DBEV2', '/T=Done/K1=27/K2=1/R=0/LL=1');
  4831.         END;
  4832.  
  4833. {This overrides events 1 or 2}
  4834.         IF (Parse_Str('/EV1=',MParm_Str) <> '') THEN
  4835.             Set_Global_Str('@DBEV1', Global_Str(Parse_Str('/EV1=',MParm_Str)));
  4836.         END;
  4837.         IF (Parse_Str('/EV2=',MParm_Str) <> '') THEN
  4838.             Set_Global_Str('@DBEV2', Global_Str(Parse_Str('/EV2=',MParm_Str)));
  4839.         END;
  4840.         Ev_Count := 2;
  4841.  
  4842.         IF (Parse_Int('/NI=',MParm_Str) = 0) THEN
  4843.             ++Ev_Count;
  4844.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Create/K1=0/K2=82/R=2');
  4845.         END;
  4846.         IF (Parse_Int('/ND=',MParm_Str) = 0) THEN
  4847.             ++Ev_Count;
  4848.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Delete/K1=0/K2=83/R=3');
  4849.         END;
  4850.         IF (Parse_Int('/NC=',MParm_Str) = 0) THEN
  4851.             ++Ev_Count;
  4852.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Copy/K1=0/K2=62/R=5/FL=Copy');
  4853.         END;
  4854.         IF (Parse_Int('/NE=',MParm_Str) = 0) THEN
  4855.             ++Ev_Count;
  4856.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Edit/K1=0/K2=61/R=4/FL=Edit');
  4857.         END;
  4858.         IF (Parse_Int('/SRP=',MParm_Str) <> 0) THEN
  4859.             ++Ev_Count;
  4860.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Search/K1=0/K2=64/R=20/FL=Search');
  4861.         END;
  4862.         IF (Use_Ps) THEN
  4863.             ++Ev_Count;
  4864.             Set_Global_Str('@DBEV' + Str(Ev_Count), '/T=Print/K1=0/K2=66/R=6/FL=Print');
  4865.         END;
  4866.  
  4867.         IF (Parse_Int('/NB=',MParm_Str)) THEN
  4868.             New_Box := 0;
  4869.         END;
  4870.         RM('USERIN^WMENU /X=' + str(x) + '/Y=' + str(y) +
  4871.                 '/DBL=1/S=' + str(cur_item) +
  4872.                 '/OR=' + str( cur_row ) +
  4873.                 '/W=' + str( max_width ) +
  4874.                 '/T=' + List_Title +
  4875.                 '/H=' + Parse_Str('/H=',MParm_Str) +
  4876.                 '/NB=' + str(new_box = 0) +
  4877.                 '/EV=@DBEV/EV#=' + Str(Ev_Count) +
  4878.                 '/NK=1' );
  4879.         new_box := false;
  4880.         cur_item := c_line;
  4881.         cur_row := c_row;
  4882.         return_str := get_line;
  4883.         switch_win_id( db_win );
  4884.     end;
  4885.     ret;
  4886.  
  4887. {This routine parses out the display line from the data line}
  4888. parse_ds:
  4889.     IF NOT(use_ds) THEN
  4890.         tstr3 := parse_str(tstr, get_line);
  4891.         Goto PARSE_DS_EXIT;
  4892.     END;
  4893.  
  4894.     tstr3 := '';
  4895.     tstr := get_line;
  4896.     tint := 0;
  4897.     WHILE tint < ds_count DO
  4898.         ++tint;
  4899.         tint2 := ASCII( str_char( dsg_ints, tint ) );
  4900.  
  4901.         IF tint2 = 0 THEN
  4902.             IF (Parse_Int(GLOBAL_STR(str( tint ) + DSG_NAME),tp_str) = 9) THEN
  4903. {This is to properly display keystroke fields}
  4904.         RM('SETUP^MAKEKEY /K1=' + Str(parse_int(GLOBAL_STR(str(tint) + DSG_NAME), tstr) and $FF) + '/K2=' +
  4905.                     Str((parse_int(GLOBAL_STR(str(tint) + DSG_NAME), tstr) shr 8) and $FF));
  4906.                 tstr3 := tstr3 + return_str + ' ';
  4907.             ELSE
  4908.                 tstr3 := tstr3 + parse_str( GLOBAL_STR(str( tint ) + DSG_NAME), tstr ) + ' ';
  4909.             END;
  4910.         ELSE
  4911.             IF (Parse_Int(GLOBAL_STR(str( tint ) + DSG_NAME),tp_str) = 9) THEN
  4912. {This is to properly display keystroke fields}
  4913.         RM('SETUP^MAKEKEY /K1=' + Str(parse_int(GLOBAL_STR(str(tint) + DSG_NAME), tstr) and $FF) + '/K2=' +
  4914.                     Str((parse_int(GLOBAL_STR(str(tint) + DSG_NAME), tstr) shr 8) and $FF));
  4915.                 Tstr2 := COPY(Return_Str,1,tint2);
  4916.             ELSE
  4917.                 tstr2 := COPY(parse_str( GLOBAL_STR(str( tint ) + DSG_NAME), tstr ), 1, tint2 );
  4918.             END;
  4919.             tstr3 := tstr3 + tstr2 +
  4920.                 copy(
  4921.                     '                                                                                ',
  4922.                     1, tint2 - svl(tstr2) );
  4923.         END;
  4924.     END;
  4925.  
  4926. PARSE_DS_EXIT:
  4927.  
  4928.     IF (Tstr3 = '') THEN
  4929. {Expand the null string so it will work right with WMENU}
  4930.         Tstr3 := ' ';
  4931.     END;
  4932.     ret;
  4933.  
  4934.  
  4935. {Goes through the display file and resets the maximum width}
  4936. set_max_width:
  4937.     MARK_POS;
  4938.     tof;
  4939.     max_width := 17;
  4940.     while NOT( at_eof ) DO
  4941.         tstr := get_line;
  4942.         jz := svl(tstr);
  4943.         IF str_char( tstr, jz ) = '|254' THEN
  4944.             --jz;
  4945.         END;
  4946.         if jz > max_width THEN
  4947.             max_width := jz;
  4948.         END;
  4949.         down;
  4950.     END;
  4951.     tof;
  4952.   ret;
  4953.  
  4954.  
  4955. move_item_to_top:
  4956.     switch_win_id( db_win );
  4957.     Goto_Line(End_Field + Cur_Item);
  4958.     tstr := get_line;
  4959.     del_line;
  4960.     goto_line( end_field);
  4961.     eol;
  4962.     Insert_Mode := true;
  4963.     cr;
  4964.     put_line( tstr );
  4965.     cur_item := 1;
  4966.     ret;
  4967.  
  4968.  
  4969. find_page_lines:
  4970.     End_Field := 0;
  4971.     header_page_line := 0;
  4972.     data_page_line := 0;
  4973.     tstr := parse_str('/HPT=', mparm_str);
  4974.     IF tstr <> '' THEN
  4975.         switch_win_id( header_win );
  4976.         tof;
  4977.         IF search_fwd('%|12' + tstr + '$',0) THEN
  4978.             header_page_line := c_line;
  4979.             IF search_fwd('%@*@*@*@*START@*@*@*@*$',0) THEN
  4980. {Look for end of header}
  4981.                 End_Field := c_line;
  4982.             END;
  4983.         END;
  4984.     END;
  4985.  
  4986.     tstr := parse_str('/DPT=', mparm_str);
  4987.     IF tstr <> '' THEN
  4988.         switch_win_id( db_win );
  4989.         tof;
  4990.         IF search_fwd('%|12' + tstr + '$',0) THEN
  4991.             data_page_line := c_line;
  4992.             IF header_page_line = 0 THEN
  4993.                 header_page_line := data_page_line;
  4994.                 IF search_fwd('%@*@*@*@*START@*@*@*@*$',0) THEN
  4995.     {Look for end of header}
  4996.                     End_Field := c_line;
  4997.                 END;
  4998.             END;
  4999.         ELSIF header_page_line <> 0 THEN
  5000.             EOF;
  5001.             EOL;
  5002.             Insert_mode := true;
  5003.             CR;
  5004.             TEXT('|12'+ tstr );
  5005.             data_page_line := c_line;
  5006.         END;
  5007.     END;
  5008.   RET;
  5009.  
  5010. set_db_global:
  5011.     set_global_str( 'DB#' + truncate_path(truncate_extension(file_name))+
  5012.                                     '^' +
  5013.                                     truncate_extension(parse_str('/DPT=', mparm_str)),
  5014.                                     '/S=' + Str(cur_item) + '/OR=' + str(cur_row) );
  5015.     ret;
  5016.  
  5017.  
  5018. exit:
  5019.     Return_Int := Search_Result - 1;
  5020. exit2:
  5021.  
  5022.     jx := 0;
  5023.     WHILE jx < ds_count DO
  5024.         ++jx;
  5025.         SET_GLOBAL_INT( str( jx ) + '#DBDS', 0 );
  5026.     END;
  5027.  
  5028.         Set_Global_Str('#DBPS@' + Str(Global_Int('MENU_LEVEL')),'');
  5029.         Set_Global_Str('#DBDS@' + Str(Global_Int('MENU_LEVEL')),'');
  5030.  
  5031.     Set_Global_Str(Prefix + 'IHELP1','');
  5032.     Set_Global_Str(Prefix + 'IHELP2','');
  5033.     Set_Global_Str(Prefix + 'IHELP3','');
  5034.  
  5035.     jx := 0;
  5036.     while jx < field_count do
  5037.         ++jx;
  5038.         set_global_str(Prefix + 'IPARM_' + str(jx), '');
  5039.         set_global_str(Prefix + 'ISTR_' + str(jx), '');
  5040.         set_global_int(Prefix + 'IINT_' + str(jx), 0);
  5041.         Set_Global_Str(Prefix + 'DB_GSTR' + Str(jx),'');
  5042.     end;
  5043.     IF (parse_int('/NK=',MParm_str)) THEN
  5044.         ++tbc
  5045.     END;
  5046.     while box_count > tbc do
  5047.         kill_box;
  5048.     end;
  5049.  
  5050.     if switch_win_id( db_win ) then
  5051.         set_global_int('@DB_FILE_CHANGED', file_changed );
  5052.         if ((file_changed = true) and (Parse_Int('/NSF=',MParm_Str) = false)) then
  5053.             save_file;
  5054.         end;
  5055.     IF NOT( db_exists ) THEN
  5056.       delete_window;
  5057.     END;
  5058.     end;
  5059.  
  5060.     if (db_win <> header_win) AND switch_win_id( header_win ) then
  5061.     IF NOT( header_exists ) THEN
  5062.       delete_window;
  5063.     END;
  5064.     end;
  5065.  
  5066.     if switch_win_id( build_win ) then
  5067.         delete_window;
  5068.     end;
  5069.  
  5070.     switch_win_id(old_win);
  5071.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  5072.     Backups := Old_Backups;
  5073.     Insert_Mode := T_Insert_Mode;
  5074.     Truncate_Spaces := T_Truncate_Spaces;
  5075.     Refresh := T_Refresh;
  5076.   update_status_line;
  5077. END_MACRO;
  5078.  
  5079. {*******************************MULTI-EDIT MACRO******************************
  5080.  
  5081. Name: SetConfig
  5082.  
  5083. Description: Loads up the specified DB file (if it is not already
  5084.                         loaded), and then searches for the specified page title.
  5085.  
  5086. Returns:        RETURN_INT = 1 IF the title was found,
  5087.                                                  0 If NOT found.
  5088.  
  5089. Parameters:        /DB=str        The db file name.
  5090.                             /T=str        The page Title.
  5091.                             /C=int        1 = Create page if not found.
  5092.  
  5093.                (C) Copyright 1989 by American Cybernetics, Inc.
  5094. ******************************************************************************}
  5095. $MACRO SetConfig FROM ALL;
  5096.     def_str( tstr[40] );
  5097.  
  5098.     return_str := parse_str('/DB=', mparm_str);
  5099.     IF user_id = '' THEN
  5100.         tstr := '';
  5101.     ELSE
  5102.         tstr := me_path + user_id + '.USR\';
  5103.     END;
  5104.     IF switch_file( CAPS( tstr + return_str ) ) THEN
  5105.         return_str := tstr + return_str;
  5106.         error_level := 0;
  5107.     ELSE
  5108.         RM('MakeUserPath /DF=1');
  5109.         error_level := 0;
  5110.         IF NOT( switch_file( return_str ) ) THEN
  5111.             Switch_Window( window_count );
  5112.             Create_Window;
  5113.             Load_File( Return_Str );
  5114.             window_attr := $81;
  5115.         END;
  5116.     END;
  5117.     RETURN_INT := 1;
  5118.     IF error_level = 0 THEN
  5119.         tstr := parse_str('/T=', mparm_str );
  5120.         reg_exp_stat := TRUE;
  5121.         IF tstr <> '' THEN
  5122.             TOF;
  5123.             IF NOT(Search_Fwd( '%|12' + tstr + '$' ,0)) THEN
  5124.                 RETURN_INT := 0;
  5125.                 IF parse_int( '/C=', mparm_str ) THEN
  5126.                     EOF;
  5127.                     Insert_mode := true;
  5128.                     IF c_col > 1 THEN
  5129.                         CR;
  5130.                     END;
  5131.                     TEXT( '|12' + tstr );
  5132.                     RETURN_INT := 1;
  5133.                 END;
  5134.             END;
  5135.         END;
  5136.     ELSE
  5137.         RETURN_INT := 0;
  5138.     END;
  5139. END_MACRO;
  5140.  
  5141. $MACRO EDITWINDOW;
  5142. {*******************************MULTI-EDIT MACRO******************************
  5143.  
  5144. Name: EditWindow
  5145.  
  5146. Description: Creates an editable window for inputing multiple lines of text.
  5147.             Uses the current window.  If you only want the text to be examined,
  5148.             not edited, then set the READ_ONLY switch to TRUE before calling
  5149.             EDITWINDOW.
  5150.  
  5151.  
  5152. Parameters:   /X=nn         X position
  5153.                             /Y=nn         Y position
  5154.                             /W=nn         Width
  5155.                             /L=nn         Length
  5156.                             /T=str        Title string.
  5157.                             /WW=                    1 = enable word wrap.
  5158.                             /RM=                    Right margin for wordwrap.  Defaults to 2048.
  5159.                             /CC=                    If 1, line changed color will be M_S_Color else
  5160.                                                         M_T_Color.
  5161.                             /NK=nn        1 = Don't kill box when done.
  5162.                             /H=str        Help string.
  5163.                             /NB=                    1 = Don't create a box.
  5164.                             /SP=                    1 = enable <AltS> to do a spell check.
  5165.                             /SE=                    1 = enable <F6> to do a search.
  5166.                             /EV1=                    Name of event global string to add.
  5167.  
  5168.                              (C) Copyright 1989 by American Cybernetics, Inc.
  5169. ******************************************************************************}
  5170.  
  5171.     DEF_INT( jx, ev_count, x, y, w, l ,T_Mode,Extra_Event, evw );
  5172.     DEF_STR( event_str[20], allowed_extended_keys[100] ,Extra_Name[20]);
  5173.  
  5174.     refresh := FALSE;
  5175.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') + 1);
  5176.     Extra_Event := false;
  5177.     Extra_Name := Parse_Str('/EV1=',MParm_Str);
  5178.     T_Mode := Mode;
  5179.     Mode := Edit;
  5180.     allowed_extended_keys :=
  5181.         '|83|72|80|77|75|71|79|116|115|119|117|73|81|132|118';
  5182.     x := parse_int('/X=', mparm_str );
  5183.     y := parse_int('/Y=', mparm_str );
  5184.     w := parse_int('/W=', mparm_str );
  5185.     l := parse_int('/L=', mparm_str );
  5186.     if x = 0 THEN
  5187.         x := 1;
  5188.     END;
  5189.     if y = 0 then
  5190.         y := 3;
  5191.     END;
  5192.     IF w = 0 THEN
  5193.         w := 40;
  5194.     END;
  5195.     if l = 0 THEN
  5196.         l := 10;
  5197.     END;
  5198.     push_labels;
  5199.  
  5200.     call test_box_size;
  5201.     call set_events;
  5202.  
  5203.     IF (x + return_int) >= screen_width THEN
  5204.         x := screen_width - return_int - 1;
  5205.         call test_box_size;
  5206.         call set_events;
  5207.     END;
  5208.  
  5209.     set_virtual_display;
  5210.     IF (Parse_Int('/NB=',MParm_Str) = 0) THEN
  5211.         Put_Box( x, y, x + w + 2, y + l + 1, 0, m_b_color, parse_str('/T=', mparm_str), TRUE );
  5212.     END;
  5213.     Size_Window( x, y, x + w, y + l );
  5214.     Window_Attr := $86;
  5215.     t_color := m_t_color;
  5216.     IF (Parse_Int('/CC=',MParm_Str)) THEN
  5217.         c_color := m_s_color;
  5218.     ELSE
  5219.         c_color := m_t_color;
  5220.     END;
  5221.     s_color := m_s_color;
  5222.     eof_color := m_s_color;
  5223.     h_color := m_h_color;
  5224.     b_color := m_b_color;
  5225.     Right_Margin := Parse_Int('/RM=',MParm_Str);
  5226.     IF ((Right_Margin < 1) or (Right_Margin > 2048)) THEN
  5227.         right_margin := 2048;
  5228.     END;
  5229.     wrap_stat := Parse_Int('/WW=',MParm_Str);
  5230.  
  5231.  
  5232.     RM('UserIn^CheckEvents /M=2/F=1/G=' + event_str + '/#=' + str(ev_count));
  5233.  
  5234.     Refresh := TRUE;
  5235.     REDRAW;
  5236.     update_virtual_display;
  5237.     reset_virtual_display;
  5238.  
  5239. LOOP:
  5240.     JX := window_id;
  5241.     READ_KEY;
  5242.     IF (Extra_Event) THEN
  5243.         IF ((Key1 = Parse_Int('/K1=',Global_Str(Extra_Name))) and
  5244.             (Key2 = Parse_Int('/K2=',Global_Str(Extra_Name)))) THEN
  5245. EXTRA_EV:
  5246.             Jx := Xpos('/MACRO=',Global_Str(Extra_Name),1);
  5247.             RM(Copy(Global_Str(Extra_Name),jx + 7,254));
  5248.             refresh := true;
  5249.             Goto LOOP;
  5250.         END;
  5251.     END;
  5252.     IF key1 = 0 THEN
  5253.         IF key2 = 250 THEN
  5254.             RM('UserIn^CheckEvents /M=1/G=' + event_str + '/#=' + str(ev_count));
  5255.             IF RETURN_INT <> 0 THEN
  5256.                 Return_Int := Parse_Int('/R=', return_str);
  5257.                 IF return_int = 0 THEN
  5258.                     Goto EXIT_LOOP;
  5259.                 ELSIF return_int = 1 THEN
  5260.                     Goto SPELL_CHECK;
  5261.                 ELSIF return_int = 2 THEN
  5262.                     Goto SEARCH;
  5263.                 ELSIF (extra_event) THEN
  5264.                     IF (Return_int = Parse_Int('/R=',Global_Str(Extra_Name))) THEN
  5265.                         Goto EXTRA_EV;
  5266.                     END;
  5267.                 END;
  5268.             ELSE
  5269.                 RM( 'MOUSE^MouEvent /M=1/S=1' );
  5270.             END;
  5271.         ELSIF key2 = 59 THEN
  5272.             Help( Parse_Str('/H=', mparm_str ) );
  5273.         ELSIF key2 = 31 THEN
  5274. SPELL_CHECK:
  5275.             RM('SPELL /BC=' + str( box_count ) );
  5276.             refresh := true;
  5277.         ELSIF key2 = 64 THEN
  5278. SEARCH:
  5279.             RM('MEUTIL2^SEARCH /BC=' + Str(Box_Count));
  5280.             refresh := true;
  5281.         ELSE
  5282.             IF xpos( CHAR(key2), allowed_extended_keys, 1) <> 0 THEN
  5283.                 Pass_Key( key1, key2 );
  5284.             END;
  5285.         END;
  5286.     ELSIF key1 = 27 THEN
  5287.         goto EXIT_LOOP;
  5288.     ELSE
  5289.         Pass_Key( key1, key2 );
  5290.     END;
  5291.     GOTO LOOP;
  5292.  
  5293. TEST_BOX_SIZE:
  5294.     IF (x + w + 2) >= Screen_Width THEN
  5295.         x := screen_width - 2 - w;
  5296.     END;
  5297.     IF x < 1 THEN
  5298.         x := 1;
  5299.     END;
  5300.     IF (x + w + 2) > Screen_Width THEN
  5301.         w := Screen_Width - x - 2;
  5302.     END;
  5303.     IF (y + l + 1) >= max_window_row THEN
  5304.         y := max_window_row - l - 1;
  5305.     END;
  5306.     IF y < 1 THEN
  5307.         y := 1;
  5308.     END;
  5309.     IF (y + l + 1) >= max_window_row THEN
  5310.         l := max_window_row - y - 1;
  5311.     END;
  5312.  
  5313.     ret;
  5314.  
  5315. SET_EVENTS:
  5316.     Ev_Count := 1;
  5317.     event_str :=  '@EV' + Str(Global_Int( 'MENU_LEVEL' )) + '#';
  5318.  
  5319.     Set_Global_Str(Event_Str + '1', '/T=Done/KC=<ESC>/K1=27/K2=1/R=0');
  5320.     IF (Parse_Int('/SP=',MParm_Str)) THEN
  5321.         ++Ev_Count;
  5322.         Set_Global_Str(Event_Str + Str(Ev_Count), '/T=Spell check/KC=<AltS>/K1=0/K2=31/R=1');
  5323.     END;
  5324.     IF (Parse_Int('/SE=',MParm_Str)) THEN
  5325.         ++Ev_Count;
  5326.         Set_Global_Str(Event_Str + Str(Ev_Count), '/T=Search/FL=Search/KC=<F6>/K1=0/K2=64/R=2');
  5327.     END;
  5328.  
  5329.     IF (Extra_Name <> '') THEN
  5330.         ++Ev_Count;
  5331.         Extra_Event := True;
  5332.         Set_Global_Str(Event_Str + Str(Ev_Count),Global_Str(Extra_Name));
  5333.     END;
  5334.  
  5335.     RM('UserIn^CheckEvents /M=4/G=' + event_str + '/#=' + str(ev_count) + '/X=' + str(x+1) + '/Y=' + str( y + l ) + '/W=' + str(w));
  5336.     RET;
  5337.  
  5338.  
  5339. EXIT_LOOP:
  5340.     Set_Global_Int('MENU_LEVEL', Global_Int('MENU_LEVEL') - 1);
  5341.     Mode := T_Mode;
  5342.     refresh := FALSE;
  5343.     IF parse_int('/NK=', mparm_str) = 0 THEN
  5344.         Kill_Box;
  5345.     END;
  5346.     pop_labels;
  5347.     RM('UserIn^CheckEvents /M=3/G=' + event_str + '/#=' + str(ev_count));
  5348. END_MACRO;