1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: stable/11/lib/libedit/TEST/wtc1.c 313981 2017-02-20 03:33:59Z pfg $");
3
4#include <stdio.h>
5#include <string.h>
6#include <signal.h>
7#include <sys/wait.h>
8#include <ctype.h>
9#include <dirent.h>
10#include <err.h>
11#include <limits.h>
12#include <locale.h>
13#include <signal.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <unistd.h>
18
19#include "../histedit.h"
20
21
22static int continuation;
23volatile sig_atomic_t gotsig;
24static const char hfile[] = ".whistory";
25
26static wchar_t *
27prompt(EditLine *el)
28{
29	static wchar_t a[] = L"\1\033[7m\1Edit$\1\033[0m\1 ";
30	static wchar_t b[] = L"Edit> ";
31
32	return continuation ? b : a;
33}
34
35
36static void
37sig(int i)
38{
39	gotsig = i;
40}
41
42const char *
43my_wcstombs(const wchar_t *wstr)
44{
45	static struct {
46		char *str;
47		int len;
48	} buf;
49
50	int needed = wcstombs(0, wstr, 0) + 1;
51	if (needed > buf.len) {
52		buf.str = malloc(needed);
53		buf.len = needed;
54	}
55	wcstombs(buf.str, wstr, needed);
56	buf.str[needed - 1] = 0;
57
58	return buf.str;
59}
60
61
62static unsigned char
63complete(EditLine *el, int ch)
64{
65	DIR *dd = opendir(".");
66	struct dirent *dp;
67	const wchar_t *ptr;
68	char *buf, *bptr;
69	const LineInfoW *lf = el_wline(el);
70	int len, mblen, i;
71	unsigned char res = 0;
72	wchar_t dir[1024];
73
74	/* Find the last word */
75	for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr)
76		continue;
77	len = lf->cursor - ++ptr;
78
79	/* Convert last word to multibyte encoding, so we can compare to it */
80	wctomb(NULL, 0); /* Reset shift state */
81	mblen = MB_LEN_MAX * len + 1;
82	buf = bptr = malloc(mblen);
83	if (buf == NULL)
84		err(1, "malloc");
85	for (i = 0; i < len; ++i) {
86		/* Note: really should test for -1 return from wctomb */
87		bptr += wctomb(bptr, ptr[i]);
88	}
89	*bptr = 0; /* Terminate multibyte string */
90	mblen = bptr - buf;
91
92	/* Scan directory for matching name */
93	for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
94		if (mblen > strlen(dp->d_name))
95			continue;
96		if (strncmp(dp->d_name, buf, mblen) == 0) {
97			mbstowcs(dir, &dp->d_name[mblen],
98			    sizeof(dir) / sizeof(*dir));
99			if (el_winsertstr(el, dir) == -1)
100				res = CC_ERROR;
101			else
102				res = CC_REFRESH;
103			break;
104		}
105	}
106
107	closedir(dd);
108	free(buf);
109	return res;
110}
111
112
113int
114main(int argc, char *argv[])
115{
116	EditLine *el = NULL;
117	int numc, ncontinuation;
118	const wchar_t *line;
119	TokenizerW *tok;
120	HistoryW *hist;
121	HistEventW ev;
122#ifdef DEBUG
123	int i;
124#endif
125
126	setlocale(LC_ALL, "");
127
128	(void)signal(SIGINT,  sig);
129	(void)signal(SIGQUIT, sig);
130	(void)signal(SIGHUP,  sig);
131	(void)signal(SIGTERM, sig);
132
133	hist = history_winit();		/* Init built-in history     */
134	history_w(hist, &ev, H_SETSIZE, 100);	/* Remember 100 events	     */
135	history_w(hist, &ev, H_LOAD, hfile);
136
137	tok = tok_winit(NULL);			/* Init the tokenizer	     */
138
139	el = el_init(argv[0], stdin, stdout, stderr);
140
141	el_wset(el, EL_EDITOR, L"vi");		/* Default editor is vi	     */
142	el_wset(el, EL_SIGNAL, 1);		/* Handle signals gracefully */
143	el_wset(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */
144
145	el_wset(el, EL_HIST, history_w, hist);	/* FIXME - history_w? */
146
147					/* Add a user-defined function	*/
148	el_wset(el, EL_ADDFN, L"ed-complete", L"Complete argument", complete);
149
150					/* Bind <tab> to it */
151	el_wset(el, EL_BIND, L"^I", L"ed-complete", NULL);
152
153	/*
154	* Bind j, k in vi command mode to previous and next line, instead
155	* of previous and next history.
156	*/
157	el_wset(el, EL_BIND, L"-a", L"k", L"ed-prev-line", NULL);
158	el_wset(el, EL_BIND, L"-a", L"j", L"ed-next-line", NULL);
159
160	/* Source the user's defaults file. */
161	el_source(el, NULL);
162
163	while((line = el_wgets(el, &numc)) != NULL && numc != 0) {
164		int ac, cc, co, rc;
165		const wchar_t **av;
166
167		const LineInfoW *li;
168		li = el_wline(el);
169
170#ifdef DEBUG
171		(void)fwprintf(stderr, L"==> got %d %ls", numc, line);
172		(void)fwprintf(stderr, L"  > li `%.*ls_%.*ls'\n",
173		    (li->cursor - li->buffer), li->buffer,
174		    (li->lastchar - 1 - li->cursor),
175		    (li->cursor >= li->lastchar) ? L"" : li->cursor);
176#endif
177
178		if (gotsig) {
179			(void)fprintf(stderr, "Got signal %d.\n", (int)gotsig);
180			gotsig = 0;
181			el_reset(el);
182		}
183
184		if(!continuation && numc == 1)
185			continue;	/* Only got a linefeed */
186
187		ac = cc = co = 0;
188		ncontinuation = tok_wline(tok, li, &ac, &av, &cc, &co);
189		if (ncontinuation < 0) {
190			(void) fprintf(stderr, "Internal error\n");
191			continuation = 0;
192			continue;
193		}
194
195#ifdef DEBUG
196		(void)fprintf(stderr, "  > nc %d ac %d cc %d co %d\n",
197			ncontinuation, ac, cc, co);
198#endif
199		history_w(hist, &ev, continuation ? H_APPEND : H_ENTER, line);
200
201		continuation = ncontinuation;
202		ncontinuation = 0;
203		if(continuation)
204			continue;
205
206#ifdef DEBUG
207		for (i = 0; i < ac; ++i) {
208			(void)fwprintf(stderr, L"  > arg# %2d ", i);
209			if (i != cc)
210				(void)fwprintf(stderr, L"`%ls'\n", av[i]);
211			else
212				(void)fwprintf(stderr, L"`%.*ls_%ls'\n",
213				    co, av[i], av[i] + co);
214		}
215#endif
216
217		if (wcscmp (av[0], L"history") == 0) {
218			switch(ac) {
219			case 1:
220				for(rc = history_w(hist, &ev, H_LAST);
221				     rc != -1;
222				     rc = history_w(hist, &ev, H_PREV))
223					(void)fwprintf(stdout, L"%4d %ls",
224					     ev.num, ev.str);
225				break;
226			case 2:
227				if (wcscmp(av[1], L"clear") == 0)
228					history_w(hist, &ev, H_CLEAR);
229				else
230					goto badhist;
231				break;
232			case 3:
233				if (wcscmp(av[1], L"load") == 0)
234					history_w(hist, &ev, H_LOAD,
235					    my_wcstombs(av[2]));
236				else if (wcscmp(av[1], L"save") == 0)
237					history_w(hist, &ev, H_SAVE,
238					    my_wcstombs(av[2]));
239				else
240					goto badhist;
241				break;
242			badhist:
243			default:
244				(void)fprintf(stderr,
245				    "Bad history arguments\n");
246				break;
247			}
248		} else if (el_wparse(el, ac, av) == -1) {
249			switch (fork()) {
250			case 0: {
251				Tokenizer *ntok = tok_init(NULL);
252				int nargc;
253				const char **nav;
254				tok_str(ntok, my_wcstombs(line), &nargc, &nav);
255				execvp(nav[0],(char **)nav);
256				perror(nav[0]);
257				_exit(1);
258				/* NOTREACHED */
259				break;
260			}
261			case -1:
262				perror("fork");
263				break;
264			default:
265				if (wait(&rc) == -1)
266					perror("wait");
267				(void)fprintf(stderr, "Exit %x\n", rc);
268				break;
269			}
270		}
271
272		tok_wreset(tok);
273	}
274
275	el_end(el);
276	tok_wend(tok);
277	history_w(hist, &ev, H_SAVE, hfile);
278	history_wend(hist);
279
280	fprintf(stdout, "\n");
281	return 0;
282}
283
284
285