1 /*
2  *      Syntax of file ~/.deco
3  *
4  *      # comment
5  *      pattern1 pattern2 ... patternN
6  *              command
7  *      pattern1 pattern2 ... patternN
8  *              command
9  *      ...
10  */
11 
12 /*
13  *      Syntax of file ./.menu
14  *
15  *      # comment
16  *      key1    string1
17  *              command1
18  *      key1    string1
19  *              command1
20  *      ...
21  *
22  *      Keys are:
23  *
24  *              a-z, A-Z, 0-9   - simple characters
25  *              F1-F10          - function keys
26  */
27 
28 /*
29  *      Command may contain macro characters:
30  *
31  *              %f      - current file name
32  *              %b      - base name
33  *              %d      - directory name
34  *              %c      - full directory name
35  *              %h      - full home directory name
36  *              %u      - user name
37  *              %g      - group name
38  *              %t      - list of tagged files or current file name
39  *              %%      - symbol '%'
40  */
41 
42 #include <stdlib.h>
43 #include <string.h>
44 #if HAVE_UNISTD_H
45 #   include <unistd.h>
46 #endif
47 #if HAVE_FCNTL_H
48 #   include <fcntl.h>
49 #endif
50 #include "dir.h"
51 #include "deco.h"
52 #include "scr.h"
53 
54 #define EXSZ   64
55 #define BUFSZ  2048
56 #define STRSZ  256
57 #define EXFILE ".deco"
58 #define MENUSZ 16
59 #define UMFILE ".menu"
60 #define INITFILE ".decoini"
61 #define ULDINITFILE "/usr/lib/deco/initfile"
62 #define ULLDINITFILE "/usr/local/share/deco/initfile"
63 #define ULDUMFILE "/usr/lib/deco/menu"
64 #define ULLDUMFILE "/usr/local/share/deco/menu"
65 #define ULDEXFILE "/usr/lib/deco/profile"
66 #define ULLDEXFILE "/usr/local/share/deco/profile"
67 
68 struct ex {
69 	char *pat;
70 	char *cmd;
71 };
72 
73 struct umenu {
74 	char key;
75 	char hist;
76 	char wait;
77 	char menu;
78 	char *str;
79 	char *cmd;
80 	char *cex;
81 };
82 
83 static struct umenu um [EXSZ];
84 static nm, menuwid, menucol, menurow;
85 static struct ex ex [EXSZ];
86 static nex = -1;
87 static char *bufp;
88 
skip()89 static void skip ()
90 {
91 	while (*bufp==' ' || *bufp=='\t')
92 		++bufp;
93 }
94 
skipln()95 static void skipln ()
96 {
97 	do {
98 		while (bufp && *bufp != '\n')
99 			++bufp;
100 		if (! bufp)
101 			return;
102 		++bufp;
103 	} while (*bufp == '#');
104 }
105 
getex()106 static char *getex ()
107 {
108 	char pat [PATSZ];
109 	char *p;
110 
111 	while (*bufp==' ' || *bufp=='\t' || *bufp=='\n')
112 		skipln ();
113 	if (! *bufp)
114 		return (0);
115 	for (p=pat; *bufp!=' ' && *bufp!='\t' && *bufp!='\n'; ++p, ++bufp) {
116 		if (! *bufp)
117 			break;
118 		if (p >= pat+PATSZ-1) {
119 			while (bufp && *bufp!=' ' && *bufp!='\t' && *bufp!='\n')
120 				++bufp;
121 			break;
122 		}
123 		*p = *bufp;
124 	}
125 	skip ();
126 	if (*bufp == '\n')
127 		skipln ();
128 	*p = 0;
129 	p = malloc (p - pat + 1);
130 	strcpy (p, pat);
131 	return (p);
132 }
133 
getkey()134 static int getkey ()
135 {
136 	int key;
137 
138 	while (*bufp==' ' || *bufp=='\t' || *bufp=='\n')
139 		skipln ();
140 	if (! *bufp)
141 		return (0);
142 	if (*bufp == 'F' && bufp[1] >= '1' && bufp[1] <= '9')
143 		key = bufp [1] - '0';
144 	else if ((*bufp >= 'a' && *bufp <= 'z') ||
145 	    (*bufp >= 'A' && *bufp <= 'Z') ||
146 	    (*bufp >= '0' && *bufp <= '9'))
147 		key = *bufp;
148 	else
149 		key = '?';
150 	while (bufp && *bufp!=' ' && *bufp!='\t' && *bufp!='\n')
151 		++bufp;
152 	skip ();
153 	return (key);
154 }
155 
getstr()156 static char *getstr ()
157 {
158 	char cmd [STRSZ];
159 	char *p;
160 
161 	if (! *bufp)
162 		return (0);
163 	for (p=cmd; *bufp!='\n'; ++p, ++bufp) {
164 		if (! *bufp)
165 			break;
166 		if (p >= cmd+STRSZ-1) {
167 			skipln ();
168 			break;
169 		}
170 		*p = *bufp;
171 	}
172 	if (*bufp == '\n')
173 		skipln ();
174 	*p = 0;
175 	p = malloc (p - cmd + 1);
176 	strcpy (p, cmd);
177 	return (p);
178 }
179 
getcmd()180 static char *getcmd ()
181 {
182 	if (*bufp!=' ' && *bufp!='\t')
183 		return (0);
184 	skip ();
185 	return (getstr ());
186 }
187 
readex()188 static void readex ()
189 {
190 	register char *cp, *ep;
191 
192 	for (nex=0; (ep=getex()); ++nex) {
193 		if (nex >= EXSZ-1)
194 			break;
195 		ex[nex].pat = ep;
196 		if ((cp = getcmd ()))
197 			ex[nex].cmd = cp;
198 	}
199 	while (nex>0 && ! ex[nex-1].cmd) {
200 		--nex;
201 		free (ex[nex].pat);
202 	}
203 	ex[nex].pat = 0;
204 }
205 
initex()206 static void initex ()
207 {
208 	register fd, n;
209 	char fname [80];
210 	char buf [BUFSZ];
211 
212 	/* look for ~/.deco */
213 	strcpy (fname, home);
214 	strcat (fname, "/");
215 	strcat (fname, EXFILE);
216 	fd = open (fname, 0);
217 	if (fd < 0) {
218 		/* look for /usr/local/lib/deco/profile */
219 		fd = open (ULLDEXFILE, 0);
220 		if (fd < 0) {
221 			/* look for /usr/lib/deco/profile */
222 			fd = open (ULDEXFILE, 0);
223 			if (fd < 0)
224 				return;
225 		}
226 	}
227 	bufp = buf;
228 	n = read (fd, buf, sizeof (buf) - 1);
229 	close (fd);
230 	if (n <= 0)
231 		return;
232 	buf [n] = 0;
233 	bufp = buf;
234 	if (*bufp == '#')
235 		skipln ();
236 
237 	readex ();
238 
239 	for (n=nex-2; n>=0; --n)
240 		if (! ex[n].cmd)
241 			ex[n].cmd = ex[n+1].cmd;
242 }
243 
expandtagged(char * cp)244 int expandtagged (char *cp)
245 {
246 	register i, n;
247 	register char *s;
248 
249 	for (i=n=0; i<cur->num; ++i)
250 		if (cur->cat[i].tag) {
251 			s = cur->cat[i].name;
252 			while (*s)
253 				*cp++ = *s++;
254 			*cp++ = ' ';
255 			++n;
256 		}
257 	*cp = 0;
258 	return (n);
259 }
260 
expand(char * cp,char * cmd,char * fname)261 static void expand (char *cp, char *cmd, char *fname)
262 {
263 	register char *s;
264 
265 	for (; *cmd; ++cmd) {
266 		if (*cmd != '%') {
267 			*cp++ = *cmd;
268 			continue;
269 		}
270 		switch (*++cmd) {
271 		default:
272 			*cp++ = *cmd;
273 			continue;
274 		case 't':               /* list of tagged files */
275 			if (expandtagged (cp)) {
276 				for (; *cp; ++cp);
277 				continue;
278 			}
279 		case 'f':               /* current file name */
280 			s = fname;
281 			break;
282 		case 'b':               /* base name */
283 			s = basename (fname);
284 			break;
285 		case 'd':               /* directory name */
286 			s = basename (cur->cwd);
287 			break;
288 		case 'c':               /* full directory name */
289 			s = cur->cwd;
290 			break;
291 		case 'h':               /* full home directory name */
292 			s = home;
293 			break;
294 		case 'u':               /* user name */
295 			s = user;
296 			break;
297 		case 'g':               /* group name */
298 			s = group;
299 			break;
300 		}
301 		if (! s)
302 			continue;
303 		while (*s)
304 			*cp++ = *s++;
305 	}
306 	*cp = 0;
307 }
308 
excommand(char * cp,char * fname)309 void excommand (char *cp, char *fname)
310 {
311 	register struct ex *ep;
312 
313 	if (nex == -1)
314 		initex ();
315 	for (ep=ex; ep->pat; ++ep) {
316 		if (match (fname, ep->pat)) {
317 			expand (cp, ep->cmd, fname);
318 			return;
319 		}
320 	}
321 	*cp = 0;
322 }
323 
freeudm()324 static void freeudm ()
325 {
326 	register n;
327 
328 	for (n=0; n<nm; ++n) {
329 		if (um[n].str)
330 			free (um[n].str);
331 		if (um[n].cmd)
332 			free (um[n].cmd);
333 	}
334 }
335 
printudm()336 static void printudm ()
337 {
338 	register n;
339 
340 	for (n=0; n<nm; ++n) {
341 		VMove (menurow+n, menucol+1);
342 		switch (um[n].key) {
343 		case 1:         VPutString ("F1");      break;
344 		case 2:         VPutString ("F2");      break;
345 		case 3:         VPutString ("F3");      break;
346 		case 4:         VPutString ("F4");      break;
347 		case 5:         VPutString ("F5");      break;
348 		case 6:         VPutString ("F6");      break;
349 		case 7:         VPutString ("F7");      break;
350 		case 8:         VPutString ("F8");      break;
351 		case 9:         VPutString ("F9");      break;
352 		default:        VPutChar (um[n].key);   break;
353 		}
354 		if (um[n].menu)
355 			VMPutString (menurow+n, menucol+3, "->");
356 		if (um[n].str)
357 			VMPutString (menurow+n, menucol+5, um[n].str);
358 	}
359 }
360 
openmenu(char * filename)361 static int openmenu (char *filename)
362 {
363 	register fd;
364 	char fname [80];
365 
366 	if (filename)
367 		return (open (filename, 0));
368 	/* look for ./.menu */
369 	fd = open (UMFILE, 0);
370 	if (fd < 0) {
371 		/* look for ~/.menu */
372 		strcpy (fname, home);
373 		strcat (fname, "/");
374 		strcat (fname, UMFILE);
375 		fd = open (fname, 0);
376 		if (fd < 0) {
377 			/* look for /usr/local/lib/deco/menu */
378 			fd = open (ULLDUMFILE, 0);
379 			if (fd < 0)
380 				/* look for /usr/lib/deco/menu */
381 				fd = open (ULDUMFILE, 0);
382 		}
383 	}
384 	return (fd);
385 }
386 
initudm(char * filename,char * scale)387 static int initudm (char *filename, char *scale)
388 {
389 	register n;
390 	register char *p;
391 	int fd;
392 	char buf [BUFSZ];
393 
394 	fd = openmenu (filename);
395 	if (fd < 0) {
396 		error ("Menu not found");
397 		return (0);
398 	}
399 	nm = 0;
400 	bufp = buf;
401 	n = read (fd, buf, sizeof (buf) - 1);
402 	close (fd);
403 	if (n <= 0) {
404 		error ("Cannot read menu");
405 		return (0);
406 	}
407 	buf [n] = 0;
408 	bufp = buf;
409 	if (*bufp == '#')
410 		skipln ();
411 
412 	for (n=0; n<128; ++n)
413 		scale [n] = MENUSZ+1;
414 
415 	menuwid = 1;
416 	for (nm=0; nm<MENUSZ && (n = getkey ()); ++nm) {
417 		scale [n] = nm;
418 		um[nm].key = n;
419 		um[nm].wait = um[nm].hist = 1;
420 		um[nm].menu = 0;
421 		um[nm].str = getstr ();
422 		if (um[nm].str && (n = strlen (um[nm].str)) > menuwid)
423 			menuwid = n;
424 		um[nm].cmd = getcmd ();
425 		if (um[nm].cmd) {
426 			p = um[nm].cmd;
427 			/* if ((n = strlen (um[nm].cmd)) > menuwid) */
428 				/* menuwid = n; */
429 			if (*p == '!') {
430 				um[nm].menu = 1;
431 				++p;
432 			}
433 			if (*p == '-') {
434 				um[nm].wait = 0;
435 				++p;
436 			}
437 			if (*p == '@') {
438 				um[nm].hist = 0;
439 				++p;
440 			}
441 			um[nm].cex = p;
442 		}
443 	}
444 	if (! nm) {
445 		error ("Menu is empty");
446 		return (0);
447 	}
448 	menuwid += 6;
449 	if (menuwid > 70)
450 		menuwid = 70;
451 	menurow = (LINES-nm) / 2;
452 	menucol = (79-menuwid) / 2;
453 	return (1);
454 }
455 
runudm(char * scale)456 static char *runudm (char *scale)
457 {
458 	/* user defined menu */
459 	register key, cm;
460 	BOX *box, *curbox;
461 
462 	box = VGetBox (menurow-2, menucol-4, nm+4, menuwid+8);
463 	VSetDim ();
464 	VStandOut ();
465 	VFillBox (menurow-2, menucol-4, nm+4, menuwid+8, ' ');
466 	VDrawBox (menurow-1, menucol-1, nm+2, menuwid+2);
467 	mvcaddstr (menurow-1, 40, " User Menu ");
468 	printudm ();
469 	VSetNormal ();
470 	VStandEnd ();
471 	cm = 0;
472 	for (;;) {
473 		curbox = VGetBox (menurow+cm, menucol, 1, menuwid);
474 		VPrintBox (curbox);
475 		hidecursor ();
476 		VSync ();
477 		key = KeyGet ();
478 		VUngetBox (curbox);
479 		VFreeBox (curbox);
480 		switch (key) {
481 		default:
482 findmenu:
483 			if (key>0 && key<0200 && scale [key] < MENUSZ) {
484 				cm = scale [key];
485 				break;
486 			}
487 			VBeep ();
488 			continue;
489 		case meta ('A'):        key = 1;        goto findmenu;
490 		case meta ('B'):        key = 2;        goto findmenu;
491 		case meta ('C'):        key = 3;        goto findmenu;
492 		case meta ('D'):        key = 4;        goto findmenu;
493 		case meta ('E'):        key = 5;        goto findmenu;
494 		case meta ('F'):        key = 6;        goto findmenu;
495 		case meta ('G'):        key = 7;        goto findmenu;
496 		case meta ('H'):        key = 8;        goto findmenu;
497 		case meta ('I'):        key = 9;        goto findmenu;
498 		case cntrl (']'):          /* redraw screen */
499 			VRedraw ();
500 			continue;
501 		case cntrl ('M'):
502 		case cntrl ('J'):
503 			break;
504 		case cntrl ('C'):
505 		case cntrl ('['):
506 		case meta ('J'):           /* f0 */
507 			cm = -1;
508 			break;
509 		case meta ('u'):          /* up */
510 			if (--cm < 0)
511 				cm = nm-1;
512 			continue;
513 		case meta ('d'):          /* down */
514 			if (++cm >= nm)
515 				cm = 0;
516 			continue;
517 		}
518 		break;
519 	}
520 	VUngetBox (box);
521 	VFreeBox (box);
522 	if (cm >= 0 && um[cm].cex) {
523 		if (um[cm].menu)
524 			return (um[cm].cex);
525 		/* execute command from menu */
526 		expand (command, um[cm].cex, cur->cat[cur->curfile].name);
527 		cpos = strlen (command);
528 		if (command [0])
529 			execmd (um[cm].wait, um[cm].hist);
530 	}
531 	return ((char *) 0);
532 }
533 
usermenu()534 void usermenu ()                /* user defined menu */
535 {
536 	char scale [128], filename [80];
537 	register char *p;
538 
539 	p = 0;
540 	while (initudm (p, scale)) {
541 		p = runudm (scale);
542 		freeudm ();
543 		if (! p)
544 			break;
545 		expand (filename, p, cur->cat[cur->curfile].name);
546 		p = filename;
547 	}
548 }
549 
getlin()550 static char *getlin ()
551 {
552 	register char *p, *s;
553 
554 	if (! *bufp)
555 		return (0);
556 	for (s=p=bufp; *p && *p != '\n'; ++p);
557 	if (*p == '\n')
558 		*p++ = 0;
559 	bufp = p;
560 	return (s);
561 }
562 
readinitfile()563 void readinitfile ()
564 {
565 	register fd, n;
566 	register char *line;
567 	struct dir *d;
568 	char fname [80];
569 	char buf [BUFSZ];
570 
571 	/* look for ~/.decoini */
572 	strcpy (fname, home);
573 	strcat (fname, "/");
574 	strcat (fname, INITFILE);
575 	fd = open (fname, 0);
576 	if (fd < 0) {
577 		/* look for /usr/local/lib/deco/initfile */
578 		fd = open (ULLDINITFILE, 0);
579 		if (fd < 0) {
580 			/* look for /usr/lib/deco/initfile */
581 			fd = open (ULDINITFILE, 0);
582 			if (fd < 0)
583 				return;
584 		}
585 	}
586 	bufp = buf;
587 	n = read (fd, buf, sizeof (buf) - 1);
588 	close (fd);
589 	if (n <= 0)
590 		return;
591 	buf [n] = 0;
592 	bufp = buf;
593 
594 	while ((line = getlin ())) {
595 		switch (line [0]) {
596 		case 'r':       /* right panel */
597 			d = &right;
598 			goto initdir;
599 		case 'l':       /* left panel */
600 			d = &left;
601 initdir:
602 			switch (line [1]) {
603 			case 'o':       /* Sort */
604 				switch (line [2]) {
605 				case 'n':       d->sort = SORTNAME;     break;
606 				case 'x':       d->sort = SORTEXT;      break;
607 				case 't':       d->sort = SORTTIME;     break;
608 				case 'z':       d->sort = SORTSIZE;     break;
609 				case 'u':       d->sort = SORTSKIP;     break;
610 				}
611 				break;
612 			case 'l':       /* Long */
613 				d->view = VIEW_LONG;
614 				break;
615 			case 'w':       /* Wide */
616 				d->view = VIEW_WIDE;
617 				break;
618 			case 'f':       /* Full */
619 				d->view = VIEW_FULL;
620 				break;
621 			case 'i':       /* Info */
622 				d->view = VIEW_INFO;
623 				break;
624 			case 's':       /* Status */
625 				d->status = 1;
626 				break;
627 			case 'p':       /* pattern */
628 				strcpy (d->pattern, line+2);
629 				break;
630 			case 'a':       /* not align extensions */
631 				d->alignext = 0;
632 				break;
633 			case 't':       /* no type sorting */
634 				d->typesort = 0;
635 				break;
636 			case 'r':       /* reverse sorting */
637 				d->revsort = 1;
638 				break;
639 			}
640 			break;
641 		case 'c':       /* use cshell */
642 			usecshell = 1;
643 			break;
644 		case 'f':       /* full screen */
645 			H = LINES-7;
646 			break;
647 		case 'w':       /* double width */
648 			widewin = 1;
649 			break;
650 		case 'h':       /* show hidden files */
651 			showhidden ^= 1;
652 			break;
653 		case 'v':       /* viewer */
654 			switch (line [1]) {
655 			case 'b':       /* built-in */
656 				userview = 1;
657 				break;
658 			case 'n':       /* name */
659 				strcpy (viewname, line+2);
660 				break;
661 			}
662 			break;
663 		case 'e':       /* editor */
664 			switch (line [1]) {
665 			case 'b':       /* built-in */
666 				useredit = 1;
667 				break;
668 			case 'n':       /* name */
669 				strcpy (editname, line+2);
670 				break;
671 			case 'r':       /* raw */
672 				viewraw = 1;
673 				break;
674 			case 'h':       /* hex */
675 				viewhex = 1;
676 				break;
677 			case 't':       /* tabs */
678 				viewtabs = 1;
679 				break;
680 			}
681 			break;
682 		case 'p':       /* palette */
683 			switch (line [1]) {
684 			case 'n':       /* normal */
685 				switch (line [2]) {
686 				case 'f':       /* foreground */
687 					palette.fg = strtol (line+3, 0, 0);
688 					dflt_palette.fg = -1;
689 					break;
690 				case 'b':       /* background */
691 					palette.bg = strtol (line+3, 0, 0);
692 					dflt_palette.bg = -1;
693 					break;
694 				case 'r':       /* reverse */
695 					switch (line [3]) {
696 					case 'f':       /* foreground */
697 						palette.revfg = strtol (line+4, 0, 0);
698 						dflt_palette.revfg = -1;
699 						break;
700 					case 'b':       /* background */
701 						palette.revbg = strtol (line+4, 0, 0);
702 						dflt_palette.revbg = -1;
703 						break;
704 					}
705 					break;
706 				}
707 				break;
708 			case 'b':       /* bold */
709 				switch (line [2]) {
710 				case 'f':       /* foreground */
711 					palette.boldfg = strtol (line+3, 0, 0);
712 					dflt_palette.boldfg = -1;
713 					break;
714 				case 'b':       /* background */
715 					palette.boldbg = strtol (line+3, 0, 0);
716 					dflt_palette.boldbg = -1;
717 					break;
718 				case 'r':       /* reverse */
719 					switch (line [3]) {
720 					case 'f':       /* foreground */
721 						palette.boldrevfg = strtol (line+4, 0, 0);
722 						dflt_palette.boldrevfg = -1;
723 						break;
724 					case 'b':       /* background */
725 						palette.boldrevbg = strtol (line+4, 0, 0);
726 						dflt_palette.boldrevbg = -1;
727 						break;
728 					}
729 					break;
730 				}
731 				break;
732 			case 'd':       /* dim */
733 				switch (line [2]) {
734 				case 'f':       /* foreground */
735 					palette.dimfg = strtol (line+3, 0, 0);
736 					dflt_palette.dimfg = -1;
737 					break;
738 				case 'b':       /* background */
739 					palette.dimbg = strtol (line+3, 0, 0);
740 					dflt_palette.dimbg = -1;
741 					break;
742 				case 'r':       /* reverse */
743 					switch (line [3]) {
744 					case 'f':       /* foreground */
745 						palette.dimrevfg = strtol (line+4, 0, 0);
746 						dflt_palette.dimrevfg = -1;
747 						break;
748 					case 'b':       /* background */
749 						palette.dimrevbg = strtol (line+4, 0, 0);
750 						dflt_palette.dimrevbg = -1;
751 						break;
752 					}
753 					break;
754 				}
755 				break;
756 			}
757 			break;
758 		}
759 	}
760 }
761 
writeinitfile()762 void writeinitfile ()
763 {
764 	register fd;
765 	char fname [80];
766 	char buf [BUFSZ];
767 
768 	/* look for ~/.decoini */
769 	strcpy (fname, home);
770 	strcat (fname, "/");
771 	strcat (fname, INITFILE);
772 	fd = creat (fname, 0600);
773 	if (fd < 0) {
774 		error ("Cannot create %s", fname);
775 		return;
776 	}
777 	bufp = buf;
778 
779 	if (left.view == VIEW_LONG)
780 		*bufp++ = 'l', *bufp++ = 'l', *bufp++ = '\n';
781 	else if (left.view == VIEW_WIDE)
782 		*bufp++ = 'l', *bufp++ = 'w', *bufp++ = '\n';
783 	else if (left.view == VIEW_FULL)
784 		*bufp++ = 'l', *bufp++ = 'f', *bufp++ = '\n';
785 	else if (left.view == VIEW_INFO)
786 		*bufp++ = 'l', *bufp++ = 'i', *bufp++ = '\n';
787 	if (right.view == VIEW_LONG)
788 		*bufp++ = 'r', *bufp++ = 'l', *bufp++ = '\n';
789 	else if (right.view == VIEW_WIDE)
790 		*bufp++ = 'r', *bufp++ = 'w', *bufp++ = '\n';
791 	else if (right.view == VIEW_FULL)
792 		*bufp++ = 'r', *bufp++ = 'f', *bufp++ = '\n';
793 	else if (right.view == VIEW_INFO)
794 		*bufp++ = 'r', *bufp++ = 'i', *bufp++ = '\n';
795 	if (left.status)
796 		*bufp++ = 'l', *bufp++ = 's', *bufp++ = '\n';
797 	if (right.status)
798 		*bufp++ = 'r', *bufp++ = 's', *bufp++ = '\n';
799 	switch (left.sort) {
800 	case SORTEXT:    break;
801 	case SORTNAME:  *bufp++ = 'l';  *bufp++ = 'o';  *bufp++ = 'n';  *bufp++ = '\n'; break;
802 	case SORTTIME:  *bufp++ = 'l';  *bufp++ = 'o';  *bufp++ = 't';  *bufp++ = '\n'; break;
803 	case SORTSIZE:  *bufp++ = 'l';  *bufp++ = 'o';  *bufp++ = 'z';  *bufp++ = '\n'; break;
804 	default:        *bufp++ = 'l';  *bufp++ = 'o';  *bufp++ = 'u';  *bufp++ = '\n'; break;
805 	}
806 	switch (right.sort) {
807 	case SORTEXT:    break;
808 	case SORTNAME:  *bufp++ = 'r';  *bufp++ = 'o';  *bufp++ = 'n';  *bufp++ = '\n'; break;
809 	case SORTTIME:  *bufp++ = 'r';  *bufp++ = 'o';  *bufp++ = 't';  *bufp++ = '\n'; break;
810 	case SORTSIZE:  *bufp++ = 'r';  *bufp++ = 'o';  *bufp++ = 'z';  *bufp++ = '\n'; break;
811 	default:        *bufp++ = 'r';  *bufp++ = 'o';  *bufp++ = 'u';  *bufp++ = '\n'; break;
812 	}
813 	if (left.pattern [0]) {
814 		*bufp++ = 'l';
815 		*bufp++ = 'p';
816 		strcpy (bufp, left.pattern);
817 		while (*bufp++);
818 		bufp [-1] = '\n';
819 	}
820 	if (right.pattern [0]) {
821 		*bufp++ = 'r';
822 		*bufp++ = 'p';
823 		strcpy (bufp, right.pattern);
824 		while (*bufp++);
825 		bufp [-1] = '\n';
826 	}
827 	if (usecshell)
828 		*bufp++ = 'c', *bufp++ = '\n';
829 	if (H == LINES-7)
830 		*bufp++ = 'f', *bufp++ = '\n';
831 	if (widewin)
832 		*bufp++ = 'w', *bufp++ = '\n';
833 	if (! showhidden)
834 		*bufp++ = 'h', *bufp++ = '\n';
835 	if (viewraw)
836 		*bufp++ = 'e', *bufp++ = 'r', *bufp++ = '\n';
837 	if (viewhex)
838 		*bufp++ = 'e', *bufp++ = 'h', *bufp++ = '\n';
839 	if (viewtabs)
840 		*bufp++ = 'e', *bufp++ = 't', *bufp++ = '\n';
841 	if (userview)
842 		*bufp++ = 'v', *bufp++ = 'b', *bufp++ = '\n';
843 	if (useredit)
844 		*bufp++ = 'e', *bufp++ = 'b', *bufp++ = '\n';
845 	if (! left.alignext)
846 		*bufp++ = 'l', *bufp++ = 'a', *bufp++ = '\n';
847 	if (! right.alignext)
848 		*bufp++ = 'r', *bufp++ = 'a', *bufp++ = '\n';
849 	if (! left.typesort)
850 		*bufp++ = 'l', *bufp++ = 't', *bufp++ = '\n';
851 	if (! right.typesort)
852 		*bufp++ = 'r', *bufp++ = 't', *bufp++ = '\n';
853 	if (left.revsort)
854 		*bufp++ = 'l', *bufp++ = 'r', *bufp++ = '\n';
855 	if (right.revsort)
856 		*bufp++ = 'r', *bufp++ = 'r', *bufp++ = '\n';
857 	if (viewname [0]) {
858 		*bufp++ = 'v';
859 		*bufp++ = 'n';
860 		strcpy (bufp, viewname);
861 		while (*bufp++);
862 		bufp [-1] = '\n';
863 	}
864 	if (editname [0]) {
865 		*bufp++ = 'e';
866 		*bufp++ = 'n';
867 		strcpy (bufp, editname);
868 		while (*bufp++);
869 		bufp [-1] = '\n';
870 	}
871 
872 	if (palette.fg != dflt_palette.fg) {
873 		*bufp++ = 'p';
874 		*bufp++ = 'n';
875 		*bufp++ = 'f';
876 		*bufp++ = '0' + palette.fg / 10;
877 		*bufp++ = '0' + palette.fg % 10;
878 		*bufp++ = '\n';
879 	}
880 	if (palette.bg != dflt_palette.bg) {
881 		*bufp++ = 'p';
882 		*bufp++ = 'n';
883 		*bufp++ = 'b';
884 		*bufp++ = '0' + palette.bg / 10;
885 		*bufp++ = '0' + palette.bg % 10;
886 		*bufp++ = '\n';
887 	}
888 	if (palette.revfg != dflt_palette.revfg) {
889 		*bufp++ = 'p';
890 		*bufp++ = 'n';
891 		*bufp++ = 'r';
892 		*bufp++ = 'f';
893 		*bufp++ = '0' + palette.revfg / 10;
894 		*bufp++ = '0' + palette.revfg % 10;
895 		*bufp++ = '\n';
896 	}
897 	if (palette.revbg != dflt_palette.revbg) {
898 		*bufp++ = 'p';
899 		*bufp++ = 'n';
900 		*bufp++ = 'r';
901 		*bufp++ = 'b';
902 		*bufp++ = '0' + palette.revbg / 10;
903 		*bufp++ = '0' + palette.revbg % 10;
904 		*bufp++ = '\n';
905 	}
906 
907 	if (palette.boldfg != dflt_palette.boldfg) {
908 		*bufp++ = 'p';
909 		*bufp++ = 'b';
910 		*bufp++ = 'f';
911 		*bufp++ = '0' + palette.boldfg / 10;
912 		*bufp++ = '0' + palette.boldfg % 10;
913 		*bufp++ = '\n';
914 	}
915 	if (palette.boldbg != dflt_palette.boldbg) {
916 		*bufp++ = 'p';
917 		*bufp++ = 'b';
918 		*bufp++ = 'b';
919 		*bufp++ = '0' + palette.boldbg / 10;
920 		*bufp++ = '0' + palette.boldbg % 10;
921 		*bufp++ = '\n';
922 	}
923 	if (palette.boldrevfg != dflt_palette.boldrevfg) {
924 		*bufp++ = 'p';
925 		*bufp++ = 'b';
926 		*bufp++ = 'r';
927 		*bufp++ = 'f';
928 		*bufp++ = '0' + palette.boldrevfg / 10;
929 		*bufp++ = '0' + palette.boldrevfg % 10;
930 		*bufp++ = '\n';
931 	}
932 	if (palette.boldrevbg != dflt_palette.boldrevbg) {
933 		*bufp++ = 'p';
934 		*bufp++ = 'b';
935 		*bufp++ = 'r';
936 		*bufp++ = 'b';
937 		*bufp++ = '0' + palette.boldrevbg / 10;
938 		*bufp++ = '0' + palette.boldrevbg % 10;
939 		*bufp++ = '\n';
940 	}
941 
942 	if (palette.dimfg != dflt_palette.dimfg) {
943 		*bufp++ = 'p';
944 		*bufp++ = 'd';
945 		*bufp++ = 'f';
946 		*bufp++ = '0' + palette.dimfg / 10;
947 		*bufp++ = '0' + palette.dimfg % 10;
948 		*bufp++ = '\n';
949 	}
950 	if (palette.dimbg != dflt_palette.dimbg) {
951 		*bufp++ = 'p';
952 		*bufp++ = 'd';
953 		*bufp++ = 'b';
954 		*bufp++ = '0' + palette.dimbg / 10;
955 		*bufp++ = '0' + palette.dimbg % 10;
956 		*bufp++ = '\n';
957 	}
958 	if (palette.dimrevfg != dflt_palette.dimrevfg) {
959 		*bufp++ = 'p';
960 		*bufp++ = 'd';
961 		*bufp++ = 'r';
962 		*bufp++ = 'f';
963 		*bufp++ = '0' + palette.dimrevfg / 10;
964 		*bufp++ = '0' + palette.dimrevfg % 10;
965 		*bufp++ = '\n';
966 	}
967 	if (palette.dimrevbg != dflt_palette.dimrevbg) {
968 		*bufp++ = 'p';
969 		*bufp++ = 'd';
970 		*bufp++ = 'r';
971 		*bufp++ = 'b';
972 		*bufp++ = '0' + palette.dimrevbg / 10;
973 		*bufp++ = '0' + palette.dimrevbg % 10;
974 		*bufp++ = '\n';
975 	}
976 
977 	message (" Setup ", "Saving setup in %s ...", fname);
978 	write (fd, buf, (unsigned) (bufp - buf));
979 	close (fd);
980 	endmesg ();
981 }
982