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

Line Branch Exec Source
1
/*	$OpenBSD: dired.c,v 1.83 2016/10/07 00:17:20 jsg Exp $	*/
2
3
/* This file is in the public domain. */
4
5
/* dired module for mg 2a
6
 * by Robert A. Larson
7
 */
8
9
#include <sys/queue.h>
10
#include <sys/resource.h>
11
#include <sys/stat.h>
12
#include <sys/time.h>
13
#include <sys/types.h>
14
#include <sys/wait.h>
15
#include <ctype.h>
16
#include <err.h>
17
#include <errno.h>
18
#include <fcntl.h>
19
#include <libgen.h>
20
#include <limits.h>
21
#include <signal.h>
22
#include <stdarg.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <unistd.h>
27
28
#include "def.h"
29
#include "funmap.h"
30
#include "kbd.h"
31
32
void		 dired_init(void);
33
static int	 dired(int, int);
34
static int	 d_otherwindow(int, int);
35
static int	 d_undel(int, int);
36
static int	 d_undelbak(int, int);
37
static int	 d_findfile(int, int);
38
static int	 d_ffotherwindow(int, int);
39
static int	 d_expunge(int, int);
40
static int	 d_copy(int, int);
41
static int	 d_del(int, int);
42
static int	 d_rename(int, int);
43
static int	 d_exec(int, struct buffer *, const char *, const char *, ...);
44
static int	 d_shell_command(int, int);
45
static int	 d_create_directory(int, int);
46
static int	 d_makename(struct line *, char *, size_t);
47
static int	 d_warpdot(struct line *, int *);
48
static int	 d_forwpage(int, int);
49
static int	 d_backpage(int, int);
50
static int	 d_forwline(int, int);
51
static int	 d_backline(int, int);
52
static int	 d_killbuffer_cmd(int, int);
53
static int	 d_refreshbuffer(int, int);
54
static int	 d_filevisitalt(int, int);
55
static void	 reaper(int);
56
static struct buffer	*refreshbuffer(struct buffer *);
57
static int	 createlist(struct buffer *);
58
static void	 redelete(struct buffer *);
59
static char 	 *findfname(struct line *, char *);
60
61
extern struct keymap_s helpmap, cXmap, metamap;
62
63
const char DDELCHAR = 'D';
64
65
/*
66
 * Structure which holds a linked list of file names marked for
67
 * deletion. Used to maintain dired buffer 'state' between refreshes.
68
 */
