int execute(int command)
{
  static char command_line[128];
  static int savedmac[128]; // sort out size limitations later
  static int *savedmacp = savedmac;
  static int nextc = 0;
  static int ecce_mode = FALSE;
  static int learning_mode = FALSE;
  static int update_required = (0==0);
  static int correction = 0;
  static int target_col = -1;

  // nasty modeful hack :-(

  if (command == ERR) {
    // *should* repaint the screen any time the keyboard is idle and
    // the display size has changed.  Unfortunately it doesn't until
    // the next keypress.  Not sure why.  But better to leave this in
    // slightly broken than omit resizing altogether, which is severely
    // broken ...

    if ((!ecce_mode) && ((LAST_DISPLAY_LINE != LINES-1) || (DISPLAY_RIGHTMOST_COLUMN != COLS))) {
      LAST_DISPLAY_LINE = LINES-1;
      DISPLAY_RIGHTMOST_COLUMN = COLS;
//      update_display(pp, preferred_display_line);
//      refresh();
//      return;
    }
    usleep(10000);
  } else {
    if (learning_mode) {
      if (command != ('E'&31)) {
        *savedmacp++ = command; *savedmacp = ERR; // record keystrokes before all other processing
      }
    }
    if ((command == ('L'&31)) && (!ecce_mode)) {
      if (learning_mode) {
        if (savedmacp != savedmac) savedmacp -= 1; // remove final ^L
        // get key sequence and assign learned commands to key sequence.
        // key sequence must be unique path through trie, not a prefix, otherwise can't assign.
        learning_mode = FALSE;
        if (savedmacp == savedmac) { // ^L^L - treat as a single ^L?
          clear();
          update_required = (0==0);
        }
      } else {
        // Start learning mode!
        learning_mode = TRUE;
        savedmacp = savedmac;
        *savedmacp = ERR;
      }
      return;
    } else if (command == ('E'&31)) {
      // TEMPORARY PROOF OF CONCEPT: Execute stored macro
      learning_mode = FALSE; // quick hack to avoid recursion problems
      savedmacp = savedmac;
      while (*savedmacp != ERR) {
        execute(*savedmacp++);
      }
      return;
    } else if ((command == '\r') && (!ecce_mode)) {
      // don't special-case enter until in ecce mode
    } else {
      if ((!ecce_mode) && ((' ' <= command) && (command <= '~'))) {
        // although we want redefine characters to take precedence,
        // simply moving this test to the end does not work...
        ecce_mode = TRUE; nextc = 0;
        if (preferred_display_line == LAST_DISPLAY_LINE) preferred_display_line -= (correction = 1);
        LAST_DISPLAY_LINE -= 1;
        update_required = (0==0);
      }
      if (ecce_mode && (command == '\r')) {
        command_line[nextc] = '\0';
        ecce_mode = FALSE;
        preferred_display_line += correction; correction = 0;
        LAST_DISPLAY_LINE += 1;
        nextc = 0;
        // execute the command here
        ecinner(command_line);
        command_line[nextc] = '\0';
        target_col = -1;
        update_display(pp, preferred_display_line);
        if (*ecce_err != '\0') {int x=DISPLAY_LEFTMOST_COLUMN;
         char *s;
         move(LAST_DISPLAY_LINE, 0);
         s=ecce_err;
         standout();
         for (;;) {
           if (*s == '\0') break;
           if (*s == '\n') break;
//           move(LAST_DISPLAY_LINE+1,x++);
           addch(*s++);
         }
         while (x++ < DISPLAY_RIGHTMOST_COLUMN) addch(' ');
         standend();
         *ecce_err = '\0';
         refresh();
        }
        return(TRUE);

      } else if (ecce_mode) {
        int x, len;

        command_line[nextc++] = command;
        command_line[nextc] = '\0';
        if (nextc == 127) nextc = 126; // truncate

        if (update_required) {
          update_required = (0!=0);
          update_display(pp, preferred_display_line);
        }
        move(LAST_DISPLAY_LINE+1, DISPLAY_LEFTMOST_COLUMN);
        standout();
        len = strlen(command_line);

        // NEED TO OUTPUT PROMPT.  need generic routine for
        // handling input line.  Must be ready for "F!" so that
        // it prompts for the find/replace strings, for when we
        // bind commands like f// to a single key...

        for (x = 0; x < len; x++) {
          addch(command_line[x]);
        }
        standend();
        for (x = DISPLAY_LEFTMOST_COLUMN+len; x < DISPLAY_RIGHTMOST_COLUMN; x++) {
          addch(' ');
        }

        move(LAST_DISPLAY_LINE+1, DISPLAY_LEFTMOST_COLUMN+strlen(command_line)); // Plus strlen(prompt) when added...
        refresh();
        return(TRUE);
      }
    }
  }
  if (command == '\e' && getch() == ERR) {
    return(FALSE);
  // to add: HOME, END (start/end of file)
  } else if (command == KEY_DOWN || command == '\r') {
    int line, before, after;
    preferred_display_line += 1;
    if (preferred_display_line > LAST_DISPLAY_LINE) preferred_display_line = LAST_DISPLAY_LINE;
    generate_screen_line_start_pointers(pp, &line, &before);
    if (target_col < 0) target_col = before;
    {
      ecinner("m");
      for (;;) {
        generate_screen_line_start_pointers(pp, &line, &after);
        if (after >= target_col) break;
        ecinner("r");
        if (*ecce_err != '\0') break;
      }
    }
    update_required = (0==0);
  } else if (command == KEY_NPAGE || command == ' ' /* "more" clone? */) {
    preferred_display_line += LAST_DISPLAY_LINE;
    if (preferred_display_line > LAST_DISPLAY_LINE) preferred_display_line = LAST_DISPLAY_LINE;
    ecinnerf("m%0d", LAST_DISPLAY_LINE);
    update_required = (0==0);
  } else if (command == KEY_UP) {
    int line, before, after;
    preferred_display_line -= 1;
    if (preferred_display_line < FIRST_DISPLAY_LINE) preferred_display_line = FIRST_DISPLAY_LINE;
    generate_screen_line_start_pointers(pp, &line, &before);
    if (target_col < 0) target_col = before;
    {
      ecinner("m-r0");
      for (;;) {
        generate_screen_line_start_pointers(pp, &line, &after);
        if (after <= target_col) break;
        ecinner("l");
      }
    }
    update_required = (0==0);
  } else if (command == KEY_PPAGE) {
    preferred_display_line -= LAST_DISPLAY_LINE;
    if (preferred_display_line < FIRST_DISPLAY_LINE) preferred_display_line = FIRST_DISPLAY_LINE;
    ecinnerf("m-%0d", LAST_DISPLAY_LINE);
    update_required = (0==0);
  } else if (command == KEY_LEFT) {
    if (pp == lbeg && pp != fbeg) {
      ecinner("m-r0");
      // see below ... ecinner("(l,m-r0)");
      preferred_display_line -= 1;
      if (preferred_display_line < FIRST_DISPLAY_LINE) preferred_display_line = FIRST_DISPLAY_LINE;
    } else ecinner("l");
    target_col = -1;
    update_required = (0==0);
  } else if (command == KEY_RIGHT) {
    if (fp == lend) {
      ecinner("m");
      // use just ecinner("(r,m)") if ecinner is allowed to update the display info
      preferred_display_line += 1;
      if (preferred_display_line > LAST_DISPLAY_LINE) preferred_display_line = LAST_DISPLAY_LINE;
    } else ecinner("r");
    target_col = -1;
    update_required = (0==0);
  } else if (command == ' ') { // 'next' - re-execute last ecce command
    ecinner("1");
    target_col = -1;
    update_required = (0==0);
  } else if (command == ('L'&31)) { // refresh
    clear();
    update_required = (0==0);
  } else if (command == ERR) {
    // update only when there is no more type-ahead
    if (update_required) {
      update_display(pp, preferred_display_line);
      refresh();
    }
    update_required = (0!=0);
  } else {
    // Debug info: unknown key?
    move(0, DISPLAY_RIGHTMOST_COLUMN-9);
    {char *hex = "0123456789ABCDEF";
     standout();
     addch(hex[(command>>28)&15]);
     addch(hex[(command>>24)&15]);
     addch(hex[(command>>20)&15]);
     addch(hex[(command>>16)&15]);
     addch(hex[(command>>12)&15]);
     addch(hex[(command>>8)&15]);
     addch(hex[(command>>4)&15]);
     addch(hex[command&15]);
     standend();
    }
  }
  return(TRUE);
}