reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
//===-- EditLineWin.cpp -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// this file is only relevant for Visual C++
#if defined(_WIN32)

#include "lldb/Host/windows/windows.h"

#include "lldb/Host/windows/editlinewin.h"
#include "llvm/Support/ErrorHandling.h"
#include <assert.h>
#include <vector>

// edit line EL_ADDFN function pointer type
typedef unsigned char (*el_addfn_func)(EditLine *e, int ch);
typedef const char *(*el_prompt_func)(EditLine *);

// edit line wrapper binding container
struct el_binding {
  //
  const char *name;
  const char *help;
  // function pointer to callback routine
  el_addfn_func func;
  // ascii key this function is bound to
  const char *key;
};

// stored key bindings
static std::vector<el_binding *> _bindings;

// TODO: this should in fact be related to the exact edit line context we create
static void *clientData = NULL;

// store the current prompt string
// default to what we expect to receive anyway
static const char *_prompt = "(lldb) ";

#if !defined(_WIP_INPUT_METHOD)

static char *el_get_s(char *buffer, int chars) { return gets_s(buffer, chars); }
#else

static void con_output(char _in) {
  HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
  DWORD written = 0;
  // get the cursor position
  CONSOLE_SCREEN_BUFFER_INFO info;
  GetConsoleScreenBufferInfo(hout, &info);
  // output this char
  WriteConsoleOutputCharacterA(hout, &_in, 1, info.dwCursorPosition, &written);
  // advance cursor position
  info.dwCursorPosition.X++;
  SetConsoleCursorPosition(hout, info.dwCursorPosition);
}

static void con_backspace(void) {
  HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
  DWORD written = 0;
  // get cursor position
  CONSOLE_SCREEN_BUFFER_INFO info;
  GetConsoleScreenBufferInfo(hout, &info);
  // nudge cursor backwards
  info.dwCursorPosition.X--;
  SetConsoleCursorPosition(hout, info.dwCursorPosition);
  // blank out the last character
  WriteConsoleOutputCharacterA(hout, " ", 1, info.dwCursorPosition, &written);
}

static void con_return(void) {
  HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
  DWORD written = 0;
  // get cursor position
  CONSOLE_SCREEN_BUFFER_INFO info;
  GetConsoleScreenBufferInfo(hout, &info);
  // move onto the new line
  info.dwCursorPosition.X = 0;
  info.dwCursorPosition.Y++;
  SetConsoleCursorPosition(hout, info.dwCursorPosition);
}

static bool runBind(char _key) {
  for (int i = 0; i < _bindings.size(); i++) {
    el_binding *bind = _bindings[i];
    if (bind->key[0] == _key) {
      bind->func((EditLine *)-1, _key);
      return true;
    }
  }
  return false;
}

// replacement get_s which is EL_BIND aware
static char *el_get_s(char *buffer, int chars) {
  //
  char *head = buffer;
  //
  for (;; Sleep(10)) {
    //
    INPUT_RECORD _record;
    //
    DWORD _read = 0;
    if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE), &_record, 1,
                          &_read) == FALSE)
      break;
    // if we didn't read a key
    if (_read == 0)
      continue;
    // only interested in key events
    if (_record.EventType != KEY_EVENT)
      continue;
    // is the key down
    if (!_record.Event.KeyEvent.bKeyDown)
      continue;
    // read the ascii key character
    char _key = _record.Event.KeyEvent.uChar.AsciiChar;
    // non ascii conformant key press
    if (_key == 0) {
      // check the scan code
      // if VK_UP scroll back through history
      // if VK_DOWN scroll forward through history
      continue;
    }
    // try to execute any bind this key may have
    if (runBind(_key))
      continue;
    // if we read a return key
    if (_key == '\n' || _key == '\r') {
      con_return();
      break;
    }
    // key is backspace
    if (_key == 0x8) {
      // avoid deleting past beginning
      if (head > buffer) {
        con_backspace();
        head--;
      }
      continue;
    }

    // add this key to the input buffer
    if ((head - buffer) < (chars - 1)) {
      con_output(_key);
      *(head++) = _key;
    }
  }
  // insert end of line character
  *head = '\0';

  return buffer;
}
#endif

// edit line initialize
EditLine *el_init(const char *, FILE *, FILE *, FILE *) {
  //
  SetConsoleTitleA("lldb");
  // return dummy handle
  return (EditLine *)-1;
}

const char *el_gets(EditLine *el, int *length) {
  // print the prompt if we have one
  if (_prompt != NULL)
    printf("%s", _prompt);
  // create a buffer for the user input
  char *buffer = new char[MAX_PATH];
  // try to get user input string
  if (el_get_s(buffer, MAX_PATH)) {
    // get the string length in 'length'
    while (buffer[*length] != '\0')
      (*length)++;
    // return the input buffer
    // remember that this memory has the be free'd somewhere
    return buffer;
  } else {
    // on error
    delete[] buffer;
    return NULL;
  }
}

