GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/word.c Lines: 0 236 0.0 %
Date: 2017-11-13 Branches: 0 176 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: word.c,v 1.19 2015/12/30 20:51:51 lum Exp $	*/
2
3
/* This file is in the public domain. */
4
5
/*
6
 *		Word mode commands.
7
 * The routines in this file implement commands that work word at a time.
8
 * There are all sorts of word mode commands.
9
 */
10
11
#include <sys/queue.h>
12
#include <signal.h>
13
#include <errno.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
#include "def.h"
19
20
RSIZE	countfword(void);
21
int	grabword(char **);
22
23
/*
24
 * Move the cursor backward by "n" words. All of the details of motion are
25
 * performed by the "backchar" and "forwchar" routines.
26
 */
27
/* ARGSUSED */
28
int
29
backword(int f, int n)
30
{
31
	if (n < 0)
32
		return (forwword(f | FFRAND, -n));
33
	if (backchar(FFRAND, 1) == FALSE)
34
		return (FALSE);
35
	while (n--) {
36
		while (inword() == FALSE) {
37
			if (backchar(FFRAND, 1) == FALSE)
38
				return (TRUE);
39
		}
40
		while (inword() != FALSE) {
41
			if (backchar(FFRAND, 1) == FALSE)
42
				return (TRUE);
43
		}
44
	}
45
	return (forwchar(FFRAND, 1));
46
}
47
48
/*
49
 * Move the cursor forward by the specified number of words.  All of the
50
 * motion is done by "forwchar".
51
 */
52
/* ARGSUSED */
53
int
54
forwword(int f, int n)
55
{
56
	if (n < 0)
57
		return (backword(f | FFRAND, -n));
58
	while (n--) {
59
		while (inword() == FALSE) {
60
			if (forwchar(FFRAND, 1) == FALSE)
61
				return (TRUE);
62
		}
63
		while (inword() != FALSE) {
64
			if (forwchar(FFRAND, 1) == FALSE)
65
				return (TRUE);
66
		}
67
	}
68
	return (TRUE);
69
}
70
71
/*
72
 * Transpose 2 words.
73
 * The function below is artifically restricted to only a maximum of 1 iteration
74
 * at the moment because the 'undo' functionality within mg needs amended for
75
 * multiple movements of point, backwards and forwards.
76
 */
