1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #if HAVE_UNISTD_H
7 #   include <unistd.h>
8 #endif
9 #if HAVE_FCNTL_H
10 #   include <fcntl.h>
11 #endif
12 #include "deco.h"
13 #include "dir.h"
14 #include "scr.h"
15 #include "env.h"
16 
17 #define SHELL           (usecshell ? cshname : shname)
18 #define ABSSHELL        (usecshell ? cshabsname : shabsname)
19 
20 #define MAXARGV 400
21 
22 static char shname [] = "sh";
23 static char cshname [] = "csh";
24 static char shabsname [] = "/bin/sh";
25 static char cshabsname [] = "/bin/csh";
26 
27 int usecshell;
28 int useredit, userview;
29 int showhidden = 1;
30 char editname [40], viewname [40];
31 
32 static int metas (char *s);
33 static int cmpfil (char *d1, char *f1, char *d2, char *f2);
34 
35 char *sysmsg [] = {
36 	0,
37 	"Hangup",               /* SIGHUP  1  hangup */
38 	"Interrupt",            /* SIGINT  2  interrupt (rubout) */
39 	"Quit",                 /* SIGQUIT 3  quit */
40 	"Illegal instruction",  /* SIGILL  4  illegal instruction */
41 	"Trace/BPT trap",       /* SIGTRAP 5  trace trap */
42 	"IOT trap",             /* SIGIOT  6  IOT instruction */
43 	"EMT trap",             /* SIGEMT  7  EMT instruction */
44 	"Floating exception",   /* SIGFPE  8  floating point exception */
45 	"Killed",               /* SIGKILL 9  kill */
46 	"Bus error",            /* SIGBUS  10 bus error */
47 	"Memory fault",         /* SIGSEGV 11 segmentation violation */
48 	"Bad system call",      /* SIGSYS  12 bad argument to system call */
49 	"Broken pipe",          /* SIGPIPE 13 write on a pipe with no one to read it */
50 	"Alarm call",           /* SIGALRM 14 alarm clock */
51 	"Terminated",           /* SIGTERM 15 software termination signal from kill */
52 };
53 
54 int numsysmsg = (sizeof sysmsg / sizeof sysmsg[0]);
55 
56 /* ARGSUSED */
57 
directory(int k,int sk)58 void directory (int k, int sk)
59 {
60 	setdir (cur, sk == 'r' ? "/" : home);
61 }
62 
switchalign(int k)63 void switchalign (int k)
64 {
65 	struct dir *d = k=='l' ? &left : &right;
66 
67 	d->alignext ^= 1;
68 }
69 
switchcmdreg()70 void switchcmdreg ()
71 {
72 	cmdreg ^= 1;
73 }
74 
switchhidden()75 void switchhidden ()
76 {
77 	showhidden ^= 1;
78 	setdir (cur == &left ? &right : &left, 0);
79 	setdir (cur, 0);
80 }
81 
switchpanels()82 void switchpanels ()
83 {
84 	cur = cur==&left ? &right : &left;
85 	chdir (cur->cwd);
86 }
87 
setstatus()88 void setstatus ()
89 {
90 	if (cur == &left)
91 		right.status ^= 1;
92 	else
93 		left.status ^= 1;
94 }
95 
fullscreen(int k,int sk)96 void fullscreen (int k, int sk)
97 {
98 	VClearBox (1, 0, LINES-2, 80);
99 	if (H == LINES/2-1)
100 		H = LINES-7;
101 	else
102 		H = LINES/2-1;
103 	while (left.topfile + PAGELEN (&left) <= left.curfile)
104 		left.topfile += H;
105 	while (right.topfile + PAGELEN (&right) <= right.curfile)
106 		right.topfile += H;
107 }
108 
redraw()109 void redraw ()
110 {
111 	VRedraw ();
112 }
113 
reread(int k,int sk)114 void reread (int k, int sk)
115 {
116 	struct dir *d = k=='l' ? &left : &right;
117 	register char *p;
118 
119 	if (! (p = getwstring (50, d->cwd, " Change directory ", "Change directory to")))
120 		return;
121 	if (! strcmp (p, d->cwd))
122 		setdir (d, 0);
123 	else if (chdir (p) < 0)
124 		error ("Cannot chdir to %s", p);
125 	else
126 		setdir (d, ".");
127 	chdir (cur->cwd);
128 }
129 
setdwid()130 void setdwid ()
131 {
132 	VClearBox (1, 0, LINES-2, 80);
133 	widewin ^= 1;
134 	while (left.topfile + PAGELEN (&left) <= left.curfile)
135 		left.topfile += H;
136 	while (right.topfile + PAGELEN (&right) <= right.curfile)
137 		right.topfile += H;
138 }
139 
setfull(int k,int sk)140 void setfull (int k, int sk)
141 {
142 	register struct dir *c = k=='l' ? &left : &right;
143 
144 	switch (sk) {
145 	case 'b':
146 		c->view = VIEW_BRIEF;
147 		break;
148 	case 'l':
149 		c->view = VIEW_LONG;
150 		break;
151 	case 'w':
152 		c->view = VIEW_WIDE;
153 		break;
154 	case 'f':
155 		c->view = VIEW_FULL;
156 		if (! widewin)
157 			setdwid ();
158 		break;
159 	case 'i':
160 		c->view = VIEW_INFO;
161 		if (! widewin)
162 			setdwid ();
163 		break;
164 	}
165 	while (c->topfile + PAGELEN (c) <= c->curfile)
166 		c->topfile += H;
167 }
168 
setsort(int k,int sk)169 void setsort (int k, int sk)
170 {
171 	register struct dir *c = k=='l' ? &left : &right;
172 
173 	switch (sk) {
174 	case 'n':       c->sort = SORTNAME;     break;
175 	case 'x':       c->sort = SORTEXT;      break;
176 	case 't':       c->sort = SORTTIME;     break;
177 	case 'z':       c->sort = SORTSIZE;     break;
178 	case 'u':       c->sort = SORTSKIP;     break;
179 	}
180 	setdir (c, 0);
181 	chdir (cur->cwd);
182 }
183 
settypesort(int k)184 void settypesort (int k)
185 {
186 	register struct dir *c = k=='l' ? &left : &right;
187 
188 	c->typesort ^= 1;
189 	setdir (c, 0);
190 	chdir (cur->cwd);
191 }
192 
setrevsort(int k)193 void setrevsort (int k)
194 {
195 	register struct dir *c = k=='l' ? &left : &right;
196 
197 	c->revsort ^= 1;
198 	setdir (c, 0);
199 	chdir (cur->cwd);
200 }
201 
setviewname()202 void setviewname ()
203 {
204 	register char *p;
205 
206 	switch (getchoice (0, " View ", "Select which viewer to use for F3:",
207 	    0, " Built-in ", " External ", 0)) {
208 	case 0:
209 		userview = 0;
210 	default:
211 		return;
212 	case 1:
213 		break;
214 	}
215 	if (! (p = getstring (40, viewname, " View ", "Viewer to use")))
216 		return;
217 	strncpy (viewname, p, 40);
218 	viewname [39] = 0;
219 	userview = 1;
220 }
221 
setshellname()222 void setshellname ()
223 {
224 	switch (getchoice (0, " Shell ", "Select which shell to use:",
225 	    0, " Shell ", " Cshell ", 0)) {
226 	case 0:
227 		usecshell = 0;
228 		break;
229 	case 1:
230 		usecshell = 1;
231 		break;
232 	}
233 }
234 
seteditname()235 void seteditname ()
236 {
237 	register char *p;
238 
239 	switch (getchoice (0, " Edit ", "Select which editor to use for F4:",
240 	    0, " Built-in ", " External ", 0)) {
241 	case 0:
242 		useredit = 0;
243 	default:
244 		return;
245 	case 1:
246 		break;
247 	}
248 	if (! (p = getstring (40, editname, " Edit ", "Editor to use")))
249 		return;
250 	strncpy (editname, p, 40);
251 	editname [39] = 0;
252 	useredit = 1;
253 }
254 
view()255 void view ()
256 {
257 	char buf [80];
258 	register char *name = cur->cat[cur->curfile].name;
259 	register d;
260 
261 	if (userview) {
262 		strcpy (buf, viewname);
263 		strcat (buf, " ");
264 		strcat (buf, name);
265 		VRestore ();
266 		syscmd (buf);
267 		VReopen ();
268 		VRedraw ();
269 		setdir (cur == &left ? &right : &left, 0);
270 		setdir (cur, 0);
271 		return;
272 	}
273 	if ((d = open (name, 0)) < 0) {
274 		error ("Cannot open %s", name);
275 		return;
276 	}
277 	viewfile (d, name);
278 	close (d);
279 }
280 
viewinfo()281 void viewinfo ()
282 {
283 	char buf [80];
284 	char name [512];
285 	register d;
286 
287 	sprintf (name, "%s/.info/%s", cur->cwd, cur->cat[cur->curfile].name);
288 	if (userview) {
289 		strcpy (buf, viewname);
290 		strcat (buf, " ");
291 		strcat (buf, name);
292 		VRestore ();
293 		syscmd (buf);
294 		VReopen ();
295 		VRedraw ();
296 		setdir (cur == &left ? &right : &left, 0);
297 		setdir (cur, 0);
298 		return;
299 	}
300 	if ((d = open (name, 0)) < 0) {
301 		error ("Cannot open %s", name);
302 		return;
303 	}
304 	viewfile (d, name);
305 	close (d);
306 }
307 
editfnam(char * name)308 static void editfnam (char *name)
309 {
310 	register d;
311 	register char *p;
312 	char buf [80];
313 	struct stat st;
314 
315 	if (stat (name, &st) >= 0) {
316 		if ((st.st_mode & S_IFMT) != S_IFREG) {
317 			error ("Cannot edit special files");
318 			return;
319 		}
320 	} else {
321 		d = creat (name, 0644);
322 		if (d < 0) {
323 			error ("Cannot create %s", name);
324 			return;
325 		}
326 		close (d);
327 	}
328 	if (useredit) {
329 		strcpy (buf, editname);
330 		strcat (buf, " ");
331 		strcat (buf, name);
332 		VRestore ();
333 		syscmd (buf);
334 		VReopen ();
335 		VRedraw ();
336 		setdir (cur == &left ? &right : &left, 0);
337 		setdir (cur, 0);
338 		return;
339 	}
340 	if ((d = open (name, 2)) < 0) {
341 		error ("Cannot open %s for writing", name);
342 		return;
343 	}
344 	/* skip directory name */
345 	for (p=name; *p; ++p);
346 	for (; p>=name && *p!='/'; --p);
347 	editfile (d, name, p+1);
348 	close (d);
349 }
350 
edit()351 void edit ()
352 {
353 	register char *name = cur->cat[cur->curfile].name;
354 	char namebuf [50];
355 
356 	if (strcmp (name, ".") == 0) {
357 		name = getstring (40, 0, " Edit ",
358 			"Enter name of file to edit");
359 		if (! name)
360 			return;
361 		strcpy (namebuf, name);
362 		editfnam (namebuf);
363 		return;
364 	}
365 	editfnam (name);
366 }
367 
editinfo()368 void editinfo ()
369 {
370 	char name [512];
371 
372 	sprintf (name, "%s/.info/%s", cur->cwd, cur->cat[cur->curfile].name);
373 	editfnam (name);
374 }
375 
menuedit()376 void menuedit ()
377 {
378 	char buf [80];
379 
380 	switch (getchoice (0, " Menu Edit ", "Select which menu to edit:",
381 	    0, " Current menu ", " Home menu ", 0)) {
382 	case 0:
383 		editfnam (".menu");
384 		break;
385 	case 1:
386 		strcpy (buf, home);
387 		strcat (buf, "/.menu");
388 		editfnam (buf);
389 		break;
390 	}
391 }
392 
extedit()393 void extedit ()
394 {
395 	char buf [80];
396 
397 	strcpy (buf, home);
398 	strcat (buf, "/.deco");
399 	editfnam (buf);
400 }
401 
quit()402 void quit ()
403 {
404 	int choice;
405 
406 	choice = getchoice (ppid == 1, " Demos Commander ",
407 		ppid == 1 ? "Do you want to log out ?" :
408 		"Do you want to quit the Demos Commander ?",
409 		0, " Yes ", " No ", " Exec shell ");
410 	if (choice == 0)
411 		quitdeco ();
412 	if (choice == 2) {
413 		/* exec shell */
414 		VClear ();
415 		VSync ();
416 		VClose ();
417 		execle (ABSSHELL, SHELL, "-i", 0, EnvVector);
418 		exit (0);
419 	}
420 	/* else stay here */
421 }
422 
quitdeco()423 void quitdeco ()
424 {
425 	VMove (LINES-1, 0);
426 	VClearLine ();
427 	VSync ();
428 	VClose ();
429 	exit (0);
430 }
431 
swappanels()432 void swappanels ()
433 {
434 	struct dir dir;
435 	int ro, lo;
436 
437 	ro = right.shortcwd - right.cwd;
438 	lo = left.shortcwd - left.cwd;
439 	dir = left;
440 	left = right;
441 	right = dir;
442 	left.basecol = 0;
443 	right.basecol = 40;
444 	right.shortcwd = lo + right.cwd;
445 	left.shortcwd = ro + left.cwd;
446 	cur = (cur == &left ? &right : &left);
447 }
448 
shell()449 void shell ()
450 {
451 	/* run shell */
452 	VClear ();
453 	VSync ();
454 	VRestore ();
455 	runl (0, ABSSHELL, SHELL, "-i", NULL);
456 	VReopen ();
457 	VClear ();
458 	setdir (cur == &left ? &right : &left, 0);
459 	setdir (cur, 0);
460 }
461 
tagged()462 int tagged ()
463 {
464 	register i, n;
465 
466 	for (i=n=0; i<cur->num; ++i)
467 		if (cur->cat[i].tag)
468 			++n;
469 	return (n);
470 }
471 
copy()472 void copy ()
473 {
474 	char buf [80];
475 	char *name;
476 	register struct file *p;
477 	register c;
478 	int done, all, ch;
479 	int exd, exf;
480 
481 	c = tagged ();
482 	if (c) {
483 		/* copy group of files */
484 
485 		sprintf (buf, "Copy %d file%s to", c, c>1 ? "s" : "");
486 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd,
487 		    " Copy ", buf)))
488 			return;
489 		runset (name);
490 		exd = exist (name);
491 		all = 0;
492 		for (p=cur->cat; p<cur->cat+cur->num; ++p)
493 			if (p->tag) {
494 				sprintf (buf, "%s/%s", name, p->name);
495 				exf = exd=='d' ? exist (buf) : 0;
496 				if (exd=='f' || exf=='f') {
497 					if (! all) {
498 						ch = getchoice (1, " Copy ", "File exists",
499 							exf=='f' ? buf : name,
500 							" Overwrite ", " All ", " Cancel ");
501 						switch (ch) {
502 						case 2:         /* cancel */
503 							--c;
504 							continue;
505 						case 1:         /* all */
506 							all = 1;
507 						case 0:         /* all */
508 							break;
509 						default:
510 							runcancel ();
511 							return;
512 						}
513 					}
514 				} else if (exf == 'd') {
515 					error ("%s is a directory", buf);
516 					continue;
517 				}
518 				runarg (p->name);
519 				p->tag = 0;
520 			}
521 		if (c <= 0) {
522 			runcancel ();
523 			return;
524 		}
525 		message (" Copy ", "Copying %d file%s to %s ...", c, c>1 ? "s" : "", name);
526 		done = rundone ("/bin/cp", "cp", "-f", "-p");
527 		if (done) {
528 			endmesg ();
529 			message (" Copy ", "Done");
530 		} else
531 			error ("Error while copying %d file%s to %s",
532 				c, c>1 ? "s" : "", name);
533 		endmesg ();
534 	} else if ((c = (p = &cur->cat[cur->curfile])->mode & S_IFMT) == S_IFDIR) {
535 		/* copying directory */
536 	} else if (c == S_IFREG) {
537 		/* copy regular file */
538 
539 		sprintf (buf, "Copy \"%s\" to", p->name);
540 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd, " Copy ", buf)))
541 			return;
542 		exd = exist (name);
543 		sprintf (buf, "%s/%s", name, p->name);
544 		exf = exd=='d' ? exist (buf) : 0;
545 		if (exd=='f' || exf=='f') {
546 			if (getchoice (1, " Copy ", "File exists",
547 			    exf=='f' ? buf : name,
548 			    " Overwrite ", " Cancel ", 0))
549 				return;
550 		} else if (exf == 'd') {
551 			error ("%s is a directory", buf);
552 			return;
553 		}
554 		if (runl (1, "/bin/cp", "cp", "-f", "-p", p->name, name, NULL)) {
555 			error ("Cannot copy %s to %s", p->name, name);
556 			return;
557 		}
558 	}
559 	setdir (cur == &left ? &right : &left, 0);
560 	setdir (cur, 0);
561 }
562 
makelink()563 void makelink ()
564 {
565 	char buf [80];
566 	char *name;
567 	register struct file *p;
568 	register c;
569 	int done;
570 	int exd, exf;
571 
572 	c = tagged ();
573 	if (c) {
574 		/* link group of files */
575 
576 		sprintf (buf, "Link %d file%s to", c, c>1 ? "s" : "");
577 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd,
578 		    " Link ", buf)))
579 			return;
580 		runset (name);
581 		exd = exist (name);
582 		for (p=cur->cat; p<cur->cat+cur->num; ++p)
583 			if (p->tag) {
584 				sprintf (buf, "%s/%s", name, p->name);
585 				exf = exd=='d' ? exist (buf) : 0;
586 				if (exd=='f' || exf=='f') {
587 					if (getchoice (1, " Link ", "File exists",
588 					    exf=='f' ? buf : name,
589 					    " Overwrite ", " Cancel ", 0))
590 						continue;
591 				} else if (exf == 'd') {
592 					error ("%s is a directory", buf);
593 					continue;
594 				}
595 				runarg (p->name);
596 				p->tag = 0;
597 			}
598 		message (" Link ", "Linking %d file%s to %s ...", c, c>1 ? "s" : "", name);
599 		done = rundone ("/bin/ln", "ln", "-f", 0);
600 		if (done) {
601 			endmesg ();
602 			message (" Link ", "Done");
603 		} else
604 			error ("Error while linking %d file%s to %s",
605 				c, c>1 ? "s" : "", name);
606 		endmesg ();
607 	} else if ((c = (p = &cur->cat[cur->curfile])->mode & S_IFMT) == S_IFDIR) {
608 		/* linking directory */
609 	} else if (c == S_IFREG) {
610 		/* link regular file */
611 
612 		sprintf (buf, "Link \"%s\" to", p->name);
613 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd, " Link ", buf)))
614 			return;
615 		exd = exist (name);
616 		sprintf (buf, "%s/%s", name, p->name);
617 		exf = exd=='d' ? exist (buf) : 0;
618 		if (exd=='f' || exf=='f') {
619 			if (getchoice (1, " Link ", "File exists",
620 			    exf=='f' ? buf : name,
621 			    " Overwrite ", " Cancel ", 0))
622 				return;
623 		} else if (exf == 'd') {
624 			error ("%s is a directory", buf);
625 			return;
626 		}
627 		if (runl (1, "/bin/ln", "ln", "-f", p->name, name, NULL)) {
628 			error ("Cannot link %s to %s", p->name, name);
629 			return;
630 		}
631 	}
632 	setdir (cur == &left ? &right : &left, 0);
633 	setdir (cur, 0);
634 }
635 
636 #ifdef S_IFLNK
makeslink()637 void makeslink ()
638 {
639 	char buf [80];
640 	char *name;
641 	register struct file *p;
642 	register c;
643 	int done;
644 	int exd, exf;
645 
646 	c = tagged ();
647 	if (c) {
648 		/* symlink group of files */
649 
650 		sprintf (buf, "Symlink %d file%s to", c, c>1 ? "s" : "");
651 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd,
652 		    " Symlink ", buf)))
653 			return;
654 		runset (name);
655 		exd = exist (name);
656 		for (p=cur->cat; p<cur->cat+cur->num; ++p)
657 			if (p->tag) {
658 				sprintf (buf, "%s/%s", name, p->name);
659 				exf = exd=='d' ? exist (buf) : 0;
660 				if (exd=='f' || exf=='f') {
661 					if (getchoice (1, " Symlink ", "File exists",
662 					    exf=='f' ? buf : name,
663 					    " Overwrite ", " Cancel ", 0))
664 						continue;
665 				} else if (exf == 'd') {
666 					error ("%s is a directory", buf);
667 					continue;
668 				}
669 				runarg (p->name);
670 				p->tag = 0;
671 			}
672 		message (" Symlink ", "Linking %d file%s to %s ...", c, c>1 ? "s" : "", name);
673 		done = rundone ("/bin/ln", "ln", "-s", "-f");
674 		if (done) {
675 			endmesg ();
676 			message (" Symlink ", "Done");
677 		} else
678 			error ("Error while linking %d file%s to %s",
679 				c, c>1 ? "s" : "", name);
680 		endmesg ();
681 	} else if ((c = (p = &cur->cat[cur->curfile])->mode & S_IFMT) == S_IFDIR) {
682 		/* symlinking directory */
683 	} else if (c == S_IFREG) {
684 		/* symlink regular file */
685 
686 		sprintf (buf, "Symlink \"%s\" to", p->name);
687 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd, " Symlink ", buf)))
688 			return;
689 		exd = exist (name);
690 		sprintf (buf, "%s/%s", name, p->name);
691 		exf = exd=='d' ? exist (buf) : 0;
692 		if (exd=='f' || exf=='f') {
693 			if (getchoice (1, " Symlink ", "File exists",
694 			    exf=='f' ? buf : name,
695 			    " Overwrite ", " Cancel ", 0))
696 				return;
697 		} else if (exf == 'd') {
698 			error ("%s is a directory", buf);
699 			return;
700 		}
701 		if (runl (1, "/bin/ln", "ln", "-s", "-f", p->name, name, NULL)) {
702 			error ("Cannot symlink %s to %s", p->name, name);
703 			return;
704 		}
705 	}
706 	setdir (cur == &left ? &right : &left, 0);
707 	setdir (cur, 0);
708 }
709 #endif /* S_IFLNK */
710 
renmove()711 void renmove ()
712 {
713 	char buf [MAXPATHLEN+20];
714 	char *name = 0;
715 	register struct file *p;
716 	register c;
717 	int done, all, ch;
718 	int exd, exf;
719 
720 	c = tagged ();
721 	if (c) {
722 		/* move group of files */
723 
724 		sprintf (buf, "Rename or move %d file%s to", c, c>1 ? "s" : "");
725 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd,
726 		    " Rename ", buf)))
727 			return;
728 		runset (name);
729 		exd = exist (name);
730 		all = 0;
731 		for (p=cur->cat; p<cur->cat+cur->num; ++p)
732 			if (p->tag) {
733 				sprintf (buf, "%s/%s", name, p->name);
734 				exf = exd=='d' ? exist (buf) : 0;
735 				if (exd=='f' || exf=='f') {
736 					if (! all) {
737 						ch = getchoice (1, " Rename ", "File exists",
738 							exf=='f' ? buf : name,
739 							" Overwrite ", " All ", " Cancel ");
740 						switch (ch) {
741 						default:
742 						case 2:         /* cancel */
743 							continue;
744 						case 1:         /* all */
745 							all = 1;
746 						}
747 					}
748 				} else if (exf == 'd') {
749 					error ("%s is a directory", buf);
750 					continue;
751 				}
752 				runarg (p->name);
753 			}
754 		message (" Move ", "Moving %d file%s to %s ...", c, c>1 ? "s" : "", name);
755 		done = rundone ("/bin/mv", "mv", "-f", 0);
756 		if (done) {
757 			endmesg ();
758 			message (" Move ", "Done");
759 		} else
760 			error ("Error while moving %d file%s to %s",
761 				c, c>1 ? "s" : "", name);
762 		endmesg ();
763 		name = 0;
764 	} else if ((c = (p = &cur->cat[cur->curfile])->mode & S_IFMT) == S_IFDIR) {
765 		/* rename directory */
766 
767 		sprintf (buf, "Rename \"%s\" to", strtail (p->name, '/', 60));
768 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd, " Rename ", buf)))
769 			return;
770 		exd = exist (name);
771 		sprintf (buf, "%s/%s", name, p->name);
772 		exf = exd=='d' ? exist (buf) : 0;
773 		if (exd=='f' || exf=='f') {
774 			if (getchoice (1, " Rename ", "File exists",
775 			    exf=='f' ? buf : name,
776 			    " Overwrite ", " Cancel ", 0))
777 				return;
778 		} else if (exf == 'd') {
779 			error ("Directory %s exists", buf);
780 			return;
781 		}
782 		if (runl (1, "/bin/mv", "mv", "-f", p->name, name, NULL)) {
783 			error ("Cannot move %s to %s", p->name, name);
784 			return;
785 		}
786 	} else if (c == S_IFREG) {
787 		/* move regular file */
788 
789 		sprintf (buf, "Rename or move \"%s\" to", p->name);
790 		if (! (name = getstring (60, (cur==&left?&right:&left)->cwd, " Rename ", buf)))
791 			return;
792 		exd = exist (name);
793 		sprintf (buf, "%s/%s", name, p->name);
794 		exf = exd=='d' ? exist (buf) : 0;
795 		if (exd=='f' || exf=='f') {
796 			if (getchoice (1, " Rename ", "File exists",
797 			    exf=='f' ? buf : name,
798 			    " Overwrite ", " Cancel ", 0))
799 				return;
800 		} else if (exf == 'd') {
801 			error ("%s is a directory", buf);
802 			return;
803 		}
804 		if (runl (1, "/bin/mv", "mv", "-f", p->name, name, NULL)) {
805 			error ("Cannot move %s to %s", p->name, name);
806 			return;
807 		}
808 	}
809 	setdir (cur == &left ? &right : &left, 0);
810 	setdir (cur, 0);
811 	if (name)
812 		findfile (cur, name);
813 }
814 
makedir()815 void makedir ()
816 {
817 	register char *p;
818 
819 	if (! (p = getstring (60, 0, " Make directory ", "Create the directory")))
820 		return;
821 	switch (exist (p)) {
822 	default:
823 	case 'f':
824 		error ("File %s exists", p);
825 		break;
826 	case 'd':
827 		error ("Directory %s already exists", p);
828 		break;
829 	case 0:
830 		if (runl (1, "/bin/mkdir", "mkdir", p, NULL)) {
831 			error ("Cannot create directory %s", p);
832 			break;
833 		}
834 		setdir (cur == &left ? &right : &left, 0);
835 		setdir (cur, 0);
836 		findfile (cur, p);
837 		break;
838 	}
839 }
840 
delete()841 void delete ()
842 {
843 	char buf [80];
844 	register struct file *p;
845 	register c;
846 
847 	c = tagged ();
848 	if (c) {
849 		/* delete group of files */
850 
851 		sprintf (buf, "You have selected %d file%s.", c, c>1 ? "s" : "");
852 		if (getchoice (0, " Delete ", buf, 0, " Delete ", " Cancel ", 0))
853 			return;
854 		sprintf (buf, "You are DELETING %d selected file%s from", c, c>1 ? "s" : "");
855 		if (getchoice (1, " Delete ", buf, cur->cwd, " Ok ", " Cancel ", 0))
856 			return;
857 		for (p=cur->cat; p<cur->cat+cur->num; ++p)
858 			if (p->tag && unlink (p->name) < 0)
859 				error ("Cannot delete %s", p->name);
860 	} else if ((c = (p = &cur->cat[cur->curfile])->mode & S_IFMT) == S_IFDIR) {
861 		/* delete directory */
862 
863 		if (getchoice (0, " Delete ", "Do you wish to delete directory",
864 		    p->name, " Delete ", " Cancel ", 0))
865 			return;
866 		if (runl (1, "/bin/rmdir", "rmdir", p->name, NULL)) {
867 			error ("Cannot delete directory %s", p->name);
868 			return;
869 		}
870 	} else if (c == S_IFREG) {
871 		/* delete regular file */
872 
873 		if (getchoice (0, " Delete ", "Do you wish to delete",
874 		    p->name, " Delete ", " Cancel ", 0))
875 			return;
876 		if (unlink (p->name) < 0) {
877 			error ("Cannot delete %s", p->name);
878 			return;
879 		}
880 	}
881 	setdir (cur == &left ? &right : &left, 0);
882 	setdir (cur, 0);
883 }
884 
findname()885 void findname ()
886 {
887 	register char *s, *q;
888 	register char *p;
889 	register struct file *f;
890 
891 	if (! (p = getwstring (20, "", " Find file ", "Enter file name")) || ! *p)
892 		return;
893 	for (f=cur->cat; f<cur->cat+cur->num; ++f) {
894 		s=p;
895 		q=f->name;
896 		for (;;) {
897 			if (! *s) {
898 				cur->curfile = f - cur->cat;
899 				if (cur->topfile > cur->curfile || cur->topfile + PAGELEN (cur) <= cur->curfile)
900 					cur->topfile = cur->curfile - PAGELEN (cur) + 1;
901 				while (cur->topfile + PAGELEN (cur) - H > cur->curfile)
902 					cur->topfile -= H;
903 				if (cur->topfile < 0)
904 					cur->topfile = 0;
905 				return;
906 			} else if (*s != *q)
907 				break;
908 			++s;
909 			++q;
910 		}
911 	}
912 	error ("File not found");
913 }
914 
tagall()915 void tagall ()
916 {
917 	register char *p;
918 	register struct file *f;
919 	static char pat [20];
920 
921 	if (! pat[0])
922 		strcpy (pat, "*");
923 	if (! (p = getwstring (20, pat, " Select ", "Select the files")))
924 		return;
925 	strncpy (pat, p, 20);
926 	pat [19] = 0;
927 	for (f=cur->cat; f<cur->cat+cur->num; ++f)
928 		if ((f->mode & S_IFMT) == (unsigned) S_IFREG &&
929 		    (! pat[0] || match (f->name, pat)))
930 			f->tag = 1;
931 	counttag (cur);
932 }
933 
untagall()934 void untagall ()
935 {
936 	register char *p;
937 	register struct file *f;
938 	static char pat [20];
939 
940 	if (! pat[0])
941 		strcpy (pat, "*");
942 	if (! (p = getwstring (20, pat, " Unselect ", "Unselect the files")))
943 		return;
944 	strncpy (pat, p, 20);
945 	pat [19] = 0;
946 	for (f=cur->cat; f<cur->cat+cur->num; ++f)
947 		if ((f->mode & S_IFMT) == (unsigned) S_IFREG &&
948 		    (! pat[0] || match (f->name, pat)))
949 			f->tag = 0;
950 	counttag (cur);
951 }
952 
setpattern(int k)953 void setpattern (int k)
954 {
955 	struct dir *d = k=='l' ? &left : &right;
956 	register char *p;
957 
958 	if (! (p = getwstring (20, d->pattern, " Set pattern ", "Set pattern for files")))
959 		return;
960 	strncpy (d->pattern, p, PATSZ);
961 	d->pattern [PATSZ-1] = 0;
962 	setdir (d, 0);
963 	chdir (cur->cwd);
964 }
965 
cmpdir()966 void cmpdir ()
967 {
968 	register struct file *f, *of;
969 	register struct dir *d, *od;
970 	struct file *end, *oend;
971 	int cmp;
972 
973 	d = &left;
974 	od = &right;
975 	end = d->cat + d->num;
976 	oend = od->cat + od->num;
977 	for (of=od->cat; of<oend; ++of)
978 		if ((of->mode & S_IFMT) == (unsigned) S_IFREG)
979 			of->tag = 1;
980 	for (f=d->cat; f<end; ++f)
981 		if ((f->mode & S_IFMT) == (unsigned) S_IFREG)
982 			f->tag = 1;
983 	for (f=d->cat, of=od->cat; of<oend; ++of) {
984 		while ((cmp = compfile (f, of)) < 0)
985 			if (++f >= end)
986 				goto breakloop;
987 		if (! of->tag || ! f->tag)
988 			continue;
989 		if (cmp || f->size != of->size)
990 			continue;
991 		if (cmpfil (d->cwd, f->name, od->cwd, of->name))
992 			f->tag = of->tag = 0;
993 	}
994 breakloop:
995 	counttag (d);
996 	counttag (od);
997 }
998 
cmpfil(char * d1,char * f1,char * d2,char * f2)999 static int cmpfil (char *d1, char *f1, char *d2, char *f2)
1000 {
1001 	register i;
1002 	int fd1, fd2;
1003 	char buf1 [512], buf2 [512];
1004 	int n1, n2, rez;
1005 
1006 	sprintf (buf1, "%s/%s", d1, f1);
1007 	sprintf (buf2, "%s/%s", d2, f2);
1008 	if ((fd1 = open (buf1, 0)) < 0)
1009 		return (0);
1010 	if ((fd2 = open (buf2, 0)) < 0) {
1011 		close (fd1);
1012 		return (0);
1013 	}
1014 	rez = 0;
1015 	for (;;) {
1016 		n1 = read (fd1, buf1, sizeof (buf1));
1017 		n2 = read (fd2, buf2, sizeof (buf2));
1018 		if (n1 < 0 || n2 < 0 || n1 != n2)
1019 			break;
1020 		if (n1 == 0) {
1021 			rez = 1;
1022 			goto breakloop;
1023 		}
1024 		for (i=0; i<n1; ++i)
1025 			if (buf1 [i] != buf2 [i])
1026 				goto breakloop;
1027 	}
1028 breakloop:
1029 	close (fd1);
1030 	close (fd2);
1031 	return (rez);
1032 }
1033 
syscmd(char * s)1034 void syscmd (char *s)
1035 {
1036 	register status, sig;
1037 
1038 	if (metas (s)) {
1039 		if (usecshell)
1040 			runl (0, cshabsname, cshname, "-f", "-c", s, NULL);
1041 		else
1042 			runl (0, shabsname, shname, "-c", s, NULL);
1043 		return;
1044 	}
1045 	status = doexec (s);
1046 	if (status < 0) {
1047 		TtyReset ();
1048 		outerr ("\n[%d] %s\n", -status, s);
1049 		jobcmd (-status, s);
1050 		return;
1051 	}
1052 	sig = status & 0177;
1053 	if (! sig)
1054 		return;
1055 	if (sig == 0177)
1056 		outerr ("ptrace: ");
1057 	else if (sig < numsysmsg && sysmsg [sig])
1058 		outerr (sysmsg [sig]);
1059 	else
1060 		outerr ("Signal %d", sig);
1061 	if (status & 0200)
1062 		outerr (" - core dumped\n");
1063 	else
1064 		outerr ("\n");
1065 }
1066 
1067 /*
1068  * Are there are any Shell meta-characters?
1069  */
metas(char * s)1070 static int metas (char *s)
1071 {
1072 	while (*s)
1073 		switch (*s++) {
1074 		case '|':       case '^':       case ';':       case '&':
1075 		case '(':       case ')':       case '<':       case '>':
1076 		case '[':       case ']':       case '*':       case '?':
1077 		case '\'':      case '\"':      case '\\':      case '`':
1078 		case '$':       case '~':
1079 		/* case '\n': case '=': case ':': */
1080 		return (1);
1081 		}
1082 	return (0);
1083 }
1084 
doexec(char * str)1085 int doexec (char *str)
1086 {
1087 	register char *t;
1088 	char *argv [MAXARGV+1];
1089 	register char **p;
1090 	int status;
1091 
1092 	while (*str == ' ' || *str == '\t')
1093 		++str;
1094 	if (! *str)
1095 		return (-1);		/* no command */
1096 	t = malloc (strlen (str) + 1);
1097 	strcpy (t, str);
1098 	str = t;
1099 	p = argv;
1100 	for (t = str; *t;) {
1101 		if (p >= argv+MAXARGV) {
1102 			error ("%s: Too many arguments", str);
1103 			break;
1104 		}
1105 		*p++ = t;
1106 		while (*t && *t!=' ' && *t!='\t')
1107 			++t;
1108 		if (*t)
1109 			for (*t++ =0; *t==' ' || *t=='\t'; ++t);
1110 	}
1111 	*p = 0;
1112 	status = runv (0, str, argv);
1113 	free (str);
1114 	return (status);
1115 }
1116