int el_set(EditLine *el, int code, ...) {
  va_list vl;
  va_start(vl, code);
  //
  switch (code) {
  // edit line set prompt message
  case (EL_PROMPT): {
    // EL_PROMPT, char *(*f)( EditLine *)
    //      define a prompt printing function as 'f', which is to return a
    //      string that
    //      contains the prompt.

    // get the function pointer from the arg list
    void *func_vp = (void *)va_arg(vl, el_prompt_func);
    // cast to suitable prototype
    el_prompt_func func_fp = (el_prompt_func)func_vp;
    // call to get the prompt as a string
    _prompt = func_fp(el);
  } break;

  case (EL_PROMPT_ESC): {
    // EL_PROMPT, char *(*f)( EditLine *)
    //      define a prompt printing function as 'f', which is to return a
    //      string that
    //      contains the prompt.

    // get the function pointer from the arg list
    void *func_vp = (void *)va_arg(vl, el_prompt_func);
    va_arg(vl, int);
    // call to get the prompt as a string
    el_prompt_func func_fp = (el_prompt_func)func_vp;
    _prompt = func_fp(el);
  } break;

  case (EL_EDITOR): {
    // EL_EDITOR, const char *mode
    //      set editing mode to "emacs" or "vi"
  } break;
  case (EL_HIST): {
    // EL_HIST, History *(*fun)(History *, int op, ... ), const char *ptr
    //      defines which history function to use, which is usually history().
    //      Ptr should be the
    //      value returned by history_init().
  } break;
  case (EL_ADDFN): {
    // EL_ADDFN, const char *name, const char *help, unsigned char
    // (*func)(EditLine *e, int ch)
    //      add a user defined function, func), referred to as 'name' which is
    //      invoked when a key which is bound to 'name' is
    //      entered. 'help' is a description of 'name'. at invocation time, 'ch'
    //      is the key which caused the invocation. the
    //      return value of 'func()' should be one of:
    //          CC_NORM         add a normal character
    //          CC_NEWLINE      end of line was entered
    //          CC_EOF          EOF was entered
    //          CC_ARGHACK      expecting further command input as arguments, do
    //          nothing visually.
    //          CC_REFRESH      refresh display.
    //          CC_REFRESH_BEEP refresh display and beep.
    //          CC_CURSOR       cursor moved so update and perform CC_REFRESH
    //          CC_REDISPLAY        redisplay entire input line. this is useful
    //          if a key binding outputs extra information.
    //          CC_ERROR            an error occurred. beep and flush tty.
    //          CC_FATAL            fatal error, reset tty to known state.

    el_binding *binding = new el_binding;
    binding->name = va_arg(vl, const char *);
    binding->help = va_arg(vl, const char *);
    binding->func = va_arg(vl, el_addfn_func);
    binding->key = 0;
    // add this to the bindings list
    _bindings.push_back(binding);
  } break;
  case (EL_BIND): {
    // EL_BIND, const char *, ..., NULL
    //      perform the BIND built-in command.  Refer to editrc(5) for more
    //      information.

    const char *name = va_arg(vl, const char *);

    for (auto bind : _bindings) {
      if (strcmp(bind->name, name) == 0) {
        bind->key = va_arg(vl, const char *);
        break;
      }
    }

  } break;
  case (EL_CLIENTDATA): {
    clientData = va_arg(vl, void *);
  } break;
  }
  return 0;
}

void el_end(EditLine *el) {
  // assert( !"Not implemented!" );
}

void el_reset(EditLine *) { llvm_unreachable("Not implemented!"); }

int el_getc(EditLine *, char *) {
  llvm_unreachable("Not implemented!");
}

void el_push(EditLine *, const char *) {}

void el_beep(EditLine *) { Beep(1000, 500); }

int el_parse(EditLine *, int, const char **) {
  llvm_unreachable("Not implemented!");
}

int el_get(EditLine *el, int code, ...) {
  va_list vl;
  va_start(vl, code);

  switch (code) {
  case (EL_CLIENTDATA): {
    void **dout = va_arg(vl, void **);
    *dout = clientData;
  } break;
  default:
    llvm_unreachable("Not implemented!");
  }
  return 0;
}

int el_source(EditLine *el, const char *file) {
  // init edit line by reading the contents of 'file' nothing to do here on
  // windows...
  return 0;
}

void el_resize(EditLine *) { llvm_unreachable("Not implemented!"); }

const LineInfo *el_line(EditLine *el) { return 0; }

int el_insertstr(EditLine *, const char *) {
  //    assert( !"Not implemented!" );
  return 0;
}

void el_deletestr(EditLine *, int) { llvm_unreachable("Not implemented!"); }

History *history_init(void) {
  // return dummy handle
  return (History *)-1;
}

void history_end(History *) {
  //    assert( !"Not implemented!" );
}

int history(History *, HistEvent *, int op, ...) {
  // perform operation 'op' on the history list with optional arguments as
  // needed by the operation.
  return 0;
}

#endif