GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/region.c Lines: 0 292 0.0 %
Date: 2016-12-06 Branches: 0 180 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: region.c,v 1.35 2015/03/19 21:22:15 bcallah Exp $	*/
2
3
/* This file is in the public domain. */
4
5
/*
6
 *		Region based commands.
7
 * The routines in this file deal with the region, that magic space between
8
 * "." and mark.  Some functions are commands.  Some functions are just for
9
 * internal use.
10
 */
11
12
#include <sys/queue.h>
13
#include <sys/socket.h>
14
#include <sys/types.h>
15
#include <errno.h>
16
#include <fcntl.h>
17
#include <poll.h>
18
#include <signal.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
#include <string.h>
22
#include <unistd.h>
23
24
#include "def.h"
25
26
#define TIMEOUT 10000
27
28
static char leftover[BUFSIZ];
29
30
static	int	getregion(struct region *);
31
static	int	iomux(int, char * const, int, struct buffer *);
32
static	int	preadin(int, struct buffer *);
33
static	void	pwriteout(int, char **, int *);
34
static	int	setsize(struct region *, RSIZE);
35
static	int	shellcmdoutput(char * const[], char * const, int);
36
37
/*
38
 * Kill the region.  Ask "getregion" to figure out the bounds of the region.
39
 * Move "." to the start, and kill the characters. Mark is cleared afterwards.
40
 */
41
/* ARGSUSED */
42
int
43
killregion(int f, int n)
44
{
45
	int	s;
46
	struct region	region;
47
48
	if ((s = getregion(&region)) != TRUE)
49
		return (s);
50
	/* This is a kill-type command, so do magic kill buffer stuff. */
51
	if ((lastflag & CFKILL) == 0)
52
		kdelete();
53
	thisflag |= CFKILL;
54
	curwp->w_dotp = region.r_linep;
55
	curwp->w_doto = region.r_offset;
56
	curwp->w_dotline = region.r_lineno;
57
	s = ldelete(region.r_size, KFORW | KREG);
58
	clearmark(FFARG, 0);
59
60
	return (s);
61
}
62
63
/*
64
 * Copy all of the characters in the region to the kill buffer,
65
 * clearing the mark afterwards.
66
 * This is a bit like a kill region followed by a yank.
67
 */
68
/* ARGSUSED */
69
int
70
copyregion(int f, int n)
71
{
72
	struct line	*linep;
73
	struct region	 region;
74
	int	 loffs;
75
	int	 s;
76
77
	if ((s = getregion(&region)) != TRUE)
78
		return (s);
79
80
	/* kill type command */
81
	if ((lastflag & CFKILL) == 0)
82
		kdelete();
83
	thisflag |= CFKILL;
84
85
	/* current line */
86
	linep = region.r_linep;
87
88
	/* current offset */
89
	loffs = region.r_offset;
90
91
	while (region.r_size--) {
92
		if (loffs == llength(linep)) {	/* End of line.		 */
93
			if ((s = kinsert('\n', KFORW)) != TRUE)
94
				return (s);
95
			linep = lforw(linep);
96
			loffs = 0;
97
		} else {			/* Middle of line.	 */
98
			if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
99
				return (s);
100
			++loffs;
101
		}
102
	}
103
	clearmark(FFARG, 0);
104
105
	return (TRUE);
106
}
107
108
/*
109
 * Lower case region.  Zap all of the upper case characters in the region to
110
 * lower case. Use the region code to set the limits. Scan the buffer, doing
111
 * the changes. Call "lchange" to ensure that redisplay is done in all
112
 * buffers.
113
 */