69
struct delentry {
70
	SLIST_ENTRY(delentry) entry;
71
	char   *fn;
72
};
73
SLIST_HEAD(slisthead, delentry) delhead = SLIST_HEAD_INITIALIZER(delhead);
74
75
static PF dirednul[] = {
76
	setmark,		/* ^@ */
77
	gotobol,		/* ^A */
78
	backchar,		/* ^B */
79
	rescan,			/* ^C */
80
	d_del,			/* ^D */
81
	gotoeol,		/* ^E */
82
	forwchar,		/* ^F */
83
	ctrlg,			/* ^G */
84
	NULL,			/* ^H */
85
};
86
87
static PF diredcl[] = {
88
	reposition,		/* ^L */
89
	d_findfile,		/* ^M */
90
	d_forwline,		/* ^N */
91
	rescan,			/* ^O */
92
	d_backline,		/* ^P */
93
	rescan,			/* ^Q */
94
	backisearch,		/* ^R */
95
	forwisearch,		/* ^S */
96
	rescan,			/* ^T */
97
	universal_argument,	/* ^U */
98
	d_forwpage,		/* ^V */
99
	rescan,			/* ^W */
100
	NULL			/* ^X */
101
};
102
103
static PF diredcz[] = {
104
	spawncli,		/* ^Z */
105
	NULL,			/* esc */
106
	rescan,			/* ^\ */
107
	rescan,			/* ^] */
108
	rescan,			/* ^^ */
109
	rescan,			/* ^_ */
110
	d_forwline,		/* SP */
111
	d_shell_command,	/* ! */
112
	rescan,			/* " */
113
	rescan,			/* # */
114
	rescan,			/* $ */
115
	rescan,			/* % */
116
	rescan,			/* & */
117
	rescan,			/* ' */
118
	rescan,			/* ( */
119
	rescan,			/* ) */
120
	rescan,			/* * */
121
	d_create_directory	/* + */
122
};
123
124
static PF direda[] = {
125
	d_filevisitalt,		/* a */
126
	rescan,			/* b */
127
	d_copy,			/* c */
128
	d_del,			/* d */
129
	d_findfile,		/* e */
130
	d_findfile,		/* f */
131
	d_refreshbuffer		/* g */
132
};
133
134
static PF diredn[] = {
135
	d_forwline,		/* n */
136
	d_ffotherwindow,	/* o */
137
	d_backline,		/* p */
138
	d_killbuffer_cmd,	/* q */
139
	d_rename,		/* r */
140
	rescan,			/* s */
141
	rescan,			/* t */
142
	d_undel,		/* u */
143
	rescan,			/* v */
144
	rescan,			/* w */
145
	d_expunge		/* x */
146
};
147
148
static PF direddl[] = {
149
	d_undelbak		/* del */
150
};
151
152
static PF diredbp[] = {
153
	d_backpage		/* v */
154
};
155
156
static PF dirednull[] = {
157
	NULL
158
};
159
160
static struct KEYMAPE (1) d_backpagemap = {
161
	1,
162
	1,
163
	rescan,
164
	{
165
		{
166
		'v', 'v', diredbp, NULL
167
		}
168
	}
169
};
170
171
static struct KEYMAPE (7) diredmap = {
172
	7,
173
	7,
174
	rescan,
175
	{
176
		{
177
			CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap
178
		},
179
		{
180
			CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
181
		},
182
		{
183
			CCHR('['), CCHR('['), dirednull, (KEYMAP *) &
184
			d_backpagemap
185
		},
186
		{
187
			CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap
188
		},
189
		{
190
			'a', 'g', direda, NULL
191
		},
192
		{
193
			'n', 'x', diredn, NULL
194
		},
195
		{
196
			CCHR('?'), CCHR('?'), direddl, NULL
197
		},
198
	}
199
};
200
201
void
202
dired_init(void)
203
{
204
	funmap_add(dired, "dired");
205
	funmap_add(d_undelbak, "dired-unmark-backward");
206
	funmap_add(d_create_directory, "dired-create-directory");
207
	funmap_add(d_copy, "dired-do-copy");
208
	funmap_add(d_expunge, "dired-do-flagged-delete");
209
	funmap_add(d_findfile, "dired-find-file");
210
	funmap_add(d_ffotherwindow, "dired-find-file-other-window");
211
	funmap_add(d_del, "dired-flag-file-deletion");
212
	funmap_add(d_forwline, "dired-next-line");
213
	funmap_add(d_otherwindow, "dired-other-window");
214
	funmap_add(d_backline, "dired-previous-line");
215
	funmap_add(d_rename, "dired-do-rename");
216
	funmap_add(d_backpage, "dired-scroll-down");
217
	funmap_add(d_forwpage, "dired-scroll-up");
218
	funmap_add(d_undel, "dired-unmark");
219
	funmap_add(d_killbuffer_cmd, "quit-window");
220
	maps_add((KEYMAP *)&diredmap, "dired");
221
	dobindkey(fundamental_map, "dired", "^Xd");
222
}
223
224
/* ARGSUSED */
225
int
226
dired(int f, int n)
227
{
228
	char		 dname[NFILEN], *bufp, *slash;
229
	struct buffer	*bp;
230
231
	if (curbp->b_fname[0] != '\0') {
232
		(void)strlcpy(dname, curbp->b_fname, sizeof(dname));
233
		if ((slash = strrchr(dname, '/')) != NULL) {
234
			*(slash + 1) = '\0';
235
		}
236
	} else {
237
		if (getcwd(dname, sizeof(dname)) == NULL)
238
			dname[0] = '\0';
239
	}
240
241
	if ((bufp = eread("Dired: ", dname, NFILEN,
242
	    EFDEF | EFNEW | EFCR)) == NULL)
243
		return (ABORT);
244
	if (bufp[0] == '\0')
245
		return (FALSE);
246
	if ((bp = dired_(bufp)) == NULL)
247
		return (FALSE);
248
249
	curbp = bp;
250
	return (showbuffer(bp, curwp, WFFULL | WFMODE));
251
}
252
253
/* ARGSUSED */
254
int
255
d_otherwindow(int f, int n)
256
{
257
	char		 dname[NFILEN], *bufp, *slash;
258
	struct buffer	*bp;
259
	struct mgwin	*wp;
260
261
	if (curbp->b_fname[0] != '\0') {
262
		(void)strlcpy(dname, curbp->b_fname, sizeof(dname));
263
		if ((slash = strrchr(dname, '/')) != NULL) {
264
			*(slash + 1) = '\0';
265
		}
266
	} else {
267
		if (getcwd(dname, sizeof(dname)) == NULL)
268
			dname[0] = '\0';
269
	}
270
271
	if ((bufp = eread("Dired other window: ", dname, NFILEN,
272
	    EFDEF | EFNEW | EFCR)) == NULL)
273
		return (ABORT);
274
	else if (bufp[0] == '\0')
275
		return (FALSE);
276
	if ((bp = dired_(bufp)) == NULL)
277
		return (FALSE);
278
	if ((wp = popbuf(bp, WNONE)) == NULL)
279
		return (FALSE);
280
	curbp = bp;
281
	curwp = wp;
282
	return (TRUE);
283
}
284
285
/* ARGSUSED */
286
int
287
d_del(int f, int n)
288
{
289
	if (n < 0)
290
		return (FALSE);
291
	while (n--) {
292
		if (d_warpdot(curwp->w_dotp, &curwp->w_doto) == TRUE) {
293
			lputc(curwp->w_dotp, 0, DDELCHAR);
294
			curbp->b_flag |= BFDIREDDEL;
295
		}
296
		if (lforw(curwp->w_dotp) != curbp->b_headp) {
297
			curwp->w_dotp = lforw(curwp->w_dotp);
298
			curwp->w_dotline++;
299
		}
300
	}
301
	curwp->w_rflag |= WFEDIT | WFMOVE;
302
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
303
}
304
305
/* ARGSUSED */
306
int
307
d_undel(int f, int n)
308
{
309
	if (n < 0)
310
		return (d_undelbak(f, -n));
311
	while (n--) {
312
		if (llength(curwp->w_dotp) > 0)
313
			lputc(curwp->w_dotp, 0, ' ');
314
		if (lforw(curwp->w_dotp) != curbp->b_headp) {
315
			curwp->w_dotp = lforw(curwp->w_dotp);
316
			curwp->w_dotline++;
317
		}
318
	}
319
	curwp->w_rflag |= WFEDIT | WFMOVE;
320
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
321
}
322
323
/* ARGSUSED */
324
int
325
d_undelbak(int f, int n)
326
{
327
	if (n < 0)
328
		return (d_undel(f, -n));
329
	while (n--) {
330
		if (lback(curwp->w_dotp) != curbp->b_headp) {
331
			curwp->w_dotp = lback(curwp->w_dotp);
332
			curwp->w_dotline--;
333
		}
334
		if (llength(curwp->w_dotp) > 0)
335
			lputc(curwp->w_dotp, 0, ' ');
336
	}
337
	curwp->w_rflag |= WFEDIT | WFMOVE;
338
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
339
}
340
341
/* ARGSUSED */
342
int
343
d_findfile(int f, int n)
344
{
345
	struct buffer	*bp;
346
	int		 s;
347
	char		 fname[NFILEN];
348
349
	if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
350
		return (FALSE);
351
	if (s == TRUE)
352
		bp = dired_(fname);
353
	else
354
		bp = findbuffer(fname);
355
	if (bp == NULL)
356
		return (FALSE);
357
	curbp = bp;
358
	if (showbuffer(bp, curwp, WFFULL) != TRUE)
359
		return (FALSE);
360
	if (bp->b_fname[0] != 0)
361
		return (TRUE);
362
	return (readin(fname));
363
}
364
365
/* ARGSUSED */
366
int
367
d_ffotherwindow(int f, int n)
368
{
369
	char		 fname[NFILEN];
370
	int		 s;
371
	struct buffer	*bp;
372
	struct mgwin	*wp;
373
374
	if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
375
		return (FALSE);
376
	if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
377
		return (FALSE);
378
	if ((wp = popbuf(bp, WNONE)) == NULL)
379
		return (FALSE);
380
	curbp = bp;
381
	curwp = wp;
382
	if (bp->b_fname[0] != 0)
383
		return (TRUE);	/* never true for dired buffers */
384
	return (readin(fname));
385
}
386
387
/* ARGSUSED */
388
int
389
d_expunge(int f, int n)
390
{
391
	struct line	*lp, *nlp;
392
	char		 fname[NFILEN], sname[NFILEN];
393
	int		 tmp;
394
395
	tmp = curwp->w_dotline;
396
	curwp->w_dotline = 0;
397
398
	for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) {
399
		curwp->w_dotline++;
400
		nlp = lforw(lp);
401
		if (llength(lp) && lgetc(lp, 0) == 'D') {
402
			switch (d_makename(lp, fname, sizeof(fname))) {
403
			case ABORT:
404
				dobeep();
405
				ewprintf("Bad line in dired buffer");
406
				curwp->w_dotline = tmp;
407
				return (FALSE);
408
			case FALSE:
409
				if (unlink(fname) < 0) {
410
					(void)xbasename(sname, fname, NFILEN);
411
					dobeep();
412
					ewprintf("Could not delete '%s'", sname);
413
					curwp->w_dotline = tmp;
414
					return (FALSE);
415
				}
416
				break;
417
			case TRUE:
418
				if (rmdir(fname) < 0) {
419
					(void)xbasename(sname, fname, NFILEN);
420
					dobeep();
421
					ewprintf("Could not delete directory "
422
					    "'%s'", sname);
423
					curwp->w_dotline = tmp;
424
					return (FALSE);
425
				}
426
				break;
427
			}
428
			lfree(lp);
429
			curwp->w_bufp->b_lines--;
430
			if (tmp > curwp->w_dotline)
431
				tmp--;
432
			curwp->w_rflag |= WFFULL;
433
		}
434
	}
