Make 'number' query-able.
[screen-lua.git] / src / process.c
blobc1d2da18333c5a22944c9b1b3a05e60ec582213c
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX)
36 # include <time.h>
37 #endif
38 #include <sys/time.h>
39 #ifndef sun
40 #include <sys/ioctl.h>
41 #endif
44 /* for solaris 2.1, Unixware (SVR4.2) and possibly others: */
45 #ifdef HAVE_STROPTS_H
46 # include <sys/stropts.h>
47 #endif
49 #include "screen.h"
50 #include "extern.h"
51 #include "logfile.h"
52 #include "layout.h"
53 #include "viewport.h"
55 extern struct comm comms[];
56 extern char *rc_name;
57 extern char *RcFileName, *home;
58 extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
59 extern char *hstatusstring, *captionstring, *timestring;
60 extern char *wliststr, *wlisttit;
61 extern int captionalways;
62 extern int queryflag;
63 extern char *hardcopydir, *screenlogfile, *logtstamp_string;
64 extern int log_flush, logtstamp_on, logtstamp_after;
65 extern char *VisualBellString;
66 extern int VBellWait, MsgWait, MsgMinWait, SilenceWait;
67 extern char SockPath[], *SockName;
68 extern int TtyMode, auto_detach, use_altscreen;
69 extern int iflag, maxwin;
70 extern int focusminwidth, focusminheight;
71 extern int use_hardstatus, visual_bell;
72 #ifdef COLOR
73 extern int attr2color[][4];
74 extern int nattr2color;
75 #endif
76 extern int hardstatusemu;
77 extern char *printcmd;
78 extern int default_startup;
79 extern int defobuflimit;
80 extern int defnonblock;
81 extern int defmousetrack;
82 extern int ZombieKey_destroy;
83 extern int ZombieKey_resurrect;
84 extern int ZombieKey_onerror;
85 #ifdef AUTO_NUKE
86 extern int defautonuke;
87 #endif
88 extern int separate_sids;
89 extern struct NewWindow nwin_default, nwin_undef;
90 #ifdef COPY_PASTE
91 extern int join_with_cr;
92 extern int compacthist;
93 extern int search_ic;
94 # ifdef FONT
95 extern int pastefont;
96 # endif
97 extern unsigned char mark_key_tab[];
98 extern char *BufferFile;
99 #endif
100 #ifdef POW_DETACH
101 extern char *BufferFile, *PowDetachString;
102 #endif
103 #ifdef MULTIUSER
104 extern struct acluser *EffectiveAclUser; /* acl.c */
105 #endif
106 extern struct term term[]; /* terminal capabilities */
107 #ifdef MAPKEYS
108 extern char *kmapdef[];
109 extern char *kmapadef[];
110 extern char *kmapmdef[];
111 #endif
112 extern struct mchar mchar_so, mchar_null;
113 extern int renditions[];
114 extern int VerboseCreate;
115 #ifdef UTF8
116 extern char *screenencodings;
117 #endif
118 #ifdef DW_CHARS
119 extern int cjkwidth;
120 #endif
122 static int CheckArgNum __P((int, char **));
123 static void ClearAction __P((struct action *));
124 static void SaveAction __P((struct action *, int, char **, int *));
125 static int NextWindow __P((void));
126 static int PreviousWindow __P((void));
127 static int MoreWindows __P((void));
128 static void LogToggle __P((int));
129 static void ShowInfo __P((void));
130 static void ShowDInfo __P((void));
131 static struct win *WindowByName __P((char *));
132 static int WindowByNumber __P((char *));
133 static int ParseOnOff __P((struct action *, int *));
134 static int ParseWinNum __P((struct action *, int *));
135 static int ParseBase __P((struct action *, char *, int *, int, char *));
136 static int ParseNum1000 __P((struct action *, int *));
137 static char **SaveArgs __P((char **));
138 static int IsNum __P((char *, int));
139 static void Colonfin __P((char *, int, char *));
140 static void InputSelect __P((void));
141 static void InputSetenv __P((char *));
142 static void InputAKA __P((void));
143 #ifdef MULTIUSER
144 static int InputSu __P((struct win *, struct acluser **, char *));
145 static void su_fin __P((char *, int, char *));
146 #endif
147 static void AKAfin __P((char *, int, char *));
148 #ifdef COPY_PASTE
149 static void copy_reg_fn __P((char *, int, char *));
150 static void ins_reg_fn __P((char *, int, char *));
151 #endif
152 static void process_fn __P((char *, int, char *));
153 #ifdef PASSWORD
154 static void pass1 __P((char *, int, char *));
155 static void pass2 __P((char *, int, char *));
156 #endif
157 #ifdef POW_DETACH
158 static void pow_detach_fn __P((char *, int, char *));
159 #endif
160 static void digraph_fn __P((char *, int, char *));
161 static int digraph_find __P((const char *buf));
162 static void confirm_fn __P((char *, int, char *));
163 static int IsOnDisplay __P((struct win *));
164 static void ResizeRegions __P((char *, int));
165 static void ResizeFin __P((char *, int, char *));
166 static struct action *FindKtab __P((char *, int));
167 static void SelectFin __P((char *, int, char *));
168 static void SelectLayoutFin __P((char *, int, char *));
171 extern struct layer *flayer;
172 extern struct display *display, *displays;
173 extern struct win *fore, *console_window, *windows;
174 extern struct acluser *users;
175 extern struct layout *layouts, *layout_attach, layout_last_marker;
176 extern struct layout *laytab[];
178 extern char screenterm[], HostName[], version[];
179 extern struct NewWindow nwin_undef, nwin_default;
180 extern struct LayFuncs WinLf, MarkLf;
182 extern int Z0width, Z1width;
183 extern int real_uid, real_gid;
185 #ifdef NETHACK
186 extern int nethackflag;
187 #endif
190 extern struct win **wtab;
192 #ifdef MULTIUSER
193 extern char *multi;
194 extern int maxusercount;
195 #endif
196 char NullStr[] = "";
198 struct plop plop_tab[MAX_PLOP_DEFS];
200 #ifndef PTYMODE
201 # define PTYMODE 0622
202 #endif
204 int TtyMode = PTYMODE;
205 int hardcopy_append = 0;
206 int all_norefresh = 0;
207 #ifdef ZMODEM
208 int zmodem_mode = 0;
209 char *zmodem_sendcmd;
210 char *zmodem_recvcmd;
211 static char *zmodes[4] = {"off", "auto", "catch", "pass"};
212 #endif
214 int idletimo;
215 struct action idleaction;
216 #ifdef BLANKER_PRG
217 char **blankerprg;
218 #endif
220 struct action ktab[256 + KMAP_KEYS]; /* command key translation table */
221 struct kclass {
222 struct kclass *next;
223 char *name;
224 struct action ktab[256 + KMAP_KEYS];
226 struct kclass *kclasses;
228 #ifdef MAPKEYS
229 struct action umtab[KMAP_KEYS+KMAP_AKEYS];
230 struct action dmtab[KMAP_KEYS+KMAP_AKEYS];
231 struct action mmtab[KMAP_KEYS+KMAP_AKEYS];
232 struct kmap_ext *kmap_exts;
233 int kmap_extn;
234 static int maptimeout = 300;
235 #endif
237 #ifndef MAX_DIGRAPH
238 #define MAX_DIGRAPH 512
239 #endif
241 struct digraph
243 unsigned char d[2];
244 int value;
247 /* digraph table taken from old vim and rfc1345 */
248 static struct digraph digraphs[MAX_DIGRAPH + 1] = {
249 {' ', ' ', 160}, /*   */
250 {'N', 'S', 160}, /*   */
251 {'~', '!', 161}, /* ¡ */
252 {'!', '!', 161}, /* ¡ */
253 {'!', 'I', 161}, /* ¡ */
254 {'c', '|', 162}, /* ¢ */
255 {'c', 't', 162}, /* ¢ */
256 {'$', '$', 163}, /* £ */
257 {'P', 'd', 163}, /* £ */
258 {'o', 'x', 164}, /* ¤ */
259 {'C', 'u', 164}, /* ¤ */
260 {'C', 'u', 164}, /* ¤ */
261 {'E', 'u', 164}, /* ¤ */
262 {'Y', '-', 165}, /* ¥ */
263 {'Y', 'e', 165}, /* ¥ */
264 {'|', '|', 166}, /* ¦ */
265 {'B', 'B', 166}, /* ¦ */
266 {'p', 'a', 167}, /* § */
267 {'S', 'E', 167}, /* § */
268 {'"', '"', 168}, /* ¨ */
269 {'\'', ':', 168}, /* ¨ */
270 {'c', 'O', 169}, /* © */
271 {'C', 'o', 169}, /* © */
272 {'a', '-', 170}, /* ª */
273 {'<', '<', 171}, /* « */
274 {'-', ',', 172}, /* ¬ */
275 {'N', 'O', 172}, /* ¬ */
276 {'-', '-', 173}, /* ­ */
277 {'r', 'O', 174}, /* ® */
278 {'R', 'g', 174}, /* ® */
279 {'-', '=', 175}, /* ¯ */
280 {'\'', 'm', 175}, /* ¯ */
281 {'~', 'o', 176}, /* ° */
282 {'D', 'G', 176}, /* ° */
283 {'+', '-', 177}, /* ± */
284 {'2', '2', 178}, /* ² */
285 {'2', 'S', 178}, /* ² */
286 {'3', '3', 179}, /* ³ */
287 {'3', 'S', 179}, /* ³ */
288 {'\'', '\'', 180}, /* ´ */
289 {'j', 'u', 181}, /* µ */
290 {'M', 'y', 181}, /* µ */
291 {'p', 'p', 182}, /* ¶ */
292 {'P', 'I', 182}, /* ¶ */
293 {'~', '.', 183}, /* · */
294 {'.', 'M', 183}, /* · */
295 {',', ',', 184}, /* ¸ */
296 {'\'', ',', 184}, /* ¸ */
297 {'1', '1', 185}, /* ¹ */
298 {'1', 'S', 185}, /* ¹ */
299 {'o', '-', 186}, /* º */
300 {'>', '>', 187}, /* » */
301 {'1', '4', 188}, /* ¼ */
302 {'1', '2', 189}, /* ½ */
303 {'3', '4', 190}, /* ¾ */
304 {'~', '?', 191}, /* ¿ */
305 {'?', '?', 191}, /* ¿ */
306 {'?', 'I', 191}, /* ¿ */
307 {'A', '`', 192}, /* À */
308 {'A', '!', 192}, /* À */
309 {'A', '\'', 193}, /* Á */
310 {'A', '^', 194}, /* Â */
311 {'A', '>', 194}, /* Â */
312 {'A', '~', 195}, /* Ã */
313 {'A', '?', 195}, /* Ã */
314 {'A', '"', 196}, /* Ä */
315 {'A', ':', 196}, /* Ä */
316 {'A', '@', 197}, /* Å */
317 {'A', 'A', 197}, /* Å */
318 {'A', 'E', 198}, /* Æ */
319 {'C', ',', 199}, /* Ç */
320 {'E', '`', 200}, /* È */
321 {'E', '!', 200}, /* È */
322 {'E', '\'', 201}, /* É */
323 {'E', '^', 202}, /* Ê */
324 {'E', '>', 202}, /* Ê */
325 {'E', '"', 203}, /* Ë */
326 {'E', ':', 203}, /* Ë */
327 {'I', '`', 204}, /* Ì */
328 {'I', '!', 204}, /* Ì */
329 {'I', '\'', 205}, /* Í */
330 {'I', '^', 206}, /* Î */
331 {'I', '>', 206}, /* Î */
332 {'I', '"', 207}, /* Ï */
333 {'I', ':', 207}, /* Ï */
334 {'D', '-', 208}, /* Ð */
335 {'N', '~', 209}, /* Ñ */
336 {'N', '?', 209}, /* Ñ */
337 {'O', '`', 210}, /* Ò */
338 {'O', '!', 210}, /* Ò */
339 {'O', '\'', 211}, /* Ó */
340 {'O', '^', 212}, /* Ô */
341 {'O', '>', 212}, /* Ô */
342 {'O', '~', 213}, /* Õ */
343 {'O', '?', 213}, /* Õ */
344 {'O', '"', 214}, /* Ö */
345 {'O', ':', 214}, /* Ö */
346 {'/', '\\', 215}, /* × */
347 {'*', 'x', 215}, /* × */
348 {'O', '/', 216}, /* Ø */
349 {'U', '`', 217}, /* Ù */
350 {'U', '!', 217}, /* Ù */
351 {'U', '\'', 218}, /* Ú */
352 {'U', '^', 219}, /* Û */
353 {'U', '>', 219}, /* Û */
354 {'U', '"', 220}, /* Ü */
355 {'U', ':', 220}, /* Ü */
356 {'Y', '\'', 221}, /* Ý */
357 {'I', 'p', 222}, /* Þ */
358 {'T', 'H', 222}, /* Þ */
359 {'s', 's', 223}, /* ß */
360 {'s', '"', 223}, /* ß */
361 {'a', '`', 224}, /* à */
362 {'a', '!', 224}, /* à */
363 {'a', '\'', 225}, /* á */
364 {'a', '^', 226}, /* â */
365 {'a', '>', 226}, /* â */
366 {'a', '~', 227}, /* ã */
367 {'a', '?', 227}, /* ã */
368 {'a', '"', 228}, /* ä */
369 {'a', ':', 228}, /* ä */
370 {'a', 'a', 229}, /* å */
371 {'a', 'e', 230}, /* æ */
372 {'c', ',', 231}, /* ç */
373 {'e', '`', 232}, /* è */
374 {'e', '!', 232}, /* è */
375 {'e', '\'', 233}, /* é */
376 {'e', '^', 234}, /* ê */
377 {'e', '>', 234}, /* ê */
378 {'e', '"', 235}, /* ë */
379 {'e', ':', 235}, /* ë */
380 {'i', '`', 236}, /* ì */
381 {'i', '!', 236}, /* ì */
382 {'i', '\'', 237}, /* í */
383 {'i', '^', 238}, /* î */
384 {'i', '>', 238}, /* î */
385 {'i', '"', 239}, /* ï */
386 {'i', ':', 239}, /* ï */
387 {'d', '-', 240}, /* ð */
388 {'n', '~', 241}, /* ñ */
389 {'n', '?', 241}, /* ñ */
390 {'o', '`', 242}, /* ò */
391 {'o', '!', 242}, /* ò */
392 {'o', '\'', 243}, /* ó */
393 {'o', '^', 244}, /* ô */
394 {'o', '>', 244}, /* ô */
395 {'o', '~', 245}, /* õ */
396 {'o', '?', 245}, /* õ */
397 {'o', '"', 246}, /* ö */
398 {'o', ':', 246}, /* ö */
399 {':', '-', 247}, /* ÷ */
400 {'o', '/', 248}, /* ø */
401 {'u', '`', 249}, /* ù */
402 {'u', '!', 249}, /* ù */
403 {'u', '\'', 250}, /* ú */
404 {'u', '^', 251}, /* û */
405 {'u', '>', 251}, /* û */
406 {'u', '"', 252}, /* ü */
407 {'u', ':', 252}, /* ü */
408 {'y', '\'', 253}, /* ý */
409 {'i', 'p', 254}, /* þ */
410 {'t', 'h', 254}, /* þ */
411 {'y', '"', 255}, /* ÿ */
412 {'y', ':', 255}, /* ÿ */
413 {'"', '[', 196}, /* Ä */
414 {'"', '\\', 214}, /* Ö */
415 {'"', ']', 220}, /* Ü */
416 {'"', '{', 228}, /* ä */
417 {'"', '|', 246}, /* ö */
418 {'"', '}', 252}, /* ü */
419 {'"', '~', 223} /* ß */
422 #define RESIZE_FLAG_H 1
423 #define RESIZE_FLAG_V 2
424 #define RESIZE_FLAG_L 4
426 static char *resizeprompts[] = {
427 "resize # lines: ",
428 "resize -h # lines: ",
429 "resize -v # lines: ",
430 "resize -b # lines: ",
431 "resize -l # lines: ",
432 "resize -l -h # lines: ",
433 "resize -l -v # lines: ",
434 "resize -l -b # lines: ",
437 static int
438 parse_input_int(buf, len, val)
439 const char *buf;
440 int len;
441 int *val;
443 int x = 0, i;
444 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))))
446 x = 0;
447 for (i = 2; i < len; i++)
449 if (buf[i] >= '0' && buf[i] <= '9')
450 x = x * 16 | (buf[i] - '0');
451 else if (buf[i] >= 'a' && buf[i] <= 'f')
452 x = x * 16 | (buf[i] - ('a' - 10));
453 else if (buf[i] >= 'A' && buf[i] <= 'F')
454 x = x * 16 | (buf[i] - ('A' - 10));
455 else
456 return 0;
459 else if (buf[0] == '0')
461 x = 0;
462 for (i = 1; i < len; i++)
464 if (buf[i] < '0' || buf[i] > '7')
465 return 0;
466 x = x * 8 | (buf[i] - '0');
469 else
470 return 0;
471 *val = x;
472 return 1;
475 char *noargs[1];
477 void
478 InitKeytab()
480 register unsigned int i;
481 #ifdef MAPKEYS
482 char *argarr[2];
483 #endif
485 for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
487 ktab[i].nr = RC_ILLEGAL;
488 ktab[i].args = noargs;
489 ktab[i].argl = 0;
491 #ifdef MAPKEYS
492 for (i = 0; i < KMAP_KEYS+KMAP_AKEYS; i++)
494 umtab[i].nr = RC_ILLEGAL;
495 umtab[i].args = noargs;
496 umtab[i].argl = 0;
497 dmtab[i].nr = RC_ILLEGAL;
498 dmtab[i].args = noargs;
499 dmtab[i].argl = 0;
500 mmtab[i].nr = RC_ILLEGAL;
501 mmtab[i].args = noargs;
502 mmtab[i].argl = 0;
504 argarr[1] = 0;
505 for (i = 0; i < NKMAPDEF; i++)
507 if (i + KMAPDEFSTART < T_CAPS)
508 continue;
509 if (i + KMAPDEFSTART >= T_CAPS + KMAP_KEYS)
510 continue;
511 if (kmapdef[i] == 0)
512 continue;
513 argarr[0] = kmapdef[i];
514 SaveAction(dmtab + i + (KMAPDEFSTART - T_CAPS), RC_STUFF, argarr, 0);
516 for (i = 0; i < NKMAPADEF; i++)
518 if (i + KMAPADEFSTART < T_CURSOR)
519 continue;
520 if (i + KMAPADEFSTART >= T_CURSOR + KMAP_AKEYS)
521 continue;
522 if (kmapadef[i] == 0)
523 continue;
524 argarr[0] = kmapadef[i];
525 SaveAction(dmtab + i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS), RC_STUFF, argarr, 0);
527 for (i = 0; i < NKMAPMDEF; i++)
529 if (i + KMAPMDEFSTART < T_CAPS)
530 continue;
531 if (i + KMAPMDEFSTART >= T_CAPS + KMAP_KEYS)
532 continue;
533 if (kmapmdef[i] == 0)
534 continue;
535 argarr[0] = kmapmdef[i];
536 argarr[1] = 0;
537 SaveAction(mmtab + i + (KMAPMDEFSTART - T_CAPS), RC_STUFF, argarr, 0);
539 #endif
541 ktab['h'].nr = RC_HARDCOPY;
542 #ifdef BSDJOBS
543 ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND;
544 #endif
545 ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN;
546 ktab[' '].nr = ktab[Ctrl(' ')].nr =
547 ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT;
548 ktab['N'].nr = RC_NUMBER;
549 ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV;
550 ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL;
551 ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY;
552 ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS;
553 ktab['v'].nr = RC_VERSION;
554 ktab[Ctrl('v')].nr = RC_DIGRAPH;
555 ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON;
556 ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF;
557 ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME;
558 ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO;
559 ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG;
560 ktab['A'].nr = RC_TITLE;
561 #if defined(UTMPOK) && defined(LOGOUTOK)
562 ktab['L'].nr = RC_LOGIN;
563 #endif
564 ktab[','].nr = RC_LICENSE;
565 ktab['W'].nr = RC_WIDTH;
566 ktab['.'].nr = RC_DUMPTERMCAP;
567 ktab[Ctrl('\\')].nr = RC_QUIT;
568 #ifdef DETACH
569 ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH;
570 # ifdef POW_DETACH
571 ktab['D'].nr = RC_POW_DETACH;
572 # endif
573 #endif
574 ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP;
575 ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW;
576 ktab['C'].nr = RC_CLEAR;
577 ktab['Z'].nr = RC_RESET;
578 ktab['H'].nr = RC_LOG;
579 ktab['M'].nr = RC_MONITOR;
580 ktab['?'].nr = RC_HELP;
581 #ifdef MULTI
582 ktab['*'].nr = RC_DISPLAYS;
583 #endif
585 char *args[2];
586 args[0] = "-";
587 args[1] = NULL;
588 SaveAction(ktab + '-', RC_SELECT, args, 0);
590 for (i = 0; i < ((maxwin && maxwin < 10) ? maxwin : 10); i++)
592 char *args[2], arg1[10];
593 args[0] = arg1;
594 args[1] = 0;
595 sprintf(arg1, "%d", i);
596 SaveAction(ktab + '0' + i, RC_SELECT, args, 0);
598 ktab['\''].nr = RC_SELECT; /* calling a window by name */
600 char *args[2];
601 args[0] = "-b";
602 args[1] = 0;
603 SaveAction(ktab + '"', RC_WINDOWLIST, args, 0);
605 ktab[Ctrl('G')].nr = RC_VBELL;
606 ktab[':'].nr = RC_COLON;
607 #ifdef COPY_PASTE
608 ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY;
610 char *args[2];
611 args[0] = ".";
612 args[1] = 0;
613 SaveAction(ktab + ']', RC_PASTE, args, 0);
614 SaveAction(ktab + Ctrl(']'), RC_PASTE, args, 0);
616 ktab['{'].nr = RC_HISTORY;
617 ktab['}'].nr = RC_HISTORY;
618 ktab['>'].nr = RC_WRITEBUF;
619 ktab['<'].nr = RC_READBUF;
620 ktab['='].nr = RC_REMOVEBUF;
621 #endif
622 #ifdef POW_DETACH
623 ktab['D'].nr = RC_POW_DETACH;
624 #endif
625 #ifdef LOCK
626 ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN;
627 #endif
628 ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK;
629 ktab['B'].nr = RC_POW_BREAK;
630 ktab['_'].nr = RC_SILENCE;
631 ktab['S'].nr = RC_SPLIT;
632 ktab['Q'].nr = RC_ONLY;
633 ktab['X'].nr = RC_REMOVE;
634 ktab['F'].nr = RC_FIT;
635 ktab['\t'].nr = RC_FOCUS;
637 char *args[2];
638 args[0] = "prev";
639 args[1] = 0;
640 SaveAction(ktab + T_BACKTAB - T_CAPS + 256, RC_FOCUS, args, 0);
643 char *args[2];
644 args[0] = "-v";
645 args[1] = 0;
646 SaveAction(ktab + '|', RC_SPLIT, args, 0);
648 /* These come last; they may want overwrite others: */
649 if (DefaultEsc >= 0)
651 ClearAction(&ktab[DefaultEsc]);
652 ktab[DefaultEsc].nr = RC_OTHER;
654 if (DefaultMetaEsc >= 0)
656 ClearAction(&ktab[DefaultMetaEsc]);
657 ktab[DefaultMetaEsc].nr = RC_META;
660 idleaction.nr = RC_BLANKER;
661 idleaction.args = noargs;
662 idleaction.argl = 0;
665 static struct action *
666 FindKtab(class, create)
667 char *class;
668 int create;
670 struct kclass *kp, **kpp;
671 int i;
673 if (class == 0)
674 return ktab;
675 for (kpp = &kclasses; (kp = *kpp) != 0; kpp = &kp->next)
676 if (!strcmp(kp->name, class))
677 break;
678 if (kp == 0)
680 if (!create)
681 return 0;
682 if (strlen(class) > 80)
684 Msg(0, "Command class name too long.");
685 return 0;
687 kp = malloc(sizeof(*kp));
688 if (kp == 0)
690 Msg(0, strnomem);
691 return 0;
693 kp->name = SaveStr(class);
694 for (i = 0; i < (int)(sizeof(kp->ktab)/sizeof(*kp->ktab)); i++)
696 kp->ktab[i].nr = RC_ILLEGAL;
697 kp->ktab[i].args = noargs;
698 kp->ktab[i].argl = 0;
699 kp->ktab[i].quiet = 0;
701 kp->next = 0;
702 *kpp = kp;
704 return kp->ktab;
707 static void
708 ClearAction(act)
709 struct action *act;
711 char **p;
713 if (act->nr == RC_ILLEGAL)
714 return;
715 act->nr = RC_ILLEGAL;
716 if (act->args == noargs)
717 return;
718 for (p = act->args; *p; p++)
719 free(*p);
720 free((char *)act->args);
721 act->args = noargs;
722 act->argl = 0;
726 * ProcessInput: process input from display and feed it into
727 * the layer on canvas D_forecv.
730 #ifdef MAPKEYS
733 * This ProcessInput just does the keybindings and passes
734 * everything else on to ProcessInput2.
737 void
738 ProcessInput(ibuf, ilen)
739 char *ibuf;
740 int ilen;
742 int ch, slen;
743 unsigned char *s, *q;
744 int i, l;
745 char *p;
747 debug1("ProcessInput: %d bytes\n", ilen);
748 if (display == 0 || ilen == 0)
749 return;
750 if (D_seql)
751 evdeq(&D_mapev);
752 slen = ilen;
753 s = (unsigned char *)ibuf;
754 while (ilen-- > 0)
756 ch = *s++;
757 if (D_dontmap || !D_nseqs)
759 D_dontmap = 0;
760 continue;
762 for (;;)
764 debug3("cmp %c %c[%d]\n", ch, *D_seqp, D_seqp - D_kmaps);
765 if (*D_seqp != ch)
767 l = D_seqp[D_seqp[-D_seql-1] + 1];
768 if (l)
770 D_seqp += l * 2 + 4;
771 debug1("miss %d\n", D_seqp - D_kmaps);
772 continue;
774 debug("complete miss\n");
775 D_mapdefault = 0;
776 l = D_seql;
777 p = (char *)D_seqp - l;
778 D_seql = 0;
779 D_seqp = D_kmaps + 3;
780 if (l == 0)
781 break;
782 if ((q = D_seqh) != 0)
784 D_seqh = 0;
785 i = q[0] << 8 | q[1];
786 i &= ~KMAP_NOTIMEOUT;
787 debug1("Mapping former hit #%d - ", i);
788 debug2("%d(%s) - ", q[2], q + 3);
789 if (StuffKey(i))
790 ProcessInput2((char *)q + 3, q[2]);
791 if (display == 0)
792 return;
793 l -= q[2];
794 p += q[2];
796 else
797 D_dontmap = 1;
798 debug1("flush old %d\n", l);
799 ProcessInput(p, l);
800 if (display == 0)
801 return;
802 evdeq(&D_mapev);
803 continue;
805 if (D_seql++ == 0)
807 /* Finish old stuff */
808 slen -= ilen + 1;
809 debug1("finish old %d\n", slen);
810 if (slen)
811 ProcessInput2(ibuf, slen);
812 if (display == 0)
813 return;
814 D_seqh = 0;
816 ibuf = (char *)s;
817 slen = ilen;
818 D_seqp++;
819 l = D_seql;
820 debug2("length am %d, want %d\n", l, D_seqp[-l - 1]);
821 if (l == D_seqp[-l - 1])
823 if (D_seqp[l] != l)
825 q = D_seqp + 1 + l;
826 if (D_kmaps + D_nseqs > q && q[2] > l && !bcmp(D_seqp - l, q + 3, l))
828 debug1("have another mapping (%s), delay execution\n", q + 3);
829 D_seqh = D_seqp - 3 - l;
830 D_seqp = q + 3 + l;
831 break;
834 i = D_seqp[-l - 3] << 8 | D_seqp[-l - 2];
835 i &= ~KMAP_NOTIMEOUT;
836 debug1("Mapping #%d - ", i);
837 p = (char *)D_seqp - l;
838 debug2("%d(%s) - ", l, p);
839 D_seql = 0;
840 D_seqp = D_kmaps + 3;
841 D_seqh = 0;
842 if (StuffKey(i))
843 ProcessInput2(p, l);
844 if (display == 0)
845 return;
847 break;
850 if (D_seql)
852 debug("am in sequence -> check for timeout\n");
853 l = D_seql;
854 for (s = D_seqp; ; s += i * 2 + 4)
856 if (s[-l-3] & KMAP_NOTIMEOUT >> 8)
857 break;
858 if ((i = s[s[-l-1] + 1]) == 0)
860 SetTimeout(&D_mapev, maptimeout);
861 evenq(&D_mapev);
862 break;
866 ProcessInput2(ibuf, slen);
869 #else
870 # define ProcessInput2 ProcessInput
871 #endif
875 * Here only the screen escape commands are handled.
878 void
879 ProcessInput2(ibuf, ilen)
880 char *ibuf;
881 int ilen;
883 char *s;
884 int ch, slen;
885 struct action *ktabp;
887 debug1("ProcessInput2: %d bytes\n", ilen);
888 while (ilen && display)
890 debug1(" - ilen now %d bytes\n", ilen);
891 flayer = D_forecv->c_layer;
892 fore = D_fore;
893 slen = ilen;
894 s = ibuf;
895 if (!D_ESCseen)
897 while (ilen > 0)
899 if ((unsigned char)*s++ == D_user->u_Esc)
900 break;
901 ilen--;
903 slen -= ilen;
904 if (slen)
905 DoProcess(fore, &ibuf, &slen, 0);
906 if (--ilen == 0)
907 D_ESCseen = ktab;
909 if (ilen <= 0)
910 return;
911 ktabp = D_ESCseen ? D_ESCseen : ktab;
912 D_ESCseen = 0;
913 ch = (unsigned char)*s;
916 * As users have different esc characters, but a common ktab[],
917 * we fold back the users esc and meta-esc key to the Default keys
918 * that can be looked up in the ktab[]. grmbl. jw.
919 * XXX: make ktab[] a per user thing.
921 if (ch == D_user->u_Esc)
922 ch = DefaultEsc;
923 else if (ch == D_user->u_MetaEsc)
924 ch = DefaultMetaEsc;
926 if (ch >= 0)
927 DoAction(&ktabp[ch], ch);
928 ibuf = (char *)(s + 1);
929 ilen--;
933 void
934 DoProcess(p, bufp, lenp, pa)
935 struct win *p;
936 char **bufp;
937 int *lenp;
938 struct paster *pa;
940 int oldlen;
941 struct display *d = display;
943 #ifdef COPY_PASTE
944 /* XXX -> PasteStart */
945 if (pa && *lenp > 1 && p && p->w_slowpaste)
947 /* schedule slowpaste event */
948 SetTimeout(&p->w_paster.pa_slowev, p->w_slowpaste);
949 evenq(&p->w_paster.pa_slowev);
950 return;
952 #endif
953 while (flayer && *lenp)
955 #ifdef COPY_PASTE
956 if (!pa && p && p->w_paster.pa_pastelen && flayer == p->w_paster.pa_pastelayer)
958 debug("layer is busy - beep!\n");
959 WBell(p, visual_bell);
960 *bufp += *lenp;
961 *lenp = 0;
962 display = d;
963 return;
965 #endif
966 oldlen = *lenp;
967 LayProcess(bufp, lenp);
968 #ifdef COPY_PASTE
969 if (pa && !pa->pa_pastelayer)
970 break; /* flush rest of paste */
971 #endif
972 if (*lenp == oldlen)
974 if (pa)
976 display = d;
977 return;
979 /* We're full, let's beep */
980 debug("layer is full - beep!\n");
981 WBell(p, visual_bell);
982 break;
985 *bufp += *lenp;
986 *lenp = 0;
987 display = d;
988 #ifdef COPY_PASTE
989 if (pa && pa->pa_pastelen == 0)
990 FreePaster(pa);
991 #endif
995 FindCommnr(str)
996 const char *str;
998 int x, m, l = 0, r = RC_LAST;
999 while (l <= r)
1001 m = (l + r) / 2;
1002 x = strcmp(str, comms[m].name);
1003 if (x > 0)
1004 l = m + 1;
1005 else if (x < 0)
1006 r = m - 1;
1007 else
1008 return m;
1010 return RC_ILLEGAL;
1013 static int
1014 CheckArgNum(nr, args)
1015 int nr;
1016 char **args;
1018 int i, n;
1019 static char *argss[] = {"no", "one", "two", "three", "four", "OOPS"};
1020 static char *orformat[] =
1022 "%s: %s: %s argument%s required",
1023 "%s: %s: %s or %s argument%s required",
1024 "%s: %s: %s, %s or %s argument%s required",
1025 "%s: %s: %s, %s, %s or %s argument%s required"
1028 n = comms[nr].flags & ARGS_MASK;
1029 for (i = 0; args[i]; i++)
1031 if (comms[nr].flags & ARGS_ORMORE)
1033 if (i < n)
1035 Msg(0, "%s: %s: at least %s argument%s required",
1036 rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
1037 return -1;
1040 else if ((comms[nr].flags & ARGS_PLUS1) &&
1041 (comms[nr].flags & ARGS_PLUS2) &&
1042 (comms[nr].flags & ARGS_PLUS3))
1044 if (i != n && i != n + 1 && i != n + 2 && i != n + 3)
1046 Msg(0, orformat[3], rc_name, comms[nr].name, argss[n],
1047 argss[n + 1], argss[n + 2], argss[n + 3], "");
1048 return -1;
1051 else if ((comms[nr].flags & ARGS_PLUS1) &&
1052 (comms[nr].flags & ARGS_PLUS2))
1054 if (i != n && i != n + 1 && i != n + 2)
1056 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1057 argss[n + 1], argss[n + 2], "");
1058 return -1;
1061 else if ((comms[nr].flags & ARGS_PLUS1) &&
1062 (comms[nr].flags & ARGS_PLUS3))
1064 if (i != n && i != n + 1 && i != n + 3)
1066 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1067 argss[n + 1], argss[n + 3], "");
1068 return -1;
1071 else if ((comms[nr].flags & ARGS_PLUS2) &&
1072 (comms[nr].flags & ARGS_PLUS3))
1074 if (i != n && i != n + 2 && i != n + 3)
1076 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1077 argss[n + 2], argss[n + 3], "");
1078 return -1;
1081 else if (comms[nr].flags & ARGS_PLUS1)
1083 if (i != n && i != n + 1)
1085 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1086 argss[n + 1], n != 0 ? "s" : "");
1087 return -1;
1090 else if (comms[nr].flags & ARGS_PLUS2)
1092 if (i != n && i != n + 2)
1094 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1095 argss[n + 2], "s");
1096 return -1;
1099 else if (comms[nr].flags & ARGS_PLUS3)
1101 if (i != n && i != n + 3)
1103 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1104 argss[n + 3], "");
1105 return -1;
1108 else if (i != n)
1110 Msg(0, orformat[0], rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
1111 return -1;
1113 return i;
1116 static void
1117 StuffFin(buf, len, data)
1118 char *buf;
1119 int len;
1120 char *data;
1122 if (!flayer)
1123 return;
1124 while(len)
1125 LayProcess(&buf, &len);
1128 /*ARGSUSED*/
1129 void
1130 DoAction(act, key)
1131 struct action *act;
1132 int key;
1134 int nr = act->nr;
1135 char **args = act->args;
1136 int *argl = act->argl;
1137 struct win *p;
1138 int argc, i, n, msgok;
1139 char *s;
1140 char ch;
1141 struct display *odisplay = display;
1142 struct acluser *user;
1144 user = display ? D_user : users;
1145 if (nr == RC_ILLEGAL)
1147 debug1("key '%c': No action\n", key);
1148 return;
1150 n = comms[nr].flags;
1151 /* Commands will have a CAN_QUERY flag, depending on whether they have
1152 * something to return on a query. For example, 'windows' can return a result,
1153 * but 'other' cannot.
1154 * If some command causes an error, then it should reset queryflag to -1, so that
1155 * the process requesting the query can be notified that an error happened.
1157 if (!(n & CAN_QUERY) && queryflag >= 0)
1159 /* Query flag is set, but this command cannot be queried. */
1160 Msg(0, "%s command cannot be queried.", comms[nr].name);
1161 queryflag = -1;
1162 return;
1164 if ((n & NEED_DISPLAY) && display == 0)
1166 Msg(0, "%s: %s: display required", rc_name, comms[nr].name);
1167 queryflag = -1;
1168 return;
1170 if ((n & NEED_FORE) && fore == 0)
1172 Msg(0, "%s: %s: window required", rc_name, comms[nr].name);
1173 queryflag = -1;
1174 return;
1176 if ((n & NEED_LAYER) && flayer == 0)
1178 Msg(0, "%s: %s: display or window required", rc_name, comms[nr].name);
1179 queryflag = -1;
1180 return;
1182 if ((argc = CheckArgNum(nr, args)) < 0)
1183 return;
1184 #ifdef MULTIUSER
1185 if (display)
1187 if (AclCheckPermCmd(D_user, ACL_EXEC, &comms[nr]))
1189 Msg(0, "%s: %s: permission denied (user %s)",
1190 rc_name, comms[nr].name, (EffectiveAclUser ? EffectiveAclUser : D_user)->u_name);
1191 queryflag = -1;
1192 return;
1195 #endif /* MULTIUSER */
1197 msgok = display && !*rc_name;
1198 switch(nr)
1200 case RC_SELECT:
1201 if (!*args)
1202 InputSelect();
1203 else if (args[0][0] == '-' && !args[0][1])
1205 SetForeWindow((struct win *)0);
1206 Activate(0);
1208 else if (args[0][0] == '.' && !args[0][1])
1210 if (!fore)
1212 Msg(0, "select . needs a window");
1213 queryflag = -1;
1215 else
1217 SetForeWindow(fore);
1218 Activate(0);
1221 else if (ParseWinNum(act, &n) == 0)
1222 SwitchWindow(n);
1223 else if (queryflag >= 0)
1224 queryflag = -1; /* ParseWinNum already prints out an appropriate error message. */
1225 break;
1226 #ifdef AUTO_NUKE
1227 case RC_DEFAUTONUKE:
1228 if (ParseOnOff(act, &defautonuke) == 0 && msgok)
1229 Msg(0, "Default autonuke turned %s", defautonuke ? "on" : "off");
1230 if (display && *rc_name)
1231 D_auto_nuke = defautonuke;
1232 break;
1233 case RC_AUTONUKE:
1234 if (ParseOnOff(act, &D_auto_nuke) == 0 && msgok)
1235 Msg(0, "Autonuke turned %s", D_auto_nuke ? "on" : "off");
1236 break;
1237 #endif
1238 case RC_DEFOBUFLIMIT:
1239 if (ParseNum(act, &defobuflimit) == 0 && msgok)
1240 Msg(0, "Default limit set to %d", defobuflimit);
1241 if (display && *rc_name)
1243 D_obufmax = defobuflimit;
1244 D_obuflenmax = D_obuflen - D_obufmax;
1246 break;
1247 case RC_OBUFLIMIT:
1248 if (*args == 0)
1249 Msg(0, "Limit is %d, current buffer size is %d", D_obufmax, D_obuflen);
1250 else if (ParseNum(act, &D_obufmax) == 0 && msgok)
1251 Msg(0, "Limit set to %d", D_obufmax);
1252 D_obuflenmax = D_obuflen - D_obufmax;
1253 break;
1254 case RC_DUMPTERMCAP:
1255 WriteFile(user, (char *)0, DUMP_TERMCAP);
1256 break;
1257 case RC_HARDCOPY:
1259 int mode = DUMP_HARDCOPY;
1261 if (argc > 1 && !strcmp(*args, "-h"))
1263 mode = DUMP_SCROLLBACK;
1264 args++;
1265 argc--;
1267 if (*args && args[1])
1269 Msg(0, "%s: hardcopy: too many arguments", rc_name);
1270 break;
1272 if (fore == 0 && *args == 0)
1273 Msg(0, "%s: hardcopy: window required", rc_name);
1274 else
1275 WriteFile(user, *args, mode);
1277 break;
1278 case RC_DEFLOG:
1279 (void)ParseOnOff(act, &nwin_default.Lflag);
1280 break;
1281 case RC_LOG:
1282 n = fore->w_log ? 1 : 0;
1283 ParseSwitch(act, &n);
1284 LogToggle(n);
1285 break;
1286 #ifdef BSDJOBS
1287 case RC_SUSPEND:
1288 Detach(D_STOP);
1289 break;
1290 #endif
1291 case RC_NEXT:
1292 if (MoreWindows())
1293 SwitchWindow(NextWindow());
1294 break;
1295 case RC_PREV:
1296 if (MoreWindows())
1297 SwitchWindow(PreviousWindow());
1298 break;
1299 case RC_KILL:
1301 char *name;
1303 if (key >= 0)
1305 #ifdef PSEUDOS
1306 Input(fore->w_pwin ? "Really kill this filter [y/n]" : "Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL);
1307 #else
1308 Input("Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL);
1309 #endif
1310 break;
1312 n = fore->w_number;
1313 #ifdef PSEUDOS
1314 if (fore->w_pwin)
1316 FreePseudowin(fore);
1317 Msg(0, "Filter removed.");
1318 break;
1320 #endif
1321 name = SaveStr(fore->w_title);
1322 KillWindow(fore);
1323 Msg(0, "Window %d (%s) killed.", n, name);
1324 if (name)
1325 free(name);
1326 break;
1328 case RC_QUIT:
1329 if (key >= 0)
1331 Input("Really quit and kill all your windows [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_QUIT);
1332 break;
1334 Finit(0);
1335 /* NOTREACHED */
1336 #ifdef DETACH
1337 case RC_DETACH:
1338 if (*args && !strcmp(*args, "-h"))
1339 Hangup();
1340 else
1341 Detach(D_DETACH);
1342 break;
1343 # ifdef POW_DETACH
1344 case RC_POW_DETACH:
1345 if (key >= 0)
1347 static char buf[2];
1349 buf[0] = key;
1350 Input(buf, 1, INP_RAW, pow_detach_fn, NULL, 0);
1352 else
1353 Detach(D_POWER); /* detach and kill Attacher's parent */
1354 break;
1355 # endif
1356 #endif
1357 case RC_DEBUG:
1358 #ifdef DEBUG
1359 if (!*args)
1361 if (dfp)
1362 Msg(0, "debugging info is written to %s/", DEBUGDIR);
1363 else
1364 Msg(0, "debugging is currently off. Use 'debug on' to enable.");
1365 break;
1367 if (dfp)
1369 debug("debug: closing debug file.\n");
1370 fflush(dfp);
1371 fclose(dfp);
1372 dfp = NULL;
1374 if (strcmp("off", *args))
1375 opendebug(0, 1);
1376 # ifdef SIG_NODEBUG
1377 else if (display)
1378 kill(D_userpid, SIG_NODEBUG); /* a one shot item, but hey... */
1379 # endif /* SIG_NODEBUG */
1380 #else
1381 if (*args == 0 || strcmp("off", *args))
1382 Msg(0, "Sorry, screen was compiled without -DDEBUG option.");
1383 #endif
1384 break;
1385 #ifdef ZMODEM
1386 case RC_ZMODEM:
1387 if (*args && !strcmp(*args, "sendcmd"))
1389 if (args[1])
1391 free(zmodem_sendcmd);
1392 zmodem_sendcmd = SaveStr(args[1]);
1394 if (msgok)
1395 Msg(0, "zmodem sendcmd: %s", zmodem_sendcmd);
1396 break;
1398 if (*args && !strcmp(*args, "recvcmd"))
1400 if (args[1])
1402 free(zmodem_recvcmd);
1403 zmodem_recvcmd = SaveStr(args[1]);
1405 if (msgok)
1406 Msg(0, "zmodem recvcmd: %s", zmodem_recvcmd);
1407 break;
1409 if (*args)
1411 for (i = 0; i < 4; i++)
1412 if (!strcmp(zmodes[i], *args))
1413 break;
1414 if (i == 4 && !strcmp(*args, "on"))
1415 i = 1;
1416 if (i == 4)
1418 Msg(0, "usage: zmodem off|auto|catch|pass");
1419 break;
1421 zmodem_mode = i;
1423 if (msgok)
1424 Msg(0, "zmodem mode is %s", zmodes[zmodem_mode]);
1425 break;
1426 #endif
1427 case RC_UNBINDALL:
1429 register unsigned int i;
1431 for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
1432 ClearAction(&ktab[i]);
1433 Msg(0, "Unbound all keys." );
1434 break;
1436 case RC_ZOMBIE:
1438 if (!(s = *args))
1440 ZombieKey_destroy = 0;
1441 break;
1443 if (*argl == 0 || *argl > 2)
1445 Msg(0, "%s:zombie: one or two characters expected.", rc_name);
1446 break;
1448 if (args[1])
1450 if (!strcmp(args[1], "onerror"))
1452 ZombieKey_onerror = 1;
1453 } else {
1454 Msg(0, "usage: zombie [keys [onerror]]");
1455 break;
1457 } else
1458 ZombieKey_onerror = 0;
1459 ZombieKey_destroy = args[0][0];
1460 ZombieKey_resurrect = *argl == 2 ? args[0][1] : 0;
1462 break;
1463 case RC_WALL:
1464 #ifdef MULTIUSER
1465 s = D_user->u_name;
1466 #else
1467 s = D_usertty;
1468 #endif
1470 struct display *olddisplay = display;
1471 display = 0; /* no display will cause a broadcast */
1472 Msg(0, "%s: %s", s, *args);
1473 display = olddisplay;
1475 break;
1476 case RC_AT:
1477 /* where this AT command comes from: */
1478 if (!user)
1479 break;
1480 #ifdef MULTIUSER
1481 s = SaveStr(user->u_name);
1482 /* DO NOT RETURN FROM HERE WITHOUT RESETTING THIS: */
1483 EffectiveAclUser = user;
1484 #else
1485 s = SaveStr(display ? D_usertty : user->u_name);
1486 #endif
1487 n = strlen(args[0]);
1488 if (n) n--;
1490 * the windows/displays loops are quite dangerous here, take extra
1491 * care not to trigger landmines. Things may appear/disappear while
1492 * we are walking along.
1494 switch (args[0][n])
1496 case '*': /* user */
1498 struct display *nd;
1499 struct acluser *u;
1501 if (!n)
1502 u = user;
1503 else
1505 for (u = users; u; u = u->u_next)
1507 debug3("strncmp('%s', '%s', %d)\n", *args, u->u_name, n);
1508 if (!strncmp(*args, u->u_name, n))
1509 break;
1511 if (!u)
1513 args[0][n] = '\0';
1514 Msg(0, "Did not find any user matching '%s'", args[0]);
1515 break;
1518 debug1("at all displays of user %s\n", u->u_name);
1519 for (display = displays; display; display = nd)
1521 nd = display->d_next;
1522 if (D_forecv == 0)
1523 continue;
1524 flayer = D_forecv->c_layer;
1525 fore = D_fore;
1526 if (D_user != u)
1527 continue;
1528 debug1("AT display %s\n", D_usertty);
1529 DoCommand(args + 1, argl + 1);
1530 if (display)
1531 Msg(0, "command from %s: %s %s",
1532 s, args[1], args[2] ? args[2] : "");
1533 display = NULL;
1534 flayer = 0;
1535 fore = NULL;
1537 break;
1539 case '%': /* display */
1541 struct display *nd;
1543 debug1("at display matching '%s'\n", args[0]);
1544 for (display = displays; display; display = nd)
1546 nd = display->d_next;
1547 if (D_forecv == 0)
1548 continue;
1549 fore = D_fore;
1550 flayer = D_forecv->c_layer;
1551 if (strncmp(args[0], D_usertty, n) &&
1552 (strncmp("/dev/", D_usertty, 5) ||
1553 strncmp(args[0], D_usertty + 5, n)) &&
1554 (strncmp("/dev/tty", D_usertty, 8) ||
1555 strncmp(args[0], D_usertty + 8, n)))
1556 continue;
1557 debug1("AT display %s\n", D_usertty);
1558 DoCommand(args + 1, argl + 1);
1559 if (display)
1560 Msg(0, "command from %s: %s %s",
1561 s, args[1], args[2] ? args[2] : "");
1562 display = NULL;
1563 fore = NULL;
1564 flayer = 0;
1566 break;
1568 case '#': /* window */
1569 n--;
1570 /* FALLTHROUGH */
1571 default:
1573 struct win *nw;
1574 int ch;
1576 n++;
1577 ch = args[0][n];
1578 args[0][n] = '\0';
1579 if (!*args[0] || (i = WindowByNumber(args[0])) < 0)
1581 args[0][n] = ch; /* must restore string in case of bind */
1582 /* try looping over titles */
1583 for (fore = windows; fore; fore = nw)
1585 nw = fore->w_next;
1586 if (strncmp(args[0], fore->w_title, n))
1587 continue;
1588 debug2("AT window %d(%s)\n", fore->w_number, fore->w_title);
1590 * consider this a bug or a feature:
1591 * while looping through windows, we have fore AND
1592 * display context. This will confuse users who try to
1593 * set up loops inside of loops, but often allows to do
1594 * what you mean, even when you adress your context wrong.
1596 i = 0;
1597 /* XXX: other displays? */
1598 if (fore->w_layer.l_cvlist)
1599 display = fore->w_layer.l_cvlist->c_display;
1600 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1601 DoCommand(args + 1, argl + 1); /* may destroy our display */
1602 if (fore && fore->w_layer.l_cvlist)
1604 display = fore->w_layer.l_cvlist->c_display;
1605 Msg(0, "command from %s: %s %s",
1606 s, args[1], args[2] ? args[2] : "");
1609 display = NULL;
1610 fore = NULL;
1611 if (i < 0)
1612 Msg(0, "%s: at '%s': no such window.\n", rc_name, args[0]);
1613 break;
1615 else if (i < maxwin && (fore = wtab[i]))
1617 args[0][n] = ch; /* must restore string in case of bind */
1618 debug2("AT window %d (%s)\n", fore->w_number, fore->w_title);
1619 if (fore->w_layer.l_cvlist)
1620 display = fore->w_layer.l_cvlist->c_display;
1621 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1622 DoCommand(args + 1, argl + 1);
1623 if (fore && fore->w_layer.l_cvlist)
1625 display = fore->w_layer.l_cvlist->c_display;
1626 Msg(0, "command from %s: %s %s",
1627 s, args[1], args[2] ? args[2] : "");
1629 display = NULL;
1630 fore = NULL;
1632 else
1633 Msg(0, "%s: at [identifier][%%|*|#] command [args]", rc_name);
1634 break;
1637 free(s);
1638 #ifdef MULTIUSER
1639 EffectiveAclUser = NULL;
1640 #endif
1641 break;
1643 #ifdef COPY_PASTE
1644 case RC_READREG:
1645 #ifdef ENCODINGS
1646 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
1647 if (args[0] && args[1] && !strcmp(args[0], "-e"))
1649 i = FindEncoding(args[1]);
1650 if (i == -1)
1652 Msg(0, "%s: readreg: unknown encoding", rc_name);
1653 break;
1655 args += 2;
1657 #endif
1659 * Without arguments we prompt for a destination register.
1660 * It will receive the copybuffer contents.
1661 * This is not done by RC_PASTE, as we prompt for source
1662 * (not dest) there.
1664 if ((s = *args) == NULL)
1666 Input("Copy to register:", 1, INP_RAW, copy_reg_fn, NULL, 0);
1667 break;
1669 if (*argl != 1)
1671 Msg(0, "%s: copyreg: character, ^x, or (octal) \\032 expected.", rc_name);
1672 break;
1674 ch = args[0][0];
1676 * With two arguments we *really* read register contents from file
1678 if (args[1])
1680 if (args[2])
1682 Msg(0, "%s: readreg: too many arguments", rc_name);
1683 break;
1685 if ((s = ReadFile(args[1], &n)))
1687 struct plop *pp = plop_tab + (int)(unsigned char)ch;
1689 if (pp->buf)
1690 free(pp->buf);
1691 pp->buf = s;
1692 pp->len = n;
1693 #ifdef ENCODINGS
1694 pp->enc = i;
1695 #endif
1698 else
1700 * with one argument we copy the copybuffer into a specified register
1701 * This could be done with RC_PASTE too, but is here to be consistent
1702 * with the zero argument call.
1704 copy_reg_fn(&ch, 0, NULL);
1705 break;
1706 #endif
1707 case RC_REGISTER:
1708 #ifdef ENCODINGS
1709 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
1710 if (args[0] && args[1] && !strcmp(args[0], "-e"))
1712 i = FindEncoding(args[1]);
1713 if (i == -1)
1715 Msg(0, "%s: register: unknown encoding", rc_name);
1716 break;
1718 args += 2;
1719 argc -= 2;
1721 #endif
1722 if (argc != 2)
1724 Msg(0, "%s: register: illegal number of arguments.", rc_name);
1725 break;
1727 if (*argl != 1)
1729 Msg(0, "%s: register: character, ^x, or (octal) \\032 expected.", rc_name);
1730 break;
1732 ch = args[0][0];
1733 #ifdef COPY_PASTE
1734 if (ch == '.')
1736 if (user->u_plop.buf != NULL)
1737 UserFreeCopyBuffer(user);
1738 if (args[1] && args[1][0])
1740 user->u_plop.buf = SaveStrn(args[1], argl[1]);
1741 user->u_plop.len = argl[1];
1742 #ifdef ENCODINGS
1743 user->u_plop.enc = i;
1744 #endif
1747 else
1748 #endif
1750 struct plop *plp = plop_tab + (int)(unsigned char)ch;
1752 if (plp->buf)
1753 free(plp->buf);
1754 plp->buf = SaveStrn(args[1], argl[1]);
1755 plp->len = argl[1];
1756 #ifdef ENCODINGS
1757 plp->enc = i;
1758 #endif
1760 break;
1761 case RC_PROCESS:
1762 if ((s = *args) == NULL)
1764 Input("Process register:", 1, INP_RAW, process_fn, NULL, 0);
1765 break;
1767 if (*argl != 1)
1769 Msg(0, "%s: process: character, ^x, or (octal) \\032 expected.", rc_name);
1770 break;
1772 ch = args[0][0];
1773 process_fn(&ch, 0, NULL);
1774 break;
1775 case RC_STUFF:
1776 s = *args;
1777 if (!args[0])
1779 Input("Stuff:", 100, INP_COOKED, StuffFin, NULL, 0);
1780 break;
1782 n = *argl;
1783 if (args[1])
1785 if (strcmp(s, "-k"))
1787 Msg(0, "%s: stuff: invalid option %s", rc_name, s);
1788 break;
1790 s = args[1];
1791 for (i = T_CAPS; i < T_OCAPS; i++)
1792 if (strcmp(term[i].tcname, s) == 0)
1793 break;
1794 if (i == T_OCAPS)
1796 Msg(0, "%s: stuff: unknown key '%s'", rc_name, s);
1797 break;
1799 #ifdef MAPKEYS
1800 if (StuffKey(i - T_CAPS) == 0)
1801 break;
1802 #endif
1803 s = display ? D_tcs[i].str : 0;
1804 if (s == 0)
1805 break;
1806 n = strlen(s);
1808 while(n)
1809 LayProcess(&s, &n);
1810 break;
1811 case RC_REDISPLAY:
1812 Activate(-1);
1813 break;
1814 case RC_WINDOWS:
1815 ShowWindows(-1);
1816 break;
1817 case RC_VERSION:
1818 Msg(0, "screen %s", version);
1819 break;
1820 case RC_TIME:
1821 if (*args)
1823 timestring = SaveStr(*args);
1824 break;
1826 Msg(0, "%s", MakeWinMsg(timestring, fore, '%'));
1827 break;
1828 case RC_INFO:
1829 ShowInfo();
1830 break;
1831 case RC_DINFO:
1832 ShowDInfo();
1833 break;
1834 case RC_COMMAND:
1836 struct action *ktabp = ktab;
1837 if (argc == 2 && !strcmp(*args, "-c"))
1839 if ((ktabp = FindKtab(args[1], 0)) == 0)
1841 Msg(0, "Unknown command class '%s'", args[1]);
1842 break;
1845 if (D_ESCseen != ktab || ktabp != ktab)
1847 D_ESCseen = ktabp;
1848 break;
1850 D_ESCseen = 0;
1852 /* FALLTHROUGH */
1853 case RC_OTHER:
1854 if (MoreWindows())
1855 SwitchWindow(display && D_other ? D_other->w_number : NextWindow());
1856 break;
1857 case RC_META:
1858 if (user->u_Esc == -1)
1859 break;
1860 ch = user->u_Esc;
1861 s = &ch;
1862 n = 1;
1863 LayProcess(&s, &n);
1864 break;
1865 case RC_XON:
1866 ch = Ctrl('q');
1867 s = &ch;
1868 n = 1;
1869 LayProcess(&s, &n);
1870 break;
1871 case RC_XOFF:
1872 ch = Ctrl('s');
1873 s = &ch;
1874 n = 1;
1875 LayProcess(&s, &n);
1876 break;
1877 case RC_DEFBREAKTYPE:
1878 case RC_BREAKTYPE:
1880 static char *types[] = { "TIOCSBRK", "TCSBRK", "tcsendbreak", NULL };
1881 extern int breaktype;
1883 if (*args)
1885 if (ParseNum(act, &n))
1886 for (n = 0; n < (int)(sizeof(types)/sizeof(*types)); n++)
1888 for (i = 0; i < 4; i++)
1890 ch = args[0][i];
1891 if (ch >= 'a' && ch <= 'z')
1892 ch -= 'a' - 'A';
1893 if (ch != types[n][i] && (ch + ('a' - 'A')) != types[n][i])
1894 break;
1896 if (i == 4)
1897 break;
1899 if (n < 0 || n >= (int)(sizeof(types)/sizeof(*types)))
1900 Msg(0, "%s invalid, chose one of %s, %s or %s", *args, types[0], types[1], types[2]);
1901 else
1903 breaktype = n;
1904 Msg(0, "breaktype set to (%d) %s", n, types[n]);
1907 else
1908 Msg(0, "breaktype is (%d) %s", breaktype, types[breaktype]);
1910 break;
1911 case RC_POW_BREAK:
1912 case RC_BREAK:
1913 n = 0;
1914 if (*args && ParseNum(act, &n))
1915 break;
1916 SendBreak(fore, n, nr == RC_POW_BREAK);
1917 break;
1918 #ifdef LOCK
1919 case RC_LOCKSCREEN:
1920 Detach(D_LOCK);
1921 break;
1922 #endif
1923 case RC_WIDTH:
1924 case RC_HEIGHT:
1926 int w, h;
1927 int what = 0;
1929 i = 1;
1930 if (*args && !strcmp(*args, "-w"))
1931 what = 1;
1932 else if (*args && !strcmp(*args, "-d"))
1933 what = 2;
1934 if (what)
1935 args++;
1936 if (what == 0 && flayer && !display)
1937 what = 1;
1938 if (what == 1)
1940 if (!flayer)
1942 Msg(0, "%s: %s: window required", rc_name, comms[nr].name);
1943 break;
1945 w = flayer->l_width;
1946 h = flayer->l_height;
1948 else
1950 if (!display)
1952 Msg(0, "%s: %s: display required", rc_name, comms[nr].name);
1953 break;
1955 w = D_width;
1956 h = D_height;
1958 if (*args && args[0][0] == '-')
1960 Msg(0, "%s: %s: unknown option %s", rc_name, comms[nr].name, *args);
1961 break;
1963 if (nr == RC_HEIGHT)
1965 if (!*args)
1967 #define H0height 42
1968 #define H1height 24
1969 if (h == H0height)
1970 h = H1height;
1971 else if (h == H1height)
1972 h = H0height;
1973 else if (h > (H0height + H1height) / 2)
1974 h = H0height;
1975 else
1976 h = H1height;
1978 else
1980 h = atoi(*args);
1981 if (args[1])
1982 w = atoi(args[1]);
1985 else
1987 if (!*args)
1989 if (w == Z0width)
1990 w = Z1width;
1991 else if (w == Z1width)
1992 w = Z0width;
1993 else if (w > (Z0width + Z1width) / 2)
1994 w = Z0width;
1995 else
1996 w = Z1width;
1998 else
2000 w = atoi(*args);
2001 if (args[1])
2002 h = atoi(args[1]);
2005 if (*args && args[1] && args[2])
2007 Msg(0, "%s: %s: too many arguments", rc_name, comms[nr].name);
2008 break;
2010 if (w <= 0)
2012 Msg(0, "Illegal width");
2013 break;
2015 if (h <= 0)
2017 Msg(0, "Illegal height");
2018 break;
2020 if (what == 1)
2022 if (flayer->l_width == w && flayer->l_height == h)
2023 break;
2024 ResizeLayer(flayer, w, h, (struct display *)0);
2025 break;
2027 if (D_width == w && D_height == h)
2028 break;
2029 if (what == 2)
2031 ChangeScreenSize(w, h, 1);
2033 else
2035 if (ResizeDisplay(w, h) == 0)
2037 Activate(D_fore ? D_fore->w_norefresh : 0);
2038 /* autofit */
2039 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0);
2040 break;
2042 if (h == D_height)
2043 Msg(0, "Your termcap does not specify how to change the terminal's width to %d.", w);
2044 else if (w == D_width)
2045 Msg(0, "Your termcap does not specify how to change the terminal's height to %d.", h);
2046 else
2047 Msg(0, "Your termcap does not specify how to change the terminal's resolution to %dx%d.", w, h);
2050 break;
2051 case RC_TITLE:
2052 if (queryflag >= 0)
2054 if (fore)
2055 Msg(0, "%s", fore->w_title);
2056 else
2057 queryflag = -1;
2059 if (*args == 0)
2060 InputAKA();
2061 else
2062 ChangeAKA(fore, *args, strlen(*args));
2063 break;
2064 case RC_COLON:
2065 Input(":", 100, INP_EVERY, Colonfin, NULL, 0);
2066 if (*args && **args)
2068 s = *args;
2069 n = strlen(s);
2070 LayProcess(&s, &n);
2072 break;
2073 case RC_LASTMSG:
2074 if (D_status_lastmsg)
2075 Msg(0, "%s", D_status_lastmsg);
2076 break;
2077 case RC_SCREEN:
2078 DoScreen("key", args);
2079 break;
2080 case RC_WRAP:
2081 if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok)
2082 Msg(0, "%cwrap", fore->w_wrap ? '+' : '-');
2083 break;
2084 case RC_FLOW:
2085 if (*args)
2087 if (args[0][0] == 'a')
2089 fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
2091 else
2093 if (ParseOnOff(act, &n))
2094 break;
2095 fore->w_flow = (fore->w_flow & FLOW_AUTO) | n;
2098 else
2100 if (fore->w_flow & FLOW_AUTOFLAG)
2101 fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW;
2102 else if (fore->w_flow & FLOW_NOW)
2103 fore->w_flow &= ~FLOW_NOW;
2104 else
2105 fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
2107 SetFlow(fore->w_flow & FLOW_NOW);
2108 if (msgok)
2109 Msg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-',
2110 (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : "");
2111 break;
2112 #ifdef MULTIUSER
2113 case RC_DEFWRITELOCK:
2114 if (args[0][0] == 'a')
2115 nwin_default.wlock = WLOCK_AUTO;
2116 else
2118 if (ParseOnOff(act, &n))
2119 break;
2120 nwin_default.wlock = n ? WLOCK_ON : WLOCK_OFF;
2122 break;
2123 case RC_WRITELOCK:
2124 if (*args)
2126 if (args[0][0] == 'a')
2128 fore->w_wlock = WLOCK_AUTO;
2130 else
2132 if (ParseOnOff(act, &n))
2133 break;
2134 fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF;
2137 * user may have permission to change the writelock setting,
2138 * but he may never aquire the lock himself without write permission
2140 if (!AclCheckPermWin(D_user, ACL_WRITE, fore))
2141 fore->w_wlockuser = D_user;
2143 Msg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" :
2144 ((fore->w_wlock == WLOCK_OFF) ? "off" : "on"));
2145 break;
2146 #endif
2147 case RC_CLEAR:
2148 ResetAnsiState(fore);
2149 WriteString(fore, "\033[H\033[J", 6);
2150 break;
2151 case RC_RESET:
2152 ResetAnsiState(fore);
2153 #ifdef ZMODEM
2154 if (fore->w_zdisplay)
2155 zmodem_abort(fore, fore->w_zdisplay);
2156 #endif
2157 WriteString(fore, "\033c", 2);
2158 break;
2159 case RC_MONITOR:
2160 n = fore->w_monitor != MON_OFF;
2161 #ifdef MULTIUSER
2162 if (display)
2163 n = n && (ACLBYTE(fore->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id));
2164 #endif
2165 if (ParseSwitch(act, &n))
2166 break;
2167 if (n)
2169 #ifdef MULTIUSER
2170 if (display) /* we tell only this user */
2171 ACLBYTE(fore->w_mon_notify, D_user->u_id) |= ACLBIT(D_user->u_id);
2172 else
2173 for (i = 0; i < maxusercount; i++)
2174 ACLBYTE(fore->w_mon_notify, i) |= ACLBIT(i);
2175 #endif
2176 if (fore->w_monitor == MON_OFF)
2177 fore->w_monitor = MON_ON;
2178 Msg(0, "Window %d (%s) is now being monitored for all activity.", fore->w_number, fore->w_title);
2180 else
2182 #ifdef MULTIUSER
2183 if (display) /* we remove only this user */
2184 ACLBYTE(fore->w_mon_notify, D_user->u_id)
2185 &= ~ACLBIT(D_user->u_id);
2186 else
2187 for (i = 0; i < maxusercount; i++)
2188 ACLBYTE(fore->w_mon_notify, i) &= ~ACLBIT(i);
2189 for (i = maxusercount - 1; i >= 0; i--)
2190 if (ACLBYTE(fore->w_mon_notify, i))
2191 break;
2192 if (i < 0)
2193 #endif
2194 fore->w_monitor = MON_OFF;
2195 Msg(0, "Window %d (%s) is no longer being monitored for activity.", fore->w_number, fore->w_title);
2197 break;
2198 #ifdef MULTI
2199 case RC_DISPLAYS:
2200 display_displays();
2201 break;
2202 #endif
2203 case RC_WINDOWLIST:
2204 if (!*args)
2205 display_wlist(0, WLIST_NUM, (struct win *)0);
2206 else if (!strcmp(*args, "string"))
2208 if (args[1])
2210 if (wliststr)
2211 free(wliststr);
2212 wliststr = SaveStr(args[1]);
2214 if (msgok)
2215 Msg(0, "windowlist string is '%s'", wliststr);
2217 else if (!strcmp(*args, "title"))
2219 if (args[1])
2221 if (wlisttit)
2222 free(wlisttit);
2223 wlisttit = SaveStr(args[1]);
2225 if (msgok)
2226 Msg(0, "windowlist title is '%s'", wlisttit);
2228 else
2230 int flag = 0;
2231 int blank = 0;
2232 for (i = 0; i < argc; i++)
2233 if (!args[i])
2234 continue;
2235 else if (!strcmp(args[i], "-m"))
2236 flag |= WLIST_MRU;
2237 else if (!strcmp(args[i], "-b"))
2238 blank = 1;
2239 else if (!strcmp(args[i], "-g"))
2240 flag |= WLIST_NESTED;
2241 else
2243 Msg(0, "usage: windowlist [-b] [-g] [-m] [string [string] | title [title]]");
2244 break;
2246 if (i == argc)
2247 display_wlist(blank, flag, (struct win *)0);
2249 break;
2250 case RC_HELP:
2251 if (argc == 2 && !strcmp(*args, "-c"))
2253 struct action *ktabp;
2254 if ((ktabp = FindKtab(args[1], 0)) == 0)
2256 Msg(0, "Unknown command class '%s'", args[1]);
2257 break;
2259 display_help(args[1], ktabp);
2261 else
2262 display_help((char *)0, ktab);
2263 break;
2264 case RC_LICENSE:
2265 display_copyright();
2266 break;
2267 #ifdef COPY_PASTE
2268 case RC_COPY:
2269 if (flayer->l_layfn != &WinLf)
2271 Msg(0, "Must be on a window layer");
2272 break;
2274 MarkRoutine();
2275 WindowChanged(fore, 'P');
2276 break;
2277 case RC_HISTORY:
2279 static char *pasteargs[] = {".", 0};
2280 static int pasteargl[] = {1};
2282 if (flayer->l_layfn != &WinLf)
2284 Msg(0, "Must be on a window layer");
2285 break;
2287 if (GetHistory() == 0)
2288 break;
2289 if (user->u_plop.buf == NULL)
2290 break;
2291 args = pasteargs;
2292 argl = pasteargl;
2294 /*FALLTHROUGH*/
2295 case RC_PASTE:
2297 char *ss, *dbuf, dch;
2298 int l = 0;
2299 # ifdef ENCODINGS
2300 int enc = -1;
2301 # endif
2304 * without args we prompt for one(!) register to be pasted in the window
2306 if ((s = *args) == NULL)
2308 Input("Paste from register:", 1, INP_RAW, ins_reg_fn, NULL, 0);
2309 break;
2311 if (args[1] == 0 && !fore) /* no window? */
2312 break;
2314 * with two arguments we paste into a destination register
2315 * (no window needed here).
2317 if (args[1] && argl[1] != 1)
2319 Msg(0, "%s: paste destination: character, ^x, or (octal) \\032 expected.",
2320 rc_name);
2321 break;
2323 # ifdef ENCODINGS
2324 else if (fore)
2325 enc = fore->w_encoding;
2326 # endif
2329 * measure length of needed buffer
2331 for (ss = s = *args; (ch = *ss); ss++)
2333 if (ch == '.')
2335 # ifdef ENCODINGS
2336 if (enc == -1)
2337 enc = user->u_plop.enc;
2338 if (enc != user->u_plop.enc)
2339 l += RecodeBuf((unsigned char *)user->u_plop.buf, user->u_plop.len, user->u_plop.enc, enc, (unsigned char *)0);
2340 else
2341 # endif
2342 l += user->u_plop.len;
2344 else
2346 # ifdef ENCODINGS
2347 if (enc == -1)
2348 enc = plop_tab[(int)(unsigned char)ch].enc;
2349 if (enc != plop_tab[(int)(unsigned char)ch].enc)
2350 l += RecodeBuf((unsigned char *)plop_tab[(int)(unsigned char)ch].buf, plop_tab[(int)(unsigned char)ch].len, plop_tab[(int)(unsigned char)ch].enc, enc, (unsigned char *)0);
2351 else
2352 # endif
2353 l += plop_tab[(int)(unsigned char)ch].len;
2356 if (l == 0)
2358 Msg(0, "empty buffer");
2359 break;
2362 * shortcut:
2363 * if there is only one source and the destination is a window, then
2364 * pass a pointer rather than duplicating the buffer.
2366 if (s[1] == 0 && args[1] == 0)
2367 # ifdef ENCODINGS
2368 if (enc == (*s == '.' ? user->u_plop.enc : plop_tab[(int)(unsigned char)*s].enc))
2369 # endif
2371 MakePaster(&fore->w_paster, *s == '.' ? user->u_plop.buf : plop_tab[(int)(unsigned char)*s].buf, l, 0);
2372 break;
2375 * if no shortcut, we construct a buffer
2377 if ((dbuf = (char *)malloc(l)) == 0)
2379 Msg(0, strnomem);
2380 break;
2382 l = 0;
2384 * concatenate all sources into our own buffer, copy buffer is
2385 * special and is skipped if no display exists.
2387 for (ss = s; (ch = *ss); ss++)
2389 struct plop *pp = (ch == '.' ? &user->u_plop : &plop_tab[(int)(unsigned char)ch]);
2390 #ifdef ENCODINGS
2391 if (pp->enc != enc)
2393 l += RecodeBuf((unsigned char *)pp->buf, pp->len, pp->enc, enc, (unsigned char *)dbuf + l);
2394 continue;
2396 #endif
2397 bcopy(pp->buf, dbuf + l, pp->len);
2398 l += pp->len;
2401 * when called with one argument we paste our buffer into the window
2403 if (args[1] == 0)
2405 MakePaster(&fore->w_paster, dbuf, l, 1);
2407 else
2410 * we have two arguments, the second is already in dch.
2411 * use this as destination rather than the window.
2413 dch = args[1][0];
2414 if (dch == '.')
2416 if (user->u_plop.buf != NULL)
2417 UserFreeCopyBuffer(user);
2418 user->u_plop.buf = dbuf;
2419 user->u_plop.len = l;
2420 #ifdef ENCODINGS
2421 user->u_plop.enc = enc;
2422 #endif
2424 else
2426 struct plop *pp = plop_tab + (int)(unsigned char)dch;
2427 if (pp->buf)
2428 free(pp->buf);
2429 pp->buf = dbuf;
2430 pp->len = l;
2431 #ifdef ENCODINGS
2432 pp->enc = enc;
2433 #endif
2436 break;
2438 case RC_WRITEBUF:
2439 if (!user->u_plop.buf)
2441 Msg(0, "empty buffer");
2442 break;
2444 #ifdef ENCODINGS
2446 struct plop oldplop;
2448 oldplop = user->u_plop;
2449 if (args[0] && args[1] && !strcmp(args[0], "-e"))
2451 int enc, l;
2452 char *newbuf;
2454 enc = FindEncoding(args[1]);
2455 if (enc == -1)
2457 Msg(0, "%s: writebuf: unknown encoding", rc_name);
2458 break;
2460 if (enc != oldplop.enc)
2462 l = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)0);
2463 newbuf = malloc(l + 1);
2464 if (!newbuf)
2466 Msg(0, strnomem);
2467 break;
2469 user->u_plop.len = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)newbuf);
2470 user->u_plop.buf = newbuf;
2471 user->u_plop.enc = enc;
2473 args += 2;
2475 #endif
2476 if (args[0] && args[1])
2477 Msg(0, "%s: writebuf: too many arguments", rc_name);
2478 else
2479 WriteFile(user, args[0], DUMP_EXCHANGE);
2480 #ifdef ENCODINGS
2481 if (user->u_plop.buf != oldplop.buf)
2482 free(user->u_plop.buf);
2483 user->u_plop = oldplop;
2485 #endif
2486 break;
2487 case RC_READBUF:
2488 #ifdef ENCODINGS
2489 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
2490 if (args[0] && args[1] && !strcmp(args[0], "-e"))
2492 i = FindEncoding(args[1]);
2493 if (i == -1)
2495 Msg(0, "%s: readbuf: unknown encoding", rc_name);
2496 break;
2498 args += 2;
2500 #endif
2501 if (args[0] && args[1])
2503 Msg(0, "%s: readbuf: too many arguments", rc_name);
2504 break;
2506 if ((s = ReadFile(args[0] ? args[0] : BufferFile, &n)))
2508 if (user->u_plop.buf)
2509 UserFreeCopyBuffer(user);
2510 user->u_plop.len = n;
2511 user->u_plop.buf = s;
2512 #ifdef ENCODINGS
2513 user->u_plop.enc = i;
2514 #endif
2516 break;
2517 case RC_REMOVEBUF:
2518 KillBuffers();
2519 break;
2520 case RC_IGNORECASE:
2521 (void)ParseSwitch(act, &search_ic);
2522 if (msgok)
2523 Msg(0, "Will %signore case in searches", search_ic ? "" : "not ");
2524 break;
2525 #endif /* COPY_PASTE */
2526 case RC_ESCAPE:
2527 if (*argl == 0)
2528 SetEscape(user, -1, -1);
2529 else if (*argl == 2)
2530 SetEscape(user, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]);
2531 else
2533 Msg(0, "%s: two characters required after escape.", rc_name);
2534 break;
2536 /* Change defescape if master user. This is because we only
2537 * have one ktab.
2539 if (display && user != users)
2540 break;
2541 /* FALLTHROUGH */
2542 case RC_DEFESCAPE:
2543 if (*argl == 0)
2544 SetEscape(NULL, -1, -1);
2545 else if (*argl == 2)
2546 SetEscape(NULL, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]);
2547 else
2549 Msg(0, "%s: two characters required after defescape.", rc_name);
2550 break;
2552 #ifdef MAPKEYS
2553 CheckEscape();
2554 #endif
2555 break;
2556 case RC_CHDIR:
2557 s = *args ? *args : home;
2558 if (chdir(s) == -1)
2559 Msg(errno, "%s", s);
2560 break;
2561 case RC_SHELL:
2562 case RC_DEFSHELL:
2563 if (ParseSaveStr(act, &ShellProg) == 0)
2564 ShellArgs[0] = ShellProg;
2565 break;
2566 case RC_HARDCOPYDIR:
2567 if (*args)
2568 (void)ParseSaveStr(act, &hardcopydir);
2569 if (msgok)
2570 Msg(0, "hardcopydir is %s\n", hardcopydir && *hardcopydir ? hardcopydir : "<cwd>");
2571 break;
2572 case RC_LOGFILE:
2573 if (*args)
2575 if (args[1] && !(strcmp(*args, "flush")))
2577 log_flush = atoi(args[1]);
2578 if (msgok)
2579 Msg(0, "log flush timeout set to %ds\n", log_flush);
2580 break;
2582 if (ParseSaveStr(act, &screenlogfile) || !msgok)
2583 break;
2585 Msg(0, "logfile is '%s'", screenlogfile);
2586 break;
2587 case RC_LOGTSTAMP:
2588 if (!*args || !strcmp(*args, "on") || !strcmp(*args, "off"))
2590 if (ParseSwitch(act, &logtstamp_on) == 0 && msgok)
2591 Msg(0, "timestamps turned %s", logtstamp_on ? "on" : "off");
2593 else if (!strcmp(*args, "string"))
2595 if (args[1])
2597 if (logtstamp_string)
2598 free(logtstamp_string);
2599 logtstamp_string = SaveStr(args[1]);
2601 if (msgok)
2602 Msg(0, "logfile timestamp is '%s'", logtstamp_string);
2604 else if (!strcmp(*args, "after"))
2606 if (args[1])
2608 logtstamp_after = atoi(args[1]);
2609 if (!msgok)
2610 break;
2612 Msg(0, "timestamp printed after %ds\n", logtstamp_after);
2614 else
2615 Msg(0, "usage: logtstamp [after [n]|string [str]|on|off]");
2616 break;
2617 case RC_SHELLTITLE:
2618 (void)ParseSaveStr(act, &nwin_default.aka);
2619 break;
2620 case RC_TERMCAP:
2621 case RC_TERMCAPINFO:
2622 case RC_TERMINFO:
2623 if (!rc_name || !*rc_name)
2624 Msg(0, "Sorry, too late now. Place that in your .screenrc file.");
2625 break;
2626 case RC_SLEEP:
2627 break; /* Already handled */
2628 case RC_TERM:
2629 s = NULL;
2630 if (ParseSaveStr(act, &s))
2631 break;
2632 if (strlen(s) >= 20)
2634 Msg(0, "%s: term: argument too long ( < 20)", rc_name);
2635 free(s);
2636 break;
2638 strcpy(screenterm, s);
2639 free(s);
2640 debug1("screenterm set to %s\n", screenterm);
2641 MakeTermcap((display == 0));
2642 debug("new termcap made\n");
2643 break;
2644 case RC_ECHO:
2645 if (!msgok && (!rc_name || strcmp(rc_name, "-X")))
2646 break;
2648 * user typed ^A:echo... well, echo isn't FinishRc's job,
2649 * but as he wanted to test us, we show good will
2651 if (argc > 1 && !strcmp(*args, "-n"))
2653 args++;
2654 argc--;
2656 s = *args;
2657 if (argc > 1 && !strcmp(*args, "-p"))
2659 args++;
2660 argc--;
2661 s = *args;
2662 if (s)
2663 s = MakeWinMsg(s, fore, '%');
2665 if (s)
2666 Msg(0, "%s", s);
2667 else
2669 Msg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name);
2670 queryflag = -1;
2672 break;
2673 case RC_BELL:
2674 case RC_BELL_MSG:
2675 if (*args == 0)
2677 char buf[256];
2678 AddXChars(buf, sizeof(buf), BellString);
2679 Msg(0, "bell_msg is '%s'", buf);
2680 break;
2682 (void)ParseSaveStr(act, &BellString);
2683 break;
2684 #ifdef COPY_PASTE
2685 case RC_BUFFERFILE:
2686 if (*args == 0)
2687 BufferFile = SaveStr(DEFAULT_BUFFERFILE);
2688 else if (ParseSaveStr(act, &BufferFile))
2689 break;
2690 if (msgok)
2691 Msg(0, "Bufferfile is now '%s'", BufferFile);
2692 break;
2693 #endif
2694 case RC_ACTIVITY:
2695 (void)ParseSaveStr(act, &ActivityString);
2696 break;
2697 #if defined(DETACH) && defined(POW_DETACH)
2698 case RC_POW_DETACH_MSG:
2699 if (*args == 0)
2701 char buf[256];
2702 AddXChars(buf, sizeof(buf), PowDetachString);
2703 Msg(0, "pow_detach_msg is '%s'", buf);
2704 break;
2706 (void)ParseSaveStr(act, &PowDetachString);
2707 break;
2708 #endif
2709 #if defined(UTMPOK) && defined(LOGOUTOK)
2710 case RC_LOGIN:
2711 n = fore->w_slot != (slot_t)-1;
2712 if (*args && !strcmp(*args, "always"))
2714 fore->w_lflag = 3;
2715 if (!displays && n)
2716 SlotToggle(n);
2717 break;
2719 if (*args && !strcmp(*args, "attached"))
2721 fore->w_lflag = 1;
2722 if (!displays && n)
2723 SlotToggle(0);
2724 break;
2726 if (ParseSwitch(act, &n) == 0)
2727 SlotToggle(n);
2728 break;
2729 case RC_DEFLOGIN:
2730 if (!strcmp(*args, "always"))
2731 nwin_default.lflag |= 2;
2732 else if (!strcmp(*args, "attached"))
2733 nwin_default.lflag &= ~2;
2734 else
2735 (void)ParseOnOff(act, &nwin_default.lflag);
2736 break;
2737 #endif
2738 case RC_DEFFLOW:
2739 if (args[0] && args[1] && args[1][0] == 'i')
2741 iflag = 1;
2742 for (display = displays; display; display = display->d_next)
2744 if (!D_flow)
2745 continue;
2746 #if defined(TERMIO) || defined(POSIX)
2747 D_NewMode.tio.c_cc[VINTR] = D_OldMode.tio.c_cc[VINTR];
2748 D_NewMode.tio.c_lflag |= ISIG;
2749 #else /* TERMIO || POSIX */
2750 D_NewMode.m_tchars.t_intrc = D_OldMode.m_tchars.t_intrc;
2751 #endif /* TERMIO || POSIX */
2752 SetTTY(D_userfd, &D_NewMode);
2755 if (args[0] && args[0][0] == 'a')
2756 nwin_default.flowflag = FLOW_AUTOFLAG;
2757 else
2758 (void)ParseOnOff(act, &nwin_default.flowflag);
2759 break;
2760 case RC_DEFWRAP:
2761 (void)ParseOnOff(act, &nwin_default.wrap);
2762 break;
2763 case RC_DEFC1:
2764 (void)ParseOnOff(act, &nwin_default.c1);
2765 break;
2766 #ifdef COLOR
2767 case RC_DEFBCE:
2768 (void)ParseOnOff(act, &nwin_default.bce);
2769 break;
2770 #endif
2771 case RC_DEFGR:
2772 (void)ParseOnOff(act, &nwin_default.gr);
2773 break;
2774 case RC_DEFMONITOR:
2775 if (ParseOnOff(act, &n) == 0)
2776 nwin_default.monitor = (n == 0) ? MON_OFF : MON_ON;
2777 break;
2778 case RC_DEFMOUSETRACK:
2779 if (ParseOnOff(act, &n) == 0)
2780 defmousetrack = (n == 0) ? 0 : 1000;
2781 break;
2782 case RC_MOUSETRACK:
2783 if (!args[0])
2785 Msg(0, "Mouse tracking for this display is turned %s", D_mousetrack ? "on" : "off");
2787 else if (ParseOnOff(act, &n) == 0)
2789 D_mousetrack = n == 0 ? 0 : 1000;
2790 if (D_fore)
2791 MouseMode(D_fore->w_mouse);
2793 break;
2794 case RC_DEFSILENCE:
2795 if (ParseOnOff(act, &n) == 0)
2796 nwin_default.silence = (n == 0) ? SILENCE_OFF : SILENCE_ON;
2797 break;
2798 case RC_VERBOSE:
2799 if (!*args)
2800 Msg(0, "W%s echo command when creating windows.",
2801 VerboseCreate ? "ill" : "on't");
2802 else if (ParseOnOff(act, &n) == 0)
2803 VerboseCreate = n;
2804 break;
2805 case RC_HARDSTATUS:
2806 if (display)
2808 Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
2809 RemoveStatus();
2811 if (args[0] && strcmp(args[0], "on") && strcmp(args[0], "off"))
2813 struct display *olddisplay = display;
2814 int old_use, new_use = -1;
2816 s = args[0];
2817 if (!strncmp(s, "always", 6))
2818 s += 6;
2819 if (!strcmp(s, "lastline"))
2820 new_use = HSTATUS_LASTLINE;
2821 else if (!strcmp(s, "ignore"))
2822 new_use = HSTATUS_IGNORE;
2823 else if (!strcmp(s, "message"))
2824 new_use = HSTATUS_MESSAGE;
2825 else if (!strcmp(args[0], "string"))
2827 if (!args[1])
2829 char buf[256];
2830 AddXChars(buf, sizeof(buf), hstatusstring);
2831 Msg(0, "hardstatus string is '%s'", buf);
2832 break;
2835 else
2837 Msg(0, "%s: usage: hardstatus [always]lastline|ignore|message|string [string]", rc_name);
2838 break;
2840 if (new_use != -1)
2842 hardstatusemu = new_use | (s == args[0] ? 0 : HSTATUS_ALWAYS);
2843 for (display = displays; display; display = display->d_next)
2845 RemoveStatus();
2846 new_use = hardstatusemu & ~HSTATUS_ALWAYS;
2847 if (D_HS && s == args[0])
2848 new_use = HSTATUS_HS;
2849 ShowHStatus((char *)0);
2850 old_use = D_has_hstatus;
2851 D_has_hstatus = new_use;
2852 if ((new_use == HSTATUS_LASTLINE && old_use != HSTATUS_LASTLINE) || (new_use != HSTATUS_LASTLINE && old_use == HSTATUS_LASTLINE))
2853 ChangeScreenSize(D_width, D_height, 1);
2854 RefreshHStatus();
2857 if (args[1])
2859 if (hstatusstring)
2860 free(hstatusstring);
2861 hstatusstring = SaveStr(args[1]);
2862 for (display = displays; display; display = display->d_next)
2863 RefreshHStatus();
2865 display = olddisplay;
2866 break;
2868 (void)ParseSwitch(act, &use_hardstatus);
2869 if (msgok)
2870 Msg(0, "messages displayed on %s", use_hardstatus ? "hardstatus line" : "window");
2871 break;
2872 case RC_CAPTION:
2873 if (strcmp(args[0], "always") == 0 || strcmp(args[0], "splitonly") == 0)
2875 struct display *olddisplay = display;
2877 captionalways = args[0][0] == 'a';
2878 for (display = displays; display; display = display->d_next)
2879 ChangeScreenSize(D_width, D_height, 1);
2880 display = olddisplay;
2882 else if (strcmp(args[0], "string") == 0)
2884 if (!args[1])
2886 char buf[256];
2887 AddXChars(buf, sizeof(buf), captionstring);
2888 Msg(0, "caption string is '%s'", buf);
2889 break;
2892 else
2894 Msg(0, "%s: usage: caption always|splitonly|string <string>", rc_name);
2895 break;
2897 if (!args[1])
2898 break;
2899 if (captionstring)
2900 free(captionstring);
2901 captionstring = SaveStr(args[1]);
2902 RedisplayDisplays(0);
2903 break;
2904 case RC_CONSOLE:
2905 n = (console_window != 0);
2906 if (ParseSwitch(act, &n))
2907 break;
2908 if (TtyGrabConsole(fore->w_ptyfd, n, rc_name))
2909 break;
2910 if (n == 0)
2911 Msg(0, "%s: releasing console %s", rc_name, HostName);
2912 else if (console_window)
2913 Msg(0, "%s: stealing console %s from window %d (%s)", rc_name,
2914 HostName, console_window->w_number, console_window->w_title);
2915 else
2916 Msg(0, "%s: grabbing console %s", rc_name, HostName);
2917 console_window = n ? fore : 0;
2918 break;
2919 case RC_ALLPARTIAL:
2920 if (ParseOnOff(act, &all_norefresh))
2921 break;
2922 if (!all_norefresh && fore)
2923 Activate(-1);
2924 if (msgok)
2925 Msg(0, all_norefresh ? "No refresh on window change!\n" :
2926 "Window specific refresh\n");
2927 break;
2928 case RC_PARTIAL:
2929 (void)ParseSwitch(act, &n);
2930 fore->w_norefresh = n;
2931 break;
2932 case RC_VBELL:
2933 if (ParseSwitch(act, &visual_bell) || !msgok)
2934 break;
2935 if (visual_bell == 0)
2936 Msg(0, "switched to audible bell.");
2937 else
2938 Msg(0, "switched to visual bell.");
2939 break;
2940 case RC_VBELLWAIT:
2941 if (ParseNum1000(act, &VBellWait) == 0 && msgok)
2942 Msg(0, "vbellwait set to %.10g seconds", VBellWait/1000.);
2943 break;
2944 case RC_MSGWAIT:
2945 if (ParseNum1000(act, &MsgWait) == 0 && msgok)
2946 Msg(0, "msgwait set to %.10g seconds", MsgWait/1000.);
2947 break;
2948 case RC_MSGMINWAIT:
2949 if (ParseNum1000(act, &MsgMinWait) == 0 && msgok)
2950 Msg(0, "msgminwait set to %.10g seconds", MsgMinWait/1000.);
2951 break;
2952 case RC_SILENCEWAIT:
2953 if (ParseNum(act, &SilenceWait))
2954 break;
2955 if (SilenceWait < 1)
2956 SilenceWait = 1;
2957 for (p = windows; p; p = p->w_next)
2958 p->w_silencewait = SilenceWait;
2959 if (msgok)
2960 Msg(0, "silencewait set to %d seconds", SilenceWait);
2961 break;
2962 case RC_NUMBER:
2963 if (*args == 0)
2964 Msg(0, queryflag >= 0 ? "%d (%s)" : "This is window %d (%s).", fore->w_number, fore->w_title);
2965 else
2967 int old = fore->w_number;
2968 int rel = 0, parse;
2969 if (args[0][0] == '+')
2970 rel = 1;
2971 else if (args[0][0] == '-')
2972 rel = -1;
2973 if (rel)
2974 ++act->args[0];
2975 parse = ParseNum(act, &n);
2976 if (rel)
2977 --act->args[0];
2978 if (parse)
2979 break;
2980 if (rel > 0)
2981 n += old;
2982 else if (rel < 0)
2983 n = old - n;
2984 if (n < 0 || n >= maxwin)
2986 Msg(0, "Given window position is invalid.");
2987 queryflag = -1;
2988 return;
2990 p = wtab[n];
2991 wtab[n] = fore;
2992 fore->w_number = n;
2993 wtab[old] = p;
2994 if (p)
2995 p->w_number = old;
2996 #ifdef MULTIUSER
2997 /* exchange the acls for these windows. */
2998 AclWinSwap(old, n);
2999 #endif
3000 #ifdef UTMPOK
3001 /* exchange the utmp-slots for these windows */
3002 if ((fore->w_slot != (slot_t) -1) && (fore->w_slot != (slot_t) 0))
3004 RemoveUtmp(fore);
3005 SetUtmp(fore);
3007 if (p && (p->w_slot != (slot_t) -1) && (p->w_slot != (slot_t) 0))
3009 /* XXX: first display wins? */
3010 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
3011 RemoveUtmp(p);
3012 SetUtmp(p);
3014 #endif
3016 WindowChanged(fore, 'n');
3017 WindowChanged((struct win *)0, 'w');
3018 WindowChanged((struct win *)0, 'W');
3019 WindowChanged((struct win *)0, 0);
3021 break;
3022 case RC_SILENCE:
3023 n = fore->w_silence != 0;
3024 i = fore->w_silencewait;
3025 if (args[0] && (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9')))
3027 if (ParseNum(act, &i))
3028 break;
3029 n = i > 0;
3031 else if (ParseSwitch(act, &n))
3032 break;
3033 if (n)
3035 #ifdef MULTIUSER
3036 if (display) /* we tell only this user */
3037 ACLBYTE(fore->w_lio_notify, D_user->u_id) |= ACLBIT(D_user->u_id);
3038 else
3039 for (n = 0; n < maxusercount; n++)
3040 ACLBYTE(fore->w_lio_notify, n) |= ACLBIT(n);
3041 #endif
3042 fore->w_silencewait = i;
3043 fore->w_silence = SILENCE_ON;
3044 SetTimeout(&fore->w_silenceev, fore->w_silencewait * 1000);
3045 evenq(&fore->w_silenceev);
3047 if (!msgok)
3048 break;
3049 Msg(0, "The window is now being monitored for %d sec. silence.", fore->w_silencewait);
3051 else
3053 #ifdef MULTIUSER
3054 if (display) /* we remove only this user */
3055 ACLBYTE(fore->w_lio_notify, D_user->u_id)
3056 &= ~ACLBIT(D_user->u_id);
3057 else
3058 for (n = 0; n < maxusercount; n++)
3059 ACLBYTE(fore->w_lio_notify, n) &= ~ACLBIT(n);
3060 for (i = maxusercount - 1; i >= 0; i--)
3061 if (ACLBYTE(fore->w_lio_notify, i))
3062 break;
3063 if (i < 0)
3064 #endif
3066 fore->w_silence = SILENCE_OFF;
3067 evdeq(&fore->w_silenceev);
3069 if (!msgok)
3070 break;
3071 Msg(0, "The window is no longer being monitored for silence.");
3073 break;
3074 #ifdef COPY_PASTE
3075 case RC_DEFSCROLLBACK:
3076 (void)ParseNum(act, &nwin_default.histheight);
3077 break;
3078 case RC_SCROLLBACK:
3079 if (flayer->l_layfn == &MarkLf)
3081 Msg(0, "Cannot resize scrollback buffer in copy/scrollback mode.");
3082 break;
3084 (void)ParseNum(act, &n);
3085 ChangeWindowSize(fore, fore->w_width, fore->w_height, n);
3086 if (msgok)
3087 Msg(0, "scrollback set to %d", fore->w_histheight);
3088 break;
3089 #endif
3090 case RC_SESSIONNAME:
3091 if (*args == 0)
3092 Msg(0, "This session is named '%s'\n", SockName);
3093 else
3095 char buf[MAXPATHLEN];
3097 s = 0;
3098 if (ParseSaveStr(act, &s))
3099 break;
3100 if (!*s || strlen(s) + (SockName - SockPath) > MAXPATHLEN - 13 || index(s, '/'))
3102 Msg(0, "%s: bad session name '%s'\n", rc_name, s);
3103 free(s);
3104 break;
3106 strncpy(buf, SockPath, SockName - SockPath);
3107 sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s);
3108 free(s);
3109 if ((access(buf, F_OK) == 0) || (errno != ENOENT))
3111 Msg(0, "%s: inappropriate path: '%s'.", rc_name, buf);
3112 break;
3114 if (rename(SockPath, buf))
3116 Msg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf);
3117 break;
3119 debug2("rename(%s, %s) done\n", SockPath, buf);
3120 strcpy(SockPath, buf);
3121 MakeNewEnv();
3122 WindowChanged((struct win *)0, 'S');
3124 break;
3125 case RC_SETENV:
3126 if (!args[0] || !args[1])
3128 debug1("RC_SETENV arguments missing: %s\n", args[0] ? args[0] : "");
3129 InputSetenv(args[0]);
3131 else
3133 xsetenv(args[0], args[1]);
3134 MakeNewEnv();
3136 break;
3137 case RC_UNSETENV:
3138 unsetenv(*args);
3139 MakeNewEnv();
3140 break;
3141 #ifdef COPY_PASTE
3142 case RC_DEFSLOWPASTE:
3143 (void)ParseNum(act, &nwin_default.slow);
3144 break;
3145 case RC_SLOWPASTE:
3146 if (*args == 0)
3147 Msg(0, fore->w_slowpaste ?
3148 "Slowpaste in window %d is %d milliseconds." :
3149 "Slowpaste in window %d is unset.",
3150 fore->w_number, fore->w_slowpaste);
3151 else if (ParseNum(act, &fore->w_slowpaste) == 0 && msgok)
3152 Msg(0, fore->w_slowpaste ?
3153 "Slowpaste in window %d set to %d milliseconds." :
3154 "Slowpaste in window %d now unset.",
3155 fore->w_number, fore->w_slowpaste);
3156 break;
3157 case RC_MARKKEYS:
3158 if (CompileKeys(*args, *argl, mark_key_tab))
3160 Msg(0, "%s: markkeys: syntax error.", rc_name);
3161 break;
3163 debug1("markkeys %s\n", *args);
3164 break;
3165 # ifdef FONT
3166 case RC_PASTEFONT:
3167 if (ParseSwitch(act, &pastefont) == 0 && msgok)
3168 Msg(0, "Will %spaste font settings", pastefont ? "" : "not ");
3169 break;
3170 # endif
3171 case RC_CRLF:
3172 (void)ParseSwitch(act, &join_with_cr);
3173 break;
3174 case RC_COMPACTHIST:
3175 if (ParseSwitch(act, &compacthist) == 0 && msgok)
3176 Msg(0, "%scompacting history lines", compacthist ? "" : "not ");
3177 break;
3178 #endif
3179 #ifdef NETHACK
3180 case RC_NETHACK:
3181 (void)ParseOnOff(act, &nethackflag);
3182 break;
3183 #endif
3184 case RC_HARDCOPY_APPEND:
3185 (void)ParseOnOff(act, &hardcopy_append);
3186 break;
3187 case RC_VBELL_MSG:
3188 if (*args == 0)
3190 char buf[256];
3191 AddXChars(buf, sizeof(buf), VisualBellString);
3192 Msg(0, "vbell_msg is '%s'", buf);
3193 break;
3195 (void)ParseSaveStr(act, &VisualBellString);
3196 debug1(" new vbellstr '%s'\n", VisualBellString);
3197 break;
3198 case RC_DEFMODE:
3199 if (ParseBase(act, *args, &n, 8, "octal"))
3200 break;
3201 if (n < 0 || n > 0777)
3203 Msg(0, "%s: mode: Invalid tty mode %o", rc_name, n);
3204 break;
3206 TtyMode = n;
3207 if (msgok)
3208 Msg(0, "Ttymode set to %03o", TtyMode);
3209 break;
3210 case RC_AUTODETACH:
3211 (void)ParseOnOff(act, &auto_detach);
3212 break;
3213 case RC_STARTUP_MESSAGE:
3214 (void)ParseOnOff(act, &default_startup);
3215 break;
3216 #ifdef PASSWORD
3217 case RC_PASSWORD:
3218 if (*args)
3220 n = (*user->u_password) ? 1 : 0;
3221 if (user->u_password != NullStr) free((char *)user->u_password);
3222 user->u_password = SaveStr(*args);
3223 if (!strcmp(user->u_password, "none"))
3225 if (n)
3226 Msg(0, "Password checking disabled");
3227 free(user->u_password);
3228 user->u_password = NullStr;
3231 else
3233 if (!fore)
3235 Msg(0, "%s: password: window required", rc_name);
3236 break;
3238 Input("New screen password:", 100, INP_NOECHO, pass1, display ? (char *)D_user : (char *)users, 0);
3240 break;
3241 #endif /* PASSWORD */
3242 case RC_BIND:
3244 struct action *ktabp = ktab;
3245 int kflag = 0;
3247 for (;;)
3249 if (argc > 2 && !strcmp(*args, "-c"))
3251 ktabp = FindKtab(args[1], 1);
3252 if (ktabp == 0)
3253 break;
3254 args += 2;
3255 argl += 2;
3256 argc -= 2;
3258 else if (argc > 1 && !strcmp(*args, "-k"))
3260 kflag = 1;
3261 args++;
3262 argl++;
3263 argc--;
3265 else
3266 break;
3268 #ifdef MAPKEYS
3269 if (kflag)
3271 for (n = 0; n < KMAP_KEYS; n++)
3272 if (strcmp(term[n + T_CAPS].tcname, *args) == 0)
3273 break;
3274 if (n == KMAP_KEYS)
3276 Msg(0, "%s: bind: unknown key '%s'", rc_name, *args);
3277 break;
3279 n += 256;
3281 else
3282 #endif
3283 if (*argl != 1)
3285 Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.", rc_name);
3286 break;
3288 else
3289 n = (unsigned char)args[0][0];
3291 if (args[1])
3293 if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
3295 Msg(0, "%s: bind: unknown command '%s'", rc_name, args[1]);
3296 break;
3298 if (CheckArgNum(i, args + 2) < 0)
3299 break;
3300 ClearAction(&ktabp[n]);
3301 SaveAction(ktabp + n, i, args + 2, argl + 2);
3303 else
3304 ClearAction(&ktabp[n]);
3306 break;
3307 #ifdef MAPKEYS
3308 case RC_BINDKEY:
3310 struct action *newact;
3311 int newnr, fl = 0, kf = 0, af = 0, df = 0, mf = 0;
3312 struct display *odisp = display;
3313 int used = 0;
3314 struct kmap_ext *kme;
3316 for (; *args && **args == '-'; args++, argl++)
3318 if (strcmp(*args, "-t") == 0)
3319 fl = KMAP_NOTIMEOUT;
3320 else if (strcmp(*args, "-k") == 0)
3321 kf = 1;
3322 else if (strcmp(*args, "-a") == 0)
3323 af = 1;
3324 else if (strcmp(*args, "-d") == 0)
3325 df = 1;
3326 else if (strcmp(*args, "-m") == 0)
3327 mf = 1;
3328 else if (strcmp(*args, "--") == 0)
3330 args++;
3331 argl++;
3332 break;
3334 else
3336 Msg(0, "%s: bindkey: invalid option %s", rc_name, *args);
3337 return;
3340 if (df && mf)
3342 Msg(0, "%s: bindkey: -d does not work with -m", rc_name);
3343 break;
3345 if (*args == 0)
3347 if (mf)
3348 display_bindkey("Edit mode", mmtab);
3349 else if (df)
3350 display_bindkey("Default", dmtab);
3351 else
3352 display_bindkey("User", umtab);
3353 break;
3355 if (kf == 0)
3357 if (af)
3359 Msg(0, "%s: bindkey: -a only works with -k", rc_name);
3360 break;
3362 if (*argl == 0)
3364 Msg(0, "%s: bindkey: empty string makes no sense", rc_name);
3365 break;
3367 for (i = 0, kme = kmap_exts; i < kmap_extn; i++, kme++)
3368 if (kme->str == 0)
3370 if (args[1])
3371 break;
3373 else
3374 if (*argl == (kme->fl & ~KMAP_NOTIMEOUT) && bcmp(kme->str, *args, *argl) == 0)
3375 break;
3376 if (i == kmap_extn)
3378 if (!args[1])
3380 Msg(0, "%s: bindkey: keybinding not found", rc_name);
3381 break;
3383 kmap_extn += 8;
3384 kmap_exts = (struct kmap_ext *)xrealloc((char *)kmap_exts, kmap_extn * sizeof(*kmap_exts));
3385 kme = kmap_exts + i;
3386 bzero((char *)kme, 8 * sizeof(*kmap_exts));
3387 for (; i < kmap_extn; i++, kme++)
3389 kme->str = 0;
3390 kme->dm.nr = kme->mm.nr = kme->um.nr = RC_ILLEGAL;
3391 kme->dm.args = kme->mm.args = kme->um.args = noargs;
3392 kme->dm.argl = kme->mm.argl = kme->um.argl = 0;
3394 i -= 8;
3395 kme -= 8;
3397 if (df == 0 && kme->dm.nr != RC_ILLEGAL)
3398 used = 1;
3399 if (mf == 0 && kme->mm.nr != RC_ILLEGAL)
3400 used = 1;
3401 if ((df || mf) && kme->um.nr != RC_ILLEGAL)
3402 used = 1;
3403 i += KMAP_KEYS + KMAP_AKEYS;
3404 newact = df ? &kme->dm : mf ? &kme->mm : &kme->um;
3406 else
3408 for (i = T_CAPS; i < T_OCAPS; i++)
3409 if (strcmp(term[i].tcname, *args) == 0)
3410 break;
3411 if (i == T_OCAPS)
3413 Msg(0, "%s: bindkey: unknown key '%s'", rc_name, *args);
3414 break;
3416 if (af && i >= T_CURSOR && i < T_OCAPS)
3417 i -= T_CURSOR - KMAP_KEYS;
3418 else
3419 i -= T_CAPS;
3420 newact = df ? &dmtab[i] : mf ? &mmtab[i] : &umtab[i];
3422 if (args[1])
3424 if ((newnr = FindCommnr(args[1])) == RC_ILLEGAL)
3426 Msg(0, "%s: bindkey: unknown command '%s'", rc_name, args[1]);
3427 break;
3429 if (CheckArgNum(newnr, args + 2) < 0)
3430 break;
3431 ClearAction(newact);
3432 SaveAction(newact, newnr, args + 2, argl + 2);
3433 if (kf == 0 && args[1])
3435 if (kme->str)
3436 free(kme->str);
3437 kme->str = SaveStrn(*args, *argl);
3438 kme->fl = fl | *argl;
3441 else
3442 ClearAction(newact);
3443 for (display = displays; display; display = display->d_next)
3444 remap(i, args[1] ? 1 : 0);
3445 if (kf == 0 && !args[1])
3447 if (!used && kme->str)
3449 free(kme->str);
3450 kme->str = 0;
3451 kme->fl = 0;
3454 display = odisp;
3456 break;
3457 case RC_MAPTIMEOUT:
3458 if (*args)
3460 if (ParseNum(act, &n))
3461 break;
3462 if (n < 0)
3464 Msg(0, "%s: maptimeout: illegal time %d", rc_name, n);
3465 break;
3467 maptimeout = n;
3469 if (*args == 0 || msgok)
3470 Msg(0, "maptimeout is %dms", maptimeout);
3471 break;
3472 case RC_MAPNOTNEXT:
3473 D_dontmap = 1;
3474 break;
3475 case RC_MAPDEFAULT:
3476 D_mapdefault = 1;
3477 break;
3478 #endif
3479 #ifdef MULTIUSER
3480 case RC_ACLCHG:
3481 case RC_ACLADD:
3482 case RC_ADDACL:
3483 case RC_CHACL:
3484 UsersAcl(NULL, argc, args);
3485 break;
3486 case RC_ACLDEL:
3487 if (UserDel(args[0], NULL))
3488 break;
3489 if (msgok)
3490 Msg(0, "%s removed from acl database", args[0]);
3491 break;
3492 case RC_ACLGRP:
3494 * modify a user to gain or lose rights granted to a group.
3495 * This group is actually a normal user whose rights were defined
3496 * with chacl in the usual way.
3498 if (args[1])
3500 if (strcmp(args[1], "none")) /* link a user to another user */
3502 if (AclLinkUser(args[0], args[1]))
3503 break;
3504 if (msgok)
3505 Msg(0, "User %s joined acl-group %s", args[0], args[1]);
3507 else /* remove all groups from user */
3509 struct acluser *u;
3510 struct aclusergroup *g;
3512 if (!(u = *FindUserPtr(args[0])))
3513 break;
3514 while ((g = u->u_group))
3516 u->u_group = g->next;
3517 free((char *)g);
3521 else /* show all groups of user */
3523 char buf[256], *p = buf;
3524 int ngroups = 0;
3525 struct acluser *u;
3526 struct aclusergroup *g;
3528 if (!(u = *FindUserPtr(args[0])))
3530 if (msgok)
3531 Msg(0, "User %s does not exist.", args[0]);
3532 break;
3534 g = u->u_group;
3535 while (g)
3537 ngroups++;
3538 sprintf(p, "%s ", g->u->u_name);
3539 p += strlen(p);
3540 if (p > buf+200)
3541 break;
3542 g = g->next;
3544 if (ngroups)
3545 *(--p) = '\0';
3546 Msg(0, "%s's group%s: %s.", args[0], (ngroups == 1) ? "" : "s",
3547 (ngroups == 0) ? "none" : buf);
3549 break;
3550 case RC_ACLUMASK:
3551 case RC_UMASK:
3552 while ((s = *args++))
3554 char *err = 0;
3556 if (AclUmask(display ? D_user : users, s, &err))
3557 Msg(0, "umask: %s\n", err);
3559 break;
3560 case RC_MULTIUSER:
3561 if (ParseOnOff(act, &n))
3562 break;
3563 multi = n ? "" : 0;
3564 chsock();
3565 if (msgok)
3566 Msg(0, "Multiuser mode %s", multi ? "enabled" : "disabled");
3567 break;
3568 #endif /* MULTIUSER */
3569 #ifdef PSEUDOS
3570 case RC_EXEC:
3571 winexec(args);
3572 break;
3573 #endif
3574 #ifdef MULTI
3575 case RC_NONBLOCK:
3576 i = D_nonblock >= 0;
3577 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.'))
3579 if (ParseNum1000(act, &i))
3580 break;
3582 else if (!ParseSwitch(act, &i))
3583 i = i == 0 ? -1 : 1000;
3584 else
3585 break;
3586 if (msgok && i == -1)
3587 Msg(0, "display set to blocking mode");
3588 else if (msgok && i == 0)
3589 Msg(0, "display set to nonblocking mode, no timeout");
3590 else if (msgok)
3591 Msg(0, "display set to nonblocking mode, %.10gs timeout", i/1000.);
3592 D_nonblock = i;
3593 if (D_nonblock <= 0)
3594 evdeq(&D_blockedev);
3595 break;
3596 case RC_DEFNONBLOCK:
3597 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.'))
3599 if (ParseNum1000(act, &defnonblock))
3600 break;
3602 else if (!ParseOnOff(act, &defnonblock))
3603 defnonblock = defnonblock == 0 ? -1 : 1000;
3604 else
3605 break;
3606 if (display && *rc_name)
3608 D_nonblock = defnonblock;
3609 if (D_nonblock <= 0)
3610 evdeq(&D_blockedev);
3612 break;
3613 #endif
3614 case RC_GR:
3615 #ifdef ENCODINGS
3616 if (fore->w_gr == 2)
3617 fore->w_gr = 0;
3618 #endif
3619 if (ParseSwitch(act, &fore->w_gr) == 0 && msgok)
3620 Msg(0, "Will %suse GR", fore->w_gr ? "" : "not ");
3621 #ifdef ENCODINGS
3622 if (fore->w_gr == 0 && fore->w_FontE)
3623 fore->w_gr = 2;
3624 #endif
3625 break;
3626 case RC_C1:
3627 if (ParseSwitch(act, &fore->w_c1) == 0 && msgok)
3628 Msg(0, "Will %suse C1", fore->w_c1 ? "" : "not ");
3629 break;
3630 #ifdef COLOR
3631 case RC_BCE:
3632 if (ParseSwitch(act, &fore->w_bce) == 0 && msgok)
3633 Msg(0, "Will %serase with background color", fore->w_bce ? "" : "not ");
3634 break;
3635 #endif
3636 #ifdef ENCODINGS
3637 case RC_KANJI:
3638 case RC_ENCODING:
3639 #ifdef UTF8
3640 if (*args && !strcmp(args[0], "-d"))
3642 if (!args[1])
3643 Msg(0, "encodings directory is %s", screenencodings ? screenencodings : "<unset>");
3644 else
3646 free(screenencodings);
3647 screenencodings = SaveStr(args[1]);
3649 break;
3651 if (*args && !strcmp(args[0], "-l"))
3653 if (!args[1])
3654 Msg(0, "encoding: -l: argument required");
3655 else if (LoadFontTranslation(-1, args[1]))
3656 Msg(0, "encoding: could not load utf8 encoding file");
3657 else if (msgok)
3658 Msg(0, "encoding: utf8 encoding file loaded");
3659 break;
3661 #else
3662 if (*args && (!strcmp(args[0], "-l") || !strcmp(args[0], "-d")))
3664 if (msgok)
3665 Msg(0, "encoding: screen is not compiled for UTF-8.");
3666 break;
3668 #endif
3669 for (i = 0; i < 2; i++)
3671 if (args[i] == 0)
3672 break;
3673 if (!strcmp(args[i], "."))
3674 continue;
3675 n = FindEncoding(args[i]);
3676 if (n == -1)
3678 Msg(0, "encoding: unknown encoding '%s'", args[i]);
3679 break;
3681 if (i == 0 && fore)
3683 WinSwitchEncoding(fore, n);
3684 ResetCharsets(fore);
3686 else if (i && display)
3687 D_encoding = n;
3689 break;
3690 case RC_DEFKANJI:
3691 case RC_DEFENCODING:
3692 n = FindEncoding(*args);
3693 if (n == -1)
3695 Msg(0, "defencoding: unknown encoding '%s'", *args);
3696 break;
3698 nwin_default.encoding = n;
3699 break;
3700 #endif
3702 #ifdef UTF8
3703 case RC_DEFUTF8:
3704 n = nwin_default.encoding == UTF8;
3705 if (ParseSwitch(act, &n) == 0)
3707 nwin_default.encoding = n ? UTF8 : 0;
3708 if (msgok)
3709 Msg(0, "Will %suse UTF-8 encoding for new windows", n ? "" : "not ");
3711 break;
3712 case RC_UTF8:
3713 for (i = 0; i < 2; i++)
3715 if (i && args[i] == 0)
3716 break;
3717 if (args[i] == 0)
3718 n = fore->w_encoding != UTF8;
3719 else if (strcmp(args[i], "off") == 0)
3720 n = 0;
3721 else if (strcmp(args[i], "on") == 0)
3722 n = 1;
3723 else
3725 Msg(0, "utf8: illegal argument (%s)", args[i]);
3726 break;
3728 if (i == 0)
3730 WinSwitchEncoding(fore, n ? UTF8 : 0);
3731 if (msgok)
3732 Msg(0, "Will %suse UTF-8 encoding", n ? "" : "not ");
3734 else if (display)
3735 D_encoding = n ? UTF8 : 0;
3736 if (args[i] == 0)
3737 break;
3739 break;
3740 #endif
3742 case RC_PRINTCMD:
3743 if (*args)
3745 if (printcmd)
3746 free(printcmd);
3747 printcmd = 0;
3748 if (**args)
3749 printcmd = SaveStr(*args);
3751 if (*args == 0 || msgok)
3753 if (printcmd)
3754 Msg(0, "using '%s' as print command", printcmd);
3755 else
3756 Msg(0, "using termcap entries for printing");
3757 break;
3759 break;
3761 case RC_DIGRAPH:
3762 if (argl && argl[0] > 0 && argl[1] > 0)
3764 if (argl[0] != 2)
3766 Msg(0, "Two characters expected to define a digraph");
3767 break;
3769 i = digraph_find(args[0]);
3770 digraphs[i].d[0] = args[0][0];
3771 digraphs[i].d[1] = args[0][1];
3772 if (!parse_input_int(args[1], argl[1], &digraphs[i].value))
3774 if (!(digraphs[i].value = atoi(args[1])))
3776 if (!args[1][1])
3777 digraphs[i].value = (int)args[1][0];
3778 #ifdef UTF8
3779 else
3781 int t;
3782 unsigned char *s = args[1];
3783 digraphs[i].value = 0;
3784 while (*s)
3786 t = FromUtf8(*s++, &digraphs[i].value);
3787 if (t == -1)
3788 continue;
3789 if (t == -2)
3790 digraphs[i].value = 0;
3791 else
3792 digraphs[i].value = t;
3793 break;
3796 #endif
3799 break;
3801 Input("Enter digraph: ", 10, INP_EVERY, digraph_fn, NULL, 0);
3802 if (*args && **args)
3804 s = *args;
3805 n = strlen(s);
3806 LayProcess(&s, &n);
3808 break;
3810 case RC_DEFHSTATUS:
3811 if (*args == 0)
3813 char buf[256];
3814 *buf = 0;
3815 if (nwin_default.hstatus)
3816 AddXChars(buf, sizeof(buf), nwin_default.hstatus);
3817 Msg(0, "default hstatus is '%s'", buf);
3818 break;
3820 (void)ParseSaveStr(act, &nwin_default.hstatus);
3821 if (*nwin_default.hstatus == 0)
3823 free(nwin_default.hstatus);
3824 nwin_default.hstatus = 0;
3826 break;
3827 case RC_HSTATUS:
3828 (void)ParseSaveStr(act, &fore->w_hstatus);
3829 if (*fore->w_hstatus == 0)
3831 free(fore->w_hstatus);
3832 fore->w_hstatus = 0;
3834 WindowChanged(fore, 'h');
3835 break;
3837 #ifdef FONT
3838 case RC_DEFCHARSET:
3839 case RC_CHARSET:
3840 if (*args == 0)
3842 char buf[256];
3843 *buf = 0;
3844 if (nwin_default.charset)
3845 AddXChars(buf, sizeof(buf), nwin_default.charset);
3846 Msg(0, "default charset is '%s'", buf);
3847 break;
3849 n = strlen(*args);
3850 if (n == 0 || n > 6)
3852 Msg(0, "%s: %s: string has illegal size.", rc_name, comms[nr].name);
3853 break;
3855 if (n > 4 && (
3856 ((args[0][4] < '0' || args[0][4] > '3') && args[0][4] != '.') ||
3857 ((args[0][5] < '0' || args[0][5] > '3') && args[0][5] && args[0][5] != '.')))
3859 Msg(0, "%s: %s: illegal mapping number.", rc_name, comms[nr].name);
3860 break;
3862 if (nr == RC_CHARSET)
3864 SetCharsets(fore, *args);
3865 break;
3867 if (nwin_default.charset)
3868 free(nwin_default.charset);
3869 nwin_default.charset = SaveStr(*args);
3870 break;
3871 #endif
3872 #ifdef COLOR
3873 case RC_ATTRCOLOR:
3874 s = args[0];
3875 if (*s >= '0' && *s <= '9')
3876 i = *s - '0';
3877 else
3878 for (i = 0; i < 8; i++)
3879 if (*s == "dubrsBiI"[i])
3880 break;
3881 s++;
3882 nr = 0;
3883 if (*s && s[1] && !s[2])
3885 if (*s == 'd' && s[1] == 'd')
3886 nr = 3;
3887 else if (*s == '.' && s[1] == 'd')
3888 nr = 2;
3889 else if (*s == 'd' && s[1] == '.')
3890 nr = 1;
3891 else if (*s != '.' || s[1] != '.')
3892 s--;
3893 s += 2;
3895 if (*s || i < 0 || i >= 8)
3897 Msg(0, "%s: attrcolor: unknown attribute '%s'.", rc_name, args[0]);
3898 break;
3900 n = 0;
3901 if (args[1])
3902 n = ParseAttrColor(args[1], args[2], 1);
3903 if (n == -1)
3904 break;
3905 attr2color[i][nr] = n;
3906 n = 0;
3907 for (i = 0; i < 8; i++)
3908 if (attr2color[i][0] || attr2color[i][1] || attr2color[i][2] || attr2color[i][3])
3909 n |= 1 << i;
3910 nattr2color = n;
3911 break;
3912 #endif
3913 case RC_RENDITION:
3914 i = -1;
3915 if (strcmp(args[0], "bell") == 0)
3917 i = REND_BELL;
3919 else if (strcmp(args[0], "monitor") == 0)
3921 i = REND_MONITOR;
3923 else if (strcmp(args[0], "so") != 0)
3925 Msg(0, "Invalid option '%s' for rendition", args[0]);
3926 break;
3929 ++args;
3930 ++argl;
3932 if (i != -1)
3934 renditions[i] = ParseAttrColor(args[0], args[1], 1);
3935 WindowChanged((struct win *)0, 'w');
3936 WindowChanged((struct win *)0, 'W');
3937 WindowChanged((struct win *)0, 0);
3938 break;
3941 /* We are here, means we want to set the sorendition. */
3942 /* FALLTHROUGH*/
3943 case RC_SORENDITION:
3944 i = 0;
3945 if (*args)
3947 i = ParseAttrColor(*args, args[1], 1);
3948 if (i == -1)
3949 break;
3950 ApplyAttrColor(i, &mchar_so);
3951 WindowChanged((struct win *)0, 0);
3952 debug2("--> %x %x\n", mchar_so.attr, mchar_so.color);
3954 if (msgok)
3955 #ifdef COLOR
3956 Msg(0, "Standout attributes 0x%02x color 0x%02x", (unsigned char)mchar_so.attr, 0x99 ^ (unsigned char)mchar_so.color);
3957 #else
3958 Msg(0, "Standout attributes 0x%02x ", (unsigned char)mchar_so.attr);
3959 #endif
3960 break;
3962 case RC_SOURCE:
3963 do_source(*args);
3964 break;
3966 #ifdef MULTIUSER
3967 case RC_SU:
3968 s = NULL;
3969 if (!*args)
3971 Msg(0, "%s:%s screen login", HostName, SockPath);
3972 InputSu(D_fore, &D_user, NULL);
3974 else if (!args[1])
3975 InputSu(D_fore, &D_user, args[0]);
3976 else if (!args[2])
3977 s = DoSu(&D_user, args[0], args[1], "\377");
3978 else
3979 s = DoSu(&D_user, args[0], args[1], args[2]);
3980 if (s)
3981 Msg(0, "%s", s);
3982 break;
3983 #endif /* MULTIUSER */
3984 case RC_SPLIT:
3985 s = args[0];
3986 if (s && !strcmp(s, "-v"))
3987 AddCanvas(SLICE_HORI);
3988 else
3989 AddCanvas(SLICE_VERT);
3990 Activate(-1);
3991 break;
3992 case RC_REMOVE:
3993 RemCanvas();
3994 Activate(-1);
3995 break;
3996 case RC_ONLY:
3997 OneCanvas();
3998 Activate(-1);
3999 break;
4000 case RC_FIT:
4001 D_forecv->c_xoff = D_forecv->c_xs;
4002 D_forecv->c_yoff = D_forecv->c_ys;
4003 RethinkViewportOffsets(D_forecv);
4004 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0);
4005 flayer = D_forecv->c_layer;
4006 LaySetCursor();
4007 break;
4008 case RC_FOCUS:
4010 struct canvas *cv = 0;
4011 if (!*args || !strcmp(*args, "next"))
4012 cv = D_forecv->c_next ? D_forecv->c_next : D_cvlist;
4013 else if (!strcmp(*args, "prev"))
4015 for (cv = D_cvlist; cv->c_next && cv->c_next != D_forecv; cv = cv->c_next)
4018 else if (!strcmp(*args, "top"))
4019 cv = D_cvlist;
4020 else if (!strcmp(*args, "bottom"))
4022 for (cv = D_cvlist; cv->c_next; cv = cv->c_next)
4025 else if (!strcmp(*args, "up"))
4026 cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ys - 1);
4027 else if (!strcmp(*args, "down"))
4028 cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ye + 2);
4029 else if (!strcmp(*args, "left"))
4030 cv = FindCanvas(D_forecv->c_xs - 1, D_forecv->c_ys);
4031 else if (!strcmp(*args, "right"))
4032 cv = FindCanvas(D_forecv->c_xe + 1, D_forecv->c_ys);
4033 else
4035 Msg(0, "%s: usage: focus [next|prev|up|down|left|right|top|bottom]", rc_name);
4036 break;
4038 SetForeCanvas(display, cv);
4040 break;
4041 case RC_RESIZE:
4042 i = 0;
4043 if (D_forecv->c_slorient == SLICE_UNKN)
4045 Msg(0, "resize: need more than one region");
4046 break;
4048 for (; *args; args++)
4050 if (!strcmp(*args, "-h"))
4051 i |= RESIZE_FLAG_H;
4052 else if (!strcmp(*args, "-v"))
4053 i |= RESIZE_FLAG_V;
4054 else if (!strcmp(*args, "-b"))
4055 i |= RESIZE_FLAG_H | RESIZE_FLAG_V;
4056 else if (!strcmp(*args, "-p"))
4057 i |= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V;
4058 else if (!strcmp(*args, "-l"))
4059 i |= RESIZE_FLAG_L;
4060 else
4061 break;
4063 if (*args && args[1])
4065 Msg(0, "%s: usage: resize [-h] [-v] [-l] [num]\n", rc_name);
4066 break;
4068 if (*args)
4069 ResizeRegions(*args, i);
4070 else
4071 Input(resizeprompts[i], 20, INP_EVERY, ResizeFin, (char*)0, i);
4072 break;
4073 case RC_SETSID:
4074 (void)ParseSwitch(act, &separate_sids);
4075 break;
4076 case RC_EVAL:
4077 args = SaveArgs(args);
4078 for (i = 0; args[i]; i++)
4080 if (args[i][0])
4081 Colonfin(args[i], strlen(args[i]), (char *)0);
4082 free(args[i]);
4084 free(args);
4085 break;
4086 case RC_ALTSCREEN:
4087 (void)ParseSwitch(act, &use_altscreen);
4088 if (msgok)
4089 Msg(0, "Will %sdo alternate screen switching", use_altscreen ? "" : "not ");
4090 break;
4091 case RC_MAXWIN:
4092 if (!args[0])
4094 Msg(0, "maximum windows allowed: %d", maxwin);
4095 break;
4097 if (ParseNum(act, &n))
4098 break;
4099 if (n < 1)
4100 Msg(0, "illegal maxwin number specified");
4101 else if (n > 2048)
4102 Msg(0, "maximum 2048 windows allowed");
4103 else if (n > maxwin && windows)
4104 Msg(0, "may increase maxwin only when there's no window");
4105 else
4107 if (!windows)
4108 wtab = realloc(wtab, n * sizeof(struct win));
4109 maxwin = n;
4111 break;
4112 case RC_BACKTICK:
4113 if (ParseBase(act, *args, &n, 10, "decimal"))
4114 break;
4115 if (!args[1])
4116 setbacktick(n, 0, 0, (char **)0);
4117 else
4119 int lifespan, tick;
4120 if (argc < 4)
4122 Msg(0, "%s: usage: backtick num [lifespan tick cmd args...]", rc_name);
4123 break;
4125 if (ParseBase(act, args[1], &lifespan, 10, "decimal"))
4126 break;
4127 if (ParseBase(act, args[2], &tick, 10, "decimal"))
4128 break;
4129 setbacktick(n, lifespan, tick, SaveArgs(args + 3));
4131 WindowChanged(0, '`');
4132 break;
4133 case RC_BLANKER:
4134 #ifdef BLANKER_PRG
4135 if (blankerprg)
4137 RunBlanker(blankerprg);
4138 break;
4140 #endif
4141 ClearAll();
4142 CursorVisibility(-1);
4143 D_blocked = 4;
4144 break;
4145 #ifdef BLANKER_PRG
4146 case RC_BLANKERPRG:
4147 if (!args[0])
4149 if (blankerprg)
4151 char path[MAXPATHLEN];
4152 char *p = path, **pp;
4153 for (pp = blankerprg; *pp; pp++)
4154 p += snprintf(p, sizeof(path) - (p - path) - 1, "%s ", *pp);
4155 *(p - 1) = '\0';
4156 Msg(0, "blankerprg: %s", path);
4158 else
4159 Msg(0, "No blankerprg set.");
4160 break;
4162 if (blankerprg)
4164 char **pp;
4165 for (pp = blankerprg; *pp; pp++)
4166 free(*pp);
4167 free(blankerprg);
4168 blankerprg = 0;
4170 if (args[0][0])
4171 blankerprg = SaveArgs(args);
4172 break;
4173 #endif
4174 case RC_IDLE:
4175 if (*args)
4177 struct display *olddisplay = display;
4178 if (!strcmp(*args, "off"))
4179 idletimo = 0;
4180 else if (args[0][0])
4181 idletimo = atoi(*args) * 1000;
4182 if (argc > 1)
4184 if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
4186 Msg(0, "%s: idle: unknown command '%s'", rc_name, args[1]);
4187 break;
4189 if (CheckArgNum(i, args + 2) < 0)
4190 break;
4191 ClearAction(&idleaction);
4192 SaveAction(&idleaction, i, args + 2, argl + 2);
4194 for (display = displays; display; display = display->d_next)
4195 ResetIdle();
4196 display = olddisplay;
4198 if (msgok)
4200 if (idletimo)
4201 Msg(0, "idle timeout %ds, %s", idletimo / 1000, comms[idleaction.nr].name);
4202 else
4203 Msg(0, "idle off");
4205 break;
4206 case RC_FOCUSMINSIZE:
4207 for (i = 0; i < 2 && args[i]; i++)
4209 if (!strcmp(args[i], "max") || !strcmp(args[i], "_"))
4210 n = -1;
4211 else
4212 n = atoi(args[i]);
4213 if (i == 0)
4214 focusminwidth = n;
4215 else
4216 focusminheight = n;
4218 if (msgok)
4220 char b[2][20];
4221 for (i = 0; i < 2; i++)
4223 n = i == 0 ? focusminwidth : focusminheight;
4224 if (n == -1)
4225 strcpy(b[i], "max");
4226 else
4227 sprintf(b[i], "%d", n);
4229 Msg(0, "focus min size is %s %s\n", b[0], b[1]);
4231 break;
4232 case RC_GROUP:
4233 if (*args)
4235 fore->w_group = 0;
4236 if (args[0][0])
4238 fore->w_group = WindowByName(*args);
4239 if (fore->w_group && fore->w_group->w_type != W_TYPE_GROUP)
4240 fore->w_group = 0;
4242 WindowChanged((struct win *)0, 'w');
4243 WindowChanged((struct win *)0, 'W');
4244 WindowChanged((struct win *)0, 0);
4246 if (msgok)
4248 if (fore->w_group)
4249 Msg(0, "window group is %d (%s)\n", fore->w_group->w_number, fore->w_group->w_title);
4250 else
4251 Msg(0, "window belongs to no group");
4253 break;
4254 case RC_LAYOUT:
4255 if (!strcmp(args[0], "title"))
4257 if (!D_layout)
4259 Msg(0, "not on a layout");
4260 break;
4262 if (!args[1])
4264 Msg(0, "current layout is %d (%s)", D_layout->lay_number, D_layout->lay_title);
4265 break;
4267 free(D_layout->lay_title);
4268 D_layout->lay_title= SaveStr(args[1]);
4270 else if (!strcmp(args[0], "number"))
4272 int old;
4273 struct layout *lay;
4274 if (!D_layout)
4276 Msg(0, "not on a layout");
4277 break;
4279 if (!args[1])
4281 Msg(0, "This is layout %d (%s).\n", D_layout->lay_number, D_layout->lay_title);
4282 break;
4284 old = D_layout->lay_number;
4285 n = atoi(args[1]);
4286 if (n < 0 || n >= MAXLAY)
4287 break;
4288 lay = laytab[n];
4289 laytab[n] = D_layout;
4290 D_layout->lay_number = n;
4291 laytab[old] = lay;
4292 if (lay)
4293 lay->lay_number = old;
4294 break;
4296 else if (!strcmp(args[0], "autosave"))
4298 if (!D_layout)
4300 Msg(0, "not on a layout");
4301 break;
4303 if (args[1])
4305 if (!strcmp(args[1], "on"))
4306 D_layout->lay_autosave = 1;
4307 else if (!strcmp(args[1], "off"))
4308 D_layout->lay_autosave = 0;
4309 else
4311 Msg(0, "invalid argument. Give 'on' or 'off");
4312 break;
4315 if (msgok)
4316 Msg(0, "autosave is %s", D_layout->lay_autosave ? "on" : "off");
4318 else if (!strcmp(args[0], "new"))
4320 char *t = args[1];
4321 n = 0;
4322 if (t)
4324 while (*t >= '0' && *t <= '9')
4325 t++;
4326 if (t != args[1] && (!*t || *t == ':'))
4328 n = atoi(args[1]);
4329 if (*t)
4330 t++;
4332 else
4333 t = args[1];
4335 if (!t || !*t)
4336 t = "layout";
4337 NewLayout(t, n);
4338 Activate(-1);
4340 else if (!strcmp(args[0], "save"))
4342 if (!args[1])
4344 Msg(0, "usage: layout save <name>");
4345 break;
4347 SaveLayout(args[1], &D_canvas);
4349 else if (!strcmp(args[0], "select"))
4351 if (!args[1])
4353 Input("Switch to layout: ", 20, INP_COOKED, SelectLayoutFin, NULL, 0);
4354 break;
4356 SelectLayoutFin(args[1], strlen(args[1]), (char *)0);
4358 else if (!strcmp(args[0], "next"))
4360 struct layout *lay = D_layout;
4361 if (lay)
4362 lay = lay->lay_next ? lay->lay_next : layouts;
4363 else
4364 lay = layouts;
4365 if (!lay)
4367 Msg(0, "no layout defined");
4368 break;
4370 if (lay == D_layout)
4371 break;
4372 LoadLayout(lay, &D_canvas);
4373 Activate(-1);
4375 else if (!strcmp(args[0], "prev"))
4377 struct layout *lay = D_layout;
4378 if (lay)
4380 for (lay = layouts; lay->lay_next && lay->lay_next != D_layout; lay = lay->lay_next)
4383 else
4384 lay = layouts;
4385 if (!lay)
4387 Msg(0, "no layout defined");
4388 break;
4390 if (lay == D_layout)
4391 break;
4392 LoadLayout(lay, &D_canvas);
4393 Activate(-1);
4395 else if (!strcmp(args[0], "attach"))
4397 if (!args[1])
4399 if (!layout_attach)
4400 Msg(0, "no attach layout set");
4401 else if (layout_attach == &layout_last_marker)
4402 Msg(0, "will attach to last layout");
4403 else
4404 Msg(0, "will attach to layout %d (%s)", layout_attach->lay_number, layout_attach->lay_title);
4405 break;
4407 if (!strcmp(args[1], ":last"))
4408 layout_attach = &layout_last_marker;
4409 else if (!args[1][0])
4410 layout_attach = 0;
4411 else
4413 struct layout *lay;
4414 lay = FindLayout(args[1]);
4415 if (!lay)
4417 Msg(0, "unknown layout '%s'", args[1]);
4418 break;
4420 layout_attach = lay;
4423 else if (!strcmp(args[0], "show"))
4425 ShowLayouts(-1);
4427 else if (!strcmp(args[0], "remove"))
4429 struct layout *lay = display ? D_layout : layouts;
4430 if (args[1])
4432 lay = layouts ? FindLayout(args[1]) : (struct layout *)0;
4433 if (!lay)
4435 Msg(0, "unknown layout '%s'", args[1]);
4436 break;
4439 if (lay)
4440 RemoveLayout(lay);
4442 else if (!strcmp(args[0], "dump"))
4444 if (!display)
4445 Msg(0, "Must have a display for 'layout dump'.");
4446 else if (!LayoutDumpCanvas(&D_canvas, args[1] ? args[1] : "layout-dump"))
4447 Msg(errno, "Error dumping layout.");
4448 else
4449 Msg(0, "Layout dumped to \"%s\"", args[1] ? args[1] : "layout-dump");
4451 else
4452 Msg(0, "unknown layout subcommand");
4453 break;
4454 #ifdef DW_CHARS
4455 case RC_CJKWIDTH:
4456 if(ParseSwitch(act, &cjkwidth) == 0)
4458 if(msgok)
4459 Msg(0, "Treat ambiguous width characters as %s width", cjkwidth ? "full" : "half");
4461 break;
4462 #endif
4463 default:
4464 #ifdef HAVE_BRAILLE
4465 /* key == -2: input from braille keybord, msgok always 0 */
4466 DoBrailleAction(act, key == -2 ? 0 : msgok);
4467 #endif
4468 break;
4470 if (display != odisplay)
4472 for (display = displays; display; display = display->d_next)
4473 if (display == odisplay)
4474 break;
4478 void
4479 DoCommand(argv, argl)
4480 char **argv;
4481 int *argl;
4483 struct action act;
4484 const char *cmd = *argv;
4486 act.quiet = 0;
4487 if (*cmd == '@') /* Suppress error */
4489 act.quiet |= 0x01;
4490 cmd++;
4492 if (*cmd == '-') /* Suppress normal message */
4494 act.quiet |= 0x02;
4495 cmd++;
4498 if ((act.nr = FindCommnr(cmd)) == RC_ILLEGAL)
4500 Msg(0, "%s: unknown command '%s'", rc_name, cmd);
4501 return;
4503 act.args = argv + 1;
4504 act.argl = argl + 1;
4505 DoAction(&act, -1);
4508 static void
4509 SaveAction(act, nr, args, argl)
4510 struct action *act;
4511 int nr;
4512 char **args;
4513 int *argl;
4515 register int argc = 0;
4516 char **pp;
4517 int *lp;
4519 if (args)
4520 while (args[argc])
4521 argc++;
4522 if (argc == 0)
4524 act->nr = nr;
4525 act->args = noargs;
4526 act->argl = 0;
4527 return;
4529 if ((pp = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0)
4530 Panic(0, strnomem);
4531 if ((lp = (int *)malloc((unsigned)(argc) * sizeof(int *))) == 0)
4532 Panic(0, strnomem);
4533 act->nr = nr;
4534 act->args = pp;
4535 act->argl = lp;
4536 while (argc--)
4538 *lp = argl ? *argl++ : (int)strlen(*args);
4539 *pp++ = SaveStrn(*args++, *lp++);
4541 *pp = 0;
4544 static char **
4545 SaveArgs(args)
4546 char **args;
4548 register char **ap, **pp;
4549 register int argc = 0;
4551 while (args[argc])
4552 argc++;
4553 if ((pp = ap = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0)
4554 Panic(0, strnomem);
4555 while (argc--)
4556 *pp++ = SaveStr(*args++);
4557 *pp = 0;
4558 return ap;
4563 * buf is split into argument vector args.
4564 * leading whitespace is removed.
4565 * @!| abbreviations are expanded.
4566 * the end of buffer is recognized by '\0' or an un-escaped '#'.
4567 * " and ' are interpreted.
4569 * argc is returned.
4571 int
4572 Parse(buf, bufl, args, argl)
4573 char *buf, **args;
4574 int bufl, *argl;
4576 register char *p = buf, **ap = args, *pp;
4577 register int delim, argc;
4578 int *lp = argl;
4580 debug2("Parse %d %s\n", bufl, buf);
4581 argc = 0;
4582 pp = buf;
4583 delim = 0;
4584 for (;;)
4586 *lp = 0;
4587 while (*p && (*p == ' ' || *p == '\t'))
4588 ++p;
4589 #ifdef PSEUDOS
4590 if (argc == 0 && *p == '!')
4592 *ap++ = "exec";
4593 *lp++ = 4;
4594 p++;
4595 argc++;
4596 continue;
4598 #endif
4599 if (*p == '\0' || *p == '#' || *p == '\n')
4601 *p = '\0';
4602 for (delim = 0; delim < argc; delim++)
4603 debug1("-- %s\n", args[delim]);
4604 args[argc] = 0;
4605 return argc;
4607 if (++argc >= MAXARGS)
4609 Msg(0, "%s: too many tokens.", rc_name);
4610 return 0;
4612 *ap++ = pp;
4614 debug1("- new arg %s\n", p);
4615 while (*p)
4617 if (*p == delim)
4618 delim = 0;
4619 else if (delim != '\'' && *p == '\\' && (p[1] == 'n' || p[1] == 'r' || p[1] == 't' || p[1] == '\'' || p[1] == '"' || p[1] == '\\' || p[1] == '$' || p[1] == '#' || p[1] == '^' || (p[1] >= '0' && p[1] <= '7')))
4621 p++;
4622 if (*p >= '0' && *p <= '7')
4624 *pp = *p - '0';
4625 if (p[1] >= '0' && p[1] <= '7')
4627 p++;
4628 *pp = (*pp << 3) | (*p - '0');
4629 if (p[1] >= '0' && p[1] <= '7')
4631 p++;
4632 *pp = (*pp << 3) | (*p - '0');
4635 pp++;
4637 else
4639 switch (*p)
4641 case 'n': *pp = '\n'; break;
4642 case 'r': *pp = '\r'; break;
4643 case 't': *pp = '\t'; break;
4644 default: *pp = *p; break;
4646 pp++;
4649 else if (delim != '\'' && *p == '$' && (p[1] == '{' || p[1] == ':' || (p[1] >= 'a' && p[1] <= 'z') || (p[1] >= 'A' && p[1] <= 'Z') || (p[1] >= '0' && p[1] <= '9') || p[1] == '_'))
4652 char *ps, *pe, op, *v, xbuf[11];
4653 int vl;
4655 ps = ++p;
4656 debug1("- var %s\n", ps);
4657 p++;
4658 while (*p)
4660 if (*ps == '{' && *p == '}')
4661 break;
4662 if (*ps == ':' && *p == ':')
4663 break;
4664 if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_')
4665 break;
4666 p++;
4668 pe = p;
4669 if (*ps == '{' || *ps == ':')
4671 if (!*p)
4673 Msg(0, "%s: bad variable name.", rc_name);
4674 return 0;
4676 p++;
4678 op = *pe;
4679 *pe = 0;
4680 debug1("- var is '%s'\n", ps);
4681 if (*ps == ':')
4682 v = gettermcapstring(ps + 1);
4683 else
4685 if (*ps == '{')
4686 ps++;
4687 v = xbuf;
4688 if (!strcmp(ps, "TERM"))
4689 v = display ? D_termname : "unknown";
4690 else if (!strcmp(ps, "COLUMNS"))
4691 sprintf(xbuf, "%d", display ? D_width : -1);
4692 else if (!strcmp(ps, "LINES"))
4693 sprintf(xbuf, "%d", display ? D_height : -1);
4694 else if (!strcmp(ps, "PID"))
4695 sprintf(xbuf, "%d", getpid());
4696 else if (!strcmp(ps, "STY"))
4697 v = SockName;
4698 else
4699 v = getenv(ps);
4701 *pe = op;
4702 vl = v ? strlen(v) : 0;
4703 if (vl)
4705 debug1("- sub is '%s'\n", v);
4706 if (p - pp < vl)
4708 int right = buf + bufl - (p + strlen(p) + 1);
4709 if (right > 0)
4711 bcopy(p, p + right, strlen(p) + 1);
4712 p += right;
4715 if (p - pp < vl)
4717 Msg(0, "%s: no space left for variable expansion.", rc_name);
4718 return 0;
4720 bcopy(v, pp, vl);
4721 pp += vl;
4723 continue;
4725 else if (delim != '\'' && *p == '^' && p[1])
4727 p++;
4728 *pp++ = *p == '?' ? '\177' : *p & 0x1f;
4730 else if (delim == 0 && (*p == '\'' || *p == '"'))
4731 delim = *p;
4732 else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n'))
4733 break;
4734 else
4735 *pp++ = *p;
4736 p++;
4738 if (delim)
4740 Msg(0, "%s: Missing %c quote.", rc_name, delim);
4741 return 0;
4743 if (*p)
4744 p++;
4745 *pp = 0;
4746 debug2("- arg done, '%s' rest %s\n", ap[-1], p);
4747 *lp++ = pp - ap[-1];
4748 pp++;
4752 void
4753 SetEscape(u, e, me)
4754 struct acluser *u;
4755 int e, me;
4757 if (u)
4759 u->u_Esc = e;
4760 u->u_MetaEsc = me;
4762 else
4764 if (users)
4766 if (DefaultEsc >= 0)
4767 ClearAction(&ktab[DefaultEsc]);
4768 if (DefaultMetaEsc >= 0)
4769 ClearAction(&ktab[DefaultMetaEsc]);
4771 DefaultEsc = e;
4772 DefaultMetaEsc = me;
4773 if (users)
4775 if (DefaultEsc >= 0)
4777 ClearAction(&ktab[DefaultEsc]);
4778 ktab[DefaultEsc].nr = RC_OTHER;
4780 if (DefaultMetaEsc >= 0)
4782 ClearAction(&ktab[DefaultMetaEsc]);
4783 ktab[DefaultMetaEsc].nr = RC_META;
4790 ParseSwitch(act, var)
4791 struct action *act;
4792 int *var;
4794 if (*act->args == 0)
4796 *var ^= 1;
4797 return 0;
4799 return ParseOnOff(act, var);
4802 static int
4803 ParseOnOff(act, var)
4804 struct action *act;
4805 int *var;
4807 register int num = -1;
4808 char **args = act->args;
4810 if (args[1] == 0)
4812 if (strcmp(args[0], "on") == 0)
4813 num = 1;
4814 else if (strcmp(args[0], "off") == 0)
4815 num = 0;
4817 if (num < 0)
4819 Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name);
4820 return -1;
4822 *var = num;
4823 return 0;
4827 ParseSaveStr(act, var)
4828 struct action *act;
4829 char **var;
4831 char **args = act->args;
4832 if (*args == 0 || args[1])
4834 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
4835 return -1;
4837 if (*var)
4838 free(*var);
4839 *var = SaveStr(*args);
4840 return 0;
4844 ParseNum(act, var)
4845 struct action *act;
4846 int *var;
4848 int i;
4849 char *p, **args = act->args;
4851 p = *args;
4852 if (p == 0 || *p == 0 || args[1])
4854 Msg(0, "%s: %s: invalid argument. Give one argument.",
4855 rc_name, comms[act->nr].name);
4856 return -1;
4858 i = 0;
4859 while (*p)
4861 if (*p >= '0' && *p <= '9')
4862 i = 10 * i + (*p - '0');
4863 else
4865 Msg(0, "%s: %s: invalid argument. Give numeric argument.",
4866 rc_name, comms[act->nr].name);
4867 return -1;
4869 p++;
4871 debug1("ParseNum got %d\n", i);
4872 *var = i;
4873 return 0;
4876 static int
4877 ParseNum1000(act, var)
4878 struct action *act;
4879 int *var;
4881 int i;
4882 char *p, **args = act->args;
4883 int dig = 0;
4885 p = *args;
4886 if (p == 0 || *p == 0 || args[1])
4888 Msg(0, "%s: %s: invalid argument. Give one argument.",
4889 rc_name, comms[act->nr].name);
4890 return -1;
4892 i = 0;
4893 while (*p)
4895 if (*p >= '0' && *p <= '9')
4897 if (dig < 4)
4898 i = 10 * i + (*p - '0');
4899 else if (dig == 4 && *p >= '5')
4900 i++;
4901 if (dig)
4902 dig++;
4904 else if (*p == '.' && !dig)
4905 dig++;
4906 else
4908 Msg(0, "%s: %s: invalid argument. Give floating point argument.",
4909 rc_name, comms[act->nr].name);
4910 return -1;
4912 p++;
4914 if (dig == 0)
4915 i *= 1000;
4916 else
4917 while (dig++ < 4)
4918 i *= 10;
4919 if (i < 0)
4920 i = (int)((unsigned int)~0 >> 1);
4921 debug1("ParseNum1000 got %d\n", i);
4922 *var = i;
4923 return 0;
4926 static struct win *
4927 WindowByName(s)
4928 char *s;
4930 struct win *p;
4932 for (p = windows; p; p = p->w_next)
4933 if (!strcmp(p->w_title, s))
4934 return p;
4935 for (p = windows; p; p = p->w_next)
4936 if (!strncmp(p->w_title, s, strlen(s)))
4937 return p;
4938 return 0;
4941 static int
4942 WindowByNumber(str)
4943 char *str;
4945 int i;
4946 char *s;
4948 for (i = 0, s = str; *s; s++)
4950 if (*s < '0' || *s > '9')
4951 break;
4952 i = i * 10 + (*s - '0');
4954 return *s ? -1 : i;
4958 * Get window number from Name or Number string.
4959 * Numbers are tried first, then names, a prefix match suffices.
4960 * Be careful when assigning numeric strings as WindowTitles.
4963 WindowByNoN(str)
4964 char *str;
4966 int i;
4967 struct win *p;
4969 if ((i = WindowByNumber(str)) < 0 || i >= maxwin)
4971 if ((p = WindowByName(str)))
4972 return p->w_number;
4973 return -1;
4975 return i;
4978 static int
4979 ParseWinNum(act, var)
4980 struct action *act;
4981 int *var;
4983 char **args = act->args;
4984 int i = 0;
4986 if (*args == 0 || args[1])
4988 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
4989 return -1;
4992 i = WindowByNoN(*args);
4993 if (i < 0)
4995 Msg(0, "%s: %s: invalid argument. Give window number or name.",
4996 rc_name, comms[act->nr].name);
4997 return -1;
4999 debug1("ParseWinNum got %d\n", i);
5000 *var = i;
5001 return 0;
5004 static int
5005 ParseBase(act, p, var, base, bname)
5006 struct action *act;
5007 char *p;
5008 int *var;
5009 int base;
5010 char *bname;
5012 int i = 0;
5013 int c;
5015 if (*p == 0)
5017 Msg(0, "%s: %s: empty argument.", rc_name, comms[act->nr].name);
5018 return -1;
5020 while ((c = *p++))
5022 if (c >= 'a' && c <= 'z')
5023 c -= 'a' - 'A';
5024 if (c >= 'A' && c <= 'Z')
5025 c -= 'A' - ('0' + 10);
5026 c -= '0';
5027 if (c < 0 || c >= base)
5029 Msg(0, "%s: %s: argument is not %s.", rc_name, comms[act->nr].name, bname);
5030 return -1;
5032 i = base * i + c;
5034 debug1("ParseBase got %d\n", i);
5035 *var = i;
5036 return 0;
5039 static int
5040 IsNum(s, base)
5041 register char *s;
5042 register int base;
5044 for (base += '0'; *s; ++s)
5045 if (*s < '0' || *s > base)
5046 return 0;
5047 return 1;
5051 IsNumColon(s, base, p, psize)
5052 int base, psize;
5053 char *s, *p;
5055 char *q;
5056 if ((q = rindex(s, ':')) != 0)
5058 strncpy(p, q + 1, psize - 1);
5059 p[psize - 1] = '\0';
5060 *q = '\0';
5062 else
5063 *p = '\0';
5064 return IsNum(s, base);
5067 void
5068 SwitchWindow(n)
5069 int n;
5071 struct win *p;
5073 debug1("SwitchWindow %d\n", n);
5074 if (n < 0 || n >= maxwin)
5076 ShowWindows(-1);
5077 return;
5079 if ((p = wtab[n]) == 0)
5081 ShowWindows(n);
5082 return;
5084 if (display == 0)
5086 fore = p;
5087 return;
5089 if (p == D_fore)
5091 Msg(0, "This IS window %d (%s).", n, p->w_title);
5092 return;
5094 #ifdef MULTIUSER
5095 if (AclCheckPermWin(D_user, ACL_READ, p))
5097 Msg(0, "Access to window %d denied.", p->w_number);
5098 return;
5100 #endif
5101 SetForeWindow(p);
5102 Activate(fore->w_norefresh);
5106 * SetForeWindow changes the window in the input focus of the display.
5107 * Puts window wi in canvas display->d_forecv.
5109 void
5110 SetForeWindow(wi)
5111 struct win *wi;
5113 struct win *p;
5114 if (display == 0)
5116 fore = wi;
5117 return;
5119 p = Layer2Window(D_forecv->c_layer);
5120 SetCanvasWindow(D_forecv, wi);
5121 if (p)
5122 WindowChanged(p, 'u');
5123 if (wi)
5124 WindowChanged(wi, 'u');
5125 flayer = D_forecv->c_layer;
5126 /* Activate called afterwards, so no RefreshHStatus needed */
5130 /*****************************************************************/
5133 * Activate - make fore window active
5134 * norefresh = -1 forces a refresh, disregard all_norefresh then.
5136 void
5137 Activate(norefresh)
5138 int norefresh;
5140 debug1("Activate(%d)\n", norefresh);
5141 if (display == 0)
5142 return;
5143 if (D_status)
5145 Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
5146 RemoveStatus();
5149 if (MayResizeLayer(D_forecv->c_layer))
5150 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, display);
5152 fore = D_fore;
5153 if (fore)
5155 /* XXX ? */
5156 if (fore->w_monitor != MON_OFF)
5157 fore->w_monitor = MON_ON;
5158 fore->w_bell = BELL_ON;
5159 WindowChanged(fore, 'f');
5161 #if 0
5162 if (ResizeDisplay(fore->w_width, fore->w_height))
5164 debug2("Cannot resize from (%d,%d)", D_width, D_height);
5165 debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height);
5166 DoResize(D_width, D_height);
5168 #endif
5170 Redisplay(norefresh + all_norefresh);
5174 static int
5175 NextWindow()
5177 register struct win **pp;
5178 int n = fore ? fore->w_number : maxwin;
5179 struct win *group = fore ? fore->w_group : 0;
5181 for (pp = fore ? wtab + n + 1 : wtab; pp != wtab + n; pp++)
5183 if (pp == wtab + maxwin)
5184 pp = wtab;
5185 if (*pp)
5187 if (!fore || group == (*pp)->w_group)
5188 break;
5191 if (pp == wtab + n)
5192 return -1;
5193 return pp - wtab;
5196 static int
5197 PreviousWindow()
5199 register struct win **pp;
5200 int n = fore ? fore->w_number : -1;
5201 struct win *group = fore ? fore->w_group : 0;
5203 for (pp = wtab + n - 1; pp != wtab + n; pp--)
5205 if (pp == wtab - 1)
5206 pp = wtab + maxwin - 1;
5207 if (*pp)
5209 if (!fore || group == (*pp)->w_group)
5210 break;
5213 if (pp == wtab + n)
5214 return -1;
5215 return pp - wtab;
5218 static int
5219 MoreWindows()
5221 char *m = "No other window.";
5222 if (windows && (fore == 0 || windows->w_next))
5223 return 1;
5224 if (fore == 0)
5226 Msg(0, "No window available");
5227 return 0;
5229 Msg(0, m, fore->w_number); /* other arg for nethack */
5230 return 0;
5233 void
5234 KillWindow(wi)
5235 struct win *wi;
5237 struct win **pp, *p;
5238 struct canvas *cv;
5239 int gotone;
5240 struct layout *lay;
5243 * Remove window from linked list.
5245 for (pp = &windows; (p = *pp); pp = &p->w_next)
5246 if (p == wi)
5247 break;
5248 ASSERT(p);
5249 *pp = p->w_next;
5250 wi->w_inlen = 0;
5251 wtab[wi->w_number] = 0;
5253 if (windows == 0)
5255 FreeWindow(wi);
5256 Finit(0);
5260 * switch to different window on all canvases
5262 for (display = displays; display; display = display->d_next)
5264 gotone = 0;
5265 for (cv = D_cvlist; cv; cv = cv->c_next)
5267 if (Layer2Window(cv->c_layer) != wi)
5268 continue;
5269 /* switch to other window */
5270 SetCanvasWindow(cv, FindNiceWindow(D_other, 0));
5271 gotone = 1;
5273 if (gotone)
5275 #ifdef ZMODEM
5276 if (wi->w_zdisplay == display)
5278 D_blocked = 0;
5279 D_readev.condpos = D_readev.condneg = 0;
5281 #endif
5282 Activate(-1);
5286 /* do the same for the layouts */
5287 for (lay = layouts; lay; lay = lay->lay_next)
5288 UpdateLayoutCanvas(&lay->lay_canvas, wi);
5290 FreeWindow(wi);
5291 WindowChanged((struct win *)0, 'w');
5292 WindowChanged((struct win *)0, 'W');
5293 WindowChanged((struct win *)0, 0);
5296 static void
5297 LogToggle(on)
5298 int on;
5300 char buf[1024];
5302 if ((fore->w_log != 0) == on)
5304 if (display && !*rc_name)
5305 Msg(0, "You are %s logging.", on ? "already" : "not");
5306 return;
5308 if (fore->w_log != 0)
5310 Msg(0, "Logfile \"%s\" closed.", fore->w_log->name);
5311 logfclose(fore->w_log);
5312 fore->w_log = 0;
5313 WindowChanged(fore, 'f');
5314 return;
5316 if (DoStartLog(fore, buf, sizeof(buf)))
5318 Msg(errno, "Error opening logfile \"%s\"", buf);
5319 return;
5321 if (ftell(fore->w_log->fp) == 0)
5322 Msg(0, "Creating logfile \"%s\".", fore->w_log->name);
5323 else
5324 Msg(0, "Appending to logfile \"%s\".", fore->w_log->name);
5325 WindowChanged(fore, 'f');
5328 char *
5329 AddWindows(buf, len, flags, where)
5330 char *buf;
5331 int len;
5332 int flags;
5333 int where;
5335 register char *s, *ss;
5336 register struct win **pp, *p;
5337 register char *cmd;
5338 int l;
5340 s = ss = buf;
5341 if ((flags & 8) && where < 0)
5343 *s = 0;
5344 return ss;
5346 for (pp = ((flags & 4) && where >= 0) ? wtab + where + 1: wtab; pp < wtab + maxwin; pp++)
5348 int rend = -1;
5349 if (pp - wtab == where && ss == buf)
5350 ss = s;
5351 if ((p = *pp) == 0)
5352 continue;
5353 if ((flags & 1) && display && p == D_fore)
5354 continue;
5355 if (display && D_fore && D_fore->w_group != p->w_group)
5356 continue;
5358 cmd = p->w_title;
5359 l = strlen(cmd);
5360 if (l > 20)
5361 l = 20;
5362 if (s - buf + l > len - 24)
5363 break;
5364 if (s > buf || (flags & 4))
5366 *s++ = ' ';
5367 *s++ = ' ';
5369 if (p->w_number == where)
5371 ss = s;
5372 if (flags & 8)
5373 break;
5375 if (!(flags & 4) || where < 0 || ((flags & 4) && where < p->w_number))
5377 if (p->w_monitor == MON_DONE && renditions[REND_MONITOR] != -1)
5378 rend = renditions[REND_MONITOR];
5379 else if ((p->w_bell == BELL_DONE || p->w_bell == BELL_FOUND) && renditions[REND_BELL] != -1)
5380 rend = renditions[REND_BELL];
5382 if (rend != -1)
5383 AddWinMsgRend(s, rend);
5384 sprintf(s, "%d", p->w_number);
5385 s += strlen(s);
5386 if (display && p == D_fore)
5387 *s++ = '*';
5388 if (!(flags & 2))
5390 if (display && p == D_other)
5391 *s++ = '-';
5392 s = AddWindowFlags(s, len, p);
5394 *s++ = ' ';
5395 strncpy(s, cmd, l);
5396 s += l;
5397 if (rend != -1)
5398 AddWinMsgRend(s, -1);
5400 *s = 0;
5401 return ss;
5404 char *
5405 AddWindowFlags(buf, len, p)
5406 char *buf;
5407 int len;
5408 struct win *p;
5410 char *s = buf;
5411 if (p == 0 || len < 12)
5413 *s = 0;
5414 return s;
5416 #if 0
5417 if (display && p == D_fore)
5418 *s++ = '*';
5419 if (display && p == D_other)
5420 *s++ = '-';
5421 #endif
5422 if (p->w_layer.l_cvlist && p->w_layer.l_cvlist->c_lnext)
5423 *s++ = '&';
5424 if (p->w_monitor == MON_DONE
5425 #ifdef MULTIUSER
5426 && (ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))
5427 #endif
5429 *s++ = '@';
5430 if (p->w_bell == BELL_DONE)
5431 *s++ = '!';
5432 #ifdef UTMPOK
5433 if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1)
5434 *s++ = '$';
5435 #endif
5436 if (p->w_log != 0)
5438 strcpy(s, "(L)");
5439 s += 3;
5441 if (p->w_ptyfd < 0 && p->w_type != W_TYPE_GROUP)
5442 *s++ = 'Z';
5443 *s = 0;
5444 return s;
5447 char *
5448 AddOtherUsers(buf, len, p)
5449 char *buf;
5450 int len;
5451 struct win *p;
5453 struct display *d, *olddisplay = display;
5454 struct canvas *cv;
5455 char *s;
5456 int l;
5458 s = buf;
5459 for (display = displays; display; display = display->d_next)
5461 if (olddisplay && D_user == olddisplay->d_user)
5462 continue;
5463 for (cv = D_cvlist; cv; cv = cv->c_next)
5464 if (Layer2Window(cv->c_layer) == p)
5465 break;
5466 if (!cv)
5467 continue;
5468 for (d = displays; d && d != display; d = d->d_next)
5469 if (D_user == d->d_user)
5470 break;
5471 if (d && d != display)
5472 continue;
5473 if (len > 1 && s != buf)
5475 *s++ = ',';
5476 len--;
5478 l = strlen(D_user->u_name);
5479 if (l + 1 > len)
5480 break;
5481 strcpy(s, D_user->u_name);
5482 s += l;
5483 len -= l;
5485 *s = 0;
5486 display = olddisplay;
5487 return s;
5490 void
5491 ShowWindows(where)
5492 int where;
5494 char buf[1024];
5495 char *s, *ss;
5497 if (display && where == -1 && D_fore)
5498 where = D_fore->w_number;
5499 ss = AddWindows(buf, sizeof(buf), 0, where);
5500 s = buf + strlen(buf);
5501 if (display && ss - buf > D_width / 2)
5503 ss -= D_width / 2;
5504 if (s - ss < D_width)
5506 ss = s - D_width;
5507 if (ss < buf)
5508 ss = buf;
5511 else
5512 ss = buf;
5513 Msg(0, "%s", ss);
5516 static void
5517 ShowInfo()
5519 char buf[512], *p;
5520 register struct win *wp = fore;
5521 register int i;
5523 if (wp == 0)
5525 Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height);
5526 return;
5528 p = buf;
5529 if (buf < (p += GetAnsiStatus(wp, p)))
5530 *p++ = ' ';
5531 sprintf(p, "(%d,%d)/(%d,%d)",
5532 wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height);
5533 #ifdef COPY_PASTE
5534 sprintf(p += strlen(p), "+%d", wp->w_histheight);
5535 #endif
5536 sprintf(p += strlen(p), " %c%sflow",
5537 (wp->w_flow & FLOW_NOW) ? '+' : '-',
5538 (wp->w_flow & FLOW_AUTOFLAG) ? "" :
5539 ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)"));
5540 if (!wp->w_wrap) sprintf(p += strlen(p), " -wrap");
5541 if (wp->w_insert) sprintf(p += strlen(p), " ins");
5542 if (wp->w_origin) sprintf(p += strlen(p), " org");
5543 if (wp->w_keypad) sprintf(p += strlen(p), " app");
5544 if (wp->w_log) sprintf(p += strlen(p), " log");
5545 if (wp->w_monitor != MON_OFF
5546 #ifdef MULTIUSER
5547 && (ACLBYTE(wp->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))
5548 #endif
5550 sprintf(p += strlen(p), " mon");
5551 if (wp->w_mouse) sprintf(p += strlen(p), " mouse");
5552 #ifdef COLOR
5553 if (wp->w_bce) sprintf(p += strlen(p), " bce");
5554 #endif
5555 if (!wp->w_c1) sprintf(p += strlen(p), " -c1");
5556 if (wp->w_norefresh) sprintf(p += strlen(p), " nored");
5558 p += strlen(p);
5559 #ifdef FONT
5560 # ifdef ENCODINGS
5561 if (wp->w_encoding && (display == 0 || D_encoding != wp->w_encoding || EncodingDefFont(wp->w_encoding) <= 0))
5563 *p++ = ' ';
5564 strcpy(p, EncodingName(wp->w_encoding));
5565 p += strlen(p);
5567 # ifdef UTF8
5568 if (wp->w_encoding != UTF8)
5569 # endif
5570 # endif
5571 if (D_CC0 || (D_CS0 && *D_CS0))
5573 if (wp->w_gr == 2)
5575 sprintf(p, " G%c", wp->w_Charset + '0');
5576 if (wp->w_FontE >= ' ')
5577 p[3] = wp->w_FontE;
5578 else
5580 p[3] = '^';
5581 p[4] = wp->w_FontE ^ 0x40;
5582 p++;
5584 p[4] = '[';
5585 p++;
5587 else if (wp->w_gr)
5588 sprintf(p++, " G%c%c[", wp->w_Charset + '0', wp->w_CharsetR + '0');
5589 else
5590 sprintf(p, " G%c[", wp->w_Charset + '0');
5591 p += 4;
5592 for (i = 0; i < 4; i++)
5594 if (wp->w_charsets[i] == ASCII)
5595 *p++ = 'B';
5596 else if (wp->w_charsets[i] >= ' ')
5597 *p++ = wp->w_charsets[i];
5598 else
5600 *p++ = '^';
5601 *p++ = wp->w_charsets[i] ^ 0x40;
5604 *p++ = ']';
5605 *p = 0;
5607 #endif
5609 if (wp->w_type == W_TYPE_PLAIN)
5611 /* add info about modem control lines */
5612 *p++ = ' ';
5613 TtyGetModemStatus(wp->w_ptyfd, p);
5615 #ifdef BUILTIN_TELNET
5616 else if (wp->w_type == W_TYPE_TELNET)
5618 *p++ = ' ';
5619 TelStatus(wp, p, sizeof(buf) - 1 - (p - buf));
5621 #endif
5622 Msg(0, "%s %d(%s)", buf, wp->w_number, wp->w_title);
5625 static void
5626 ShowDInfo()
5628 char buf[512], *p;
5629 if (display == 0)
5630 return;
5631 p = buf;
5632 sprintf(p, "(%d,%d)", D_width, D_height),
5633 p += strlen(p);
5634 #ifdef ENCODINGS
5635 if (D_encoding)
5637 *p++ = ' ';
5638 strcpy(p, EncodingName(D_encoding));
5639 p += strlen(p);
5641 #endif
5642 if (D_CXT)
5644 strcpy(p, " xterm");
5645 p += strlen(p);
5647 #ifdef COLOR
5648 if (D_hascolor)
5650 strcpy(p, " color");
5651 p += strlen(p);
5653 #endif
5654 #ifdef FONT
5655 if (D_CG0)
5657 strcpy(p, " iso2022");
5658 p += strlen(p);
5660 else if (D_CS0 && *D_CS0)
5662 strcpy(p, " altchar");
5663 p += strlen(p);
5665 #endif
5666 Msg(0, "%s", buf);
5669 static void
5670 AKAfin(buf, len, data)
5671 char *buf;
5672 int len;
5673 char *data; /* dummy */
5675 ASSERT(display);
5676 if (len && fore)
5677 ChangeAKA(fore, buf, strlen(buf));
5680 static void
5681 InputAKA()
5683 char *s, *ss;
5684 int n;
5685 Input("Set window's title to: ", sizeof(fore->w_akabuf) - 1, INP_COOKED, AKAfin, NULL, 0);
5686 s = fore->w_title;
5687 if (!s)
5688 return;
5689 for (; *s; s++)
5691 if ((*(unsigned char *)s & 0x7f) < 0x20 || *s == 0x7f)
5692 continue;
5693 ss = s;
5694 n = 1;
5695 LayProcess(&ss, &n);
5699 static void
5700 Colonfin(buf, len, data)
5701 char *buf;
5702 int len;
5703 char *data; /* dummy */
5705 char mbuf[256];
5707 RemoveStatus();
5708 if (buf[len] == '\t')
5710 int m, x;
5711 int l = 0, r = RC_LAST;
5712 int showmessage = 0;
5713 char *s = buf;
5715 while (*s && s - buf < len)
5716 if (*s++ == ' ')
5717 return;
5719 /* Showing a message when there's no hardstatus or caption cancels the input */
5720 if (display &&
5721 (captionalways || D_has_hstatus == HSTATUS_LASTLINE || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext)))
5722 showmessage = 1;
5724 while (l <= r)
5726 m = (l + r) / 2;
5727 x = strncmp(buf, comms[m].name, len);
5728 if (x > 0)
5729 l = m + 1;
5730 else if (x < 0)
5731 r = m - 1;
5732 else
5734 s = mbuf;
5735 for (l = m - 1; l >= 0 && strncmp(buf, comms[l].name, len) == 0; l--)
5737 for (m = ++l; m <= r && strncmp(buf, comms[m].name, len) == 0 && s - mbuf < sizeof(mbuf); m++)
5738 s += snprintf(s, sizeof(mbuf) - (s - mbuf), " %s", comms[m].name);
5739 if (l < m - 1)
5741 if (showmessage)
5742 Msg(0, "Possible commands:%s", mbuf);
5744 else
5746 s = mbuf;
5747 len = snprintf(mbuf, sizeof(mbuf), "%s \t", comms[l].name + len);
5748 if (len > 0 && len < sizeof(mbuf))
5749 LayProcess(&s, &len);
5751 break;
5754 if (l > r && showmessage)
5755 Msg(0, "No commands matching '%*s'", len, buf);
5756 return;
5759 if (!len || buf[len])
5760 return;
5762 len = strlen(buf) + 1;
5763 if (len > (int)sizeof(mbuf))
5764 RcLine(buf, len);
5765 else
5767 bcopy(buf, mbuf, len);
5768 RcLine(mbuf, sizeof mbuf);
5772 static void
5773 SelectFin(buf, len, data)
5774 char *buf;
5775 int len;
5776 char *data; /* dummy */
5778 int n;
5780 if (!len || !display)
5781 return;
5782 if (len == 1 && *buf == '-')
5784 SetForeWindow((struct win *)0);
5785 Activate(0);
5786 return;
5788 if ((n = WindowByNoN(buf)) < 0)
5789 return;
5790 SwitchWindow(n);
5793 static void
5794 SelectLayoutFin(buf, len, data)
5795 char *buf;
5796 int len;
5797 char *data; /* dummy */
5799 struct layout *lay;
5801 if (!len || !display)
5802 return;
5803 if (len == 1 && *buf == '-')
5805 LoadLayout((struct layout *)0, (struct canvas *)0);
5806 Activate(0);
5807 return;
5809 lay = FindLayout(buf);
5810 if (!lay)
5811 Msg(0, "No such layout\n");
5812 else if (lay == D_layout)
5813 Msg(0, "This IS layout %d (%s).\n", lay->lay_number, lay->lay_title);
5814 else
5816 LoadLayout(lay, &D_canvas);
5817 Activate(0);
5822 static void
5823 InputSelect()
5825 Input("Switch to window: ", 20, INP_COOKED, SelectFin, NULL, 0);
5828 static char setenv_var[31];
5831 static void
5832 SetenvFin1(buf, len, data)
5833 char *buf;
5834 int len;
5835 char *data; /* dummy */
5837 if (!len || !display)
5838 return;
5839 InputSetenv(buf);
5842 static void
5843 SetenvFin2(buf, len, data)
5844 char *buf;
5845 int len;
5846 char *data; /* dummy */
5848 if (!len || !display)
5849 return;
5850 debug2("SetenvFin2: setenv '%s' '%s'\n", setenv_var, buf);
5851 xsetenv(setenv_var, buf);
5852 MakeNewEnv();
5855 static void
5856 InputSetenv(arg)
5857 char *arg;
5859 static char setenv_buf[50 + sizeof(setenv_var)]; /* need to be static here, cannot be freed */
5861 if (arg)
5863 strncpy(setenv_var, arg, sizeof(setenv_var) - 1);
5864 sprintf(setenv_buf, "Enter value for %s: ", setenv_var);
5865 Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL, 0);
5867 else
5868 Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL, 0);
5872 * the following options are understood by this parser:
5873 * -f, -f0, -f1, -fy, -fa
5874 * -t title, -T terminal-type, -h height-of-scrollback,
5875 * -ln, -l0, -ly, -l1, -l
5876 * -a, -M, -L
5878 void
5879 DoScreen(fn, av)
5880 char *fn, **av;
5882 struct NewWindow nwin;
5883 register int num;
5884 char buf[20];
5886 nwin = nwin_undef;
5887 while (av && *av && av[0][0] == '-')
5889 if (av[0][1] == '-')
5891 av++;
5892 break;
5894 switch (av[0][1])
5896 case 'f':
5897 switch (av[0][2])
5899 case 'n':
5900 case '0':
5901 nwin.flowflag = FLOW_NOW * 0;
5902 break;
5903 case 'y':
5904 case '1':
5905 case '\0':
5906 nwin.flowflag = FLOW_NOW * 1;
5907 break;
5908 case 'a':
5909 nwin.flowflag = FLOW_AUTOFLAG;
5910 break;
5911 default:
5912 break;
5914 break;
5915 case 't': /* no more -k */
5916 if (av[0][2])
5917 nwin.aka = &av[0][2];
5918 else if (*++av)
5919 nwin.aka = *av;
5920 else
5921 --av;
5922 break;
5923 case 'T':
5924 if (av[0][2])
5925 nwin.term = &av[0][2];
5926 else if (*++av)
5927 nwin.term = *av;
5928 else
5929 --av;
5930 break;
5931 case 'h':
5932 if (av[0][2])
5933 nwin.histheight = atoi(av[0] + 2);
5934 else if (*++av)
5935 nwin.histheight = atoi(*av);
5936 else
5937 --av;
5938 break;
5939 #ifdef LOGOUTOK
5940 case 'l':
5941 switch (av[0][2])
5943 case 'n':
5944 case '0':
5945 nwin.lflag = 0;
5946 break;
5947 case 'y':
5948 case '1':
5949 case '\0':
5950 nwin.lflag = 1;
5951 break;
5952 case 'a':
5953 nwin.lflag = 3;
5954 break;
5955 default:
5956 break;
5958 break;
5959 #endif
5960 case 'a':
5961 nwin.aflag = 1;
5962 break;
5963 case 'M':
5964 nwin.monitor = MON_ON;
5965 break;
5966 case 'L':
5967 nwin.Lflag = 1;
5968 break;
5969 default:
5970 Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
5971 break;
5973 ++av;
5975 num = 0;
5976 if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
5978 if (*buf != '\0')
5979 nwin.aka = buf;
5980 num = atoi(*av);
5981 if (num < 0 || num > maxwin - 1)
5983 Msg(0, "%s: illegal screen number %d.", fn, num);
5984 num = 0;
5986 nwin.StartAt = num;
5987 ++av;
5989 if (av && *av)
5991 nwin.args = av;
5992 if (!nwin.aka)
5993 nwin.aka = Filename(*av);
5995 MakeWindow(&nwin);
5998 #ifdef COPY_PASTE
6000 * CompileKeys must be called before Markroutine is first used.
6001 * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
6003 * s is an ascii string in a termcap-like syntax. It looks like
6004 * "j=u:k=d:l=r:h=l: =.:" and so on...
6005 * this example rebinds the cursormovement to the keys u (up), d (down),
6006 * l (left), r (right). placing a mark will now be done with ".".
6009 CompileKeys(s, sl, array)
6010 char *s;
6011 int sl;
6012 unsigned char *array;
6014 int i;
6015 unsigned char key, value;
6017 if (sl == 0)
6019 for (i = 0; i < 256; i++)
6020 array[i] = i;
6021 return 0;
6023 debug1("CompileKeys: '%s'\n", s);
6024 while (sl)
6026 key = *(unsigned char *)s++;
6027 if (*s != '=' || sl < 3)
6028 return -1;
6029 sl--;
6032 s++;
6033 sl -= 2;
6034 value = *(unsigned char *)s++;
6035 array[value] = key;
6037 while (*s == '=' && sl >= 2);
6038 if (sl == 0)
6039 break;
6040 if (*s++ != ':')
6041 return -1;
6042 sl--;
6044 return 0;
6046 #endif /* COPY_PASTE */
6049 * Asynchronous input functions
6052 #if defined(DETACH) && defined(POW_DETACH)
6053 static void
6054 pow_detach_fn(buf, len, data)
6055 char *buf;
6056 int len;
6057 char *data; /* dummy */
6059 debug("pow_detach_fn called\n");
6060 if (len)
6062 *buf = 0;
6063 return;
6065 if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH)
6067 if (display)
6068 write(D_userfd, "\007", 1);
6069 Msg(0, "Detach aborted.");
6071 else
6072 Detach(D_POWER);
6074 #endif /* POW_DETACH */
6076 #ifdef COPY_PASTE
6077 static void
6078 copy_reg_fn(buf, len, data)
6079 char *buf;
6080 int len;
6081 char *data; /* dummy */
6083 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6085 if (len)
6087 *buf = 0;
6088 return;
6090 if (pp->buf)
6091 free(pp->buf);
6092 pp->buf = 0;
6093 pp->len = 0;
6094 if (D_user->u_plop.len)
6096 if ((pp->buf = (char *)malloc(D_user->u_plop.len)) == NULL)
6098 Msg(0, strnomem);
6099 return;
6101 bcopy(D_user->u_plop.buf, pp->buf, D_user->u_plop.len);
6103 pp->len = D_user->u_plop.len;
6104 #ifdef ENCODINGS
6105 pp->enc = D_user->u_plop.enc;
6106 #endif
6107 Msg(0, "Copied %d characters into register %c", D_user->u_plop.len, *buf);
6110 static void
6111 ins_reg_fn(buf, len, data)
6112 char *buf;
6113 int len;
6114 char *data; /* dummy */
6116 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6118 if (len)
6120 *buf = 0;
6121 return;
6123 if (!fore)
6124 return; /* Input() should not call us w/o fore, but you never know... */
6125 if (*buf == '.')
6126 Msg(0, "ins_reg_fn: Warning: pasting real register '.'!");
6127 if (pp->buf)
6129 MakePaster(&fore->w_paster, pp->buf, pp->len, 0);
6130 return;
6132 Msg(0, "Empty register.");
6134 #endif /* COPY_PASTE */
6136 static void
6137 process_fn(buf, len, data)
6138 char *buf;
6139 int len;
6140 char *data; /* dummy */
6142 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6144 if (len)
6146 *buf = 0;
6147 return;
6149 if (pp->buf)
6151 ProcessInput(pp->buf, pp->len);
6152 return;
6154 Msg(0, "Empty register.");
6157 static void
6158 confirm_fn(buf, len, data)
6159 char *buf;
6160 int len;
6161 char *data;
6163 struct action act;
6165 if (len || (*buf != 'y' && *buf != 'Y'))
6167 *buf = 0;
6168 return;
6170 act.nr = *(int *)data;
6171 act.args = noargs;
6172 act.argl = 0;
6173 act.quiet = 0;
6174 DoAction(&act, -1);
6177 #ifdef MULTIUSER
6178 struct inputsu
6180 struct acluser **up;
6181 char name[24];
6182 char pw1[130]; /* FreeBSD crypts to 128 bytes */
6183 char pw2[130];
6186 static void
6187 su_fin(buf, len, data)
6188 char *buf;
6189 int len;
6190 char *data;
6192 struct inputsu *i = (struct inputsu *)data;
6193 char *p;
6194 int l;
6196 if (!*i->name)
6197 { p = i->name; l = sizeof(i->name) - 1; }
6198 else if (!*i->pw1)
6199 { strcpy(p = i->pw1, "\377"); l = sizeof(i->pw1) - 1; }
6200 else
6201 { strcpy(p = i->pw2, "\377"); l = sizeof(i->pw2) - 1; }
6202 if (buf && len)
6203 strncpy(p, buf, 1 + (l < len) ? l : len);
6204 if (!*i->name)
6205 Input("Screen User: ", sizeof(i->name) - 1, INP_COOKED, su_fin, (char *)i, 0);
6206 else if (!*i->pw1)
6207 Input("User's UNIX Password: ", sizeof(i->pw1)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0);
6208 else if (!*i->pw2)
6209 Input("User's Screen Password: ", sizeof(i->pw2)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0);
6210 else
6212 if ((p = DoSu(i->up, i->name, i->pw2, i->pw1)))
6213 Msg(0, "%s", p);
6214 free((char *)i);
6218 static int
6219 InputSu(w, up, name)
6220 struct win *w;
6221 struct acluser **up;
6222 char *name;
6224 struct inputsu *i;
6226 if (!(i = (struct inputsu *)calloc(1, sizeof(struct inputsu))))
6227 return -1;
6229 i->up = up;
6230 if (name && *name)
6231 su_fin(name, (int)strlen(name), (char *)i); /* can also initialise stuff */
6232 else
6233 su_fin((char *)0, 0, (char *)i);
6234 return 0;
6236 #endif /* MULTIUSER */
6238 #ifdef PASSWORD
6240 static void
6241 pass1(buf, len, data)
6242 char *buf;
6243 int len;
6244 char *data;
6246 struct acluser *u = (struct acluser *)data;
6248 if (!*buf)
6249 return;
6250 ASSERT(u);
6251 if (u->u_password != NullStr)
6252 free((char *)u->u_password);
6253 u->u_password = SaveStr(buf);
6254 bzero(buf, strlen(buf));
6255 Input("Retype new password:", 100, INP_NOECHO, pass2, data, 0);
6258 static void
6259 pass2(buf, len, data)
6260 char *buf;
6261 int len;
6262 char *data;
6264 int st;
6265 char salt[3];
6266 struct acluser *u = (struct acluser *)data;
6268 ASSERT(u);
6269 if (!buf || strcmp(u->u_password, buf))
6271 Msg(0, "[ Passwords don't match - checking turned off ]");
6272 if (u->u_password != NullStr)
6274 bzero(u->u_password, strlen(u->u_password));
6275 free((char *)u->u_password);
6277 u->u_password = NullStr;
6279 else if (u->u_password[0] == '\0')
6281 Msg(0, "[ No password - no secure ]");
6282 if (buf)
6283 bzero(buf, strlen(buf));
6286 if (u->u_password != NullStr)
6288 for (st = 0; st < 2; st++)
6289 salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26);
6290 salt[2] = 0;
6291 buf = crypt(u->u_password, salt);
6292 bzero(u->u_password, strlen(u->u_password));
6293 free((char *)u->u_password);
6294 u->u_password = SaveStr(buf);
6295 bzero(buf, strlen(buf));
6296 #ifdef COPY_PASTE
6297 if (u->u_plop.buf)
6298 UserFreeCopyBuffer(u);
6299 u->u_plop.len = strlen(u->u_password);
6300 # ifdef ENCODINGS
6301 u->u_plop.enc = 0;
6302 #endif
6303 if (!(u->u_plop.buf = SaveStr(u->u_password)))
6305 Msg(0, strnomem);
6306 D_user->u_plop.len = 0;
6308 else
6309 Msg(0, "[ Password moved into copybuffer ]");
6310 #else /* COPY_PASTE */
6311 Msg(0, "[ Crypted password is \"%s\" ]", u->u_password);
6312 #endif /* COPY_PASTE */
6315 #endif /* PASSWORD */
6317 static int
6318 digraph_find(buf)
6319 const char *buf;
6321 int i;
6322 for (i = 0; i < MAX_DIGRAPH && digraphs[i].d[0]; i++)
6323 if ((digraphs[i].d[0] == (unsigned char)buf[0] && digraphs[i].d[1] == (unsigned char)buf[1]) ||
6324 (digraphs[i].d[0] == (unsigned char)buf[1] && digraphs[i].d[1] == (unsigned char)buf[0]))
6325 break;
6326 return i;
6329 static void
6330 digraph_fn(buf, len, data)
6331 char *buf;
6332 int len;
6333 char *data; /* dummy */
6335 int ch, i, x;
6337 ch = buf[len];
6338 if (ch)
6340 buf[len + 1] = ch; /* so we can restore it later */
6341 if (ch < ' ' || ch == '\177')
6342 return;
6343 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))))
6345 if (len == 1)
6346 return;
6347 if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F'))
6349 buf[len] = '\034'; /* ^] is ignored by Input() */
6350 return;
6352 if (len == (*buf == 'U' ? 5 : 3))
6353 buf[len] = '\n';
6354 return;
6356 if (len && *buf == '0')
6358 if (ch < '0' || ch > '7')
6360 buf[len] = '\034'; /* ^] is ignored by Input() */
6361 return;
6363 if (len == 3)
6364 buf[len] = '\n';
6365 return;
6367 if (len == 1)
6368 buf[len] = '\n';
6369 return;
6371 if (len < 1)
6372 return;
6373 if (buf[len + 1])
6375 buf[len] = buf[len + 1]; /* stored above */
6376 len++;
6378 if (len < 2)
6379 return;
6380 if (!parse_input_int(buf, len, &x))
6382 i = digraph_find(buf);
6383 if ((x = digraphs[i].value) <= 0)
6385 Msg(0, "Unknown digraph");
6386 return;
6389 i = 1;
6390 *buf = x;
6391 #ifdef UTF8
6392 if (flayer->l_encoding == UTF8)
6393 i = ToUtf8(buf, x); /* buf is big enough for all UTF-8 codes */
6394 #endif
6395 while(i)
6396 LayProcess(&buf, &i);
6399 #ifdef MAPKEYS
6401 StuffKey(i)
6402 int i;
6404 struct action *act;
6405 int discard = 0;
6407 debug1("StuffKey #%d", i);
6408 #ifdef DEBUG
6409 if (i < KMAP_KEYS)
6410 debug1(" - %s", term[i + T_CAPS].tcname);
6411 #endif
6413 if (i < KMAP_KEYS && D_ESCseen)
6415 struct action *act = &D_ESCseen[i + 256];
6416 if (act->nr != RC_ILLEGAL)
6418 D_ESCseen = 0;
6419 DoAction(act, i + 256);
6420 return 0;
6422 discard = 1;
6425 if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys)
6426 i += T_OCAPS - T_CURSOR;
6427 else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad)
6428 i += T_OCAPS - T_CURSOR;
6429 debug1(" - action %d\n", i);
6430 flayer = D_forecv->c_layer;
6431 fore = D_fore;
6432 act = 0;
6433 #ifdef COPY_PASTE
6434 if (flayer && flayer->l_mode == 1)
6435 act = i < KMAP_KEYS+KMAP_AKEYS ? &mmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].mm;
6436 #endif
6437 if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault)
6438 act = i < KMAP_KEYS+KMAP_AKEYS ? &umtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].um;
6439 if (!act || act->nr == RC_ILLEGAL)
6440 act = i < KMAP_KEYS+KMAP_AKEYS ? &dmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].dm;
6442 if (discard && (!act || act->nr != RC_COMMAND))
6444 D_ESCseen = 0;
6445 return 0;
6447 D_mapdefault = 0;
6449 if (act == 0 || act->nr == RC_ILLEGAL)
6450 return -1;
6451 DoAction(act, 0);
6452 return 0;
6454 #endif
6457 static int
6458 IsOnDisplay(wi)
6459 struct win *wi;
6461 struct canvas *cv;
6462 ASSERT(display);
6463 for (cv = D_cvlist; cv; cv = cv->c_next)
6464 if (Layer2Window(cv->c_layer) == wi)
6465 return 1;
6466 return 0;
6469 struct win *
6470 FindNiceWindow(wi, presel)
6471 struct win *wi;
6472 char *presel;
6474 int i;
6476 debug2("FindNiceWindow %d %s\n", wi ? wi->w_number : -1 , presel ? presel : "NULL");
6477 if (presel)
6479 i = WindowByNoN(presel);
6480 if (i >= 0)
6481 wi = wtab[i];
6483 if (!display)
6484 return wi;
6485 #ifdef MULTIUSER
6486 if (wi && AclCheckPermWin(D_user, ACL_READ, wi))
6487 wi = 0;
6488 #endif
6489 if (!wi || (IsOnDisplay(wi) && !presel))
6491 /* try to get another window */
6492 wi = 0;
6493 #ifdef MULTIUSER
6494 for (wi = windows; wi; wi = wi->w_next)
6495 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_WRITE, wi))
6496 break;
6497 if (!wi)
6498 for (wi = windows; wi; wi = wi->w_next)
6499 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_WRITE, wi))
6500 break;
6501 if (!wi)
6502 for (wi = windows; wi; wi = wi->w_next)
6503 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_READ, wi))
6504 break;
6505 if (!wi)
6506 for (wi = windows; wi; wi = wi->w_next)
6507 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_READ, wi))
6508 break;
6509 #endif
6510 if (!wi)
6511 for (wi = windows; wi; wi = wi->w_next)
6512 if (!wi->w_layer.l_cvlist)
6513 break;
6514 if (!wi)
6515 for (wi = windows; wi; wi = wi->w_next)
6516 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi))
6517 break;
6519 #ifdef MULTIUSER
6520 if (wi && AclCheckPermWin(D_user, ACL_READ, wi))
6521 wi = 0;
6522 #endif
6523 return wi;
6526 #if 0
6528 /* sorted list of all commands */
6529 static struct comm **commtab;
6530 static int ncommtab;
6532 void
6533 AddComms(cos, hand)
6534 struct comm *cos;
6535 void (*hand) __P((struct comm *, char **, int));
6537 int n, i, j, r;
6538 for (n = 0; cos[n].name; n++)
6540 if (n == 0)
6541 return;
6542 if (commtab)
6543 commtab = (struct commt *)realloc(commtab, sizeof(*commtab) * (ncommtab + n));
6544 else
6545 commtab = (struct commt *)malloc(sizeof(*commtab) * (ncommtab + n));
6546 if (!commtab)
6547 Panic(0, strnomem);
6548 for (i = 0; i < n; i++)
6550 for (j = 0; j < ncommtab; j++)
6552 r = strcmp(cos[i].name, commtab[j]->name);
6553 if (r == 0)
6554 Panic(0, "Duplicate command: %s\n", cos[i].name);
6555 if (r < 0)
6556 break;
6558 for (r = ncommtab; r > j; r--)
6559 commtab[r] = commtab[r - 1];
6560 commtab[j] = cos + i;
6561 cos[i].handler = hand;
6562 bzero(cos[i].userbits, sizeof(cos[i].userbits));
6563 ncommtab++;
6567 struct comm *
6568 FindComm(str)
6569 char *str;
6571 int x, m, l = 0, r = ncommtab - 1;
6572 while (l <= r)
6574 m = (l + r) / 2;
6575 x = strcmp(str, commtab[m]->name);
6576 if (x > 0)
6577 l = m + 1;
6578 else if (x < 0)
6579 r = m - 1;
6580 else
6581 return commtab[m];
6583 return 0;
6586 #endif
6588 static int
6589 CalcSlicePercent(cv, percent)
6590 struct canvas *cv;
6591 int percent;
6593 int w, wsum, up;
6594 if (!cv || !cv->c_slback)
6595 return percent;
6596 up = CalcSlicePercent(cv->c_slback->c_slback, percent);
6597 w = cv->c_slweight;
6598 for (cv = cv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext)
6599 wsum += cv->c_slweight;
6600 if (wsum == 0)
6601 return 0;
6602 return (up * w) / wsum;
6605 static int
6606 ChangeCanvasSize(fcv, abs, diff, gflag, percent)
6607 struct canvas *fcv; /* make this canvas bigger */
6608 int abs; /* mode: 0:rel 1:abs 2:max */
6609 int diff; /* change this much */
6610 int gflag; /* go up if neccessary */
6611 int percent;
6613 struct canvas *cv;
6614 int done, have, m, dir;
6616 debug3("ChangeCanvasSize abs %d diff %d percent=%d\n", abs, diff, percent);
6617 if (abs == 0 && diff == 0)
6618 return 0;
6619 if (abs == 2)
6621 if (diff == 0)
6622 fcv->c_slweight = 0;
6623 else
6625 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6626 cv->c_slweight = 0;
6627 fcv->c_slweight = 1;
6628 cv = fcv->c_slback->c_slback;
6629 if (gflag && cv && cv->c_slback)
6630 ChangeCanvasSize(cv, abs, diff, gflag, percent);
6632 return diff;
6634 if (abs)
6636 if (diff < 0)
6637 diff = 0;
6638 if (percent && diff > percent)
6639 diff = percent;
6641 if (percent)
6643 int wsum, up;
6644 for (cv = fcv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext)
6645 wsum += cv->c_slweight;
6646 if (wsum)
6648 up = gflag ? CalcSlicePercent(fcv->c_slback->c_slback, percent) : percent;
6649 debug3("up=%d, wsum=%d percent=%d\n", up, wsum, percent);
6650 if (wsum < 1000)
6652 int scale = wsum < 10 ? 1000 : 100;
6653 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6654 cv->c_slweight *= scale;
6655 wsum *= scale;
6656 debug1("scaled wsum to %d\n", wsum);
6658 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6660 if (cv->c_slweight)
6662 cv->c_slweight = (cv->c_slweight * up) / percent;
6663 if (cv->c_slweight == 0)
6664 cv->c_slweight = 1;
6666 debug1(" - weight %d\n", cv->c_slweight);
6668 diff = (diff * wsum) / percent;
6669 percent = wsum;
6672 else
6674 if (abs && diff == (fcv->c_slorient == SLICE_VERT ? fcv->c_ye - fcv->c_ys + 2 : fcv->c_xe - fcv->c_xs + 2))
6675 return 0;
6676 /* fix weights to real size (can't be helped, sorry) */
6677 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6679 cv->c_slweight = cv->c_slorient == SLICE_VERT ? cv->c_ye - cv->c_ys + 2 : cv->c_xe - cv->c_xs + 2;
6680 debug1(" - weight %d\n", cv->c_slweight);
6683 if (abs)
6684 diff = diff - fcv->c_slweight;
6685 debug1("diff = %d\n", diff);
6686 if (diff == 0)
6687 return 0;
6688 if (diff < 0)
6690 cv = fcv->c_slnext ? fcv->c_slnext : fcv->c_slprev;
6691 fcv->c_slweight += diff;
6692 cv->c_slweight -= diff;
6693 return diff;
6695 done = 0;
6696 dir = 1;
6697 for (cv = fcv->c_slnext; diff > 0; cv = dir > 0 ? cv->c_slnext : cv->c_slprev)
6699 if (!cv)
6701 debug1("reached end, dir is %d\n", dir);
6702 if (dir == -1)
6703 break;
6704 dir = -1;
6705 cv = fcv;
6706 continue;
6708 if (percent)
6709 m = 1;
6710 else
6711 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 : 2;
6712 debug2("min is %d, have %d\n", m, cv->c_slweight);
6713 if (cv->c_slweight > m)
6715 have = cv->c_slweight - m;
6716 if (have > diff)
6717 have = diff;
6718 debug1("subtract %d\n", have);
6719 cv->c_slweight -= have;
6720 done += have;
6721 diff -= have;
6724 if (diff && gflag)
6726 /* need more room! */
6727 cv = fcv->c_slback->c_slback;
6728 if (cv && cv->c_slback)
6729 done += ChangeCanvasSize(fcv->c_slback->c_slback, 0, diff, gflag, percent);
6731 fcv->c_slweight += done;
6732 debug1("ChangeCanvasSize returns %d\n", done);
6733 return done;
6736 static void
6737 ResizeRegions(arg, flags)
6738 char *arg;
6739 int flags;
6741 struct canvas *cv;
6742 int diff, l;
6743 int gflag = 0, abs = 0, percent = 0;
6744 int orient = 0;
6746 ASSERT(display);
6747 if (!*arg)
6748 return;
6749 if (D_forecv->c_slorient == SLICE_UNKN)
6751 Msg(0, "resize: need more than one region");
6752 return;
6754 gflag = flags & RESIZE_FLAG_L ? 0 : 1;
6755 orient |= flags & RESIZE_FLAG_H ? SLICE_HORI : 0;
6756 orient |= flags & RESIZE_FLAG_V ? SLICE_VERT : 0;
6757 if (orient == 0)
6758 orient = D_forecv->c_slorient;
6759 l = strlen(arg);
6760 if (*arg == '=')
6762 /* make all regions the same height */
6763 struct canvas *cv = gflag ? &D_canvas : D_forecv->c_slback;
6764 if (cv->c_slperp->c_slorient & orient)
6765 EqualizeCanvas(cv->c_slperp, gflag);
6766 /* can't use cv->c_slorient directly as it can be D_canvas */
6767 if ((cv->c_slperp->c_slorient ^ (SLICE_HORI ^ SLICE_VERT)) & orient)
6769 if (cv->c_slback)
6771 cv = cv->c_slback;
6772 EqualizeCanvas(cv->c_slperp, gflag);
6774 else
6775 EqualizeCanvas(cv, gflag);
6777 ResizeCanvas(cv);
6778 RecreateCanvasChain();
6779 RethinkDisplayViewports();
6780 ResizeLayersToCanvases();
6781 return;
6783 if (!strcmp(arg, "min") || !strcmp(arg, "0"))
6785 abs = 2;
6786 diff = 0;
6788 else if (!strcmp(arg, "max") || !strcmp(arg, "_"))
6790 abs = 2;
6791 diff = 1;
6793 else
6795 if (l > 0 && arg[l - 1] == '%')
6796 percent = 1000;
6797 if (*arg == '+')
6798 diff = atoi(arg + 1);
6799 else if (*arg == '-')
6800 diff = -atoi(arg + 1);
6801 else
6803 diff = atoi(arg); /* +1 because of caption line */
6804 if (diff < 0)
6805 diff = 0;
6806 abs = diff == 0 ? 2 : 1;
6809 if (!abs && !diff)
6810 return;
6811 if (percent)
6812 diff = diff * percent / 100;
6813 cv = D_forecv;
6814 if (cv->c_slorient & orient)
6815 ChangeCanvasSize(cv, abs, diff, gflag, percent);
6816 if (cv->c_slback->c_slorient & orient)
6817 ChangeCanvasSize(cv->c_slback, abs, diff, gflag, percent);
6819 ResizeCanvas(&D_canvas);
6820 RecreateCanvasChain();
6821 RethinkDisplayViewports();
6822 ResizeLayersToCanvases();
6823 return;
6825 #if 0
6827 if (siz + diff < 1)
6828 diff = 1 - siz;
6829 if (siz + diff > dsize - (nreg - 1) * 2 - 1)
6830 diff = dsize - (nreg - 1) * 2 - 1 - siz;
6831 if (diff == 0 || siz + diff < 1)
6832 return;
6834 if (diff < 0)
6836 if (D_forecv->c_next)
6838 D_forecv->c_ye += diff;
6839 D_forecv->c_next->c_ys += diff;
6840 D_forecv->c_next->c_yoff += diff;
6842 else
6844 for (cv = D_cvlist; cv; cv = cv->c_next)
6845 if (cv->c_next == D_forecv)
6846 break;
6847 ASSERT(cv);
6848 cv->c_ye -= diff;
6849 D_forecv->c_ys -= diff;
6850 D_forecv->c_yoff -= diff;
6853 else
6855 int s, i = 0, found = 0, di = diff, d2;
6856 s = dsize - (nreg - 1) * 2 - 1 - siz;
6857 for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next)
6859 if (cv == D_forecv)
6861 cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff;
6862 cv->c_yoff -= cv->c_ys - i;
6863 cv->c_ys = i;
6864 found = 1;
6865 continue;
6867 s -= cv->c_ye - cv->c_ys;
6868 if (!found)
6870 if (s >= di)
6871 continue;
6872 d2 = di - s;
6874 else
6875 d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di;
6876 di -= d2;
6877 cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2;
6878 cv->c_yoff -= cv->c_ys - i;
6879 cv->c_ys = i;
6882 RethinkDisplayViewports();
6883 ResizeLayersToCanvases();
6884 #endif
6887 static void
6888 ResizeFin(buf, len, data)
6889 char *buf;
6890 int len;
6891 char *data;
6893 int ch;
6894 int flags = *(int *)data;
6895 ch = ((unsigned char *)buf)[len];
6896 if (ch == 0)
6898 ResizeRegions(buf, flags);
6899 return;
6901 if (ch == 'h')
6902 flags ^= RESIZE_FLAG_H;
6903 else if (ch == 'v')
6904 flags ^= RESIZE_FLAG_V;
6905 else if (ch == 'b')
6906 flags |= RESIZE_FLAG_H|RESIZE_FLAG_V;
6907 else if (ch == 'p')
6908 flags ^= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V;
6909 else if (ch == 'l')
6910 flags ^= RESIZE_FLAG_L;
6911 else
6912 return;
6913 inp_setprompt(resizeprompts[flags], NULL);
6914 *(int *)data = flags;
6915 buf[len] = '\034';
6918 void
6919 SetForeCanvas(d, cv)
6920 struct display *d;
6921 struct canvas *cv;
6923 struct display *odisplay = display;
6924 if (d->d_forecv == cv)
6925 return;
6927 display = d;
6928 D_forecv = cv;
6929 if ((focusminwidth && (focusminwidth < 0 || D_forecv->c_xe - D_forecv->c_xs + 1 < focusminwidth)) ||
6930 (focusminheight && (focusminheight < 0 || D_forecv->c_ye - D_forecv->c_ys + 1 < focusminheight)))
6932 ResizeCanvas(&D_canvas);
6933 RecreateCanvasChain();
6934 RethinkDisplayViewports();
6935 ResizeLayersToCanvases(); /* redisplays */
6937 fore = D_fore = Layer2Window(D_forecv->c_layer);
6938 if (D_other == fore)
6939 D_other = 0;
6940 flayer = D_forecv->c_layer;
6941 #ifdef RXVT_OSC
6942 if (D_xtermosc[2] || D_xtermosc[3])
6944 Activate(-1);
6946 else
6947 #endif
6949 RefreshHStatus();
6950 #ifdef RXVT_OSC
6951 RefreshXtermOSC();
6952 #endif
6953 flayer = D_forecv->c_layer;
6954 CV_CALL(D_forecv, LayRestore();LaySetCursor());
6955 WindowChanged(0, 'F');
6958 display = odisplay;
6961 #ifdef RXVT_OSC
6962 void
6963 RefreshXtermOSC()
6965 int i;
6966 struct win *p;
6968 p = Layer2Window(D_forecv->c_layer);
6969 for (i = 3; i >=0; i--)
6970 SetXtermOSC(i, p ? p->w_xtermosc[i] : 0);
6972 #endif
6975 ParseAttrColor(s1, s2, msgok)
6976 char *s1, *s2;
6977 int msgok;
6979 int i, n;
6980 char *s, *ss;
6981 int r = 0;
6983 s = s1;
6984 while (*s == ' ')
6985 s++;
6986 ss = s;
6987 while (*ss && *ss != ' ')
6988 ss++;
6989 while (*ss == ' ')
6990 ss++;
6991 if (*s && (s2 || *ss || !((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || *s == '.')))
6993 int mode = 0, n = 0;
6994 if (*s == '+')
6996 mode = 1;
6997 s++;
6999 else if (*s == '-')
7001 mode = -1;
7002 s++;
7004 else if (*s == '!')
7006 mode = 2;
7007 s++;
7009 else if (*s == '=')
7010 s++;
7011 if (*s >= '0' && *s <= '9')
7013 n = *s++ - '0';
7014 if (*s >= '0' && *s <= '9')
7015 n = n * 16 + (*s++ - '0');
7016 else if (*s >= 'a' && *s <= 'f')
7017 n = n * 16 + (*s++ - ('a' - 10));
7018 else if (*s >= 'A' && *s <= 'F')
7019 n = n * 16 + (*s++ - ('A' - 10));
7020 else if (*s && *s != ' ')
7022 if (msgok)
7023 Msg(0, "Illegal attribute hexchar '%c'", *s);
7024 return -1;
7027 else
7029 while (*s && *s != ' ')
7031 if (*s == 'd')
7032 n |= A_DI;
7033 else if (*s == 'u')
7034 n |= A_US;
7035 else if (*s == 'b')
7036 n |= A_BD;
7037 else if (*s == 'r')
7038 n |= A_RV;
7039 else if (*s == 's')
7040 n |= A_SO;
7041 else if (*s == 'B')
7042 n |= A_BL;
7043 else
7045 if (msgok)
7046 Msg(0, "Illegal attribute specifier '%c'", *s);
7047 return -1;
7049 s++;
7052 if (*s && *s != ' ')
7054 if (msgok)
7055 Msg(0, "junk after attribute description: '%c'", *s);
7056 return -1;
7058 if (mode == -1)
7059 r = n << 8 | n;
7060 else if (mode == 1)
7061 r = n << 8;
7062 else if (mode == 2)
7063 r = n;
7064 else if (mode == 0)
7065 r = 0xffff ^ n;
7067 while (*s && *s == ' ')
7068 s++;
7070 if (s2)
7072 if (*s)
7074 if (msgok)
7075 Msg(0, "junk after description: '%c'", *s);
7076 return -1;
7078 s = s2;
7079 while (*s && *s == ' ')
7080 s++;
7083 #ifdef COLOR
7084 if (*s)
7086 static char costr[] = "krgybmcw d i.01234567 9 f FKRGYBMCW I ";
7087 int numco = 0, j;
7089 n = 0;
7090 if (*s == '.')
7092 numco++;
7093 n = 0x0f;
7094 s++;
7096 for (j = 0; j < 2 && *s && *s != ' '; j++)
7098 for (i = 0; costr[i]; i++)
7099 if (*s == costr[i])
7100 break;
7101 if (!costr[i])
7103 if (msgok)
7104 Msg(0, "illegal color descriptor: '%c'", *s);
7105 return -1;
7107 numco++;
7108 n = n << 4 | (i & 15);
7109 #ifdef COLORS16
7110 if (i >= 48)
7111 n = (n & 0x20ff) | 0x200;
7112 #endif
7113 s++;
7115 if ((n & 0xf00) == 0xf00)
7116 n ^= 0xf00; /* clear superflous bits */
7117 #ifdef COLORS16
7118 if (n & 0x2000)
7119 n ^= 0x2400; /* shift bit into right position */
7120 #endif
7121 if (numco == 1)
7122 n |= 0xf0; /* don't change bg color */
7123 if (numco != 2 && n != 0xff)
7124 n |= 0x100; /* special invert mode */
7125 if (*s && *s != ' ')
7127 if (msgok)
7128 Msg(0, "junk after color description: '%c'", *s);
7129 return -1;
7131 n ^= 0xff;
7132 r |= n << 16;
7134 #endif
7136 while (*s && *s == ' ')
7137 s++;
7138 if (*s)
7140 if (msgok)
7141 Msg(0, "junk after description: '%c'", *s);
7142 return -1;
7144 debug1("ParseAttrColor %06x\n", r);
7145 return r;
7149 * Color coding:
7150 * 0-7 normal colors
7151 * 9 default color
7152 * e just set intensity
7153 * f don't change anything
7154 * Intensity is encoded into bits 17(fg) and 18(bg).
7156 void
7157 ApplyAttrColor(i, mc)
7158 int i;
7159 struct mchar *mc;
7161 debug1("ApplyAttrColor %06x\n", i);
7162 mc->attr |= i >> 8 & 255;
7163 mc->attr ^= i & 255;
7164 #ifdef COLOR
7165 i = (i >> 16) ^ 0xff;
7166 if ((i & 0x100) != 0)
7168 i &= 0xeff;
7169 if (mc->attr & (A_SO|A_RV))
7170 # ifdef COLORS16
7171 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4) | ((i & 0x200) << 1) | ((i & 0x400) >> 1);
7172 # else
7173 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4);
7174 # endif
7176 # ifdef COLORS16
7177 if ((i & 0x0f) != 0x0f)
7178 mc->attr = (mc->attr & 0xbf) | ((i >> 3) & 0x40);
7179 if ((i & 0xf0) != 0xf0)
7180 mc->attr = (mc->attr & 0x7f) | ((i >> 3) & 0x80);
7181 # endif
7182 mc->color = 0x99 ^ mc->color;
7183 if ((i & 0x0e) == 0x0e)
7184 i = (i & 0xf0) | (mc->color & 0x0f);
7185 if ((i & 0xe0) == 0xe0)
7186 i = (i & 0x0f) | (mc->color & 0xf0);
7187 mc->color = 0x99 ^ i;
7188 debug2("ApplyAttrColor - %02x %02x\n", mc->attr, i);
7189 #endif