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 ---------------------------------------------------===//
//
// 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
|