]> jfr.im git - irc.git/blame - software/ircd/www.irc.org/ftp/irc/clients/vms/doughirc/inp.c
init
[irc.git] / software / ircd / www.irc.org / ftp / irc / clients / vms / doughirc / inp.c
CommitLineData
3bd189cb
JR
1/* ------------------------------------------------------------------------ */
2/* You have just entered the world of inp.c */
3/* In this file we will strive for excellence in keyboard input. That is */
4/* all this file is for. I have adopted some ideas from the makers of IRCII */
5/* ------------------------------------------------------------------------ */
6/* All rights reserved. Do not distribute this code without permission of */
7/* the programmer(s). (Douglas Lewis) */
8/* ------------------------------------------------------------------------ */
9#define NEW_INP
10
11#include <stdio.h>
12#include <ssdef.h>
13#include <descrip.h>
14#ifdef __GNUC__
15#define PSL$C_USER 3
16
17#define SMG$K_TRM_UP 274
18#define SMG$K_TRM_DOWN 275
19#define SMG$K_TRM_LEFT 276
20#define SMG$K_TRM_RIGHT 277
21#else
22#include <smgdef.h>
23#include <psldef.h>
24#endif
25#include <iodef.h>
26#include <ttdef.h>
27#include <tt2def.h>
28#include <ssdef.h>
29#include <string.h>
30#include <stdlib.h>
31#include <time.h>
32#include <ctype.h>
33#include <lib$routines.h>
34
35#include "base_includes.h"
36#include "binding.h"
37#include "qio.h"
38#include "list.h"
39#include "inp.h"
40#include "system.h"
41
42extern server_ptr gsrv;
43extern int DUMB;
44
45#define NUMKEYS 26 /* Number of special keys defined. */
46
47static unsigned in_chan = 0;
48
49#define INPUT_QIO 2
50#define INPUT_GETS 1
51#define INPUT_NONE 0
52int INPUT_DEFINED = INPUT_QIO;
53
54static unsigned long keybd_efn;
55static unsigned char new_keyget(void);
56unsigned char (*input_routine)(void) = new_keyget;
57int last_keyhit;
58static int dont_restart_qio = 1;
59
60static struct iosb_type ast_iosb;
61static char inp_ast, buff_ast[256];
62static int buff_left = 0, buff_start = 0, buff_curr = 0;
63
64/* ------------------------------------------------------------------------ */
65static void ctrlc_ast(void)
66{
67 yell("received a control-c");
68 tcp_connect_cancel();
69}
70
71/* ------------------------------------------------------------------------ */
72static void new_keyget_ast(void)
73{
74 unsigned status;
75 if (!(ast_iosb.status & 1)) {
76 /* 2104 is a data overrun */
77 if (ast_iosb.status && ast_iosb.status != 2104) {
78 if (dont_restart_qio)
79 {
80 /* abort - called by spawn */
81 if (ast_iosb.status != 44)
82 my_sig(ast_iosb.status, "keyget not restarting");
83 return;
84 }
85 }
86 } else {
87 last_keyhit = time(NULL);
88 if (inp_ast==3) ctrlc_ast();
89 if (buff_start==256) buff_start = 0;
90 if (buff_left==256)
91 yell("input buffer is full");
92 else {
93 buff_ast[buff_start++] = inp_ast;
94 buff_left++;
95 status = sys$setef(KEYGET_EF);
96 }
97 }
98 status = sys$qio(keybd_efn, in_chan, IO$_READVBLK|IO$M_NOECHO, &ast_iosb,
99 new_keyget_ast, 0, &inp_ast, sizeof(inp_ast), 0,
100 0, 0, 0);
101}
102/* ------------------------------------------------------------------------ */
103static void start_keyget_ast(void)
104{
105 unsigned status, loop;
106
107 buff_curr = buff_left = buff_start = 0;
108 status = sys$clref(KEYGET_EF);
109 status = sys$qio(keybd_efn, in_chan, IO$_READVBLK|IO$M_NOECHO, &ast_iosb,
110 new_keyget_ast, 0, &inp_ast, sizeof(inp_ast), 0, 0, 0, 0);
111}
112/* ------------------------------------------------------------------------ */
113static unsigned char new_keyget(void)
114{
115 extern void wait_routine(int);
116 int old;
117 old = sys$setast(0);
118 if (!buff_left) {
119 if (old==SS$_WASSET) sys$setast(1);
120 wait_routine(KEYGET_EF);
121 old = sys$setast(0);
122 }
123 if (buff_curr==256) buff_curr = 0;
124 buff_left--;
125 if (!buff_left) sys$clref(KEYGET_EF);
126 if (old==SS$_WASSET) sys$setast(1);
127 return buff_ast[buff_curr++];
128}
129/* ------------------------------------------------------------------------ */
130/* ------------------------------------------------------------------------ */
131/* Initialize the keyboard information. */
132/* ------------------------------------------------------------------------ */
133
134struct devchars {
135 char class;
136 char ttype;
137 unsigned short width;
138 unsigned long basic;
139 union tt2def exten;
140};
141
142static int oldpasthru = -1;
143
144void set_pasthru(int reset)
145{
146 int status;
147 struct devchars dc;
148 struct iosb_type iosb;
149
150 if (in_chan==0) return;
151 status = sys$qiow(0, in_chan, IO$_SENSEMODE, &iosb, 0, 0,
152 &dc, sizeof(dc),0,0,0,0);
153 if (!ODD(status) || !ODD(iosb.status))
154 yell("Error in sensemode pasthru: %d", ODD(status)?iosb.status:status);
155
156#ifdef __GNUC__
157 if (reset) {
158 if (oldpasthru != -1)
159 dc.exten.tt2$r_tt2def_bits.tt2$v_pasthru = oldpasthru;
160 } else {
161 if (oldpasthru == -1) oldpasthru = dc.exten.tt2$r_tt2def_bits.tt2$v_pasthru;
162 dc.exten.tt2$r_tt2def_bits.tt2$v_pasthru = 1; /**/
163 }
164#else
165 if (reset) {
166 if (oldpasthru != -1) dc.exten.tt2$v_pasthru = oldpasthru;
167 } else {
168 if (oldpasthru == -1) oldpasthru = dc.exten.tt2$v_pasthru;
169 dc.exten.tt2$v_pasthru = 1; /**/
170 }
171#endif
172 status = sys$qiow(0, in_chan, IO$_SETMODE, &iosb, 0, 0,
173 &dc, sizeof(dc),0,0,0,0);
174 if (!ODD(status) || !ODD(iosb.status))
175 yell("Error in setmode pasthru: %d", ODD(status)?iosb.status:status);
176}
177
178void stop_input(void)
179{
180 if (INPUT_DEFINED!=INPUT_QIO) return;
181 dont_restart_qio = TRUE;
182 sys$cancel(in_chan);
183}
184void cleanup_input(void)
185{
186 int loop;
187 unsigned status;
188 if (INPUT_DEFINED!=INPUT_QIO) return;
189 set_pasthru(TRUE);
190}
191
192void init_keybdio(void)
193{
194 unsigned status, loop;
195 char input[10] = "SYS$INPUT";
196 $DESCRIPTOR(input_d, "TT");
197 unsigned prcpri;
198 struct devchars dc;
199 struct iosb_type iosb;
200
201 last_keyhit = time(NULL);
202 if (DUMB==1) INPUT_DEFINED = INPUT_GETS;
203 if (DUMB==2) INPUT_DEFINED = INPUT_NONE;
204 if (INPUT_DEFINED!=INPUT_QIO) return;
205 status = sys$setpri(0, 0, 4, &prcpri);
206 if (!ODD(status)) my_sig(status, "keybdio");
207
208 status = sys$assign(&input_d, &in_chan, PSL$C_USER, 0, 0);
209 if (!ODD(status)) my_sig(status, "keybdio2");
210
211 status = sys$qiow(0, in_chan, IO$_SENSEMODE, &iosb, 0, 0,
212 &dc, sizeof(dc),0,0,0,0);
213 if (!ODD(status) || !ODD(iosb.status))
214 say("Error in sensemode2 pasthru: %d", ODD(status)?iosb.status:status);
215 if (!((dc.ttype == TT$_VT100) || (dc.ttype == TT$_VT200_SERIES) ||
216 (dc.ttype == TT$_VT300_SERIES) || (dc.ttype == TT$_VT102))) {
217 (void)printf("Please use a VT100/VT200/VT300 compatible terminal.\n");
218 exit(0);
219 }
220
221 set_pasthru(FALSE);
222 lib$get_ef(&keybd_efn);
223}
224
225void start_keybdio(void)
226{
227 if (dont_restart_qio == FALSE) return;
228 dont_restart_qio = FALSE;
229 start_keyget_ast();
230}
231
232/* ------------------------------------------------------------------------ */
233/* Offset is used to determine when the input buffer should be "scrolled" */
234/* to the next line of input. When the current screen position falls out of */
235/* the range, the input buffer will be scrolled. I.E. (curr<OFFSET or */
236/* Curr> (screen_width-OFFSET)) */
237/* ------------------------------------------------------------------------ */
238
239#define OFFSET 10
240
241/* ------------------------------------------------------------------------ */
242/* Global variables used to handle the input line. Determines cursor */
243/* position, the "visible window", line length, actual position in the */
244/* string and various limits. */
245/* ------------------------------------------------------------------------ */
246
247static int wstart = OFFSET, wcurs=0, wend, line_len = 0;
248static int actual = 0;
249static int pl = 0, max;
250static char *work = NULL;
251static int screen_width = 80;
252static int global_maxlen;
253static char prompt[80];
254
255/* ------------------------------------------------------------------------ */
256/* Check to see if the position where we are in the input string is actual- */
257/* ly in the current window. If it is not, scroll the window to get it in. */
258/* If we had to scroll, or all is true, then reprint the input line. */
259/* ------------------------------------------------------------------------ */
260
261static void check_input(int all)
262{
263 int oldstart, tot, old;
264
265 if (INPUT_DEFINED != INPUT_QIO) return;
266 old = sys$setast(0);
267 oldstart = wstart;
268 wend = wstart + screen_width- 2 * OFFSET;
269
270 while ((actual < wstart) && (wstart > OFFSET))
271 {
272 wend = wstart;
273 wstart = wstart - max;
274 }
275 while (actual >= wend)
276 {
277 wstart = wend;
278 wend = wend + max;
279 }
280 wcurs = actual-wstart+OFFSET+1;
281 if ((tot = (line_len-wstart+OFFSET)) > screen_width)
282 tot = screen_width;
283 if ((wstart!=oldstart) || (all)) {
284 (void)print_at(&work[wstart-OFFSET], tot, pl);
285 }
286 (void)putcursor(wcurs);
287 if (old==SS$_WASSET) (void)sys$setast(1);
288}
289
290static char prompt_format[80] = "";
291
292/* ----------------------------------------------------------------------- */
293/* "Rebuild" the prompt and compare it to the old one. If there is a */
294/* change, rewrite the input line to correct for a different prompt. */
295/* flag is FALSE if is the begginning of a new input line, else it is TRUE */
296/* ----------------------------------------------------------------------- */
297
298void find_input_prompt(flag)
299 int flag;
300{
301 char *temp;
302 int temppl, loop, num = 0, added;
303
304 if (INPUT_DEFINED != INPUT_QIO) return;
305 expand_alias(prompt_format, "", &added, prompt, sizeof(prompt));
306 temppl = strlen(prompt);
307
308 /* Check if the prompt has changed */
309 if (flag || (strncasecmp(prompt, work, temppl) != 0) || (temppl!=pl))
310 {
311 temp = (char *)mymalloc(global_maxlen + temppl + 1);
312 (void)strcpy(temp, prompt);
313
314 if (line_len == 0) num = 0;
315 else num = line_len - pl;
316
317 for (loop=0; loop<num; loop++) temp[temppl+loop] = work[pl+loop];
318
319 line_len = num + temppl;
320 if (!actual) actual = temppl;
321 else actual = actual + temppl - pl;
322
323 pl = temppl;
324 if (work) myfree(work);
325/* yell("printing [%s] at len 0, pl %d", temp, pl); */
326 screen_width = print_at(temp, 0, pl); /* Was line_len */
327 work = temp;
328 wstart = OFFSET;
329 wend = wstart + screen_width- 2 * OFFSET;
330 max = screen_width - 2 * OFFSET;
331 check_input(TRUE);
332 }
333}
334
335/* ----------------------------------------------------------------------- */
336/* Go left a character in the input string. */
337/* ----------------------------------------------------------------------- */
338void inp_backward_character(void)
339{
340 if (actual > pl) {
341 actual--;
342 wcurs--;
343 (void)putcursor(wcurs);
344 }
345}
346
347static void inp_history_line(int flag)
348{
349 char *str;
350 str = get_prev_input(flag, TRUE);
351 if (!str) return;
352 (void)sprintf(work+pl, "%s\0", str);
353 line_len = pl+strlen(str);
354 wcurs = line_len;
355 actual = line_len;
356 check_input(TRUE);
357}
358
359void inp_forward_history(void)
360 { inp_history_line(0); }
361
362void inp_backward_history(void)
363 { inp_history_line(1); }
364
365void inp_beginning_of_line(void)
366{
367 actual = pl;
368 check_input(TRUE);
369}
370
371void inp_forward_character(void)
372{
373 if (actual < line_len) {
374 actual++;
375 wcurs++;
376 (void)putcursor(wcurs);
377 }
378}
379
380int inp_backspace(void)
381{
382 int loop;
383 if (actual > pl) { /* Are we at the start of the line when we delete */
384 for (loop=actual-1; loop<line_len; loop++)
385 work[loop] = work[loop+1];
386 actual--; line_len--; wcurs--;
387 (void)del_char_from_input(wcurs, 1);
388 }
389 return 1;
390}
391
392int inp_toggle_insert_mode(void)
393 { setivar(VAR_INSERT_MODE, !getivar(VAR_INSERT_MODE)); return 1; }
394
395void inp_insert_char(char key)
396{
397 int loop;
398 if (getivar(VAR_INSERT_MODE)) {
399 if ((line_len-pl) < global_maxlen) {
400 for (loop=line_len; (loop>actual); loop--)
401 work[loop] = work[loop-1];
402 line_len++;
403 (void)insert_char((char)key, wcurs);
404 work[actual++] = (char)key; wcurs++;
405 }
406 } else {
407 if ((actual-pl) < global_maxlen) {
408 (void)rep_char_in_input((char)key, wcurs);
409 if (line_len==actual) line_len++;
410 work[actual++] = (char)key; wcurs++;
411 }
412 }
413}
414
415int inp_eol(void)
416{
417 actual = line_len;
418 wcurs = line_len;
419 (void)putcursor(wcurs+pl);
420 return 1;
421}
422
423static int global_done = FALSE;
424int inp_send_line(void)
425{
426 global_done = TRUE;
427 return 1;
428}
429
430int inp_delete_current_char(void)
431{
432 int loop;
433 if (actual<line_len) {
434 line_len--;
435 for (loop=actual; loop<line_len; loop++)
436 work[loop] = work[loop+1];
437 (void)del_char_from_input(wcurs, 1);
438 }
439 return 1;
440}
441
442int inp_delete_to_bol(void)
443{
444 int loop, count;
445 for (loop=actual, count = pl; loop<line_len; loop++)
446 work[count++] = work[loop];
447 line_len=(line_len-actual+pl);
448 wcurs = pl; actual = pl;
449 check_input(TRUE);
450 return 1;
451}
452
453/* ----------------------------------------------------------------------- */
454/* Read input from the input device and handle any characters as they come */
455/* up. Read up to maxlen characters for the input. */
456/* ----------------------------------------------------------------------- */
457
458static char *input_line;
459
460static void handle_key(unsigned char real)
461{
462 int key, done, num = 0, ac_loop, meta_key = MAX_META;
463 u_char saved_bind[10]; /* Assume there are no sequences over 10 characters */
464
465 key = real;
466 if (key<128)
467 done = (int)(*META)[meta_key][key].func_bind >= 0;
468 while (!done) {
469 saved_bind[num++] = key;
470 meta_key = (int)(*META)[meta_key][key].func_bind;
471 if (meta_key<0) {
472 key = input_routine();
473 if (key>127) done = TRUE;
474 meta_key += MAX_META;
475 if (!done) done = (int)(*META)[meta_key][key].func_bind >= 0;
476 } else done = TRUE;
477 }
478
479 if (key<128)
480 if ((int)(*META)[meta_key][key].func_bind>0) {
481 (void)(*META)[meta_key][key].func_bind((*META)[meta_key][key].param, FALSE, 0);
482 return;
483 }
484 saved_bind[num++] = key;
485 for (ac_loop=0;ac_loop<num;ac_loop++) {
486 key = saved_bind[ac_loop];
487 inp_insert_char(key);
488 } /* for loop */
489}
490
491static char *dumb_input(char *input)
492{
493 gets(input);
494 return input;
495}
496
497char *read_input(char input[MAXLEN], int maxlen, char *pr)
498{
499 int count, num, old_global_done, old_global_maxlen;
500 char oldprompt[80];
501 int oldline_len;
502
503 oldline_len = line_len;
504 (void)strcpy(oldprompt, prompt_format);
505 if (pr)
506 (void)strcpy(prompt_format, pr);
507 else
508 (void)strcpy(prompt_format, getvar(VAR_INPUT_PROMPT));
509 old_global_maxlen = global_maxlen;
510 global_maxlen = maxlen;
511 if (INPUT_DEFINED == INPUT_GETS) return dumb_input(input);
512 if (INPUT_DEFINED == INPUT_NONE) {
513 yell("Oh shit, we ended up in a hiber loop!");
514 *input = 0;
515 sys$hiber();
516 return NULL;
517 }
518
519 line_len = 0;
520 actual = 0;
521
522 num = sys$setast(0);
523 find_input_prompt(TRUE);
524 if (num == SS$_WASSET) (void)sys$setast(1);
525
526 (void)putcursor(pl);
527 old_global_done = global_done;
528 global_done = FALSE;
529 do {
530 check_input(FALSE);
531 handle_key(input_routine());
532 } while (!global_done);
533 global_maxlen = old_global_maxlen;
534 global_done = old_global_done;
535 (void)strncpy(input, &work[pl], line_len-pl);
536 work[pl] = 0;
537 input[line_len-pl] = 0;
538 line_len=pl;
539 actual = line_len;
540 strcpy(prompt_format, oldprompt);
541 return input;
542}
543
544/* ----------------------------------------------------------------------- */
545/* End of file. */
546/* ----------------------------------------------------------------------- */