1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <sys/ioctl.h>
5 #if HAVE_UNISTD_H
6 #   include <unistd.h>
7 #endif
8 #include "scr.h"
9 #include "dir.h"
10 #include "deco.h"
11 #include "env.h"
12 
13 struct dir left, right;                 /* left and right directories */
14 struct dir *cur;                        /* current directory */
15 int H;                                  /* file window height */
16 int uid;                                /* real user id */
17 int main_pid;                           /* our process id */
18 int ppid;                               /* parent process id */
19 int widewin;                            /* full window mode */
20 char *user;
21 char *group;
22 char *tty = 0;
23 char *machine;
24 int cpos;                               /* position of command line cursor */
25 int cmdreg;                             /* cursor in command line */
26 int visualwin = 1;                      /* cursor in command line */
27 int lang;
28 
29 #ifndef GETGROUPS_T
30 #define GETGROUPS_T int
31 #endif
32 
33 GETGROUPS_T gidlist [128];              /* groups list */
34 int gidnum;                             /* number of groups in list */
35 
36 struct palette dflt_palette = { 7, 0, 7, 6, 15, 0, 15, 6, 3, 0, 0, 7, };
37 struct palette palette;
38 
39 static struct KeyMap keymap [] = {
40 	{ "kl",         0,              meta ('l')      },
41 	{ "kr",         0,              meta ('r')      },
42 	{ "ku",         0,              meta ('u')      },
43 	{ "kd",         0,              meta ('d')      },
44 	{ "kN",         0,              meta ('n')      },
45 	{ "kP",         0,              meta ('p')      },
46 	{ "kh",         0,              meta ('h')      },
47 	{ "kH",         0,              meta ('e')      },
48 	{ "@7",         0,              meta ('e')      },
49 	{ "kI",         0,              cntrl ('T')     },
50 	{ "k.",         0,              cntrl ('G')     },
51 	{ "kD",         0,              cntrl ('G')     },
52 	{ "kE",         0,              meta ('h')      },
53 	{ "kS",         0,              meta ('e')      },
54 	{ "k1",         0,              meta ('A')      },
55 	{ "k2",         0,              meta ('B')      },
56 	{ "k3",         0,              meta ('C')      },
57 	{ "k4",         0,              meta ('D')      },
58 	{ "k5",         0,              meta ('E')      },
59 	{ "k6",         0,              meta ('F')      },
60 	{ "k7",         0,              meta ('G')      },
61 	{ "k8",         0,              meta ('H')      },
62 	{ "k9",         0,              meta ('I')      },
63 	{ "k0",         0,              meta ('J')      },
64 	{ "k;",         0,              meta ('J')      },
65 	{ "f1",         0,              meta ('A')      },
66 	{ "f2",         0,              meta ('B')      },
67 	{ "f3",         0,              meta ('C')      },
68 	{ "f4",         0,              meta ('D')      },
69 	{ "f5",         0,              meta ('E')      },
70 	{ "f6",         0,              meta ('F')      },
71 	{ "f7",         0,              meta ('G')      },
72 	{ "f8",         0,              meta ('H')      },
73 	{ "f9",         0,              meta ('I')      },
74 	{ "f0",         0,              meta ('J')      },
75 	{ "kb",         "\b",           meta ('b')      },
76 	{ 0,            "\0331",        meta ('A')      },
77 	{ 0,            "\0332",        meta ('B')      },
78 	{ 0,            "\0333",        meta ('C')      },
79 	{ 0,            "\0334",        meta ('D')      },
80 	{ 0,            "\0335",        meta ('E')      },
81 	{ 0,            "\0336",        meta ('F')      },
82 	{ 0,            "\0337",        meta ('G')      },
83 	{ 0,            "\0338",        meta ('H')      },
84 	{ 0,            "\0339",        meta ('I')      },
85 	{ 0,            "\0330",        meta ('J')      },
86 
87 	{ 0,            "\033l",        meta ('l')      },
88 	{ 0,            "\033r",        meta ('r')      },
89 	{ 0,            "\033u",        meta ('u')      },
90 	{ 0,            "\033d",        meta ('d')      },
91 	{ 0,            "\033n",        meta ('n')      },
92 	{ 0,            "\033p",        meta ('p')      },
93 	{ 0,            "\033h",        meta ('h')      },
94 	{ 0,            "\033e",        meta ('e')      },
95 
96 	{ 0,            "\033\033",     cntrl ('C')     },
97 	{ 0,            0,              0               },
98 };
99 
100 static void init (void);
101 static void inithome (void);
102 static void initlang (void);
103 static void execute (void);
104 static void docmdreg (int c);
105 static void doscrreg (int c);
106 
main(int argc,char ** argv,char ** envp)107 int main (int argc, char **argv, char **envp)
108 {
109 	register c;
110 
111 	if (argc > 2) {
112 		outerr ("Usage: deco [dirname]\n");
113 		exit (1);
114 	}
115 #ifdef GC
116 	/*GC_set_warn_proc (outerr);*/
117 #endif
118 	outerr ("Demos Commander, Copyright (C) 1989-1997 Serge Vakulenko\n");
119 	palette = dflt_palette;
120 	if (argc > 1)
121 		chdir (argv [1]);
122 	EnvInit (envp);
123 	initlang ();
124 	uid = getuid ();
125 #ifdef HAVE_GETGROUPS
126 	gidnum = getgroups (sizeof(gidlist)/sizeof(gidlist[0]), gidlist);
127 #else
128 	gidlist[0] = getgid ();
129 	gidnum = 1;
130 #endif
131 	main_pid = getpid ();
132 	ppid = getppid ();
133 	user = username (uid);
134 	group = groupname (gidlist[0]);
135 	tty = ttyname (0);
136 	machine = getmachine ();
137 	sigign ();
138 	tcsetpgrp (2, main_pid);
139 
140 	init ();
141 	inithome ();
142 	VClear ();
143 	right.sort = SORTEXT;
144 	left.sort = SORTEXT;
145 	right.typesort = 1;
146 	left.typesort = 1;
147 	right.alignext = 1;
148 	left.alignext = 1;
149 	readinitfile ();
150 	if (uid == 0)
151 		palette.dimfg = 6;
152 	VSetPalette (palette.fg, palette.bg, palette.revfg, palette.revbg,
153 		palette.boldfg, palette.boldbg, palette.boldrevfg, palette.boldrevbg,
154 		palette.dimfg, palette.dimbg, palette.dimrevfg, palette.dimrevbg);
155 	setdir (&left, ".");
156 	setdir (&right, home);
157 	chdir (left.cwd);
158 	cur = &left;
159 	draw ();
160 	for (;;) {
161 		if (! cmdreg)
162 			drawcursor ();
163 		drawcmd ();
164 		VSync ();
165 		c = KeyGet ();
166 		if (! cmdreg)
167 			undrawcursor ();
168 		switch (c) {
169 		case '+':               /* select */
170 		case '-':               /* unselect */
171 			if (! cpos && ! cmdreg && ! cur->status) {
172 				if (c == '+')
173 					tagall ();
174 				else
175 					untagall ();
176 				draw ();
177 				continue;
178 			}
179 		default:
180 			if ((c>=' ' && c<='~') || (c>=0300 && c<=0377)) {
181 				if (cpos || c!=' ')
182 					inscmd (c);
183 				continue;
184 			}
185 			VBeep ();
186 			continue;
187 		case cntrl ('V'):       /* quote next char */
188 			inscmd (quote ());
189 			continue;
190 		case cntrl ('J'):       /* insert file name */
191 			if (! cmdreg && ! cur->status)
192 				namecmd ();
193 			continue;
194 		case cntrl ('G'):
195 			delcmd ();
196 			continue;
197 		case meta ('b'):        /* backspace */
198 			if (cpos) {
199 				leftcmd ();
200 				delcmd ();
201 			}
202 			continue;
203 		case cntrl ('O'):       /* set/unset command mode */
204 		case cntrl ('P'):       /* set/unset command mode */
205 			switchcmdreg ();
206 			if (! cmdreg)
207 				visualwin = 1;
208 			draw ();
209 			continue;
210 		case cntrl ('M'):         /* return */
211 			if (command [0]) {
212 				execmd (1, 1);
213 				draw ();
214 				continue;
215 			}
216 			if (cmdreg) {
217 				cmdreg = 0;
218 				if (! visualwin) {
219 					visualwin = 1;
220 					setdir (cur==&left ? &right : &left, 0);
221 					setdir (cur, 0);
222 				}
223 				draw ();
224 				continue;
225 			}
226 			execute ();
227 			continue;
228 		case cntrl (']'):       /* redraw screen */
229 			VRedraw ();
230 			continue;
231 		case cntrl ('B'):        /* history */
232 			if (! visualwin)
233 				VClearBox (1, 0, LINES-2, 80);
234 			histmenu ();
235 			draw ();
236 			continue;
237 		case meta ('A'):        /* f1 */
238 			genhelp ();
239 			draw ();
240 			continue;
241 		case meta ('B'):          /* f2 */
242 			usermenu ();
243 			draw ();
244 			continue;
245 		case meta ('I'):        /* f9 */
246 			runmenu (cur==&left ? 'l' : 'r');
247 			draw ();
248 			continue;
249 		case meta ('J'):        /* f0 */
250 		case cntrl ('C'):       /* quit */
251 			quit ();
252 			continue;
253 		case cntrl ('U'):       /* swap panels */
254 			swappanels ();
255 			draw ();
256 			continue;
257 		case cntrl ('F'):       /* full screen */
258 			fullscreen (0, 0);
259 			draw ();
260 			continue;
261 		case cntrl ('^'):       /* cd / */
262 			directory (0, 'r');
263 			if (! cur->status)
264 				drawdir (cur, 1);
265 			continue;
266 		case cntrl ('\\'):      /* cd $HOME */
267 			directory (0, 'o');
268 			if (! cur->status)
269 				drawdir (cur, 1);
270 			continue;
271 		case cntrl ('Y'):       /* clear line */
272 			command [cpos = 0] = 0;
273 			continue;
274 		case cntrl ('X'):       /* next history */
275 			nextcmd ();
276 			continue;
277 		case cntrl ('E'):       /* prev history */
278 			prevcmd ();
279 			continue;
280 		case cntrl ('S'):       /* char left */
281 		case cntrl ('A'):       /* char left */
282 			leftcmd ();
283 			continue;
284 		case cntrl ('D'):       /* char right */
285 			rightcmd ();
286 			continue;
287 		case cntrl ('I'):       /* tab */
288 			if (cmdreg)
289 				if (command [cpos])
290 					endcmd ();
291 				else
292 					homecmd ();
293 			else {
294 				switchpanels ();
295 				if (widewin) {
296 					drawbanners ();
297 					drawdir (cur, 0);
298 					break;
299 				}
300 			}
301 			continue;
302 		case cntrl ('W'):       /* double width */
303 			if (! cmdreg) {
304 				setdwid ();
305 				draw ();
306 			}
307 			continue;
308 		case meta ('G'):        /* f7 */
309 			makedir ();
310 			draw ();
311 			continue;
312 		case meta ('h'):        /* home */
313 		case meta ('e'):        /* end */
314 		case meta ('u'):        /* up */
315 		case meta ('d'):        /* down */
316 		case meta ('l'):        /* left */
317 		case meta ('r'):        /* right */
318 		case meta ('n'):        /* next page */
319 		case meta ('p'):        /* prev page */
320 		case cntrl ('K'):       /* find file */
321 		case cntrl ('R'):       /* reread catalog */
322 		case cntrl ('T'):       /* tag file */
323 		case meta ('C'):        /* f3 */
324 		case meta ('D'):        /* f4 */
325 		case meta ('E'):        /* f5 */
326 		case meta ('F'):        /* f6 */
327 		case meta ('H'):        /* f8 */
328 		case cntrl ('L'):       /* status */
329 			if (cmdreg || cur->status)
330 				docmdreg (c);
331 			else
332 				doscrreg (c);
333 			continue;
334 		}
335 	}
336 }
337 
doscrreg(int c)338 static void doscrreg (int c)
339 {
340 	switch (c) {
341 	case meta ('h'):          /* home */
342 		cur->curfile = cur->topfile = 0;
343 		break;
344 	case meta ('e'):          /* end */
345 		cur->curfile = cur->num - 1;
346 		cur->topfile = cur->num - PAGELEN (cur);
347 		if (cur->topfile < 0)
348 			cur->topfile = 0;
349 		break;
350 	case meta ('u'):          /* up */
351 		if (cur->curfile <= 0)
352 			return;
353 		if (cur->curfile > cur->topfile) {
354 			--cur->curfile;
355 			return;
356 		}
357 		cur->topfile = --cur->curfile;
358 		break;
359 	case meta ('d'):          /* down */
360 		if (cur->curfile >= cur->num-1)
361 			return;
362 		if (cur->topfile + PAGELEN (cur) - 1 > cur->curfile) {
363 			++cur->curfile;
364 			return;
365 		}
366 		cur->topfile = ++cur->curfile - PAGELEN (cur) + 1;
367 		break;
368 	case meta ('l'):          /* left */
369 		if (cur->curfile < H) {
370 			if (cur->topfile <= 0)
371 				return;
372 			cur->curfile -= cur->topfile;
373 			cur->topfile = 0;
374 			break;
375 		}
376 		cur->curfile -= H;
377 		if (cur->topfile <= cur->curfile)
378 			return;
379 		cur->topfile -= H;
380 		if (cur->topfile <= 0) {
381 			cur->curfile -= cur->topfile;
382 			cur->topfile = 0;
383 		}
384 		break;
385 	case meta ('r'):          /* right */
386 		if (cur->curfile + H < cur->num) {
387 			cur->curfile += H;
388 			if (cur->topfile + PAGELEN (cur) > cur->curfile)
389 				return;
390 			cur->topfile += H;
391 			break;
392 		}
393 		if (cur->topfile + PAGELEN (cur) < cur->num) {
394 			cur->curfile = cur->num-1;
395 			cur->topfile += H;
396 			break;
397 		}
398 		if ((cur->curfile - cur->topfile) / H <
399 		    (cur->num - cur->topfile - 1) / H)
400 			cur->curfile = cur->num-1;
401 		return;
402 	case meta ('n'):          /* next page */
403 		if (cur->topfile + PAGELEN (cur) >= cur->num) {
404 			cur->curfile = cur->num-1;
405 		} else if (cur->topfile + 2 * PAGELEN (cur) >= cur->num) {
406 			cur->curfile = cur->num-1;
407 			cur->topfile = cur->num - PAGELEN (cur);
408 		} else {
409 			cur->curfile += PAGELEN (cur);
410 			cur->topfile += PAGELEN (cur);
411 		}
412 		break;
413 	case meta ('p'):          /* prev page */
414 		if (cur->topfile == 0) {
415 			cur->curfile = 0;
416 		} else {
417 			cur->curfile -= PAGELEN (cur);
418 			if (cur->topfile > cur->curfile)
419 				cur->topfile -= PAGELEN (cur);
420 			if (cur->topfile < 0) {
421 				cur->curfile -= cur->topfile;
422 				cur->topfile = 0;
423 			}
424 		}
425 		break;
426 	case cntrl ('K'):         /* find file */
427 		findname ();
428 		break;
429 	case cntrl ('R'):         /* reread catalog */
430 		reread (cur==&left ? 'l' : 'r', 0);
431 		break;
432 	case cntrl ('T'):         /* tag file */
433 		if ((cur->cat[cur->curfile].mode & S_IFMT) == (unsigned) S_IFREG) {
434 			cur->cat[cur->curfile].tag ^= 1;
435 			counttag (cur);
436 		}
437 		if (cur->curfile < cur->num-1) {
438 			/* move down */
439 			++cur->curfile;
440 			if (cur->topfile + PAGELEN (cur) - 1 < cur->curfile)
441 				cur->topfile = cur->curfile - PAGELEN (cur) + 1;
442 		}
443 		break;
444 	case meta ('C'):          /* f3 */
445 		if ((cur->cat[cur->curfile].mode & S_IFMT) != (unsigned) S_IFREG)
446 			return;
447 		view ();
448 		draw ();
449 		return;
450 	case meta ('D'):          /* f4 */
451 		edit ();
452 		setdir (cur==&left ? &right : &left, 0);
453 		setdir (cur, 0);
454 		draw ();
455 		return;
456 	case meta ('E'):          /* f5 */
457 		copy ();
458 		draw ();
459 		return;
460 	case meta ('F'):          /* f6 */
461 		renmove ();
462 		draw ();
463 		return;
464 	case meta ('H'):          /* f8 */
465 		delete ();
466 		draw ();
467 		return;
468 	case cntrl ('L'):         /* status */
469 		setstatus ();
470 		draw ();
471 		return;
472 	}
473 	drawdir (cur, 1);
474 }
475 
docmdreg(int c)476 static void docmdreg (int c)
477 {
478 	switch (c) {
479 	case meta ('h'):          /* home */
480 		homecmd ();
481 		return;
482 	case meta ('e'):          /* end */
483 		endcmd ();
484 		return;
485 	case meta ('l'):          /* left */
486 		leftcmd ();
487 		return;
488 	case meta ('r'):          /* right */
489 		rightcmd ();
490 		return;
491 	case meta ('u'):          /* up */
492 		upcmd ();
493 		return;
494 	case meta ('d'):          /* down */
495 		downcmd ();
496 		return;
497 	case meta ('n'):          /* next page */
498 		nextcmd ();
499 		return;
500 	case meta ('p'):          /* prev page */
501 		prevcmd ();
502 		return;
503 	}
504 }
505 
execute()506 static void execute ()
507 {
508 	register struct file *file = &cur->cat[cur->curfile];
509 	register char *name = file->name;
510 	int updir, dev = 0, ino = 0;
511 
512 	switch (file->mode & S_IFMT) {
513 	case S_IFDIR:
514 		if (! strcmp (name, ".")) {
515 			setdir (cur, 0);
516 			break;
517 		}
518 		if ((updir = !strcmp (name, ".."))) {
519 			dev = cur->dev;
520 			ino = cur->ino;
521 		}
522 		if (chdir (name) < 0)
523 			break;
524 		setdir (cur, ".");
525 		if (updir) {
526 			for (cur->curfile=0; cur->curfile<cur->num; ++cur->curfile) {
527 				if (cur->cat[cur->curfile].dev == dev &&
528 				    cur->cat[cur->curfile].ino == ino)
529 					break;
530 			}
531 			if (cur->curfile >= cur->num)
532 				cur->curfile = 0;
533 			if (cur->topfile + PAGELEN (cur) <= cur->curfile)
534 				cur->topfile = cur->curfile - PAGELEN (cur) + 1;
535 		}
536 		if (visualwin) {
537 			drawdir (&left, 0);
538 			drawdir (&right, 0);
539 		}
540 		break;
541 	case S_IFREG:
542 		if (file->execable)
543 			strcpy (command, file->name);
544 		else
545 			excommand (command, file->name);
546 		cpos = strlen (command);
547 		if (! command [0])
548 			break;
549 		execmd (file->execable ? 1 : 0, 1);
550 		draw ();
551 		break;
552 	}
553 }
554 
init()555 static void init ()
556 {
557 	char *buf;
558 
559 	buf = malloc (2048);
560 	if (! CapInit (buf)) {
561 		outerr ("Cannot read termcap\n");
562 		exit (1);
563 	}
564 	if (! VInit ()) {
565 		outerr ("Cannot initialize video device\n");
566 		exit (1);
567 	}
568 	if (COLS < 80) {
569 		outerr ("The screen must have at least 80 columns\n");
570 		exit (1);
571 	}
572 	KeyInit (keymap, VFlush);
573 	VOpen ();
574 	free (buf);
575 
576 	/* H is the number of lines at file window */
577 
578 	H = LINES/2-1;
579 
580 	left.basecol = 0;
581 	right.basecol = 40;
582 }
583 
pagelen(int view)584 int pagelen (int view)
585 {
586 	register h = H;
587 
588 	if (! widewin)
589 		return (view == VIEW_BRIEF ? h+h : h);
590 	switch (view) {
591 	case VIEW_BRIEF:
592 		h += h;
593 	case VIEW_LONG:
594 	case VIEW_WIDE:
595 		return (h+h);
596 	default:
597 		return (h);
598 	}
599 }
600 
inithome()601 static void inithome ()
602 {
603 	register char *s;
604 
605 	if ((s = EnvGet ("HOME")))
606 		home = s;
607 }
608 
initlang()609 static void initlang ()
610 {
611 	register char *s = EnvGet ("MSG");
612 
613 	if (! s)
614 		s = "e";
615 	switch (*s) {
616 	default:  lang = ENG; break;
617 	case 'r': lang = RUS; break;
618 	case 'u': lang = UKR; break;
619 	case 'd': lang = DEU; break;
620 	case 'f': lang = FRA; break;
621 	}
622 }
623 
setlang()624 void setlang ()
625 {
626 	char *s, *altlang;
627 
628 	s = EnvGet ("MSG");
629 	if (! s)
630 		s = "l";
631 	switch (*s) {
632 	default:  altlang = " Russian ";   break;
633 	case 'u': altlang = " Ukrainian "; break;
634 	case 'd': altlang = " Deutch ";    break;
635 	case 'f': altlang = " Francais ";  break;
636 	}
637 	switch (getchoice (0, " Language ", "Select language to use:",
638 	    0, " English ", altlang, 0)) {
639 	case 0:
640 		lang = ENG;
641 		break;
642 	case 1:
643 		switch (*s) {
644 		default:  lang = RUS; break;
645 		case 'u': lang = UKR; break;
646 		case 'd': lang = DEU; break;
647 		case 'f': lang = FRA; break;
648 		}
649 		break;
650 	}
651 }
652 
hidecursor()653 void hidecursor ()
654 {
655 	VMove (LINES-1, COLS-2);
656 }
657 
mvcaddstr(int r,int c,char * s)658 void mvcaddstr (int r, int c, char *s)
659 {
660 	VMPutString (r, c - (strlen (s) + 1) / 2, s);
661 }
662 
quote()663 int quote ()
664 {
665 	register c, i;
666 
667 	c = KeyGet ();
668 	if (c<'0' || c>'3')
669 		return (c);
670 	i = c & 3;
671 	c = KeyGet ();
672 	if (c<'0' || c>'7') {
673 		KeyUnget (c);
674 		return (i);
675 	}
676 	i = i << 3 | (c & 7);
677 	c = KeyGet ();
678 	if (c<'0' || c>'7') {
679 		KeyUnget (c);
680 		return (i);
681 	}
682 	return (i << 3 | (c & 7));
683 }
684 
mygroup(int gid)685 int mygroup (int gid)
686 {
687 	int i;
688 
689 	for (i=0; i<gidnum; ++i)
690 		if (gid == gidlist[i])
691 			return 1;
692 	return 0;
693 }
694