435
	curwp->w_dotline = tmp;
436
	d_warpdot(curwp->w_dotp, &curwp->w_doto);
437
438
	/* we have deleted all items successfully, remove del flag */
439
	curbp->b_flag &= ~BFDIREDDEL;
440
441
	return (TRUE);
442
}
443
444
/* ARGSUSED */
445
int
446
d_copy(int f, int n)
447
{
448
	char		 frname[NFILEN], toname[NFILEN], sname[NFILEN];
449
	char		*topath, *bufp;
450
	int		 ret;
451
	size_t		 off;
452
	struct buffer	*bp;
453
454
	if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
455
		dobeep();
456
		ewprintf("Not a file");
457
		return (FALSE);
458
	}
459
	off = strlcpy(toname, curbp->b_fname, sizeof(toname));
460
	if (off >= sizeof(toname) - 1) {	/* can't happen, really */
461
		dobeep();
462
		ewprintf("Directory name too long");
463
		return (FALSE);
464
	}
465
	(void)xbasename(sname, frname, NFILEN);
466
	bufp = eread("Copy %s to: ", toname, sizeof(toname),
467
	    EFDEF | EFNEW | EFCR, sname);
468
	if (bufp == NULL)
469
		return (ABORT);
470
	else if (bufp[0] == '\0')
