embox

Форк
0
/
rl_linenoise.c 
236 строк · 4.6 Кб
1
/**
2
 * @file
3
 * @brief
4
 *
5
 * @author Ilia Vaprol
6
 * @date 04.04.13
7
 */
8

9
#include <ctype.h>
10
#include <dirent.h>
11
#include <errno.h>
12
#include <limits.h>
13
#include <stddef.h>
14
#include <stdlib.h>
15
#include <string.h>
16

17
#include <cmd/shell.h>
18
#include <lib/linenoise.h>
19
#include <readline/history.h>
20
#include <readline/readline.h>
21

22
#define DEFAULT_HISTORY_FILE "~/.history"
23

24
rl_compentry_func_t *rl_completion_entry_function;
25
rl_completion_func_t *rl_attempted_completion_function;
26

27
static rl_command_func_t *complcb_function;
28
static const char *complcb_text;
29
static linenoiseCompletions *complcb_lc;
30

31
char *readline(const char *prompt) {
32
	return linenoise(prompt != NULL ? prompt : "");
33
}
34

35
void readline_free(char *line) {
36
	if (line) {
37
		linenoiseFree(line);
38
	}
39
}
40

41
static void completion_callback(const char *text, linenoiseCompletions *lc) {
42
	complcb_text = text;
43
	complcb_lc = lc;
44
	complcb_function(0, '\t');
45
}
46

47
int rl_bind_key(int key, rl_command_func_t *function) {
48
	if (key == '\t') {
49
		complcb_function = function;
50
		linenoiseSetCompletionCallback(completion_callback);
51
		return 0;
52
	}
53

54
	return EINVAL;
55
}
56

57
int rl_complete(int ignore, int invoking_key) {
58
	const char *last_word;
59
	size_t start, end;
60
	char **matches, **match, buff[SHELL_INPUT_BUFF_SZ];
61

62
	if (invoking_key != '\t') {
63
		return EINVAL;
64
	}
65

66
	end = strlen(complcb_text);
67
	last_word = complcb_text + end;
68
	while ((last_word >= complcb_text) && !isspace(*last_word)) {
69
		--last_word;
70
	}
71
	start = ++last_word - complcb_text;
72

73
	if (rl_attempted_completion_function != NULL) {
74
		matches = rl_attempted_completion_function(last_word, start, end);
75
	}
76
	else {
77
		matches = NULL;
78
	}
79

80
	if (matches == NULL) {
81
		matches = rl_completion_matches(last_word,
82
		    (rl_completion_entry_function != NULL)
83
		        ? rl_completion_entry_function
84
		        : rl_filename_completion_function);
85
		if (matches == NULL) {
86
			return 0;
87
		}
88
	}
89

90
	strncpy(&buff[0], complcb_text, start);
91
	for (match = matches + 1; *match != NULL; ++match) {
92
		strcpy(&buff[start], *match);
93
		linenoiseAddCompletion(complcb_lc, &buff[0]);
94
		free(*match);
95
	}
96
	free(matches);
97

98
	return 0;
99
}
100

101
char **rl_completion_matches(const char *text,
102
    rl_compentry_func_t *entry_func) {
103
	int ind;
104
	char **matches, **tmp, *match;
105
	size_t matches_sz;
106

107
	match = entry_func(text, 0);
108
	if (match == NULL) {
109
		return NULL;
110
	}
111

112
	matches_sz = 3 * sizeof *matches; /* +1 for null-term array */
113
	matches = malloc(matches_sz);
114
	if (matches == NULL) {
115
		free(match);
116
		return NULL; /* error: no memory */
117
	}
118

119
	matches[0] = (char *)text;
120
	matches[1] = match;
121

122
	ind = 0;
123
	while (NULL != (match = entry_func(text, ++ind))) {
124
		matches[ind + 1] = match;
125
		matches_sz += sizeof *matches;
126
		tmp = realloc(matches, matches_sz);
127
		if (tmp == NULL) {
128
			while (ind >= 0) {
129
				free(matches[ind-- + 1]);
130
			}
131
			free(matches);
132
			return NULL; /* error: no memory */
133
		}
134
		matches = tmp;
135
	}
136

137
	matches[ind + 1] = NULL;
138

139
	return matches;
140
}
141

142
char *rl_filename_completion_function(const char *text, int state) {
143
	static DIR *dir = NULL;
144
	static char path[PATH_MAX], name[NAME_MAX];
145
	static size_t path_len, name_len;
146
	struct dirent *dent;
147
	const char *slash, *tmp;
148
	char filename[PATH_MAX];
149

150
	if (state == 0) {
151
		/* parse path and name */
152
		slash = NULL;
153
		tmp = text;
154
		while (NULL != (tmp = strchr(tmp, '/'))) {
155
			slash = tmp;
156
			++tmp;
157
		}
158
		if (slash == NULL) {
159
			path[0] = '\0';
160
			strcpy(&name[0], text);
161
		}
162
		else {
163
			strncpy(&path[0], text, (slash - text + 1));
164
			path[slash - text + 1] = '\0';
165
			strcpy(&name[0], slash + 1);
166
		}
167
		path_len = strlen(&path[0]);
168
		name_len = strlen(&name[0]);
169

170
		/* close old dir */
171
		if (dir != NULL) {
172
			closedir(dir);
173
		}
174
		/* open path dir */
175
		dir = opendir(&path[0]);
176
		if (dir == NULL) {
177
			return NULL; /* error: see errno */
178
		}
179
	}
180

181
	while (NULL != (dent = readdir(dir))) {
182
		if (strncmp(&name[0], &dent->d_name[0], name_len) == 0) {
183
			strcpy(&filename[0], &path[0]);
184
			strcpy(&filename[path_len], &dent->d_name[0]);
185
			return strdup(&filename[0]);
186
		}
187
	}
188

189
	closedir(dir);
190
	dir = NULL;
191

192
	return NULL;
193
}
194

195
void add_history(const char *line) {
196
	linenoiseHistoryAdd(line);
197
}
198

199
void stifle_history(int max) {
200
	linenoiseHistorySetMaxLen(max);
201
}
202

203
int read_history(const char *filename) {
204
	if (!filename) {
205
		filename = DEFAULT_HISTORY_FILE;
206
	}
207

208
	if (-1 == linenoiseHistoryLoad(filename)) {
209
		return errno;
210
	}
211

212
	return 0;
213
}
214

215
int write_history(const char *filename) {
216
	if (!filename) {
217
		filename = DEFAULT_HISTORY_FILE;
218
	}
219

220
	if (-1 == linenoiseHistorySave(filename)) {
221
		return errno;
222
	}
223

224
	return 0;
225
}
226

227
void readline_init(void) {
228
	/* init global */
229
	rl_completion_entry_function = NULL;
230
	rl_attempted_completion_function = NULL;
231

232
	/* init static */
233
	complcb_function = NULL;
234
	complcb_text = NULL;
235
	complcb_lc = NULL;
236
}
237

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.