home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR8 / TDE32.ZIP / MACRO.C < prev    next >
C/C++ Source or Header  |  1993-11-13  |  29KB  |  853 lines

  1. /*
  2.  * The "macro" routines in TDE are not really macro routines in the classical
  3.  * sense.  In TDE, "macros" are just recordings of key sequences.  But,
  4.  * actually, I find the ability to record and playback keystrokes generally
  5.  * more useful than writing a macro.  Being that I'm so stupid, it takes me
  6.  * half the morning to write and half the afternoon to debug a simple classical
  7.  * macro.  For most of my routine, little jobs, I find it more convenient
  8.  * to record my keystrokes and playback those keystrokes at appropriate places
  9.  * in a file.  It just seems easier for me to "teach" the editor what to do
  10.  * rather than "instruct" the editor what to do.
  11.  *
  12.  * New editor name:  TDE, the Thomson-Davis Editor.
  13.  * Author:           Frank Davis
  14.  * Date:             June 5, 1991, version 1.0
  15.  * Date:             July 29, 1991, version 1.1
  16.  * Date:             October 5, 1991, version 1.2
  17.  * Date:             January 20, 1992, version 1.3
  18.  * Date:             February 17, 1992, version 1.4
  19.  * Date:             April 1, 1992, version 1.5
  20.  * Date:             June 5, 1992, version 2.0
  21.  * Date:             October 31, 1992, version 2.1
  22.  * Date:             April 1, 1993, version 2.2
  23.  * Date:             June 5, 1993, version 3.0
  24.  * Date:             August 29, 1993, version 3.1
  25.  * Date:             November 13, 1993, version 3.2
  26.  *
  27.  * This modification of Douglas Thomson's code is released into the
  28.  * public domain, Frank Davis.  You may distribute it freely.
  29.  */
  30.  
  31.  
  32. #include "tdestr.h"             /* tde types */
  33. #include "common.h"
  34. #include "define.h"
  35. #include "tdefunc.h"
  36.  
  37.  
  38. /*
  39.  *              keystroke record functions
  40.  */
  41.  
  42. /*
  43.  * Name:    record_on_off
  44.  * Purpose: save keystrokes in keystroke buffer
  45.  * Date:    April 1, 1992
  46.  * Passed:  window:  pointer to current window
  47.  * Notes:   -1 in .next field indicates the end of a recording
  48.  *          -1 in .key field indicates the initial, unassigned macro key
  49.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  50.  */
  51. int  record_on_off( TDE_WIN *window )
  52. {
  53. register int next;
  54. int  prev;
  55. int  line;
  56. int  key;
  57. int  func;
  58. char temp[MAX_COLS+2];
  59. #if defined( __UNIX__ )
  60.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  61. #else
  62.  char display_buff[(MAX_COLS+2)*2];
  63. #endif
  64.  
  65.    mode.record = !mode.record;
  66.    if (mode.record == TRUE) {
  67.       line = window->bottom_line;
  68.       show_avail_strokes( );
  69.       save_screen_line( 0, line, display_buff );
  70.       /*
  71.        * press key that will play back recording
  72.        */
  73.       set_prompt( main11, line );
  74.  
  75.       /*
  76.        * get the candidate macro key and look up the function assigned to it.
  77.        */
  78.       key = getkey( );
  79.       func = getfunc( key );
  80.  
  81.       /*
  82.        * the key must be an unused, recognized function key or a function
  83.        *  key assigned to a previously defined macro.  we also need room
  84.        *  in the macro structure.
  85.        */
  86.       if (key <= 256 || (func != 0 && func != PlayBack)) {
  87.          /*
  88.           * cannot assign a recording to this key
  89.           */
  90.          error( WARNING, line, main12 );
  91.          mode.record = FALSE;
  92.       } else if (g_status.stroke_count == 0) {
  93.          /*
  94.           * no more room in recording buffer
  95.           */
  96.          error( WARNING, line, main13 );
  97.          mode.record = FALSE;
  98.       } else {
  99.  
  100.          /*
  101.           * everything is everything so far, just check for a prev macro
  102.           */
  103.          prev = OK;
  104.          if (func == PlayBack) {
  105.             /*
  106.              * overwrite recording (y/n)?
  107.              */
  108.             set_prompt( main14, line );
  109.             if (get_yn( ) == A_NO) {
  110.                prev = ERROR;
  111.                mode.record = FALSE;
  112.             }
  113.          }
  114.          if (prev == OK) {
  115.             g_status.recording_key = key;
  116.             next = macro.first_stroke[key-256];
  117.  
  118.             /*
  119.              * if key has already been assigned to a macro, clear macro def.
  120.              */
  121.             if (next != STROKE_LIMIT+1) {
  122.                do {
  123.                   prev = next;
  124.                   next = macro.strokes[next].next;
  125.                   macro.strokes[prev].key  = MAX_KEYS+1;
  126.                   macro.strokes[prev].next = STROKE_LIMIT+1;
  127.                   ++g_status.stroke_count;
  128.                } while (next != -1);
  129.                show_avail_strokes( );
  130.             }
  131.  
  132.             /*
  133.              * find the first open space and initialize
  134.              */
  135.             for (next=0; macro.strokes[next].next != STROKE_LIMIT+1;)
  136.                next++;
  137.             macro.first_stroke[key-256] = next;
  138.             macro.strokes[next].key  = -1;
  139.             macro.strokes[next].next = -1;
  140.             key_func.key[key-256] = PlayBack;
  141.             /*
  142.              * recording
  143.              */
  144.             s_output( main15, g_display.mode_line, 22,
  145.                       g_display.mode_color | 0x80 );
  146.          }
  147.       }
  148.       restore_screen_line( 0, line, display_buff );
  149.    }
  150.  
  151.    /*
  152.     * the flashing "Recording" and the stroke count write over the modes.
  153.     *  when we get thru defining a macro, redisplay the modes.
  154.     */
  155.    if (mode.record == FALSE) {
  156.  
  157.       memset( temp, ' ', 36 );
  158.       temp[36] = '\0';
  159.       s_output( temp, g_display.mode_line, 22, g_display.mode_color );
  160.       show_tab_modes( );
  161.       show_indent_mode( );
  162.       show_sync_mode( );
  163.       show_search_case( );
  164.       show_wordwrap_mode( );
  165.  
  166.       /*
  167.        * let's look at the macro.  if the first .key of the macro is
  168.        *  still -1, which is the initial unassigned key in a macro, reset
  169.        *  the macro so other keys may be assigned to this node.
  170.        */
  171.       key = g_status.recording_key;
  172.       if (key != 0) {
  173.          next = macro.first_stroke[key-256];
  174.          if (macro.strokes[next].key == -1) {
  175.             macro.strokes[next].key  = MAX_KEYS+1;
  176.             macro.strokes[next].next = STROKE_LIMIT+1;
  177.             macro.first_stroke[key-256] = STROKE_LIMIT+1;
  178.             if (getfunc( key ) == PlayBack)
  179.                key_func.key[key-256] = 0;
  180.          }
  181.       }
  182.       g_status.recording_key = 0;
  183.    }
  184.    return( OK );
  185. }
  186.  
  187.  
  188. /*
  189.  * Name:    record_keys
  190.  * Purpose: save keystrokes in keystroke buffer
  191.  * Date:    April 1, 1992
  192.  * Passed:  line: line to display prompts
  193.  * Notes:   -1 in .next field indicates the end of a recording
  194.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  195.  */
  196. void record_keys( int line )
  197. {
  198. register int next;
  199. register int prev;
  200. int  key;
  201. int  func;
  202.  
  203.    if (mode.record == TRUE) {
  204.       if (g_status.stroke_count == 0)
  205.          /*
  206.           * no more room in recording buffer
  207.           */
  208.          error( WARNING, line, main13 );
  209.       else {
  210.          key = g_status.key_pressed;
  211.          func = getfunc( key );
  212.          if (func != RecordMacro && func != SaveMacro && func != LoadMacro &&
  213.              func != ClearAllMacros) {
  214.  
  215.             /*
  216.              * a -1 in the next field marks the end of the keystroke recording.
  217.              */
  218.             next = macro.first_stroke[g_status.recording_key - 256];
  219.             if (macro.strokes[next].next != STROKE_LIMIT+1) {
  220.                while (macro.strokes[next].next != -1)
  221.                   next = macro.strokes[next].next;
  222.             }
  223.             prev = next;
  224.  
  225.             /*
  226.              * now find an open space to record the current key.
  227.              */
  228.             if (macro.strokes[next].key != -1) {
  229.                for (; next < STROKE_LIMIT &&
  230.                             macro.strokes[next].next != STROKE_LIMIT+1;)
  231.                   next++;
  232.                if (next == STROKE_LIMIT) {
  233.                   for (next=0; next < prev &&
  234.                                macro.strokes[next].next != STROKE_LIMIT+1;)
  235.                      next++;
  236.                }
  237.             }
  238.             if (next == prev && macro.strokes[prev].key != -1)
  239.                /*
  240.                 * no more room in recording buffer
  241.                 */
  242.                error( WARNING, line, main13 );
  243.             else {
  244.             /*
  245.              * next == prev if we are recording the initial macro node.
  246.              */
  247.                macro.strokes[prev].next = next;
  248.                macro.strokes[next].next = -1;
  249.                macro.strokes[next].key  = key;
  250.                g_status.stroke_count--;
  251.                show_avail_strokes( );
  252.             }
  253.          }
  254.       }
  255.    }
  256. }
  257.  
  258.  
  259. /*
  260.  * Name:    show_avail_strokes
  261.  * Purpose: show available free key strokes in lite bar at bottom of screen
  262.  * Date:    April 1, 1992
  263.  */
  264. void show_avail_strokes( void )
  265. {
  266. char temp[MAX_COLS+2];
  267.  
  268.    s_output( main18, g_display.mode_line, 33, g_display.mode_color );
  269.    my_ltoa( g_status.stroke_count, temp, 10 );
  270.    s_output( "      ", g_display.mode_line, 51, g_display.mode_color );
  271.    s_output( temp, g_display.mode_line, 51, g_display.mode_color );
  272. }
  273.  
  274. #if defined( __UNIX__ )
  275.  
  276. /*
  277.  * Name:    save_strokes
  278.  * Purpose: save strokes to a file
  279.  * Date:    November 13, 1993
  280.  * Passed:  window:  pointer to current window
  281.  */
  282. int  save_strokes( TDE_WIN *window )
  283. {
  284. FILE *fp;                       /* file to be written */
  285. register int rc;
  286. int  prompt_line;
  287. char answer[PATH_MAX+2];
  288. #if defined( __UNIX__ )
  289.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  290.  mode_t  fattr;
  291. #else
  292.  char display_buff[(MAX_COLS+2)*2];
  293.  int  fattr;
  294. #endif
  295.  
  296.    answer[0] = '\0';
  297.    prompt_line = window->bottom_line;
  298.    save_screen_line( 0, prompt_line, display_buff );
  299.    /*
  300.     * name for macro file
  301.     */
  302.    if ((rc = get_name( main19, prompt_line, answer,
  303.                g_display.message_color )) == OK  &&  *answer != '\0') {
  304.  
  305.       /*
  306.        * make sure it is OK to overwrite any existing file
  307.        */
  308.       rc = get_fattr( answer, &fattr );
  309.       if (rc == OK) {
  310.          /*
  311.           * file exists. make sure this is a regular file, first
  312.           */
  313.          if (S_ISREG( fattr )) {
  314.             /*
  315.              * overwrite existing file?
  316.              */
  317.             set_prompt( main20, prompt_line );
  318.             if (get_yn( ) != A_YES  ||
  319.                            change_mode( answer, prompt_line ) == ERROR)
  320.                rc = ERROR;
  321.          } else
  322.             rc = ERROR;
  323.       } else
  324.  
  325.          /*
  326.           * file does not exist.  take a chance on a valid file name.
  327.           */
  328.          rc = OK;
  329.  
  330.       if (rc != ERROR) {
  331.          if ((fp = fopen( answer, "wb" )) != NULL) {
  332.             fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  333.             fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  334.             fclose( fp );
  335.          }
  336.       }
  337.    }
  338.    restore_screen_line( 0, prompt_line, display_buff );
  339.    return( OK );
  340. }
  341.  
  342. #else
  343.  
  344. /*
  345.  * Name:    save_strokes
  346.  * Purpose: save strokes to a file
  347.  * Date:    April 1, 1992
  348.  * Passed:  window:  pointer to current window
  349.  */
  350. int  save_strokes( TDE_WIN *window )
  351. {
  352. FILE *fp;                       /* file to be written */
  353. register int rc;
  354. int  prompt_line;
  355. char answer[MAX_COLS+2];
  356. #if defined( __UNIX__ )
  357.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  358.  mode_t  fattr;
  359. #else
  360.  char display_buff[(MAX_COLS+2)*2];
  361.  int  fattr;
  362. #endif
  363.  
  364.    answer[0] = '\0';
  365.    prompt_line = window->bottom_line;
  366.    save_screen_line( 0, prompt_line, display_buff );
  367.    /*
  368.     * name for macro file
  369.     */
  370.    if ((rc = get_name( main19, prompt_line, answer,
  371.                g_display.message_color )) == OK  &&  *answer != '\0') {
  372.  
  373.       /*
  374.        * make sure it is OK to overwrite any existing file
  375.        */
  376.       rc = get_fattr( answer, &fattr );
  377.       if (rc == OK) {
  378.          /*
  379.           * overwrite existing file
  380.           */
  381.          set_prompt( main20, prompt_line );
  382.          if (get_yn( ) != A_YES || change_mode( answer, prompt_line ) == ERROR)
  383.             rc = ERROR;
  384.       }
  385.       if (rc != ERROR) {
  386.          if ((fp = fopen( answer, "wb" )) != NULL) {
  387.             fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  388.             fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  389.             fclose( fp );
  390.          }
  391.       }
  392.    }
  393.    restore_screen_line( 0, prompt_line, display_buff );
  394.    return( OK );
  395. }
  396.  
  397. #endif
  398.  
  399. /*
  400.  * Name:    load_strokes
  401.  * Purpose: load strokes from a file
  402.  * Date:    April 1, 1992
  403.  * Passed:  window:  pointer to current window
  404.  * Notes:   show the user a file pick list.  I can never remember macro
  405.  *           file names or the directory in which they hide.  might as well
  406.  *           give the user a file pick list.
  407.  */
  408. int  load_strokes( TDE_WIN *window )
  409. {
  410. register FILE *fp;      /* file to be read */
  411. char dname[MAX_COLS];   /* directory search pattern */
  412. char stem[MAX_COLS];    /* directory stem */
  413. register int rc;
  414.  
  415.    dname[0] = '\0';
  416.    /*
  417.     * search path for macro file
  418.     */
  419.    if (get_name( main21, window->bottom_line, dname,
  420.                  g_display.message_color ) == OK  &&  *dname != '\0') {
  421.       if (validate_path( dname, stem ) == OK) {
  422.          rc = list_and_pick( dname, stem, window );
  423.  
  424.          /*
  425.           * if everything is everything, load in the file selected by user.
  426.           */
  427.          if (rc == OK) {
  428.             if ((fp = fopen( dname, "rb" )) != NULL && ceh.flag != ERROR) {
  429.                fread( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  430.                fread( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  431.                fclose( fp );
  432.             }
  433.             if (ceh.flag == OK)
  434.                connect_macros( );
  435.          }
  436.       } else
  437.          /*
  438.           * invalid path or file name
  439.           */
  440.          error( WARNING, window->bottom_line, main22 );
  441.    }
  442.    return( OK );
  443. }
  444.  
  445.  
  446. /*
  447.  * Name:    clear_macro
  448.  * Purpose: reset all macro buffers, pointers, functions.
  449.  * Date:    April 1, 1992
  450.  * Notes:   reset the available macro stroke count.  reset all fields in
  451.  *           macro structure.  clear any keys assigned to macros in the
  452.  *           function assignment array.
  453.  */
  454. int  clear_macros( TDE_WIN *arg_filler )
  455. {
  456. register int i;
  457.  
  458.    g_status.stroke_count = STROKE_LIMIT;
  459.    for (i=0; i<STROKE_LIMIT; i++) {
  460.       macro.strokes[i].next = STROKE_LIMIT+1;
  461.       macro.strokes[i].key  = MAX_KEYS+1;
  462.    }
  463.    for (i=0; i<MAX_KEYS; i++) {
  464.       macro.first_stroke[i] = STROKE_LIMIT+1;
  465.       if (key_func.key[i] == PlayBack)
  466.          key_func.key[i] = 0;
  467.    }
  468.    return( OK );
  469. }
  470.  
  471.  
  472. /*
  473.  * Name:    connect_macros
  474.  * Purpose: hook up all (if any) macros to the function key definition table
  475.  * Date:    April 1, 1992
  476.  * Notes:   we need to connect all macro definitions to the key definition
  477.  *           table in the startup routine or when we read in a new macro
  478.  *           definition file.  the predefined func assignments take
  479.  *           precedence over macro definitions.
  480.  */
  481. void connect_macros( void )
  482. {
  483. register int i;
  484.  
  485.    /*
  486.     * reset the key function assignment array.  initially, no keys may be
  487.     *  assigned to a macro.
  488.     */
  489.    for (i=0; i<MAX_KEYS; i++)
  490.       if (key_func.key[i] == PlayBack)
  491.          key_func.key[i] = 0;
  492.  
  493.    /*
  494.     * now, find out how many free keystrokes are in the macro structure.
  495.     */
  496.    g_status.stroke_count = 0;
  497.    for (i=0; i<STROKE_LIMIT; i++)
  498.       if (macro.strokes[i].next == STROKE_LIMIT+1)
  499.          ++g_status.stroke_count;
  500.  
  501.    /*
  502.     * go thru the first stroke list to see if any key has been assigned to
  503.     *  a macro and connect the macro def to the key.  predefined function
  504.     *  assignments take precedence over macros.
  505.     */
  506.    for (i=0; i<MAX_KEYS; i++) {
  507.       if (macro.first_stroke[i] != STROKE_LIMIT+1)
  508.          if (key_func.key[i] == 0)
  509.             key_func.key[i] = PlayBack;
  510.    }
  511. }
  512.  
  513.  
  514. /*
  515.  *              keystroke play back functions
  516.  */
  517.  
  518.  
  519. /*
  520.  * Name:    play_back
  521.  * Purpose: play back a series of keystrokes assigned to key
  522.  * Date:    April 1, 1992
  523.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  524.  * Notes:   go thru the macro key list playing back the recorded keystrokes.
  525.  *          to let macros call other macros, we have to 1) save the next
  526.  *           keystroke of the current macro in a stack, 2) execute the
  527.  *           the called macro, 3) pop the key that saved by the calling
  528.  *           macro, 4) continue executing the macro, beginning with the
  529.  *           key we just popped.
  530.  *          use a local stack to store keys.  currently, there is room
  531.  *           for 256 keys -- should be enough room for most purposes.
  532.  *
  533.  * Change:  Support for IfCapsLock and IfNotCapsLock
  534.  */
  535. int  play_back( TDE_WIN *window )
  536. {
  537. int  key;
  538. int  rc = OK;
  539. int  popped;            /* flag is set when macro is popped */
  540.  
  541.    /*
  542.     * if we are recording a macro, let's just return if we do a recursive
  543.     *  definition.  Otherwise, we end up executing our recursive macro
  544.     *  while we are defining it.
  545.     */
  546.    if (mode.record == TRUE && g_status.key_pressed == g_status.recording_key)
  547.       rc = ERROR;
  548.    else {
  549.  
  550.       /*
  551.        * set the global macro flags, so other routines will know
  552.        *  if a macro is executing.
  553.        * set the stack_pointer to "empty" or -1.  initialize the popped
  554.        *  flag to FALSE being that we haven't popped any thing off the stack,
  555.        *  yet.
  556.        */
  557.       g_status.macro_executing = TRUE;
  558.       g_status.mstack_pointer  = -1;
  559.       popped = FALSE;
  560.       key = 0;
  561.       rc = OK;
  562.       while (rc == OK) {
  563.  
  564.          /*
  565.           * the first time thru the loop, popped is FALSE.  some lint
  566.           *  utilities may complain about key being used but not defined.
  567.           */
  568.          if (popped == FALSE) {
  569.  
  570.             /*
  571.              * find the first keystroke in the macro.  when we pop the stack,
  572.              *  all this stuff is reset by the pop -- do not reset it again.
  573.              */
  574.             g_status.macro_next = macro.first_stroke[g_status.key_pressed-256];
  575.             g_status.current_macro = g_status.key_pressed;
  576.             key = macro.strokes[g_status.macro_next].key;
  577.          }
  578.          popped = FALSE;
  579.          if (key != MAX_KEYS+1  &&  key != -1) {
  580.             do {
  581.  
  582.                /*
  583.                 * set up all editor variables as if we were entering
  584.                 *  keys from the keyboard.
  585.                 */
  586.                window = g_status.current_window;
  587.                display_dirty_windows( window );
  588.                ceh.flag = OK;
  589.                g_status.key_pressed = macro.strokes[g_status.macro_next].key;
  590.                g_status.command = getfunc( g_status.key_pressed );
  591.                if (g_status.wrapped  ||  g_status.key_pending) {
  592.                   g_status.key_pending = FALSE;
  593.                   g_status.wrapped = FALSE;
  594.                   show_search_message( CLR_SEARCH, g_display.mode_color );
  595.                }
  596.  
  597.                /*
  598.                 * while there are no errors or Control-Breaks, let's keep on
  599.                 *  executing a macro.  g_status.control_break is a global
  600.                 *  editor flag that is set in our Control-Break interrupt
  601.                 *  handler routine.
  602.                 */
  603.                if (g_status.control_break == TRUE) {
  604.                   rc = ERROR;
  605.                   break;
  606.                }
  607.  
  608.                /*
  609.                 * Now check for the special macro if-instructions
  610.                 */
  611.                if (g_status.command == IfCapsLock) {
  612.                   if (!capslock_active( )) {
  613.                      /* Caps Lock is not active: Drop now next key */
  614.                      g_status.macro_next =
  615.                           macro.strokes[g_status.macro_next].next;
  616.                      /* Check existence of dropped key */
  617.                      if (g_status.macro_next == -1)
  618.                         break;
  619.                   }
  620.                }
  621.                if (g_status.command == IfNotCapsLock) {
  622.                   if (capslock_active( )) {
  623.                      /* Caps Lock is active: Drop now next key */
  624.                      g_status.macro_next =
  625.                           macro.strokes[g_status.macro_next].next;
  626.                      /* Check existence of dropped key */
  627.                      if (g_status.macro_next == -1)
  628.                         break;
  629.                   }
  630.                }
  631.  
  632.                /*
  633.                 * we haven't called any editor function yet.  we need
  634.                 *  to look at the editor command that is to be executed.
  635.                 *  if the command is PlayBack, we need to break out of
  636.                 *  this inner do loop and start executing the macro
  637.                 *  from the beginning (the outer do loop).
  638.                 *
  639.                 * if we don't break out now from a recursive macro, we will
  640.                 *  recursively call PlayBack and we will likely overflow
  641.                 *  the main (as opposed to the macro_stack) stack.
  642.                 */
  643.                if (g_status.command == PlayBack) {
  644.  
  645.                   /*
  646.                    * recursive macros are handled differently from
  647.                    *  macros that call other macros.
  648.                    * recursive macros - break out of this inner loop
  649.                    *  and begin executing the macro from the beg of macro.
  650.                    * standard macros - save the next instruction of this
  651.                    *  macro on the stack and begin executing the called macro.
  652.                    */
  653.                   if (g_status.current_macro != g_status.key_pressed) {
  654.                      if (push_macro_stack(
  655.                                    macro.strokes[g_status.macro_next].next )
  656.                                    != OK) {
  657.                         error( WARNING, window->bottom_line, ed16 );
  658.                         rc = ERROR;
  659.                      }
  660.                      g_status.macro_next =
  661.                                 macro.first_stroke[g_status.key_pressed-256];
  662.                      g_status.current_macro = g_status.key_pressed;
  663.                      key = macro.strokes[g_status.macro_next].key;
  664.  
  665.                      /*
  666.                       * execute called macro at beginning of this do loop.
  667.                       */
  668.                      continue;
  669.                   } else
  670.  
  671.                      /*
  672.                       * recursive macro - break out of this inner loop
  673.                       *  or else we may overflow the stack(s).
  674.                       */
  675.                      break;
  676.                }
  677.  
  678.  
  679.                /*
  680.                 * just as we assert before the main editor routine, let's
  681.                 *  assert in the macro function to make sure everything
  682.                 *  is everything.
  683.                 */
  684. #if defined(  __MSC__ )
  685.                assert( window != NULL );
  686.                assert( window->file_info != NULL );
  687.                assert( window->file_info->line_list != NULL );
  688.                assert( window->file_info->line_list_end != NULL );
  689.                assert( window->file_info->line_list_end->len == EOF );
  690.                assert( window->visible == TRUE );
  691.                assert( window->rline >= 0 );
  692.                assert( window->rline <= window->file_info->length + 1 );
  693.                assert( window->rcol >= 0 );
  694.                assert( window->rcol < MAX_LINE_LENGTH );
  695.                assert( window->ccol >= window->start_col );
  696.                assert( window->ccol <= window->end_col );
  697.                assert( window->bcol >= 0 );
  698.                assert( window->bcol < MAX_LINE_LENGTH );
  699.                assert( window->bcol == window->rcol-(window->ccol - window->start_col) );
  700.                assert( window->start_col >= 0 );
  701.                assert( window->start_col < window->end_col );
  702.                assert( window->end_col < g_display.ncols );
  703.                assert( window->cline >= window->top_line );
  704.                assert( window->cline <= window->bottom_line );
  705.                assert( window->top_line > 0 );
  706.                assert( window->top_line <= window->bottom_line );
  707.                assert( window->bottom_line <= g_display.nlines );
  708.                assert( window->bin_offset >= 0 );
  709.                if (window->ll->next == NULL)
  710.                   assert( window->ll->len == EOF );
  711.                else
  712.                   assert( window->ll->len >= 0 );
  713.                assert( window->ll->len <  MAX_LINE_LENGTH );
  714. #endif
  715.  
  716. #if defined( __UNIX__ )
  717.                refresh( );
  718. #endif
  719.  
  720.                if (g_status.command >= 0 && g_status.command < NUM_FUNCS)
  721.                    rc = (*do_it[g_status.command])( window );
  722.                g_status.macro_next =
  723.                           macro.strokes[g_status.macro_next].next;
  724.             } while (rc == OK  &&  g_status.macro_next != -1);
  725.  
  726.             /*
  727.              * if we have come the end of a macro definition and there
  728.              *  are no keys saved on the stack, we have finished our
  729.              *  macro.  get out.
  730.              */
  731.             if (g_status.macro_next == -1 && g_status.mstack_pointer < 0)
  732.                rc = ERROR;
  733.             else if (rc != ERROR  &&  g_status.mstack_pointer >= 0) {
  734.  
  735.                /*
  736.                 * if this is a recursive macro, don't pop the stack
  737.                 *  because we didn't push.
  738.                 * for a standard macro, get back the next key in the
  739.                 *  calling macro.
  740.                 */
  741.                if (g_status.current_macro != g_status.key_pressed) {
  742.                   if (pop_macro_stack( &g_status.macro_next ) != OK) {
  743.                      error( WARNING, window->bottom_line, ed17 );
  744.                      rc = ERROR;
  745.                   } else {
  746.                      popped = TRUE;
  747.                      key = macro.strokes[g_status.macro_next].key;
  748.                   }
  749.                }
  750.             }
  751.          }
  752.       }
  753.       g_status.macro_executing = FALSE;
  754.    }
  755.    return( OK );
  756. }
  757.  
  758.  
  759. /*
  760.  * Name:    push_macro_stack
  761.  * Purpose: push the next key in a currently executing macro on local stack
  762.  * Date:    October 31, 1992
  763.  * Notes:   finally got tired of letting macros only "jump" and not call
  764.  *           other macros.
  765.  *          the first time in, stack_pointer is -1.
  766.  */
  767. int  push_macro_stack( int key )
  768. {
  769.    /*
  770.     * first, make sure we have room to push the key.
  771.     */
  772.    if (g_status.mstack_pointer+1 < MAX_KEYS) {
  773.  
  774.       /*
  775.        * increment the stack pointer and store the pointer to the next key
  776.        *  of the currently executing macro.  store the currently executing
  777.        *  macro, too.
  778.        */
  779.       ++g_status.mstack_pointer;
  780.       macro_stack[g_status.mstack_pointer].key = key;
  781.       macro_stack[g_status.mstack_pointer].macro = g_status.current_macro;
  782.       return( OK );
  783.    } else
  784.       return( STACK_OVERFLOW );
  785. }
  786.  
  787.  
  788. /*
  789.  * Name:    pop_macro_stack
  790.  * Purpose: pop currently executing macro on local stack
  791.  * Date:    October 31, 1992
  792.  * Notes:   finally got tired of letting macros only "jump" and not "call"
  793.  *           other macros.
  794.  *          pop the macro stack.  stack pointer is pointing to last key saved
  795.  *           on stack.
  796.  */
  797. int  pop_macro_stack( int *key )
  798. {
  799.  
  800.    /*
  801.     * before we pop the stack, make sure there is something in the stack.
  802.     */
  803.    if (g_status.mstack_pointer >= 0) {
  804.  
  805.       /*
  806.        * pop the pointer to the next key and the current macro, then
  807.        *  decrement the stack_pointer.
  808.        */
  809.       *key = macro_stack[g_status.mstack_pointer].key;
  810.       g_status.current_macro = macro_stack[g_status.mstack_pointer].macro;
  811.       --g_status.mstack_pointer;
  812.       return( OK );
  813.    } else
  814.       return( STACK_UNDERFLOW );
  815. }
  816.  
  817.  
  818. /*
  819.  * Name:    macro_pause
  820.  * Purpose: Enter pause state for macros
  821.  * Date:    June 5, 1992
  822.  * Passed:  arg_filler:  argument to satify function prototype
  823.  * Returns: ERROR if the ESC key was pressed, OK otherwise.
  824.  * Notes:   this little function is quite useful in macro definitions.  if
  825.  *          it is called near the beginning of a macro, the user may decide
  826.  *          whether or not to stop the macro.
  827.  */
  828. int  macro_pause( TDE_WIN *arg_filler )
  829. {
  830. int  c;
  831.  
  832.    /*
  833.     * tell user we are paused.  the '|  0x80' turns on the blink attribute
  834.     */
  835.    s_output( paused1, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  836.    s_output( paused2, g_display.mode_line, 23+strlen( paused1 ),
  837.              g_display.mode_color );
  838.  
  839.    /*
  840.     * get the user's response and restore the mode line.
  841.     */
  842.    c = getkey( );
  843.    show_modes( );
  844.    if (mode.record == TRUE) {
  845.       /*
  846.        * if recording a macro, show recording message
  847.        */
  848.       s_output( main15, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  849.       show_avail_strokes( );
  850.    }
  851.    return( c == ESC ? ERROR : OK );
  852. }
  853.