114
/* ARGSUSED */
115
int
116
lowerregion(int f, int n)
117
{
118
	struct line	*linep;
119
	struct region	 region;
120
	int	 loffs, c, s;
121
122
	if ((s = checkdirty(curbp)) != TRUE)
123
		return (s);
124
	if (curbp->b_flag & BFREADONLY) {
125
		dobeep();
126
		ewprintf("Buffer is read-only");
127
		return (FALSE);
128
	}
129
130
	if ((s = getregion(&region)) != TRUE)
131
		return (s);
132
133
	undo_add_change(region.r_linep, region.r_offset, region.r_size);
134
135
	lchange(WFFULL);
136
	linep = region.r_linep;
137
	loffs = region.r_offset;
138
	while (region.r_size--) {
139
		if (loffs == llength(linep)) {
140
			linep = lforw(linep);
141
			loffs = 0;
142
		} else {
143
			c = lgetc(linep, loffs);
144
			if (ISUPPER(c) != FALSE)
145
				lputc(linep, loffs, TOLOWER(c));
146
			++loffs;
147
		}
148
	}
149
	return (TRUE);
150
}
151
152
/*
153
 * Upper case region.  Zap all of the lower case characters in the region to
154
 * upper case.  Use the region code to set the limits.  Scan the buffer,
155
 * doing the changes.  Call "lchange" to ensure that redisplay is done in all
156
 * buffers.
157
 */
158
/* ARGSUSED */
159
int
160
upperregion(int f, int n)
161
{
162
	struct line	 *linep;
163
	struct region	  region;
164
	int	  loffs, c, s;
165
166
	if ((s = checkdirty(curbp)) != TRUE)
167
		return (s);
168
	if (curbp->b_flag & BFREADONLY) {
169
		dobeep();
170
		ewprintf("Buffer is read-only");
171
		return (FALSE);
172
	}
173
	if ((s = getregion(&region)) != TRUE)
174
		return (s);
175
176
	undo_add_change(region.r_linep, region.r_offset, region.r_size);
177
178
	lchange(WFFULL);
179
	linep = region.r_linep;
180
	loffs = region.r_offset;
181
	while (region.r_size--) {
182
		if (loffs == llength(linep)) {
183
			linep = lforw(linep);
184
			loffs = 0;
185
		} else {
186
			c = lgetc(linep, loffs);
187
			if (ISLOWER(c) != FALSE)
188
				lputc(linep, loffs, TOUPPER(c));
189
			++loffs;
190
		}
191
	}
192
	return (TRUE);
193
}
194
195
/*
196
 * This routine figures out the bound of the region in the current window,
197
 * and stores the results into the fields of the REGION structure. Dot and
198
 * mark are usually close together, but I don't know the order, so I scan
199
 * outward from dot, in both directions, looking for mark. The size is kept
200
 * in a long. At the end, after the size is figured out, it is assigned to
201
 * the size field of the region structure. If this assignment loses any bits,
202
 * then we print an error. This is "type independent" overflow checking. All
203
 * of the callers of this routine should be ready to get an ABORT status,
204
 * because I might add a "if regions is big, ask before clobbering" flag.
205
 */
206
static int
207
getregion(struct region *rp)
208
{
209
	struct line	*flp, *blp;
210
	long	 fsize, bsize;
211
212
	if (curwp->w_markp == NULL) {
213
		dobeep();
214
		ewprintf("No mark set in this window");
215
		return (FALSE);
216
	}
217
218
	/* "r_size" always ok */
219
	if (curwp->w_dotp == curwp->w_markp) {
220
		rp->r_linep = curwp->w_dotp;
221
		rp->r_lineno = curwp->w_dotline;
222
		if (curwp->w_doto < curwp->w_marko) {
223
			rp->r_offset = curwp->w_doto;
224
			rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
225
		} else {
226
			rp->r_offset = curwp->w_marko;
227
			rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
228
		}
229
		return (TRUE);
230
	}
231
	/* get region size */
232
	flp = blp = curwp->w_dotp;
233
	bsize = curwp->w_doto;
234
	fsize = llength(flp) - curwp->w_doto + 1;
235
	while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
236
		if (lforw(flp) != curbp->b_headp) {
237
			flp = lforw(flp);
238
			if (flp == curwp->w_markp) {
239
				rp->r_linep = curwp->w_dotp;
240
				rp->r_offset = curwp->w_doto;
241
				rp->r_lineno = curwp->w_dotline;
242
				return (setsize(rp,
243
				    (RSIZE)(fsize + curwp->w_marko)));
244
			}
245
			fsize += llength(flp) + 1;
246
		}
247
		if (lback(blp) != curbp->b_headp) {
248
			blp = lback(blp);
249
			bsize += llength(blp) + 1;
250
			if (blp == curwp->w_markp) {
251
				rp->r_linep = blp;
252
				rp->r_offset = curwp->w_marko;
253
				rp->r_lineno = curwp->w_markline;
254
				return (setsize(rp,
255
				    (RSIZE)(bsize - curwp->w_marko)));
256
			}
257
		}
258
	}