471
		return (FALSE);
472
473
	topath = adjustname(toname, TRUE);
474
	ret = (copy(frname, topath) >= 0) ? TRUE : FALSE;
475
	if (ret != TRUE)
476
		return (ret);
477
	if ((bp = refreshbuffer(curbp)) == NULL)
478
		return (FALSE);
479
	return (showbuffer(bp, curwp, WFFULL | WFMODE));
480
}
481
482
/* ARGSUSED */
483
int
484
d_rename(int f, int n)
485
{
486
	char		 frname[NFILEN], toname[NFILEN];
487
	char		*topath, *bufp;
488
	int		 ret;
489
	size_t		 off;
490
	struct buffer	*bp;
491
	char		 sname[NFILEN];
492
493
	if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
494
		dobeep();
495
		ewprintf("Not a file");
496
		return (FALSE);
497
	}
498
	off = strlcpy(toname, curbp->b_fname, sizeof(toname));
499
	if (off >= sizeof(toname) - 1) {	/* can't happen, really */
500
		dobeep();
501
		ewprintf("Directory name too long");
502
		return (FALSE);
503
	}
504
	(void)xbasename(sname, frname, NFILEN);
505
	bufp = eread("Rename %s to: ", toname,
506
	    sizeof(toname), EFDEF | EFNEW | EFCR, sname);
507
	if (bufp == NULL)
508
		return (ABORT);
