GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/region.c Lines: 0 301 0.0 %
Date: 2017-11-07 Branches: 0 180 0.0 %

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