259
	dobeep();
260
	ewprintf("Bug: lost mark");
261
	return (FALSE);
262
}
263
264
/*
265
 * Set size, and check for overflow.
266
 */
267
static int
268
setsize(struct region *rp, RSIZE size)
269
{
270
	rp->r_size = size;
271
	if (rp->r_size != size) {
272
		dobeep();
273
		ewprintf("Region is too large");
274
		return (FALSE);
275
	}
276
	return (TRUE);
277
}
278
279
#define PREFIXLENGTH 40
280
static char	prefix_string[PREFIXLENGTH] = {'>', '\0'};
281
282
/*
283
 * Prefix the region with whatever is in prefix_string.  Leaves dot at the
284
 * beginning of the line after the end of the region.  If an argument is
285
 * given, prompts for the line prefix string.
286
 */
287
/* ARGSUSED */
288
int
289
prefixregion(int f, int n)
290
{
291
	struct line	*first, *last;
292
	struct region	 region;
293
	char	*prefix = prefix_string;
294
	int	 nline;
295
	int	 s;
296
297
	if ((s = checkdirty(curbp)) != TRUE)
298
		return (s);
299
	if (curbp->b_flag & BFREADONLY) {
300
		dobeep();
301
		ewprintf("Buffer is read-only");
302
		return (FALSE);
303
	}
304
	if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
305
		return (s);
306
307
	/* get # of lines to affect */
308
	if ((s = getregion(&region)) != TRUE)
309
		return (s);
310
	first = region.r_linep;
311
	last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
312
	for (nline = 1; first != last; nline++)
313
		first = lforw(first);
314
315
	/* move to beginning of region */
316
	curwp->w_dotp = region.r_linep;
317
	curwp->w_doto = region.r_offset;
318
	curwp->w_dotline = region.r_lineno;
319
320
	/* for each line, go to beginning and insert the prefix string */
321
	while (nline--) {
322
		(void)gotobol(FFRAND, 1);
323
		for (prefix = prefix_string; *prefix; prefix++)
324
			(void)linsert(1, *prefix);
325
		(void)forwline(FFRAND, 1);
326
	}
327
	(void)gotobol(FFRAND, 1);
328
	return (TRUE);
329
}
330
331
/*
332
 * Set line prefix string. Used by prefixregion.
333
 */
334
/* ARGSUSED */
335
int
336
setprefix(int f, int n)
337
{
338
	char	buf[PREFIXLENGTH], *rep;
339
	int	retval;
340
341
	if (prefix_string[0] == '\0')
342
		rep = eread("Prefix string: ", buf, sizeof(buf),
343
		    EFNEW | EFCR);
344
	else
345
		rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
346
		    EFNUL | EFNEW | EFCR, prefix_string);
347
	if (rep == NULL)
348
		return (ABORT);
349
	if (rep[0] != '\0') {
350
		(void)strlcpy(prefix_string, rep, sizeof(prefix_string));
351
		retval = TRUE;
352
	} else if (rep[0] == '\0' && prefix_string[0] != '\0') {
353
		/* CR -- use old one */
354
		retval = TRUE;
355
	} else
356
		retval = FALSE;
357
	return (retval);
