Merge branch 'master' into lua-scripting
[screen-lua.git] / src / help.c
blob4dc2d31cf6b89378ef9fc8677d120854470a5809
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
26 #include "config.h"
28 #include "screen.h"
29 #include "extern.h"
31 char version[40]; /* initialised by main() */
33 extern struct layer *flayer;
34 extern struct display *display, *displays;
35 extern struct win *windows;
36 extern char *noargs[];
37 extern struct mchar mchar_blank, mchar_so;
38 extern unsigned char *blank;
39 extern struct win *wtab[];
40 #ifdef MAPKEYS
41 extern struct term term[];
42 #endif
44 static void PadStr __P((char *, int, int, int));
46 extern char *wliststr;
47 extern char *wlisttit;
49 void
50 exit_with_usage(myname, message, arg)
51 char *myname, *message, *arg;
53 printf("Use: %s [-opts] [cmd [args]]\n", myname);
54 printf(" or: %s -r [host.tty]\n\nOptions:\n", myname);
55 printf("-a Force all capabilities into each window's termcap.\n");
56 printf("-A -[r|R] Adapt all windows to the new display width & height.\n");
57 printf("-c file Read configuration file instead of '.screenrc'.\n");
58 #ifdef REMOTE_DETACH
59 printf("-d (-r) Detach the elsewhere running screen (and reattach here).\n");
60 printf("-dmS name Start as daemon: Screen session in detached mode.\n");
61 printf("-D (-r) Detach and logout remote (and reattach here).\n");
62 printf("-D -RR Do whatever is needed to get a screen session.\n");
63 #endif
64 printf("-e xy Change command characters.\n");
65 printf("-f Flow control on, -fn = off, -fa = auto.\n");
66 printf("-h lines Set the size of the scrollback history buffer.\n");
67 printf("-i Interrupt output sooner when flow control is on.\n");
68 #if defined(LOGOUTOK) && defined(UTMPOK)
69 printf("-l Login mode on (update %s), -ln = off.\n", UTMPFILE);
70 #endif
71 printf("-list or -ls. Do nothing, just list our SockDir.\n");
72 printf("-L Turn on output logging.\n");
73 printf("-m ignore $STY variable, do create a new screen session.\n");
74 printf("-O Choose optimal output rather than exact vt100 emulation.\n");
75 printf("-p window Preselect the named window if it exists.\n");
76 printf("-q Quiet startup. Exits with non-zero return code if unsuccessful.\n");
77 printf("-r Reattach to a detached screen process.\n");
78 printf("-R Reattach if possible, otherwise start a new session.\n");
79 printf("-s shell Shell to execute rather than $SHELL.\n");
80 printf("-S sockname Name this session <pid>.sockname instead of <pid>.<tty>.<host>.\n");
81 printf("-t title Set title. (window's name).\n");
82 printf("-T term Use term as $TERM for windows, rather than \"screen\".\n");
83 #ifdef UTF8
84 printf("-U Tell screen to use UTF-8 encoding.\n");
85 #endif
86 printf("-v Print \"Screen version %s\".\n", version);
87 printf("-wipe Do nothing, just clean up SockDir.\n");
88 #ifdef MULTI
89 printf("-x Attach to a not detached screen. (Multi display mode).\n");
90 #endif /* MULTI */
91 printf("-X Execute <cmd> as a screen command in the specified session.\n");
92 if (message && *message)
94 printf("\nError: ");
95 printf(message, arg);
96 printf("\n");
98 exit(1);
102 ** Here come the help page routines
105 extern struct comm comms[];
106 extern struct action ktab[];
108 static void HelpProcess __P((char **, int *));
109 static void HelpAbort __P((void));
110 static void HelpRedisplayLine __P((int, int, int, int));
111 static void add_key_to_buf __P((char *, int));
112 static void AddAction __P((struct action *, int, int));
113 static int helppage __P((void));
115 struct helpdata
117 char *class;
118 struct action *ktabp;
119 int maxrow, grow, numcols, numrows, num_names;
120 int numskip, numpages;
121 int command_search, command_bindings;
122 int refgrow, refcommand_search;
123 int inter, mcom, mkey;
124 int nact[RC_LAST + 1];
127 #define MAXKLEN 256
129 static struct LayFuncs HelpLf =
131 HelpProcess,
132 HelpAbort,
133 HelpRedisplayLine,
134 DefClearLine,
135 DefRewrite,
136 DefResize,
137 DefRestore
141 void
142 display_help(class, ktabp)
143 char *class;
144 struct action *ktabp;
146 int i, n, key, mcom, mkey, l;
147 struct helpdata *helpdata;
148 int used[RC_LAST + 1];
150 if (flayer->l_height < 6)
152 LMsg(0, "Window height too small for help page");
153 return;
155 if (InitOverlayPage(sizeof(*helpdata), &HelpLf, 0))
156 return;
158 helpdata = (struct helpdata *)flayer->l_data;
159 helpdata->class = class;
160 helpdata->ktabp = ktabp;
161 helpdata->num_names = helpdata->command_bindings = 0;
162 helpdata->command_search = 0;
163 for (n = 0; n <= RC_LAST; n++)
164 used[n] = 0;
165 mcom = 0;
166 mkey = 0;
167 for (key = 0; key < 256 + KMAP_KEYS; key++)
169 n = ktabp[key].nr;
170 if (n == RC_ILLEGAL)
171 continue;
172 if (ktabp[key].args == noargs)
174 used[n] += (key <= ' ' || key == 0x7f) ? 3 :
175 (key > 0x7f) ? 5 : 2;
177 else
178 helpdata->command_bindings++;
180 for (n = i = 0; n <= RC_LAST; n++)
181 if (used[n])
183 l = strlen(comms[n].name);
184 if (l > mcom)
185 mcom = l;
186 if (used[n] > mkey)
187 mkey = used[n];
188 helpdata->nact[i++] = n;
190 debug1("help: %d commands bound to keys with no arguments\n", i);
191 debug2("mcom: %d mkey: %d\n", mcom, mkey);
192 helpdata->num_names = i;
194 if (mkey > MAXKLEN)
195 mkey = MAXKLEN;
196 helpdata->numcols = flayer->l_width / (mcom + mkey + 1);
197 if (helpdata->numcols == 0)
199 HelpAbort();
200 LMsg(0, "Width too small");
201 return;
203 helpdata->inter = (flayer->l_width - (mcom + mkey) * helpdata->numcols) / (helpdata->numcols + 1);
204 if (helpdata->inter <= 0)
205 helpdata->inter = 1;
206 debug1("inter: %d\n", helpdata->inter);
207 helpdata->mcom = mcom;
208 helpdata->mkey = mkey;
209 helpdata->numrows = (helpdata->num_names + helpdata->numcols - 1) / helpdata->numcols;
210 debug1("Numrows: %d\n", helpdata->numrows);
211 helpdata->numskip = flayer->l_height-5 - (2 + helpdata->numrows);
212 while (helpdata->numskip < 0)
213 helpdata->numskip += flayer->l_height-5;
214 helpdata->numskip %= flayer->l_height-5;
215 debug1("Numskip: %d\n", helpdata->numskip);
216 if (helpdata->numskip > flayer->l_height/3 || helpdata->numskip > helpdata->command_bindings)
217 helpdata->numskip = 1;
218 helpdata->maxrow = 2 + helpdata->numrows + helpdata->numskip + helpdata->command_bindings;
219 helpdata->grow = 0;
221 helpdata->numpages = (helpdata->maxrow + flayer->l_height-6) / (flayer->l_height-5);
222 flayer->l_x = 0;
223 flayer->l_y = flayer->l_height - 1;
224 helppage();
227 static void
228 HelpProcess(ppbuf, plen)
229 char **ppbuf;
230 int *plen;
232 int done = 0;
234 while (!done && *plen > 0)
236 switch (**ppbuf)
238 case ' ':
239 if (helppage() == 0)
240 break;
241 /* FALLTHROUGH */
242 case '\r':
243 case '\n':
244 done = 1;
245 break;
246 default:
247 break;
249 ++*ppbuf;
250 --*plen;
252 if (done)
253 HelpAbort();
256 static void
257 HelpAbort()
259 LAY_CALL_UP(LRefreshAll(flayer, 0));
260 ExitOverlayPage();
264 static int
265 helppage()
267 struct helpdata *helpdata;
268 int col, crow, n, key, x;
269 char buf[MAXKLEN], Esc_buf[5], cbuf[256];
270 struct action *ktabp;
272 helpdata = (struct helpdata *)flayer->l_data;
274 ktabp = helpdata->ktabp;
275 if (helpdata->grow >= helpdata->maxrow)
276 return -1;
277 helpdata->refgrow = helpdata->grow;
278 helpdata->refcommand_search = helpdata->command_search;
280 /* Clear the help screen */
281 LClearAll(flayer, 0);
283 sprintf(cbuf,"Screen key bindings, page %d of %d.", helpdata->grow / (flayer->l_height-5) + 1, helpdata->numpages);
284 centerline(cbuf, 0);
285 crow = 2;
287 *Esc_buf = '\0';
288 *buf = '\0';
289 /* XXX fix escape character */
290 if (flayer->l_cvlist && flayer->l_cvlist->c_display)
292 add_key_to_buf(buf, flayer->l_cvlist->c_display->d_user->u_MetaEsc);
293 add_key_to_buf(Esc_buf, flayer->l_cvlist->c_display->d_user->u_Esc);
295 else
297 strcpy(Esc_buf, "??");
298 strcpy(buf, "??");
301 for (; crow < flayer->l_height - 3; crow++)
303 if (helpdata->grow < 1)
305 if (ktabp == ktab)
306 sprintf(cbuf,"Command key: %s Literal %s: %s", Esc_buf, Esc_buf, buf);
307 else
308 sprintf(cbuf,"Command class: '%.80s'", helpdata->class);
309 centerline(cbuf, crow);
310 helpdata->grow++;
312 else if (helpdata->grow >= 2 && helpdata->grow-2 < helpdata->numrows)
314 x = 0;
315 for (col = 0; col < helpdata->numcols && (n = helpdata->numrows * col + (helpdata->grow-2)) < helpdata->num_names; col++)
317 x += helpdata->inter - !col;
318 n = helpdata->nact[n];
319 buf[0] = '\0';
320 for (key = 0; key < 256 + KMAP_KEYS; key++)
321 if (ktabp[key].nr == n && ktabp[key].args == noargs && strlen(buf) < sizeof(buf) - 7)
323 strcat(buf, " ");
324 add_key_to_buf(buf, key);
326 PadStr(comms[n].name, helpdata->mcom, x, crow);
327 x += helpdata->mcom;
328 PadStr(buf, helpdata->mkey, x, crow);
329 x += helpdata->mkey;
331 helpdata->grow++;
333 else if (helpdata->grow-2-helpdata->numrows >= helpdata->numskip
334 && helpdata->grow-2-helpdata->numrows-helpdata->numskip < helpdata->command_bindings)
336 while ((n = ktabp[helpdata->command_search].nr) == RC_ILLEGAL
337 || ktabp[helpdata->command_search].args == noargs)
339 if (++helpdata->command_search >= 256 + KMAP_KEYS)
340 return -1;
342 buf[0] = '\0';
343 add_key_to_buf(buf, helpdata->command_search);
344 PadStr(buf, 5, 0, crow);
345 AddAction(&ktabp[helpdata->command_search++], 5, crow);
346 helpdata->grow++;
348 else
349 helpdata->grow++;
351 sprintf(cbuf,"[Press Space %s Return to end.]",
352 helpdata->grow < helpdata->maxrow ? "for next page;" : "or");
353 centerline(cbuf, flayer->l_height - 2);
354 LaySetCursor();
355 return 0;
358 static void
359 AddAction(act, x, y)
360 struct action *act;
361 int x, y;
363 char buf[256];
364 int del, l;
365 char *bp, *cp, **pp;
366 int *lp, ll;
367 int fr;
368 struct mchar mchar_dol;
370 mchar_dol = mchar_blank;
371 mchar_dol.image = '$';
373 fr = flayer->l_width - 1 - x;
374 if (fr <= 0)
375 return;
376 l = strlen(comms[act->nr].name);
378 if (l + 1 > fr)
379 l = fr - 1;
380 PadStr(comms[act->nr].name, l, x, y);
381 x += l;
382 fr -= l + 1;
383 LPutChar(flayer, fr ? &mchar_blank : &mchar_dol, x++, y);
385 pp = act->args;
386 lp = act->argl;
387 while (pp && (cp = *pp) != NULL)
389 del = 0;
390 bp = buf;
391 ll = *lp++;
392 if (!ll || (index(cp, ' ') != NULL))
394 if (index(cp, '\'') != NULL)
395 *bp++ = del = '"';
396 else
397 *bp++ = del = '\'';
399 while (ll-- && bp < buf + 250)
400 bp += AddXChar(bp, *(unsigned char *)cp++);
401 if (del)
402 *bp++ = del;
403 *bp = 0;
404 if ((fr -= (bp - buf) + 1) < 0)
406 fr += bp - buf;
407 if (fr > 0)
408 PadStr(buf, fr, x, y);
409 if (fr == 0)
410 LPutChar(flayer, &mchar_dol, x, y);
411 return;
413 PadStr(buf, strlen(buf), x, y);
414 x += strlen(buf);
415 pp++;
416 if (*pp)
417 LPutChar(flayer, fr ? &mchar_blank : &mchar_dol, x++, y);
421 static void
422 add_key_to_buf(buf, key)
423 char *buf;
424 int key;
426 buf += strlen(buf);
427 if (key < 0)
428 strcpy(buf, "unset");
429 else if (key == ' ')
430 strcpy(buf, "sp");
431 #ifdef MAPKEYS
432 else if (key >= 256)
434 key = key - 256 + T_CAPS;
435 buf[0] = ':';
436 buf[1] = term[key].tcname[0];
437 buf[2] = term[key].tcname[1];
438 buf[3] = ':';
439 buf[4] = 0;
441 #endif
442 else
443 buf[AddXChar(buf, key)] = 0;
447 static void
448 HelpRedisplayLine(y, xs, xe, isblank)
449 int y, xs, xe, isblank;
451 if (y < 0)
453 struct helpdata *helpdata;
455 helpdata = (struct helpdata *)flayer->l_data;
456 helpdata->grow = helpdata->refgrow;
457 helpdata->command_search = helpdata->refcommand_search;
458 helppage();
459 return;
461 if (y != 0 && y != flayer->l_height - 1)
462 return;
463 if (!isblank)
464 LClearArea(flayer, xs, y, xe, y, 0, 0);
470 ** here is all the copyright stuff
474 static void CopyrightProcess __P((char **, int *));
475 static void CopyrightRedisplayLine __P((int, int, int, int));
476 static void CopyrightAbort __P((void));
477 static void copypage __P((void));
479 struct copydata
481 char *cps, *savedcps; /* position in the message */
482 char *refcps, *refsavedcps; /* backup for redisplaying */
485 static struct LayFuncs CopyrightLf =
487 CopyrightProcess,
488 CopyrightAbort,
489 CopyrightRedisplayLine,
490 DefClearLine,
491 DefRewrite,
492 DefResize,
493 DefRestore
496 static const char cpmsg[] = "\
498 Screen version %v\n\
500 Copyright (c) 1993-2002 Juergen Weigert, Michael Schroeder\n\
501 Copyright (c) 1987 Oliver Laumann\n\
503 This program is free software; you can redistribute it and/or \
504 modify it under the terms of the GNU General Public License as published \
505 by the Free Software Foundation; either version 2, or (at your option) \
506 any later version.\n\
508 This program is distributed in the hope that it will be useful, \
509 but WITHOUT ANY WARRANTY; without even the implied warranty of \
510 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
511 GNU General Public License for more details.\n\
513 You should have received a copy of the GNU General Public License \
514 along with this program (see the file COPYING); if not, write to the \
515 Free Software Foundation, Inc., \
516 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\
518 Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza to \
519 screen@uni-erlangen.de\n";
522 static void
523 CopyrightProcess(ppbuf, plen)
524 char **ppbuf;
525 int *plen;
527 int done = 0;
528 struct copydata *copydata;
530 copydata = (struct copydata *)flayer->l_data;
531 while (!done && *plen > 0)
533 switch (**ppbuf)
535 case ' ':
536 if (*copydata->cps)
538 copypage();
539 break;
541 /* FALLTHROUGH */
542 case '\r':
543 case '\n':
544 CopyrightAbort();
545 done = 1;
546 break;
547 default:
548 break;
550 ++*ppbuf;
551 --*plen;
555 static void
556 CopyrightAbort()
558 LAY_CALL_UP(LRefreshAll(flayer, 0));
559 ExitOverlayPage();
562 void
563 display_copyright()
565 struct copydata *copydata;
567 if (flayer->l_width < 10 || flayer->l_height < 5)
569 LMsg(0, "Window size too small for copyright page");
570 return;
572 if (InitOverlayPage(sizeof(*copydata), &CopyrightLf, 0))
573 return;
574 copydata = (struct copydata *)flayer->l_data;
575 copydata->cps = (char *)cpmsg;
576 copydata->savedcps = 0;
577 flayer->l_x = 0;
578 flayer->l_y = flayer->l_height - 1;
579 copypage();
582 static void
583 copypage()
585 register char *cps;
586 char *ws;
587 int x, y, l;
588 char cbuf[80];
589 struct copydata *copydata;
591 ASSERT(flayer);
592 copydata = (struct copydata *)flayer->l_data;
594 LClearAll(flayer, 0);
595 x = y = 0;
596 cps = copydata->cps;
597 copydata->refcps = cps;
598 copydata->refsavedcps = copydata->savedcps;
599 while (*cps && y < flayer->l_height - 3)
601 ws = cps;
602 while (*cps == ' ')
603 cps++;
604 if (strncmp(cps, "%v", 2) == 0)
606 copydata->savedcps = cps + 2;
607 cps = version;
608 continue;
610 while (*cps && *cps != ' ' && *cps != '\n')
611 cps++;
612 l = cps - ws;
613 cps = ws;
614 if (l > flayer->l_width - 1)
615 l = flayer->l_width - 1;
616 if (x && x + l >= flayer->l_width - 2)
618 x = 0;
619 y++;
620 continue;
622 if (x)
624 LPutChar(flayer, &mchar_blank, x, y);
625 x++;
627 if (l)
628 LPutStr(flayer, ws, l, &mchar_blank, x, y);
629 x += l;
630 cps += l;
631 if (*cps == 0 && copydata->savedcps)
633 cps = copydata->savedcps;
634 copydata->savedcps = 0;
636 if (*cps == '\n')
638 x = 0;
639 y++;
641 if (*cps == ' ' || *cps == '\n')
642 cps++;
644 while (*cps == '\n')
645 cps++;
646 sprintf(cbuf,"[Press Space %s Return to end.]",
647 *cps ? "for next page;" : "or");
648 centerline(cbuf, flayer->l_height - 2);
649 copydata->cps = cps;
650 LaySetCursor();
653 static void
654 CopyrightRedisplayLine(y, xs, xe, isblank)
655 int y, xs, xe, isblank;
657 ASSERT(flayer);
658 if (y < 0)
660 struct copydata *copydata;
662 copydata = (struct copydata *)flayer->l_data;
663 copydata->cps = copydata->refcps;
664 copydata->savedcps = copydata->refsavedcps;
665 copypage();
666 return;
668 if (y != 0 && y != flayer->l_height - 1)
669 return;
670 if (isblank)
671 return;
672 LClearArea(flayer, xs, y, xe, y, 0, 0);
679 ** here is all the displays stuff
683 #ifdef MULTI
685 static void DisplaysProcess __P((char **, int *));
686 static void DisplaysRedisplayLine __P((int, int, int, int));
687 static void displayspage __P((void));
689 struct displaysdata
691 int dummy_element_for_solaris;
694 static struct LayFuncs DisplaysLf =
696 DisplaysProcess,
697 HelpAbort,
698 DisplaysRedisplayLine,
699 DefClearLine,
700 DefRewrite,
701 DefResize,
702 DefRestore
705 static void
706 DisplaysProcess(ppbuf, plen)
707 char **ppbuf;
708 int *plen;
710 int done = 0;
712 ASSERT(flayer);
713 while (!done && *plen > 0)
715 switch (**ppbuf)
717 case ' ':
718 displayspage();
719 break;
720 case '\r':
721 case '\n':
722 HelpAbort();
723 done = 1;
724 break;
725 default:
726 break;
728 ++*ppbuf;
729 --*plen;
734 void
735 display_displays()
737 if (flayer->l_width < 10 || flayer->l_height < 5)
739 LMsg(0, "Window size too small for displays page");
740 return;
742 if (InitOverlayPage(sizeof(struct displaysdata), &DisplaysLf, 0))
743 return;
744 flayer->l_x = 0;
745 flayer->l_y = flayer->l_height - 1;
746 displayspage();
750 * layout of the displays page is as follows:
752 xterm 80x42 jnweiger@/dev/ttyp4 0(m11) &rWx
753 facit 80x24 nb mlschroe@/dev/ttyhf 11(tcsh) rwx
754 xterm 80x42 jnhollma@/dev/ttyp5 0(m11) &R.x
756 | | | | | | | | ¦___ window permissions
757 | | | | | | | | (R. is locked r-only,
758 | | | | | | | | W has wlock)
759 | | | | | | | |___ Window is shared
760 | | | | | | |___ Name/Title of window
761 | | | | | |___ Number of window
762 | | | | |___ Name of the display (the attached device)
763 | | | |___ Username who is logged in at the display
764 | | |___ Display is in nonblocking mode. Shows 'NB' if obuf is full.
765 | |___ Displays geometry as width x height.
766 |___ the terminal type known by screen for this display.
770 static void
771 displayspage()
773 int y, l;
774 char tbuf[80];
775 struct display *d;
776 struct win *w;
777 static char *blockstates[5] = {"nb", "NB", "Z<", "Z>", "BL"};
779 LClearAll(flayer, 0);
781 leftline("term-type size user interface window", 0);
782 leftline("---------- ------- ---------- ----------------- ----------", 1);
783 y = 2;
785 for (d = displays; d; d = d->d_next)
787 w = d->d_fore;
789 if (y >= flayer->l_height - 3)
790 break;
791 sprintf(tbuf, "%-10.10s%4dx%-4d%10.10s@%-16.16s%s",
792 d->d_termname, d->d_width, d->d_height, d->d_user->u_name,
793 d->d_usertty,
794 (d->d_blocked || d->d_nonblock >= 0) && d->d_blocked <= 4 ? blockstates[d->d_blocked] : " ");
796 if (w)
798 l = 10 - strlen(w->w_title);
799 if (l < 0)
800 l = 0;
801 sprintf(tbuf + strlen(tbuf), "%3d(%.10s)%*s%c%c%c%c",
802 w->w_number, w->w_title, l, "",
803 /* w->w_dlist->next */ 0 ? '&' : ' ',
805 * The rwx triple:
806 * -,r,R no read, read, read only due to foreign wlock
807 * -,.,w,W no write, write suppressed by foreign wlock,
808 * write, own wlock
809 * -,x no execute, execute
811 #ifdef MULTIUSER
812 (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
813 ((w->w_wlock == WLOCK_OFF || d->d_user == w->w_wlockuser) ?
814 'r' : 'R')),
815 (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
816 ((w->w_wlock == WLOCK_OFF) ? 'w' :
817 ((d->d_user == w->w_wlockuser) ? 'W' : 'v'))),
818 (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' : 'x')
819 #else
820 'r', 'w', 'x'
821 #endif
824 leftline(tbuf, y);
825 y++;
827 sprintf(tbuf,"[Press Space %s Return to end.]",
828 1 ? "to refresh;" : "or");
829 centerline(tbuf, flayer->l_height - 2);
830 LaySetCursor();
833 static void
834 DisplaysRedisplayLine(y, xs, xe, isblank)
835 int y, xs, xe, isblank;
837 ASSERT(flayer);
838 if (y < 0)
840 displayspage();
841 return;
843 if (y != 0 && y != flayer->l_height - 1)
844 return;
845 if (isblank)
846 return;
847 LClearArea(flayer, xs, y, xe, y, 0, 0);
848 /* To be filled in... */
851 #endif /* MULTI */
856 ** here is the windowlist
860 struct wlistdata;
862 static void WListProcess __P((char **, int *));
863 static void WListRedisplayLine __P((int, int, int, int));
864 static void wlistpage __P((void));
865 static void WListLine __P((int, int, int, int));
866 static void WListLines __P((int, int));
867 static void WListMove __P((int, int));
868 static void WListUpdate __P((struct win *));
869 static int WListNormalize __P((void));
870 static int WListResize __P((int, int));
871 static int WListNext __P((struct wlistdata *, int, int));
873 struct wlistdata {
874 int pos;
875 int ypos;
876 int npos;
877 int numwin;
878 int first;
879 int last;
880 int start;
881 int order;
882 struct win *group;
885 static struct LayFuncs WListLf =
887 WListProcess,
888 HelpAbort,
889 WListRedisplayLine,
890 DefClearLine,
891 DefRewrite,
892 WListResize,
893 DefRestore
896 #define WTAB_GROUP_MATCHES(i) (group == wtab[i]->w_group)
898 static int
899 WListResize(wi, he)
900 int wi, he;
902 struct wlistdata *wlistdata;
903 if (wi < 10 || he < 5)
904 return -1;
905 wlistdata = (struct wlistdata *)flayer->l_data;
906 flayer->l_width = wi;
907 flayer->l_height = he;
908 wlistdata->numwin = he - 3;
909 if (wlistdata->ypos >= wlistdata->numwin)
910 wlistdata->ypos = wlistdata->numwin - 1;
911 flayer->l_y = he - 1;
912 return 0;
915 static void
916 WListProcess(ppbuf, plen)
917 char **ppbuf;
918 int *plen;
920 int done = 0;
921 struct wlistdata *wlistdata;
922 struct display *olddisplay = display;
923 int h;
924 struct win *group;
926 ASSERT(flayer);
927 wlistdata = (struct wlistdata *)flayer->l_data;
928 group = wlistdata->group;
929 h = wlistdata->numwin;
930 while (!done && *plen > 0)
932 if ((unsigned char)**ppbuf >= '0' && (unsigned char)**ppbuf <= '9')
934 int n = (unsigned char)**ppbuf - '0';
935 int d = 0;
936 if (n < MAXWIN && wtab[n] && WTAB_GROUP_MATCHES(n))
938 int i;
939 for (d = -wlistdata->npos, i = WListNext(wlistdata, -1, 0); i != n; i = WListNext(wlistdata, i, 1), d++)
942 if (d)
943 WListMove(d, -1);
945 switch ((unsigned char)**ppbuf)
947 case 0220: /* up */
948 case 16: /* ^P like emacs */
949 case 'k':
950 WListMove(-1, -1);
951 break;
952 case 0216: /* down */
953 case 14: /* ^N like emacs */
954 case 'j':
955 WListMove(1, -1);
956 break;
957 case '\025':
958 WListMove(-(h / 2), wlistdata->ypos);
959 break;
960 case '\004':
961 WListMove(h / 2, wlistdata->ypos);
962 break;
963 case 0002:
964 case 'b':
965 WListMove(-h, -1);
966 break;
967 case 0006:
968 case 'f':
969 WListMove(h, -1);
970 break;
971 case 0201: /* home */
972 WListMove(-wlistdata->pos, -1);
973 break;
974 case 0205: /* end */
975 WListMove(MAXWIN, -1);
976 break;
977 case '\r':
978 case '\n':
979 case ' ':
980 done = 1;
981 h = wlistdata->pos;
982 if (!display || h == MAXWIN || !wtab[h] || wtab[h] == D_fore || (flayer->l_cvlist && flayer->l_cvlist->c_lnext))
983 HelpAbort();
984 #ifdef MULTIUSER
985 else if (AclCheckPermWin(D_user, ACL_READ, wtab[h]))
986 HelpAbort();
987 #endif
988 else
989 ExitOverlayPage(); /* no need to redisplay */
990 /* restore display, don't switch wrong user */
991 display = olddisplay;
992 if (h != MAXWIN)
993 SwitchWindow(h);
994 break;
995 case 0033:
996 case 0007:
997 h = wlistdata->start;
998 HelpAbort();
999 display = olddisplay;
1000 if (h >= 0 && wtab[h])
1001 SwitchWindow(h);
1002 else if (h == -2)
1004 struct win *p = FindNiceWindow(display ? D_other : (struct win *)0, 0);
1005 if (p)
1006 SwitchWindow(p->w_number);
1008 done = 1;
1009 break;
1010 default:
1011 break;
1013 ++*ppbuf;
1014 --*plen;
1018 static void
1019 WListLine(y, i, pos, isblank)
1020 int y, i;
1021 int pos;
1022 int isblank;
1024 char *str;
1025 int n;
1026 int yoff;
1027 struct wlistdata *wlistdata;
1029 if (i == MAXWIN)
1030 return;
1031 wlistdata = (struct wlistdata *)flayer->l_data;
1032 yoff = wlistdata->group ? 3 : 2;
1033 display = Layer2Window(flayer) ? 0 : flayer->l_cvlist ? flayer->l_cvlist->c_display : 0;
1034 str = MakeWinMsgEv(wliststr, wtab[i], '%', flayer->l_width, (struct event *)0, 0);
1035 n = strlen(str);
1036 if (i != pos && isblank)
1037 while (n && str[n - 1] == ' ')
1038 n--;
1039 LPutWinMsg(flayer, str, (i == pos || !isblank) ? flayer->l_width : n, i == pos ? &mchar_so : &mchar_blank, 0, y + yoff);
1040 #if 0
1041 LPutStr(flayer, str, n, i == pos ? &mchar_so : &mchar_blank, 0, y + yoff);
1042 if (i == pos || !isblank)
1043 while(n < flayer->l_width)
1044 LPutChar(flayer, i == pos ? &mchar_so : &mchar_blank, n++, y + yoff);
1045 #endif
1046 return;
1050 static int
1051 WListNext(wlistdata, old, delta)
1052 struct wlistdata *wlistdata;
1053 int old, delta;
1055 int i, j;
1056 struct win *group = wlistdata->group;
1058 if (old == MAXWIN)
1059 return MAXWIN;
1060 if (wlistdata->order == WLIST_NUM)
1062 if (old == -1)
1064 for (old = 0; old < MAXWIN; old++)
1065 if (wtab[old] && WTAB_GROUP_MATCHES(old))
1066 break;
1067 if (old == MAXWIN)
1068 return old;
1070 if (!wtab[old] || !WTAB_GROUP_MATCHES(old))
1071 return MAXWIN;
1072 i = old;
1073 while (delta > 0 && i < MAXWIN - 1)
1074 if (wtab[++i] && WTAB_GROUP_MATCHES(i))
1076 old = i;
1077 delta--;
1079 while (delta < 0 && i > 0)
1080 if (wtab[--i] && WTAB_GROUP_MATCHES(i))
1082 old = i;
1083 delta++;
1086 else
1088 if (old == -1)
1089 old = windows->w_number;
1090 if (!wtab[old])
1091 return MAXWIN;
1092 for (; delta > 0; delta--)
1093 if (wtab[old]->w_next)
1094 old = wtab[old]->w_next->w_number;
1095 if (delta < 0)
1097 for (j = i = windows->w_number; j != old; )
1099 if (delta++ >= 0 && wtab[i]->w_next)
1100 i = wtab[i]->w_next->w_number;
1101 if (wtab[j]->w_next)
1102 j = wtab[j]->w_next->w_number;
1104 old = i;
1107 return old;
1110 static void
1111 WListLines(up, oldpos)
1112 int up, oldpos;
1114 struct wlistdata *wlistdata;
1115 int ypos, pos;
1116 int y, i, oldi;
1118 wlistdata = (struct wlistdata *)flayer->l_data;
1119 ypos = wlistdata->ypos;
1120 pos = wlistdata->pos;
1122 i = WListNext(wlistdata, pos, -ypos);
1123 for (y = 0; y < wlistdata->numwin; y++)
1125 if (i == MAXWIN || !wtab[i])
1126 return;
1127 if (y == 0)
1128 wlistdata->first = i;
1129 wlistdata->last = i;
1130 if (((i == oldpos || i == pos) && pos != oldpos) || (up > 0 && y >= wlistdata->numwin - up) || (up < 0 && y < -up))
1131 WListLine(y, i, pos, i != oldpos);
1132 if (i == pos)
1133 wlistdata->ypos = y;
1134 oldi = i;
1135 i = WListNext(wlistdata, i, 1);
1136 if (i == MAXWIN || i == oldi)
1137 break;
1141 static int
1142 WListNormalize()
1144 struct wlistdata *wlistdata;
1145 int i, oldi, n;
1146 int ypos, pos;
1148 wlistdata = (struct wlistdata *)flayer->l_data;
1149 ypos = wlistdata->ypos;
1150 pos = wlistdata->pos;
1151 if (ypos < 0)
1152 ypos = 0;
1153 if (ypos >= wlistdata->numwin)
1154 ypos = wlistdata->numwin - 1;
1155 for (n = 0, oldi = MAXWIN, i = pos; i != MAXWIN && i != oldi && n < wlistdata->numwin; oldi = i, i = WListNext(wlistdata, i, 1))
1156 n++;
1157 if (ypos < wlistdata->numwin - n)
1158 ypos = wlistdata->numwin - n;
1159 for (n = 0, oldi = MAXWIN, i = WListNext(wlistdata, -1, 0); i != MAXWIN && i != oldi && i != pos; oldi = i, i = WListNext(wlistdata, i, 1))
1160 n++;
1161 if (ypos > n)
1162 ypos = n;
1163 wlistdata->ypos = ypos;
1164 wlistdata->npos = n;
1165 return ypos;
1168 static void
1169 WListMove(num, ypos)
1170 int num;
1171 int ypos;
1173 struct wlistdata *wlistdata;
1174 int oldpos, oldypos, oldnpos;
1175 int pos, up;
1177 wlistdata = (struct wlistdata *)flayer->l_data;
1178 oldpos = wlistdata->pos;
1179 oldypos = wlistdata->ypos;
1180 oldnpos = wlistdata->npos;
1181 wlistdata->ypos = ypos == -1 ? oldypos + num : ypos;
1182 pos = WListNext(wlistdata, oldpos, num);
1183 wlistdata->pos = pos;
1184 ypos = WListNormalize();
1185 up = wlistdata->npos - ypos - (oldnpos - oldypos);
1186 if (up)
1188 LScrollV(flayer, up, 2, 2 + wlistdata->numwin - 1, 0);
1189 WListLines(up, oldpos);
1190 LaySetCursor();
1191 return;
1193 if (pos == oldpos)
1194 return;
1195 WListLine(oldypos, oldpos, pos, 0);
1196 WListLine(ypos, pos, pos, 1);
1197 LaySetCursor();
1200 static void
1201 WListRedisplayLine(y, xs, xe, isblank)
1202 int y, xs, xe, isblank;
1204 ASSERT(flayer);
1205 if (y < 0)
1207 wlistpage();
1208 return;
1210 if (y != 0 && y != flayer->l_height - 1)
1211 return;
1212 if (!isblank)
1213 LClearArea(flayer, xs, y, xe, y, 0, 0);
1216 void
1217 display_wlist(onblank, order, group)
1218 int onblank;
1219 int order;
1220 struct win *group;
1222 struct win *p;
1223 struct wlistdata *wlistdata;
1225 if (flayer->l_width < 10 || flayer->l_height < 6)
1227 LMsg(0, "Window size too small for window list page");
1228 return;
1230 if (onblank)
1232 debug3("flayer %x %d %x\n", flayer, flayer->l_width, flayer->l_height);
1233 if (!display)
1235 LMsg(0, "windowlist -b: display required");
1236 return;
1238 p = D_fore;
1239 if (p)
1241 SetForeWindow((struct win *)0);
1242 if (p->w_group)
1244 D_fore = p->w_group;
1245 flayer->l_data = (char *)p->w_group;
1247 Activate(0);
1249 if (flayer->l_width < 10 || flayer->l_height < 6)
1251 LMsg(0, "Window size too small for window list page");
1252 return;
1255 else
1256 p = Layer2Window(flayer);
1257 if (!group && p)
1258 group = p->w_group;
1259 if (InitOverlayPage(sizeof(*wlistdata), &WListLf, 0))
1260 return;
1261 wlistdata = (struct wlistdata *)flayer->l_data;
1262 flayer->l_x = 0;
1263 flayer->l_y = flayer->l_height - 1;
1264 wlistdata->start = onblank && p ? p->w_number : -1;
1265 wlistdata->order = order;
1266 wlistdata->group = group;
1267 wlistdata->pos = p ? p->w_number : WListNext(wlistdata, -1, 0);
1268 wlistdata->ypos = wlistdata->npos = 0;
1269 wlistdata->numwin= flayer->l_height - (group ? 4 : 3);
1270 wlistpage();
1273 static void
1274 wlistpage()
1276 struct wlistdata *wlistdata;
1277 char *str;
1278 int pos;
1279 struct win *group;
1281 wlistdata = (struct wlistdata *)flayer->l_data;
1282 group = wlistdata->group;
1284 LClearAll(flayer, 0);
1285 if (wlistdata->start >= 0 && wtab[wlistdata->start] == 0)
1286 wlistdata->start = -2;
1288 pos = wlistdata->pos;
1289 if (pos == MAXWIN || !wtab[pos] || !WTAB_GROUP_MATCHES(pos))
1291 if (wlistdata->order == WLIST_MRU)
1292 pos = WListNext(wlistdata, -1, wlistdata->npos);
1293 else
1295 /* find new position */
1296 if (pos < MAXWIN)
1297 while(++pos < MAXWIN)
1298 if (wtab[pos] && WTAB_GROUP_MATCHES(pos))
1299 break;
1300 if (pos == MAXWIN)
1301 while (--pos >= 0)
1302 if (wtab[pos] && WTAB_GROUP_MATCHES(pos))
1303 break;
1304 if (pos == -1)
1305 pos == MAXWIN;
1308 wlistdata->pos = pos;
1310 display = 0;
1311 str = MakeWinMsgEv(wlisttit, (struct win *)0, '%', flayer->l_width, (struct event *)0, 0);
1312 if (wlistdata->group)
1314 LPutWinMsg(flayer, "Group: ", 7, &mchar_blank, 0, 0);
1315 LPutWinMsg(flayer, wlistdata->group->w_title, strlen(wlistdata->group->w_title), &mchar_blank, 7, 0);
1316 LPutWinMsg(flayer, str, strlen(str), &mchar_blank, 0, 1);
1318 else
1320 LPutWinMsg(flayer, str, strlen(str), &mchar_blank, 0, 0);
1322 WListNormalize();
1323 WListLines(wlistdata->numwin, -1);
1324 LaySetCursor();
1327 static void
1328 WListUpdate(p)
1329 struct win *p;
1331 struct wlistdata *wlistdata;
1332 int i, n, y;
1334 if (p == 0)
1336 wlistpage();
1337 return;
1339 wlistdata = (struct wlistdata *)flayer->l_data;
1340 n = p->w_number;
1341 if (wlistdata->order == WLIST_NUM && (n < wlistdata->first || n > wlistdata->last))
1342 return;
1343 i = wlistdata->first;
1344 for (y = 0; y < wlistdata->numwin; y++)
1346 if (i == n)
1347 break;
1348 i = WListNext(wlistdata, i, 1);
1350 if (y == wlistdata->numwin)
1351 return;
1352 WListLine(y, i, wlistdata->pos, 0);
1353 LaySetCursor();
1356 void
1357 WListUpdatecv(cv, p)
1358 struct canvas *cv;
1359 struct win *p;
1361 if (cv->c_layer->l_layfn != &WListLf)
1362 return;
1363 CV_CALL(cv, WListUpdate(p));
1366 void
1367 WListLinkChanged()
1369 struct display *olddisplay = display;
1370 struct canvas *cv;
1371 struct wlistdata *wlistdata;
1373 for (display = displays; display; display = display->d_next)
1374 for (cv = D_cvlist; cv; cv = cv->c_next)
1376 if (!cv->c_layer || cv->c_layer->l_layfn != &WListLf)
1377 continue;
1378 wlistdata = (struct wlistdata *)cv->c_layer->l_data;
1379 if (wlistdata->order != WLIST_MRU)
1380 continue;
1381 CV_CALL(cv, WListUpdate(0));
1383 display = olddisplay;
1387 InWList()
1389 if (flayer && flayer->l_layfn == &WListLf)
1390 return 1;
1391 return 0;
1398 ** The bindkey help page
1402 #ifdef MAPKEYS
1403 extern struct kmap_ext *kmap_exts;
1404 extern int kmap_extn;
1405 extern struct action dmtab[];
1406 extern struct action mmtab[];
1409 static void BindkeyProcess __P((char **, int *));
1410 static void BindkeyAbort __P((void));
1411 static void BindkeyRedisplayLine __P((int, int, int, int));
1412 static void bindkeypage __P((void));
1414 struct bindkeydata
1416 char *title;
1417 struct action *tab;
1418 int pos;
1419 int last;
1420 int page;
1421 int pages;
1424 static struct LayFuncs BindkeyLf =
1426 BindkeyProcess,
1427 BindkeyAbort,
1428 BindkeyRedisplayLine,
1429 DefClearLine,
1430 DefRewrite,
1431 DefResize,
1432 DefRestore
1436 void
1437 display_bindkey(title, tab)
1438 char *title;
1439 struct action *tab;
1441 struct bindkeydata *bindkeydata;
1442 int i, n;
1444 if (flayer->l_height < 6)
1446 LMsg(0, "Window height too small for bindkey page");
1447 return;
1449 if (InitOverlayPage(sizeof(*bindkeydata), &BindkeyLf, 0))
1450 return;
1452 bindkeydata = (struct bindkeydata *)flayer->l_data;
1453 bindkeydata->title = title;
1454 bindkeydata->tab = tab;
1456 n = 0;
1457 for (i = 0; i < KMAP_KEYS+KMAP_AKEYS+kmap_extn; i++)
1459 if (tab[i].nr != RC_ILLEGAL)
1460 n++;
1462 bindkeydata->pos = 0;
1463 bindkeydata->page = 1;
1464 bindkeydata->pages = (n + flayer->l_height - 6) / (flayer->l_height - 5);
1465 if (bindkeydata->pages == 0)
1466 bindkeydata->pages = 1;
1467 flayer->l_x = 0;
1468 flayer->l_y = flayer->l_height - 1;
1469 bindkeypage();
1472 static void
1473 BindkeyAbort()
1475 LAY_CALL_UP(LRefreshAll(flayer, 0));
1476 ExitOverlayPage();
1479 static void
1480 bindkeypage()
1482 struct bindkeydata *bindkeydata;
1483 struct kmap_ext *kme;
1484 char tbuf[256];
1485 int del, i, y, sl;
1486 struct action *act;
1487 char *xch, *s, *p;
1489 bindkeydata = (struct bindkeydata *)flayer->l_data;
1491 LClearAll(flayer, 0);
1493 sprintf(tbuf, "%s key bindings, page %d of %d.", bindkeydata->title, bindkeydata->page, bindkeydata->pages);
1494 centerline(tbuf, 0);
1495 y = 2;
1496 for (i = bindkeydata->pos; i < KMAP_KEYS+KMAP_AKEYS+kmap_extn && y < flayer->l_height - 3; i++)
1498 p = tbuf;
1499 xch = " ";
1500 if (i < KMAP_KEYS)
1502 act = &bindkeydata->tab[i];
1503 if (act->nr == RC_ILLEGAL)
1504 continue;
1505 del = *p++ = ':';
1506 s = term[i + T_CAPS].tcname;
1507 sl = s ? strlen(s) : 0;
1509 else if (i < KMAP_KEYS+KMAP_AKEYS)
1511 act = &bindkeydata->tab[i];
1512 if (act->nr == RC_ILLEGAL)
1513 continue;
1514 del = *p++ = ':';
1515 s = term[i + (T_CAPS - T_OCAPS + T_CURSOR)].tcname;
1516 sl = s ? strlen(s) : 0;
1517 xch = "[A]";
1519 else
1521 kme = kmap_exts + (i - (KMAP_KEYS+KMAP_AKEYS));
1522 del = 0;
1523 s = kme->str;
1524 sl = kme->fl & ~KMAP_NOTIMEOUT;
1525 if ((kme->fl & KMAP_NOTIMEOUT) != 0)
1526 xch = "[T]";
1527 act = bindkeydata->tab == dmtab ? &kme->dm : bindkeydata->tab == mmtab ? &kme->mm : &kme->um;
1528 if (act->nr == RC_ILLEGAL)
1529 continue;
1531 while (sl-- > 0)
1532 p += AddXChar(p, *(unsigned char *)s++);
1533 if (del)
1534 *p++ = del;
1535 *p++ = ' ';
1536 while (p < tbuf + 15)
1537 *p++ = ' ';
1538 sprintf(p, "%s -> ", xch);
1539 p += 7;
1540 if (p - tbuf > flayer->l_width - 1)
1542 tbuf[flayer->l_width - 2] = '$';
1543 tbuf[flayer->l_width - 1] = 0;
1545 PadStr(tbuf, strlen(tbuf), 0, y);
1546 AddAction(act, strlen(tbuf), y);
1547 y++;
1549 y++;
1550 bindkeydata->last = i;
1551 sprintf(tbuf,"[Press Space %s Return to end.]", bindkeydata->page < bindkeydata->pages ? "for next page;" : "or");
1552 centerline(tbuf, flayer->l_height - 2);
1553 LaySetCursor();
1556 static void
1557 BindkeyProcess(ppbuf, plen)
1558 char **ppbuf;
1559 int *plen;
1561 int done = 0;
1562 struct bindkeydata *bindkeydata;
1564 bindkeydata = (struct bindkeydata *)flayer->l_data;
1565 while (!done && *plen > 0)
1567 switch (**ppbuf)
1569 case ' ':
1570 if (bindkeydata->page < bindkeydata->pages)
1572 bindkeydata->pos = bindkeydata->last;
1573 bindkeydata->page++;
1574 bindkeypage();
1575 break;
1577 /* FALLTHROUGH */
1578 case '\r':
1579 case '\n':
1580 done = 1;
1581 break;
1582 default:
1583 break;
1585 ++*ppbuf;
1586 --*plen;
1588 if (done)
1589 BindkeyAbort();
1592 static void
1593 BindkeyRedisplayLine(y, xs, xe, isblank)
1594 int y, xs, xe, isblank;
1596 if (y < 0)
1598 bindkeypage();
1599 return;
1601 if (y != 0 && y != flayer->l_height - 1)
1602 return;
1603 if (!isblank)
1604 LClearArea(flayer, xs, y, xe, y, 0, 0);
1607 #endif /* MAPKEYS */
1612 ** The zmodem active page
1616 #ifdef ZMODEM
1618 static void ZmodemRedisplayLine __P((int, int, int, int));
1619 static int ZmodemResize __P((int, int));
1621 static struct LayFuncs ZmodemLf =
1623 DefProcess,
1625 ZmodemRedisplayLine,
1626 DefClearLine,
1627 DefRewrite,
1628 ZmodemResize,
1629 DefRestore
1632 /*ARGSUSED*/
1633 static int
1634 ZmodemResize(wi, he)
1635 int wi, he;
1637 flayer->l_width = wi;
1638 flayer->l_height = he;
1639 flayer->l_x = flayer->l_width > 32 ? 32 : 0;
1640 return 0;
1643 static void
1644 ZmodemRedisplayLine(y, xs, xe, isblank)
1645 int y, xs, xe, isblank;
1647 DefRedisplayLine(y, xs, xe, isblank);
1648 if (y == 0 && xs == 0)
1649 LPutStr(flayer, "Zmodem active on another display", flayer->l_width > 32 ? 32 : flayer->l_width, &mchar_blank, 0, 0);
1652 void
1653 ZmodemPage()
1655 if (InitOverlayPage(1, &ZmodemLf, 1))
1656 return;
1657 LRefreshAll(flayer, 0);
1658 flayer->l_x = flayer->l_width > 32 ? 32 : 0;
1659 flayer->l_y = 0;
1662 #endif
1666 static void
1667 PadStr(str, n, x, y)
1668 char *str;
1669 int n, x, y;
1671 int l;
1673 l = strlen(str);
1674 if (l > n)
1675 l = n;
1676 LPutStr(flayer, str, l, &mchar_blank, x, y);
1677 if (l < n)
1678 LPutStr(flayer, (char *)blank, n - l, &mchar_blank, x + l, y);