77
int
78
transposeword(int f, int n)
79
{
80
	struct line	*tmp1_w_dotp = NULL;
81
	struct line	*tmp2_w_dotp = NULL;
82
	int		 tmp2_w_doto = 0;
83
	int		 tmp1_w_dotline = 0;
84
	int		 tmp2_w_dotline = 0;
85
	int		 tmp1_w_doto;
86
	int		 i;		/* start-of-line space counter */
87
	int		 ret, s;
88
	int		 newline;
89
	int		 leave = 0;
90
	int		 tmp_len;
91
	char		*word1 = NULL;
92
	char		*word2 = NULL;
93
	char		*chr;
94
95
	if (n == 0)
96
		return (TRUE);
97
98
	n = 1; /* remove this line to allow muliple-iterations */
99
100
	if ((s = checkdirty(curbp)) != TRUE)
101
		return (s);
102
	if (curbp->b_flag & BFREADONLY) {
103
		dobeep();
104
		ewprintf("Buffer is read-only");
105
		return (FALSE);
106
	}
107
	undo_boundary_enable(FFRAND, 0);
108
109
	/* go backwards to find the start of a word to transpose. */
110
	(void)backword(FFRAND, 1);
111
	ret = grabword(&word1);
112
	if (ret == ABORT) {
113
		ewprintf("No word to the left to tranpose.");
114
		return (FALSE);
115
	}
116
	if (ret < 0) {
117
		dobeep();
118
		ewprintf("Error copying word: %s", strerror(ret));
119
		free(word1);
120
		return (FALSE);
121
	}
122
123
	while (n-- > 0) {
124
		i = 0;
125
		newline = 0;
126
127
		tmp1_w_doto = curwp->w_doto;
128
		tmp1_w_dotline = curwp->w_dotline;
129
		tmp1_w_dotp = curwp->w_dotp;
130
131
		/* go forward and find next word. */
132
		while (inword() == FALSE) {
133
			if (forwchar(FFRAND, 1) == FALSE) {
134
				leave = 1;
135
				if (tmp1_w_dotline < curwp->w_dotline)
136
					curwp->w_dotline--;
137
				ewprintf("Don't have two things to transpose");
138
				break;
139
			}
140
			if (curwp->w_doto == 0) {
141
				newline = 1;
142
				i = 0;
143
			} else if (newline)
144
				i++;
145
		}
146
		if (leave) {
147
			tmp2_w_doto = tmp1_w_doto;
148
			tmp2_w_dotline = tmp1_w_dotline;
149
			tmp2_w_dotp = tmp1_w_dotp;
150
			break;
151
		}
152
		tmp2_w_doto = curwp->w_doto;
153
		tmp2_w_dotline = curwp->w_dotline;
154
		tmp2_w_dotp = curwp->w_dotp;
155
156
		ret = grabword(&word2);
157
		if (ret < 0 || ret == ABORT) {
158
			dobeep();
159
			ewprintf("Error copying word: %s", strerror(ret));
160
			free(word1);
161
			return (FALSE);
162
		}
163
		tmp_len = strlen(word2);
164
		tmp2_w_doto += tmp_len;
165
166
		curwp->w_doto = tmp1_w_doto;
167
		curwp->w_dotline = tmp1_w_dotline;
168
		curwp->w_dotp = tmp1_w_dotp;
169
170
		/* insert shuffled along word */
171
		for (chr = word2; *chr != '\0'; ++chr)
172
			linsert(1, *chr);
173
174
		if (newline)
175
			tmp2_w_doto = i;
176
177
		curwp->w_doto = tmp2_w_doto;
178
		curwp->w_dotline = tmp2_w_dotline;
179
		curwp->w_dotp = tmp2_w_dotp;
180
181
		word2 = NULL;
182
	}
183
	curwp->w_doto = tmp2_w_doto;
184
	curwp->w_dotline = tmp2_w_dotline;
185
	curwp->w_dotp = tmp2_w_dotp;
186
187
	/* insert very first word in its new position */
188
	for (chr = word1; *chr != '\0'; ++chr)
189
		linsert(1, *chr);
190
191
	if (leave)
192
		(void)backword(FFRAND, 1);
193
194
	free(word1);
195
	free(word2);
196
197
	undo_boundary_enable(FFRAND, 1);
198
199
	return (TRUE);
200
}
201
202
/*
203
 * copy and delete word.
204
*/
205
int
206
grabword(char **word)
207
{
208
	int c;
209
210
	while (inword() == TRUE) {
211
		c = lgetc(curwp->w_dotp, curwp->w_doto);
212
		if (*word == NULL) {
213
			if (asprintf(word, "%c", c) == -1)
214
				return (errno);
215
		} else {
216
			if (asprintf(word, "%s%c", *word, c) == -1)
217
				return (errno);
218
		}
219
		(void)forwdel(FFRAND, 1);
220
	}
221
	if (*word == NULL)
222
		return (ABORT);
223
	return (TRUE);
224
}
225
226
/*
227
 * Move the cursor forward by the specified number of words.  As you move,
228
 * convert any characters to upper case.
229
 */
230
/* ARGSUSED */
231
int
232
upperword(int f, int n)
233
{
234
	int	c, s;
235
	RSIZE	size;
236
237
	if ((s = checkdirty(curbp)) != TRUE)
238
		return (s);
239
	if (curbp->b_flag & BFREADONLY) {
240
		dobeep();
241
		ewprintf("Buffer is read-only");
242
		return (FALSE);
243
	}
244
245
	if (n < 0)
246
		return (FALSE);
247
	while (n--) {
248
		while (inword() == FALSE) {
249
			if (forwchar(FFRAND, 1) == FALSE)
250
				return (TRUE);
251
		}
252
		size = countfword();
253
		undo_add_change(curwp->w_dotp, curwp->w_doto, size);
254
255
		while (inword() != FALSE) {
256
			c = lgetc(curwp->w_dotp, curwp->w_doto);
257
			if (ISLOWER(c) != FALSE) {
258
				c = TOUPPER(c);
259
				lputc(curwp->w_dotp, curwp->w_doto, c);
260
				lchange(WFFULL);
261
			}
262
			if (forwchar(FFRAND, 1) == FALSE)
263
				return (TRUE);
264
		}
265
	}
266
	return (TRUE);
267
}
268
269
/*
270
 * Move the cursor forward by the specified number of words.  As you move
271
 * convert characters to lower case.
272
 */
