Fix 'hardcopy -h'.
[screen-lua.git] / src / process.c
blob783fdd7566845aca8dcd74ce63f8ceb457147acc
1 /* Copyright (c) 2010
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
4 * Copyright (c) 2008, 2009
5 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
6 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
7 * Micah Cowan (micah@cowan.name)
8 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
9 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
10 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
11 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
12 * Copyright (c) 1987 Oliver Laumann
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3, or (at your option)
17 * any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program (see the file COPYING); if not, see
26 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 ****************************************************************
32 #include "config.h"
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX)
39 # include <time.h>
40 #endif
41 #include <sys/time.h>
42 #ifndef sun
43 #include <sys/ioctl.h>
44 #endif
47 /* for solaris 2.1, Unixware (SVR4.2) and possibly others: */
48 #ifdef HAVE_STROPTS_H
49 # include <sys/stropts.h>
50 #endif
52 #include "screen.h"
53 #include "extern.h"
54 #include "logfile.h"
55 #include "layout.h"
56 #include "viewport.h"
57 #include "list_generic.h"
59 extern struct comm comms[];
60 extern char *rc_name;
61 extern char *RcFileName, *home;
62 extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
63 extern char *hstatusstring, *captionstring, *timestring;
64 extern char *wliststr, *wlisttit;
65 extern int captionalways;
66 extern int queryflag;
67 extern char *hardcopydir, *screenlogfile, *logtstamp_string;
68 extern int log_flush, logtstamp_on, logtstamp_after;
69 extern char *VisualBellString;
70 extern int VBellWait, MsgWait, MsgMinWait, SilenceWait;
71 extern char SockPath[], *SockName;
72 extern int TtyMode, auto_detach, use_altscreen;
73 extern int iflag, maxwin;
74 extern int focusminwidth, focusminheight;
75 extern int use_hardstatus, visual_bell;
76 #ifdef COLOR
77 extern int attr2color[][4];
78 extern int nattr2color;
79 #endif
80 extern int hardstatusemu;
81 extern char *printcmd;
82 extern int default_startup;
83 extern int defobuflimit;
84 extern int defnonblock;
85 extern int defmousetrack;
86 extern int ZombieKey_destroy;
87 extern int ZombieKey_resurrect;
88 extern int ZombieKey_onerror;
89 #ifdef AUTO_NUKE
90 extern int defautonuke;
91 #endif
92 extern int separate_sids;
93 extern struct NewWindow nwin_default, nwin_undef;
94 #ifdef COPY_PASTE
95 extern int join_with_cr;
96 extern int compacthist;
97 extern int search_ic;
98 # ifdef FONT
99 extern int pastefont;
100 # endif
101 extern unsigned char mark_key_tab[];
102 extern char *BufferFile;
103 #endif
104 #ifdef POW_DETACH
105 extern char *BufferFile, *PowDetachString;
106 #endif
107 #ifdef MULTIUSER
108 extern struct acluser *EffectiveAclUser; /* acl.c */
109 #endif
110 extern struct term term[]; /* terminal capabilities */
111 #ifdef MAPKEYS
112 extern char *kmapdef[];
113 extern char *kmapadef[];
114 extern char *kmapmdef[];
115 #endif
116 extern struct mchar mchar_so, mchar_null;
117 extern int renditions[];
118 extern int VerboseCreate;
119 #ifdef UTF8
120 extern char *screenencodings;
121 #endif
122 #ifdef DW_CHARS
123 extern int cjkwidth;
124 #endif
126 static int CheckArgNum __P((int, char **));
127 static void ClearAction __P((struct action *));
128 static void SaveAction __P((struct action *, int, char **, int *));
129 static int NextWindow __P((void));
130 static int PreviousWindow __P((void));
131 static int MoreWindows __P((void));
132 static void LogToggle __P((int));
133 static void ShowInfo __P((void));
134 static void ShowDInfo __P((void));
135 static struct win *WindowByName __P((char *));
136 static int WindowByNumber __P((char *));
137 static int ParseOnOff __P((struct action *, int *));
138 static int ParseWinNum __P((struct action *, int *));
139 static int ParseBase __P((struct action *, char *, int *, int, char *));
140 static int ParseNum1000 __P((struct action *, int *));
141 static char **SaveArgs __P((char **));
142 static int IsNum __P((char *, int));
143 static void Colonfin __P((char *, int, char *));
144 static void InputSelect __P((void));
145 static void InputSetenv __P((char *));
146 static void InputAKA __P((void));
147 #ifdef MULTIUSER
148 static int InputSu __P((struct win *, struct acluser **, char *));
149 static void su_fin __P((char *, int, char *));
150 #endif
151 static void AKAfin __P((char *, int, char *));
152 #ifdef COPY_PASTE
153 static void copy_reg_fn __P((char *, int, char *));
154 static void ins_reg_fn __P((char *, int, char *));
155 #endif
156 static void process_fn __P((char *, int, char *));
157 #ifdef PASSWORD
158 static void pass1 __P((char *, int, char *));
159 static void pass2 __P((char *, int, char *));
160 #endif
161 #ifdef POW_DETACH
162 static void pow_detach_fn __P((char *, int, char *));
163 #endif
164 static void digraph_fn __P((char *, int, char *));
165 static int digraph_find __P((const char *buf));
166 static void confirm_fn __P((char *, int, char *));
167 static int IsOnDisplay __P((struct win *));
168 static void ResizeRegions __P((char *, int));
169 static void ResizeFin __P((char *, int, char *));
170 static struct action *FindKtab __P((char *, int));
171 static void SelectFin __P((char *, int, char *));
172 static void SelectLayoutFin __P((char *, int, char *));
175 extern struct layer *flayer;
176 extern struct display *display, *displays;
177 extern struct win *fore, *console_window, *windows;
178 extern struct acluser *users;
179 extern struct layout *layouts, *layout_attach, layout_last_marker;
180 extern struct layout *laytab[];
182 extern char screenterm[], HostName[], version[];
183 extern struct NewWindow nwin_undef, nwin_default;
184 extern struct LayFuncs WinLf, MarkLf;
186 extern int Z0width, Z1width;
187 extern int real_uid, real_gid;
189 #ifdef NETHACK
190 extern int nethackflag;
191 #endif
194 extern struct win **wtab;
196 #ifdef MULTIUSER
197 extern char *multi;
198 extern int maxusercount;
199 #endif
200 char NullStr[] = "";
202 struct plop plop_tab[MAX_PLOP_DEFS];
204 #ifndef PTYMODE
205 # define PTYMODE 0622
206 #endif
208 int TtyMode = PTYMODE;
209 int hardcopy_append = 0;
210 int all_norefresh = 0;
211 #ifdef ZMODEM
212 int zmodem_mode = 0;
213 char *zmodem_sendcmd;
214 char *zmodem_recvcmd;
215 static char *zmodes[4] = {"off", "auto", "catch", "pass"};
216 #endif
218 int idletimo;
219 struct action idleaction;
220 #ifdef BLANKER_PRG
221 char **blankerprg;
222 #endif
224 struct action ktab[256 + KMAP_KEYS]; /* command key translation table */
225 struct kclass {
226 struct kclass *next;
227 char *name;
228 struct action ktab[256 + KMAP_KEYS];
230 struct kclass *kclasses;
232 #ifdef MAPKEYS
233 struct action umtab[KMAP_KEYS+KMAP_AKEYS];
234 struct action dmtab[KMAP_KEYS+KMAP_AKEYS];
235 struct action mmtab[KMAP_KEYS+KMAP_AKEYS];
236 struct kmap_ext *kmap_exts;
237 int kmap_extn;
238 static int maptimeout = 300;
239 #endif
241 #ifndef MAX_DIGRAPH
242 #define MAX_DIGRAPH 512
243 #endif
245 struct digraph
247 unsigned char d[2];
248 int value;
251 /* digraph table taken from old vim and rfc1345 */
252 static struct digraph digraphs[MAX_DIGRAPH + 1] = {
253 {' ', ' ', 160}, /*   */
254 {'N', 'S', 160}, /*   */
255 {'~', '!', 161}, /* ¡ */
256 {'!', '!', 161}, /* ¡ */
257 {'!', 'I', 161}, /* ¡ */
258 {'c', '|', 162}, /* ¢ */
259 {'c', 't', 162}, /* ¢ */
260 {'$', '$', 163}, /* £ */
261 {'P', 'd', 163}, /* £ */
262 {'o', 'x', 164}, /* ¤ */
263 {'C', 'u', 164}, /* ¤ */
264 {'C', 'u', 164}, /* ¤ */
265 {'E', 'u', 164}, /* ¤ */
266 {'Y', '-', 165}, /* ¥ */
267 {'Y', 'e', 165}, /* ¥ */
268 {'|', '|', 166}, /* ¦ */
269 {'B', 'B', 166}, /* ¦ */
270 {'p', 'a', 167}, /* § */
271 {'S', 'E', 167}, /* § */
272 {'"', '"', 168}, /* ¨ */
273 {'\'', ':', 168}, /* ¨ */
274 {'c', 'O', 169}, /* © */
275 {'C', 'o', 169}, /* © */
276 {'a', '-', 170}, /* ª */
277 {'<', '<', 171}, /* « */
278 {'-', ',', 172}, /* ¬ */
279 {'N', 'O', 172}, /* ¬ */
280 {'-', '-', 173}, /* ­ */
281 {'r', 'O', 174}, /* ® */
282 {'R', 'g', 174}, /* ® */
283 {'-', '=', 175}, /* ¯ */
284 {'\'', 'm', 175}, /* ¯ */
285 {'~', 'o', 176}, /* ° */
286 {'D', 'G', 176}, /* ° */
287 {'+', '-', 177}, /* ± */
288 {'2', '2', 178}, /* ² */
289 {'2', 'S', 178}, /* ² */
290 {'3', '3', 179}, /* ³ */
291 {'3', 'S', 179}, /* ³ */
292 {'\'', '\'', 180}, /* ´ */
293 {'j', 'u', 181}, /* µ */
294 {'M', 'y', 181}, /* µ */
295 {'p', 'p', 182}, /* ¶ */
296 {'P', 'I', 182}, /* ¶ */
297 {'~', '.', 183}, /* · */
298 {'.', 'M', 183}, /* · */
299 {',', ',', 184}, /* ¸ */
300 {'\'', ',', 184}, /* ¸ */
301 {'1', '1', 185}, /* ¹ */
302 {'1', 'S', 185}, /* ¹ */
303 {'o', '-', 186}, /* º */
304 {'>', '>', 187}, /* » */
305 {'1', '4', 188}, /* ¼ */
306 {'1', '2', 189}, /* ½ */
307 {'3', '4', 190}, /* ¾ */
308 {'~', '?', 191}, /* ¿ */
309 {'?', '?', 191}, /* ¿ */
310 {'?', 'I', 191}, /* ¿ */
311 {'A', '`', 192}, /* À */
312 {'A', '!', 192}, /* À */
313 {'A', '\'', 193}, /* Á */
314 {'A', '^', 194}, /* Â */
315 {'A', '>', 194}, /* Â */
316 {'A', '~', 195}, /* Ã */
317 {'A', '?', 195}, /* Ã */
318 {'A', '"', 196}, /* Ä */
319 {'A', ':', 196}, /* Ä */
320 {'A', '@', 197}, /* Å */
321 {'A', 'A', 197}, /* Å */
322 {'A', 'E', 198}, /* Æ */
323 {'C', ',', 199}, /* Ç */
324 {'E', '`', 200}, /* È */
325 {'E', '!', 200}, /* È */
326 {'E', '\'', 201}, /* É */
327 {'E', '^', 202}, /* Ê */
328 {'E', '>', 202}, /* Ê */
329 {'E', '"', 203}, /* Ë */
330 {'E', ':', 203}, /* Ë */
331 {'I', '`', 204}, /* Ì */
332 {'I', '!', 204}, /* Ì */
333 {'I', '\'', 205}, /* Í */
334 {'I', '^', 206}, /* Î */
335 {'I', '>', 206}, /* Î */
336 {'I', '"', 207}, /* Ï */
337 {'I', ':', 207}, /* Ï */
338 {'D', '-', 208}, /* Ð */
339 {'N', '~', 209}, /* Ñ */
340 {'N', '?', 209}, /* Ñ */
341 {'O', '`', 210}, /* Ò */
342 {'O', '!', 210}, /* Ò */
343 {'O', '\'', 211}, /* Ó */
344 {'O', '^', 212}, /* Ô */
345 {'O', '>', 212}, /* Ô */
346 {'O', '~', 213}, /* Õ */
347 {'O', '?', 213}, /* Õ */
348 {'O', '"', 214}, /* Ö */
349 {'O', ':', 214}, /* Ö */
350 {'/', '\\', 215}, /* × */
351 {'*', 'x', 215}, /* × */
352 {'O', '/', 216}, /* Ø */
353 {'U', '`', 217}, /* Ù */
354 {'U', '!', 217}, /* Ù */
355 {'U', '\'', 218}, /* Ú */
356 {'U', '^', 219}, /* Û */
357 {'U', '>', 219}, /* Û */
358 {'U', '"', 220}, /* Ü */
359 {'U', ':', 220}, /* Ü */
360 {'Y', '\'', 221}, /* Ý */
361 {'I', 'p', 222}, /* Þ */
362 {'T', 'H', 222}, /* Þ */
363 {'s', 's', 223}, /* ß */
364 {'s', '"', 223}, /* ß */
365 {'a', '`', 224}, /* à */
366 {'a', '!', 224}, /* à */
367 {'a', '\'', 225}, /* á */
368 {'a', '^', 226}, /* â */
369 {'a', '>', 226}, /* â */
370 {'a', '~', 227}, /* ã */
371 {'a', '?', 227}, /* ã */
372 {'a', '"', 228}, /* ä */
373 {'a', ':', 228}, /* ä */
374 {'a', 'a', 229}, /* å */
375 {'a', 'e', 230}, /* æ */
376 {'c', ',', 231}, /* ç */
377 {'e', '`', 232}, /* è */
378 {'e', '!', 232}, /* è */
379 {'e', '\'', 233}, /* é */
380 {'e', '^', 234}, /* ê */
381 {'e', '>', 234}, /* ê */
382 {'e', '"', 235}, /* ë */
383 {'e', ':', 235}, /* ë */
384 {'i', '`', 236}, /* ì */
385 {'i', '!', 236}, /* ì */
386 {'i', '\'', 237}, /* í */
387 {'i', '^', 238}, /* î */
388 {'i', '>', 238}, /* î */
389 {'i', '"', 239}, /* ï */
390 {'i', ':', 239}, /* ï */
391 {'d', '-', 240}, /* ð */
392 {'n', '~', 241}, /* ñ */
393 {'n', '?', 241}, /* ñ */
394 {'o', '`', 242}, /* ò */
395 {'o', '!', 242}, /* ò */
396 {'o', '\'', 243}, /* ó */
397 {'o', '^', 244}, /* ô */
398 {'o', '>', 244}, /* ô */
399 {'o', '~', 245}, /* õ */
400 {'o', '?', 245}, /* õ */
401 {'o', '"', 246}, /* ö */
402 {'o', ':', 246}, /* ö */
403 {':', '-', 247}, /* ÷ */
404 {'o', '/', 248}, /* ø */
405 {'u', '`', 249}, /* ù */
406 {'u', '!', 249}, /* ù */
407 {'u', '\'', 250}, /* ú */
408 {'u', '^', 251}, /* û */
409 {'u', '>', 251}, /* û */
410 {'u', '"', 252}, /* ü */
411 {'u', ':', 252}, /* ü */
412 {'y', '\'', 253}, /* ý */
413 {'i', 'p', 254}, /* þ */
414 {'t', 'h', 254}, /* þ */
415 {'y', '"', 255}, /* ÿ */
416 {'y', ':', 255}, /* ÿ */
417 {'"', '[', 196}, /* Ä */
418 {'"', '\\', 214}, /* Ö */
419 {'"', ']', 220}, /* Ü */
420 {'"', '{', 228}, /* ä */
421 {'"', '|', 246}, /* ö */
422 {'"', '}', 252}, /* ü */
423 {'"', '~', 223} /* ß */
426 #define RESIZE_FLAG_H 1
427 #define RESIZE_FLAG_V 2
428 #define RESIZE_FLAG_L 4
430 static char *resizeprompts[] = {
431 "resize # lines: ",
432 "resize -h # lines: ",
433 "resize -v # lines: ",
434 "resize -b # lines: ",
435 "resize -l # lines: ",
436 "resize -l -h # lines: ",
437 "resize -l -v # lines: ",
438 "resize -l -b # lines: ",
441 static int
442 parse_input_int(buf, len, val)
443 const char *buf;
444 int len;
445 int *val;
447 int x = 0, i;
448 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))))
450 x = 0;
451 for (i = 2; i < len; i++)
453 if (buf[i] >= '0' && buf[i] <= '9')
454 x = x * 16 | (buf[i] - '0');
455 else if (buf[i] >= 'a' && buf[i] <= 'f')
456 x = x * 16 | (buf[i] - ('a' - 10));
457 else if (buf[i] >= 'A' && buf[i] <= 'F')
458 x = x * 16 | (buf[i] - ('A' - 10));
459 else
460 return 0;
463 else if (buf[0] == '0')
465 x = 0;
466 for (i = 1; i < len; i++)
468 if (buf[i] < '0' || buf[i] > '7')
469 return 0;
470 x = x * 8 | (buf[i] - '0');
473 else
474 return 0;
475 *val = x;
476 return 1;
479 char *noargs[1];
481 void
482 InitKeytab()
484 register unsigned int i;
485 #ifdef MAPKEYS
486 char *argarr[2];
487 #endif
489 for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
491 ktab[i].nr = RC_ILLEGAL;
492 ktab[i].args = noargs;
493 ktab[i].argl = 0;
495 #ifdef MAPKEYS
496 for (i = 0; i < KMAP_KEYS+KMAP_AKEYS; i++)
498 umtab[i].nr = RC_ILLEGAL;
499 umtab[i].args = noargs;
500 umtab[i].argl = 0;
501 dmtab[i].nr = RC_ILLEGAL;
502 dmtab[i].args = noargs;
503 dmtab[i].argl = 0;
504 mmtab[i].nr = RC_ILLEGAL;
505 mmtab[i].args = noargs;
506 mmtab[i].argl = 0;
508 argarr[1] = 0;
509 for (i = 0; i < NKMAPDEF; i++)
511 if (i + KMAPDEFSTART < T_CAPS)
512 continue;
513 if (i + KMAPDEFSTART >= T_CAPS + KMAP_KEYS)
514 continue;
515 if (kmapdef[i] == 0)
516 continue;
517 argarr[0] = kmapdef[i];
518 SaveAction(dmtab + i + (KMAPDEFSTART - T_CAPS), RC_STUFF, argarr, 0);
520 for (i = 0; i < NKMAPADEF; i++)
522 if (i + KMAPADEFSTART < T_CURSOR)
523 continue;
524 if (i + KMAPADEFSTART >= T_CURSOR + KMAP_AKEYS)
525 continue;
526 if (kmapadef[i] == 0)
527 continue;
528 argarr[0] = kmapadef[i];
529 SaveAction(dmtab + i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS), RC_STUFF, argarr, 0);
531 for (i = 0; i < NKMAPMDEF; i++)
533 if (i + KMAPMDEFSTART < T_CAPS)
534 continue;
535 if (i + KMAPMDEFSTART >= T_CAPS + KMAP_KEYS)
536 continue;
537 if (kmapmdef[i] == 0)
538 continue;
539 argarr[0] = kmapmdef[i];
540 argarr[1] = 0;
541 SaveAction(mmtab + i + (KMAPMDEFSTART - T_CAPS), RC_STUFF, argarr, 0);
543 #endif
545 ktab['h'].nr = RC_HARDCOPY;
546 #ifdef BSDJOBS
547 ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND;
548 #endif
549 ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN;
550 ktab[' '].nr = ktab[Ctrl(' ')].nr =
551 ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT;
552 ktab['N'].nr = RC_NUMBER;
553 ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV;
554 ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL;
555 ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY;
556 ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS;
557 ktab['v'].nr = RC_VERSION;
558 ktab[Ctrl('v')].nr = RC_DIGRAPH;
559 ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON;
560 ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF;
561 ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME;
562 ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO;
563 ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG;
564 ktab['A'].nr = RC_TITLE;
565 #if defined(UTMPOK) && defined(LOGOUTOK)
566 ktab['L'].nr = RC_LOGIN;
567 #endif
568 ktab[','].nr = RC_LICENSE;
569 ktab['W'].nr = RC_WIDTH;
570 ktab['.'].nr = RC_DUMPTERMCAP;
571 ktab[Ctrl('\\')].nr = RC_QUIT;
572 #ifdef DETACH
573 ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH;
574 # ifdef POW_DETACH
575 ktab['D'].nr = RC_POW_DETACH;
576 # endif
577 #endif
578 ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP;
579 ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW;
580 ktab['C'].nr = RC_CLEAR;
581 ktab['Z'].nr = RC_RESET;
582 ktab['H'].nr = RC_LOG;
583 ktab['M'].nr = RC_MONITOR;
584 ktab['?'].nr = RC_HELP;
585 #ifdef MULTI
586 ktab['*'].nr = RC_DISPLAYS;
587 #endif
589 char *args[2];
590 args[0] = "-";
591 args[1] = NULL;
592 SaveAction(ktab + '-', RC_SELECT, args, 0);
594 for (i = 0; i < ((maxwin && maxwin < 10) ? maxwin : 10); i++)
596 char *args[2], arg1[10];
597 args[0] = arg1;
598 args[1] = 0;
599 sprintf(arg1, "%d", i);
600 SaveAction(ktab + '0' + i, RC_SELECT, args, 0);
602 ktab['\''].nr = RC_SELECT; /* calling a window by name */
604 char *args[2];
605 args[0] = "-b";
606 args[1] = 0;
607 SaveAction(ktab + '"', RC_WINDOWLIST, args, 0);
609 ktab[Ctrl('G')].nr = RC_VBELL;
610 ktab[':'].nr = RC_COLON;
611 #ifdef COPY_PASTE
612 ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY;
614 char *args[2];
615 args[0] = ".";
616 args[1] = 0;
617 SaveAction(ktab + ']', RC_PASTE, args, 0);
618 SaveAction(ktab + Ctrl(']'), RC_PASTE, args, 0);
620 ktab['{'].nr = RC_HISTORY;
621 ktab['}'].nr = RC_HISTORY;
622 ktab['>'].nr = RC_WRITEBUF;
623 ktab['<'].nr = RC_READBUF;
624 ktab['='].nr = RC_REMOVEBUF;
625 #endif
626 #ifdef POW_DETACH
627 ktab['D'].nr = RC_POW_DETACH;
628 #endif
629 #ifdef LOCK
630 ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN;
631 #endif
632 ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK;
633 ktab['B'].nr = RC_POW_BREAK;
634 ktab['_'].nr = RC_SILENCE;
635 ktab['S'].nr = RC_SPLIT;
636 ktab['Q'].nr = RC_ONLY;
637 ktab['X'].nr = RC_REMOVE;
638 ktab['F'].nr = RC_FIT;
639 ktab['\t'].nr = RC_FOCUS;
641 char *args[2];
642 args[0] = "prev";
643 args[1] = 0;
644 SaveAction(ktab + T_BACKTAB - T_CAPS + 256, RC_FOCUS, args, 0);
647 char *args[2];
648 args[0] = "-v";
649 args[1] = 0;
650 SaveAction(ktab + '|', RC_SPLIT, args, 0);
652 /* These come last; they may want overwrite others: */
653 if (DefaultEsc >= 0)
655 ClearAction(&ktab[DefaultEsc]);
656 ktab[DefaultEsc].nr = RC_OTHER;
658 if (DefaultMetaEsc >= 0)
660 ClearAction(&ktab[DefaultMetaEsc]);
661 ktab[DefaultMetaEsc].nr = RC_META;
664 idleaction.nr = RC_BLANKER;
665 idleaction.args = noargs;
666 idleaction.argl = 0;
669 static struct action *
670 FindKtab(class, create)
671 char *class;
672 int create;
674 struct kclass *kp, **kpp;
675 int i;
677 if (class == 0)
678 return ktab;
679 for (kpp = &kclasses; (kp = *kpp) != 0; kpp = &kp->next)
680 if (!strcmp(kp->name, class))
681 break;
682 if (kp == 0)
684 if (!create)
685 return 0;
686 if (strlen(class) > 80)
688 Msg(0, "Command class name too long.");
689 return 0;
691 kp = malloc(sizeof(*kp));
692 if (kp == 0)
694 Msg(0, "%s", strnomem);
695 return 0;
697 kp->name = SaveStr(class);
698 for (i = 0; i < (int)(sizeof(kp->ktab)/sizeof(*kp->ktab)); i++)
700 kp->ktab[i].nr = RC_ILLEGAL;
701 kp->ktab[i].args = noargs;
702 kp->ktab[i].argl = 0;
703 kp->ktab[i].quiet = 0;
705 kp->next = 0;
706 *kpp = kp;
708 return kp->ktab;
711 static void
712 ClearAction(act)
713 struct action *act;
715 char **p;
717 if (act->nr == RC_ILLEGAL)
718 return;
719 act->nr = RC_ILLEGAL;
720 if (act->args == noargs)
721 return;
722 for (p = act->args; *p; p++)
723 free(*p);
724 free((char *)act->args);
725 act->args = noargs;
726 act->argl = 0;
730 * ProcessInput: process input from display and feed it into
731 * the layer on canvas D_forecv.
734 #ifdef MAPKEYS
737 * This ProcessInput just does the keybindings and passes
738 * everything else on to ProcessInput2.
741 void
742 ProcessInput(ibuf, ilen)
743 char *ibuf;
744 int ilen;
746 int ch, slen;
747 unsigned char *s, *q;
748 int i, l;
749 char *p;
751 debug1("ProcessInput: %d bytes\n", ilen);
752 if (display == 0 || ilen == 0)
753 return;
754 if (D_seql)
755 evdeq(&D_mapev);
756 slen = ilen;
757 s = (unsigned char *)ibuf;
758 while (ilen-- > 0)
760 ch = *s++;
761 if (D_dontmap || !D_nseqs)
763 D_dontmap = 0;
764 continue;
766 for (;;)
768 debug3("cmp %c %c[%d]\n", ch, *D_seqp, D_seqp - D_kmaps);
769 if (*D_seqp != ch)
771 l = D_seqp[D_seqp[-D_seql-1] + 1];
772 if (l)
774 D_seqp += l * 2 + 4;
775 debug1("miss %d\n", D_seqp - D_kmaps);
776 continue;
778 debug("complete miss\n");
779 D_mapdefault = 0;
780 l = D_seql;
781 p = (char *)D_seqp - l;
782 D_seql = 0;
783 D_seqp = D_kmaps + 3;
784 if (l == 0)
785 break;
786 if ((q = D_seqh) != 0)
788 D_seqh = 0;
789 i = q[0] << 8 | q[1];
790 i &= ~KMAP_NOTIMEOUT;
791 debug1("Mapping former hit #%d - ", i);
792 debug2("%d(%s) - ", q[2], q + 3);
793 if (StuffKey(i))
794 ProcessInput2((char *)q + 3, q[2]);
795 if (display == 0)
796 return;
797 l -= q[2];
798 p += q[2];
800 else
801 D_dontmap = 1;
802 debug1("flush old %d\n", l);
803 ProcessInput(p, l);
804 if (display == 0)
805 return;
806 evdeq(&D_mapev);
807 continue;
809 if (D_seql++ == 0)
811 /* Finish old stuff */
812 slen -= ilen + 1;
813 debug1("finish old %d\n", slen);
814 if (slen)
815 ProcessInput2(ibuf, slen);
816 if (display == 0)
817 return;
818 D_seqh = 0;
820 ibuf = (char *)s;
821 slen = ilen;
822 D_seqp++;
823 l = D_seql;
824 debug2("length am %d, want %d\n", l, D_seqp[-l - 1]);
825 if (l == D_seqp[-l - 1])
827 if (D_seqp[l] != l)
829 q = D_seqp + 1 + l;
830 if (D_kmaps + D_nseqs > q && q[2] > l && !bcmp(D_seqp - l, q + 3, l))
832 debug1("have another mapping (%s), delay execution\n", q + 3);
833 D_seqh = D_seqp - 3 - l;
834 D_seqp = q + 3 + l;
835 break;
838 i = D_seqp[-l - 3] << 8 | D_seqp[-l - 2];
839 i &= ~KMAP_NOTIMEOUT;
840 debug1("Mapping #%d - ", i);
841 p = (char *)D_seqp - l;
842 debug2("%d(%s) - ", l, p);
843 D_seql = 0;
844 D_seqp = D_kmaps + 3;
845 D_seqh = 0;
846 if (StuffKey(i))
847 ProcessInput2(p, l);
848 if (display == 0)
849 return;
851 break;
854 if (D_seql)
856 debug("am in sequence -> check for timeout\n");
857 l = D_seql;
858 for (s = D_seqp; ; s += i * 2 + 4)
860 if (s[-l-3] & KMAP_NOTIMEOUT >> 8)
861 break;
862 if ((i = s[s[-l-1] + 1]) == 0)
864 SetTimeout(&D_mapev, maptimeout);
865 evenq(&D_mapev);
866 break;
870 ProcessInput2(ibuf, slen);
873 #else
874 # define ProcessInput2 ProcessInput
875 #endif
879 * Here only the screen escape commands are handled.
882 void
883 ProcessInput2(ibuf, ilen)
884 char *ibuf;
885 int ilen;
887 char *s;
888 int ch, slen;
889 struct action *ktabp;
891 debug1("ProcessInput2: %d bytes\n", ilen);
892 while (ilen && display)
894 debug1(" - ilen now %d bytes\n", ilen);
895 flayer = D_forecv->c_layer;
896 fore = D_fore;
897 slen = ilen;
898 s = ibuf;
899 if (!D_ESCseen)
901 while (ilen > 0)
903 if ((unsigned char)*s++ == D_user->u_Esc)
904 break;
905 ilen--;
907 slen -= ilen;
908 if (slen)
909 DoProcess(fore, &ibuf, &slen, 0);
910 if (--ilen == 0)
911 D_ESCseen = ktab;
913 if (ilen <= 0)
914 return;
915 ktabp = D_ESCseen ? D_ESCseen : ktab;
916 D_ESCseen = 0;
917 ch = (unsigned char)*s;
920 * As users have different esc characters, but a common ktab[],
921 * we fold back the users esc and meta-esc key to the Default keys
922 * that can be looked up in the ktab[]. grmbl. jw.
923 * XXX: make ktab[] a per user thing.
925 if (ch == D_user->u_Esc)
926 ch = DefaultEsc;
927 else if (ch == D_user->u_MetaEsc)
928 ch = DefaultMetaEsc;
930 if (ch >= 0)
931 DoAction(&ktabp[ch], ch);
932 ibuf = (char *)(s + 1);
933 ilen--;
937 void
938 DoProcess(p, bufp, lenp, pa)
939 struct win *p;
940 char **bufp;
941 int *lenp;
942 struct paster *pa;
944 int oldlen;
945 struct display *d = display;
947 #ifdef COPY_PASTE
948 /* XXX -> PasteStart */
949 if (pa && *lenp > 1 && p && p->w_slowpaste)
951 /* schedule slowpaste event */
952 SetTimeout(&p->w_paster.pa_slowev, p->w_slowpaste);
953 evenq(&p->w_paster.pa_slowev);
954 return;
956 #endif
957 while (flayer && *lenp)
959 #ifdef COPY_PASTE
960 if (!pa && p && p->w_paster.pa_pastelen && flayer == p->w_paster.pa_pastelayer)
962 debug("layer is busy - beep!\n");
963 WBell(p, visual_bell);
964 *bufp += *lenp;
965 *lenp = 0;
966 display = d;
967 return;
969 #endif
970 oldlen = *lenp;
971 LayProcess(bufp, lenp);
972 #ifdef COPY_PASTE
973 if (pa && !pa->pa_pastelayer)
974 break; /* flush rest of paste */
975 #endif
976 if (*lenp == oldlen)
978 if (pa)
980 display = d;
981 return;
983 /* We're full, let's beep */
984 debug("layer is full - beep!\n");
985 WBell(p, visual_bell);
986 break;
989 *bufp += *lenp;
990 *lenp = 0;
991 display = d;
992 #ifdef COPY_PASTE
993 if (pa && pa->pa_pastelen == 0)
994 FreePaster(pa);
995 #endif
999 FindCommnr(str)
1000 const char *str;
1002 int x, m, l = 0, r = RC_LAST;
1003 while (l <= r)
1005 m = (l + r) / 2;
1006 x = strcmp(str, comms[m].name);
1007 if (x > 0)
1008 l = m + 1;
1009 else if (x < 0)
1010 r = m - 1;
1011 else
1012 return m;
1014 return RC_ILLEGAL;
1017 static int
1018 CheckArgNum(nr, args)
1019 int nr;
1020 char **args;
1022 int i, n;
1023 static char *argss[] = {"no", "one", "two", "three", "four", "OOPS"};
1024 static char *orformat[] =
1026 "%s: %s: %s argument%s required",
1027 "%s: %s: %s or %s argument%s required",
1028 "%s: %s: %s, %s or %s argument%s required",
1029 "%s: %s: %s, %s, %s or %s argument%s required"
1032 n = comms[nr].flags & ARGS_MASK;
1033 for (i = 0; args[i]; i++)
1035 if (comms[nr].flags & ARGS_ORMORE)
1037 if (i < n)
1039 Msg(0, "%s: %s: at least %s argument%s required",
1040 rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
1041 return -1;
1044 else if ((comms[nr].flags & ARGS_PLUS1) &&
1045 (comms[nr].flags & ARGS_PLUS2) &&
1046 (comms[nr].flags & ARGS_PLUS3))
1048 if (i != n && i != n + 1 && i != n + 2 && i != n + 3)
1050 Msg(0, orformat[3], rc_name, comms[nr].name, argss[n],
1051 argss[n + 1], argss[n + 2], argss[n + 3], "");
1052 return -1;
1055 else if ((comms[nr].flags & ARGS_PLUS1) &&
1056 (comms[nr].flags & ARGS_PLUS2))
1058 if (i != n && i != n + 1 && i != n + 2)
1060 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1061 argss[n + 1], argss[n + 2], "");
1062 return -1;
1065 else if ((comms[nr].flags & ARGS_PLUS1) &&
1066 (comms[nr].flags & ARGS_PLUS3))
1068 if (i != n && i != n + 1 && i != n + 3)
1070 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1071 argss[n + 1], argss[n + 3], "");
1072 return -1;
1075 else if ((comms[nr].flags & ARGS_PLUS2) &&
1076 (comms[nr].flags & ARGS_PLUS3))
1078 if (i != n && i != n + 2 && i != n + 3)
1080 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n],
1081 argss[n + 2], argss[n + 3], "");
1082 return -1;
1085 else if (comms[nr].flags & ARGS_PLUS1)
1087 if (i != n && i != n + 1)
1089 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1090 argss[n + 1], n != 0 ? "s" : "");
1091 return -1;
1094 else if (comms[nr].flags & ARGS_PLUS2)
1096 if (i != n && i != n + 2)
1098 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1099 argss[n + 2], "s");
1100 return -1;
1103 else if (comms[nr].flags & ARGS_PLUS3)
1105 if (i != n && i != n + 3)
1107 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n],
1108 argss[n + 3], "");
1109 return -1;
1112 else if (i != n)
1114 Msg(0, orformat[0], rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
1115 return -1;
1117 return i;
1120 static void
1121 StuffFin(buf, len, data)
1122 char *buf;
1123 int len;
1124 char *data;
1126 if (!flayer)
1127 return;
1128 while(len)
1129 LayProcess(&buf, &len);
1132 /* If the command is not 'quieted', then use Msg to output the message. If it's a remote
1133 * query, then Msg takes care of also outputting the message to the querying client.
1135 * If we want the command to be quiet, and it's a remote query, then use QueryMsg so that
1136 * the response does go back to the querying client.
1138 * If the command is quieted, and it's not a remote query, then just don't print the message.
1140 #define OutputMsg (!act->quiet ? Msg : queryflag >= 0 ? QueryMsg : Dummy)
1142 /*ARGSUSED*/
1143 void
1144 DoAction(act, key)
1145 struct action *act;
1146 int key;
1148 int nr = act->nr;
1149 char **args = act->args;
1150 int *argl = act->argl;
1151 struct win *p;
1152 int argc, i, n, msgok;
1153 char *s;
1154 char ch;
1155 struct display *odisplay = display;
1156 struct acluser *user;
1158 user = display ? D_user : users;
1159 if (nr == RC_ILLEGAL)
1161 debug1("key '%c': No action\n", key);
1162 return;
1164 n = comms[nr].flags;
1165 /* Commands will have a CAN_QUERY flag, depending on whether they have
1166 * something to return on a query. For example, 'windows' can return a result,
1167 * but 'other' cannot.
1168 * If some command causes an error, then it should reset queryflag to -1, so that
1169 * the process requesting the query can be notified that an error happened.
1171 if (!(n & CAN_QUERY) && queryflag >= 0)
1173 /* Query flag is set, but this command cannot be queried. */
1174 OutputMsg(0, "%s command cannot be queried.", comms[nr].name);
1175 queryflag = -1;
1176 return;
1178 if ((n & NEED_DISPLAY) && display == 0)
1180 OutputMsg(0, "%s: %s: display required", rc_name, comms[nr].name);
1181 queryflag = -1;
1182 return;
1184 if ((n & NEED_FORE) && fore == 0)
1186 OutputMsg(0, "%s: %s: window required", rc_name, comms[nr].name);
1187 queryflag = -1;
1188 return;
1190 if ((n & NEED_LAYER) && flayer == 0)
1192 OutputMsg(0, "%s: %s: display or window required", rc_name, comms[nr].name);
1193 queryflag = -1;
1194 return;
1196 if ((argc = CheckArgNum(nr, args)) < 0)
1197 return;
1198 #ifdef MULTIUSER
1199 if (display)
1201 if (AclCheckPermCmd(D_user, ACL_EXEC, &comms[nr]))
1203 OutputMsg(0, "%s: %s: permission denied (user %s)",
1204 rc_name, comms[nr].name, (EffectiveAclUser ? EffectiveAclUser : D_user)->u_name);
1205 queryflag = -1;
1206 return;
1209 #endif /* MULTIUSER */
1211 msgok = display && !*rc_name;
1212 switch(nr)
1214 case RC_SELECT:
1215 if (!*args)
1216 InputSelect();
1217 else if (args[0][0] == '-' && !args[0][1])
1219 SetForeWindow((struct win *)0);
1220 Activate(0);
1222 else if (args[0][0] == '.' && !args[0][1])
1224 if (!fore)
1226 OutputMsg(0, "select . needs a window");
1227 queryflag = -1;
1229 else
1231 SetForeWindow(fore);
1232 Activate(0);
1235 else if (ParseWinNum(act, &n) == 0)
1236 SwitchWindow(n);
1237 else if (queryflag >= 0)
1238 queryflag = -1; /* ParseWinNum already prints out an appropriate error message. */
1239 break;
1240 #ifdef AUTO_NUKE
1241 case RC_DEFAUTONUKE:
1242 if (ParseOnOff(act, &defautonuke) == 0 && msgok)
1243 OutputMsg(0, "Default autonuke turned %s", defautonuke ? "on" : "off");
1244 if (display && *rc_name)
1245 D_auto_nuke = defautonuke;
1246 break;
1247 case RC_AUTONUKE:
1248 if (ParseOnOff(act, &D_auto_nuke) == 0 && msgok)
1249 OutputMsg(0, "Autonuke turned %s", D_auto_nuke ? "on" : "off");
1250 break;
1251 #endif
1252 case RC_DEFOBUFLIMIT:
1253 if (ParseNum(act, &defobuflimit) == 0 && msgok)
1254 OutputMsg(0, "Default limit set to %d", defobuflimit);
1255 if (display && *rc_name)
1257 D_obufmax = defobuflimit;
1258 D_obuflenmax = D_obuflen - D_obufmax;
1260 break;
1261 case RC_OBUFLIMIT:
1262 if (*args == 0)
1263 OutputMsg(0, "Limit is %d, current buffer size is %d", D_obufmax, D_obuflen);
1264 else if (ParseNum(act, &D_obufmax) == 0 && msgok)
1265 OutputMsg(0, "Limit set to %d", D_obufmax);
1266 D_obuflenmax = D_obuflen - D_obufmax;
1267 break;
1268 case RC_DUMPTERMCAP:
1269 WriteFile(user, (char *)0, DUMP_TERMCAP);
1270 break;
1271 case RC_HARDCOPY:
1273 int mode = DUMP_HARDCOPY;
1274 char *file = NULL;
1276 if (args[0])
1278 if (!strcmp(*args, "-h"))
1280 mode = DUMP_SCROLLBACK;
1281 file = args[1];
1283 else if (!strcmp(*args, "--") && args[1])
1284 file = args[1];
1285 else
1286 file = args[0];
1289 if (args[0] && file == args[0] && args[1])
1291 OutputMsg(0, "%s: hardcopy: too many arguments", rc_name);
1292 break;
1294 if (fore == 0 && *args == 0)
1295 OutputMsg(0, "%s: hardcopy: window required", rc_name);
1296 else
1297 WriteFile(user, file, mode);
1299 break;
1300 case RC_DEFLOG:
1301 (void)ParseOnOff(act, &nwin_default.Lflag);
1302 break;
1303 case RC_LOG:
1304 n = fore->w_log ? 1 : 0;
1305 ParseSwitch(act, &n);
1306 LogToggle(n);
1307 break;
1308 #ifdef BSDJOBS
1309 case RC_SUSPEND:
1310 Detach(D_STOP);
1311 break;
1312 #endif
1313 case RC_NEXT:
1314 if (MoreWindows())
1315 SwitchWindow(NextWindow());
1316 break;
1317 case RC_PREV:
1318 if (MoreWindows())
1319 SwitchWindow(PreviousWindow());
1320 break;
1321 case RC_KILL:
1323 char *name;
1325 if (key >= 0)
1327 #ifdef PSEUDOS
1328 Input(fore->w_pwin ? "Really kill this filter [y/n]" : "Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL);
1329 #else
1330 Input("Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL);
1331 #endif
1332 break;
1334 n = fore->w_number;
1335 #ifdef PSEUDOS
1336 if (fore->w_pwin)
1338 FreePseudowin(fore);
1339 OutputMsg(0, "Filter removed.");
1340 break;
1342 #endif
1343 name = SaveStr(fore->w_title);
1344 KillWindow(fore);
1345 OutputMsg(0, "Window %d (%s) killed.", n, name);
1346 if (name)
1347 free(name);
1348 break;
1350 case RC_QUIT:
1351 if (key >= 0)
1353 Input("Really quit and kill all your windows [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_QUIT);
1354 break;
1356 Finit(0);
1357 /* NOTREACHED */
1358 #ifdef DETACH
1359 case RC_DETACH:
1360 if (*args && !strcmp(*args, "-h"))
1361 Hangup();
1362 else
1363 Detach(D_DETACH);
1364 break;
1365 # ifdef POW_DETACH
1366 case RC_POW_DETACH:
1367 if (key >= 0)
1369 static char buf[2];
1371 buf[0] = key;
1372 Input(buf, 1, INP_RAW, pow_detach_fn, NULL, 0);
1374 else
1375 Detach(D_POWER); /* detach and kill Attacher's parent */
1376 break;
1377 # endif
1378 #endif
1379 case RC_DEBUG:
1380 #ifdef DEBUG
1381 if (!*args)
1383 if (dfp)
1384 OutputMsg(0, "debugging info is written to %s/", DEBUGDIR);
1385 else
1386 OutputMsg(0, "debugging is currently off. Use 'debug on' to enable.");
1387 break;
1389 if (dfp)
1391 debug("debug: closing debug file.\n");
1392 fflush(dfp);
1393 fclose(dfp);
1394 dfp = NULL;
1396 if (strcmp("off", *args))
1397 opendebug(0, 1);
1398 # ifdef SIG_NODEBUG
1399 else if (display)
1400 kill(D_userpid, SIG_NODEBUG); /* a one shot item, but hey... */
1401 # endif /* SIG_NODEBUG */
1402 #else
1403 if (*args == 0 || strcmp("off", *args))
1404 OutputMsg(0, "Sorry, screen was compiled without -DDEBUG option.");
1405 #endif
1406 break;
1407 #ifdef ZMODEM
1408 case RC_ZMODEM:
1409 if (*args && !strcmp(*args, "sendcmd"))
1411 if (args[1])
1413 free(zmodem_sendcmd);
1414 zmodem_sendcmd = SaveStr(args[1]);
1416 if (msgok)
1417 OutputMsg(0, "zmodem sendcmd: %s", zmodem_sendcmd);
1418 break;
1420 if (*args && !strcmp(*args, "recvcmd"))
1422 if (args[1])
1424 free(zmodem_recvcmd);
1425 zmodem_recvcmd = SaveStr(args[1]);
1427 if (msgok)
1428 OutputMsg(0, "zmodem recvcmd: %s", zmodem_recvcmd);
1429 break;
1431 if (*args)
1433 for (i = 0; i < 4; i++)
1434 if (!strcmp(zmodes[i], *args))
1435 break;
1436 if (i == 4 && !strcmp(*args, "on"))
1437 i = 1;
1438 if (i == 4)
1440 OutputMsg(0, "usage: zmodem off|auto|catch|pass");
1441 break;
1443 zmodem_mode = i;
1445 if (msgok)
1446 OutputMsg(0, "zmodem mode is %s", zmodes[zmodem_mode]);
1447 break;
1448 #endif
1449 case RC_UNBINDALL:
1451 register unsigned int i;
1453 for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
1454 ClearAction(&ktab[i]);
1455 OutputMsg(0, "Unbound all keys." );
1456 break;
1458 case RC_ZOMBIE:
1460 if (!(s = *args))
1462 ZombieKey_destroy = 0;
1463 break;
1465 if (*argl == 0 || *argl > 2)
1467 OutputMsg(0, "%s:zombie: one or two characters expected.", rc_name);
1468 break;
1470 if (args[1])
1472 if (!strcmp(args[1], "onerror"))
1474 ZombieKey_onerror = 1;
1475 } else {
1476 OutputMsg(0, "usage: zombie [keys [onerror]]");
1477 break;
1479 } else
1480 ZombieKey_onerror = 0;
1481 ZombieKey_destroy = args[0][0];
1482 ZombieKey_resurrect = *argl == 2 ? args[0][1] : 0;
1484 break;
1485 case RC_WALL:
1486 #ifdef MULTIUSER
1487 s = D_user->u_name;
1488 #else
1489 s = D_usertty;
1490 #endif
1492 struct display *olddisplay = display;
1493 display = 0; /* no display will cause a broadcast */
1494 OutputMsg(0, "%s: %s", s, *args);
1495 display = olddisplay;
1497 break;
1498 case RC_AT:
1499 /* where this AT command comes from: */
1500 if (!user)
1501 break;
1502 #ifdef MULTIUSER
1503 s = SaveStr(user->u_name);
1504 /* DO NOT RETURN FROM HERE WITHOUT RESETTING THIS: */
1505 EffectiveAclUser = user;
1506 #else
1507 s = SaveStr(display ? D_usertty : user->u_name);
1508 #endif
1509 n = strlen(args[0]);
1510 if (n) n--;
1512 * the windows/displays loops are quite dangerous here, take extra
1513 * care not to trigger landmines. Things may appear/disappear while
1514 * we are walking along.
1516 switch (args[0][n])
1518 case '*': /* user */
1520 struct display *nd;
1521 struct acluser *u;
1523 if (!n)
1524 u = user;
1525 else
1527 for (u = users; u; u = u->u_next)
1529 debug3("strncmp('%s', '%s', %d)\n", *args, u->u_name, n);
1530 if (!strncmp(*args, u->u_name, n))
1531 break;
1533 if (!u)
1535 args[0][n] = '\0';
1536 OutputMsg(0, "Did not find any user matching '%s'", args[0]);
1537 break;
1540 debug1("at all displays of user %s\n", u->u_name);
1541 for (display = displays; display; display = nd)
1543 nd = display->d_next;
1544 if (D_forecv == 0)
1545 continue;
1546 flayer = D_forecv->c_layer;
1547 fore = D_fore;
1548 if (D_user != u)
1549 continue;
1550 debug1("AT display %s\n", D_usertty);
1551 DoCommand(args + 1, argl + 1);
1552 if (display)
1553 OutputMsg(0, "command from %s: %s %s",
1554 s, args[1], args[2] ? args[2] : "");
1555 display = NULL;
1556 flayer = 0;
1557 fore = NULL;
1559 break;
1561 case '%': /* display */
1563 struct display *nd;
1565 debug1("at display matching '%s'\n", args[0]);
1566 for (display = displays; display; display = nd)
1568 nd = display->d_next;
1569 if (D_forecv == 0)
1570 continue;
1571 fore = D_fore;
1572 flayer = D_forecv->c_layer;
1573 if (strncmp(args[0], D_usertty, n) &&
1574 (strncmp("/dev/", D_usertty, 5) ||
1575 strncmp(args[0], D_usertty + 5, n)) &&
1576 (strncmp("/dev/tty", D_usertty, 8) ||
1577 strncmp(args[0], D_usertty + 8, n)))
1578 continue;
1579 debug1("AT display %s\n", D_usertty);
1580 DoCommand(args + 1, argl + 1);
1581 if (display)
1582 OutputMsg(0, "command from %s: %s %s",
1583 s, args[1], args[2] ? args[2] : "");
1584 display = NULL;
1585 fore = NULL;
1586 flayer = 0;
1588 break;
1590 case '#': /* window */
1591 n--;
1592 /* FALLTHROUGH */
1593 default:
1595 struct win *nw;
1596 int ch;
1598 n++;
1599 ch = args[0][n];
1600 args[0][n] = '\0';
1601 if (!*args[0] || (i = WindowByNumber(args[0])) < 0)
1603 args[0][n] = ch; /* must restore string in case of bind */
1604 /* try looping over titles */
1605 for (fore = windows; fore; fore = nw)
1607 nw = fore->w_next;
1608 if (strncmp(args[0], fore->w_title, n))
1609 continue;
1610 debug2("AT window %d(%s)\n", fore->w_number, fore->w_title);
1612 * consider this a bug or a feature:
1613 * while looping through windows, we have fore AND
1614 * display context. This will confuse users who try to
1615 * set up loops inside of loops, but often allows to do
1616 * what you mean, even when you adress your context wrong.
1618 i = 0;
1619 /* XXX: other displays? */
1620 if (fore->w_layer.l_cvlist)
1621 display = fore->w_layer.l_cvlist->c_display;
1622 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1623 DoCommand(args + 1, argl + 1); /* may destroy our display */
1624 if (fore && fore->w_layer.l_cvlist)
1626 display = fore->w_layer.l_cvlist->c_display;
1627 OutputMsg(0, "command from %s: %s %s",
1628 s, args[1], args[2] ? args[2] : "");
1631 display = NULL;
1632 fore = NULL;
1633 if (i < 0)
1634 OutputMsg(0, "%s: at '%s': no such window.\n", rc_name, args[0]);
1635 break;
1637 else if (i < maxwin && (fore = wtab[i]))
1639 args[0][n] = ch; /* must restore string in case of bind */
1640 debug2("AT window %d (%s)\n", fore->w_number, fore->w_title);
1641 if (fore->w_layer.l_cvlist)
1642 display = fore->w_layer.l_cvlist->c_display;
1643 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
1644 DoCommand(args + 1, argl + 1);
1645 if (fore && fore->w_layer.l_cvlist)
1647 display = fore->w_layer.l_cvlist->c_display;
1648 OutputMsg(0, "command from %s: %s %s",
1649 s, args[1], args[2] ? args[2] : "");
1651 display = NULL;
1652 fore = NULL;
1654 else
1655 OutputMsg(0, "%s: at [identifier][%%|*|#] command [args]", rc_name);
1656 break;
1659 free(s);
1660 #ifdef MULTIUSER
1661 EffectiveAclUser = NULL;
1662 #endif
1663 break;
1665 #ifdef COPY_PASTE
1666 case RC_READREG:
1667 #ifdef ENCODINGS
1668 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
1669 if (args[0] && args[1] && !strcmp(args[0], "-e"))
1671 i = FindEncoding(args[1]);
1672 if (i == -1)
1674 OutputMsg(0, "%s: readreg: unknown encoding", rc_name);
1675 break;
1677 args += 2;
1679 #endif
1681 * Without arguments we prompt for a destination register.
1682 * It will receive the copybuffer contents.
1683 * This is not done by RC_PASTE, as we prompt for source
1684 * (not dest) there.
1686 if ((s = *args) == NULL)
1688 Input("Copy to register:", 1, INP_RAW, copy_reg_fn, NULL, 0);
1689 break;
1691 if (*argl != 1)
1693 OutputMsg(0, "%s: copyreg: character, ^x, or (octal) \\032 expected.", rc_name);
1694 break;
1696 ch = args[0][0];
1698 * With two arguments we *really* read register contents from file
1700 if (args[1])
1702 if (args[2])
1704 OutputMsg(0, "%s: readreg: too many arguments", rc_name);
1705 break;
1707 if ((s = ReadFile(args[1], &n)))
1709 struct plop *pp = plop_tab + (int)(unsigned char)ch;
1711 if (pp->buf)
1712 free(pp->buf);
1713 pp->buf = s;
1714 pp->len = n;
1715 #ifdef ENCODINGS
1716 pp->enc = i;
1717 #endif
1720 else
1722 * with one argument we copy the copybuffer into a specified register
1723 * This could be done with RC_PASTE too, but is here to be consistent
1724 * with the zero argument call.
1726 copy_reg_fn(&ch, 0, NULL);
1727 break;
1728 #endif
1729 case RC_REGISTER:
1730 #ifdef ENCODINGS
1731 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
1732 if (args[0] && args[1] && !strcmp(args[0], "-e"))
1734 i = FindEncoding(args[1]);
1735 if (i == -1)
1737 OutputMsg(0, "%s: register: unknown encoding", rc_name);
1738 break;
1740 args += 2;
1741 argc -= 2;
1743 #endif
1744 if (argc != 2)
1746 OutputMsg(0, "%s: register: illegal number of arguments.", rc_name);
1747 break;
1749 if (*argl != 1)
1751 OutputMsg(0, "%s: register: character, ^x, or (octal) \\032 expected.", rc_name);
1752 break;
1754 ch = args[0][0];
1755 #ifdef COPY_PASTE
1756 if (ch == '.')
1758 if (user->u_plop.buf != NULL)
1759 UserFreeCopyBuffer(user);
1760 if (args[1] && args[1][0])
1762 user->u_plop.buf = SaveStrn(args[1], argl[1]);
1763 user->u_plop.len = argl[1];
1764 #ifdef ENCODINGS
1765 user->u_plop.enc = i;
1766 #endif
1769 else
1770 #endif
1772 struct plop *plp = plop_tab + (int)(unsigned char)ch;
1774 if (plp->buf)
1775 free(plp->buf);
1776 plp->buf = SaveStrn(args[1], argl[1]);
1777 plp->len = argl[1];
1778 #ifdef ENCODINGS
1779 plp->enc = i;
1780 #endif
1782 break;
1783 case RC_PROCESS:
1784 if ((s = *args) == NULL)
1786 Input("Process register:", 1, INP_RAW, process_fn, NULL, 0);
1787 break;
1789 if (*argl != 1)
1791 OutputMsg(0, "%s: process: character, ^x, or (octal) \\032 expected.", rc_name);
1792 break;
1794 ch = args[0][0];
1795 process_fn(&ch, 0, NULL);
1796 break;
1797 case RC_STUFF:
1798 s = *args;
1799 if (!args[0])
1801 Input("Stuff:", 100, INP_COOKED, StuffFin, NULL, 0);
1802 break;
1804 n = *argl;
1805 if (args[1])
1807 if (strcmp(s, "-k"))
1809 OutputMsg(0, "%s: stuff: invalid option %s", rc_name, s);
1810 break;
1812 s = args[1];
1813 for (i = T_CAPS; i < T_OCAPS; i++)
1814 if (strcmp(term[i].tcname, s) == 0)
1815 break;
1816 if (i == T_OCAPS)
1818 OutputMsg(0, "%s: stuff: unknown key '%s'", rc_name, s);
1819 break;
1821 #ifdef MAPKEYS
1822 if (StuffKey(i - T_CAPS) == 0)
1823 break;
1824 #endif
1825 s = display ? D_tcs[i].str : 0;
1826 if (s == 0)
1827 break;
1828 n = strlen(s);
1830 while(n)
1831 LayProcess(&s, &n);
1832 break;
1833 case RC_REDISPLAY:
1834 Activate(-1);
1835 break;
1836 case RC_WINDOWS:
1837 ShowWindows(-1);
1838 break;
1839 case RC_VERSION:
1840 OutputMsg(0, "screen %s", version);
1841 break;
1842 case RC_TIME:
1843 if (*args)
1845 timestring = SaveStr(*args);
1846 break;
1848 OutputMsg(0, "%s", MakeWinMsg(timestring, fore, '%'));
1849 break;
1850 case RC_INFO:
1851 ShowInfo();
1852 break;
1853 case RC_DINFO:
1854 ShowDInfo();
1855 break;
1856 case RC_COMMAND:
1858 struct action *ktabp = ktab;
1859 if (argc == 2 && !strcmp(*args, "-c"))
1861 if ((ktabp = FindKtab(args[1], 0)) == 0)
1863 OutputMsg(0, "Unknown command class '%s'", args[1]);
1864 break;
1867 if (D_ESCseen != ktab || ktabp != ktab)
1869 D_ESCseen = ktabp;
1870 break;
1872 D_ESCseen = 0;
1874 /* FALLTHROUGH */
1875 case RC_OTHER:
1876 if (MoreWindows())
1877 SwitchWindow(display && D_other ? D_other->w_number : NextWindow());
1878 break;
1879 case RC_META:
1880 if (user->u_Esc == -1)
1881 break;
1882 ch = user->u_Esc;
1883 s = &ch;
1884 n = 1;
1885 LayProcess(&s, &n);
1886 break;
1887 case RC_XON:
1888 ch = Ctrl('q');
1889 s = &ch;
1890 n = 1;
1891 LayProcess(&s, &n);
1892 break;
1893 case RC_XOFF:
1894 ch = Ctrl('s');
1895 s = &ch;
1896 n = 1;
1897 LayProcess(&s, &n);
1898 break;
1899 case RC_DEFBREAKTYPE:
1900 case RC_BREAKTYPE:
1902 static char *types[] = { "TIOCSBRK", "TCSBRK", "tcsendbreak", NULL };
1903 extern int breaktype;
1905 if (*args)
1907 if (ParseNum(act, &n))
1908 for (n = 0; n < (int)(sizeof(types)/sizeof(*types)); n++)
1910 for (i = 0; i < 4; i++)
1912 ch = args[0][i];
1913 if (ch >= 'a' && ch <= 'z')
1914 ch -= 'a' - 'A';
1915 if (ch != types[n][i] && (ch + ('a' - 'A')) != types[n][i])
1916 break;
1918 if (i == 4)
1919 break;
1921 if (n < 0 || n >= (int)(sizeof(types)/sizeof(*types)))
1922 OutputMsg(0, "%s invalid, chose one of %s, %s or %s", *args, types[0], types[1], types[2]);
1923 else
1925 breaktype = n;
1926 OutputMsg(0, "breaktype set to (%d) %s", n, types[n]);
1929 else
1930 OutputMsg(0, "breaktype is (%d) %s", breaktype, types[breaktype]);
1932 break;
1933 case RC_POW_BREAK:
1934 case RC_BREAK:
1935 n = 0;
1936 if (*args && ParseNum(act, &n))
1937 break;
1938 SendBreak(fore, n, nr == RC_POW_BREAK);
1939 break;
1940 #ifdef LOCK
1941 case RC_LOCKSCREEN:
1942 Detach(D_LOCK);
1943 break;
1944 #endif
1945 case RC_WIDTH:
1946 case RC_HEIGHT:
1948 int w, h;
1949 int what = 0;
1951 i = 1;
1952 if (*args && !strcmp(*args, "-w"))
1953 what = 1;
1954 else if (*args && !strcmp(*args, "-d"))
1955 what = 2;
1956 if (what)
1957 args++;
1958 if (what == 0 && flayer && !display)
1959 what = 1;
1960 if (what == 1)
1962 if (!flayer)
1964 OutputMsg(0, "%s: %s: window required", rc_name, comms[nr].name);
1965 break;
1967 w = flayer->l_width;
1968 h = flayer->l_height;
1970 else
1972 if (!display)
1974 OutputMsg(0, "%s: %s: display required", rc_name, comms[nr].name);
1975 break;
1977 w = D_width;
1978 h = D_height;
1980 if (*args && args[0][0] == '-')
1982 OutputMsg(0, "%s: %s: unknown option %s", rc_name, comms[nr].name, *args);
1983 break;
1985 if (nr == RC_HEIGHT)
1987 if (!*args)
1989 #define H0height 42
1990 #define H1height 24
1991 if (h == H0height)
1992 h = H1height;
1993 else if (h == H1height)
1994 h = H0height;
1995 else if (h > (H0height + H1height) / 2)
1996 h = H0height;
1997 else
1998 h = H1height;
2000 else
2002 h = atoi(*args);
2003 if (args[1])
2004 w = atoi(args[1]);
2007 else
2009 if (!*args)
2011 if (w == Z0width)
2012 w = Z1width;
2013 else if (w == Z1width)
2014 w = Z0width;
2015 else if (w > (Z0width + Z1width) / 2)
2016 w = Z0width;
2017 else
2018 w = Z1width;
2020 else
2022 w = atoi(*args);
2023 if (args[1])
2024 h = atoi(args[1]);
2027 if (*args && args[1] && args[2])
2029 OutputMsg(0, "%s: %s: too many arguments", rc_name, comms[nr].name);
2030 break;
2032 if (w <= 0)
2034 OutputMsg(0, "Illegal width");
2035 break;
2037 if (h <= 0)
2039 OutputMsg(0, "Illegal height");
2040 break;
2042 if (what == 1)
2044 if (flayer->l_width == w && flayer->l_height == h)
2045 break;
2046 ResizeLayer(flayer, w, h, (struct display *)0);
2047 break;
2049 if (D_width == w && D_height == h)
2050 break;
2051 if (what == 2)
2053 ChangeScreenSize(w, h, 1);
2055 else
2057 if (ResizeDisplay(w, h) == 0)
2059 Activate(D_fore ? D_fore->w_norefresh : 0);
2060 /* autofit */
2061 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0);
2062 break;
2064 if (h == D_height)
2065 OutputMsg(0, "Your termcap does not specify how to change the terminal's width to %d.", w);
2066 else if (w == D_width)
2067 OutputMsg(0, "Your termcap does not specify how to change the terminal's height to %d.", h);
2068 else
2069 OutputMsg(0, "Your termcap does not specify how to change the terminal's resolution to %dx%d.", w, h);
2072 break;
2073 case RC_TITLE:
2074 if (queryflag >= 0)
2076 if (fore)
2077 OutputMsg(0, "%s", fore->w_title);
2078 else
2079 queryflag = -1;
2080 break;
2082 if (*args == 0)
2083 InputAKA();
2084 else
2085 ChangeAKA(fore, *args, strlen(*args));
2086 break;
2087 case RC_COLON:
2088 Input(":", 100, INP_EVERY, Colonfin, NULL, 0);
2089 if (*args && **args)
2091 s = *args;
2092 n = strlen(s);
2093 LayProcess(&s, &n);
2095 break;
2096 case RC_LASTMSG:
2097 if (D_status_lastmsg)
2098 OutputMsg(0, "%s", D_status_lastmsg);
2099 break;
2100 case RC_SCREEN:
2101 DoScreen("key", args);
2102 break;
2103 case RC_WRAP:
2104 if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok)
2105 OutputMsg(0, "%cwrap", fore->w_wrap ? '+' : '-');
2106 break;
2107 case RC_FLOW:
2108 if (*args)
2110 if (args[0][0] == 'a')
2112 fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
2114 else
2116 if (ParseOnOff(act, &n))
2117 break;
2118 fore->w_flow = (fore->w_flow & FLOW_AUTO) | n;
2121 else
2123 if (fore->w_flow & FLOW_AUTOFLAG)
2124 fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW;
2125 else if (fore->w_flow & FLOW_NOW)
2126 fore->w_flow &= ~FLOW_NOW;
2127 else
2128 fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
2130 SetFlow(fore->w_flow & FLOW_NOW);
2131 if (msgok)
2132 OutputMsg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-',
2133 (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : "");
2134 break;
2135 #ifdef MULTIUSER
2136 case RC_DEFWRITELOCK:
2137 if (args[0][0] == 'a')
2138 nwin_default.wlock = WLOCK_AUTO;
2139 else
2141 if (ParseOnOff(act, &n))
2142 break;
2143 nwin_default.wlock = n ? WLOCK_ON : WLOCK_OFF;
2145 break;
2146 case RC_WRITELOCK:
2147 if (*args)
2149 if (args[0][0] == 'a')
2151 fore->w_wlock = WLOCK_AUTO;
2153 else
2155 if (ParseOnOff(act, &n))
2156 break;
2157 fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF;
2160 * user may have permission to change the writelock setting,
2161 * but he may never aquire the lock himself without write permission
2163 if (!AclCheckPermWin(D_user, ACL_WRITE, fore))
2164 fore->w_wlockuser = D_user;
2166 OutputMsg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" :
2167 ((fore->w_wlock == WLOCK_OFF) ? "off" : "on"));
2168 break;
2169 #endif
2170 case RC_CLEAR:
2171 ResetAnsiState(fore);
2172 WriteString(fore, "\033[H\033[J", 6);
2173 break;
2174 case RC_RESET:
2175 ResetAnsiState(fore);
2176 #ifdef ZMODEM
2177 if (fore->w_zdisplay)
2178 zmodem_abort(fore, fore->w_zdisplay);
2179 #endif
2180 WriteString(fore, "\033c", 2);
2181 break;
2182 case RC_MONITOR:
2183 n = fore->w_monitor != MON_OFF;
2184 #ifdef MULTIUSER
2185 if (display)
2186 n = n && (ACLBYTE(fore->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id));
2187 #endif
2188 if (ParseSwitch(act, &n))
2189 break;
2190 if (n)
2192 #ifdef MULTIUSER
2193 if (display) /* we tell only this user */
2194 ACLBYTE(fore->w_mon_notify, D_user->u_id) |= ACLBIT(D_user->u_id);
2195 else
2196 for (i = 0; i < maxusercount; i++)
2197 ACLBYTE(fore->w_mon_notify, i) |= ACLBIT(i);
2198 #endif
2199 if (fore->w_monitor == MON_OFF)
2200 fore->w_monitor = MON_ON;
2201 OutputMsg(0, "Window %d (%s) is now being monitored for all activity.", fore->w_number, fore->w_title);
2203 else
2205 #ifdef MULTIUSER
2206 if (display) /* we remove only this user */
2207 ACLBYTE(fore->w_mon_notify, D_user->u_id)
2208 &= ~ACLBIT(D_user->u_id);
2209 else
2210 for (i = 0; i < maxusercount; i++)
2211 ACLBYTE(fore->w_mon_notify, i) &= ~ACLBIT(i);
2212 for (i = maxusercount - 1; i >= 0; i--)
2213 if (ACLBYTE(fore->w_mon_notify, i))
2214 break;
2215 if (i < 0)
2216 #endif
2217 fore->w_monitor = MON_OFF;
2218 OutputMsg(0, "Window %d (%s) is no longer being monitored for activity.", fore->w_number, fore->w_title);
2220 break;
2221 #ifdef MULTI
2222 case RC_DISPLAYS:
2223 display_displays();
2224 break;
2225 #endif
2226 case RC_WINDOWLIST:
2227 if (!*args)
2228 display_windows(0, WLIST_NUM, (struct win *)0);
2229 else if (!strcmp(*args, "string"))
2231 if (args[1])
2233 if (wliststr)
2234 free(wliststr);
2235 wliststr = SaveStr(args[1]);
2237 if (msgok)
2238 OutputMsg(0, "windowlist string is '%s'", wliststr);
2240 else if (!strcmp(*args, "title"))
2242 if (args[1])
2244 if (wlisttit)
2245 free(wlisttit);
2246 wlisttit = SaveStr(args[1]);
2248 if (msgok)
2249 OutputMsg(0, "windowlist title is '%s'", wlisttit);
2251 else
2253 int flag = 0;
2254 int blank = 0;
2255 for (i = 0; i < argc; i++)
2256 if (!args[i])
2257 continue;
2258 else if (!strcmp(args[i], "-m"))
2259 flag |= WLIST_MRU;
2260 else if (!strcmp(args[i], "-b"))
2261 blank = 1;
2262 else if (!strcmp(args[i], "-g"))
2263 flag |= WLIST_NESTED;
2264 else
2266 OutputMsg(0, "usage: windowlist [-b] [-g] [-m] [string [string] | title [title]]");
2267 break;
2269 if (i == argc)
2270 display_windows(blank, flag, (struct win *)0);
2272 break;
2273 case RC_HELP:
2274 if (argc == 2 && !strcmp(*args, "-c"))
2276 struct action *ktabp;
2277 if ((ktabp = FindKtab(args[1], 0)) == 0)
2279 OutputMsg(0, "Unknown command class '%s'", args[1]);
2280 break;
2282 display_help(args[1], ktabp);
2284 else
2285 display_help((char *)0, ktab);
2286 break;
2287 case RC_LICENSE:
2288 display_copyright();
2289 break;
2290 #ifdef COPY_PASTE
2291 case RC_COPY:
2292 if (flayer->l_layfn != &WinLf)
2294 OutputMsg(0, "Must be on a window layer");
2295 break;
2297 MarkRoutine();
2298 WindowChanged(fore, 'P');
2299 break;
2300 case RC_HISTORY:
2302 static char *pasteargs[] = {".", 0};
2303 static int pasteargl[] = {1};
2305 if (flayer->l_layfn != &WinLf)
2307 OutputMsg(0, "Must be on a window layer");
2308 break;
2310 if (GetHistory() == 0)
2311 break;
2312 if (user->u_plop.buf == NULL)
2313 break;
2314 args = pasteargs;
2315 argl = pasteargl;
2317 /*FALLTHROUGH*/
2318 case RC_PASTE:
2320 char *ss, *dbuf, dch;
2321 int l = 0;
2322 # ifdef ENCODINGS
2323 int enc = -1;
2324 # endif
2327 * without args we prompt for one(!) register to be pasted in the window
2329 if ((s = *args) == NULL)
2331 Input("Paste from register:", 1, INP_RAW, ins_reg_fn, NULL, 0);
2332 break;
2334 if (args[1] == 0 && !fore) /* no window? */
2335 break;
2337 * with two arguments we paste into a destination register
2338 * (no window needed here).
2340 if (args[1] && argl[1] != 1)
2342 OutputMsg(0, "%s: paste destination: character, ^x, or (octal) \\032 expected.",
2343 rc_name);
2344 break;
2346 # ifdef ENCODINGS
2347 else if (fore)
2348 enc = fore->w_encoding;
2349 # endif
2352 * measure length of needed buffer
2354 for (ss = s = *args; (ch = *ss); ss++)
2356 if (ch == '.')
2358 # ifdef ENCODINGS
2359 if (enc == -1)
2360 enc = user->u_plop.enc;
2361 if (enc != user->u_plop.enc)
2362 l += RecodeBuf((unsigned char *)user->u_plop.buf, user->u_plop.len, user->u_plop.enc, enc, (unsigned char *)0);
2363 else
2364 # endif
2365 l += user->u_plop.len;
2367 else
2369 # ifdef ENCODINGS
2370 if (enc == -1)
2371 enc = plop_tab[(int)(unsigned char)ch].enc;
2372 if (enc != plop_tab[(int)(unsigned char)ch].enc)
2373 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);
2374 else
2375 # endif
2376 l += plop_tab[(int)(unsigned char)ch].len;
2379 if (l == 0)
2381 OutputMsg(0, "empty buffer");
2382 break;
2385 * shortcut:
2386 * if there is only one source and the destination is a window, then
2387 * pass a pointer rather than duplicating the buffer.
2389 if (s[1] == 0 && args[1] == 0)
2390 # ifdef ENCODINGS
2391 if (enc == (*s == '.' ? user->u_plop.enc : plop_tab[(int)(unsigned char)*s].enc))
2392 # endif
2394 MakePaster(&fore->w_paster, *s == '.' ? user->u_plop.buf : plop_tab[(int)(unsigned char)*s].buf, l, 0);
2395 break;
2398 * if no shortcut, we construct a buffer
2400 if ((dbuf = (char *)malloc(l)) == 0)
2402 OutputMsg(0, "%s", strnomem);
2403 break;
2405 l = 0;
2407 * concatenate all sources into our own buffer, copy buffer is
2408 * special and is skipped if no display exists.
2410 for (ss = s; (ch = *ss); ss++)
2412 struct plop *pp = (ch == '.' ? &user->u_plop : &plop_tab[(int)(unsigned char)ch]);
2413 #ifdef ENCODINGS
2414 if (pp->enc != enc)
2416 l += RecodeBuf((unsigned char *)pp->buf, pp->len, pp->enc, enc, (unsigned char *)dbuf + l);
2417 continue;
2419 #endif
2420 bcopy(pp->buf, dbuf + l, pp->len);
2421 l += pp->len;
2424 * when called with one argument we paste our buffer into the window
2426 if (args[1] == 0)
2428 MakePaster(&fore->w_paster, dbuf, l, 1);
2430 else
2433 * we have two arguments, the second is already in dch.
2434 * use this as destination rather than the window.
2436 dch = args[1][0];
2437 if (dch == '.')
2439 if (user->u_plop.buf != NULL)
2440 UserFreeCopyBuffer(user);
2441 user->u_plop.buf = dbuf;
2442 user->u_plop.len = l;
2443 #ifdef ENCODINGS
2444 user->u_plop.enc = enc;
2445 #endif
2447 else
2449 struct plop *pp = plop_tab + (int)(unsigned char)dch;
2450 if (pp->buf)
2451 free(pp->buf);
2452 pp->buf = dbuf;
2453 pp->len = l;
2454 #ifdef ENCODINGS
2455 pp->enc = enc;
2456 #endif
2459 break;
2461 case RC_WRITEBUF:
2462 if (!user->u_plop.buf)
2464 OutputMsg(0, "empty buffer");
2465 break;
2467 #ifdef ENCODINGS
2469 struct plop oldplop;
2471 oldplop = user->u_plop;
2472 if (args[0] && args[1] && !strcmp(args[0], "-e"))
2474 int enc, l;
2475 char *newbuf;
2477 enc = FindEncoding(args[1]);
2478 if (enc == -1)
2480 OutputMsg(0, "%s: writebuf: unknown encoding", rc_name);
2481 break;
2483 if (enc != oldplop.enc)
2485 l = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)0);
2486 newbuf = malloc(l + 1);
2487 if (!newbuf)
2489 OutputMsg(0, "%s", strnomem);
2490 break;
2492 user->u_plop.len = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)newbuf);
2493 user->u_plop.buf = newbuf;
2494 user->u_plop.enc = enc;
2496 args += 2;
2498 #endif
2499 if (args[0] && args[1])
2500 OutputMsg(0, "%s: writebuf: too many arguments", rc_name);
2501 else
2502 WriteFile(user, args[0], DUMP_EXCHANGE);
2503 #ifdef ENCODINGS
2504 if (user->u_plop.buf != oldplop.buf)
2505 free(user->u_plop.buf);
2506 user->u_plop = oldplop;
2508 #endif
2509 break;
2510 case RC_READBUF:
2511 #ifdef ENCODINGS
2512 i = fore ? fore->w_encoding : display ? display->d_encoding : 0;
2513 if (args[0] && args[1] && !strcmp(args[0], "-e"))
2515 i = FindEncoding(args[1]);
2516 if (i == -1)
2518 OutputMsg(0, "%s: readbuf: unknown encoding", rc_name);
2519 break;
2521 args += 2;
2523 #endif
2524 if (args[0] && args[1])
2526 OutputMsg(0, "%s: readbuf: too many arguments", rc_name);
2527 break;
2529 if ((s = ReadFile(args[0] ? args[0] : BufferFile, &n)))
2531 if (user->u_plop.buf)
2532 UserFreeCopyBuffer(user);
2533 user->u_plop.len = n;
2534 user->u_plop.buf = s;
2535 #ifdef ENCODINGS
2536 user->u_plop.enc = i;
2537 #endif
2539 break;
2540 case RC_REMOVEBUF:
2541 KillBuffers();
2542 break;
2543 case RC_IGNORECASE:
2544 (void)ParseSwitch(act, &search_ic);
2545 if (msgok)
2546 OutputMsg(0, "Will %signore case in searches", search_ic ? "" : "not ");
2547 break;
2548 #endif /* COPY_PASTE */
2549 case RC_ESCAPE:
2550 if (*argl == 0)
2551 SetEscape(user, -1, -1);
2552 else if (*argl == 2)
2553 SetEscape(user, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]);
2554 else
2556 OutputMsg(0, "%s: two characters required after escape.", rc_name);
2557 break;
2559 /* Change defescape if master user. This is because we only
2560 * have one ktab.
2562 if (display && user != users)
2563 break;
2564 /* FALLTHROUGH */
2565 case RC_DEFESCAPE:
2566 if (*argl == 0)
2567 SetEscape(NULL, -1, -1);
2568 else if (*argl == 2)
2569 SetEscape(NULL, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]);
2570 else
2572 OutputMsg(0, "%s: two characters required after defescape.", rc_name);
2573 break;
2575 #ifdef MAPKEYS
2576 CheckEscape();
2577 #endif
2578 break;
2579 case RC_CHDIR:
2580 s = *args ? *args : home;
2581 if (chdir(s) == -1)
2582 OutputMsg(errno, "%s", s);
2583 break;
2584 case RC_SHELL:
2585 case RC_DEFSHELL:
2586 if (ParseSaveStr(act, &ShellProg) == 0)
2587 ShellArgs[0] = ShellProg;
2588 break;
2589 case RC_HARDCOPYDIR:
2590 if (*args)
2591 (void)ParseSaveStr(act, &hardcopydir);
2592 if (msgok)
2593 OutputMsg(0, "hardcopydir is %s\n", hardcopydir && *hardcopydir ? hardcopydir : "<cwd>");
2594 break;
2595 case RC_LOGFILE:
2596 if (*args)
2598 if (args[1] && !(strcmp(*args, "flush")))
2600 log_flush = atoi(args[1]);
2601 if (msgok)
2602 OutputMsg(0, "log flush timeout set to %ds\n", log_flush);
2603 break;
2605 if (ParseSaveStr(act, &screenlogfile) || !msgok)
2606 break;
2608 OutputMsg(0, "logfile is '%s'", screenlogfile);
2609 break;
2610 case RC_LOGTSTAMP:
2611 if (!*args || !strcmp(*args, "on") || !strcmp(*args, "off"))
2613 if (ParseSwitch(act, &logtstamp_on) == 0 && msgok)
2614 OutputMsg(0, "timestamps turned %s", logtstamp_on ? "on" : "off");
2616 else if (!strcmp(*args, "string"))
2618 if (args[1])
2620 if (logtstamp_string)
2621 free(logtstamp_string);
2622 logtstamp_string = SaveStr(args[1]);
2624 if (msgok)
2625 OutputMsg(0, "logfile timestamp is '%s'", logtstamp_string);
2627 else if (!strcmp(*args, "after"))
2629 if (args[1])
2631 logtstamp_after = atoi(args[1]);
2632 if (!msgok)
2633 break;
2635 OutputMsg(0, "timestamp printed after %ds\n", logtstamp_after);
2637 else
2638 OutputMsg(0, "usage: logtstamp [after [n]|string [str]|on|off]");
2639 break;
2640 case RC_SHELLTITLE:
2641 (void)ParseSaveStr(act, &nwin_default.aka);
2642 break;
2643 case RC_TERMCAP:
2644 case RC_TERMCAPINFO:
2645 case RC_TERMINFO:
2646 if (!rc_name || !*rc_name)
2647 OutputMsg(0, "Sorry, too late now. Place that in your .screenrc file.");
2648 break;
2649 case RC_SLEEP:
2650 break; /* Already handled */
2651 case RC_TERM:
2652 s = NULL;
2653 if (ParseSaveStr(act, &s))
2654 break;
2655 if (strlen(s) >= 20)
2657 OutputMsg(0, "%s: term: argument too long ( < 20)", rc_name);
2658 free(s);
2659 break;
2661 strcpy(screenterm, s);
2662 free(s);
2663 debug1("screenterm set to %s\n", screenterm);
2664 MakeTermcap((display == 0));
2665 debug("new termcap made\n");
2666 break;
2667 case RC_ECHO:
2668 if (!msgok && (!rc_name || strcmp(rc_name, "-X")))
2669 break;
2671 * user typed ^A:echo... well, echo isn't FinishRc's job,
2672 * but as he wanted to test us, we show good will
2674 if (argc > 1 && !strcmp(*args, "-n"))
2676 args++;
2677 argc--;
2679 s = *args;
2680 if (argc > 1 && !strcmp(*args, "-p"))
2682 args++;
2683 argc--;
2684 s = *args;
2685 if (s)
2686 s = MakeWinMsg(s, fore, '%');
2688 if (s)
2689 OutputMsg(0, "%s", s);
2690 else
2692 OutputMsg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name);
2693 queryflag = -1;
2695 break;
2696 case RC_BELL:
2697 case RC_BELL_MSG:
2698 if (*args == 0)
2700 char buf[256];
2701 AddXChars(buf, sizeof(buf), BellString);
2702 OutputMsg(0, "bell_msg is '%s'", buf);
2703 break;
2705 (void)ParseSaveStr(act, &BellString);
2706 break;
2707 #ifdef COPY_PASTE
2708 case RC_BUFFERFILE:
2709 if (*args == 0)
2710 BufferFile = SaveStr(DEFAULT_BUFFERFILE);
2711 else if (ParseSaveStr(act, &BufferFile))
2712 break;
2713 if (msgok)
2714 OutputMsg(0, "Bufferfile is now '%s'", BufferFile);
2715 break;
2716 #endif
2717 case RC_ACTIVITY:
2718 (void)ParseSaveStr(act, &ActivityString);
2719 break;
2720 #if defined(DETACH) && defined(POW_DETACH)
2721 case RC_POW_DETACH_MSG:
2722 if (*args == 0)
2724 char buf[256];
2725 AddXChars(buf, sizeof(buf), PowDetachString);
2726 OutputMsg(0, "pow_detach_msg is '%s'", buf);
2727 break;
2729 (void)ParseSaveStr(act, &PowDetachString);
2730 break;
2731 #endif
2732 #if defined(UTMPOK) && defined(LOGOUTOK)
2733 case RC_LOGIN:
2734 n = fore->w_slot != (slot_t)-1;
2735 if (*args && !strcmp(*args, "always"))
2737 fore->w_lflag = 3;
2738 if (!displays && n)
2739 SlotToggle(n);
2740 break;
2742 if (*args && !strcmp(*args, "attached"))
2744 fore->w_lflag = 1;
2745 if (!displays && n)
2746 SlotToggle(0);
2747 break;
2749 if (ParseSwitch(act, &n) == 0)
2750 SlotToggle(n);
2751 break;
2752 case RC_DEFLOGIN:
2753 if (!strcmp(*args, "always"))
2754 nwin_default.lflag |= 2;
2755 else if (!strcmp(*args, "attached"))
2756 nwin_default.lflag &= ~2;
2757 else
2758 (void)ParseOnOff(act, &nwin_default.lflag);
2759 break;
2760 #endif
2761 case RC_DEFFLOW:
2762 if (args[0] && args[1] && args[1][0] == 'i')
2764 iflag = 1;
2765 for (display = displays; display; display = display->d_next)
2767 if (!D_flow)
2768 continue;
2769 #if defined(TERMIO) || defined(POSIX)
2770 D_NewMode.tio.c_cc[VINTR] = D_OldMode.tio.c_cc[VINTR];
2771 D_NewMode.tio.c_lflag |= ISIG;
2772 #else /* TERMIO || POSIX */
2773 D_NewMode.m_tchars.t_intrc = D_OldMode.m_tchars.t_intrc;
2774 #endif /* TERMIO || POSIX */
2775 SetTTY(D_userfd, &D_NewMode);
2778 if (args[0] && args[0][0] == 'a')
2779 nwin_default.flowflag = FLOW_AUTOFLAG;
2780 else
2781 (void)ParseOnOff(act, &nwin_default.flowflag);
2782 break;
2783 case RC_DEFWRAP:
2784 (void)ParseOnOff(act, &nwin_default.wrap);
2785 break;
2786 case RC_DEFC1:
2787 (void)ParseOnOff(act, &nwin_default.c1);
2788 break;
2789 #ifdef COLOR
2790 case RC_DEFBCE:
2791 (void)ParseOnOff(act, &nwin_default.bce);
2792 break;
2793 #endif
2794 case RC_DEFGR:
2795 (void)ParseOnOff(act, &nwin_default.gr);
2796 break;
2797 case RC_DEFMONITOR:
2798 if (ParseOnOff(act, &n) == 0)
2799 nwin_default.monitor = (n == 0) ? MON_OFF : MON_ON;
2800 break;
2801 case RC_DEFMOUSETRACK:
2802 if (ParseOnOff(act, &n) == 0)
2803 defmousetrack = (n == 0) ? 0 : 1000;
2804 break;
2805 case RC_MOUSETRACK:
2806 if (!args[0])
2808 OutputMsg(0, "Mouse tracking for this display is turned %s", D_mousetrack ? "on" : "off");
2810 else if (ParseOnOff(act, &n) == 0)
2812 D_mousetrack = n == 0 ? 0 : 1000;
2813 if (D_fore)
2814 MouseMode(D_fore->w_mouse);
2816 break;
2817 case RC_DEFSILENCE:
2818 if (ParseOnOff(act, &n) == 0)
2819 nwin_default.silence = (n == 0) ? SILENCE_OFF : SILENCE_ON;
2820 break;
2821 case RC_VERBOSE:
2822 if (!*args)
2823 OutputMsg(0, "W%s echo command when creating windows.",
2824 VerboseCreate ? "ill" : "on't");
2825 else if (ParseOnOff(act, &n) == 0)
2826 VerboseCreate = n;
2827 break;
2828 case RC_HARDSTATUS:
2829 if (display)
2831 OutputMsg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
2832 RemoveStatus();
2834 if (args[0] && strcmp(args[0], "on") && strcmp(args[0], "off"))
2836 struct display *olddisplay = display;
2837 int old_use, new_use = -1;
2839 s = args[0];
2840 if (!strncmp(s, "always", 6))
2841 s += 6;
2842 if (!strcmp(s, "lastline"))
2843 new_use = HSTATUS_LASTLINE;
2844 else if (!strcmp(s, "ignore"))
2845 new_use = HSTATUS_IGNORE;
2846 else if (!strcmp(s, "message"))
2847 new_use = HSTATUS_MESSAGE;
2848 else if (!strcmp(args[0], "string"))
2850 if (!args[1])
2852 char buf[256];
2853 AddXChars(buf, sizeof(buf), hstatusstring);
2854 OutputMsg(0, "hardstatus string is '%s'", buf);
2855 break;
2858 else
2860 OutputMsg(0, "%s: usage: hardstatus [always]lastline|ignore|message|string [string]", rc_name);
2861 break;
2863 if (new_use != -1)
2865 hardstatusemu = new_use | (s == args[0] ? 0 : HSTATUS_ALWAYS);
2866 for (display = displays; display; display = display->d_next)
2868 RemoveStatus();
2869 new_use = hardstatusemu & ~HSTATUS_ALWAYS;
2870 if (D_HS && s == args[0])
2871 new_use = HSTATUS_HS;
2872 ShowHStatus((char *)0);
2873 old_use = D_has_hstatus;
2874 D_has_hstatus = new_use;
2875 if ((new_use == HSTATUS_LASTLINE && old_use != HSTATUS_LASTLINE) || (new_use != HSTATUS_LASTLINE && old_use == HSTATUS_LASTLINE))
2876 ChangeScreenSize(D_width, D_height, 1);
2877 RefreshHStatus();
2880 if (args[1])
2882 if (hstatusstring)
2883 free(hstatusstring);
2884 hstatusstring = SaveStr(args[1]);
2885 for (display = displays; display; display = display->d_next)
2886 RefreshHStatus();
2888 display = olddisplay;
2889 break;
2891 (void)ParseSwitch(act, &use_hardstatus);
2892 if (msgok)
2893 OutputMsg(0, "messages displayed on %s", use_hardstatus ? "hardstatus line" : "window");
2894 break;
2895 case RC_CAPTION:
2896 if (strcmp(args[0], "always") == 0 || strcmp(args[0], "splitonly") == 0)
2898 struct display *olddisplay = display;
2900 captionalways = args[0][0] == 'a';
2901 for (display = displays; display; display = display->d_next)
2902 ChangeScreenSize(D_width, D_height, 1);
2903 display = olddisplay;
2905 else if (strcmp(args[0], "string") == 0)
2907 if (!args[1])
2909 char buf[256];
2910 AddXChars(buf, sizeof(buf), captionstring);
2911 OutputMsg(0, "caption string is '%s'", buf);
2912 break;
2915 else
2917 OutputMsg(0, "%s: usage: caption always|splitonly|string <string>", rc_name);
2918 break;
2920 if (!args[1])
2921 break;
2922 if (captionstring)
2923 free(captionstring);
2924 captionstring = SaveStr(args[1]);
2925 RedisplayDisplays(0);
2926 break;
2927 case RC_CONSOLE:
2928 n = (console_window != 0);
2929 if (ParseSwitch(act, &n))
2930 break;
2931 if (TtyGrabConsole(fore->w_ptyfd, n, rc_name))
2932 break;
2933 if (n == 0)
2934 OutputMsg(0, "%s: releasing console %s", rc_name, HostName);
2935 else if (console_window)
2936 OutputMsg(0, "%s: stealing console %s from window %d (%s)", rc_name,
2937 HostName, console_window->w_number, console_window->w_title);
2938 else
2939 OutputMsg(0, "%s: grabbing console %s", rc_name, HostName);
2940 console_window = n ? fore : 0;
2941 break;
2942 case RC_ALLPARTIAL:
2943 if (ParseOnOff(act, &all_norefresh))
2944 break;
2945 if (!all_norefresh && fore)
2946 Activate(-1);
2947 if (msgok)
2948 OutputMsg(0, all_norefresh ? "No refresh on window change!\n" :
2949 "Window specific refresh\n");
2950 break;
2951 case RC_PARTIAL:
2952 (void)ParseSwitch(act, &n);
2953 fore->w_norefresh = n;
2954 break;
2955 case RC_VBELL:
2956 if (ParseSwitch(act, &visual_bell) || !msgok)
2957 break;
2958 if (visual_bell == 0)
2959 OutputMsg(0, "switched to audible bell.");
2960 else
2961 OutputMsg(0, "switched to visual bell.");
2962 break;
2963 case RC_VBELLWAIT:
2964 if (ParseNum1000(act, &VBellWait) == 0 && msgok)
2965 OutputMsg(0, "vbellwait set to %.10g seconds", VBellWait/1000.);
2966 break;
2967 case RC_MSGWAIT:
2968 if (ParseNum1000(act, &MsgWait) == 0 && msgok)
2969 OutputMsg(0, "msgwait set to %.10g seconds", MsgWait/1000.);
2970 break;
2971 case RC_MSGMINWAIT:
2972 if (ParseNum1000(act, &MsgMinWait) == 0 && msgok)
2973 OutputMsg(0, "msgminwait set to %.10g seconds", MsgMinWait/1000.);
2974 break;
2975 case RC_SILENCEWAIT:
2976 if (ParseNum(act, &SilenceWait))
2977 break;
2978 if (SilenceWait < 1)
2979 SilenceWait = 1;
2980 for (p = windows; p; p = p->w_next)
2981 p->w_silencewait = SilenceWait;
2982 if (msgok)
2983 OutputMsg(0, "silencewait set to %d seconds", SilenceWait);
2984 break;
2985 case RC_NUMBER:
2986 if (*args == 0)
2987 OutputMsg(0, queryflag >= 0 ? "%d (%s)" : "This is window %d (%s).", fore->w_number, fore->w_title);
2988 else
2990 int old = fore->w_number;
2991 int rel = 0, parse;
2992 if (args[0][0] == '+')
2993 rel = 1;
2994 else if (args[0][0] == '-')
2995 rel = -1;
2996 if (rel)
2997 ++act->args[0];
2998 parse = ParseNum(act, &n);
2999 if (rel)
3000 --act->args[0];
3001 if (parse)
3002 break;
3003 if (rel > 0)
3004 n += old;
3005 else if (rel < 0)
3006 n = old - n;
3007 if (!WindowChangeNumber(fore, n))
3009 /* Window number could not be changed. */
3010 queryflag = -1;
3011 return;
3014 break;
3015 case RC_SILENCE:
3016 n = fore->w_silence != 0;
3017 i = fore->w_silencewait;
3018 if (args[0] && (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9')))
3020 if (ParseNum(act, &i))
3021 break;
3022 n = i > 0;
3024 else if (ParseSwitch(act, &n))
3025 break;
3026 if (n)
3028 #ifdef MULTIUSER
3029 if (display) /* we tell only this user */
3030 ACLBYTE(fore->w_lio_notify, D_user->u_id) |= ACLBIT(D_user->u_id);
3031 else
3032 for (n = 0; n < maxusercount; n++)
3033 ACLBYTE(fore->w_lio_notify, n) |= ACLBIT(n);
3034 #endif
3035 fore->w_silencewait = i;
3036 fore->w_silence = SILENCE_ON;
3037 SetTimeout(&fore->w_silenceev, fore->w_silencewait * 1000);
3038 evenq(&fore->w_silenceev);
3040 if (!msgok)
3041 break;
3042 OutputMsg(0, "The window is now being monitored for %d sec. silence.", fore->w_silencewait);
3044 else
3046 #ifdef MULTIUSER
3047 if (display) /* we remove only this user */
3048 ACLBYTE(fore->w_lio_notify, D_user->u_id)
3049 &= ~ACLBIT(D_user->u_id);
3050 else
3051 for (n = 0; n < maxusercount; n++)
3052 ACLBYTE(fore->w_lio_notify, n) &= ~ACLBIT(n);
3053 for (i = maxusercount - 1; i >= 0; i--)
3054 if (ACLBYTE(fore->w_lio_notify, i))
3055 break;
3056 if (i < 0)
3057 #endif
3059 fore->w_silence = SILENCE_OFF;
3060 evdeq(&fore->w_silenceev);
3062 if (!msgok)
3063 break;
3064 OutputMsg(0, "The window is no longer being monitored for silence.");
3066 break;
3067 #ifdef COPY_PASTE
3068 case RC_DEFSCROLLBACK:
3069 (void)ParseNum(act, &nwin_default.histheight);
3070 break;
3071 case RC_SCROLLBACK:
3072 if (flayer->l_layfn == &MarkLf)
3074 OutputMsg(0, "Cannot resize scrollback buffer in copy/scrollback mode.");
3075 break;
3077 (void)ParseNum(act, &n);
3078 ChangeWindowSize(fore, fore->w_width, fore->w_height, n);
3079 if (msgok)
3080 OutputMsg(0, "scrollback set to %d", fore->w_histheight);
3081 break;
3082 #endif
3083 case RC_SESSIONNAME:
3084 if (*args == 0)
3085 OutputMsg(0, "This session is named '%s'\n", SockName);
3086 else
3088 char buf[MAXPATHLEN];
3090 s = 0;
3091 if (ParseSaveStr(act, &s))
3092 break;
3093 if (!*s || strlen(s) + (SockName - SockPath) > MAXPATHLEN - 13 || index(s, '/'))
3095 OutputMsg(0, "%s: bad session name '%s'\n", rc_name, s);
3096 free(s);
3097 break;
3099 strncpy(buf, SockPath, SockName - SockPath);
3100 sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s);
3101 free(s);
3102 if ((access(buf, F_OK) == 0) || (errno != ENOENT))
3104 OutputMsg(0, "%s: inappropriate path: '%s'.", rc_name, buf);
3105 break;
3107 if (rename(SockPath, buf))
3109 OutputMsg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf);
3110 break;
3112 debug2("rename(%s, %s) done\n", SockPath, buf);
3113 strcpy(SockPath, buf);
3114 MakeNewEnv();
3115 WindowChanged((struct win *)0, 'S');
3117 break;
3118 case RC_SETENV:
3119 if (!args[0] || !args[1])
3121 debug1("RC_SETENV arguments missing: %s\n", args[0] ? args[0] : "");
3122 InputSetenv(args[0]);
3124 else
3126 xsetenv(args[0], args[1]);
3127 MakeNewEnv();
3129 break;
3130 case RC_UNSETENV:
3131 unsetenv(*args);
3132 MakeNewEnv();
3133 break;
3134 #ifdef COPY_PASTE
3135 case RC_DEFSLOWPASTE:
3136 (void)ParseNum(act, &nwin_default.slow);
3137 break;
3138 case RC_SLOWPASTE:
3139 if (*args == 0)
3140 OutputMsg(0, fore->w_slowpaste ?
3141 "Slowpaste in window %d is %d milliseconds." :
3142 "Slowpaste in window %d is unset.",
3143 fore->w_number, fore->w_slowpaste);
3144 else if (ParseNum(act, &fore->w_slowpaste) == 0 && msgok)
3145 OutputMsg(0, fore->w_slowpaste ?
3146 "Slowpaste in window %d set to %d milliseconds." :
3147 "Slowpaste in window %d now unset.",
3148 fore->w_number, fore->w_slowpaste);
3149 break;
3150 case RC_MARKKEYS:
3151 if (CompileKeys(*args, *argl, mark_key_tab))
3153 OutputMsg(0, "%s: markkeys: syntax error.", rc_name);
3154 break;
3156 debug1("markkeys %s\n", *args);
3157 break;
3158 # ifdef FONT
3159 case RC_PASTEFONT:
3160 if (ParseSwitch(act, &pastefont) == 0 && msgok)
3161 OutputMsg(0, "Will %spaste font settings", pastefont ? "" : "not ");
3162 break;
3163 # endif
3164 case RC_CRLF:
3165 (void)ParseSwitch(act, &join_with_cr);
3166 break;
3167 case RC_COMPACTHIST:
3168 if (ParseSwitch(act, &compacthist) == 0 && msgok)
3169 OutputMsg(0, "%scompacting history lines", compacthist ? "" : "not ");
3170 break;
3171 #endif
3172 #ifdef NETHACK
3173 case RC_NETHACK:
3174 (void)ParseOnOff(act, &nethackflag);
3175 break;
3176 #endif
3177 case RC_HARDCOPY_APPEND:
3178 (void)ParseOnOff(act, &hardcopy_append);
3179 break;
3180 case RC_VBELL_MSG:
3181 if (*args == 0)
3183 char buf[256];
3184 AddXChars(buf, sizeof(buf), VisualBellString);
3185 OutputMsg(0, "vbell_msg is '%s'", buf);
3186 break;
3188 (void)ParseSaveStr(act, &VisualBellString);
3189 debug1(" new vbellstr '%s'\n", VisualBellString);
3190 break;
3191 case RC_DEFMODE:
3192 if (ParseBase(act, *args, &n, 8, "octal"))
3193 break;
3194 if (n < 0 || n > 0777)
3196 OutputMsg(0, "%s: mode: Invalid tty mode %o", rc_name, n);
3197 break;
3199 TtyMode = n;
3200 if (msgok)
3201 OutputMsg(0, "Ttymode set to %03o", TtyMode);
3202 break;
3203 case RC_AUTODETACH:
3204 (void)ParseOnOff(act, &auto_detach);
3205 break;
3206 case RC_STARTUP_MESSAGE:
3207 (void)ParseOnOff(act, &default_startup);
3208 break;
3209 #ifdef PASSWORD
3210 case RC_PASSWORD:
3211 if (*args)
3213 n = (*user->u_password) ? 1 : 0;
3214 if (user->u_password != NullStr) free((char *)user->u_password);
3215 user->u_password = SaveStr(*args);
3216 if (!strcmp(user->u_password, "none"))
3218 if (n)
3219 OutputMsg(0, "Password checking disabled");
3220 free(user->u_password);
3221 user->u_password = NullStr;
3224 else
3226 if (!fore)
3228 OutputMsg(0, "%s: password: window required", rc_name);
3229 break;
3231 Input("New screen password:", 100, INP_NOECHO, pass1, display ? (char *)D_user : (char *)users, 0);
3233 break;
3234 #endif /* PASSWORD */
3235 case RC_BIND:
3237 struct action *ktabp = ktab;
3238 int kflag = 0;
3240 for (;;)
3242 if (argc > 2 && !strcmp(*args, "-c"))
3244 ktabp = FindKtab(args[1], 1);
3245 if (ktabp == 0)
3246 break;
3247 args += 2;
3248 argl += 2;
3249 argc -= 2;
3251 else if (argc > 1 && !strcmp(*args, "-k"))
3253 kflag = 1;
3254 args++;
3255 argl++;
3256 argc--;
3258 else
3259 break;
3261 #ifdef MAPKEYS
3262 if (kflag)
3264 for (n = 0; n < KMAP_KEYS; n++)
3265 if (strcmp(term[n + T_CAPS].tcname, *args) == 0)
3266 break;
3267 if (n == KMAP_KEYS)
3269 OutputMsg(0, "%s: bind: unknown key '%s'", rc_name, *args);
3270 break;
3272 n += 256;
3274 else
3275 #endif
3276 if (*argl != 1)
3278 OutputMsg(0, "%s: bind: character, ^x, or (octal) \\032 expected.", rc_name);
3279 break;
3281 else
3282 n = (unsigned char)args[0][0];
3284 if (args[1])
3286 if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
3288 OutputMsg(0, "%s: bind: unknown command '%s'", rc_name, args[1]);
3289 break;
3291 if (CheckArgNum(i, args + 2) < 0)
3292 break;
3293 ClearAction(&ktabp[n]);
3294 SaveAction(ktabp + n, i, args + 2, argl + 2);
3296 else
3297 ClearAction(&ktabp[n]);
3299 break;
3300 #ifdef MAPKEYS
3301 case RC_BINDKEY:
3303 struct action *newact;
3304 int newnr, fl = 0, kf = 0, af = 0, df = 0, mf = 0;
3305 struct display *odisp = display;
3306 int used = 0;
3307 struct kmap_ext *kme;
3309 for (; *args && **args == '-'; args++, argl++)
3311 if (strcmp(*args, "-t") == 0)
3312 fl = KMAP_NOTIMEOUT;
3313 else if (strcmp(*args, "-k") == 0)
3314 kf = 1;
3315 else if (strcmp(*args, "-a") == 0)
3316 af = 1;
3317 else if (strcmp(*args, "-d") == 0)
3318 df = 1;
3319 else if (strcmp(*args, "-m") == 0)
3320 mf = 1;
3321 else if (strcmp(*args, "--") == 0)
3323 args++;
3324 argl++;
3325 break;
3327 else
3329 OutputMsg(0, "%s: bindkey: invalid option %s", rc_name, *args);
3330 return;
3333 if (df && mf)
3335 OutputMsg(0, "%s: bindkey: -d does not work with -m", rc_name);
3336 break;
3338 if (*args == 0)
3340 if (mf)
3341 display_bindkey("Edit mode", mmtab);
3342 else if (df)
3343 display_bindkey("Default", dmtab);
3344 else
3345 display_bindkey("User", umtab);
3346 break;
3348 if (kf == 0)
3350 if (af)
3352 OutputMsg(0, "%s: bindkey: -a only works with -k", rc_name);
3353 break;
3355 if (*argl == 0)
3357 OutputMsg(0, "%s: bindkey: empty string makes no sense", rc_name);
3358 break;
3360 for (i = 0, kme = kmap_exts; i < kmap_extn; i++, kme++)
3361 if (kme->str == 0)
3363 if (args[1])
3364 break;
3366 else
3367 if (*argl == (kme->fl & ~KMAP_NOTIMEOUT) && bcmp(kme->str, *args, *argl) == 0)
3368 break;
3369 if (i == kmap_extn)
3371 if (!args[1])
3373 OutputMsg(0, "%s: bindkey: keybinding not found", rc_name);
3374 break;
3376 kmap_extn += 8;
3377 kmap_exts = (struct kmap_ext *)xrealloc((char *)kmap_exts, kmap_extn * sizeof(*kmap_exts));
3378 kme = kmap_exts + i;
3379 bzero((char *)kme, 8 * sizeof(*kmap_exts));
3380 for (; i < kmap_extn; i++, kme++)
3382 kme->str = 0;
3383 kme->dm.nr = kme->mm.nr = kme->um.nr = RC_ILLEGAL;
3384 kme->dm.args = kme->mm.args = kme->um.args = noargs;
3385 kme->dm.argl = kme->mm.argl = kme->um.argl = 0;
3387 i -= 8;
3388 kme -= 8;
3390 if (df == 0 && kme->dm.nr != RC_ILLEGAL)
3391 used = 1;
3392 if (mf == 0 && kme->mm.nr != RC_ILLEGAL)
3393 used = 1;
3394 if ((df || mf) && kme->um.nr != RC_ILLEGAL)
3395 used = 1;
3396 i += KMAP_KEYS + KMAP_AKEYS;
3397 newact = df ? &kme->dm : mf ? &kme->mm : &kme->um;
3399 else
3401 for (i = T_CAPS; i < T_OCAPS; i++)
3402 if (strcmp(term[i].tcname, *args) == 0)
3403 break;
3404 if (i == T_OCAPS)
3406 OutputMsg(0, "%s: bindkey: unknown key '%s'", rc_name, *args);
3407 break;
3409 if (af && i >= T_CURSOR && i < T_OCAPS)
3410 i -= T_CURSOR - KMAP_KEYS;
3411 else
3412 i -= T_CAPS;
3413 newact = df ? &dmtab[i] : mf ? &mmtab[i] : &umtab[i];
3415 if (args[1])
3417 if ((newnr = FindCommnr(args[1])) == RC_ILLEGAL)
3419 OutputMsg(0, "%s: bindkey: unknown command '%s'", rc_name, args[1]);
3420 break;
3422 if (CheckArgNum(newnr, args + 2) < 0)
3423 break;
3424 ClearAction(newact);
3425 SaveAction(newact, newnr, args + 2, argl + 2);
3426 if (kf == 0 && args[1])
3428 if (kme->str)
3429 free(kme->str);
3430 kme->str = SaveStrn(*args, *argl);
3431 kme->fl = fl | *argl;
3434 else
3435 ClearAction(newact);
3436 for (display = displays; display; display = display->d_next)
3437 remap(i, args[1] ? 1 : 0);
3438 if (kf == 0 && !args[1])
3440 if (!used && kme->str)
3442 free(kme->str);
3443 kme->str = 0;
3444 kme->fl = 0;
3447 display = odisp;
3449 break;
3450 case RC_MAPTIMEOUT:
3451 if (*args)
3453 if (ParseNum(act, &n))
3454 break;
3455 if (n < 0)
3457 OutputMsg(0, "%s: maptimeout: illegal time %d", rc_name, n);
3458 break;
3460 maptimeout = n;
3462 if (*args == 0 || msgok)
3463 OutputMsg(0, "maptimeout is %dms", maptimeout);
3464 break;
3465 case RC_MAPNOTNEXT:
3466 D_dontmap = 1;
3467 break;
3468 case RC_MAPDEFAULT:
3469 D_mapdefault = 1;
3470 break;
3471 #endif
3472 #ifdef MULTIUSER
3473 case RC_ACLCHG:
3474 case RC_ACLADD:
3475 case RC_ADDACL:
3476 case RC_CHACL:
3477 UsersAcl(NULL, argc, args);
3478 break;
3479 case RC_ACLDEL:
3480 if (UserDel(args[0], NULL))
3481 break;
3482 if (msgok)
3483 OutputMsg(0, "%s removed from acl database", args[0]);
3484 break;
3485 case RC_ACLGRP:
3487 * modify a user to gain or lose rights granted to a group.
3488 * This group is actually a normal user whose rights were defined
3489 * with chacl in the usual way.
3491 if (args[1])
3493 if (strcmp(args[1], "none")) /* link a user to another user */
3495 if (AclLinkUser(args[0], args[1]))
3496 break;
3497 if (msgok)
3498 OutputMsg(0, "User %s joined acl-group %s", args[0], args[1]);
3500 else /* remove all groups from user */
3502 struct acluser *u;
3503 struct aclusergroup *g;
3505 if (!(u = *FindUserPtr(args[0])))
3506 break;
3507 while ((g = u->u_group))
3509 u->u_group = g->next;
3510 free((char *)g);
3514 else /* show all groups of user */
3516 char buf[256], *p = buf;
3517 int ngroups = 0;
3518 struct acluser *u;
3519 struct aclusergroup *g;
3521 if (!(u = *FindUserPtr(args[0])))
3523 if (msgok)
3524 OutputMsg(0, "User %s does not exist.", args[0]);
3525 break;
3527 g = u->u_group;
3528 while (g)
3530 ngroups++;
3531 sprintf(p, "%s ", g->u->u_name);
3532 p += strlen(p);
3533 if (p > buf+200)
3534 break;
3535 g = g->next;
3537 if (ngroups)
3538 *(--p) = '\0';
3539 OutputMsg(0, "%s's group%s: %s.", args[0], (ngroups == 1) ? "" : "s",
3540 (ngroups == 0) ? "none" : buf);
3542 break;
3543 case RC_ACLUMASK:
3544 case RC_UMASK:
3545 while ((s = *args++))
3547 char *err = 0;
3549 if (AclUmask(display ? D_user : users, s, &err))
3550 OutputMsg(0, "umask: %s\n", err);
3552 break;
3553 case RC_MULTIUSER:
3554 if (ParseOnOff(act, &n))
3555 break;
3556 multi = n ? "" : 0;
3557 chsock();
3558 if (msgok)
3559 OutputMsg(0, "Multiuser mode %s", multi ? "enabled" : "disabled");
3560 break;
3561 #endif /* MULTIUSER */
3562 #ifdef PSEUDOS
3563 case RC_EXEC:
3564 winexec(args);
3565 break;
3566 #endif
3567 #ifdef MULTI
3568 case RC_NONBLOCK:
3569 i = D_nonblock >= 0;
3570 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.'))
3572 if (ParseNum1000(act, &i))
3573 break;
3575 else if (!ParseSwitch(act, &i))
3576 i = i == 0 ? -1 : 1000;
3577 else
3578 break;
3579 if (msgok && i == -1)
3580 OutputMsg(0, "display set to blocking mode");
3581 else if (msgok && i == 0)
3582 OutputMsg(0, "display set to nonblocking mode, no timeout");
3583 else if (msgok)
3584 OutputMsg(0, "display set to nonblocking mode, %.10gs timeout", i/1000.);
3585 D_nonblock = i;
3586 if (D_nonblock <= 0)
3587 evdeq(&D_blockedev);
3588 break;
3589 case RC_DEFNONBLOCK:
3590 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.'))
3592 if (ParseNum1000(act, &defnonblock))
3593 break;
3595 else if (!ParseOnOff(act, &defnonblock))
3596 defnonblock = defnonblock == 0 ? -1 : 1000;
3597 else
3598 break;
3599 if (display && *rc_name)
3601 D_nonblock = defnonblock;
3602 if (D_nonblock <= 0)
3603 evdeq(&D_blockedev);
3605 break;
3606 #endif
3607 case RC_GR:
3608 #ifdef ENCODINGS
3609 if (fore->w_gr == 2)
3610 fore->w_gr = 0;
3611 #endif
3612 if (ParseSwitch(act, &fore->w_gr) == 0 && msgok)
3613 OutputMsg(0, "Will %suse GR", fore->w_gr ? "" : "not ");
3614 #ifdef ENCODINGS
3615 if (fore->w_gr == 0 && fore->w_FontE)
3616 fore->w_gr = 2;
3617 #endif
3618 break;
3619 case RC_C1:
3620 if (ParseSwitch(act, &fore->w_c1) == 0 && msgok)
3621 OutputMsg(0, "Will %suse C1", fore->w_c1 ? "" : "not ");
3622 break;
3623 #ifdef COLOR
3624 case RC_BCE:
3625 if (ParseSwitch(act, &fore->w_bce) == 0 && msgok)
3626 OutputMsg(0, "Will %serase with background color", fore->w_bce ? "" : "not ");
3627 break;
3628 #endif
3629 #ifdef ENCODINGS
3630 case RC_KANJI:
3631 case RC_ENCODING:
3632 #ifdef UTF8
3633 if (*args && !strcmp(args[0], "-d"))
3635 if (!args[1])
3636 OutputMsg(0, "encodings directory is %s", screenencodings ? screenencodings : "<unset>");
3637 else
3639 free(screenencodings);
3640 screenencodings = SaveStr(args[1]);
3642 break;
3644 if (*args && !strcmp(args[0], "-l"))
3646 if (!args[1])
3647 OutputMsg(0, "encoding: -l: argument required");
3648 else if (LoadFontTranslation(-1, args[1]))
3649 OutputMsg(0, "encoding: could not load utf8 encoding file");
3650 else if (msgok)
3651 OutputMsg(0, "encoding: utf8 encoding file loaded");
3652 break;
3654 #else
3655 if (*args && (!strcmp(args[0], "-l") || !strcmp(args[0], "-d")))
3657 if (msgok)
3658 OutputMsg(0, "encoding: screen is not compiled for UTF-8.");
3659 break;
3661 #endif
3662 for (i = 0; i < 2; i++)
3664 if (args[i] == 0)
3665 break;
3666 if (!strcmp(args[i], "."))
3667 continue;
3668 n = FindEncoding(args[i]);
3669 if (n == -1)
3671 OutputMsg(0, "encoding: unknown encoding '%s'", args[i]);
3672 break;
3674 if (i == 0 && fore)
3676 WinSwitchEncoding(fore, n);
3677 ResetCharsets(fore);
3679 else if (i && display)
3680 D_encoding = n;
3682 break;
3683 case RC_DEFKANJI:
3684 case RC_DEFENCODING:
3685 n = FindEncoding(*args);
3686 if (n == -1)
3688 OutputMsg(0, "defencoding: unknown encoding '%s'", *args);
3689 break;
3691 nwin_default.encoding = n;
3692 break;
3693 #endif
3695 #ifdef UTF8
3696 case RC_DEFUTF8:
3697 n = nwin_default.encoding == UTF8;
3698 if (ParseSwitch(act, &n) == 0)
3700 nwin_default.encoding = n ? UTF8 : 0;
3701 if (msgok)
3702 OutputMsg(0, "Will %suse UTF-8 encoding for new windows", n ? "" : "not ");
3704 break;
3705 case RC_UTF8:
3706 for (i = 0; i < 2; i++)
3708 if (i && args[i] == 0)
3709 break;
3710 if (args[i] == 0)
3711 n = fore->w_encoding != UTF8;
3712 else if (strcmp(args[i], "off") == 0)
3713 n = 0;
3714 else if (strcmp(args[i], "on") == 0)
3715 n = 1;
3716 else
3718 OutputMsg(0, "utf8: illegal argument (%s)", args[i]);
3719 break;
3721 if (i == 0)
3723 WinSwitchEncoding(fore, n ? UTF8 : 0);
3724 if (msgok)
3725 OutputMsg(0, "Will %suse UTF-8 encoding", n ? "" : "not ");
3727 else if (display)
3728 D_encoding = n ? UTF8 : 0;
3729 if (args[i] == 0)
3730 break;
3732 break;
3733 #endif
3735 case RC_PRINTCMD:
3736 if (*args)
3738 if (printcmd)
3739 free(printcmd);
3740 printcmd = 0;
3741 if (**args)
3742 printcmd = SaveStr(*args);
3744 if (*args == 0 || msgok)
3746 if (printcmd)
3747 OutputMsg(0, "using '%s' as print command", printcmd);
3748 else
3749 OutputMsg(0, "using termcap entries for printing");
3750 break;
3752 break;
3754 case RC_DIGRAPH:
3755 if (argl && argl[0] > 0 && argl[1] > 0)
3757 if (argl[0] != 2)
3759 OutputMsg(0, "Two characters expected to define a digraph");
3760 break;
3762 i = digraph_find(args[0]);
3763 digraphs[i].d[0] = args[0][0];
3764 digraphs[i].d[1] = args[0][1];
3765 if (!parse_input_int(args[1], argl[1], &digraphs[i].value))
3767 if (!(digraphs[i].value = atoi(args[1])))
3769 if (!args[1][1])
3770 digraphs[i].value = (int)args[1][0];
3771 #ifdef UTF8
3772 else
3774 int t;
3775 unsigned char *s = args[1];
3776 digraphs[i].value = 0;
3777 while (*s)
3779 t = FromUtf8(*s++, &digraphs[i].value);
3780 if (t == -1)
3781 continue;
3782 if (t == -2)
3783 digraphs[i].value = 0;
3784 else
3785 digraphs[i].value = t;
3786 break;
3789 #endif
3792 break;
3794 Input("Enter digraph: ", 10, INP_EVERY, digraph_fn, NULL, 0);
3795 if (*args && **args)
3797 s = *args;
3798 n = strlen(s);
3799 LayProcess(&s, &n);
3801 break;
3803 case RC_DEFHSTATUS:
3804 if (*args == 0)
3806 char buf[256];
3807 *buf = 0;
3808 if (nwin_default.hstatus)
3809 AddXChars(buf, sizeof(buf), nwin_default.hstatus);
3810 OutputMsg(0, "default hstatus is '%s'", buf);
3811 break;
3813 (void)ParseSaveStr(act, &nwin_default.hstatus);
3814 if (*nwin_default.hstatus == 0)
3816 free(nwin_default.hstatus);
3817 nwin_default.hstatus = 0;
3819 break;
3820 case RC_HSTATUS:
3821 (void)ParseSaveStr(act, &fore->w_hstatus);
3822 if (*fore->w_hstatus == 0)
3824 free(fore->w_hstatus);
3825 fore->w_hstatus = 0;
3827 WindowChanged(fore, 'h');
3828 break;
3830 #ifdef FONT
3831 case RC_DEFCHARSET:
3832 case RC_CHARSET:
3833 if (*args == 0)
3835 char buf[256];
3836 *buf = 0;
3837 if (nwin_default.charset)
3838 AddXChars(buf, sizeof(buf), nwin_default.charset);
3839 OutputMsg(0, "default charset is '%s'", buf);
3840 break;
3842 n = strlen(*args);
3843 if (n == 0 || n > 6)
3845 OutputMsg(0, "%s: %s: string has illegal size.", rc_name, comms[nr].name);
3846 break;
3848 if (n > 4 && (
3849 ((args[0][4] < '0' || args[0][4] > '3') && args[0][4] != '.') ||
3850 ((args[0][5] < '0' || args[0][5] > '3') && args[0][5] && args[0][5] != '.')))
3852 OutputMsg(0, "%s: %s: illegal mapping number.", rc_name, comms[nr].name);
3853 break;
3855 if (nr == RC_CHARSET)
3857 SetCharsets(fore, *args);
3858 break;
3860 if (nwin_default.charset)
3861 free(nwin_default.charset);
3862 nwin_default.charset = SaveStr(*args);
3863 break;
3864 #endif
3865 #ifdef COLOR
3866 case RC_ATTRCOLOR:
3867 s = args[0];
3868 if (*s >= '0' && *s <= '9')
3869 i = *s - '0';
3870 else
3871 for (i = 0; i < 8; i++)
3872 if (*s == "dubrsBiI"[i])
3873 break;
3874 s++;
3875 nr = 0;
3876 if (*s && s[1] && !s[2])
3878 if (*s == 'd' && s[1] == 'd')
3879 nr = 3;
3880 else if (*s == '.' && s[1] == 'd')
3881 nr = 2;
3882 else if (*s == 'd' && s[1] == '.')
3883 nr = 1;
3884 else if (*s != '.' || s[1] != '.')
3885 s--;
3886 s += 2;
3888 if (*s || i < 0 || i >= 8)
3890 OutputMsg(0, "%s: attrcolor: unknown attribute '%s'.", rc_name, args[0]);
3891 break;
3893 n = 0;
3894 if (args[1])
3895 n = ParseAttrColor(args[1], args[2], 1);
3896 if (n == -1)
3897 break;
3898 attr2color[i][nr] = n;
3899 n = 0;
3900 for (i = 0; i < 8; i++)
3901 if (attr2color[i][0] || attr2color[i][1] || attr2color[i][2] || attr2color[i][3])
3902 n |= 1 << i;
3903 nattr2color = n;
3904 break;
3905 #endif
3906 case RC_RENDITION:
3907 i = -1;
3908 if (strcmp(args[0], "bell") == 0)
3910 i = REND_BELL;
3912 else if (strcmp(args[0], "monitor") == 0)
3914 i = REND_MONITOR;
3916 else if (strcmp(args[0], "silence") == 0)
3918 i = REND_SILENCE;
3920 else if (strcmp(args[0], "so") != 0)
3922 OutputMsg(0, "Invalid option '%s' for rendition", args[0]);
3923 break;
3926 ++args;
3927 ++argl;
3929 if (i != -1)
3931 renditions[i] = ParseAttrColor(args[0], args[1], 1);
3932 WindowChanged((struct win *)0, 'w');
3933 WindowChanged((struct win *)0, 'W');
3934 WindowChanged((struct win *)0, 0);
3935 break;
3938 /* We are here, means we want to set the sorendition. */
3939 /* FALLTHROUGH*/
3940 case RC_SORENDITION:
3941 i = 0;
3942 if (*args)
3944 i = ParseAttrColor(*args, args[1], 1);
3945 if (i == -1)
3946 break;
3947 ApplyAttrColor(i, &mchar_so);
3948 WindowChanged((struct win *)0, 0);
3949 debug2("--> %x %x\n", mchar_so.attr, mchar_so.color);
3951 if (msgok)
3952 #ifdef COLOR
3953 OutputMsg(0, "Standout attributes 0x%02x color 0x%02x", (unsigned char)mchar_so.attr, 0x99 ^ (unsigned char)mchar_so.color);
3954 #else
3955 OutputMsg(0, "Standout attributes 0x%02x ", (unsigned char)mchar_so.attr);
3956 #endif
3957 break;
3959 case RC_SOURCE:
3960 do_source(*args);
3961 break;
3963 #ifdef MULTIUSER
3964 case RC_SU:
3965 s = NULL;
3966 if (!*args)
3968 OutputMsg(0, "%s:%s screen login", HostName, SockPath);
3969 InputSu(D_fore, &D_user, NULL);
3971 else if (!args[1])
3972 InputSu(D_fore, &D_user, args[0]);
3973 else if (!args[2])
3974 s = DoSu(&D_user, args[0], args[1], "\377");
3975 else
3976 s = DoSu(&D_user, args[0], args[1], args[2]);
3977 if (s)
3978 OutputMsg(0, "%s", s);
3979 break;
3980 #endif /* MULTIUSER */
3981 case RC_SPLIT:
3982 s = args[0];
3983 if (s && !strcmp(s, "-v"))
3984 AddCanvas(SLICE_HORI);
3985 else
3986 AddCanvas(SLICE_VERT);
3987 Activate(-1);
3988 break;
3989 case RC_REMOVE:
3990 RemCanvas();
3991 Activate(-1);
3992 break;
3993 case RC_ONLY:
3994 OneCanvas();
3995 Activate(-1);
3996 break;
3997 case RC_FIT:
3998 D_forecv->c_xoff = D_forecv->c_xs;
3999 D_forecv->c_yoff = D_forecv->c_ys;
4000 RethinkViewportOffsets(D_forecv);
4001 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0);
4002 flayer = D_forecv->c_layer;
4003 LaySetCursor();
4004 break;
4005 case RC_FOCUS:
4007 struct canvas *cv = 0;
4008 if (!*args || !strcmp(*args, "next"))
4009 cv = D_forecv->c_next ? D_forecv->c_next : D_cvlist;
4010 else if (!strcmp(*args, "prev"))
4012 for (cv = D_cvlist; cv->c_next && cv->c_next != D_forecv; cv = cv->c_next)
4015 else if (!strcmp(*args, "top"))
4016 cv = D_cvlist;
4017 else if (!strcmp(*args, "bottom"))
4019 for (cv = D_cvlist; cv->c_next; cv = cv->c_next)
4022 else if (!strcmp(*args, "up"))
4023 cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ys - 1);
4024 else if (!strcmp(*args, "down"))
4025 cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ye + 2);
4026 else if (!strcmp(*args, "left"))
4027 cv = FindCanvas(D_forecv->c_xs - 1, D_forecv->c_ys);
4028 else if (!strcmp(*args, "right"))
4029 cv = FindCanvas(D_forecv->c_xe + 1, D_forecv->c_ys);
4030 else
4032 OutputMsg(0, "%s: usage: focus [next|prev|up|down|left|right|top|bottom]", rc_name);
4033 break;
4035 SetForeCanvas(display, cv);
4037 break;
4038 case RC_RESIZE:
4039 i = 0;
4040 if (D_forecv->c_slorient == SLICE_UNKN)
4042 OutputMsg(0, "resize: need more than one region");
4043 break;
4045 for (; *args; args++)
4047 if (!strcmp(*args, "-h"))
4048 i |= RESIZE_FLAG_H;
4049 else if (!strcmp(*args, "-v"))
4050 i |= RESIZE_FLAG_V;
4051 else if (!strcmp(*args, "-b"))
4052 i |= RESIZE_FLAG_H | RESIZE_FLAG_V;
4053 else if (!strcmp(*args, "-p"))
4054 i |= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V;
4055 else if (!strcmp(*args, "-l"))
4056 i |= RESIZE_FLAG_L;
4057 else
4058 break;
4060 if (*args && args[1])
4062 OutputMsg(0, "%s: usage: resize [-h] [-v] [-l] [num]\n", rc_name);
4063 break;
4065 if (*args)
4066 ResizeRegions(*args, i);
4067 else
4068 Input(resizeprompts[i], 20, INP_EVERY, ResizeFin, (char*)0, i);
4069 break;
4070 case RC_SETSID:
4071 (void)ParseSwitch(act, &separate_sids);
4072 break;
4073 case RC_EVAL:
4074 args = SaveArgs(args);
4075 for (i = 0; args[i]; i++)
4077 if (args[i][0])
4078 Colonfin(args[i], strlen(args[i]), (char *)0);
4079 free(args[i]);
4081 free(args);
4082 break;
4083 case RC_ALTSCREEN:
4084 (void)ParseSwitch(act, &use_altscreen);
4085 if (msgok)
4086 OutputMsg(0, "Will %sdo alternate screen switching", use_altscreen ? "" : "not ");
4087 break;
4088 case RC_MAXWIN:
4089 if (!args[0])
4091 OutputMsg(0, "maximum windows allowed: %d", maxwin);
4092 break;
4094 if (ParseNum(act, &n))
4095 break;
4096 if (n < 1)
4097 OutputMsg(0, "illegal maxwin number specified");
4098 else if (n > 2048)
4099 OutputMsg(0, "maximum 2048 windows allowed");
4100 else if (n > maxwin && windows)
4101 OutputMsg(0, "may increase maxwin only when there's no window");
4102 else
4104 if (!windows)
4105 wtab = realloc(wtab, n * sizeof(struct win *));
4106 maxwin = n;
4108 break;
4109 case RC_BACKTICK:
4110 if (ParseBase(act, *args, &n, 10, "decimal"))
4111 break;
4112 if (!args[1])
4113 setbacktick(n, 0, 0, (char **)0);
4114 else
4116 int lifespan, tick;
4117 if (argc < 4)
4119 OutputMsg(0, "%s: usage: backtick num [lifespan tick cmd args...]", rc_name);
4120 break;
4122 if (ParseBase(act, args[1], &lifespan, 10, "decimal"))
4123 break;
4124 if (ParseBase(act, args[2], &tick, 10, "decimal"))
4125 break;
4126 setbacktick(n, lifespan, tick, SaveArgs(args + 3));
4128 WindowChanged(0, '`');
4129 break;
4130 case RC_BLANKER:
4131 #ifdef BLANKER_PRG
4132 if (blankerprg)
4134 RunBlanker(blankerprg);
4135 break;
4137 #endif
4138 ClearAll();
4139 CursorVisibility(-1);
4140 D_blocked = 4;
4141 break;
4142 #ifdef BLANKER_PRG
4143 case RC_BLANKERPRG:
4144 if (!args[0])
4146 if (blankerprg)
4148 char path[MAXPATHLEN];
4149 char *p = path, **pp;
4150 for (pp = blankerprg; *pp; pp++)
4151 p += snprintf(p, sizeof(path) - (p - path) - 1, "%s ", *pp);
4152 *(p - 1) = '\0';
4153 OutputMsg(0, "blankerprg: %s", path);
4155 else
4156 OutputMsg(0, "No blankerprg set.");
4157 break;
4159 if (blankerprg)
4161 char **pp;
4162 for (pp = blankerprg; *pp; pp++)
4163 free(*pp);
4164 free(blankerprg);
4165 blankerprg = 0;
4167 if (args[0][0])
4168 blankerprg = SaveArgs(args);
4169 break;
4170 #endif
4171 case RC_IDLE:
4172 if (*args)
4174 struct display *olddisplay = display;
4175 if (!strcmp(*args, "off"))
4176 idletimo = 0;
4177 else if (args[0][0])
4178 idletimo = atoi(*args) * 1000;
4179 if (argc > 1)
4181 if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
4183 OutputMsg(0, "%s: idle: unknown command '%s'", rc_name, args[1]);
4184 break;
4186 if (CheckArgNum(i, args + 2) < 0)
4187 break;
4188 ClearAction(&idleaction);
4189 SaveAction(&idleaction, i, args + 2, argl + 2);
4191 for (display = displays; display; display = display->d_next)
4192 ResetIdle();
4193 display = olddisplay;
4195 if (msgok)
4197 if (idletimo)
4198 OutputMsg(0, "idle timeout %ds, %s", idletimo / 1000, comms[idleaction.nr].name);
4199 else
4200 OutputMsg(0, "idle off");
4202 break;
4203 case RC_FOCUSMINSIZE:
4204 for (i = 0; i < 2 && args[i]; i++)
4206 if (!strcmp(args[i], "max") || !strcmp(args[i], "_"))
4207 n = -1;
4208 else
4209 n = atoi(args[i]);
4210 if (i == 0)
4211 focusminwidth = n;
4212 else
4213 focusminheight = n;
4215 if (msgok)
4217 char b[2][20];
4218 for (i = 0; i < 2; i++)
4220 n = i == 0 ? focusminwidth : focusminheight;
4221 if (n == -1)
4222 strcpy(b[i], "max");
4223 else
4224 sprintf(b[i], "%d", n);
4226 OutputMsg(0, "focus min size is %s %s\n", b[0], b[1]);
4228 break;
4229 case RC_GROUP:
4230 if (*args)
4232 fore->w_group = 0;
4233 if (args[0][0])
4235 fore->w_group = WindowByName(*args);
4236 if (fore->w_group == fore || (fore->w_group && fore->w_group->w_type != W_TYPE_GROUP))
4237 fore->w_group = 0;
4239 WindowChanged((struct win *)0, 'w');
4240 WindowChanged((struct win *)0, 'W');
4241 WindowChanged((struct win *)0, 0);
4243 if (msgok)
4245 if (fore->w_group)
4246 OutputMsg(0, "window group is %d (%s)\n", fore->w_group->w_number, fore->w_group->w_title);
4247 else
4248 OutputMsg(0, "window belongs to no group");
4250 break;
4251 case RC_LAYOUT:
4252 if (!strcmp(args[0], "title"))
4254 if (!D_layout)
4256 OutputMsg(0, "not on a layout");
4257 break;
4259 if (!args[1])
4261 OutputMsg(0, "current layout is %d (%s)", D_layout->lay_number, D_layout->lay_title);
4262 break;
4264 free(D_layout->lay_title);
4265 D_layout->lay_title= SaveStr(args[1]);
4267 else if (!strcmp(args[0], "number"))
4269 int old;
4270 struct layout *lay;
4271 if (!D_layout)
4273 OutputMsg(0, "not on a layout");
4274 break;
4276 if (!args[1])
4278 OutputMsg(0, "This is layout %d (%s).\n", D_layout->lay_number, D_layout->lay_title);
4279 break;
4281 old = D_layout->lay_number;
4282 n = atoi(args[1]);
4283 if (n < 0 || n >= MAXLAY)
4284 break;
4285 lay = laytab[n];
4286 laytab[n] = D_layout;
4287 D_layout->lay_number = n;
4288 laytab[old] = lay;
4289 if (lay)
4290 lay->lay_number = old;
4291 break;
4293 else if (!strcmp(args[0], "autosave"))
4295 if (!D_layout)
4297 OutputMsg(0, "not on a layout");
4298 break;
4300 if (args[1])
4302 if (!strcmp(args[1], "on"))
4303 D_layout->lay_autosave = 1;
4304 else if (!strcmp(args[1], "off"))
4305 D_layout->lay_autosave = 0;
4306 else
4308 OutputMsg(0, "invalid argument. Give 'on' or 'off");
4309 break;
4312 if (msgok)
4313 OutputMsg(0, "autosave is %s", D_layout->lay_autosave ? "on" : "off");
4315 else if (!strcmp(args[0], "new"))
4317 char *t = args[1];
4318 n = 0;
4319 if (t)
4321 while (*t >= '0' && *t <= '9')
4322 t++;
4323 if (t != args[1] && (!*t || *t == ':'))
4325 n = atoi(args[1]);
4326 if (*t)
4327 t++;
4329 else
4330 t = args[1];
4332 if (!t || !*t)
4333 t = "layout";
4334 NewLayout(t, n);
4335 Activate(-1);
4337 else if (!strcmp(args[0], "save"))
4339 if (!args[1])
4341 OutputMsg(0, "usage: layout save <name>");
4342 break;
4344 SaveLayout(args[1], &D_canvas);
4346 else if (!strcmp(args[0], "select"))
4348 if (!args[1])
4350 Input("Switch to layout: ", 20, INP_COOKED, SelectLayoutFin, NULL, 0);
4351 break;
4353 SelectLayoutFin(args[1], strlen(args[1]), (char *)0);
4355 else if (!strcmp(args[0], "next"))
4357 struct layout *lay = D_layout;
4358 if (lay)
4359 lay = lay->lay_next ? lay->lay_next : layouts;
4360 else
4361 lay = layouts;
4362 if (!lay)
4364 OutputMsg(0, "no layout defined");
4365 break;
4367 if (lay == D_layout)
4368 break;
4369 LoadLayout(lay, &D_canvas);
4370 Activate(-1);
4372 else if (!strcmp(args[0], "prev"))
4374 struct layout *lay = D_layout;
4375 if (lay)
4377 for (lay = layouts; lay->lay_next && lay->lay_next != D_layout; lay = lay->lay_next)
4380 else
4381 lay = layouts;
4382 if (!lay)
4384 OutputMsg(0, "no layout defined");
4385 break;
4387 if (lay == D_layout)
4388 break;
4389 LoadLayout(lay, &D_canvas);
4390 Activate(-1);
4392 else if (!strcmp(args[0], "attach"))
4394 if (!args[1])
4396 if (!layout_attach)
4397 OutputMsg(0, "no attach layout set");
4398 else if (layout_attach == &layout_last_marker)
4399 OutputMsg(0, "will attach to last layout");
4400 else
4401 OutputMsg(0, "will attach to layout %d (%s)", layout_attach->lay_number, layout_attach->lay_title);
4402 break;
4404 if (!strcmp(args[1], ":last"))
4405 layout_attach = &layout_last_marker;
4406 else if (!args[1][0])
4407 layout_attach = 0;
4408 else
4410 struct layout *lay;
4411 lay = FindLayout(args[1]);
4412 if (!lay)
4414 OutputMsg(0, "unknown layout '%s'", args[1]);
4415 break;
4417 layout_attach = lay;
4420 else if (!strcmp(args[0], "show"))
4422 ShowLayouts(-1);
4424 else if (!strcmp(args[0], "remove"))
4426 struct layout *lay = display ? D_layout : layouts;
4427 if (args[1])
4429 lay = layouts ? FindLayout(args[1]) : (struct layout *)0;
4430 if (!lay)
4432 OutputMsg(0, "unknown layout '%s'", args[1]);
4433 break;
4436 if (lay)
4437 RemoveLayout(lay);
4439 else if (!strcmp(args[0], "dump"))
4441 if (!display)
4442 OutputMsg(0, "Must have a display for 'layout dump'.");
4443 else if (!LayoutDumpCanvas(&D_canvas, args[1] ? args[1] : "layout-dump"))
4444 OutputMsg(errno, "Error dumping layout.");
4445 else
4446 OutputMsg(0, "Layout dumped to \"%s\"", args[1] ? args[1] : "layout-dump");
4448 else
4449 OutputMsg(0, "unknown layout subcommand");
4450 break;
4451 #ifdef DW_CHARS
4452 case RC_CJKWIDTH:
4453 if(ParseSwitch(act, &cjkwidth) == 0)
4455 if(msgok)
4456 OutputMsg(0, "Treat ambiguous width characters as %s width", cjkwidth ? "full" : "half");
4458 break;
4459 #endif
4460 default:
4461 #ifdef HAVE_BRAILLE
4462 /* key == -2: input from braille keybord, msgok always 0 */
4463 DoBrailleAction(act, key == -2 ? 0 : msgok);
4464 #endif
4465 break;
4467 if (display != odisplay)
4469 for (display = displays; display; display = display->d_next)
4470 if (display == odisplay)
4471 break;
4474 #undef OutputMsg
4476 void
4477 DoCommand(argv, argl)
4478 char **argv;
4479 int *argl;
4481 struct action act;
4482 const char *cmd = *argv;
4484 act.quiet = 0;
4485 /* For now, we actually treat both 'supress error' and 'suppress normal message' as the
4486 * same, and ignore all messages on either flag. If we wanted to do otherwise, we would
4487 * need to change the definition of 'OutputMsg' slightly. */
4488 if (*cmd == '@') /* Suppress error */
4490 act.quiet |= 0x01;
4491 cmd++;
4493 if (*cmd == '-') /* Suppress normal message */
4495 act.quiet |= 0x02;
4496 cmd++;
4499 if ((act.nr = FindCommnr(cmd)) == RC_ILLEGAL)
4501 Msg(0, "%s: unknown command '%s'", rc_name, cmd);
4502 return;
4504 act.args = argv + 1;
4505 act.argl = argl + 1;
4506 DoAction(&act, -1);
4509 static void
4510 SaveAction(act, nr, args, argl)
4511 struct action *act;
4512 int nr;
4513 char **args;
4514 int *argl;
4516 register int argc = 0;
4517 char **pp;
4518 int *lp;
4520 if (args)
4521 while (args[argc])
4522 argc++;
4523 if (argc == 0)
4525 act->nr = nr;
4526 act->args = noargs;
4527 act->argl = 0;
4528 return;
4530 if ((pp = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0)
4531 Panic(0, "%s", strnomem);
4532 if ((lp = (int *)malloc((unsigned)(argc) * sizeof(int *))) == 0)
4533 Panic(0, "%s", strnomem);
4534 act->nr = nr;
4535 act->args = pp;
4536 act->argl = lp;
4537 while (argc--)
4539 *lp = argl ? *argl++ : (int)strlen(*args);
4540 *pp++ = SaveStrn(*args++, *lp++);
4542 *pp = 0;
4545 static char **
4546 SaveArgs(args)
4547 char **args;
4549 register char **ap, **pp;
4550 register int argc = 0;
4552 while (args[argc])
4553 argc++;
4554 if ((pp = ap = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0)
4555 Panic(0, "%s", strnomem);
4556 while (argc--)
4557 *pp++ = SaveStr(*args++);
4558 *pp = 0;
4559 return ap;
4564 * buf is split into argument vector args.
4565 * leading whitespace is removed.
4566 * @!| abbreviations are expanded.
4567 * the end of buffer is recognized by '\0' or an un-escaped '#'.
4568 * " and ' are interpreted.
4570 * argc is returned.
4572 int
4573 Parse(buf, bufl, args, argl)
4574 char *buf, **args;
4575 int bufl, *argl;
4577 register char *p = buf, **ap = args, *pp;
4578 register int delim, argc;
4579 int *lp = argl;
4581 debug2("Parse %d %s\n", bufl, buf);
4582 argc = 0;
4583 pp = buf;
4584 delim = 0;
4585 for (;;)
4587 *lp = 0;
4588 while (*p && (*p == ' ' || *p == '\t'))
4589 ++p;
4590 #ifdef PSEUDOS
4591 if (argc == 0 && *p == '!')
4593 *ap++ = "exec";
4594 *lp++ = 4;
4595 p++;
4596 argc++;
4597 continue;
4599 #endif
4600 if (*p == '\0' || *p == '#' || *p == '\n')
4602 *p = '\0';
4603 for (delim = 0; delim < argc; delim++)
4604 debug1("-- %s\n", args[delim]);
4605 args[argc] = 0;
4606 return argc;
4608 if (++argc >= MAXARGS)
4610 Msg(0, "%s: too many tokens.", rc_name);
4611 return 0;
4613 *ap++ = pp;
4615 debug1("- new arg %s\n", p);
4616 while (*p)
4618 if (*p == delim)
4619 delim = 0;
4620 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')))
4622 p++;
4623 if (*p >= '0' && *p <= '7')
4625 *pp = *p - '0';
4626 if (p[1] >= '0' && p[1] <= '7')
4628 p++;
4629 *pp = (*pp << 3) | (*p - '0');
4630 if (p[1] >= '0' && p[1] <= '7')
4632 p++;
4633 *pp = (*pp << 3) | (*p - '0');
4636 pp++;
4638 else
4640 switch (*p)
4642 case 'n': *pp = '\n'; break;
4643 case 'r': *pp = '\r'; break;
4644 case 't': *pp = '\t'; break;
4645 default: *pp = *p; break;
4647 pp++;
4650 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] == '_'))
4653 char *ps, *pe, op, *v, xbuf[11], path[MAXPATHLEN];
4654 int vl;
4656 ps = ++p;
4657 debug1("- var %s\n", ps);
4658 p++;
4659 while (*p)
4661 if (*ps == '{' && *p == '}')
4662 break;
4663 if (*ps == ':' && *p == ':')
4664 break;
4665 if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_')
4666 break;
4667 p++;
4669 pe = p;
4670 if (*ps == '{' || *ps == ':')
4672 if (!*p)
4674 Msg(0, "%s: bad variable name.", rc_name);
4675 return 0;
4677 p++;
4679 op = *pe;
4680 *pe = 0;
4681 debug1("- var is '%s'\n", ps);
4682 if (*ps == ':')
4683 v = gettermcapstring(ps + 1);
4684 else
4686 if (*ps == '{')
4687 ps++;
4688 v = xbuf;
4689 if (!strcmp(ps, "TERM"))
4690 v = display ? D_termname : "unknown";
4691 else if (!strcmp(ps, "COLUMNS"))
4692 sprintf(xbuf, "%d", display ? D_width : -1);
4693 else if (!strcmp(ps, "LINES"))
4694 sprintf(xbuf, "%d", display ? D_height : -1);
4695 else if (!strcmp(ps, "PID"))
4696 sprintf(xbuf, "%d", getpid());
4697 else if (!strcmp(ps, "PWD"))
4699 if (getcwd(path, sizeof(path) - 1) == 0)
4700 v = "?";
4701 else
4702 v = path;
4704 else if (!strcmp(ps, "STY"))
4706 if ((v = strchr(SockName, '.'))) /* Skip the PID */
4707 v++;
4708 else
4709 v = SockName;
4711 else
4712 v = getenv(ps);
4714 *pe = op;
4715 vl = v ? strlen(v) : 0;
4716 if (vl)
4718 debug1("- sub is '%s'\n", v);
4719 if (p - pp < vl)
4721 int right = buf + bufl - (p + strlen(p) + 1);
4722 if (right > 0)
4724 bcopy(p, p + right, strlen(p) + 1);
4725 p += right;
4728 if (p - pp < vl)
4730 Msg(0, "%s: no space left for variable expansion.", rc_name);
4731 return 0;
4733 bcopy(v, pp, vl);
4734 pp += vl;
4736 continue;
4738 else if (delim != '\'' && *p == '^' && p[1])
4740 p++;
4741 *pp++ = *p == '?' ? '\177' : *p & 0x1f;
4743 else if (delim == 0 && (*p == '\'' || *p == '"'))
4744 delim = *p;
4745 else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n'))
4746 break;
4747 else
4748 *pp++ = *p;
4749 p++;
4751 if (delim)
4753 Msg(0, "%s: Missing %c quote.", rc_name, delim);
4754 return 0;
4756 if (*p)
4757 p++;
4758 *pp = 0;
4759 debug2("- arg done, '%s' rest %s\n", ap[-1], p);
4760 *lp++ = pp - ap[-1];
4761 pp++;
4765 void
4766 SetEscape(u, e, me)
4767 struct acluser *u;
4768 int e, me;
4770 if (u)
4772 u->u_Esc = e;
4773 u->u_MetaEsc = me;
4775 else
4777 if (users)
4779 if (DefaultEsc >= 0)
4780 ClearAction(&ktab[DefaultEsc]);
4781 if (DefaultMetaEsc >= 0)
4782 ClearAction(&ktab[DefaultMetaEsc]);
4784 DefaultEsc = e;
4785 DefaultMetaEsc = me;
4786 if (users)
4788 if (DefaultEsc >= 0)
4790 ClearAction(&ktab[DefaultEsc]);
4791 ktab[DefaultEsc].nr = RC_OTHER;
4793 if (DefaultMetaEsc >= 0)
4795 ClearAction(&ktab[DefaultMetaEsc]);
4796 ktab[DefaultMetaEsc].nr = RC_META;
4803 ParseSwitch(act, var)
4804 struct action *act;
4805 int *var;
4807 if (*act->args == 0)
4809 *var ^= 1;
4810 return 0;
4812 return ParseOnOff(act, var);
4815 static int
4816 ParseOnOff(act, var)
4817 struct action *act;
4818 int *var;
4820 register int num = -1;
4821 char **args = act->args;
4823 if (args[1] == 0)
4825 if (strcmp(args[0], "on") == 0)
4826 num = 1;
4827 else if (strcmp(args[0], "off") == 0)
4828 num = 0;
4830 if (num < 0)
4832 Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name);
4833 return -1;
4835 *var = num;
4836 return 0;
4840 ParseSaveStr(act, var)
4841 struct action *act;
4842 char **var;
4844 char **args = act->args;
4845 if (*args == 0 || args[1])
4847 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
4848 return -1;
4850 if (*var)
4851 free(*var);
4852 *var = SaveStr(*args);
4853 return 0;
4857 ParseNum(act, var)
4858 struct action *act;
4859 int *var;
4861 int i;
4862 char *p, **args = act->args;
4864 p = *args;
4865 if (p == 0 || *p == 0 || args[1])
4867 Msg(0, "%s: %s: invalid argument. Give one argument.",
4868 rc_name, comms[act->nr].name);
4869 return -1;
4871 i = 0;
4872 while (*p)
4874 if (*p >= '0' && *p <= '9')
4875 i = 10 * i + (*p - '0');
4876 else
4878 Msg(0, "%s: %s: invalid argument. Give numeric argument.",
4879 rc_name, comms[act->nr].name);
4880 return -1;
4882 p++;
4884 debug1("ParseNum got %d\n", i);
4885 *var = i;
4886 return 0;
4889 static int
4890 ParseNum1000(act, var)
4891 struct action *act;
4892 int *var;
4894 int i;
4895 char *p, **args = act->args;
4896 int dig = 0;
4898 p = *args;
4899 if (p == 0 || *p == 0 || args[1])
4901 Msg(0, "%s: %s: invalid argument. Give one argument.",
4902 rc_name, comms[act->nr].name);
4903 return -1;
4905 i = 0;
4906 while (*p)
4908 if (*p >= '0' && *p <= '9')
4910 if (dig < 4)
4911 i = 10 * i + (*p - '0');
4912 else if (dig == 4 && *p >= '5')
4913 i++;
4914 if (dig)
4915 dig++;
4917 else if (*p == '.' && !dig)
4918 dig++;
4919 else
4921 Msg(0, "%s: %s: invalid argument. Give floating point argument.",
4922 rc_name, comms[act->nr].name);
4923 return -1;
4925 p++;
4927 if (dig == 0)
4928 i *= 1000;
4929 else
4930 while (dig++ < 4)
4931 i *= 10;
4932 if (i < 0)
4933 i = (int)((unsigned int)~0 >> 1);
4934 debug1("ParseNum1000 got %d\n", i);
4935 *var = i;
4936 return 0;
4939 static struct win *
4940 WindowByName(s)
4941 char *s;
4943 struct win *p;
4945 for (p = windows; p; p = p->w_next)
4946 if (!strcmp(p->w_title, s))
4947 return p;
4948 for (p = windows; p; p = p->w_next)
4949 if (!strncmp(p->w_title, s, strlen(s)))
4950 return p;
4951 return 0;
4954 static int
4955 WindowByNumber(str)
4956 char *str;
4958 int i;
4959 char *s;
4961 for (i = 0, s = str; *s; s++)
4963 if (*s < '0' || *s > '9')
4964 break;
4965 i = i * 10 + (*s - '0');
4967 return *s ? -1 : i;
4971 * Get window number from Name or Number string.
4972 * Numbers are tried first, then names, a prefix match suffices.
4973 * Be careful when assigning numeric strings as WindowTitles.
4976 WindowByNoN(str)
4977 char *str;
4979 int i;
4980 struct win *p;
4982 if ((i = WindowByNumber(str)) < 0 || i >= maxwin)
4984 if ((p = WindowByName(str)))
4985 return p->w_number;
4986 return -1;
4988 return i;
4991 static int
4992 ParseWinNum(act, var)
4993 struct action *act;
4994 int *var;
4996 char **args = act->args;
4997 int i = 0;
4999 if (*args == 0 || args[1])
5001 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
5002 return -1;
5005 i = WindowByNoN(*args);
5006 if (i < 0)
5008 Msg(0, "%s: %s: invalid argument. Give window number or name.",
5009 rc_name, comms[act->nr].name);
5010 return -1;
5012 debug1("ParseWinNum got %d\n", i);
5013 *var = i;
5014 return 0;
5017 static int
5018 ParseBase(act, p, var, base, bname)
5019 struct action *act;
5020 char *p;
5021 int *var;
5022 int base;
5023 char *bname;
5025 int i = 0;
5026 int c;
5028 if (*p == 0)
5030 Msg(0, "%s: %s: empty argument.", rc_name, comms[act->nr].name);
5031 return -1;
5033 while ((c = *p++))
5035 if (c >= 'a' && c <= 'z')
5036 c -= 'a' - 'A';
5037 if (c >= 'A' && c <= 'Z')
5038 c -= 'A' - ('0' + 10);
5039 c -= '0';
5040 if (c < 0 || c >= base)
5042 Msg(0, "%s: %s: argument is not %s.", rc_name, comms[act->nr].name, bname);
5043 return -1;
5045 i = base * i + c;
5047 debug1("ParseBase got %d\n", i);
5048 *var = i;
5049 return 0;
5052 static int
5053 IsNum(s, base)
5054 register char *s;
5055 register int base;
5057 for (base += '0'; *s; ++s)
5058 if (*s < '0' || *s > base)
5059 return 0;
5060 return 1;
5064 IsNumColon(s, base, p, psize)
5065 int base, psize;
5066 char *s, *p;
5068 char *q;
5069 if ((q = rindex(s, ':')) != 0)
5071 strncpy(p, q + 1, psize - 1);
5072 p[psize - 1] = '\0';
5073 *q = '\0';
5075 else
5076 *p = '\0';
5077 return IsNum(s, base);
5080 void
5081 SwitchWindow(n)
5082 int n;
5084 struct win *p;
5086 debug1("SwitchWindow %d\n", n);
5087 if (n < 0 || n >= maxwin)
5089 ShowWindows(-1);
5090 return;
5092 if ((p = wtab[n]) == 0)
5094 ShowWindows(n);
5095 return;
5097 if (display == 0)
5099 fore = p;
5100 return;
5102 if (p == D_fore)
5104 Msg(0, "This IS window %d (%s).", n, p->w_title);
5105 return;
5107 #ifdef MULTIUSER
5108 if (AclCheckPermWin(D_user, ACL_READ, p))
5110 Msg(0, "Access to window %d denied.", p->w_number);
5111 return;
5113 #endif
5114 SetForeWindow(p);
5115 Activate(fore->w_norefresh);
5119 * SetForeWindow changes the window in the input focus of the display.
5120 * Puts window wi in canvas display->d_forecv.
5122 void
5123 SetForeWindow(wi)
5124 struct win *wi;
5126 struct win *p;
5127 if (display == 0)
5129 fore = wi;
5130 return;
5132 p = Layer2Window(D_forecv->c_layer);
5133 SetCanvasWindow(D_forecv, wi);
5134 if (p)
5135 WindowChanged(p, 'u');
5136 if (wi)
5137 WindowChanged(wi, 'u');
5138 flayer = D_forecv->c_layer;
5139 /* Activate called afterwards, so no RefreshHStatus needed */
5143 /*****************************************************************/
5146 * Activate - make fore window active
5147 * norefresh = -1 forces a refresh, disregard all_norefresh then.
5149 void
5150 Activate(norefresh)
5151 int norefresh;
5153 debug1("Activate(%d)\n", norefresh);
5154 if (display == 0)
5155 return;
5156 if (D_status)
5158 Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
5159 RemoveStatus();
5162 if (MayResizeLayer(D_forecv->c_layer))
5163 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, display);
5165 fore = D_fore;
5166 if (fore)
5168 /* XXX ? */
5169 if (fore->w_monitor != MON_OFF)
5170 fore->w_monitor = MON_ON;
5171 fore->w_bell = BELL_ON;
5172 WindowChanged(fore, 'f');
5174 #if 0
5175 if (ResizeDisplay(fore->w_width, fore->w_height))
5177 debug2("Cannot resize from (%d,%d)", D_width, D_height);
5178 debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height);
5179 DoResize(D_width, D_height);
5181 #endif
5183 Redisplay(norefresh + all_norefresh);
5187 static int
5188 NextWindow()
5190 register struct win **pp;
5191 int n = fore ? fore->w_number : maxwin;
5192 struct win *group = fore ? fore->w_group : 0;
5194 for (pp = fore ? wtab + n + 1 : wtab; pp != wtab + n; pp++)
5196 if (pp == wtab + maxwin)
5197 pp = wtab;
5198 if (*pp)
5200 if (!fore || group == (*pp)->w_group)
5201 break;
5204 if (pp == wtab + n)
5205 return -1;
5206 return pp - wtab;
5209 static int
5210 PreviousWindow()
5212 register struct win **pp;
5213 int n = fore ? fore->w_number : -1;
5214 struct win *group = fore ? fore->w_group : 0;
5216 for (pp = wtab + n - 1; pp != wtab + n; pp--)
5218 if (pp == wtab - 1)
5219 pp = wtab + maxwin - 1;
5220 if (*pp)
5222 if (!fore || group == (*pp)->w_group)
5223 break;
5226 if (pp == wtab + n)
5227 return -1;
5228 return pp - wtab;
5231 static int
5232 MoreWindows()
5234 char *m = "No other window.";
5235 if (windows && (fore == 0 || windows->w_next))
5236 return 1;
5237 if (fore == 0)
5239 Msg(0, "No window available");
5240 return 0;
5242 Msg(0, m, fore->w_number); /* other arg for nethack */
5243 return 0;
5246 void
5247 KillWindow(wi)
5248 struct win *wi;
5250 struct win **pp, *p;
5251 struct canvas *cv;
5252 int gotone;
5253 struct layout *lay;
5256 * Remove window from linked list.
5258 for (pp = &windows; (p = *pp); pp = &p->w_next)
5259 if (p == wi)
5260 break;
5261 ASSERT(p);
5262 *pp = p->w_next;
5263 wi->w_inlen = 0;
5264 wtab[wi->w_number] = 0;
5266 if (windows == 0)
5268 FreeWindow(wi);
5269 Finit(0);
5273 * switch to different window on all canvases
5275 for (display = displays; display; display = display->d_next)
5277 gotone = 0;
5278 for (cv = D_cvlist; cv; cv = cv->c_next)
5280 if (Layer2Window(cv->c_layer) != wi)
5281 continue;
5282 /* switch to other window */
5283 SetCanvasWindow(cv, FindNiceWindow(D_other, 0));
5284 gotone = 1;
5286 if (gotone)
5288 #ifdef ZMODEM
5289 if (wi->w_zdisplay == display)
5291 D_blocked = 0;
5292 D_readev.condpos = D_readev.condneg = 0;
5294 #endif
5295 Activate(-1);
5299 /* do the same for the layouts */
5300 for (lay = layouts; lay; lay = lay->lay_next)
5301 UpdateLayoutCanvas(&lay->lay_canvas, wi);
5303 FreeWindow(wi);
5304 WindowChanged((struct win *)0, 'w');
5305 WindowChanged((struct win *)0, 'W');
5306 WindowChanged((struct win *)0, 0);
5309 static void
5310 LogToggle(on)
5311 int on;
5313 char buf[1024];
5315 if ((fore->w_log != 0) == on)
5317 if (display && !*rc_name)
5318 Msg(0, "You are %s logging.", on ? "already" : "not");
5319 return;
5321 if (fore->w_log != 0)
5323 Msg(0, "Logfile \"%s\" closed.", fore->w_log->name);
5324 logfclose(fore->w_log);
5325 fore->w_log = 0;
5326 WindowChanged(fore, 'f');
5327 return;
5329 if (DoStartLog(fore, buf, sizeof(buf)))
5331 Msg(errno, "Error opening logfile \"%s\"", buf);
5332 return;
5334 if (ftell(fore->w_log->fp) == 0)
5335 Msg(0, "Creating logfile \"%s\".", fore->w_log->name);
5336 else
5337 Msg(0, "Appending to logfile \"%s\".", fore->w_log->name);
5338 WindowChanged(fore, 'f');
5341 char *
5342 AddWindows(buf, len, flags, where)
5343 char *buf;
5344 int len;
5345 int flags;
5346 int where;
5348 register char *s, *ss;
5349 register struct win **pp, *p;
5350 register char *cmd;
5351 int l;
5353 s = ss = buf;
5354 if ((flags & 8) && where < 0)
5356 *s = 0;
5357 return ss;
5359 for (pp = ((flags & 4) && where >= 0) ? wtab + where + 1: wtab; pp < wtab + maxwin; pp++)
5361 int rend = -1;
5362 if (pp - wtab == where && ss == buf)
5363 ss = s;
5364 if ((p = *pp) == 0)
5365 continue;
5366 if ((flags & 1) && display && p == D_fore)
5367 continue;
5368 if (display && D_fore && D_fore->w_group != p->w_group)
5369 continue;
5371 cmd = p->w_title;
5372 l = strlen(cmd);
5373 if (l > 20)
5374 l = 20;
5375 if (s - buf + l > len - 24)
5376 break;
5377 if (s > buf || (flags & 4))
5379 *s++ = ' ';
5380 *s++ = ' ';
5382 if (p->w_number == where)
5384 ss = s;
5385 if (flags & 8)
5386 break;
5388 if (!(flags & 4) || where < 0 || ((flags & 4) && where < p->w_number))
5390 if (p->w_monitor == MON_DONE && renditions[REND_MONITOR] != -1)
5391 rend = renditions[REND_MONITOR];
5392 else if ((p->w_bell == BELL_DONE || p->w_bell == BELL_FOUND) && renditions[REND_BELL] != -1)
5393 rend = renditions[REND_BELL];
5394 else if ((p->w_silence == SILENCE_FOUND || p->w_silence == SILENCE_DONE) && renditions[REND_SILENCE] != -1)
5395 rend = renditions[REND_SILENCE];
5397 if (rend != -1)
5398 AddWinMsgRend(s, rend);
5399 sprintf(s, "%d", p->w_number);
5400 s += strlen(s);
5401 if (display && p == D_fore)
5402 *s++ = '*';
5403 if (!(flags & 2))
5405 if (display && p == D_other)
5406 *s++ = '-';
5407 s = AddWindowFlags(s, len, p);
5409 *s++ = ' ';
5410 strncpy(s, cmd, l);
5411 s += l;
5412 if (rend != -1)
5413 AddWinMsgRend(s, -1);
5415 *s = 0;
5416 return ss;
5419 char *
5420 AddWindowFlags(buf, len, p)
5421 char *buf;
5422 int len;
5423 struct win *p;
5425 char *s = buf;
5426 if (p == 0 || len < 12)
5428 *s = 0;
5429 return s;
5431 #if 0
5432 if (display && p == D_fore)
5433 *s++ = '*';
5434 if (display && p == D_other)
5435 *s++ = '-';
5436 #endif
5437 if (p->w_layer.l_cvlist && p->w_layer.l_cvlist->c_lnext)
5438 *s++ = '&';
5439 if (p->w_monitor == MON_DONE
5440 #ifdef MULTIUSER
5441 && (ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))
5442 #endif
5444 *s++ = '@';
5445 if (p->w_bell == BELL_DONE)
5446 *s++ = '!';
5447 #ifdef UTMPOK
5448 if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1)
5449 *s++ = '$';
5450 #endif
5451 if (p->w_log != 0)
5453 strcpy(s, "(L)");
5454 s += 3;
5456 if (p->w_ptyfd < 0 && p->w_type != W_TYPE_GROUP)
5457 *s++ = 'Z';
5458 *s = 0;
5459 return s;
5462 char *
5463 AddOtherUsers(buf, len, p)
5464 char *buf;
5465 int len;
5466 struct win *p;
5468 struct display *d, *olddisplay = display;
5469 struct canvas *cv;
5470 char *s;
5471 int l;
5473 s = buf;
5474 for (display = displays; display; display = display->d_next)
5476 if (olddisplay && D_user == olddisplay->d_user)
5477 continue;
5478 for (cv = D_cvlist; cv; cv = cv->c_next)
5479 if (Layer2Window(cv->c_layer) == p)
5480 break;
5481 if (!cv)
5482 continue;
5483 for (d = displays; d && d != display; d = d->d_next)
5484 if (D_user == d->d_user)
5485 break;
5486 if (d && d != display)
5487 continue;
5488 if (len > 1 && s != buf)
5490 *s++ = ',';
5491 len--;
5493 l = strlen(D_user->u_name);
5494 if (l + 1 > len)
5495 break;
5496 strcpy(s, D_user->u_name);
5497 s += l;
5498 len -= l;
5500 *s = 0;
5501 display = olddisplay;
5502 return s;
5505 void
5506 ShowWindows(where)
5507 int where;
5509 char buf[1024];
5510 char *s, *ss;
5512 if (display && where == -1 && D_fore)
5513 where = D_fore->w_number;
5514 ss = AddWindows(buf, sizeof(buf), 0, where);
5515 s = buf + strlen(buf);
5516 if (display && ss - buf > D_width / 2)
5518 ss -= D_width / 2;
5519 if (s - ss < D_width)
5521 ss = s - D_width;
5522 if (ss < buf)
5523 ss = buf;
5526 else
5527 ss = buf;
5528 Msg(0, "%s", ss);
5531 static void
5532 ShowInfo()
5534 char buf[512], *p;
5535 register struct win *wp = fore;
5536 register int i;
5538 if (wp == 0)
5540 Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height);
5541 return;
5543 p = buf;
5544 if (buf < (p += GetAnsiStatus(wp, p)))
5545 *p++ = ' ';
5546 sprintf(p, "(%d,%d)/(%d,%d)",
5547 wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height);
5548 #ifdef COPY_PASTE
5549 sprintf(p += strlen(p), "+%d", wp->w_histheight);
5550 #endif
5551 sprintf(p += strlen(p), " %c%sflow",
5552 (wp->w_flow & FLOW_NOW) ? '+' : '-',
5553 (wp->w_flow & FLOW_AUTOFLAG) ? "" :
5554 ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)"));
5555 if (!wp->w_wrap) sprintf(p += strlen(p), " -wrap");
5556 if (wp->w_insert) sprintf(p += strlen(p), " ins");
5557 if (wp->w_origin) sprintf(p += strlen(p), " org");
5558 if (wp->w_keypad) sprintf(p += strlen(p), " app");
5559 if (wp->w_log) sprintf(p += strlen(p), " log");
5560 if (wp->w_monitor != MON_OFF
5561 #ifdef MULTIUSER
5562 && (ACLBYTE(wp->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))
5563 #endif
5565 sprintf(p += strlen(p), " mon");
5566 if (wp->w_mouse) sprintf(p += strlen(p), " mouse");
5567 #ifdef COLOR
5568 if (wp->w_bce) sprintf(p += strlen(p), " bce");
5569 #endif
5570 if (!wp->w_c1) sprintf(p += strlen(p), " -c1");
5571 if (wp->w_norefresh) sprintf(p += strlen(p), " nored");
5573 p += strlen(p);
5574 #ifdef FONT
5575 # ifdef ENCODINGS
5576 if (wp->w_encoding && (display == 0 || D_encoding != wp->w_encoding || EncodingDefFont(wp->w_encoding) <= 0))
5578 *p++ = ' ';
5579 strcpy(p, EncodingName(wp->w_encoding));
5580 p += strlen(p);
5582 # ifdef UTF8
5583 if (wp->w_encoding != UTF8)
5584 # endif
5585 # endif
5586 if (D_CC0 || (D_CS0 && *D_CS0))
5588 if (wp->w_gr == 2)
5590 sprintf(p, " G%c", wp->w_Charset + '0');
5591 if (wp->w_FontE >= ' ')
5592 p[3] = wp->w_FontE;
5593 else
5595 p[3] = '^';
5596 p[4] = wp->w_FontE ^ 0x40;
5597 p++;
5599 p[4] = '[';
5600 p++;
5602 else if (wp->w_gr)
5603 sprintf(p++, " G%c%c[", wp->w_Charset + '0', wp->w_CharsetR + '0');
5604 else
5605 sprintf(p, " G%c[", wp->w_Charset + '0');
5606 p += 4;
5607 for (i = 0; i < 4; i++)
5609 if (wp->w_charsets[i] == ASCII)
5610 *p++ = 'B';
5611 else if (wp->w_charsets[i] >= ' ')
5612 *p++ = wp->w_charsets[i];
5613 else
5615 *p++ = '^';
5616 *p++ = wp->w_charsets[i] ^ 0x40;
5619 *p++ = ']';
5620 *p = 0;
5622 #endif
5624 if (wp->w_type == W_TYPE_PLAIN)
5626 /* add info about modem control lines */
5627 *p++ = ' ';
5628 TtyGetModemStatus(wp->w_ptyfd, p);
5630 #ifdef BUILTIN_TELNET
5631 else if (wp->w_type == W_TYPE_TELNET)
5633 *p++ = ' ';
5634 TelStatus(wp, p, sizeof(buf) - 1 - (p - buf));
5636 #endif
5637 Msg(0, "%s %d(%s)", buf, wp->w_number, wp->w_title);
5640 static void
5641 ShowDInfo()
5643 char buf[512], *p;
5644 if (display == 0)
5645 return;
5646 p = buf;
5647 sprintf(p, "(%d,%d)", D_width, D_height),
5648 p += strlen(p);
5649 #ifdef ENCODINGS
5650 if (D_encoding)
5652 *p++ = ' ';
5653 strcpy(p, EncodingName(D_encoding));
5654 p += strlen(p);
5656 #endif
5657 if (D_CXT)
5659 strcpy(p, " xterm");
5660 p += strlen(p);
5662 #ifdef COLOR
5663 if (D_hascolor)
5665 strcpy(p, " color");
5666 p += strlen(p);
5668 #endif
5669 #ifdef FONT
5670 if (D_CG0)
5672 strcpy(p, " iso2022");
5673 p += strlen(p);
5675 else if (D_CS0 && *D_CS0)
5677 strcpy(p, " altchar");
5678 p += strlen(p);
5680 #endif
5681 Msg(0, "%s", buf);
5684 static void
5685 AKAfin(buf, len, data)
5686 char *buf;
5687 int len;
5688 char *data; /* dummy */
5690 ASSERT(display);
5691 if (len && fore)
5692 ChangeAKA(fore, buf, strlen(buf));
5695 static void
5696 InputAKA()
5698 char *s, *ss;
5699 int n;
5700 Input("Set window's title to: ", sizeof(fore->w_akabuf) - 1, INP_COOKED, AKAfin, NULL, 0);
5701 s = fore->w_title;
5702 if (!s)
5703 return;
5704 for (; *s; s++)
5706 if ((*(unsigned char *)s & 0x7f) < 0x20 || *s == 0x7f)
5707 continue;
5708 ss = s;
5709 n = 1;
5710 LayProcess(&ss, &n);
5714 static void
5715 Colonfin(buf, len, data)
5716 char *buf;
5717 int len;
5718 char *data; /* dummy */
5720 char mbuf[256];
5722 RemoveStatus();
5723 if (buf[len] == '\t')
5725 int m, x;
5726 int l = 0, r = RC_LAST;
5727 int showmessage = 0;
5728 char *s = buf;
5730 while (*s && s - buf < len)
5731 if (*s++ == ' ')
5732 return;
5734 /* Showing a message when there's no hardstatus or caption cancels the input */
5735 if (display &&
5736 (captionalways || D_has_hstatus == HSTATUS_LASTLINE || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext)))
5737 showmessage = 1;
5739 while (l <= r)
5741 m = (l + r) / 2;
5742 x = strncmp(buf, comms[m].name, len);
5743 if (x > 0)
5744 l = m + 1;
5745 else if (x < 0)
5746 r = m - 1;
5747 else
5749 s = mbuf;
5750 for (l = m - 1; l >= 0 && strncmp(buf, comms[l].name, len) == 0; l--)
5752 for (m = ++l; m <= r && strncmp(buf, comms[m].name, len) == 0 && s - mbuf < sizeof(mbuf); m++)
5753 s += snprintf(s, sizeof(mbuf) - (s - mbuf), " %s", comms[m].name);
5754 if (l < m - 1)
5756 if (showmessage)
5757 Msg(0, "Possible commands:%s", mbuf);
5759 else
5761 s = mbuf;
5762 len = snprintf(mbuf, sizeof(mbuf), "%s \t", comms[l].name + len);
5763 if (len > 0 && len < sizeof(mbuf))
5764 LayProcess(&s, &len);
5766 break;
5769 if (l > r && showmessage)
5770 Msg(0, "No commands matching '%*s'", len, buf);
5771 return;
5774 if (!len || buf[len])
5775 return;
5777 len = strlen(buf) + 1;
5778 if (len > (int)sizeof(mbuf))
5779 RcLine(buf, len);
5780 else
5782 bcopy(buf, mbuf, len);
5783 RcLine(mbuf, sizeof mbuf);
5787 static void
5788 SelectFin(buf, len, data)
5789 char *buf;
5790 int len;
5791 char *data; /* dummy */
5793 int n;
5795 if (!len || !display)
5796 return;
5797 if (len == 1 && *buf == '-')
5799 SetForeWindow((struct win *)0);
5800 Activate(0);
5801 return;
5803 if ((n = WindowByNoN(buf)) < 0)
5804 return;
5805 SwitchWindow(n);
5808 static void
5809 SelectLayoutFin(buf, len, data)
5810 char *buf;
5811 int len;
5812 char *data; /* dummy */
5814 struct layout *lay;
5816 if (!len || !display)
5817 return;
5818 if (len == 1 && *buf == '-')
5820 LoadLayout((struct layout *)0, (struct canvas *)0);
5821 Activate(0);
5822 return;
5824 lay = FindLayout(buf);
5825 if (!lay)
5826 Msg(0, "No such layout\n");
5827 else if (lay == D_layout)
5828 Msg(0, "This IS layout %d (%s).\n", lay->lay_number, lay->lay_title);
5829 else
5831 LoadLayout(lay, &D_canvas);
5832 Activate(0);
5837 static void
5838 InputSelect()
5840 Input("Switch to window: ", 20, INP_COOKED, SelectFin, NULL, 0);
5843 static char setenv_var[31];
5846 static void
5847 SetenvFin1(buf, len, data)
5848 char *buf;
5849 int len;
5850 char *data; /* dummy */
5852 if (!len || !display)
5853 return;
5854 InputSetenv(buf);
5857 static void
5858 SetenvFin2(buf, len, data)
5859 char *buf;
5860 int len;
5861 char *data; /* dummy */
5863 if (!len || !display)
5864 return;
5865 debug2("SetenvFin2: setenv '%s' '%s'\n", setenv_var, buf);
5866 xsetenv(setenv_var, buf);
5867 MakeNewEnv();
5870 static void
5871 InputSetenv(arg)
5872 char *arg;
5874 static char setenv_buf[50 + sizeof(setenv_var)]; /* need to be static here, cannot be freed */
5876 if (arg)
5878 strncpy(setenv_var, arg, sizeof(setenv_var) - 1);
5879 sprintf(setenv_buf, "Enter value for %s: ", setenv_var);
5880 Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL, 0);
5882 else
5883 Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL, 0);
5887 * the following options are understood by this parser:
5888 * -f, -f0, -f1, -fy, -fa
5889 * -t title, -T terminal-type, -h height-of-scrollback,
5890 * -ln, -l0, -ly, -l1, -l
5891 * -a, -M, -L
5893 void
5894 DoScreen(fn, av)
5895 char *fn, **av;
5897 struct NewWindow nwin;
5898 register int num;
5899 char buf[20];
5901 nwin = nwin_undef;
5902 while (av && *av && av[0][0] == '-')
5904 if (av[0][1] == '-')
5906 av++;
5907 break;
5909 switch (av[0][1])
5911 case 'f':
5912 switch (av[0][2])
5914 case 'n':
5915 case '0':
5916 nwin.flowflag = FLOW_NOW * 0;
5917 break;
5918 case 'y':
5919 case '1':
5920 case '\0':
5921 nwin.flowflag = FLOW_NOW * 1;
5922 break;
5923 case 'a':
5924 nwin.flowflag = FLOW_AUTOFLAG;
5925 break;
5926 default:
5927 break;
5929 break;
5930 case 't': /* no more -k */
5931 if (av[0][2])
5932 nwin.aka = &av[0][2];
5933 else if (*++av)
5934 nwin.aka = *av;
5935 else
5936 --av;
5937 break;
5938 case 'T':
5939 if (av[0][2])
5940 nwin.term = &av[0][2];
5941 else if (*++av)
5942 nwin.term = *av;
5943 else
5944 --av;
5945 break;
5946 case 'h':
5947 if (av[0][2])
5948 nwin.histheight = atoi(av[0] + 2);
5949 else if (*++av)
5950 nwin.histheight = atoi(*av);
5951 else
5952 --av;
5953 break;
5954 #ifdef LOGOUTOK
5955 case 'l':
5956 switch (av[0][2])
5958 case 'n':
5959 case '0':
5960 nwin.lflag = 0;
5961 break;
5962 case 'y':
5963 case '1':
5964 case '\0':
5965 nwin.lflag = 1;
5966 break;
5967 case 'a':
5968 nwin.lflag = 3;
5969 break;
5970 default:
5971 break;
5973 break;
5974 #endif
5975 case 'a':
5976 nwin.aflag = 1;
5977 break;
5978 case 'M':
5979 nwin.monitor = MON_ON;
5980 break;
5981 case 'L':
5982 nwin.Lflag = 1;
5983 break;
5984 default:
5985 Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
5986 break;
5988 ++av;
5990 num = 0;
5991 if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
5993 if (*buf != '\0')
5994 nwin.aka = buf;
5995 num = atoi(*av);
5996 if (num < 0 || (maxwin && num > maxwin - 1) || (!maxwin && num > MAXWIN - 1))
5998 Msg(0, "%s: illegal screen number %d.", fn, num);
5999 num = 0;
6001 nwin.StartAt = num;
6002 ++av;
6004 if (av && *av)
6006 nwin.args = av;
6007 if (!nwin.aka)
6008 nwin.aka = Filename(*av);
6010 MakeWindow(&nwin);
6013 #ifdef COPY_PASTE
6015 * CompileKeys must be called before Markroutine is first used.
6016 * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
6018 * s is an ascii string in a termcap-like syntax. It looks like
6019 * "j=u:k=d:l=r:h=l: =.:" and so on...
6020 * this example rebinds the cursormovement to the keys u (up), d (down),
6021 * l (left), r (right). placing a mark will now be done with ".".
6024 CompileKeys(s, sl, array)
6025 char *s;
6026 int sl;
6027 unsigned char *array;
6029 int i;
6030 unsigned char key, value;
6032 if (sl == 0)
6034 for (i = 0; i < 256; i++)
6035 array[i] = i;
6036 return 0;
6038 debug1("CompileKeys: '%s'\n", s);
6039 while (sl)
6041 key = *(unsigned char *)s++;
6042 if (*s != '=' || sl < 3)
6043 return -1;
6044 sl--;
6047 s++;
6048 sl -= 2;
6049 value = *(unsigned char *)s++;
6050 array[value] = key;
6052 while (*s == '=' && sl >= 2);
6053 if (sl == 0)
6054 break;
6055 if (*s++ != ':')
6056 return -1;
6057 sl--;
6059 return 0;
6061 #endif /* COPY_PASTE */
6064 * Asynchronous input functions
6067 #if defined(DETACH) && defined(POW_DETACH)
6068 static void
6069 pow_detach_fn(buf, len, data)
6070 char *buf;
6071 int len;
6072 char *data; /* dummy */
6074 debug("pow_detach_fn called\n");
6075 if (len)
6077 *buf = 0;
6078 return;
6080 if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH)
6082 if (display)
6083 write(D_userfd, "\007", 1);
6084 Msg(0, "Detach aborted.");
6086 else
6087 Detach(D_POWER);
6089 #endif /* POW_DETACH */
6091 #ifdef COPY_PASTE
6092 static void
6093 copy_reg_fn(buf, len, data)
6094 char *buf;
6095 int len;
6096 char *data; /* dummy */
6098 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6100 if (len)
6102 *buf = 0;
6103 return;
6105 if (pp->buf)
6106 free(pp->buf);
6107 pp->buf = 0;
6108 pp->len = 0;
6109 if (D_user->u_plop.len)
6111 if ((pp->buf = (char *)malloc(D_user->u_plop.len)) == NULL)
6113 Msg(0, "%s", strnomem);
6114 return;
6116 bcopy(D_user->u_plop.buf, pp->buf, D_user->u_plop.len);
6118 pp->len = D_user->u_plop.len;
6119 #ifdef ENCODINGS
6120 pp->enc = D_user->u_plop.enc;
6121 #endif
6122 Msg(0, "Copied %d characters into register %c", D_user->u_plop.len, *buf);
6125 static void
6126 ins_reg_fn(buf, len, data)
6127 char *buf;
6128 int len;
6129 char *data; /* dummy */
6131 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6133 if (len)
6135 *buf = 0;
6136 return;
6138 if (!fore)
6139 return; /* Input() should not call us w/o fore, but you never know... */
6140 if (*buf == '.')
6141 Msg(0, "ins_reg_fn: Warning: pasting real register '.'!");
6142 if (pp->buf)
6144 MakePaster(&fore->w_paster, pp->buf, pp->len, 0);
6145 return;
6147 Msg(0, "Empty register.");
6149 #endif /* COPY_PASTE */
6151 static void
6152 process_fn(buf, len, data)
6153 char *buf;
6154 int len;
6155 char *data; /* dummy */
6157 struct plop *pp = plop_tab + (int)(unsigned char)*buf;
6159 if (len)
6161 *buf = 0;
6162 return;
6164 if (pp->buf)
6166 ProcessInput(pp->buf, pp->len);
6167 return;
6169 Msg(0, "Empty register.");
6172 static void
6173 confirm_fn(buf, len, data)
6174 char *buf;
6175 int len;
6176 char *data;
6178 struct action act;
6180 if (len || (*buf != 'y' && *buf != 'Y'))
6182 *buf = 0;
6183 return;
6185 act.nr = *(int *)data;
6186 act.args = noargs;
6187 act.argl = 0;
6188 act.quiet = 0;
6189 DoAction(&act, -1);
6192 #ifdef MULTIUSER
6193 struct inputsu
6195 struct acluser **up;
6196 char name[24];
6197 char pw1[130]; /* FreeBSD crypts to 128 bytes */
6198 char pw2[130];
6201 static void
6202 su_fin(buf, len, data)
6203 char *buf;
6204 int len;
6205 char *data;
6207 struct inputsu *i = (struct inputsu *)data;
6208 char *p;
6209 int l;
6211 if (!*i->name)
6212 { p = i->name; l = sizeof(i->name) - 1; }
6213 else if (!*i->pw1)
6214 { strcpy(p = i->pw1, "\377"); l = sizeof(i->pw1) - 1; }
6215 else
6216 { strcpy(p = i->pw2, "\377"); l = sizeof(i->pw2) - 1; }
6217 if (buf && len)
6218 strncpy(p, buf, 1 + (l < len) ? l : len);
6219 if (!*i->name)
6220 Input("Screen User: ", sizeof(i->name) - 1, INP_COOKED, su_fin, (char *)i, 0);
6221 else if (!*i->pw1)
6222 Input("User's UNIX Password: ", sizeof(i->pw1)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0);
6223 else if (!*i->pw2)
6224 Input("User's Screen Password: ", sizeof(i->pw2)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0);
6225 else
6227 if ((p = DoSu(i->up, i->name, i->pw2, i->pw1)))
6228 Msg(0, "%s", p);
6229 free((char *)i);
6233 static int
6234 InputSu(w, up, name)
6235 struct win *w;
6236 struct acluser **up;
6237 char *name;
6239 struct inputsu *i;
6241 if (!(i = (struct inputsu *)calloc(1, sizeof(struct inputsu))))
6242 return -1;
6244 i->up = up;
6245 if (name && *name)
6246 su_fin(name, (int)strlen(name), (char *)i); /* can also initialise stuff */
6247 else
6248 su_fin((char *)0, 0, (char *)i);
6249 return 0;
6251 #endif /* MULTIUSER */
6253 #ifdef PASSWORD
6255 static void
6256 pass1(buf, len, data)
6257 char *buf;
6258 int len;
6259 char *data;
6261 struct acluser *u = (struct acluser *)data;
6263 if (!*buf)
6264 return;
6265 ASSERT(u);
6266 if (u->u_password != NullStr)
6267 free((char *)u->u_password);
6268 u->u_password = SaveStr(buf);
6269 bzero(buf, strlen(buf));
6270 Input("Retype new password:", 100, INP_NOECHO, pass2, data, 0);
6273 static void
6274 pass2(buf, len, data)
6275 char *buf;
6276 int len;
6277 char *data;
6279 int st;
6280 char salt[3];
6281 struct acluser *u = (struct acluser *)data;
6283 ASSERT(u);
6284 if (!buf || strcmp(u->u_password, buf))
6286 Msg(0, "[ Passwords don't match - checking turned off ]");
6287 if (u->u_password != NullStr)
6289 bzero(u->u_password, strlen(u->u_password));
6290 free((char *)u->u_password);
6292 u->u_password = NullStr;
6294 else if (u->u_password[0] == '\0')
6296 Msg(0, "[ No password - no secure ]");
6297 if (buf)
6298 bzero(buf, strlen(buf));
6301 if (u->u_password != NullStr)
6303 for (st = 0; st < 2; st++)
6304 salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26);
6305 salt[2] = 0;
6306 buf = crypt(u->u_password, salt);
6307 bzero(u->u_password, strlen(u->u_password));
6308 free((char *)u->u_password);
6309 u->u_password = SaveStr(buf);
6310 bzero(buf, strlen(buf));
6311 #ifdef COPY_PASTE
6312 if (u->u_plop.buf)
6313 UserFreeCopyBuffer(u);
6314 u->u_plop.len = strlen(u->u_password);
6315 # ifdef ENCODINGS
6316 u->u_plop.enc = 0;
6317 #endif
6318 if (!(u->u_plop.buf = SaveStr(u->u_password)))
6320 Msg(0, "%s", strnomem);
6321 D_user->u_plop.len = 0;
6323 else
6324 Msg(0, "[ Password moved into copybuffer ]");
6325 #else /* COPY_PASTE */
6326 Msg(0, "[ Crypted password is \"%s\" ]", u->u_password);
6327 #endif /* COPY_PASTE */
6330 #endif /* PASSWORD */
6332 static int
6333 digraph_find(buf)
6334 const char *buf;
6336 int i;
6337 for (i = 0; i < MAX_DIGRAPH && digraphs[i].d[0]; i++)
6338 if ((digraphs[i].d[0] == (unsigned char)buf[0] && digraphs[i].d[1] == (unsigned char)buf[1]) ||
6339 (digraphs[i].d[0] == (unsigned char)buf[1] && digraphs[i].d[1] == (unsigned char)buf[0]))
6340 break;
6341 return i;
6344 static void
6345 digraph_fn(buf, len, data)
6346 char *buf;
6347 int len;
6348 char *data; /* dummy */
6350 int ch, i, x;
6352 ch = buf[len];
6353 if (ch)
6355 buf[len + 1] = ch; /* so we can restore it later */
6356 if (ch < ' ' || ch == '\177')
6357 return;
6358 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))))
6360 if (len == 1)
6361 return;
6362 if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F'))
6364 buf[len] = '\034'; /* ^] is ignored by Input() */
6365 return;
6367 if (len == (*buf == 'U' ? 5 : 3))
6368 buf[len] = '\n';
6369 return;
6371 if (len && *buf == '0')
6373 if (ch < '0' || ch > '7')
6375 buf[len] = '\034'; /* ^] is ignored by Input() */
6376 return;
6378 if (len == 3)
6379 buf[len] = '\n';
6380 return;
6382 if (len == 1)
6383 buf[len] = '\n';
6384 return;
6386 if (len < 1)
6387 return;
6388 if (buf[len + 1])
6390 buf[len] = buf[len + 1]; /* stored above */
6391 len++;
6393 if (len < 2)
6394 return;
6395 if (!parse_input_int(buf, len, &x))
6397 i = digraph_find(buf);
6398 if ((x = digraphs[i].value) <= 0)
6400 Msg(0, "Unknown digraph");
6401 return;
6404 i = 1;
6405 *buf = x;
6406 #ifdef UTF8
6407 if (flayer->l_encoding == UTF8)
6408 i = ToUtf8(buf, x); /* buf is big enough for all UTF-8 codes */
6409 #endif
6410 while(i)
6411 LayProcess(&buf, &i);
6414 #ifdef MAPKEYS
6416 StuffKey(i)
6417 int i;
6419 struct action *act;
6420 int discard = 0;
6422 debug1("StuffKey #%d", i);
6423 #ifdef DEBUG
6424 if (i < KMAP_KEYS)
6425 debug1(" - %s", term[i + T_CAPS].tcname);
6426 #endif
6428 if (i < KMAP_KEYS && D_ESCseen)
6430 struct action *act = &D_ESCseen[i + 256];
6431 if (act->nr != RC_ILLEGAL)
6433 D_ESCseen = 0;
6434 DoAction(act, i + 256);
6435 return 0;
6437 discard = 1;
6440 if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys)
6441 i += T_OCAPS - T_CURSOR;
6442 else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad)
6443 i += T_OCAPS - T_CURSOR;
6444 debug1(" - action %d\n", i);
6445 flayer = D_forecv->c_layer;
6446 fore = D_fore;
6447 act = 0;
6448 #ifdef COPY_PASTE
6449 if (flayer && flayer->l_mode == 1)
6450 act = i < KMAP_KEYS+KMAP_AKEYS ? &mmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].mm;
6451 #endif
6452 if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault)
6453 act = i < KMAP_KEYS+KMAP_AKEYS ? &umtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].um;
6454 if (!act || act->nr == RC_ILLEGAL)
6455 act = i < KMAP_KEYS+KMAP_AKEYS ? &dmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].dm;
6457 if (discard && (!act || act->nr != RC_COMMAND))
6459 D_ESCseen = 0;
6460 return 0;
6462 D_mapdefault = 0;
6464 if (act == 0 || act->nr == RC_ILLEGAL)
6465 return -1;
6466 DoAction(act, 0);
6467 return 0;
6469 #endif
6472 static int
6473 IsOnDisplay(wi)
6474 struct win *wi;
6476 struct canvas *cv;
6477 ASSERT(display);
6478 for (cv = D_cvlist; cv; cv = cv->c_next)
6479 if (Layer2Window(cv->c_layer) == wi)
6480 return 1;
6481 return 0;
6484 struct win *
6485 FindNiceWindow(wi, presel)
6486 struct win *wi;
6487 char *presel;
6489 int i;
6491 debug2("FindNiceWindow %d %s\n", wi ? wi->w_number : -1 , presel ? presel : "NULL");
6492 if (presel)
6494 i = WindowByNoN(presel);
6495 if (i >= 0)
6496 wi = wtab[i];
6498 if (!display)
6499 return wi;
6500 #ifdef MULTIUSER
6501 if (wi && AclCheckPermWin(D_user, ACL_READ, wi))
6502 wi = 0;
6503 #endif
6504 if (!wi || (IsOnDisplay(wi) && !presel))
6506 /* try to get another window */
6507 wi = 0;
6508 #ifdef MULTIUSER
6509 for (wi = windows; wi; wi = wi->w_next)
6510 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_WRITE, wi))
6511 break;
6512 if (!wi)
6513 for (wi = windows; wi; wi = wi->w_next)
6514 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_WRITE, wi))
6515 break;
6516 if (!wi)
6517 for (wi = windows; wi; wi = wi->w_next)
6518 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_READ, wi))
6519 break;
6520 if (!wi)
6521 for (wi = windows; wi; wi = wi->w_next)
6522 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_READ, wi))
6523 break;
6524 #endif
6525 if (!wi)
6526 for (wi = windows; wi; wi = wi->w_next)
6527 if (!wi->w_layer.l_cvlist)
6528 break;
6529 if (!wi)
6530 for (wi = windows; wi; wi = wi->w_next)
6531 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi))
6532 break;
6534 #ifdef MULTIUSER
6535 if (wi && AclCheckPermWin(D_user, ACL_READ, wi))
6536 wi = 0;
6537 #endif
6538 return wi;
6541 #if 0
6543 /* sorted list of all commands */
6544 static struct comm **commtab;
6545 static int ncommtab;
6547 void
6548 AddComms(cos, hand)
6549 struct comm *cos;
6550 void (*hand) __P((struct comm *, char **, int));
6552 int n, i, j, r;
6553 for (n = 0; cos[n].name; n++)
6555 if (n == 0)
6556 return;
6557 if (commtab)
6558 commtab = (struct commt *)realloc(commtab, sizeof(*commtab) * (ncommtab + n));
6559 else
6560 commtab = (struct commt *)malloc(sizeof(*commtab) * (ncommtab + n));
6561 if (!commtab)
6562 Panic(0, strnomem);
6563 for (i = 0; i < n; i++)
6565 for (j = 0; j < ncommtab; j++)
6567 r = strcmp(cos[i].name, commtab[j]->name);
6568 if (r == 0)
6569 Panic(0, "Duplicate command: %s\n", cos[i].name);
6570 if (r < 0)
6571 break;
6573 for (r = ncommtab; r > j; r--)
6574 commtab[r] = commtab[r - 1];
6575 commtab[j] = cos + i;
6576 cos[i].handler = hand;
6577 bzero(cos[i].userbits, sizeof(cos[i].userbits));
6578 ncommtab++;
6582 struct comm *
6583 FindComm(str)
6584 char *str;
6586 int x, m, l = 0, r = ncommtab - 1;
6587 while (l <= r)
6589 m = (l + r) / 2;
6590 x = strcmp(str, commtab[m]->name);
6591 if (x > 0)
6592 l = m + 1;
6593 else if (x < 0)
6594 r = m - 1;
6595 else
6596 return commtab[m];
6598 return 0;
6601 #endif
6603 static int
6604 CalcSlicePercent(cv, percent)
6605 struct canvas *cv;
6606 int percent;
6608 int w, wsum, up;
6609 if (!cv || !cv->c_slback)
6610 return percent;
6611 up = CalcSlicePercent(cv->c_slback->c_slback, percent);
6612 w = cv->c_slweight;
6613 for (cv = cv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext)
6614 wsum += cv->c_slweight;
6615 if (wsum == 0)
6616 return 0;
6617 return (up * w) / wsum;
6620 static int
6621 ChangeCanvasSize(fcv, abs, diff, gflag, percent)
6622 struct canvas *fcv; /* make this canvas bigger */
6623 int abs; /* mode: 0:rel 1:abs 2:max */
6624 int diff; /* change this much */
6625 int gflag; /* go up if neccessary */
6626 int percent;
6628 struct canvas *cv;
6629 int done, have, m, dir;
6631 debug3("ChangeCanvasSize abs %d diff %d percent=%d\n", abs, diff, percent);
6632 if (abs == 0 && diff == 0)
6633 return 0;
6634 if (abs == 2)
6636 if (diff == 0)
6637 fcv->c_slweight = 0;
6638 else
6640 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6641 cv->c_slweight = 0;
6642 fcv->c_slweight = 1;
6643 cv = fcv->c_slback->c_slback;
6644 if (gflag && cv && cv->c_slback)
6645 ChangeCanvasSize(cv, abs, diff, gflag, percent);
6647 return diff;
6649 if (abs)
6651 if (diff < 0)
6652 diff = 0;
6653 if (percent && diff > percent)
6654 diff = percent;
6656 if (percent)
6658 int wsum, up;
6659 for (cv = fcv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext)
6660 wsum += cv->c_slweight;
6661 if (wsum)
6663 up = gflag ? CalcSlicePercent(fcv->c_slback->c_slback, percent) : percent;
6664 debug3("up=%d, wsum=%d percent=%d\n", up, wsum, percent);
6665 if (wsum < 1000)
6667 int scale = wsum < 10 ? 1000 : 100;
6668 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6669 cv->c_slweight *= scale;
6670 wsum *= scale;
6671 debug1("scaled wsum to %d\n", wsum);
6673 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6675 if (cv->c_slweight)
6677 cv->c_slweight = (cv->c_slweight * up) / percent;
6678 if (cv->c_slweight == 0)
6679 cv->c_slweight = 1;
6681 debug1(" - weight %d\n", cv->c_slweight);
6683 diff = (diff * wsum) / percent;
6684 percent = wsum;
6687 else
6689 if (abs && diff == (fcv->c_slorient == SLICE_VERT ? fcv->c_ye - fcv->c_ys + 2 : fcv->c_xe - fcv->c_xs + 2))
6690 return 0;
6691 /* fix weights to real size (can't be helped, sorry) */
6692 for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext)
6694 cv->c_slweight = cv->c_slorient == SLICE_VERT ? cv->c_ye - cv->c_ys + 2 : cv->c_xe - cv->c_xs + 2;
6695 debug1(" - weight %d\n", cv->c_slweight);
6698 if (abs)
6699 diff = diff - fcv->c_slweight;
6700 debug1("diff = %d\n", diff);
6701 if (diff == 0)
6702 return 0;
6703 if (diff < 0)
6705 cv = fcv->c_slnext ? fcv->c_slnext : fcv->c_slprev;
6706 fcv->c_slweight += diff;
6707 cv->c_slweight -= diff;
6708 return diff;
6710 done = 0;
6711 dir = 1;
6712 for (cv = fcv->c_slnext; diff > 0; cv = dir > 0 ? cv->c_slnext : cv->c_slprev)
6714 if (!cv)
6716 debug1("reached end, dir is %d\n", dir);
6717 if (dir == -1)
6718 break;
6719 dir = -1;
6720 cv = fcv;
6721 continue;
6723 if (percent)
6724 m = 1;
6725 else
6726 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 : 2;
6727 debug2("min is %d, have %d\n", m, cv->c_slweight);
6728 if (cv->c_slweight > m)
6730 have = cv->c_slweight - m;
6731 if (have > diff)
6732 have = diff;
6733 debug1("subtract %d\n", have);
6734 cv->c_slweight -= have;
6735 done += have;
6736 diff -= have;
6739 if (diff && gflag)
6741 /* need more room! */
6742 cv = fcv->c_slback->c_slback;
6743 if (cv && cv->c_slback)
6744 done += ChangeCanvasSize(fcv->c_slback->c_slback, 0, diff, gflag, percent);
6746 fcv->c_slweight += done;
6747 debug1("ChangeCanvasSize returns %d\n", done);
6748 return done;
6751 static void
6752 ResizeRegions(arg, flags)
6753 char *arg;
6754 int flags;
6756 struct canvas *cv;
6757 int diff, l;
6758 int gflag = 0, abs = 0, percent = 0;
6759 int orient = 0;
6761 ASSERT(display);
6762 if (!*arg)
6763 return;
6764 if (D_forecv->c_slorient == SLICE_UNKN)
6766 Msg(0, "resize: need more than one region");
6767 return;
6769 gflag = flags & RESIZE_FLAG_L ? 0 : 1;
6770 orient |= flags & RESIZE_FLAG_H ? SLICE_HORI : 0;
6771 orient |= flags & RESIZE_FLAG_V ? SLICE_VERT : 0;
6772 if (orient == 0)
6773 orient = D_forecv->c_slorient;
6774 l = strlen(arg);
6775 if (*arg == '=')
6777 /* make all regions the same height */
6778 struct canvas *cv = gflag ? &D_canvas : D_forecv->c_slback;
6779 if (cv->c_slperp->c_slorient & orient)
6780 EqualizeCanvas(cv->c_slperp, gflag);
6781 /* can't use cv->c_slorient directly as it can be D_canvas */
6782 if ((cv->c_slperp->c_slorient ^ (SLICE_HORI ^ SLICE_VERT)) & orient)
6784 if (cv->c_slback)
6786 cv = cv->c_slback;
6787 EqualizeCanvas(cv->c_slperp, gflag);
6789 else
6790 EqualizeCanvas(cv, gflag);
6792 ResizeCanvas(cv);
6793 RecreateCanvasChain();
6794 RethinkDisplayViewports();
6795 ResizeLayersToCanvases();
6796 return;
6798 if (!strcmp(arg, "min") || !strcmp(arg, "0"))
6800 abs = 2;
6801 diff = 0;
6803 else if (!strcmp(arg, "max") || !strcmp(arg, "_"))
6805 abs = 2;
6806 diff = 1;
6808 else
6810 if (l > 0 && arg[l - 1] == '%')
6811 percent = 1000;
6812 if (*arg == '+')
6813 diff = atoi(arg + 1);
6814 else if (*arg == '-')
6815 diff = -atoi(arg + 1);
6816 else
6818 diff = atoi(arg); /* +1 because of caption line */
6819 if (diff < 0)
6820 diff = 0;
6821 abs = diff == 0 ? 2 : 1;
6824 if (!abs && !diff)
6825 return;
6826 if (percent)
6827 diff = diff * percent / 100;
6828 cv = D_forecv;
6829 if (cv->c_slorient & orient)
6830 ChangeCanvasSize(cv, abs, diff, gflag, percent);
6831 if (cv->c_slback->c_slorient & orient)
6832 ChangeCanvasSize(cv->c_slback, abs, diff, gflag, percent);
6834 ResizeCanvas(&D_canvas);
6835 RecreateCanvasChain();
6836 RethinkDisplayViewports();
6837 ResizeLayersToCanvases();
6838 return;
6840 #if 0
6842 if (siz + diff < 1)
6843 diff = 1 - siz;
6844 if (siz + diff > dsize - (nreg - 1) * 2 - 1)
6845 diff = dsize - (nreg - 1) * 2 - 1 - siz;
6846 if (diff == 0 || siz + diff < 1)
6847 return;
6849 if (diff < 0)
6851 if (D_forecv->c_next)
6853 D_forecv->c_ye += diff;
6854 D_forecv->c_next->c_ys += diff;
6855 D_forecv->c_next->c_yoff += diff;
6857 else
6859 for (cv = D_cvlist; cv; cv = cv->c_next)
6860 if (cv->c_next == D_forecv)
6861 break;
6862 ASSERT(cv);
6863 cv->c_ye -= diff;
6864 D_forecv->c_ys -= diff;
6865 D_forecv->c_yoff -= diff;
6868 else
6870 int s, i = 0, found = 0, di = diff, d2;
6871 s = dsize - (nreg - 1) * 2 - 1 - siz;
6872 for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next)
6874 if (cv == D_forecv)
6876 cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff;
6877 cv->c_yoff -= cv->c_ys - i;
6878 cv->c_ys = i;
6879 found = 1;
6880 continue;
6882 s -= cv->c_ye - cv->c_ys;
6883 if (!found)
6885 if (s >= di)
6886 continue;
6887 d2 = di - s;
6889 else
6890 d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di;
6891 di -= d2;
6892 cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2;
6893 cv->c_yoff -= cv->c_ys - i;
6894 cv->c_ys = i;
6897 RethinkDisplayViewports();
6898 ResizeLayersToCanvases();
6899 #endif
6902 static void
6903 ResizeFin(buf, len, data)
6904 char *buf;
6905 int len;
6906 char *data;
6908 int ch;
6909 int flags = *(int *)data;
6910 ch = ((unsigned char *)buf)[len];
6911 if (ch == 0)
6913 ResizeRegions(buf, flags);
6914 return;
6916 if (ch == 'h')
6917 flags ^= RESIZE_FLAG_H;
6918 else if (ch == 'v')
6919 flags ^= RESIZE_FLAG_V;
6920 else if (ch == 'b')
6921 flags |= RESIZE_FLAG_H|RESIZE_FLAG_V;
6922 else if (ch == 'p')
6923 flags ^= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V;
6924 else if (ch == 'l')
6925 flags ^= RESIZE_FLAG_L;
6926 else
6927 return;
6928 inp_setprompt(resizeprompts[flags], NULL);
6929 *(int *)data = flags;
6930 buf[len] = '\034';
6933 void
6934 SetForeCanvas(d, cv)
6935 struct display *d;
6936 struct canvas *cv;
6938 struct display *odisplay = display;
6939 if (d->d_forecv == cv)
6940 return;
6942 display = d;
6943 D_forecv = cv;
6944 if ((focusminwidth && (focusminwidth < 0 || D_forecv->c_xe - D_forecv->c_xs + 1 < focusminwidth)) ||
6945 (focusminheight && (focusminheight < 0 || D_forecv->c_ye - D_forecv->c_ys + 1 < focusminheight)))
6947 ResizeCanvas(&D_canvas);
6948 RecreateCanvasChain();
6949 RethinkDisplayViewports();
6950 ResizeLayersToCanvases(); /* redisplays */
6952 fore = D_fore = Layer2Window(D_forecv->c_layer);
6953 if (D_other == fore)
6954 D_other = 0;
6955 flayer = D_forecv->c_layer;
6956 #ifdef RXVT_OSC
6957 if (D_xtermosc[2] || D_xtermosc[3])
6959 Activate(-1);
6961 else
6962 #endif
6964 RefreshHStatus();
6965 #ifdef RXVT_OSC
6966 RefreshXtermOSC();
6967 #endif
6968 flayer = D_forecv->c_layer;
6969 CV_CALL(D_forecv, LayRestore();LaySetCursor());
6970 WindowChanged(0, 'F');
6973 display = odisplay;
6976 #ifdef RXVT_OSC
6977 void
6978 RefreshXtermOSC()
6980 int i;
6981 struct win *p;
6983 p = Layer2Window(D_forecv->c_layer);
6984 for (i = 3; i >=0; i--)
6985 SetXtermOSC(i, p ? p->w_xtermosc[i] : 0);
6987 #endif
6990 ParseAttrColor(s1, s2, msgok)
6991 char *s1, *s2;
6992 int msgok;
6994 int i, n;
6995 char *s, *ss;
6996 int r = 0;
6998 s = s1;
6999 while (*s == ' ')
7000 s++;
7001 ss = s;
7002 while (*ss && *ss != ' ')
7003 ss++;
7004 while (*ss == ' ')
7005 ss++;
7006 if (*s && (s2 || *ss || !((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || *s == '.')))
7008 int mode = 0, n = 0;
7009 if (*s == '+')
7011 mode = 1;
7012 s++;
7014 else if (*s == '-')
7016 mode = -1;
7017 s++;
7019 else if (*s == '!')
7021 mode = 2;
7022 s++;
7024 else if (*s == '=')
7025 s++;
7026 if (*s >= '0' && *s <= '9')
7028 n = *s++ - '0';
7029 if (*s >= '0' && *s <= '9')
7030 n = n * 16 + (*s++ - '0');
7031 else if (*s >= 'a' && *s <= 'f')
7032 n = n * 16 + (*s++ - ('a' - 10));
7033 else if (*s >= 'A' && *s <= 'F')
7034 n = n * 16 + (*s++ - ('A' - 10));
7035 else if (*s && *s != ' ')
7037 if (msgok)
7038 Msg(0, "Illegal attribute hexchar '%c'", *s);
7039 return -1;
7042 else
7044 while (*s && *s != ' ')
7046 if (*s == 'd')
7047 n |= A_DI;
7048 else if (*s == 'u')
7049 n |= A_US;
7050 else if (*s == 'b')
7051 n |= A_BD;
7052 else if (*s == 'r')
7053 n |= A_RV;
7054 else if (*s == 's')
7055 n |= A_SO;
7056 else if (*s == 'B')
7057 n |= A_BL;
7058 else
7060 if (msgok)
7061 Msg(0, "Illegal attribute specifier '%c'", *s);
7062 return -1;
7064 s++;
7067 if (*s && *s != ' ')
7069 if (msgok)
7070 Msg(0, "junk after attribute description: '%c'", *s);
7071 return -1;
7073 if (mode == -1)
7074 r = n << 8 | n;
7075 else if (mode == 1)
7076 r = n << 8;
7077 else if (mode == 2)
7078 r = n;
7079 else if (mode == 0)
7080 r = 0xffff ^ n;
7082 while (*s && *s == ' ')
7083 s++;
7085 if (s2)
7087 if (*s)
7089 if (msgok)
7090 Msg(0, "junk after description: '%c'", *s);
7091 return -1;
7093 s = s2;
7094 while (*s && *s == ' ')
7095 s++;
7098 #ifdef COLOR
7099 if (*s)
7101 static char costr[] = "krgybmcw d i.01234567 9 f FKRGYBMCW I ";
7102 int numco = 0, j;
7104 n = 0;
7105 if (*s == '.')
7107 numco++;
7108 n = 0x0f;
7109 s++;
7111 for (j = 0; j < 2 && *s && *s != ' '; j++)
7113 for (i = 0; costr[i]; i++)
7114 if (*s == costr[i])
7115 break;
7116 if (!costr[i])
7118 if (msgok)
7119 Msg(0, "illegal color descriptor: '%c'", *s);
7120 return -1;
7122 numco++;
7123 n = n << 4 | (i & 15);
7124 #ifdef COLORS16
7125 if (i >= 48)
7126 n = (n & 0x20ff) | 0x200;
7127 #endif
7128 s++;
7130 if ((n & 0xf00) == 0xf00)
7131 n ^= 0xf00; /* clear superflous bits */
7132 #ifdef COLORS16
7133 if (n & 0x2000)
7134 n ^= 0x2400; /* shift bit into right position */
7135 #endif
7136 if (numco == 1)
7137 n |= 0xf0; /* don't change bg color */
7138 if (numco != 2 && n != 0xff)
7139 n |= 0x100; /* special invert mode */
7140 if (*s && *s != ' ')
7142 if (msgok)
7143 Msg(0, "junk after color description: '%c'", *s);
7144 return -1;
7146 n ^= 0xff;
7147 r |= n << 16;
7149 #endif
7151 while (*s && *s == ' ')
7152 s++;
7153 if (*s)
7155 if (msgok)
7156 Msg(0, "junk after description: '%c'", *s);
7157 return -1;
7159 debug1("ParseAttrColor %06x\n", r);
7160 return r;
7164 * Color coding:
7165 * 0-7 normal colors
7166 * 9 default color
7167 * e just set intensity
7168 * f don't change anything
7169 * Intensity is encoded into bits 17(fg) and 18(bg).
7171 void
7172 ApplyAttrColor(i, mc)
7173 int i;
7174 struct mchar *mc;
7176 debug1("ApplyAttrColor %06x\n", i);
7177 mc->attr |= i >> 8 & 255;
7178 mc->attr ^= i & 255;
7179 #ifdef COLOR
7180 i = (i >> 16) ^ 0xff;
7181 if ((i & 0x100) != 0)
7183 i &= 0xeff;
7184 if (mc->attr & (A_SO|A_RV))
7185 # ifdef COLORS16
7186 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4) | ((i & 0x200) << 1) | ((i & 0x400) >> 1);
7187 # else
7188 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4);
7189 # endif
7191 # ifdef COLORS16
7192 if ((i & 0x0f) != 0x0f)
7193 mc->attr = (mc->attr & 0xbf) | ((i >> 3) & 0x40);
7194 if ((i & 0xf0) != 0xf0)
7195 mc->attr = (mc->attr & 0x7f) | ((i >> 3) & 0x80);
7196 # endif
7197 mc->color = 0x99 ^ mc->color;
7198 if ((i & 0x0e) == 0x0e)
7199 i = (i & 0xf0) | (mc->color & 0x0f);
7200 if ((i & 0xe0) == 0xe0)
7201 i = (i & 0x0f) | (mc->color & 0xf0);
7202 mc->color = 0x99 ^ i;
7203 debug2("ApplyAttrColor - %02x %02x\n", mc->attr, i);
7204 #endif