GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/emacs.c Lines: 0 158 0.0 %
Date: 2017-11-07 Branches: 0 86 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: emacs.c,v 1.17 2016/05/06 13:12:52 schwarze Exp $	*/
2
/*	$NetBSD: emacs.c,v 1.35 2016/04/18 17:01:19 christos Exp $	*/
3
4
/*-
5
 * Copyright (c) 1992, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Christos Zoulas of Cornell University.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
#include "config.h"
37
38
/*
39
 * emacs.c: Emacs functions
40
 */
41
#include <ctype.h>
42
43
#include "el.h"
44
#include "emacs.h"
45
#include "fcns.h"
46
47
/* em_delete_or_list():
48
 *	Delete character under cursor or list completions if at end of line
49
 *	[^D]
50
 */
51
protected el_action_t
52
/*ARGSUSED*/
53
em_delete_or_list(EditLine *el, wint_t c)
54
{
55
56
	if (el->el_line.cursor == el->el_line.lastchar) {
57
					/* if I'm at the end */
58
		if (el->el_line.cursor == el->el_line.buffer) {
59
					/* and the beginning */
60
			terminal_writec(el, c);	/* then do an EOF */
61
			return CC_EOF;
62
		} else {
63
			/*
64
			 * Here we could list completions, but it is an
65
			 * error right now
66
			 */
67
			terminal_beep(el);
68
			return CC_ERROR;
69
		}
70
	} else {
71
		if (el->el_state.doingarg)
72
			c_delafter(el, el->el_state.argument);
73
		else
74
			c_delafter1(el);
75
		if (el->el_line.cursor > el->el_line.lastchar)
76
			el->el_line.cursor = el->el_line.lastchar;
77
				/* bounds check */
78
		return CC_REFRESH;
79
	}
80
}
81
82
83
/* em_delete_next_word():
84
 *	Cut from cursor to end of current word
85
 *	[M-d]
86
 */
87
protected el_action_t
88
/*ARGSUSED*/
89
em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
90
{
91
	wchar_t *cp, *p, *kp;
92
93
	if (el->el_line.cursor == el->el_line.lastchar)
94
		return CC_ERROR;
95
96
	cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
97
	    el->el_state.argument, ce__isword);
98
99
	for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
100
				/* save the text */
101
		*kp++ = *p;
102
	el->el_chared.c_kill.last = kp;
103
104
	c_delafter(el, (int)(cp - el->el_line.cursor));	/* delete after dot */
105
	if (el->el_line.cursor > el->el_line.lastchar)
106
		el->el_line.cursor = el->el_line.lastchar;
107
				/* bounds check */
108
	return CC_REFRESH;
109
}
110
111
112
/* em_yank():
113
 *	Paste cut buffer at cursor position
114
 *	[^Y]
115
 */