358
}
359
360
int
361
region_get_data(struct region *reg, char *buf, int len)
362
{
363
	int	 i, off;
364
	struct line	*lp;
365
366
	off = reg->r_offset;
367
	lp = reg->r_linep;
368
	for (i = 0; i < len; i++) {
369
		if (off == llength(lp)) {
370
			lp = lforw(lp);
371
			if (lp == curbp->b_headp)
372
				break;
373
			off = 0;
374
			buf[i] = '\n';
375
		} else {
376
			buf[i] = lgetc(lp, off);
377
			off++;
378
		}
379
	}
380
	buf[i] = '\0';
381
	return (i);
382
}
383
384
void
385
region_put_data(const char *buf, int len)
386
{
387
	int i;
388
389
	for (i = 0; buf[i] != '\0' && i < len; i++) {
390
		if (buf[i] == '\n')
391
			lnewline();
392
		else
393
			linsert(1, buf[i]);
394
	}
395
}
396
397
/*
398
 * Mark whole buffer by first traversing to end-of-buffer
399
 * and then to beginning-of-buffer. Mark, dot are implicitly
400
 * set to eob, bob respectively during traversal.
401
 */
402
int
403
markbuffer(int f, int n)
404
{
405
	if (gotoeob(f,n) == FALSE)
406
		return (FALSE);
407
	if (gotobob(f,n) == FALSE)
408
		return (FALSE);
409
	return (TRUE);
410
}
411
412
/*
413
 * Pipe text from current region to external command.
414
 */
415
/*ARGSUSED */
416
int
417
piperegion(int f, int n)
418
{
419
	struct region region;
420
	int len;
421
	char *cmd, cmdbuf[NFILEN], *text;
422
	char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
423
424
	/* C-u M-| is not supported yet */
425
	if (n > 1)
426
		return (ABORT);
427
428
	if (curwp->w_markp == NULL) {
429
		dobeep();
430
		ewprintf("The mark is not set now, so there is no region");
431
		return (FALSE);
432
	}
433
434
	if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
435
	    EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
436
		return (ABORT);
437
438
	argv[2] = cmd;
439
440
	if (getregion(&region) != TRUE)
441
		return (FALSE);
442
443
	len = region.r_size;
444
445
	if ((text = malloc(len + 1)) == NULL) {
446
		dobeep();
447
		ewprintf("Cannot allocate memory.");
448
		return (FALSE);
449
	}
450
451
	region_get_data(&region, text, len);
452
453
	return shellcmdoutput(argv, text, len);
454
}
455
456
/*
457
 * Get command from mini-buffer and execute externally.
458
 */
459
/*ARGSUSED */
460
int
461
shellcommand(int f, int n)
462
{
463
464
	char *cmd, cmdbuf[NFILEN];
465
	char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
466
467
	if (n > 1)
468
		return (ABORT);
469
470
	if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf),
471
	    EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
472
		return (ABORT);
473
474
	argv[2] = cmd;
475
476
	return shellcmdoutput(argv, NULL, 0);
477
}
478
479
480
int
481
shellcmdoutput(char* const argv[], char* const text, int len)
482
{
483
484
	struct buffer *bp;
485
	char	*shellp;
486
	int	 ret;
487
488
	bp = bfind("*Shell Command Output*", TRUE);
489
	bp->b_flag |= BFREADONLY;
490
	if (bclear(bp) != TRUE) {
491
		free(text);
492
		return (FALSE);
493
	}
494
495
	shellp = getenv("SHELL");
496
497
	ret = pipeio(shellp, argv, text, len, bp);
498
499
	if (ret == TRUE) {
500
		eerase();
501
		if (lforw(bp->b_headp) == bp->b_headp)
502
			addline(bp, "(Shell command succeeded with no output)");
503
	}
504
505
	free(text);
506
	return (ret);
507
}
508
509
/*
510
 * Create a socketpair, fork and execv path with argv.
511
 * STDIN, STDOUT and STDERR of child process are redirected to socket.
512
 * Parent writes len chars from text to socket.
513
 */
514
int
515
pipeio(const char* const path, char* const argv[], char* const text, int len,
516
    struct buffer *outbp)
517
{
518
	int s[2];
519
	char *err;
520
521
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
522
		dobeep();
523
		ewprintf("socketpair error");
524
		return (FALSE);
525
	}