273
/* ARGSUSED */
274
int
275
lowerword(int f, int n)
276
{
277
	int	c, s;
278
	RSIZE	size;
279
280
	if ((s = checkdirty(curbp)) != TRUE)
281
		return (s);
282
	if (curbp->b_flag & BFREADONLY) {
283
		dobeep();
284
		ewprintf("Buffer is read-only");
285
		return (FALSE);
286
	}
287
	if (n < 0)
288
		return (FALSE);
289
	while (n--) {
290
		while (inword() == FALSE) {
291
			if (forwchar(FFRAND, 1) == FALSE)
292
				return (TRUE);
293
		}
294
		size = countfword();
295
		undo_add_change(curwp->w_dotp, curwp->w_doto, size);
296
297
		while (inword() != FALSE) {
298
			c = lgetc(curwp->w_dotp, curwp->w_doto);
299
			if (ISUPPER(c) != FALSE) {
300
				c = TOLOWER(c);
301
				lputc(curwp->w_dotp, curwp->w_doto, c);
302
				lchange(WFFULL);
303
			}
304
			if (forwchar(FFRAND, 1) == FALSE)
305
				return (TRUE);
306
		}
307
	}
308
	return (TRUE);
309
}
310
311
/*
312
 * Move the cursor forward by the specified number of words.  As you move
313
 * convert the first character of the word to upper case, and subsequent
314
 * characters to lower case.  Error if you try to move past the end of the
315
 * buffer.
316
 */
317
/* ARGSUSED */
318
int
319
capword(int f, int n)
320
{
321
	int	c, s;
322
	RSIZE	size;
323
324
	if ((s = checkdirty(curbp)) != TRUE)
325
		return (s);
326
	if (curbp->b_flag & BFREADONLY) {
327
		dobeep();
328
		ewprintf("Buffer is read-only");
329
		return (FALSE);
330
	}
331
332
	if (n < 0)
333
		return (FALSE);
334
	while (n--) {
335
		while (inword() == FALSE) {
336
			if (forwchar(FFRAND, 1) == FALSE)
337
				return (TRUE);
338
		}
339
		size = countfword();
340
		undo_add_change(curwp->w_dotp, curwp->w_doto, size);
341
342
		if (inword() != FALSE) {
343
			c = lgetc(curwp->w_dotp, curwp->w_doto);
344
			if (ISLOWER(c) != FALSE) {
345
				c = TOUPPER(c);
346
				lputc(curwp->w_dotp, curwp->w_doto, c);
347
				lchange(WFFULL);
348
			}
349
			if (forwchar(FFRAND, 1) == FALSE)
350
				return (TRUE);
351
			while (inword() != FALSE) {
352
				c = lgetc(curwp->w_dotp, curwp->w_doto);
353
				if (ISUPPER(c) != FALSE) {
354
					c = TOLOWER(c);
355
					lputc(curwp->w_dotp, curwp->w_doto, c);
356
					lchange(WFFULL);
357
				}
358
				if (forwchar(FFRAND, 1) == FALSE)
359
					return (TRUE);
360
			}
361
		}
362
	}
363
	return (TRUE);
364
}
365
366
/*
367
 * Count characters in word, from current position
368
 */