509
	else if (bufp[0] == '\0')
510
		return (FALSE);
511
512
	topath = adjustname(toname, TRUE);
513
	ret = (rename(frname, topath) >= 0) ? TRUE : FALSE;
514
	if (ret != TRUE)
515
		return (ret);
516
	if ((bp = refreshbuffer(curbp)) == NULL)
517
		return (FALSE);
518
	return (showbuffer(bp, curwp, WFFULL | WFMODE));
519
}
520
521
/* ARGSUSED */
522
void
523
reaper(int signo __attribute__((unused)))
524
{
525
	int	save_errno = errno, status;
526
527
	while (waitpid(-1, &status, WNOHANG) >= 0)
528
		;
529
	errno = save_errno;
530
}
531
532
/*
533
 * Pipe the currently selected file through a shell command.
534
 */
535
/* ARGSUSED */
536
int
537
d_shell_command(int f, int n)
538
{
539
	char		 command[512], fname[PATH_MAX], *bufp;
540
	struct buffer	*bp;
541
	struct mgwin	*wp;
542
	char		 sname[NFILEN];
543
544
	bp = bfind("*Shell Command Output*", TRUE);
545
	if (bclear(bp) != TRUE)
546
		return (ABORT);
547
548
	if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) {
549
		dobeep();
550
		ewprintf("bad line");
551
		return (ABORT);
552
	}
553
554
	command[0] = '\0';
555
	(void)xbasename(sname, fname, NFILEN);
556
	bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname);
557
	if (bufp == NULL)
558
		return (ABORT);
559
560
	if (d_exec(0, bp, fname, "sh", "-c", command, NULL) != TRUE)
561
		return (ABORT);
562
563
	if ((wp = popbuf(bp, WNONE)) == NULL)
564
		return (ABORT);	/* XXX - free the buffer?? */
565
	curwp = wp;
566
	curbp = wp->w_bufp;
567
	return (TRUE);
568
}
569
570
/*
571
 * Pipe input file to cmd and insert the command's output in the
572
 * given buffer.  Each line will be prefixed with the given
573
 * number of spaces.
574
 */
