Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/input.c
1069 views
1
/*
2
* input.c: does the actual input line stuff... keeps the appropriate stuff
3
* on the input line, handles insert/delete of characters/words... the whole
4
* ball o wax
5
*
6
* Written By Michael Sandrof
7
*
8
* Copyright(c) 1990
9
*
10
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
11
*/
12
13
#include "irc.h"
14
static char cvsrevision[] = "$Id: input.c 160 2012-03-06 11:14:51Z keaston $";
15
CVS_REVISION(input_c)
16
#include <pwd.h>
17
#include "struct.h"
18
19
#include "alias.h"
20
#include "commands.h"
21
#include "exec.h"
22
#include "history.h"
23
#include "bsdglob.h"
24
#include "hook.h"
25
#include "input.h"
26
#include "ircaux.h"
27
#include "keys.h"
28
#include "screen.h"
29
#include "server.h"
30
#include "ircterm.h"
31
#include "list.h"
32
#include "vars.h"
33
#include "misc.h"
34
#include "screen.h"
35
#include "output.h"
36
#include "chelp.h"
37
#include "dcc.h"
38
#include "cdcc.h"
39
#include "whowas.h"
40
#include "tcl_bx.h"
41
#include "window.h"
42
#include "status.h"
43
#include "hash2.h"
44
45
#ifdef TRANSLATE
46
#include "translat.h"
47
#endif
48
#ifdef WANT_HEBREW
49
#include "hebrew.h"
50
#endif
51
52
#define MAIN_SOURCE
53
#include "modval.h"
54
55
#include <sys/ioctl.h>
56
57
void get_history (int);
58
59
static char new_nick[NICKNAME_LEN+1] = "";
60
static char *input_lastmsg = NULL;
61
62
extern NickTab *BX_getnextnick (int, char *, char *, char *);
63
extern int extended_handled;
64
extern char *BX_getchannick (char *, char *);
65
extern int foreground;
66
67
NickTab *tabkey_array = NULL, *autoreply_array = NULL;
68
69
70
71
const int WIDTH = 10;
72
73
/* input_prompt: contains the current, unexpanded input prompt */
74
static char *input_prompt = NULL;
75
76
enum I_STATE {
77
STATE_NORMAL = 0,
78
STATE_COMPLETE,
79
STATE_TABKEY,
80
STATE_TABKEYNEXT,
81
STATE_CNICK,
82
STATE_CNICKNEXT
83
} in_completion = STATE_NORMAL;
84
85
/* These are sanity macros. The file was completely unreadable before
86
* i put these in here. I make no apologies for them.
87
*/
88
#define current_screen last_input_screen
89
#define INPUT_CURSOR current_screen->input_cursor
90
#define INPUT_BUFFER current_screen->input_buffer
91
#define MIN_POS current_screen->buffer_min_pos
92
#define THIS_POS current_screen->buffer_pos
93
#define THIS_CHAR INPUT_BUFFER[THIS_POS]
94
#define MIN_CHAR INPUT_BUFFER[MIN_POS]
95
#define PREV_CHAR INPUT_BUFFER[THIS_POS-1]
96
#define NEXT_CHAR INPUT_BUFFER[THIS_POS+1]
97
#define ADD_TO_INPUT(x) strmcat(INPUT_BUFFER, (x), INPUT_BUFFER_SIZE);
98
#define INPUT_ONSCREEN current_screen->input_visible
99
#define INPUT_VISIBLE INPUT_BUFFER[INPUT_ONSCREEN]
100
#define ZONE current_screen->input_zone_len
101
#define START_ZONE current_screen->input_start_zone
102
#define END_ZONE current_screen->input_end_zone
103
#define INPUT_PROMPT current_screen->input_prompt
104
#define INPUT_PROMPT_LEN current_screen->input_prompt_len
105
#define INPUT_LINE current_screen->input_line
106
#define BUILT_IN_KEYBINDING(x) void x (char key, char *string)
107
108
109
#define HOLDLAST current_screen->current_window->screen_hold
110
111
Display *get_screen_hold(Window *win)
112
{
113
return win->screen_hold;
114
}
115
116
static int safe_puts (register char *str, int len, int echo)
117
{
118
int i = 0;
119
while (*str && i < len)
120
{
121
term_putchar(*str);
122
str++; i++;
123
}
124
return i;
125
}
126
127
/* cursor_to_input: move the cursor to the input line, if not there already */
128
extern void BX_cursor_to_input (void)
129
{
130
Screen *oldscreen = last_input_screen;
131
Screen *screen;
132
133
if (!foreground)
134
return;
135
136
for (screen = screen_list; screen; screen = screen->next)
137
{
138
if (screen->alive && is_cursor_in_display(screen))
139
{
140
output_screen = screen;
141
last_input_screen = screen;
142
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
143
cursor_not_in_display(screen);
144
term_flush();
145
}
146
}
147
output_screen = last_input_screen = oldscreen;
148
}
149
150
/*
151
* update_input: does varying amount of updating on the input line depending
152
* upon the position of the cursor and the update flag. If the cursor has
153
* move toward one of the edge boundaries on the screen, update_cursor()
154
* flips the input line to the next (previous) line of text. The update flag
155
* may be:
156
*
157
* NO_UPDATE - only do the above bounds checking.
158
*
159
* UPDATE_JUST_CURSOR - do bounds checking and position cursor where is should
160
* be.
161
*
162
* UPDATE_FROM_CURSOR - does all of the above, and makes sure everything from
163
* the cursor to the right edge of the screen is current (by redrawing it).
164
*
165
* UPDATE_ALL - redraws the entire line
166
*/
167
extern void BX_update_input (int update)
168
{
169
int old_zone;
170
char *ptr, *ptr_free;
171
int len,
172
free_it = 0,
173
echo = 1,
174
max;
175
176
char *prompt;
177
Screen *os = last_input_screen;
178
Screen *ns;
179
Window *saved_current_window = current_window;
180
181
182
#ifdef WANT_HEBREW
183
void BX_set_input_heb (char *str);
184
char prehebbuff[2000];
185
#endif
186
if (dumb_mode || !foreground)
187
return;
188
for (ns = screen_list; ns; ns = ns->next)
189
{
190
last_input_screen = ns;
191
current_window = ns->current_window;
192
193
#ifdef WANT_HEBREW
194
/*
195
* crisk: hebrew thingy
196
*/
197
if (get_int_var(HEBREW_TOGGLE_VAR))
198
{
199
update = UPDATE_ALL;
200
strcpy(prehebbuff, get_input());
201
hebrew_process(get_input());
202
}
203
#endif
204
205
cursor_to_input();
206
207
if (last_input_screen && last_input_screen->promptlist)
208
prompt = last_input_screen->promptlist->prompt;
209
else
210
prompt = input_prompt;
211
212
if (prompt)
213
{
214
char *loc;
215
int i;
216
extern int in_chelp;
217
218
loc = alloca(strlen(prompt)+200);
219
for (i = 0; prompt[i]; i++)
220
{
221
if (prompt[i] == '$')
222
loc[i++] = '$';
223
loc[i] = prompt[i];
224
}
225
loc[i] = 0;
226
in_chelp++;
227
prompt = convert_output_format(loc, NULL, NULL);
228
in_chelp--;
229
}
230
231
if (prompt && update != NO_UPDATE)
232
{
233
int args_used;
234
235
if (is_valid_process(get_target_by_refnum(0)) != -1)
236
ptr = (char *)get_prompt_by_refnum(0);
237
else
238
{
239
ptr = expand_alias(prompt, empty_string, &args_used, NULL);
240
free_it = 1;
241
}
242
if (last_input_screen->promptlist)
243
term_echo(last_input_screen->promptlist->echo);
244
245
ptr_free = ptr;
246
ptr = (char *)strip_ansi(ptr);
247
strcat(ptr, ALL_OFF_STR); /* Yes, we can do this */
248
if (free_it)
249
new_free(&ptr_free);
250
free_it = 1;
251
252
if ((ptr && !INPUT_LINE) || (!ptr && INPUT_LINE) ||
253
strcmp(ptr, last_input_screen->input_buffer))
254
{
255
if (last_input_screen->input_prompt_malloc)
256
new_free(&INPUT_PROMPT);
257
258
last_input_screen->input_prompt_malloc = free_it;
259
260
INPUT_PROMPT = ptr;
261
len = strlen(INPUT_PROMPT);
262
INPUT_PROMPT_LEN = output_with_count(INPUT_PROMPT, 0, 0);
263
update = UPDATE_ALL;
264
}
265
else
266
{
267
if (free_it)
268
new_free(&ptr);
269
}
270
}
271
272
/*
273
*
274
* HAS THE SCREEN CHANGED SIZE SINCE THE LAST TIME?
275
*
276
*/
277
278
/*
279
* If the screen has resized, then we need to re-compute the
280
* side-to-side scrolling effect.
281
*/
282
if ((last_input_screen->li != last_input_screen->old_li) ||
283
(last_input_screen->co != last_input_screen->old_co))
284
{
285
/*
286
* The input line is always the bottom line
287
*/
288
289
INPUT_LINE = last_input_screen->li - 1;
290
291
/*
292
* The "zone" is the range in which when you type, the
293
* input line does not scroll. Its WIDTH chars in from
294
* either side.
295
*/
296
ZONE = last_input_screen->co - (WIDTH * 2);
297
if (ZONE < 10)
298
ZONE = 10; /* Take that! */
299
300
START_ZONE = WIDTH;
301
END_ZONE = last_input_screen->co - WIDTH;
302
303
last_input_screen->old_co = last_input_screen->co;
304
last_input_screen->old_li = last_input_screen->li;
305
}
306
/*
307
* About zones:
308
* The input line is divided into "zones". A "zone" is set above,
309
* and is the width of the screen minus 20 (by default). The input
310
* line, as displayed, is therefore composed of the current "zone",
311
* plus 10 characters from the previous zone, plus 10 characters
312
* from the next zone. When the cursor moves to an adjacent zone,
313
* (by going into column 9 from the right or left of the edge), the
314
* input line is redrawn. There is one catch. The first "zone"
315
* includes the first ten characters of the input line.
316
*/
317
old_zone = START_ZONE;
318
319
/*
320
* The BEGINNING of the current "zone" is a calculated value:
321
* The number of characters since the origin of the input buffer
322
* is the number of printable chars in the input prompt plus the
323
* current position in the input buffer. We subtract from that
324
* the WIDTH delta to take off the first delta, which doesnt
325
* count towards the width of the zone. Then we divide that by
326
* the size of the zone, to get an integer, then we multiply it
327
* back. This gives us the first character on the screen. We
328
* add WIDTH to the result in order to get the start of the zone
329
* itself.
330
* The END of the current "zone" is just the beginning plus the width.
331
* If we have moved to an adjacent "zone" since last time, we want to
332
* completely redraw the input line.
333
*/
334
START_ZONE = ((INPUT_PROMPT_LEN + THIS_POS - WIDTH) / ZONE) * ZONE + WIDTH;
335
END_ZONE = START_ZONE + ZONE;
336
337
if (old_zone != START_ZONE)
338
update = UPDATE_ALL;
339
340
/*
341
* Now that we know where the "zone" is in the input buffer, we can
342
* easily calculate where where we want to start displaying stuff
343
* from the INPUT_BUFFER. If we're in the first "zone", then we will
344
* output from the beginning of the buffer. If we're not in the first
345
* "zone", then we will begin to output from 10 characters to the
346
* left of the zone, after adjusting for the length of the prompt.
347
*/
348
if (START_ZONE == WIDTH)
349
INPUT_ONSCREEN = 0;
350
else
351
INPUT_ONSCREEN = START_ZONE - WIDTH - INPUT_PROMPT_LEN;
352
353
/*
354
* And the cursor is simply how many characters away THIS_POS is
355
* from the first column on the screen.
356
*/
357
if (INPUT_ONSCREEN == 0)
358
INPUT_CURSOR = INPUT_PROMPT_LEN + THIS_POS;
359
else
360
INPUT_CURSOR = THIS_POS - INPUT_ONSCREEN;
361
362
/*
363
* If the cursor moved, or if we're supposed to do a full update,
364
* then redrwa the entire input line.
365
*/
366
if (update == UPDATE_ALL)
367
{
368
term_move_cursor(0, INPUT_LINE);
369
370
/*
371
* If the input line is NOT empty, and we're starting the
372
* display at the beginning of the input buffer, then we
373
* output the prompt first.
374
*/
375
if (INPUT_ONSCREEN == 0 && INPUT_PROMPT && *INPUT_PROMPT)
376
{
377
/*
378
* Forcibly turn on echo.
379
*/
380
int echo = term_echo(1);
381
382
/*
383
* Crop back the input prompt so it does not extend
384
* past the end of the zone.
385
*/
386
if (INPUT_PROMPT_LEN > (last_input_screen->co - WIDTH))
387
INPUT_PROMPT_LEN = last_input_screen->co - WIDTH - 1;
388
389
/*
390
* Output the prompt.
391
*/
392
output_with_count(INPUT_PROMPT, 0, 1);
393
394
/*
395
* Turn the echo back to what it was before,
396
* and output the rest of the input buffer.
397
*/
398
term_echo(echo);
399
safe_puts(INPUT_BUFFER, last_input_screen->co - INPUT_PROMPT_LEN, echo);
400
}
401
402
/*
403
* Otherwise we just output whatever we have.
404
*/
405
else if (echo)
406
safe_puts(&(INPUT_VISIBLE), last_input_screen->co, echo);
407
408
/*
409
* Clear the rest of the input line and reset the cursor
410
* to the current input position.
411
*/
412
term_clear_to_eol();
413
}
414
else if (update == UPDATE_FROM_CURSOR)
415
{
416
/*
417
* Move the cursor to where its supposed to be,
418
* Figure out how much we can output from here,
419
* and then output it.
420
*/
421
#ifdef __EMXPM__
422
int echo = term_echo(1);
423
#endif
424
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
425
max = last_input_screen->co - (THIS_POS - INPUT_ONSCREEN);
426
if (INPUT_ONSCREEN == 0 && INPUT_PROMPT && *INPUT_PROMPT)
427
max -= INPUT_PROMPT_LEN;
428
429
if ((len = strlen(&(THIS_CHAR))) > max)
430
len = max;
431
safe_puts(&(THIS_CHAR), len, echo);
432
term_clear_to_eol();
433
}
434
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
435
term_echo(1);
436
term_flush();
437
#ifdef WANT_HEBREW
438
/*
439
* crisk: hebrew thingy
440
*/
441
if (get_int_var(HEBREW_TOGGLE_VAR))
442
BX_set_input_heb(prehebbuff);
443
#endif
444
}
445
last_input_screen = os;
446
current_window = saved_current_window;
447
}
448
449
void change_input_prompt (int direction)
450
{
451
if (!last_input_screen->promptlist)
452
{
453
strcpy(INPUT_BUFFER, last_input_screen->saved_input_buffer);
454
THIS_POS = last_input_screen->saved_buffer_pos;
455
MIN_POS = last_input_screen->saved_min_buffer_pos;
456
*last_input_screen->saved_input_buffer = '\0';
457
last_input_screen->saved_buffer_pos = 0;
458
last_input_screen->saved_min_buffer_pos = 0;
459
update_input(UPDATE_ALL);
460
}
461
462
else if (direction == -1)
463
update_input(UPDATE_ALL);
464
465
else if (!last_input_screen->promptlist->next)
466
{
467
strcpy(last_input_screen->saved_input_buffer, INPUT_BUFFER);
468
last_input_screen->saved_buffer_pos = THIS_POS;
469
last_input_screen->saved_min_buffer_pos = MIN_POS;
470
*INPUT_BUFFER = '\0';
471
THIS_POS = MIN_POS = 0;
472
update_input(UPDATE_ALL);
473
}
474
}
475
476
/* input_move_cursor: moves the cursor left or right... got it? */
477
extern void input_move_cursor (int dir)
478
{
479
cursor_to_input();
480
if (dir)
481
{
482
if (THIS_CHAR)
483
{
484
THIS_POS++;
485
term_cursor_right();
486
}
487
}
488
else
489
{
490
if (THIS_POS > MIN_POS)
491
{
492
THIS_POS--;
493
term_cursor_left();
494
}
495
}
496
update_input(NO_UPDATE);
497
}
498
499
/*
500
* set_input: sets the input buffer to the given string, discarding whatever
501
* was in the input buffer before
502
*/
503
void BX_set_input (char *str)
504
{
505
strmcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
506
THIS_POS = strlen(INPUT_BUFFER);
507
}
508
509
#ifdef WANT_HEBREW
510
/*
511
* eilon: same as the above just without the cursor reposition.
512
* this allows input buffer "traveling" in Hebrew mode
513
*/
514
void BX_set_input_heb (char *str)
515
{
516
strmcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
517
}
518
#endif
519
520
/*
521
* get_input: returns a pointer to the input buffer. Changing this will
522
* actually change the input buffer. This is a bad way to change the input
523
* buffer tho, cause no bounds checking won't be done
524
*/
525
char *BX_get_input (void)
526
{
527
return (&(MIN_CHAR));
528
}
529
530
/* init_input: initialized the input buffer by clearing it out */
531
extern void init_input (void)
532
{
533
*INPUT_BUFFER = (char) 0;
534
THIS_POS = MIN_POS;
535
}
536
537
/* get_input_prompt: returns the current input_prompt */
538
extern char *BX_get_input_prompt (void)
539
{
540
return input_prompt;
541
}
542
543
/*
544
* set_input_prompt: sets a prompt that will be displayed in the input
545
* buffer. This prompt cannot be backspaced over, etc. It's a prompt.
546
* Setting the prompt to null uses no prompt
547
*/
548
void BX_set_input_prompt (Window *win, char *prompt, int unused)
549
{
550
if (prompt)
551
malloc_strcpy(&input_prompt, prompt);
552
else if (input_prompt)
553
malloc_strcpy(&input_prompt, empty_string);
554
else
555
return;
556
557
update_input(UPDATE_ALL);
558
}
559
560
561
/*
562
* Why did i put these in this file? I dunno. But i do know that the ones
563
* in edit.c didnt have to be here, and i knew the ones that were here DID
564
* have to be here, so i just moved them all to here, so that they would all
565
* be in the same place. Easy enough. (jfn, june 1995)
566
*/
567
568
/*
569
* input_forward_word: move the input cursor forward one word in the input
570
* line
571
*/
572
BUILT_IN_KEYBINDING(input_forward_word)
573
{
574
cursor_to_input();
575
576
while ((my_isspace(THIS_CHAR) || ispunct((unsigned char)THIS_CHAR)) && (THIS_CHAR))
577
THIS_POS++;
578
while (!(ispunct((unsigned char)THIS_CHAR) || my_isspace(THIS_CHAR)) && (THIS_CHAR))
579
THIS_POS++;
580
update_input(UPDATE_JUST_CURSOR);
581
}
582
583
/* input_backward_word: move the cursor left on word in the input line */
584
BUILT_IN_KEYBINDING(input_backward_word)
585
{
586
cursor_to_input();
587
while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct((unsigned char)PREV_CHAR)))
588
THIS_POS--;
589
while ((THIS_POS > MIN_POS) && !(ispunct((unsigned char)PREV_CHAR) || my_isspace(PREV_CHAR)))
590
THIS_POS--;
591
592
update_input(UPDATE_JUST_CURSOR);
593
}
594
595
/* inPut_delete_character: deletes a character from the input line */
596
BUILT_IN_KEYBINDING(input_delete_character)
597
{
598
int pos;
599
cursor_to_input();
600
in_completion = STATE_NORMAL;
601
if (!THIS_CHAR)
602
return;
603
ov_strcpy(&THIS_CHAR, &NEXT_CHAR);
604
if (!(termfeatures & TERM_CAN_DELETE))
605
update_input(UPDATE_FROM_CURSOR);
606
else
607
{
608
term_delete(1);
609
pos = INPUT_ONSCREEN + last_input_screen->co - 1;
610
if (pos < strlen(INPUT_BUFFER))
611
{
612
term_move_cursor(last_input_screen->co - 1, INPUT_LINE);
613
term_putchar(INPUT_BUFFER[pos]);
614
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
615
}
616
update_input(NO_UPDATE);
617
}
618
}
619
620
/* input_backspace: does a backspace in the input buffer */
621
BUILT_IN_KEYBINDING(input_backspace)
622
{
623
cursor_to_input();
624
if (THIS_POS > MIN_POS)
625
{
626
char *ptr = NULL;
627
int pos;
628
629
ptr = LOCAL_COPY(&THIS_CHAR);
630
strcpy(&(PREV_CHAR), ptr);
631
THIS_POS--;
632
term_cursor_left();
633
if (THIS_CHAR)
634
{
635
if (!(termfeatures & TERM_CAN_DELETE))
636
update_input(UPDATE_FROM_CURSOR);
637
else
638
{
639
term_delete(1);
640
pos = INPUT_ONSCREEN + last_input_screen->co - 1;
641
/*
642
* If the prompt is visible right now,
643
* then we have to cope with that.
644
*/
645
if (START_ZONE == WIDTH)
646
pos -= INPUT_PROMPT_LEN;
647
if (pos < strlen(INPUT_BUFFER))
648
{
649
term_move_cursor(last_input_screen->co - 1, INPUT_LINE);
650
term_putchar(INPUT_BUFFER[pos]);
651
}
652
update_input(UPDATE_JUST_CURSOR);
653
}
654
}
655
else
656
{
657
term_putchar(' ');
658
#ifndef __EMX__
659
term_cursor_left();
660
update_input(NO_UPDATE);
661
#else
662
update_input(UPDATE_FROM_CURSOR);
663
#endif
664
}
665
}
666
if (THIS_POS == MIN_POS)
667
HOLDLAST = NULL;
668
in_completion = STATE_NORMAL;
669
*new_nick = 0;
670
}
671
672
/*
673
* input_beginning_of_line: moves the input cursor to the first character in
674
* the input buffer
675
*/
676
BUILT_IN_KEYBINDING(input_beginning_of_line)
677
{
678
cursor_to_input();
679
THIS_POS = MIN_POS;
680
update_input(UPDATE_JUST_CURSOR);
681
}
682
683
/*
684
* input_beginning_of_line: moves the input cursor to the first character in
685
* the input buffer
686
*/
687
BUILT_IN_KEYBINDING(new_input_beginning_of_line)
688
{
689
cursor_to_input();
690
THIS_POS = MIN_POS;
691
update_input(UPDATE_JUST_CURSOR);
692
extended_handled = 1;
693
}
694
695
/*
696
* input_end_of_line: moves the input cursor to the last character in the
697
* input buffer
698
*/
699
BUILT_IN_KEYBINDING(input_end_of_line)
700
{
701
cursor_to_input();
702
THIS_POS = strlen(INPUT_BUFFER);
703
update_input(UPDATE_JUST_CURSOR);
704
}
705
706
BUILT_IN_KEYBINDING(input_delete_to_previous_space)
707
{
708
int old_pos;
709
char c;
710
711
cursor_to_input();
712
old_pos = THIS_POS;
713
c = THIS_CHAR;
714
715
while (!my_isspace(THIS_CHAR) && THIS_POS >= MIN_POS)
716
THIS_POS--;
717
718
if (THIS_POS < old_pos)
719
{
720
strcpy(&(NEXT_CHAR), &(INPUT_BUFFER[old_pos]));
721
THIS_POS++;
722
}
723
724
update_input(UPDATE_FROM_CURSOR);
725
}
726
727
728
/*
729
* input_delete_previous_word: deletes from the cursor backwards to the next
730
* space character.
731
*/
732
BUILT_IN_KEYBINDING(input_delete_previous_word)
733
{
734
int old_pos;
735
char c;
736
737
cursor_to_input();
738
old_pos = THIS_POS;
739
while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct((unsigned char)PREV_CHAR)))
740
THIS_POS--;
741
while ((THIS_POS > MIN_POS) && !(ispunct((unsigned char)PREV_CHAR) || my_isspace(PREV_CHAR)))
742
THIS_POS--;
743
c = INPUT_BUFFER[old_pos];
744
INPUT_BUFFER[old_pos] = (char) 0;
745
malloc_strcpy(&cut_buffer, &THIS_CHAR);
746
INPUT_BUFFER[old_pos] = c;
747
strcpy(&(THIS_CHAR), &(INPUT_BUFFER[old_pos]));
748
update_input(UPDATE_FROM_CURSOR);
749
}
750
751
/*
752
* input_delete_next_word: deletes from the cursor to the end of the next
753
* word
754
*/
755
BUILT_IN_KEYBINDING(input_delete_next_word)
756
{
757
int pos;
758
char *ptr = NULL,
759
c;
760
761
cursor_to_input();
762
pos = THIS_POS;
763
while ((my_isspace(INPUT_BUFFER[pos]) || ispunct((unsigned char)INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
764
pos++;
765
while (!(ispunct((unsigned char)INPUT_BUFFER[pos]) || my_isspace(INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
766
pos++;
767
c = INPUT_BUFFER[pos];
768
INPUT_BUFFER[pos] = (char) 0;
769
malloc_strcpy(&cut_buffer, &(THIS_CHAR));
770
INPUT_BUFFER[pos] = c;
771
malloc_strcpy(&ptr, &(INPUT_BUFFER[pos]));
772
strcpy(&(THIS_CHAR), ptr);
773
new_free(&ptr);
774
update_input(UPDATE_FROM_CURSOR);
775
}
776
777
/*
778
* input_add_character: adds the character c to the input buffer, repecting
779
* the current overwrite/insert mode status, etc
780
*/
781
BUILT_IN_KEYBINDING(input_add_character)
782
{
783
int display_flag = NO_UPDATE;
784
785
if (last_input_screen->promptlist)
786
term_echo(last_input_screen->promptlist->echo);
787
788
cursor_to_input();
789
if (THIS_POS >= INPUT_BUFFER_SIZE)
790
{
791
term_echo(1);
792
return;
793
}
794
795
if (get_int_var(INSERT_MODE_VAR))
796
{
797
if (THIS_CHAR)
798
{
799
char *ptr = NULL;
800
801
ptr = alloca(strlen(&(THIS_CHAR)) + 1);
802
strcpy(ptr, &(THIS_CHAR));
803
THIS_CHAR = key;
804
NEXT_CHAR = 0;
805
ADD_TO_INPUT(ptr);
806
if (termfeatures & TERM_CAN_INSERT)
807
term_insert(key);
808
else
809
{
810
term_putchar(key);
811
if (NEXT_CHAR)
812
display_flag = UPDATE_FROM_CURSOR;
813
else
814
display_flag = NO_UPDATE;
815
}
816
}
817
else
818
{
819
THIS_CHAR = key;
820
NEXT_CHAR = 0;
821
term_putchar(key);
822
}
823
}
824
else
825
{
826
if (THIS_CHAR == 0)
827
NEXT_CHAR = 0;
828
THIS_CHAR = key;
829
term_putchar(key);
830
}
831
832
if (!THIS_POS)
833
HOLDLAST = current_window->display_ip;
834
THIS_POS++;
835
#ifdef GUI
836
gui_flush();
837
#endif
838
update_input(display_flag);
839
if (in_completion == STATE_COMPLETE && key == ' ' && input_lastmsg)
840
{
841
new_free(&input_lastmsg);
842
*new_nick = 0;
843
in_completion = STATE_NORMAL;
844
}
845
term_echo(1);
846
}
847
848
/* input_clear_to_eol: erases from the cursor to the end of the input buffer */
849
BUILT_IN_KEYBINDING(input_clear_to_eol)
850
{
851
cursor_to_input();
852
malloc_strcpy(&cut_buffer, &(THIS_CHAR));
853
THIS_CHAR = 0;
854
term_clear_to_eol();
855
update_input(NO_UPDATE);
856
}
857
858
/*
859
* input_clear_to_bol: clears from the cursor to the beginning of the input
860
* buffer
861
*/
862
BUILT_IN_KEYBINDING(input_clear_to_bol)
863
{
864
char *ptr = NULL;
865
cursor_to_input();
866
malloc_strcpy(&cut_buffer, &(MIN_CHAR));
867
cut_buffer[THIS_POS - MIN_POS] = (char) 0;
868
malloc_strcpy(&ptr, &(THIS_CHAR));
869
MIN_CHAR = (char) 0;
870
ADD_TO_INPUT(ptr);
871
new_free(&ptr);
872
THIS_POS = MIN_POS;
873
term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
874
term_clear_to_eol();
875
update_input(UPDATE_FROM_CURSOR);
876
}
877
878
/*
879
* input_clear_line: clears entire input line
880
*/
881
BUILT_IN_KEYBINDING(input_clear_line)
882
{
883
cursor_to_input();
884
malloc_strcpy(&cut_buffer, INPUT_BUFFER + MIN_POS);
885
MIN_CHAR = (char) 0;
886
THIS_POS = MIN_POS;
887
term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
888
term_clear_to_eol();
889
update_input(NO_UPDATE);
890
}
891
892
/*
893
* input_transpose_characters: swaps the positions of the two characters
894
* before the cursor position
895
*/
896
BUILT_IN_KEYBINDING(input_transpose_characters)
897
{
898
cursor_to_input();
899
if (last_input_screen->buffer_pos > MIN_POS)
900
{
901
u_char c1[3] = { 0 };
902
int pos, end_of_line = 0;
903
904
if (THIS_CHAR)
905
pos = THIS_POS;
906
else if (strlen(get_input()) > MIN_POS + 2)
907
{
908
pos = THIS_POS - 1;
909
end_of_line = 1;
910
}
911
else
912
return;
913
914
c1[0] = INPUT_BUFFER[pos];
915
c1[1] = INPUT_BUFFER[pos] = INPUT_BUFFER[pos - 1];
916
INPUT_BUFFER[pos - 1] = c1[0];
917
term_cursor_left();
918
if (end_of_line)
919
term_cursor_left();
920
921
term_putchar(c1[0]);
922
term_putchar(c1[1]);
923
if (!end_of_line)
924
term_cursor_left();
925
update_input(NO_UPDATE);
926
}
927
}
928
929
930
BUILT_IN_KEYBINDING(refresh_inputline)
931
{
932
update_input(UPDATE_ALL);
933
}
934
935
/*
936
* input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
937
* into the input line
938
*/
939
BUILT_IN_KEYBINDING(input_yank_cut_buffer)
940
{
941
char *ptr = NULL;
942
943
if (cut_buffer)
944
{
945
malloc_strcpy(&ptr, &(THIS_CHAR));
946
/* Ooops... */
947
THIS_CHAR = 0;
948
ADD_TO_INPUT(cut_buffer);
949
ADD_TO_INPUT(ptr);
950
new_free(&ptr);
951
update_input(UPDATE_FROM_CURSOR);
952
THIS_POS += strlen(cut_buffer);
953
if (THIS_POS > INPUT_BUFFER_SIZE)
954
THIS_POS = INPUT_BUFFER_SIZE;
955
update_input(UPDATE_JUST_CURSOR);
956
}
957
}
958
959
960
/* used with input_move_cursor */
961
#define RIGHT 1
962
#define LEFT 0
963
964
/* BIND functions: */
965
BUILT_IN_KEYBINDING(forward_character)
966
{
967
input_move_cursor(RIGHT);
968
}
969
970
BUILT_IN_KEYBINDING(backward_character)
971
{
972
input_move_cursor(LEFT);
973
}
974
975
BUILT_IN_KEYBINDING(backward_history)
976
{
977
get_history(PREV);
978
}
979
980
BUILT_IN_KEYBINDING(forward_history)
981
{
982
get_history(NEXT);
983
}
984
985
BUILT_IN_KEYBINDING(toggle_insert_mode)
986
{
987
int tog = get_int_var(INSERT_MODE_VAR);
988
tog ^= 1;
989
set_int_var(INSERT_MODE_VAR, tog);
990
}
991
992
993
BUILT_IN_KEYBINDING(input_msgreply)
994
{
995
char *cmdchar;
996
char *line, *cmd, *t;
997
char *snick;
998
NickTab *nick = NULL;
999
int got_space = 0;
1000
1001
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
1002
cmdchar = DEFAULT_CMDCHARS;
1003
1004
t = line = m_strdup(get_input());
1005
if (t)
1006
got_space = strchr(t, ' ') ? 1 : 0;
1007
cmd = next_arg(line, &line);
1008
snick = next_arg(line, &line);
1009
if ((cmd && *cmd == *cmdchar && got_space) || !cmd)
1010
{
1011
1012
if (cmd && *cmd == *cmdchar)
1013
cmd++;
1014
if (in_completion == STATE_NORMAL && snick)
1015
strncpy(new_nick, snick, sizeof(new_nick)-1);
1016
1017
if ((nick = getnextnick(0, new_nick, input_lastmsg, snick)))
1018
{
1019
if (nick->nick && *(nick->nick))
1020
{
1021
snick = nick->nick;
1022
malloc_strcpy(&input_lastmsg, nick->nick);
1023
}
1024
}
1025
if (nick)
1026
{
1027
char *tmp = NULL;
1028
input_clear_line('\0', NULL);
1029
if (fget_string_var(FORMAT_NICK_MSG_FSET))
1030
malloc_strcpy(&tmp, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_MSG_FSET), "%s%s %s %s", cmdchar, nick->type ? nick->type:cmd?cmd:"msg", nick->nick, line?line:empty_string)));
1031
else
1032
malloc_sprintf(&tmp, "%s%s %s %s", cmdchar, nick->type?nick->type:cmd?cmd:"msg", nick->nick, line?line:empty_string);
1033
set_input(tmp);
1034
new_free(&tmp);
1035
} else
1036
command_completion(0, NULL);
1037
}
1038
else
1039
command_completion(0, NULL);
1040
update_input(UPDATE_ALL);
1041
new_free(&t);
1042
}
1043
1044
BUILT_IN_KEYBINDING(input_msgreplyback)
1045
{
1046
#if 0
1047
char *tmp = NULL;
1048
char *cmdchar;
1049
tmp = gettabkey(-1, 0, NULL);
1050
if (tmp && *tmp)
1051
{
1052
char *tmp1 = NULL;
1053
input_clear_line('\0', NULL);
1054
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
1055
cmdchar = DEFAULT_CMDCHARS;
1056
if (fget_string_var(FORMAT_NICK_MSG_FSET))
1057
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_MSG_FSET), "%cmsg %s", *cmdchar, tmp)));
1058
else
1059
malloc_sprintf(&tmp1, "%cmsg %s ", *cmdchar, tmp);
1060
set_input(tmp1);
1061
new_free(&tmp1);
1062
}
1063
#endif
1064
}
1065
1066
void add_autonick_input(char *nick, char *line)
1067
{
1068
char *tmp1 = NULL;
1069
input_clear_line('\0', NULL);
1070
if ((do_hook(REPLY_AR_LIST, "%s", nick)))
1071
{
1072
if (fget_string_var(FORMAT_NICK_AUTO_FSET))
1073
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_AUTO_FSET), "%s %s", nick, line?line:empty_string)));
1074
else
1075
malloc_sprintf(&tmp1, "%s\002:\002 %s" , nick, line);
1076
set_input(tmp1);
1077
new_free(&tmp1);
1078
}
1079
update_input(UPDATE_ALL);
1080
}
1081
1082
BUILT_IN_KEYBINDING(input_autoreply)
1083
{
1084
char *tmp = NULL, *q;
1085
char *nick = NULL;
1086
char *line = NULL;
1087
1088
q = line = m_strdup(&last_input_screen->input_buffer[MIN_POS]);
1089
if ((nick = next_arg(line, &line)))
1090
{
1091
if ((tmp = strrchr(nick, ':')))
1092
*tmp = 0;
1093
if ((tmp = strrchr(nick, '\002')))
1094
*tmp = 0;
1095
}
1096
if (!input_lastmsg)
1097
{
1098
NickTab *t;
1099
t = gettabkey(1, 1, nick);
1100
if (*new_nick && !tmp)
1101
t = gettabkey(1,1,new_nick);
1102
if (t)
1103
tmp = t->nick;
1104
}
1105
if (tmp && *tmp)
1106
{
1107
add_autonick_input(tmp, line);
1108
strcpy(new_nick, tmp);
1109
}
1110
else
1111
{
1112
tmp = getchannick(input_lastmsg, nick);
1113
if (*new_nick && !tmp)
1114
tmp = getchannick(input_lastmsg, new_nick);
1115
if (tmp)
1116
{
1117
add_autonick_input(tmp, line);
1118
strcpy(new_nick, tmp);
1119
}
1120
}
1121
malloc_strcpy(&input_lastmsg, nick);
1122
in_completion = STATE_COMPLETE;
1123
new_free(&q);
1124
}
1125
1126
BUILT_IN_KEYBINDING(input_autoreplyback)
1127
{
1128
#if 0
1129
char *tmp = NULL;
1130
tmp = gettabkey(-1, 1, NULL);
1131
if (tmp && *tmp)
1132
{
1133
char *tmp1 = NULL;
1134
input_clear_line('\0', NULL);
1135
if ((do_hook(AR_REPLY_LIST, "%s", tmp)))
1136
{
1137
if (fget_int_var(FORMAT_NICK_AUTO_FSET))
1138
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_AUTO_FSET), "%s", tmp)));
1139
else
1140
malloc_sprintf(&tmp1, "%s\002:\002", tmp);
1141
set_input(tmp1);
1142
new_free(&tmp1);
1143
}
1144
}
1145
#endif
1146
}
1147
1148
NickList *BX_lookup_nickcompletion(ChannelList *chan, char *possible)
1149
{
1150
NickList *nick, *ntmp = NULL, *bestmatch = NULL;
1151
for (nick = next_nicklist(chan, NULL); nick; nick = next_nicklist(chan, nick))
1152
{
1153
if (!my_stricmp(possible, nick->nick))
1154
bestmatch = ntmp = nick;
1155
else if (!my_strnicmp(possible, nick->nick, strlen(possible)))
1156
ntmp = nick;
1157
else if (!ntmp && my_strnstr(nick->nick, possible, strlen(possible)))
1158
ntmp = nick;
1159
}
1160
return bestmatch ? bestmatch : ntmp;
1161
}
1162
1163
BUILT_IN_KEYBINDING(send_line)
1164
{
1165
int server;
1166
WaitPrompt *OldPrompt;
1167
1168
server = from_server;
1169
from_server = get_window_server(0);
1170
unhold_a_window(last_input_screen->current_window);
1171
if (last_input_screen->promptlist && last_input_screen->promptlist->type == WAIT_PROMPT_LINE)
1172
{
1173
OldPrompt = last_input_screen->promptlist;
1174
(*OldPrompt->func)(OldPrompt->data, get_input());
1175
set_input(empty_string);
1176
last_input_screen->promptlist = OldPrompt->next;
1177
new_free(&OldPrompt->data);
1178
new_free(&OldPrompt->prompt);
1179
new_free((char **)&OldPrompt);
1180
change_input_prompt(-1);
1181
}
1182
else
1183
{
1184
char *line,
1185
*cmdchar,
1186
*tmp = NULL;
1187
1188
line = get_input();
1189
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
1190
cmdchar = "/";
1191
malloc_strcpy(&tmp, line);
1192
if (line && (*line != *cmdchar) && get_int_var(NICK_COMPLETION_VAR) && !current_window->query_nick)
1193
{
1194
char auto_comp_char;
1195
char *p;
1196
1197
/* this is for people with old BitchX.sav files that set it to '\0' */
1198
if (!(auto_comp_char = (char)get_int_var(NICK_COMPLETION_CHAR_VAR)))
1199
auto_comp_char = DEFAULT_NICK_COMPLETION_CHAR;
1200
1201
/* possible nick completion */
1202
if ((p = strchr(tmp, auto_comp_char)) && do_hook(NICK_COMP_LIST, "%s", line))
1203
{
1204
ChannelList *chan;
1205
NickList *nick;
1206
char *channel;
1207
*p++ = 0;
1208
if (*tmp && *p && (strlen(tmp) >= get_int_var(NICK_COMPLETION_LEN_VAR) && (channel = get_current_channel_by_refnum(0))))
1209
{
1210
chan = lookup_channel(channel, from_server, 0);
1211
nick = lookup_nickcompletion(chan, tmp);
1212
if (nick)
1213
{
1214
if (fget_string_var(FORMAT_NICK_COMP_FSET))
1215
malloc_strcpy(&tmp, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_COMP_FSET), "%s %s", nick->nick, p)));
1216
else
1217
malloc_sprintf(&tmp, "%s\002%c\002%s", nick->nick, auto_comp_char, p);
1218
} else
1219
malloc_strcpy(&tmp, line);
1220
} else
1221
malloc_strcpy(&tmp, line);
1222
}
1223
}
1224
set_input(empty_string);
1225
update_input(UPDATE_ALL);
1226
reset_display_target();
1227
#ifdef WANT_TCL
1228
1229
if (!check_tcl_input(tmp) && do_hook(INPUT_LIST, "%s", tmp))
1230
#else
1231
if (do_hook(INPUT_LIST, "%s", tmp))
1232
#endif
1233
{
1234
if (get_int_var(INPUT_ALIASES_VAR))
1235
parse_line(NULL, tmp, empty_string, 1, 0, 1);
1236
else
1237
parse_line(NULL, tmp, NULL, 1, 0, 1);
1238
}
1239
new_free(&tmp);
1240
}
1241
new_free(&input_lastmsg);
1242
*new_nick = 0;
1243
in_completion = STATE_NORMAL;
1244
HOLDLAST = NULL;
1245
from_server = server;
1246
}
1247
1248
#define METAX(x) \
1249
BUILT_IN_KEYBINDING( meta ## x ## _char ) \
1250
{ last_input_screen->meta_hit = (x); }
1251
METAX(39) METAX(38) METAX(37) METAX(36) METAX(35)
1252
METAX(34) METAX(33) METAX(32) METAX(31) METAX(30)
1253
METAX(29) METAX(28) METAX(27) METAX(26) METAX(25)
1254
METAX(24) METAX(23) METAX(22) METAX(21) METAX(20)
1255
METAX(19) METAX(18) METAX(17) METAX(16) METAX(15)
1256
METAX(14) METAX(13) METAX(12) METAX(11) METAX(10)
1257
METAX(9) METAX(8) METAX(7) METAX(6) METAX(5)
1258
METAX(3) METAX(2) METAX(1)
1259
1260
1261
BUILT_IN_KEYBINDING(meta4_char)
1262
{
1263
if (last_input_screen->meta_hit == 4)
1264
last_input_screen->meta_hit = 0;
1265
else
1266
last_input_screen->meta_hit = 4;
1267
}
1268
1269
BUILT_IN_KEYBINDING(quote_char)
1270
{
1271
last_input_screen->quote_hit = 1;
1272
}
1273
1274
/* These four functions are boomerang functions, which allow the highlight
1275
* characters to be bound by simply having these functions put in the
1276
* appropriate characters when you press any key to which you have bound
1277
* that highlight character. >;-)
1278
*/
1279
BUILT_IN_KEYBINDING(insert_bold)
1280
{
1281
input_add_character (BOLD_TOG, string);
1282
}
1283
1284
BUILT_IN_KEYBINDING(insert_reverse)
1285
{
1286
input_add_character (REV_TOG, string);
1287
}
1288
1289
BUILT_IN_KEYBINDING(insert_underline)
1290
{
1291
input_add_character (UND_TOG, string);
1292
}
1293
1294
BUILT_IN_KEYBINDING(highlight_off)
1295
{
1296
input_add_character (ALL_OFF, string);
1297
}
1298
1299
BUILT_IN_KEYBINDING(insert_blink)
1300
{
1301
input_add_character (BLINK_TOG, string);
1302
}
1303
1304
BUILT_IN_KEYBINDING(insert_altcharset)
1305
{
1306
input_add_character (ALT_TOG, string);
1307
}
1308
1309
/* type_text: the BIND function TYPE_TEXT */
1310
BUILT_IN_KEYBINDING(type_text)
1311
{
1312
if (!string)
1313
return;
1314
for (; *string; string++)
1315
input_add_character(*string, empty_string);
1316
}
1317
1318
/*
1319
* clear_screen: the CLEAR_SCREEN function for BIND. Clears the screen and
1320
* starts it if it is held
1321
*/
1322
BUILT_IN_KEYBINDING(clear_screen)
1323
{
1324
set_hold_mode(NULL, OFF, 1);
1325
clear_window_by_refnum(0);
1326
}
1327
1328
/* parse_text: the bindable function that executes its string */
1329
BUILT_IN_KEYBINDING(parse_text)
1330
{
1331
parse_line(NULL, string, empty_string, 0, 0, 1);
1332
}
1333
1334
/*
1335
* edit_char: handles each character for an input stream. Not too difficult
1336
* to work out.
1337
*/
1338
void edit_char (u_char key)
1339
{
1340
void (*func) (char, char *) = NULL;
1341
char *ptr = NULL;
1342
u_char extended_key;
1343
WaitPrompt *oldprompt;
1344
int xxx_return = 0;
1345
1346
if (dumb_mode)
1347
{
1348
#ifdef TIOCSTI
1349
ioctl(0, TIOCSTI, &key);
1350
#else
1351
say("Sorry, your system doesnt support 'faking' user input...");
1352
#endif
1353
return;
1354
}
1355
1356
/* were we waiting for a keypress? */
1357
if (last_input_screen->promptlist && last_input_screen->promptlist->type == WAIT_PROMPT_KEY)
1358
{
1359
unsigned char key_[2] = "\0";
1360
key_[0] = key;
1361
oldprompt = last_input_screen->promptlist;
1362
last_input_screen->promptlist = oldprompt->next;
1363
(*oldprompt->func)(oldprompt->data, key_);
1364
new_free(&oldprompt->data);
1365
new_free(&oldprompt->prompt);
1366
new_free((char **)&oldprompt);
1367
set_input(empty_string);
1368
change_input_prompt(-1);
1369
xxx_return = 1;
1370
}
1371
if (last_input_screen->promptlist &&
1372
last_input_screen->promptlist->type == WAIT_PROMPT_DUMMY)
1373
{
1374
oldprompt = last_input_screen->promptlist;
1375
(*oldprompt->func)(oldprompt->data, NULL);
1376
last_input_screen->promptlist = oldprompt->next;
1377
new_free(&oldprompt->data);
1378
new_free(&oldprompt->prompt);
1379
new_free((char **)&oldprompt);
1380
}
1381
1382
if (xxx_return)
1383
return;
1384
1385
#if __bsdi__
1386
if (key & 0x80)
1387
{
1388
if (meta_mode)
1389
{
1390
edit_char('\033');
1391
key &= ~0x80;
1392
}
1393
else if (!term_eight_bit())
1394
key &= ~0x80;
1395
}
1396
#endif
1397
1398
#ifdef TRANSLATE
1399
if (translation)
1400
extended_key = transFromClient[key];
1401
else
1402
#endif
1403
extended_key = key;
1404
1405
1406
#ifdef __EMX__
1407
if (key == 0)
1408
key = 27;
1409
#endif
1410
1411
/* did we just hit the quote character? */
1412
if (last_input_screen->quote_hit)
1413
{
1414
last_input_screen->quote_hit = 0;
1415
input_add_character(extended_key, empty_string);
1416
}
1417
else
1418
{
1419
int m = last_input_screen->meta_hit;
1420
int i;
1421
1422
if ((i = get_binding(m, key, &func, &ptr)))
1423
last_input_screen->meta_hit = i;
1424
else if (last_input_screen->meta_hit != 4)
1425
last_input_screen->meta_hit = 0;
1426
if (func)
1427
func(extended_key, SAFE(ptr));
1428
}
1429
}
1430
1431
#ifdef GUI
1432
BUILT_IN_KEYBINDING(paste_to_input)
1433
{
1434
/* Try calling this directly ... */
1435
parse_line(NULL, "//pmpaste -input", NULL, 0, 0, 1);
1436
}
1437
#endif
1438
1439
BUILT_IN_KEYBINDING(my_scrollback)
1440
{
1441
scrollback_backwards(key, string);
1442
extended_handled = 1;
1443
}
1444
1445
BUILT_IN_KEYBINDING(my_scrollforward)
1446
{
1447
scrollback_forwards(key, string);
1448
extended_handled = 1;
1449
}
1450
1451
BUILT_IN_KEYBINDING(my_scrollend)
1452
{
1453
scrollback_end(key, string);
1454
extended_handled = 1;
1455
}
1456
1457
#ifdef WANT_CHELP
1458
BUILT_IN_KEYBINDING(do_chelp)
1459
{
1460
chelp(NULL, "INDEX", NULL, NULL);
1461
extended_handled = 1;
1462
}
1463
#endif
1464
1465
#ifdef WANT_CDCC
1466
BUILT_IN_KEYBINDING(cdcc_plist)
1467
{
1468
l_plist(NULL, NULL);
1469
extended_handled = 1;
1470
}
1471
#endif
1472
1473
BUILT_IN_KEYBINDING(dcc_plist)
1474
{
1475
dcc_glist(NULL, NULL);
1476
extended_handled = 1;
1477
}
1478
1479
BUILT_IN_KEYBINDING(toggle_cloak)
1480
{
1481
if (get_int_var(CLOAK_VAR) == 1 || get_int_var(CLOAK_VAR) == 2)
1482
set_int_var(CLOAK_VAR, 0);
1483
else
1484
set_int_var(CLOAK_VAR, 1);
1485
put_it("CTCP Cloaking is now [\002%s\002]", on_off(get_int_var(CLOAK_VAR)));
1486
extended_handled = 1;
1487
}
1488
1489
1490
extern int in_window_command;
1491
1492
static void handle_swap(int windownum)
1493
{
1494
char *p = NULL;
1495
malloc_sprintf(&p, "SWAP %d", windownum);
1496
windowcmd(NULL, p, NULL, NULL);
1497
set_channel_window(current_window, get_current_channel_by_refnum(current_window->refnum), current_window->server);
1498
new_free(&p);
1499
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
1500
target_window = NULL;
1501
update_input(UPDATE_ALL);
1502
update_all_windows();
1503
}
1504
1505
BUILT_IN_KEYBINDING(window_swap1)
1506
{
1507
handle_swap(1);
1508
extended_handled = 1;
1509
}
1510
1511
BUILT_IN_KEYBINDING(window_swap2)
1512
{
1513
handle_swap(2);
1514
extended_handled = 1;
1515
}
1516
1517
BUILT_IN_KEYBINDING(window_swap3)
1518
{
1519
handle_swap(3);
1520
extended_handled = 1;
1521
}
1522
1523
BUILT_IN_KEYBINDING(window_swap4)
1524
{
1525
handle_swap(4);
1526
extended_handled = 1;
1527
}
1528
1529
BUILT_IN_KEYBINDING(window_swap5)
1530
{
1531
handle_swap(5);
1532
extended_handled = 1;
1533
}
1534
1535
BUILT_IN_KEYBINDING(window_swap6)
1536
{
1537
handle_swap(6);
1538
extended_handled = 1;
1539
}
1540
1541
BUILT_IN_KEYBINDING(window_swap7)
1542
{
1543
handle_swap(7);
1544
extended_handled = 1;
1545
}
1546
BUILT_IN_KEYBINDING(window_swap8)
1547
{
1548
handle_swap(8);
1549
extended_handled = 1;
1550
}
1551
BUILT_IN_KEYBINDING(window_swap9)
1552
{
1553
handle_swap(9);
1554
extended_handled = 1;
1555
}
1556
BUILT_IN_KEYBINDING(window_swap10)
1557
{
1558
handle_swap(10);
1559
extended_handled = 1;
1560
}
1561
1562
BUILT_IN_KEYBINDING(channel_chops)
1563
{
1564
users("chops", "-ops", NULL, NULL);
1565
extended_handled = 1;
1566
}
1567
1568
BUILT_IN_KEYBINDING(channel_nonops)
1569
{
1570
users("nops", "-nonops", NULL, NULL);
1571
extended_handled = 1;
1572
}
1573
1574
#ifdef WANT_CHELP
1575
BUILT_IN_KEYBINDING(w_help)
1576
{
1577
chelp(NULL, "WINDOW", NULL, NULL);
1578
}
1579
#endif
1580
1581
BUILT_IN_KEYBINDING(change_to_split)
1582
{
1583
extern char *last_split_server;
1584
if (!last_split_server)
1585
return;
1586
servercmd(NULL, last_split_server, NULL, NULL);
1587
}
1588
1589
BUILT_IN_KEYBINDING(join_last_invite)
1590
{
1591
if (invite_channel)
1592
{
1593
if (!in_join_list(invite_channel, from_server))
1594
{
1595
win_create(JOIN_NEW_WINDOW_VAR, 0);
1596
send_to_server("JOIN %s", invite_channel);
1597
new_free(&invite_channel);
1598
}
1599
else
1600
bitchsay("Already joining %s", invite_channel);
1601
}
1602
else
1603
bitchsay("You haven't been invited to a channel yet");
1604
}
1605
1606
BUILT_IN_KEYBINDING(wholeft)
1607
{
1608
show_wholeft(NULL);
1609
}
1610
1611
static int oiwc;
1612
static int osu;
1613
1614
BUILT_IN_KEYBINDING(window_key_balance)
1615
{
1616
oiwc = in_window_command;
1617
osu = status_update_flag;
1618
in_window_command = 1;
1619
set_display_target(NULL, LOG_CURRENT);
1620
rebalance_windows(current_window->screen);
1621
in_window_command = oiwc;
1622
status_update_flag = osu;
1623
update_all_windows();
1624
update_all_status(current_window, NULL, 0);
1625
reset_display_target();
1626
}
1627
1628
BUILT_IN_KEYBINDING(window_grow_one)
1629
{
1630
oiwc = in_window_command;
1631
osu = status_update_flag;
1632
in_window_command = 1;
1633
set_display_target(NULL, LOG_CURRENT);
1634
resize_window(1, current_window, 1);
1635
in_window_command = oiwc;
1636
status_update_flag = osu;
1637
update_all_windows();
1638
update_all_status(current_window, NULL, 0);
1639
reset_display_target();
1640
}
1641
1642
BUILT_IN_KEYBINDING(window_key_hide)
1643
{
1644
oiwc = in_window_command;
1645
osu = status_update_flag;
1646
in_window_command = 1;
1647
set_display_target(NULL, LOG_CURRENT);
1648
hide_window(current_window);
1649
in_window_command = oiwc;
1650
status_update_flag = osu;
1651
update_all_windows();
1652
update_all_status(current_window, NULL, 0);
1653
reset_display_target();
1654
}
1655
1656
BUILT_IN_KEYBINDING(window_key_kill)
1657
{
1658
oiwc = in_window_command;
1659
osu = status_update_flag;
1660
in_window_command = 1;
1661
set_display_target(NULL, LOG_CURRENT);
1662
delete_window(current_window);
1663
in_window_command = oiwc;
1664
status_update_flag = osu;
1665
update_all_windows();
1666
update_all_status(current_window, NULL, 0);
1667
reset_display_target();
1668
}
1669
1670
BUILT_IN_KEYBINDING(window_key_list)
1671
{
1672
oiwc = in_window_command;
1673
osu = status_update_flag;
1674
in_window_command = 1;
1675
set_display_target(NULL, LOG_CURRENT);
1676
window_list(current_window, NULL, NULL);
1677
in_window_command = oiwc;
1678
status_update_flag = osu;
1679
reset_display_target();
1680
}
1681
1682
BUILT_IN_KEYBINDING(window_key_move)
1683
{
1684
oiwc = in_window_command;
1685
osu = status_update_flag;
1686
in_window_command = 1;
1687
set_display_target(NULL, LOG_CURRENT);
1688
move_window(current_window, 1);
1689
in_window_command = oiwc;
1690
status_update_flag = osu;
1691
update_all_windows();
1692
update_all_status(current_window, NULL, 0);
1693
reset_display_target();
1694
}
1695
1696
BUILT_IN_KEYBINDING(window_shrink_one)
1697
{
1698
oiwc = in_window_command;
1699
osu = status_update_flag;
1700
in_window_command = 1;
1701
set_display_target(NULL, LOG_CURRENT);
1702
resize_window(1, current_window, -1);
1703
in_window_command = oiwc;
1704
status_update_flag = osu;
1705
update_all_windows();
1706
update_all_status(current_window, NULL, 0);
1707
reset_display_target();
1708
}
1709
1710
BUILT_IN_KEYBINDING(dcc_ostats)
1711
{
1712
set_display_target(NULL, LOG_CURRENT);
1713
extended_handled = 1;
1714
dcc_stats(NULL, NULL);
1715
reset_display_target();
1716
}
1717
1718
BUILT_IN_KEYBINDING(cpu_saver_on)
1719
{
1720
cpu_saver = 1;
1721
update_all_status(current_window, NULL, 0);
1722
}
1723
1724
BUILT_IN_KEYBINDING(input_unclear_screen)
1725
{
1726
set_hold_mode(NULL, OFF, 1);
1727
unclear_window_by_refnum(0);
1728
}
1729
1730
BUILT_IN_KEYBINDING(ignore_last_nick)
1731
{
1732
NickTab *nick;
1733
char *tmp1;
1734
if ((nick = gettabkey(1, 0, NULL)))
1735
{
1736
set_input(empty_string);
1737
tmp1 = m_sprintf("%sig %s", get_string_var(CMDCHARS_VAR), nick->nick);
1738
set_input(tmp1);
1739
new_free(&tmp1);
1740
}
1741
update_input(UPDATE_ALL);
1742
}
1743
1744
BUILT_IN_KEYBINDING(nick_completion)
1745
{
1746
char *q, *line;
1747
int i = -1;
1748
char *nick = NULL, *tmp;
1749
1750
q = line = m_strdup(&last_input_screen->input_buffer[MIN_POS]);
1751
if (in_completion == STATE_NORMAL)
1752
{
1753
i = word_count(line);
1754
nick = extract(line, i-1, i);
1755
}
1756
if (nick)
1757
line[strlen(line)-strlen(nick)] = 0;
1758
else
1759
*line = 0;
1760
if ((tmp = getchannick(input_lastmsg, nick && *nick ? nick : NULL)))
1761
{
1762
malloc_strcat(&q, tmp);
1763
set_input(q);
1764
update_input(UPDATE_ALL);
1765
malloc_strcpy(&input_lastmsg, tmp);
1766
in_completion = STATE_COMPLETE;
1767
}
1768
new_free(&q);
1769
new_free(&nick);
1770
}
1771
1772
char *BX_getchannick (char *oldnick, char *nick)
1773
{
1774
ChannelList *chan;
1775
char *channel, *tnick = NULL;
1776
NickList *cnick;
1777
channel = get_current_channel_by_refnum(0);
1778
if (channel)
1779
{
1780
if (!(chan = lookup_channel(channel, from_server, 0)) || !(cnick = next_nicklist(chan, NULL)))
1781
{
1782
in_completion = STATE_NORMAL;
1783
return NULL;
1784
}
1785
/*
1786
* we've never been here before so return first nick
1787
* user hasn't entered anything on the line.
1788
*/
1789
if (!oldnick && !nick && cnick)
1790
{
1791
in_completion = STATE_CNICK;
1792
return cnick->nick;
1793
}
1794
/*
1795
* user has been here before so we attempt to find the correct
1796
* first nick to start from.
1797
*/
1798
if (oldnick)
1799
{
1800
/* find the old nick so we have a frame of reference */
1801
for(cnick = next_nicklist(chan, NULL); cnick; cnick = next_nicklist(chan, cnick))
1802
{
1803
if (!my_strnicmp(cnick->nick, oldnick, strlen(oldnick)))
1804
{
1805
tnick = cnick->nick;
1806
if ((cnick = next_nicklist(chan, cnick)))
1807
tnick = cnick->nick;
1808
break;
1809
1810
}
1811
1812
}
1813
}
1814
/*
1815
* if the user has put something on the line
1816
* we attempt to pattern match here.
1817
*/
1818
if (nick && in_completion == STATE_NORMAL)
1819
{
1820
/*
1821
* if oldnick was the last one in the channel
1822
* cnick will be NULL;
1823
*/
1824
if (!cnick)
1825
{
1826
cnick = next_nicklist(chan, NULL);
1827
tnick = cnick->nick;
1828
}
1829
/* we have a new nick */
1830
else if (next_nicklist(chan, cnick))
1831
{
1832
/*
1833
* if there's more than one nick, start
1834
* scanning.
1835
*/
1836
for (; cnick; cnick = next_nicklist(chan, cnick))
1837
{
1838
#if 1
1839
if (!my_strnicmp(cnick->nick, nick, strlen(nick)) || my_strnstr(cnick->nick, nick, strlen(nick)))
1840
#else
1841
if (!my_strnicmp(cnick->nick, nick, strlen(nick)))
1842
#endif
1843
{
1844
tnick = cnick->nick;
1845
break;
1846
}
1847
}
1848
#if 1
1849
/* Same as before, make sure bx gets its try w/o ours interfering... */
1850
1851
if (!tnick)
1852
{
1853
for (; cnick; cnick = next_nicklist(chan, cnick))
1854
{
1855
if (my_strnstr(cnick->nick, nick, strlen(nick)))
1856
{
1857
tnick = cnick->nick;
1858
break;
1859
}
1860
}
1861
}
1862
#endif
1863
}
1864
else
1865
tnick = cnick->nick;
1866
}
1867
else if (in_completion == STATE_CNICK)
1868
{
1869
/*
1870
* else we've been here before so
1871
* attempt to continue through the nicks
1872
*/
1873
if (!cnick)
1874
cnick = next_nicklist(chan, NULL);
1875
tnick = cnick->nick;
1876
}
1877
}
1878
if (tnick)
1879
in_completion = STATE_CNICK;
1880
1881
return tnick;
1882
}
1883
1884
/*
1885
* set which to 1 to access autoreply array.
1886
* 0 for msglist array
1887
*/
1888
1889
void BX_addtabkey(char *nick, char *type, int which)
1890
{
1891
NickTab *tmp, *new;
1892
1893
tmp = (which == 1) ? autoreply_array : tabkey_array;
1894
1895
if (!tmp || !(new = (NickTab *)remove_from_list((List **)&tmp, nick)))
1896
{
1897
new = (NickTab *)new_malloc(sizeof(NickTab));
1898
malloc_strcpy(&new->nick, nick);
1899
if (type)
1900
malloc_strcpy(&new->type, type);
1901
}
1902
/*
1903
* most recent nick is at the top of the list
1904
*/
1905
new->next = tmp;
1906
tmp = new;
1907
if (which == 1)
1908
autoreply_array = tmp;
1909
else
1910
tabkey_array = tmp;
1911
}
1912
1913
1914
NickTab *BX_gettabkey(int direction, int which, char *nick)
1915
{
1916
NickTab *tmp, *new;
1917
1918
1919
new = tmp = (which == 1) ? autoreply_array : tabkey_array;
1920
1921
if (nick)
1922
{
1923
for (; tmp; tmp = tmp->next)
1924
if (!my_strnicmp(nick, tmp->nick, strlen(nick)))
1925
return tmp;
1926
return NULL;
1927
}
1928
tmp = new;
1929
if (!tmp)
1930
return NULL;
1931
1932
switch(direction)
1933
{
1934
case 1:
1935
default:
1936
{
1937
/*
1938
* need at least two nicks in the list
1939
*/
1940
if (new->next)
1941
{
1942
/*
1943
* reset top of array
1944
*/
1945
if (which == 1)
1946
autoreply_array = new->next;
1947
else
1948
tabkey_array = new->next;
1949
1950
/*
1951
* set the current nick next pointer to NULL
1952
* and then reset top of list.
1953
*/
1954
1955
new->next = NULL;
1956
if (which == 1)
1957
tmp = autoreply_array;
1958
else
1959
tmp = tabkey_array;
1960
1961
/*
1962
* find the last nick in the list
1963
* so we can make the old top pointer
1964
* point to the item
1965
*/
1966
while (tmp)
1967
if (tmp->next)
1968
tmp = tmp->next;
1969
else
1970
break;
1971
/* set the pointer and then return. */
1972
tmp->next = new;
1973
}
1974
break;
1975
}
1976
case -1:
1977
{
1978
if (new && new->next)
1979
{
1980
tmp = new;
1981
while(tmp)
1982
if (tmp->next && tmp->next->next)
1983
tmp = tmp->next;
1984
else
1985
break;
1986
/*
1987
* tmp now points at last two items in list
1988
* now just swap some pointers.
1989
*/
1990
new = tmp->next;
1991
tmp->next = NULL;
1992
if (which == 1)
1993
{
1994
new->next = autoreply_array;
1995
autoreply_array = new;
1996
} else {
1997
new->next = tabkey_array;
1998
tabkey_array = new;
1999
}
2000
}
2001
break;
2002
}
2003
}
2004
if (new && new->nick)
2005
return new;
2006
return NULL;
2007
}
2008
2009
NickTab *BX_getnextnick(int which, char *input_nick, char *oldnick, char *nick)
2010
{
2011
ChannelList *chan;
2012
NickList *cnick = NULL;
2013
NickTab *tmp = (which == 1) ? autoreply_array : tabkey_array;
2014
int server = from_server;
2015
static NickTab sucks = { NULL };
2016
2017
if (tmp && (in_completion == STATE_NORMAL || in_completion == STATE_TABKEY))
2018
{
2019
2020
2021
if (!oldnick && !nick && tmp)
2022
{
2023
in_completion = STATE_TABKEY;
2024
return tmp;
2025
}
2026
if (oldnick)
2027
{
2028
for (; tmp; tmp = tmp->next)
2029
{
2030
if (!my_strnicmp(oldnick, tmp->nick, strlen(oldnick)))
2031
break;
2032
}
2033
/* nick was not in the list. oops didn't come from here */
2034
if (!tmp && in_completion == STATE_TABKEY)
2035
tmp = (which == 1) ? autoreply_array : tabkey_array;
2036
else if (tmp)
2037
tmp = tmp->next;
2038
}
2039
if (nick && in_completion != STATE_TABKEY)
2040
{
2041
if (tmp && tmp->next)
2042
{
2043
for (; tmp; tmp = tmp->next)
2044
if (!my_strnicmp(nick, tmp->nick, strlen(nick)))
2045
break;
2046
}
2047
}
2048
if (tmp)
2049
{
2050
in_completion = STATE_TABKEY;
2051
return tmp;
2052
}
2053
}
2054
2055
if ((chan = prepare_command(&server, NULL, PC_SILENT)))
2056
{
2057
cnick = next_nicklist(chan, NULL);
2058
/*
2059
* we've never been here before so return first nick
2060
* user hasn't entered anything on the line.
2061
*/
2062
if (!oldnick && !nick && cnick)
2063
{
2064
in_completion = STATE_CNICK;
2065
sucks.nick = cnick->nick;
2066
return &sucks;
2067
}
2068
/*
2069
* user has been here before so we attempt to find the correct
2070
* first nick to start from.
2071
*/
2072
if (oldnick)
2073
{
2074
/* find the old nick so we have a frame of reference */
2075
for (; cnick; cnick = next_nicklist(chan, cnick))
2076
{
2077
if (!my_strnicmp(cnick->nick, oldnick, strlen(oldnick)))
2078
{
2079
cnick = next_nicklist(chan, cnick);
2080
break;
2081
}
2082
}
2083
}
2084
/*
2085
* if the user has put something on the line
2086
* we attempt to pattern match here.
2087
*/
2088
if (input_nick)
2089
{
2090
/*
2091
* if oldnick was the last one in the channel
2092
* cnick will be NULL;
2093
*/
2094
if (!cnick && oldnick)
2095
cnick = next_nicklist(chan, NULL);
2096
/* we have a new nick */
2097
else if (cnick)
2098
{
2099
/*
2100
* if there's more than one nick, start
2101
* scanning.
2102
*/
2103
for (;cnick; cnick = next_nicklist(chan, cnick))
2104
{
2105
if (!my_strnicmp(cnick->nick, input_nick, strlen(input_nick)) || !strcasecmp(cnick->nick, input_nick))
2106
break;
2107
}
2108
}
2109
}
2110
else if (in_completion == STATE_CNICK)
2111
{
2112
/*
2113
* else we've been here before so
2114
* attempt to continue through the nicks
2115
*/
2116
/*
2117
if (!cnick)
2118
cnick = chan->nicks;
2119
*/
2120
}
2121
}
2122
if (!cnick)
2123
in_completion = STATE_NORMAL;
2124
else
2125
in_completion = STATE_CNICK;
2126
if (cnick)
2127
sucks.nick = cnick->nick;
2128
return sucks.nick ? &sucks : NULL;
2129
}
2130
2131
2132
#ifdef WANT_TABKEY
2133
2134
#define TABDEBUG
2135
2136
struct _name_type {
2137
char name[10];
2138
int len;
2139
};
2140
2141
struct _name_type
2142
name_type[] = {
2143
{"MP3", 3},
2144
{"DCC", 3},
2145
{"EXEC",4},
2146
{"LS", 2},
2147
{"LOAD",4},
2148
{"SERVER",6},
2149
{"CDCC",4},
2150
{"MSG", 1},
2151
{"KB", 2},
2152
{"CD", 2},
2153
{ "", 0}};
2154
2155
enum tab_types { MP3 = 0, DCC, EXEC, LS, LOAD, SERVER, CDCC, IMSG, KB, CHDIR};
2156
2157
typedef struct _ext_name_type {
2158
struct _ext_name_type *next;
2159
char *name;
2160
int len;
2161
enum completion type;
2162
} Ext_Name_Type;
2163
2164
Ext_Name_Type *ext_completion = NULL;
2165
2166
char *get_home_dir(char *possible, int *count)
2167
{
2168
#ifdef HAVE_GETPWENT
2169
struct passwd *pw;
2170
char *booya = NULL;
2171
int len = 0;
2172
char *q;
2173
char str[BIG_BUFFER_SIZE+1];
2174
(*count) = 0;
2175
if (possible)
2176
{
2177
possible++;
2178
len = strlen(possible);
2179
}
2180
while ((pw = getpwent()))
2181
{
2182
*str = 0;
2183
if ((q = strrchr(pw->pw_dir, '/')))
2184
q++;
2185
if (possible && *possible && q && strncmp(possible, q, len))
2186
continue;
2187
if (q && *q)
2188
{
2189
strmopencat(str, BIG_BUFFER_SIZE, "~", q, NULL);
2190
m_s3cat(&booya, space, str);
2191
}
2192
else
2193
m_s3cat(&booya, space, pw->pw_dir);
2194
(*count)++;
2195
}
2196
endpwent();
2197
if (*count)
2198
return booya;
2199
#endif
2200
return NULL;
2201
}
2202
2203
char *get_completions(enum completion type, char *possible, int *count, char **suggested)
2204
{
2205
char *booya = NULL;
2206
char *path = NULL;
2207
char *path2, *freeme;
2208
glob_t globbers;
2209
int numglobs = 0, i;
2210
int globtype = GLOB_MARK;
2211
2212
#if defined(__EMX__) || defined(WINNT)
2213
if (possible && *possible)
2214
convert_unix(possible);
2215
#endif
2216
2217
switch(type)
2218
{
2219
case SERVER_COMPLETION:
2220
{
2221
for (i = 0; i < server_list_size(); i++)
2222
{
2223
if (possible && my_strnicmp(possible, get_server_name(i), strlen(possible)))
2224
continue;
2225
m_s3cat(&booya, space, get_server_name(i));
2226
(*count)++;
2227
}
2228
return booya;
2229
}
2230
case TABKEY_COMPLETION:
2231
{
2232
NickTab *n = tabkey_array;
2233
*count = 0;
2234
if (possible)
2235
{
2236
if (*possible == '#' || *possible == '&')
2237
{
2238
ChannelList *chan;
2239
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
2240
{
2241
if (my_strnicmp(possible, chan->channel, strlen(possible)))
2242
continue;
2243
m_s3cat(&booya, space, chan->channel);
2244
(*count)++;
2245
}
2246
}
2247
else
2248
{
2249
for ( ; n; n = n->next)
2250
{
2251
if (possible && my_strnicmp(possible, n->nick, strlen(possible)))
2252
continue;
2253
m_s3cat(&booya, space, n->nick);
2254
(*count)++;
2255
}
2256
if (*count == 1 && !strcmp(possible, booya))
2257
{
2258
new_free(&booya);
2259
(*count) = 0;
2260
possible = NULL;
2261
}
2262
}
2263
}
2264
if (((*count) == 0) || ((*count) == 1))
2265
{
2266
/*
2267
* nothing specified for a match.
2268
* so grab the first one, if available.
2269
* or, only one match was available.
2270
*/
2271
if (possible && count == 0)
2272
possible = NULL;
2273
if ((n = gettabkey(1, 0, possible)) && !booya)
2274
{
2275
(*count) = 1;
2276
booya = m_strdup(n->nick);
2277
if (suggested)
2278
*suggested = n->type;
2279
}
2280
}
2281
return booya;
2282
}
2283
case COM_COMPLETION:
2284
command_completion(0, NULL);
2285
return NULL;
2286
case CHAN_COMPLETION:
2287
{
2288
NickList *cnick = NULL;
2289
ChannelList *chan = NULL;
2290
int server = from_server;
2291
chan = prepare_command(&server, NULL, PC_SILENT);
2292
if (possible && (*possible == '#' || *possible == '&'))
2293
{
2294
int len = strlen(possible);
2295
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
2296
{
2297
if ((len == 1) || (len >= 2 && !my_strnicmp(possible, chan->channel, len)))
2298
{
2299
(*count)++;
2300
m_s3cat(&booya, space, chan->channel);
2301
}
2302
}
2303
}
2304
else if (chan)
2305
{
2306
cnick = next_nicklist(chan, NULL);
2307
for (; cnick; cnick = next_nicklist(chan, cnick))
2308
{
2309
if (possible && my_strnicmp(cnick->nick, possible, strlen(possible)))
2310
continue;
2311
(*count)++;
2312
m_s3cat(&booya, space, cnick->nick);
2313
}
2314
}
2315
if (!booya)
2316
{
2317
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
2318
{
2319
cnick = next_nicklist(chan, NULL);
2320
for (; cnick; cnick = next_nicklist(chan, cnick))
2321
{
2322
if (possible && my_strnicmp(cnick->nick, possible, strlen(possible)))
2323
continue;
2324
(*count)++;
2325
m_s3cat(&booya, space, cnick->nick);
2326
}
2327
}
2328
}
2329
return booya;
2330
}
2331
case LOAD_COMPLETION:
2332
{
2333
if (!possible)
2334
path = m_sprintf("~/.BitchX/");
2335
else
2336
{
2337
if (*possible == '/' || *possible == '~' || *possible == '.')
2338
path = m_sprintf("%s*", possible);
2339
else
2340
path = m_sprintf("~/%s*", possible);
2341
}
2342
break;
2343
}
2344
case EXEC_COMPLETION:
2345
{
2346
if (!possible)
2347
#if !defined(__EMX__) && !defined(WINNT)
2348
path = m_sprintf("/usr/bin/*");
2349
#elif defined(__EMX__)
2350
path = m_sprintf("C:/OS2/*.EXE");
2351
#elif defined(WINNT) /* Might need something for WinNT itself C:/WINNT/SYSTEM32/ *.EXE */
2352
path = m_sprintf("C:/WINDOWS/COMMAND/*.EXE");
2353
#endif
2354
else
2355
{
2356
if (*possible == '~' && (*(possible+1) != '/'))
2357
{
2358
if ((booya = get_home_dir(possible, count)))
2359
return booya;
2360
}
2361
#if defined(__EMX__) || defined(WINNT)
2362
if (*possible == '/' || *possible == '~' || *possible == '.' || (strlen(possible) > 3 && *(possible+1) == ':' && *(possible+2) == '/'))
2363
path = m_sprintf("%s*.EXE", possible);
2364
else
2365
path = m_sprintf("~/%s*.EXE", possible);
2366
#else
2367
if (*possible == '/' || *possible == '~' || *possible == '.')
2368
path = m_sprintf("%s*", possible);
2369
else
2370
path = m_sprintf("~/%s*", possible);
2371
#endif
2372
}
2373
break;
2374
}
2375
case CDCC_COMPLETION:
2376
case DCC_COMPLETION:
2377
{
2378
char *dl = get_string_var(DCC_DLDIR_VAR);
2379
if (!possible)
2380
path = m_sprintf("%s%s%s", dl, strrchr(dl, '/')?empty_string:"/", "*");
2381
else
2382
{
2383
if (*possible == '~' && (*(possible+1) != '/'))
2384
{
2385
if ((booya = get_home_dir(possible, count)))
2386
return booya;
2387
}
2388
#if defined(__EMX__) || defined(WINNT)
2389
if (*possible == '/' || *possible == '~' || *possible == '.' || (strlen(possible) > 3 && *(possible+1) == ':' && *(possible+2) == '/'))
2390
#else
2391
if (*possible == '/' || *possible == '~' || *possible == '.')
2392
#endif
2393
path = m_sprintf("%s*", possible);
2394
else
2395
path = m_sprintf("~/%s*", possible);
2396
}
2397
break;
2398
}
2399
case FILE_COMPLETION:
2400
{
2401
globtype |= GLOB_TILDE;
2402
if (!possible)
2403
path = m_sprintf("~/*");
2404
else if (*possible == '~' && (*(possible+1) != '/'))
2405
{
2406
if ((booya = get_home_dir(possible, count)))
2407
return booya;
2408
path = m_strdup(possible);
2409
}
2410
else if (*possible == '/' || *possible == '~' || *possible == '.')
2411
path = m_sprintf("%s*", possible);
2412
else
2413
path = m_sprintf("~/%s*", possible);
2414
#if 0
2415
path = m_sprintf("%s%s%s", possible, strrchr(possible, '/') ? empty_string: "/", strchr(possible, '*')?empty_string:"*");
2416
#endif
2417
break;
2418
}
2419
default:
2420
return NULL;
2421
}
2422
#ifdef NEED_GLOB
2423
#define glob bsd_glob
2424
#define globfree bsd_globfree
2425
#endif
2426
freeme = path2 = expand_twiddle(path);
2427
if (!path2)
2428
path2 = path;
2429
memset(&globbers, 0, sizeof(glob_t));
2430
numglobs = glob(path2, globtype, NULL, &globbers);
2431
for (i = 0; i < globbers.gl_pathc; i++)
2432
{
2433
if (strchr(globbers.gl_pathv[i], ' '))
2434
{
2435
int len = strlen(globbers.gl_pathv[i])+4;
2436
char *b = alloca(len+1);
2437
*b = 0;
2438
strmopencat(b, len, "\"", globbers.gl_pathv[i], "\"", NULL);
2439
m_s3cat(&booya, space, b);
2440
}
2441
else
2442
m_s3cat(&booya, space, globbers.gl_pathv[i]);
2443
(*count)++;
2444
}
2445
globfree(&globbers);
2446
new_free(&freeme);
2447
new_free(&path);
2448
return booya;
2449
}
2450
2451
/*
2452
* this is an oddball routine that attempts to figure out where
2453
* the last char is in the completes array, that is equal in all
2454
* the array conditions. when found it sets the input prompt to the
2455
* command [inp] and the greatest amount of chars found common in all
2456
* array elements.
2457
*/
2458
void set_input_best(enum completion type, char *inp, char *old, int count, char **completes)
2459
{
2460
int i,
2461
c,
2462
j = 0,
2463
match = 0;
2464
char buffer[BIG_BUFFER_SIZE+1];
2465
2466
match = strlen(old);
2467
if (count == 2)
2468
{
2469
#if !defined(__EMX__) && !defined(WINNT)
2470
if (type == CHAN_COMPLETION || type == NICK_COMPLETION || type == TABKEY_COMPLETION)
2471
i = strieq(completes[0], completes[1]);
2472
else
2473
#endif
2474
i = streq(completes[0], completes[1]);
2475
completes[0][i] = 0;
2476
}
2477
else
2478
{
2479
int getout;
2480
i = match - 1;
2481
while (1)
2482
{
2483
getout = 0;
2484
c = 1;
2485
for (j = 1; j < count; j++)
2486
{
2487
if (!completes[0][i] || !completes[j][i])
2488
break;
2489
#if defined(__EMX__) || defined(WINNT)
2490
if (toupper(completes[0][i]) == toupper(completes[j][i]))
2491
c++;
2492
#else
2493
if (type == CHAN_COMPLETION || type == NICK_COMPLETION || type == TABKEY_COMPLETION)
2494
{
2495
if (toupper(completes[0][i]) == toupper(completes[j][i]))
2496
c++;
2497
else
2498
{
2499
getout = 1;
2500
break;
2501
}
2502
}
2503
else
2504
{
2505
if (completes[0][i] == completes[j][i])
2506
c++;
2507
else
2508
{
2509
getout = 1;
2510
break;
2511
}
2512
}
2513
#endif
2514
}
2515
if ((c != count) || getout)
2516
break;
2517
i++;
2518
}
2519
if (i)
2520
completes[0][i] = 0;
2521
}
2522
if (old && *old)
2523
{
2524
if (strchr(completes[0], ' '))
2525
sprintf(buffer, "%s%s\"%s\"", inp, space, i ? completes[0] : old);
2526
else
2527
sprintf(buffer, "%s%s%s", inp, space, i ? completes[0] : old);
2528
}
2529
else
2530
strcpy(buffer, completes[0]);
2531
if (strcmp(buffer, get_input()))
2532
set_input(buffer);
2533
if (strchr(completes[0], ' '))
2534
THIS_POS = strlen(INPUT_BUFFER) - 1;
2535
}
2536
2537
BUILT_IN_KEYBINDING(tab_completion)
2538
{
2539
int count = 0,
2540
wcount = 0;
2541
enum completion type = NO_COMPLETION;
2542
char *inp = NULL;
2543
char *possible = NULL, *old_pos = NULL;
2544
char *cmdchar;
2545
char *suggested = NULL;
2546
int got_space = 0;
2547
char *get = NULL;
2548
Ext_Name_Type *extcomp = ext_completion;
2549
2550
/*
2551
* is this the != second word, then just complete from the
2552
* channel nicks. if it is the second word, grab the first word, and
2553
* this is used to determine what type of nick completion will be
2554
* done.
2555
*/
2556
inp = alloca(strlen(get_input())+2);
2557
strcpy(inp, get_input() ? get_input() : empty_string);
2558
2559
if (*inp && inp[strlen(inp)-1] == ' ')
2560
got_space = 1;
2561
wcount = word_count(inp);
2562
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
2563
cmdchar = "/";
2564
switch(wcount)
2565
{
2566
case 0:
2567
{
2568
type = TABKEY_COMPLETION;
2569
break;
2570
}
2571
case 1:
2572
{
2573
if (*inp != *cmdchar)
2574
{
2575
type = CHAN_COMPLETION;
2576
possible = m_strdup(get_input());
2577
break;
2578
}
2579
else if (!got_space)
2580
{
2581
type = COM_COMPLETION;
2582
break;
2583
}
2584
}
2585
default:
2586
{
2587
char *p, *old_p;
2588
int i, got_comp = 0;
2589
2590
old_p = p = extract(inp, 0, 0);
2591
if (wcount > 1)
2592
old_pos = possible = extract(inp, wcount-1, EOS);
2593
if ((*p == *cmdchar))
2594
p++;
2595
if (possible && (*possible == '"'))
2596
{
2597
possible++;
2598
if (*possible)
2599
chop(possible, 1);
2600
else
2601
possible = NULL;
2602
}
2603
if (type == NO_COMPLETION)
2604
type = CHAN_COMPLETION;
2605
for (i = 0; *p && name_type[i].len; i++)
2606
{
2607
if (!my_strnicmp(p, name_type[i].name, name_type[i].len/*strlen(p)*/))
2608
{
2609
got_comp = 1;
2610
switch(i)
2611
{
2612
case IMSG:
2613
case KB:
2614
type = TABKEY_COMPLETION;
2615
break;
2616
case DCC:
2617
if (wcount <= 3 && !got_space)
2618
type = TABKEY_COMPLETION;
2619
else
2620
type = DCC_COMPLETION;
2621
if (wcount == 3 && got_space)
2622
{
2623
new_free(&old_pos);
2624
possible = NULL;
2625
}
2626
break;
2627
case EXEC:
2628
type = EXEC_COMPLETION;
2629
break;
2630
case CHDIR:
2631
case MP3:
2632
case LS:
2633
type = FILE_COMPLETION;
2634
break;
2635
case LOAD:
2636
type = LOAD_COMPLETION;
2637
break;
2638
case SERVER:
2639
type = SERVER_COMPLETION;
2640
break;
2641
case CDCC:
2642
if (wcount == 2 || wcount == 3)
2643
type = CDCC_COMPLETION;
2644
break;
2645
}
2646
break;
2647
}
2648
}
2649
if (!got_comp)
2650
{
2651
for (extcomp = ext_completion; extcomp; extcomp = extcomp->next)
2652
{
2653
if (!my_strnicmp(p, extcomp->name, extcomp->len))
2654
{
2655
type = extcomp->type;
2656
break;
2657
}
2658
}
2659
}
2660
new_free(&old_p);
2661
break;
2662
}
2663
}
2664
#ifdef TABDEBUG1
2665
put_it("type = %s", type == TABKEY_COMPLETION ? "TABKEY":
2666
type == CHAN_COMPLETION? "CHAN" :
2667
type == COM_COMPLETION? "COMMAND":
2668
type == EXEC_COMPLETION? "EXEC":
2669
type == FILE_COMPLETION? "FILE":
2670
type == DCC_COMPLETION? "DCC":
2671
"NO_COMPLETION");
2672
#endif
2673
do_more_tab:
2674
count = 0;
2675
if ((get = get_completions(type, possible, &count, &suggested)))
2676
{
2677
char buffer[BIG_BUFFER_SIZE+1];
2678
char *p = NULL;
2679
char *old = NULL;
2680
*buffer = 0;
2681
if (count == 1)
2682
{
2683
if (wcount > 1)
2684
p = extract(get_input(), 0, wcount - 2);
2685
else if (suggested && *suggested)
2686
p = m_3dup("/", suggested, "");
2687
if (type == TABKEY_COMPLETION)
2688
snprintf(buffer, BIG_BUFFER_SIZE, "%s %s%s%s ", (p && *p == '/') ? p : "/m", get, (p && (*p != '/'))?space:empty_string, (p && (*p != '/'))?p:empty_string);
2689
else
2690
{
2691
if (wcount == 1 && got_space)
2692
snprintf(buffer, BIG_BUFFER_SIZE, "%s %s ", get_input(), get);
2693
else
2694
snprintf(buffer, BIG_BUFFER_SIZE, "%s%s%s ", p ? p : get, p ? space : empty_string, p ? get : empty_string);
2695
}
2696
if ((type == CDCC_COMPLETION || type == LOAD_COMPLETION || type == FILE_COMPLETION || type == DCC_COMPLETION) || ((type == EXEC_COMPLETION) && (get[strlen(get)-1] == '/')))
2697
chop(buffer, 1);
2698
set_input(buffer);
2699
if (strchr(get, ' '))
2700
THIS_POS = strlen(INPUT_BUFFER) - 1;
2701
new_free(&p);
2702
}
2703
else
2704
{
2705
char **completes = NULL;
2706
int c = 0, matches = count;
2707
RESIZE(completes, char *, count+1);
2708
if (wcount > 1)
2709
{
2710
if (!got_space)
2711
{
2712
old = inp;
2713
old = last_arg(&inp);
2714
if ((*old == '"'))
2715
{
2716
old++;
2717
chop(old, 1);
2718
}
2719
}
2720
}
2721
switch(type)
2722
{
2723
case LOAD_COMPLETION:
2724
case DCC_COMPLETION:
2725
case FILE_COMPLETION:
2726
case CDCC_COMPLETION:
2727
{
2728
char *n, *use = get;
2729
bitchsay("Found %d files/dirs", count);
2730
n = new_next_arg(use, &use);
2731
while (n && *n)
2732
{
2733
put_it("%s", n);
2734
completes[c++] = n;
2735
n = new_next_arg(use, &use);
2736
}
2737
break;
2738
}
2739
case EXEC_COMPLETION:
2740
{
2741
char *n, *q, *use = get;
2742
char path[BIG_BUFFER_SIZE+1];
2743
*path = 0;
2744
memset(path, 0, sizeof(path));
2745
n = new_next_arg(use, &use);
2746
if ((q = strrchr(n, '/')) && *(q+1))
2747
{
2748
strncpy(path, n, q - n + 1);
2749
bitchsay("path = %s", path);
2750
}
2751
count = 0;
2752
while (n && *n)
2753
{
2754
if ((q = strrchr(n, '/')) && *(q+1))
2755
q++;
2756
else
2757
q = n;
2758
strmcat(buffer, q, BIG_BUFFER_SIZE);
2759
strmcat(buffer, space, BIG_BUFFER_SIZE);
2760
if (++count == 4)
2761
{
2762
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
2763
count = 0;
2764
*buffer = 0;
2765
}
2766
completes[c++] = n;
2767
n = new_next_arg(use, &use);
2768
}
2769
if (count)
2770
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
2771
break;
2772
}
2773
case SERVER_COMPLETION:
2774
case TABKEY_COMPLETION:
2775
case CHAN_COMPLETION:
2776
{
2777
char *n, *use = get;
2778
n = new_next_arg(use, &use);
2779
count = 0;
2780
while (n && *n)
2781
{
2782
strmcat(buffer, n, BIG_BUFFER_SIZE);
2783
strmcat(buffer, space, BIG_BUFFER_SIZE);
2784
if (++count == 4)
2785
{
2786
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
2787
count = 0;
2788
*buffer = 0;
2789
}
2790
completes[c++] = n;
2791
n = new_next_arg(use, &use);
2792
}
2793
if (count)
2794
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
2795
break;
2796
}
2797
case NO_COMPLETION:
2798
break;
2799
default:
2800
put_it("get = %s[%d]", get, count);
2801
2802
}
2803
if (old && c)
2804
set_input_best(type, inp, old, matches, completes);
2805
new_free((char **)&completes);
2806
}
2807
update_input(UPDATE_ALL);
2808
}
2809
else if (type == TABKEY_COMPLETION)
2810
{
2811
if (get_current_channel_by_refnum(0))
2812
{
2813
type = CHAN_COMPLETION;
2814
goto do_more_tab;
2815
}
2816
}
2817
new_free(&get);
2818
new_free(&old_pos);
2819
return;
2820
}
2821
2822
int BX_add_completion_type(char *name, int len, enum completion type)
2823
{
2824
Ext_Name_Type *new;
2825
if (!find_in_list((List **)&ext_completion, name, 0))
2826
{
2827
new = (Ext_Name_Type *)new_malloc(sizeof(Ext_Name_Type));
2828
new->name = m_strdup(name);
2829
new->len = len;
2830
new->type = type;
2831
add_to_list((List **)&ext_completion, (List *)new);
2832
return 1;
2833
}
2834
return 0;
2835
}
2836
2837
#endif
2838
2839
/*
2840
* type: The TYPE command. This parses the given string and treats each
2841
* character as though it were typed in by the user. Thus key bindings
2842
* are used for each character parsed. Special case characters are control
2843
* character sequences, specified by a ^ follow by a legal control key.
2844
* Thus doing "/TYPE ^B" will be as tho ^B were hit at the keyboard,
2845
* probably moving the cursor backward one character.
2846
*
2847
* This was moved from keys.c, because it certainly does not belong there,
2848
* and this seemed a reasonable place for it to go for now.
2849
*/
2850
BUILT_IN_COMMAND(type)
2851
{
2852
int c;
2853
char key;
2854
2855
while (*args)
2856
{
2857
if (*args == '^')
2858
{
2859
switch (*(++args))
2860
{
2861
case '?':
2862
{
2863
key = '\177';
2864
args++;
2865
break;
2866
}
2867
default:
2868
{
2869
c = *(args++);
2870
if (islower(c))
2871
c = toupper(c);
2872
if (c < 64)
2873
{
2874
say("Invalid key sequence: ^%c", c);
2875
return;
2876
}
2877
key = c - 64;
2878
break;
2879
}
2880
}
2881
}
2882
else if (*args == '\\')
2883
{
2884
key = *++args;
2885
args++;
2886
}
2887
else
2888
key = *(args++);
2889
2890
edit_char(key);
2891
}
2892
}
2893
2894
2895