369
RSIZE
370
countfword()
371
{
372
	RSIZE		 size;
373
	struct line	*dotp;
374
	int		 doto;
375
376
	dotp = curwp->w_dotp;
377
	doto = curwp->w_doto;
378
	size = 0;
379
380
	while (inword() != FALSE) {
381
		if (forwchar(FFRAND, 1) == FALSE)
382
			/* hit the end of the buffer */
383
			goto out;
384
		++size;
385
	}
386
out:
387
	curwp->w_dotp = dotp;
388
	curwp->w_doto = doto;
389
	return (size);
390
}
391
392
393
/*
394
 * Kill forward by "n" words.
395
 */
396
/* ARGSUSED */
397
int
398
delfword(int f, int n)
399
{
400
	RSIZE		 size;
401
	struct line	*dotp;
402
	int		 doto;
403
	int s;
404
405
	if ((s = checkdirty(curbp)) != TRUE)
406
		return (s);
407
	if (curbp->b_flag & BFREADONLY) {
408
		dobeep();
409
		ewprintf("Buffer is read-only");
410
		return (FALSE);
411
	}
412
	if (n < 0)
413
		return (FALSE);
414
415
	/* purge kill buffer */
416
	if ((lastflag & CFKILL) == 0)
417
		kdelete();
418
419
	thisflag |= CFKILL;
420
	dotp = curwp->w_dotp;
421
	doto = curwp->w_doto;
422
	size = 0;
423
424
	while (n--) {
425
		while (inword() == FALSE) {
426
			if (forwchar(FFRAND, 1) == FALSE)
427
				/* hit the end of the buffer */
428
				goto out;
429
			++size;
430
		}
431
		while (inword() != FALSE) {
432
			if (forwchar(FFRAND, 1) == FALSE)
433
				/* hit the end of the buffer */
434
				goto out;
435
			++size;
436
		}
437
	}
438
out:
439
	curwp->w_dotp = dotp;
440
	curwp->w_doto = doto;
441
	return (ldelete(size, KFORW));
442
}
443
444
/*
445
 * Kill backwards by "n" words.  The rules for success and failure are now
446
 * different, to prevent strange behavior at the start of the buffer.  The
447
 * command only fails if something goes wrong with the actual delete of the
448
 * characters.  It is successful even if no characters are deleted, or if you
449
 * say delete 5 words, and there are only 4 words left.  I considered making
450
 * the first call to "backchar" special, but decided that that would just be
451
 * weird. Normally this is bound to "M-Rubout" and to "M-Backspace".
452
 */
453
/* ARGSUSED */
454
int
455
delbword(int f, int n)
456
{
457
	RSIZE	size;
458
	int s;
459
460
	if ((s = checkdirty(curbp)) != TRUE)
461
		return (s);
462
	if (curbp->b_flag & BFREADONLY) {
463
		dobeep();
464
		ewprintf("Buffer is read-only");
465
		return (FALSE);
466
	}
467
468
	if (n < 0)
469
		return (FALSE);
470
471
	/* purge kill buffer */
472
	if ((lastflag & CFKILL) == 0)
473
		kdelete();
474
	thisflag |= CFKILL;
475
	if (backchar(FFRAND, 1) == FALSE)
476
		/* hit buffer start */
477
		return (TRUE);
478
479
	/* one deleted */
480
	size = 1;
481
	while (n--) {
482
		while (inword() == FALSE) {
483
			if (backchar(FFRAND, 1) == FALSE)
484
				/* hit buffer start */
485
				goto out;
486
			++size;
487
		}
488
		while (inword() != FALSE) {
489
			if (backchar(FFRAND, 1) == FALSE)
490
				/* hit buffer start */
491
				goto out;
492
			++size;
493
		}
494
	}
495
	if (forwchar(FFRAND, 1) == FALSE)
496
		return (FALSE);
497
498
	/* undo assumed delete */
499
	--size;
500
out:
501
	return (ldelete(size, KBACK));
502
}
503
504
/*
505
 * Return TRUE if the character at dot is a character that is considered to be
506
 * part of a word. The word character list is hard coded. Should be settable.
507
 */
508
int
509
inword(void)
510
{
511
	/* can't use lgetc in ISWORD due to bug in OSK cpp */
512
	return (curwp->w_doto != llength(curwp->w_dotp) &&
513
	    ISWORD(curwp->w_dotp->l_text[curwp->w_doto]));
514
}