575
static int
576
d_exec(int space, struct buffer *bp, const char *input, const char *cmd, ...)
577
{
578
	char	 buf[BUFSIZ];
579
	va_list	 ap;
580
	struct	 sigaction olda, newa;
581
	char	**argv = NULL, *cp;
582
	FILE	*fin;
583
	int	 fds[2] = { -1, -1 };
584
	int	 infd = -1;
585
	int	 ret = (ABORT), n;
586
	pid_t	 pid;
587
588
	if (sigaction(SIGCHLD, NULL, &olda) == -1)
589
		return (ABORT);
590
591
	/* Find the number of arguments. */
592
	va_start(ap, cmd);
593
	for (n = 2; va_arg(ap, char *) != NULL; n++)
594
		;
595
	va_end(ap);
596
597
	/* Allocate and build the argv. */
598
	if ((argv = calloc(n, sizeof(*argv))) == NULL) {
599
		dobeep();
600
		ewprintf("Can't allocate argv : %s", strerror(errno));
601
		goto out;
602
	}
603
604
	n = 1;
605
	argv[0] = (char *)cmd;
606
	va_start(ap, cmd);
607
	while ((argv[n] = va_arg(ap, char *)) != NULL)
608
		n++;
609
	va_end(ap);
610
611
	if (input == NULL)
612
		input = "/dev/null";
613
614
	if ((infd = open(input, O_RDONLY)) == -1) {
615
		dobeep();
616
		ewprintf("Can't open input file : %s", strerror(errno));
617
		goto out;
618
	}
619
620
	if (pipe(fds) == -1) {
621
		dobeep();
622
		ewprintf("Can't create pipe : %s", strerror(errno));
623
		goto out;
624
	}
625
626
	newa.sa_handler = reaper;
627
	newa.sa_flags = 0;
628
	if (sigaction(SIGCHLD, &newa, NULL) == -1)
629
		goto out;
630
631
	if ((pid = fork()) == -1) {
632
		dobeep();
633
		ewprintf("Can't fork");
634
		goto out;
635
	}
636
637
	switch (pid) {
638
	case 0: /* Child */
639
		close(fds[0]);
640
		dup2(infd, STDIN_FILENO);
641
		dup2(fds[1], STDOUT_FILENO);
642
		dup2(fds[1], STDERR_FILENO);
643
		if (execvp(argv[0], argv) == -1)
644
			ewprintf("Can't exec %s: %s", argv[0], strerror(errno));
645
		exit(1);
646
		break;
647
	default: /* Parent */
648
		close(infd);
649
		close(fds[1]);
650
		infd = fds[1] = -1;
651
		if ((fin = fdopen(fds[0], "r")) == NULL)
652
			goto out;
653
		while (fgets(buf, sizeof(buf), fin) != NULL) {
654
			cp = strrchr(buf, '\n');
655
			if (cp == NULL && !feof(fin)) {	/* too long a line */
656
				int c;
657
				addlinef(bp, "%*s%s...", space, "", buf);
658
				while ((c = getc(fin)) != EOF && c != '\n')
659
					;
660
				continue;
661
			} else if (cp)
662
				*cp = '\0';
663
			addlinef(bp, "%*s%s", space, "", buf);
664
		}
665
		fclose(fin);
666
		break;
667
	}
668
	ret = (TRUE);
669
670
out:
671
	if (sigaction(SIGCHLD, &olda, NULL) == -1)
672
		ewprintf("Warning, couldn't reset previous signal handler");
673
	if (fds[0] != -1)
674
		close(fds[0]);
675
	if (fds[1] != -1)
676
		close(fds[1]);
677
	if (infd != -1)
678
		close(infd);
679
	free(argv);
680
	return ret;
681
}
682
683
/* ARGSUSED */
684
int
685
d_create_directory(int f, int n)
686
{
687
	int ret;
688
	struct buffer	*bp;
689
690
	ret = ask_makedir();
691
	if (ret != TRUE)
692
		return(ret);
693
694
	if ((bp = refreshbuffer(curbp)) == NULL)
695
		return (FALSE);
696
697
	return (showbuffer(bp, curwp, WFFULL | WFMODE));
698
}
699
700
/* ARGSUSED */
701
int
702
d_killbuffer_cmd(int f, int n)
703
{
704
	return(killbuffer_cmd(FFRAND, 0));
705
}
706
707
int
708
d_refreshbuffer(int f, int n)
709
{
710
	struct buffer *bp;
711
712
	if ((bp = refreshbuffer(curbp)) == NULL)
713
		return (FALSE);
714
715
	return (showbuffer(bp, curwp, WFFULL | WFMODE));
716
}
717
718
/*
719
 * Kill then re-open the requested dired buffer.
720
 * If required, take a note of any files marked for deletion. Then once
721
 * the buffer has been re-opened, remark the same files as deleted.
722
 */
723
struct buffer *
724
refreshbuffer(struct buffer *bp)
725
{
726
	char		*tmp_b_fname;
727
	int	 	 i, tmp_w_dotline, ddel = 0;
728
729
	/* remember directory path to open later */
730
	tmp_b_fname = strdup(bp->b_fname);
731
	if (tmp_b_fname == NULL) {
732
		dobeep();
733
		ewprintf("Out of memory");
734
		return (NULL);
735
	}
736
	tmp_w_dotline = curwp->w_dotline;
737
738
	/* create a list of files for deletion */
739
	if (bp->b_flag & BFDIREDDEL)
740
		ddel = createlist(bp);
741
742
	killbuffer(bp);
743
744
	/* dired_() uses findbuffer() to create new buffer */
745
	if ((bp = dired_(tmp_b_fname)) == NULL) {
746
		free(tmp_b_fname);
747
		return (NULL);
748
	}
749
	free(tmp_b_fname);
750
751
	/* remark any previously deleted files with a 'D' */
752
	if (ddel)
753
		redelete(bp);
754
755
	/* find dot line */
756
	bp->b_dotp = bfirstlp(bp);
757
	if (tmp_w_dotline > bp->b_lines)
758
		tmp_w_dotline = bp->b_lines - 1;
759
	for (i = 1; i < tmp_w_dotline; i++)
760
		bp->b_dotp = lforw(bp->b_dotp);
761
762
	bp->b_dotline = i;
763
	bp->b_doto = 0;
764
	d_warpdot(bp->b_dotp, &bp->b_doto);
765
766
	curbp = bp;
767
768
	return (bp);
769
}
770
771
static int
772
d_makename(struct line *lp, char *fn, size_t len)
773
{
774
	int	 start, nlen;
775
	char	*namep;
776
777
	if (d_warpdot(lp, &start) == FALSE)
778
		return (ABORT);
779
	namep = &lp->l_text[start];
780
	nlen = llength(lp) - start;
781
782
	if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len)