116
protected el_action_t
117
/*ARGSUSED*/
118
em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
119
{
120
	wchar_t *kp, *cp;
121
122
	if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
123
		return CC_NORM;
124
125
	if (el->el_line.lastchar +
126
	    (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
127
	    el->el_line.limit)
128
		return CC_ERROR;
129
130
	el->el_chared.c_kill.mark = el->el_line.cursor;
131
	cp = el->el_line.cursor;
132
133
	/* open the space, */
134
	c_insert(el,
135
	    (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
136
	/* copy the chars */
137
	for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
138
		*cp++ = *kp;
139
140
	/* if an arg, cursor at beginning else cursor at end */
141
	if (el->el_state.argument == 1)
142
		el->el_line.cursor = cp;
143
144
	return CC_REFRESH;
145
}
146
147
148
/* em_kill_line():
149
 *	Cut the entire line and save in cut buffer
150
 *	[^U]
151
 */
152
protected el_action_t
153
/*ARGSUSED*/
154
em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
155
{
156
	wchar_t *kp, *cp;
157
158
	cp = el->el_line.buffer;
159
	kp = el->el_chared.c_kill.buf;
160
	while (cp < el->el_line.lastchar)
161
		*kp++ = *cp++;	/* copy it */
162
	el->el_chared.c_kill.last = kp;
163
				/* zap! -- delete all of it */
164
	el->el_line.lastchar = el->el_line.buffer;
165
	el->el_line.cursor = el->el_line.buffer;
166
	return CC_REFRESH;
167
}
168
169
170
/* em_kill_region():
171
 *	Cut area between mark and cursor and save in cut buffer
172
 *	[^W]
173
 */
174
protected el_action_t
175
/*ARGSUSED*/
176
em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
177
{
178
	wchar_t *kp, *cp;
179
180
	if (!el->el_chared.c_kill.mark)
181
		return CC_ERROR;
182
183
	if (el->el_chared.c_kill.mark > el->el_line.cursor) {
184
		cp = el->el_line.cursor;
185
		kp = el->el_chared.c_kill.buf;
186
		while (cp < el->el_chared.c_kill.mark)
187
			*kp++ = *cp++;	/* copy it */
188
		el->el_chared.c_kill.last = kp;
189
		c_delafter(el, (int)(cp - el->el_line.cursor));
190
	} else {		/* mark is before cursor */
191
		cp = el->el_chared.c_kill.mark;
192
		kp = el->el_chared.c_kill.buf;
193
		while (cp < el->el_line.cursor)
194
			*kp++ = *cp++;	/* copy it */
195
		el->el_chared.c_kill.last = kp;
196
		c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
197
		el->el_line.cursor = el->el_chared.c_kill.mark;
198
	}
199
	return CC_REFRESH;
200
}
201
202
203
/* em_copy_region():
204
 *	Copy area between mark and cursor to cut buffer
205
 *	[M-W]
206
 */
207
protected el_action_t
208
/*ARGSUSED*/
209
em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
210
{
211
	wchar_t *kp, *cp;
212
213
	if (!el->el_chared.c_kill.mark)
214
		return CC_ERROR;
215
216
	if (el->el_chared.c_kill.mark > el->el_line.cursor) {
217
		cp = el->el_line.cursor;
218
		kp = el->el_chared.c_kill.buf;
219
		while (cp < el->el_chared.c_kill.mark)
220
			*kp++ = *cp++;	/* copy it */
221
		el->el_chared.c_kill.last = kp;
222
	} else {
223
		cp = el->el_chared.c_kill.mark;
224
		kp = el->el_chared.c_kill.buf;
225
		while (cp < el->el_line.cursor)
226
			*kp++ = *cp++;	/* copy it */
227
		el->el_chared.c_kill.last = kp;
228
	}
229
	return CC_NORM;
230
}
231
232
233
/* em_gosmacs_transpose():
234
 *	Exchange the two characters before the cursor
235
 *	Gosling emacs transpose chars [^T]
236
 */
237
protected el_action_t
238
em_gosmacs_transpose(EditLine *el, wint_t c)
239
{
240
241
	if (el->el_line.cursor > &el->el_line.buffer[1]) {
242
		/* must have at least two chars entered */
243
		c = el->el_line.cursor[-2];
244
		el->el_line.cursor[-2] = el->el_line.cursor[-1];
245
		el->el_line.cursor[-1] = c;
246
		return CC_REFRESH;
247
	} else
248
		return CC_ERROR;
249
}
250
251
252
/* em_next_word():
253
 *	Move next to end of current word
254
 *	[M-f]
255
 */
256
protected el_action_t
257
/*ARGSUSED*/
258
em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
259
{
260
	if (el->el_line.cursor == el->el_line.lastchar)
261
		return CC_ERROR;
262
263
	el->el_line.cursor = c__next_word(el->el_line.cursor,
264
	    el->el_line.lastchar,
265
	    el->el_state.argument,
266
	    ce__isword);
267
268
	if (el->el_map.type == MAP_VI)
269
		if (el->el_chared.c_vcmd.action != NOP) {
270
			cv_delfini(el);
271
			return CC_REFRESH;
272
		}
273
	return CC_CURSOR;
274
}
275
276
277
/* em_upper_case():
278
 *	Uppercase the characters from cursor to end of current word
279
 *	[M-u]
280
 */
281
protected el_action_t
282
/*ARGSUSED*/
283
em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
284
{
285
	wchar_t *cp, *ep;
286
287
	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
288
	    el->el_state.argument, ce__isword);
289
290
	for (cp = el->el_line.cursor; cp < ep; cp++)
291
		if (iswlower(*cp))
292
			*cp = towupper(*cp);
293
294
	el->el_line.cursor = ep;
295
	if (el->el_line.cursor > el->el_line.lastchar)
296
		el->el_line.cursor = el->el_line.lastchar;
297
	return CC_REFRESH;
298
}
299
300
301
/* em_capitol_case():
302
 *	Capitalize the characters from cursor to end of current word
303
 *	[M-c]
304
 */
305
protected el_action_t
306
/*ARGSUSED*/
307
em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
308
{
309
	wchar_t *cp, *ep;
310
311
	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
312
	    el->el_state.argument, ce__isword);
313
314
	for (cp = el->el_line.cursor; cp < ep; cp++) {
315
		if (iswalpha(*cp)) {
316
			if (iswlower(*cp))
317
				*cp = towupper(*cp);
318
			cp++;
319
			break;
320
		}
321
	}
322
	for (; cp < ep; cp++)
323
		if (iswupper(*cp))
324
			*cp = towlower(*cp);
325
326
	el->el_line.cursor = ep;
327
	if (el->el_line.cursor > el->el_line.lastchar)
328
		el->el_line.cursor = el->el_line.lastchar;
329
	return CC_REFRESH;
330
}
331
332
333
/* em_lower_case():
334
 *	Lowercase the characters from cursor to end of current word
335
 *	[M-l]
336
 */
337
protected el_action_t
338
/*ARGSUSED*/
339
em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
340
{
341
	wchar_t *cp, *ep;
342
343
	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
344
	    el->el_state.argument, ce__isword);
345
346
	for (cp = el->el_line.cursor; cp < ep; cp++)
347
		if (iswupper(*cp))
348
			*cp = towlower(*cp);
349
350
	el->el_line.cursor = ep;
351
	if (el->el_line.cursor > el->el_line.lastchar)
352
		el->el_line.cursor = el->el_line.lastchar;
353
	return CC_REFRESH;
354
}
355
356
357
/* em_set_mark():
358
 *	Set the mark at cursor
359
 *	[^@]
360
 */
