1 /* Copyright (c) 2013-2014 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "cli-el-backend.h"
7 
8 #include <mgba/core/version.h>
9 
10 #include <signal.h>
11 
12 static struct CLIDebugger* _activeDebugger;
13 
_prompt(EditLine * el)14 static char* _prompt(EditLine* el) {
15 	UNUSED(el);
16 	return "> ";
17 }
18 
_breakIntoDefault(int signal)19 static void _breakIntoDefault(int signal) {
20 	UNUSED(signal);
21 	mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
22 }
23 
_tabComplete(EditLine * elstate,int ch)24 static unsigned char _tabComplete(EditLine* elstate, int ch) {
25 	UNUSED(ch);
26 	const LineInfo* li = el_line(elstate);
27 	if (!li->buffer[0]) {
28 		return CC_ERROR;
29 	}
30 
31 	struct CLIDebuggerEditLineBackend* elbe;
32 	el_get(elstate, EL_CLIENTDATA, &elbe);
33 	// TODO: not always true
34 	if (CLIDebuggerTabComplete(elbe->d.p, li->buffer, true, li->cursor - li->buffer)) {
35 		return CC_REDISPLAY;
36 	}
37 	return CC_ERROR;
38 }
39 
40 ATTRIBUTE_FORMAT(printf, 2, 3)
_CLIDebuggerEditLinePrintf(struct CLIDebuggerBackend * be,const char * fmt,...)41 void _CLIDebuggerEditLinePrintf(struct CLIDebuggerBackend* be, const char* fmt, ...) {
42 	UNUSED(be);
43 	va_list args;
44 	va_start(args, fmt);
45 	vprintf(fmt, args);
46 	va_end(args);
47 }
48 
_CLIDebuggerEditLineInit(struct CLIDebuggerBackend * be)49 void _CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) {
50 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
51 	// TODO: get argv[0]
52 	elbe->elstate = el_init(binaryName, stdin, stdout, stderr);
53 	el_set(elbe->elstate, EL_PROMPT, _prompt);
54 	el_set(elbe->elstate, EL_EDITOR, "emacs");
55 
56 	el_set(elbe->elstate, EL_CLIENTDATA, elbe);
57 	el_set(elbe->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
58 	el_set(elbe->elstate, EL_BIND, "\t", "tab-complete", 0);
59 	elbe->histate = history_init();
60 	HistEvent ev;
61 	history(elbe->histate, &ev, H_SETSIZE, 200);
62 	el_set(elbe->elstate, EL_HIST, history, elbe->histate);
63 	_activeDebugger = be->p;
64 	signal(SIGINT, _breakIntoDefault);
65 }
66 
_CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend * be)67 void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
68 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
69 	history_end(elbe->histate);
70 	el_end(elbe->elstate);
71 	free(elbe);
72 }
73 
_CLIDebuggerEditLineReadLine(struct CLIDebuggerBackend * be,size_t * len)74 const char* _CLIDebuggerEditLineReadLine(struct CLIDebuggerBackend* be, size_t* len) {
75 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
76 	int count;
77 	*len = 0;
78 	const char* line = el_gets(elbe->elstate, &count);
79 	if (line) {
80 		if (count > 1) {
81 			// Crop off newline
82 			*len = (size_t) count - 1;
83 		} else if (count == 1) {
84 			*len = 1;
85 		}
86 	}
87 	return line;
88 }
_CLIDebuggerEditLineLineAppend(struct CLIDebuggerBackend * be,const char * line)89 void _CLIDebuggerEditLineLineAppend(struct CLIDebuggerBackend* be, const char* line) {
90 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
91 	el_insertstr(elbe->elstate, line);
92 }
93 
_CLIDebuggerEditLineHistoryLast(struct CLIDebuggerBackend * be,size_t * len)94 const char* _CLIDebuggerEditLineHistoryLast(struct CLIDebuggerBackend* be, size_t* len) {
95 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
96 	HistEvent ev;
97 	if (history(elbe->histate, &ev, H_FIRST) < 0) {
98 		*len = 0;
99 		return NULL;
100 	}
101 	const char* newline = strchr(ev.str, '\n');
102 	if (!newline) {
103 		*len = strlen(ev.str);
104 	} else {
105 		*len = newline - ev.str;
106 	}
107 
108 	return ev.str;
109 }
110 
_CLIDebuggerEditLineHistoryAppend(struct CLIDebuggerBackend * be,const char * line)111 void _CLIDebuggerEditLineHistoryAppend(struct CLIDebuggerBackend* be, const char* line) {
112 	struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
113 	HistEvent ev;
114 	history(elbe->histate, &ev, H_ENTER, line);
115 }
116 
CLIDebuggerEditLineBackendCreate(void)117 struct CLIDebuggerBackend* CLIDebuggerEditLineBackendCreate(void) {
118 	struct CLIDebuggerEditLineBackend* elbe = malloc(sizeof(*elbe));
119 	elbe->d.printf = _CLIDebuggerEditLinePrintf;
120 	elbe->d.init = _CLIDebuggerEditLineInit;
121 	elbe->d.deinit = _CLIDebuggerEditLineDeinit;
122 	elbe->d.readline = _CLIDebuggerEditLineReadLine;
123 	elbe->d.lineAppend = _CLIDebuggerEditLineLineAppend;
124 	elbe->d.historyLast = _CLIDebuggerEditLineHistoryLast;
125 	elbe->d.historyAppend = _CLIDebuggerEditLineHistoryAppend;
126 	return &elbe->d;
127 }
128