783
		return (ABORT); /* Name is too long. */
784
785
	/* Return TRUE if the entry is a directory. */
786
	return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
787
}
788
789
#define NAME_FIELD	9
790
791
static int
792
d_warpdot(struct line *dotp, int *doto)
793
{
794
	char *tp = dotp->l_text;
795
	int off = 0, field = 0, len;
796
797
	/*
798
	 * Find the byte offset to the (space-delimited) filename
799
	 * field in formatted ls output.
800
	 */
801
	len = llength(dotp);
802
	while (off < len) {
803
		if (tp[off++] == ' ') {
804
			if (++field == NAME_FIELD) {
805
				*doto = off;
806
				return (TRUE);
807
			}
808
			/* Skip the space. */
809
			while (off < len && tp[off] == ' ')
810
				off++;
811
		}
812
	}
813
	/* We didn't find the field. */
814
	*doto = 0;
815
	return (FALSE);
816
}
817
818
static int
819
d_forwpage(int f, int n)
820
{
821
	forwpage(f | FFRAND, n);
822
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
823
}
824
825
static int
826
d_backpage (int f, int n)
827
{
828
	backpage(f | FFRAND, n);
829
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
830
}
831
832
static int
833
d_forwline (int f, int n)
834
{
835
	forwline(f | FFRAND, n);
836
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
837
}
838
839
static int
840
d_backline (int f, int n)
841
{
842
	backline(f | FFRAND, n);
843
	return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
844
}
845
846
int
847
d_filevisitalt (int f, int n)
848
{
849
	char	 fname[NFILEN];
850
851
	if (d_makename(curwp->w_dotp, fname, sizeof(fname)) == ABORT)
852
		return (FALSE);
853
854
	return(do_filevisitalt(fname));
855
}
856
857
/*
858
 * XXX dname needs to have enough place to store an additional '/'.
859
 */
860
struct buffer *
861
dired_(char *dname)
862
{
863
	struct buffer	*bp;
864
	int		 i;
865
	size_t		 len;
866
867
	if ((dname = adjustname(dname, TRUE)) == NULL) {
868
		dobeep();
869
		ewprintf("Bad directory name");
870
		return (NULL);
871
	}
872
	/* this should not be done, instead adjustname() should get a flag */
873
	len = strlen(dname);
874
	if (dname[len - 1] != '/') {
875
		dname[len++] = '/';
876
		dname[len] = '\0';
877
	}
878
	if ((access(dname, R_OK | X_OK)) == -1) {
879
		if (errno == EACCES) {
880
			dobeep();
881
			ewprintf("Permission denied: %s", dname);
882
		}
883
		return (NULL);
884
	}
885
	for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
886
		if (strcmp(bp->b_fname, dname) == 0) {
887
			if (fchecktime(bp) != TRUE)
888
				ewprintf("Directory has changed on disk;"
889
				    " type g to update Dired");
890
			return (bp);
891
		}
892
893
	}
894
	bp = bfind(dname, TRUE);
895
	bp->b_flag |= BFREADONLY | BFIGNDIRTY;
896
897
	if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE)
898
		return (NULL);
899
900
	/* Find the line with ".." on it. */
901
	bp->b_dotp = bfirstlp(bp);
902
	bp->b_dotline = 1;
903
	for (i = 0; i < bp->b_lines; i++) {
904
		bp->b_dotp = lforw(bp->b_dotp);
905
		bp->b_dotline++;
906
		if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
907
			continue;
908
		if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
909
			break;
910
	}
911
912
	/* We want dot on the entry right after "..", if possible. */
913
	if (++i < bp->b_lines - 2) {
914
		bp->b_dotp = lforw(bp->b_dotp);
915
		bp->b_dotline++;
916
	}
917
	d_warpdot(bp->b_dotp, &bp->b_doto);
918
919
	(void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname));
920
	(void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd));
921
	if ((bp->b_modes[1] = name_mode("dired")) == NULL) {
922
		bp->b_modes[0] = name_mode("fundamental");
923
		dobeep();
924
		ewprintf("Could not find mode dired");
925
		return (NULL);
926
	}