361
protected el_action_t
362
/*ARGSUSED*/
363
em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
364
{
365
366
	el->el_chared.c_kill.mark = el->el_line.cursor;
367
	return CC_NORM;
368
}
369
370
371
/* em_exchange_mark():
372
 *	Exchange the cursor and mark
373
 *	[^X^X]
374
 */
375
protected el_action_t
376
/*ARGSUSED*/
377
em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
378
{
379
	wchar_t *cp;
380
381
	cp = el->el_line.cursor;
382
	el->el_line.cursor = el->el_chared.c_kill.mark;
383
	el->el_chared.c_kill.mark = cp;
384
	return CC_CURSOR;
385
}
386
387
388
/* em_universal_argument():
389
 *	Universal argument (argument times 4)
390
 *	[^U]
391
 */
392
protected el_action_t
393
/*ARGSUSED*/
394
em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
395
{				/* multiply current argument by 4 */
396
397
	if (el->el_state.argument > 1000000)
398
		return CC_ERROR;
399
	el->el_state.doingarg = 1;
400
	el->el_state.argument *= 4;
401
	return CC_ARGHACK;
402
}
403
404
405
/* em_meta_next():
406
 *	Add 8th bit to next character typed
407
 *	[<ESC>]
408
 */
409
protected el_action_t
410
/*ARGSUSED*/
411
em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
412
{
413
414
	el->el_state.metanext = 1;
415
	return CC_ARGHACK;
416
}
417
418
419
/* em_toggle_overwrite():
420
 *	Switch from insert to overwrite mode or vice versa
421
 */
422
protected el_action_t
423
/*ARGSUSED*/
424
em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
425
{
426
427
	el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
428
	    MODE_REPLACE : MODE_INSERT;
429
	return CC_NORM;
430
}
431
432
433
/* em_copy_prev_word():
434
 *	Copy current word to cursor
435
 */
436
protected el_action_t
437
/*ARGSUSED*/
438
em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
439
{
440
	wchar_t *cp, *oldc, *dp;
441
442
	if (el->el_line.cursor == el->el_line.buffer)
443
		return CC_ERROR;
444
445
	oldc = el->el_line.cursor;
446
	/* does a bounds check */
447
	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
448
	    el->el_state.argument, ce__isword);
449
450
	c_insert(el, (int)(oldc - cp));
451
	for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
452
		*dp++ = *cp;
453
454
	el->el_line.cursor = dp;/* put cursor at end */
455
456
	return CC_REFRESH;
457
}
458
459
460
/* em_inc_search_next():
461
 *	Emacs incremental next search
462
 */
463
protected el_action_t
464
/*ARGSUSED*/
465
em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
466
{
467
468
	el->el_search.patlen = 0;
469
	return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
470
}
471
472
473
/* em_inc_search_prev():
474
 *	Emacs incremental reverse search
475
 */
476
protected el_action_t
477
/*ARGSUSED*/
478
em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
479
{
480
481
	el->el_search.patlen = 0;
482
	return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
483
}
484
485
486
/* em_delete_prev_char():
487
 *	Delete the character to the left of the cursor
488
 *	[^?]
489
 */
490
protected el_action_t
491
/*ARGSUSED*/
492
em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
493
{
494
495
	if (el->el_line.cursor <= el->el_line.buffer)
496
		return CC_ERROR;
497
498
	if (el->el_state.doingarg)
499
		c_delbefore(el, el->el_state.argument);
500
	else
501
		c_delbefore1(el);
502
	el->el_line.cursor -= el->el_state.argument;
503
	if (el->el_line.cursor < el->el_line.buffer)
504
		el->el_line.cursor = el->el_line.buffer;
505
	return CC_REFRESH;
506
}