526
527
	switch(fork()) {
528
	case -1:
529
		dobeep();
530
		ewprintf("Can't fork");
531
		return (FALSE);
532
	case 0:
533
		/* Child process */
534
		close(s[0]);
535
		if (dup2(s[1], STDIN_FILENO) == -1)
536
			_exit(1);
537
		if (dup2(s[1], STDOUT_FILENO) == -1)
538
			_exit(1);
539
		if (dup2(s[1], STDERR_FILENO) == -1)
540
			_exit(1);
541
		if (path == NULL)
542
			_exit(1);
543
544
		execv(path, argv);
545
		err = strerror(errno);
546
		write(s[1], err, strlen(err));
547
		_exit(1);
548
	default:
549
		/* Parent process */
550
		close(s[1]);
551
		return (iomux(s[0], text, len, outbp));
552
	}
553
	return (FALSE);
554
}
555
556
/*
557
 * Multiplex read, write on socket fd passed. Put output in outbp
558
 * Poll on the fd for both read and write readiness.
559
 */
560
int
561
iomux(int fd, char* const text, int len, struct buffer *outbp)
562
{
563
	struct pollfd pfd[1];
564
	int nfds;
565
	char *textcopy;
566
567
	textcopy = text;
568
	fcntl(fd, F_SETFL, O_NONBLOCK);
569
	pfd[0].fd = fd;
570
571
	/* There is nothing to write if len is zero
572
	 * but the cmd's output should be read so shutdown
573
	 * the socket for writing only and don't wait for POLLOUT
574
	 */
575
	if (len == 0) {
576
		shutdown(fd, SHUT_WR);
577
		pfd[0].events = POLLIN;
578
	} else
579
		pfd[0].events = POLLIN | POLLOUT;
580
581
	while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
582
	    (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
583
		if (pfd[0].revents & POLLOUT && len > 0)
584
			pwriteout(fd, &textcopy, &len);
585
		else if (pfd[0].revents & POLLIN)
586
			if (preadin(fd, outbp) == FALSE)
587
				break;
588
		if (len == 0 && pfd[0].events & POLLOUT)
589
			pfd[0].events = POLLIN;
590
	}
591
	close(fd);
592
593
	/* In case if last line doesn't have a '\n' add the leftover
594
	 * characters to buffer.
595
	 */
596
	if (leftover[0] != '\0') {
597
		addline(outbp, leftover);
598
		leftover[0] = '\0';
599
	}
600
	if (nfds == 0) {
601
		dobeep();
602
		ewprintf("poll timed out");
603
		return (FALSE);
604
	} else if (nfds == -1) {
605
		dobeep();
606
		ewprintf("poll error");
607
		return (FALSE);
608
	}
609
	return (popbuftop(outbp, WNONE));
610
}
611
612
/*
613
 * Write some text from region to fd. Once done shutdown the
614
 * write end.
615
 */
616
void
617
pwriteout(int fd, char **text, int *len)
618
{
619
	int w;
620
621
	if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
622
		switch(errno) {
623
		case EPIPE:
624
			*len = -1;
625
			break;
626
		case EAGAIN:
627
			return;
628
		}
629
	} else
630
		*len -= w;
631
632
	*text += w;
633
	if (*len <= 0)
634
		shutdown(fd, SHUT_WR);
635
}
636
637
/*
638
 * Read some data from socket fd, break on '\n' and add
639
 * to buffer. If couldn't break on newline hold leftover
640
 * characters and append in next iteration.
641
 */
642
int
643
preadin(int fd, struct buffer *bp)
644
{
645
	int len;
646
	char buf[BUFSIZ], *p, *q;
647
648
	if ((len = read(fd, buf, BUFSIZ - 1)) == 0)
649
		return (FALSE);
650
651
	buf[len] = '\0';
652
	p = q = buf;
653
	if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) {
654
		*q++ = '\0';
655
		if (strlcat(leftover, p, sizeof(leftover)) >=
656
		    sizeof(leftover)) {
657
			dobeep();
658
			ewprintf("line too long");
659
			return (FALSE);
660
		}
661
		addline(bp, leftover);
662
		leftover[0] = '\0';
663
		p = q;
664
	}
665
	while ((q = strchr(p, '\n')) != NULL) {
666
		*q++ = '\0';
667
		addline(bp, p);
668
		p = q;
669
	}
670
	if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
671
		dobeep();
672
		ewprintf("line too long");
673
		return (FALSE);
674
	}
675
	return (TRUE);
676
}