927
	(void)fupdstat(bp);
928
	bp->b_nmodes = 1;
929
	return (bp);
930
}
931
932
/*
933
 * Iterate through the lines of the dired buffer looking for files
934
 * collected in the linked list made in createlist(). If a line is found
935
 * replace 'D' as first char in a line. As lines are found, remove the
936
 * corresponding item from the linked list. Iterate for as long as there
937
 * are items in the linked list or until end of buffer is found.
938
 */
939
void
940
redelete(struct buffer *bp)
941
{
942
	struct delentry	*dt, *d1 = NULL;
943
	struct line	*lp, *nlp;
944
	char		 fname[NFILEN];
945
	char		*p = fname;
946
	size_t		 plen, fnlen;
947
	int		 finished = 0;
948
949
	/* reset the deleted file buffer flag until a deleted file is found */
950
	bp->b_flag &= ~BFDIREDDEL;
951
952
	for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
953
		bp->b_dotp = lp;
954
		if ((p = findfname(lp, p)) == NULL) {
955
			nlp = lforw(lp);
956
			continue;
957
		}
958
		plen = strlen(p);
959
		SLIST_FOREACH_SAFE(d1, &delhead, entry, dt) {
960
			fnlen = strlen(d1->fn);
961
			if ((plen == fnlen) &&
962
			    (strncmp(p, d1->fn, plen) == 0)) {
963
				lputc(bp->b_dotp, 0, DDELCHAR);
964
				bp->b_flag |= BFDIREDDEL;
965
				SLIST_REMOVE(&delhead, d1, delentry, entry);
966
				if (SLIST_EMPTY(&delhead)) {
967
					finished = 1;
968
					break;
969
				}
970
			}
971
		}
972
		if (finished)
973
			break;
974
		nlp = lforw(lp);
975
	}
976
	while (!SLIST_EMPTY(&delhead)) {
977
		d1 = SLIST_FIRST(&delhead);
978
		SLIST_REMOVE_HEAD(&delhead, entry);
979
		free(d1->fn);
980
		free(d1);
981
	}
982
	return;
983
}
984
985
/*
986
 * Create a list of files marked for deletion.
987
 */
988
int
989
createlist(struct buffer *bp)
990
{
991
	struct delentry	*d1 = NULL, *d2;
992
	struct line	*lp, *nlp;
993
	char		 fname[NFILEN];
994
	char		*p = fname;
995
	int		 ret = FALSE;
996
997
	for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
998
		/*
999
		 * Check if the line has 'D' on the first char and if a valid
1000
		 * filename can be extracted from it.
1001
		 */
1002
		if (((lp->l_text[0] != DDELCHAR)) ||
1003
		    ((p = findfname(lp, p)) == NULL)) {
1004
			nlp = lforw(lp);
1005
			continue;
1006
		}
1007
		if (SLIST_EMPTY(&delhead)) {
1008
			if ((d1 = malloc(sizeof(struct delentry)))
1009
			     == NULL)
1010
				return (ABORT);
1011
			if ((d1->fn = strdup(p)) == NULL) {
1012
				free(d1);
1013
				return (ABORT);
1014
			}
1015
			SLIST_INSERT_HEAD(&delhead, d1, entry);
1016
		} else {
1017
			if ((d2 = malloc(sizeof(struct delentry)))
1018
			     == NULL) {
1019
				free(d1->fn);
1020
				free(d1);
1021
				return (ABORT);
1022
			}
1023
			if ((d2->fn = strdup(p)) == NULL) {
1024
				free(d1->fn);
1025
				free(d1);
1026
				free(d2);
1027
				return (ABORT);
1028
			}
1029
			SLIST_INSERT_AFTER(d1, d2, entry);
1030
			d1 = d2;
1031
		}
1032
		ret = TRUE;
1033
		nlp = lforw(lp);
1034
	}
1035
	return (ret);
1036
}
1037
1038
/*
1039
 * Look for and extract a file name on a dired buffer line.
1040
 */
1041
char *
1042
findfname(struct line *lp, char *fn)
1043
{
1044
	int start;
1045
1046
	(void)d_warpdot(lp, &start);
1047
	if (start < 1)
1048
		return NULL;
1049
	fn = &lp->l_text[start];
1050
	return fn;
1051
}