1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis
3 * This file is part of JED editor library source.
4 *
5 * You may distribute this file under the terms the GNU General Public
6 * License. See the file COPYING for more information.
7 */
8 #include "config.h"
9 #include "jed-feat.h"
10 /*{{{ Include Files */
11
12 #include <stdio.h>
13 #include <slang.h>
14
15 #include "jdmacros.h"
16
17 #include <string.h>
18 #include <setjmp.h>
19 #include <stdarg.h>
20
21 #include "buffer.h"
22 #include "screen.h"
23 #include "window.h"
24 #include "display.h"
25 #include "sysdep.h"
26 #include "file.h"
27 #include "keymap.h"
28 #include "ledit.h"
29 #include "misc.h"
30 #include "ins.h"
31 #include "paste.h"
32
33 /*}}}*/
34
35 /*{{{ Global Variables */
36
37 /* Do not malloc these without changing occurances of sizeof() first */
38 char Error_Buffer[256];
39 int Exit_From_MiniBuffer;
40
41 static unsigned char Macro_Buffer[JED_KBD_MACRO_SIZE];
42 unsigned char *Macro_Buffer_Ptr = Macro_Buffer;
43 static unsigned char *Macro_Ptr_Max = Macro_Buffer;
44 int Defining_Keyboard_Macro = 0;
45 int Executing_Keyboard_Macro = 0;
46
47 MiniInfo_Type Mini_Info;
48
49 /*}}}*/
50
51 typedef struct /*{{{*/
52 {
53 jmp_buf b;
54 }
55
56 /*}}}*/
57 jmp_buf_struct;
58
59 extern jmp_buf_struct Jump_Buffer, *Jump_Buffer_Ptr;
60
61 static struct /*{{{*/
62 {
63 int def;
64 int exe;
65 }
66
67 /*}}}*/
68 Macro_State;
69
macro_store_key(char ch)70 static void macro_store_key(char ch) /*{{{*/
71 {
72 /* I need to put something here to increase the size of the Macro_Buffer
73 in case of overflow */
74
75 if (Macro_Buffer_Ptr - Macro_Buffer >= JED_KBD_MACRO_SIZE) msg_error("Macro Size exceeded.");
76 else *Macro_Buffer_Ptr++ = ch;
77 }
78
79 /*}}}*/
80
restore_macro_state(void)81 static void restore_macro_state(void) /*{{{*/
82 {
83 Defining_Keyboard_Macro = Macro_State.def;
84 Executing_Keyboard_Macro = Macro_State.exe;
85 }
86
87 /*}}}*/
88
set_macro_state(void)89 static void set_macro_state(void) /*{{{*/
90 {
91 Macro_State.def = Defining_Keyboard_Macro;
92 Macro_State.exe = Executing_Keyboard_Macro;
93 }
94
95 /*}}}*/
96
jed_abort_keyboard_macro(void)97 void jed_abort_keyboard_macro (void)
98 {
99 Defining_Keyboard_Macro = Executing_Keyboard_Macro = 0;
100 set_macro_state();
101 }
102
103 /* if not in the mini buffer and if during keyboard macro, allow user to enter
104 different text each time macro is executed */
105
macro_query()106 int macro_query() /*{{{*/
107 {
108 char *s;
109 int n;
110
111 /* macro state is already set */
112 Defining_Keyboard_Macro = 0;
113 Executing_Keyboard_Macro = 0;
114
115 if (!IN_MINI_WINDOW)
116 {
117 if (NULL == (s = read_from_minibuffer("Enter String:", (char *) NULL, NULL, &n))) return(0);
118 (void) jed_insert_nbytes ((unsigned char *) s, n);
119 SLfree(s);
120 }
121
122 /* exit from mini restores the state */
123 return(1);
124 }
125
126 /*}}}*/
127
jed_check_string_key_buffer(void)128 int jed_check_string_key_buffer (void)
129 {
130 int ch, ch1;
131
132 if (Read_This_Character == NULL)
133 return -1;
134
135 ch = *Read_This_Character++;
136 if (ch == 0)
137 {
138 Read_This_Character = NULL;
139 return -1;
140 }
141
142 if ((ch1 = *Read_This_Character) == 0)
143 {
144 Read_This_Character = NULL;
145 return ch;
146 }
147
148 if (ch == '^')
149 {
150 if (ch1 == '?') ch = 127;
151 else ch = ch1 - '@';
152 Read_This_Character++;
153 }
154 else if (ch == '\\')
155 {
156 ch = ch1;
157 Read_This_Character++;
158 }
159 if (*Read_This_Character == 0) Read_This_Character = NULL;
160
161 return ch;
162 }
163
164
165
jed_getkey(void)166 int jed_getkey (void) /*{{{*/
167 {
168 int ch, diff;
169 static int mini_flag = 0;
170 int *srf;
171
172 ch = jed_check_string_key_buffer ();
173 if (ch != -1)
174 return ch;
175
176 if (Executing_Keyboard_Macro)
177 {
178 if (Macro_Buffer_Ptr < Macro_Ptr_Max) return (*Macro_Buffer_Ptr++);
179 Executing_Keyboard_Macro = 0;
180 #if JED_HAS_MENUS
181 /* This means that the macro was stopped from a menu */
182 if (Jed_Menus_Active)
183 (void) jed_exit_menu_bar ();
184 #endif
185 update((Line *) NULL, 0, 0, 1);
186 }
187
188 diff = (int) (Key_Bufferp - Key_Buffer);
189 if ((SLang_get_error () == 0)
190 && SLang_Key_TimeOut_Flag
191 && ((mini_flag && (diff > 0))
192 || !input_pending(&Number_Ten)))
193 {
194 message(Key_Buffer);
195 safe_strcat(Message_Buffer, "-", sizeof(Message_Buffer));
196
197 /* This ensures that the update is performed if we are echoing from
198 * digit argument */
199 srf = Repeat_Factor; Repeat_Factor = NULL;
200 update((Line *)NULL, 0, 0, 1);
201 Repeat_Factor = srf;
202 clear_message ();
203 mini_flag = 1;
204 }
205 else (mini_flag = 0);
206
207 ch = my_getkey();
208 if (diff < SLANG_MAX_KEYMAP_KEY_SEQ)
209 {
210 *Key_Bufferp++ = (char) ch;
211 *Key_Bufferp = 0;
212 }
213 else
214 {
215 /* msg_error("KeyBuffer overflow!"); */
216 Key_Bufferp = Key_Buffer;
217 }
218
219
220 if (Defining_Keyboard_Macro)
221 {
222 /* starting a new keysequence to save this point */
223 if (diff == 0)
224 {
225 Macro_Ptr_Max = Macro_Buffer_Ptr;
226 }
227
228 macro_store_key(ch);
229 }
230 return(ch);
231 }
232
233 /*}}}*/
234
jed_error_hook(SLFUTURE_CONST char * msg)235 void jed_error_hook (SLFUTURE_CONST char *msg)
236 {
237 if ((JWindow == NULL) || Batch)
238 fprintf(stderr, "%s\r\n", msg);
239 else
240 JWindow->trashed = 1;
241
242 if (Error_Buffer[0] == 0)
243 safe_strcpy(Error_Buffer, msg, sizeof (Error_Buffer));
244 }
245
msg_error(char * msg)246 void msg_error(char *msg) /*{{{*/
247 {
248 #if 0
249 Defining_Keyboard_Macro = Executing_Keyboard_Macro = 0;
250 Read_This_Character = NULL;
251 Repeat_Factor = NULL;
252 set_macro_state();
253 #endif
254 SLang_verror (SL_INTRINSIC_ERROR, "%s", msg);
255 }
256
257 /*}}}*/
258
259 /* read from minibuffer using prompt providing a default, and stuffing
260 the minibuffer with init if necessary */
261 /* I should make recursive mini buffers */
read_from_minibuffer_1(char * prompt,char * deflt,char * what,int * n)262 static char *read_from_minibuffer_1 (char *prompt, char *deflt, char *what, int *n) /*{{{*/
263 {
264 char buf[JED_MAX_PATH_LEN];
265 jmp_buf_struct *mini_jmp_save, mini_jmp_buf;
266 unsigned char *ps;
267 unsigned char *p, ch;
268 static Window_Type *current_window;
269 /* may get changed if user leaves minibuffer and returns from other
270 * window which means that the new window becomes target
271 * of minibuffer action
272 */
273 Window_Type *w;
274 char *ret;
275 int len;
276 Buffer *start_buffer;
277
278 if (Batch)
279 {
280 if (prompt != NULL)
281 fputs (prompt, stdout);
282 if ((deflt != NULL) && (*deflt != 0))
283 fprintf (stdout, "(default %s)", deflt);
284
285 fflush (stdout);
286
287 *n = 0;
288 if (NULL == fgets (buf, sizeof(buf), stdin))
289 {
290 SLang_verror (SL_Read_Error, "Read from stdin failed");
291 return NULL;
292 }
293
294 if (NULL == (ret = SLmake_string (buf)))
295 return NULL;
296
297 len = strlen (ret);
298 if (len && (ret[len-1] == '\n'))
299 {
300 len--;
301 ret[len] = 0;
302 }
303 *n = (int) len;
304 return ret;
305 }
306
307 if (!IN_MINI_WINDOW)
308 {
309 current_window = JWindow;
310 start_buffer = CBuf;
311 }
312 else
313 {
314 current_window = NULL;
315 start_buffer = NULL;
316 }
317
318 if (select_minibuffer()) return(NULL); /* we should be on a new line of mini buffer */
319
320 ps = Mini_Info.prompt;
321 p = (unsigned char *) prompt;
322 len = 0;
323
324 if (p != NULL)
325 {
326 while (0 != (ch = *p++))
327 {
328 *ps++ = ch;
329 len++;
330 }
331 *ps++ = ' ';
332 len++;
333 }
334
335 if ((deflt != NULL) && (*deflt != 0))
336 {
337 SLsnprintf (buf, sizeof (buf), "(default: %s) ", deflt);
338 p = (unsigned char *) buf;
339
340 while (0 != (ch = *p++))
341 {
342 *ps++ = ch;
343 len++;
344 }
345 }
346 *ps = 0;
347
348 Mini_Info.prompt_len = len;
349 Mini_Info.effective_prompt_len = jed_compute_effective_length (Mini_Info.prompt, Mini_Info.prompt + len);
350
351 touch_window();
352 if (what != NULL) jed_insert_string(what);
353 update((Line *) NULL, 0, 0, 1);
354
355 mini_jmp_save = Jump_Buffer_Ptr;
356 Jump_Buffer_Ptr = &mini_jmp_buf;
357
358 if (setjmp(mini_jmp_buf.b) != 0)
359 {
360 /* Do not call the restart function from here, in case this function
361 * has been called from the interpreter.
362 */
363 /* SLang_restart(1); */
364 update((Line *) NULL, 0, 0, 1);
365 }
366
367 while(!Exit_From_MiniBuffer)
368 {
369 int err = 0;
370 do_jed();
371
372 err = SLang_get_error ();
373 if (((err == SL_USER_BREAK) || SLKeyBoard_Quit)
374 && IN_MINI_WINDOW)
375 break;
376
377 update((Line *) NULL, 0, 0, 1);
378 if (err)
379 {
380 SLang_restart (0);
381 SLang_set_error (0);
382 SLKeyBoard_Quit = 0;
383 }
384 }
385
386 if (Exit_From_MiniBuffer && !Executing_Keyboard_Macro
387 && (Repeat_Factor == NULL) && !JWindow->trashed && !input_pending(&Number_Zero))
388 {
389 SLsmg_gotorc (Jed_Num_Screen_Rows - 1, 0);
390 SLsmg_refresh ();
391 }
392
393 Jump_Buffer_Ptr = mini_jmp_save;
394
395 exit_minibuffer (); /* be graceful */
396
397 Exit_From_MiniBuffer = 0;
398 MiniBuffer_Active = 0;
399 restore_macro_state();
400
401 if (!SLKeyBoard_Quit)
402 {
403 if (CLine->len == 0)
404 {
405 if (deflt != NULL) jed_insert_string(deflt);
406 }
407 bob();
408 jed_push_mark();
409 eob();
410 ret = make_buffer_substring(n);
411 }
412 else
413 {
414 SLKeyBoard_Quit = 0;
415 ret = NULL;
416 }
417
418 /* we should be in minibuffer so delete marks and spots */
419 while (CBuf->spots) pop_spot();
420 while (CBuf->marks) jed_pop_mark(0);
421 erase_buffer();
422
423 /* Remove MiniWindow from the ring */
424 w = JWindow;
425 while (w->next != JWindow) w = w->next;
426 other_window();
427 w->next = JWindow;
428
429 if (current_window != NULL)
430 {
431 /* Note that by this time, current_window might not exist. */
432 while((JWindow != current_window) && (JWindow != w))
433 other_window();
434 }
435
436 if ((start_buffer != NULL)
437 && (buffer_exists (start_buffer)))
438 switch_to_buffer (start_buffer);
439
440 JWindow->trashed = 1;
441
442 /* delete_buffer(MiniBuffer); */
443 MiniBuffer = NULL;
444
445 #if JED_HAS_MENUS
446 jed_notify_menu_buffer_changed ();
447 #endif
448
449 return(ret);
450 }
451
452 /*}}}*/
453
read_from_minibuffer(char * prompt,char * deflt,char * what,int * n)454 char *read_from_minibuffer (char *prompt, char *deflt, char *what, int *n)
455 {
456 int *rf = Repeat_Factor;
457 int repeat = 0;
458 char *s;
459
460 if (rf != NULL)
461 repeat = *rf;
462
463 s = read_from_minibuffer_1 (prompt, deflt, what, n);
464
465 if (rf != NULL)
466 {
467 Repeat_Factor = rf;
468 *rf = repeat;
469 }
470
471 return s;
472 }
473
474 static int Macro_Illegal_Now = 0;
check_macro_legality(void)475 static int check_macro_legality(void) /*{{{*/
476 {
477 if (Macro_Illegal_Now)
478 {
479 msg_error("Illegal context for Macro definition.");
480 return (0);
481 }
482 return (1);
483 }
484
485 /*}}}*/
486
begin_keyboard_macro()487 int begin_keyboard_macro() /*{{{*/
488 {
489 if (!check_macro_legality()) return (0);
490
491 Macro_Buffer_Ptr = Macro_Buffer;
492 message("Defining Macro.");
493 Defining_Keyboard_Macro = 1;
494 set_macro_state();
495 return(1);
496 }
497
498 /*}}}*/
499
end_keyboard_macro()500 int end_keyboard_macro() /*{{{*/
501 {
502
503 if (Defining_Keyboard_Macro) message("Macro Defined.");
504 else
505 {
506 if (!Executing_Keyboard_Macro) msg_error("Not defining Macro!");
507 Executing_Keyboard_Macro = 0;
508 return(1);
509 }
510
511 /* Macro_Ptr_Max = Macro_Buffer_Ptr; */
512 Defining_Keyboard_Macro = 0;
513 set_macro_state();
514 return(1);
515 }
516
517 /*}}}*/
518
execute_keyboard_macro()519 int execute_keyboard_macro() /*{{{*/
520 {
521 int repeat = 0, *repeat_ptr;
522
523 if (!check_macro_legality()) return (0);
524
525 if (Defining_Keyboard_Macro)
526 {
527 msg_error("Can't execute a macro while defining one.");
528 return(0);
529 }
530
531 Executing_Keyboard_Macro = 1;
532 set_macro_state();
533 Macro_Buffer_Ptr = Macro_Buffer;
534
535 /* save the repeat context */
536 repeat_ptr = Repeat_Factor;
537 if (repeat_ptr != NULL) repeat = *repeat_ptr;
538
539 JWindow->trashed = 1;
540 Macro_Illegal_Now = 1;
541 while ((Macro_Buffer_Ptr < Macro_Ptr_Max)
542 && Executing_Keyboard_Macro) /* since we might enter minibuffer
543 and stop macro before returning
544 here */
545 {
546 Repeat_Factor = NULL;
547 /* ch = *Macro_Buffer_Ptr++; */
548 (void) jed_do_key();
549 if (SLKeyBoard_Quit || (*Error_Buffer)) break;
550 }
551 Macro_Illegal_Now = 0;
552
553 /* restore context */
554 Repeat_Factor = repeat_ptr;
555 if (repeat_ptr != NULL) *repeat_ptr = repeat;
556 Executing_Keyboard_Macro = 0;
557 #if JED_HAS_MENUS
558 /* This means that the macro was stopped from a menu */
559 if (Jed_Menus_Active)
560 (void) jed_exit_menu_bar ();
561 #endif
562 set_macro_state();
563 return(1);
564 }
565
566 /*}}}*/
567
get_last_macro()568 void get_last_macro () /*{{{*/
569 {
570 unsigned char *m, *s;
571 unsigned char buf[2 * JED_KBD_MACRO_SIZE + 1];
572
573 if (Defining_Keyboard_Macro)
574 {
575 msg_error("Complete Macro first!");
576 return;
577 }
578
579 m = Macro_Buffer;
580 if (m == Macro_Ptr_Max)
581 {
582 msg_error("Macro not defined.");
583 return;
584 }
585 s = buf;
586 while (m < Macro_Ptr_Max)
587 {
588 unsigned char ch = *m++;
589 if ((ch < ' ') || (ch == 127))
590 {
591 *s++ = '^';
592 if (ch == 127) ch = '?'; else ch = '@' + ch;
593 }
594 else if ((ch == '^') || (ch == '\\'))
595 {
596 *s++ = '\\';
597 }
598
599 *s++ = (char)ch;
600 }
601 *s = 0;
602 SLang_push_string ((char *)buf);
603 }
604
605 /*}}}*/
606
safe_strcpy(char * a,SLFUTURE_CONST char * b,unsigned int n)607 char *safe_strcpy (char *a, SLFUTURE_CONST char *b, unsigned int n) /*{{{*/
608 {
609 if (n != 0)
610 {
611 n--;
612 strncpy (a, b, n);
613 a[n] = 0;
614 }
615 return a;
616 }
617
618 /*}}}*/
619
safe_strcat(char * a,SLFUTURE_CONST char * b,unsigned int n)620 char *safe_strcat (char *a, SLFUTURE_CONST char *b, unsigned int n) /*{{{*/
621 {
622 unsigned int len = strlen (a);
623 unsigned int max;
624
625 n--;
626
627 if (n > len)
628 {
629 max = n - len;
630 strncpy (a + len, b, max);
631 a[n] = 0;
632 }
633 return a;
634 }
635
636 /*}}}*/
637
jed_vmessage(int now,char * fmt,...)638 void jed_vmessage (int now, char *fmt, ...)
639 {
640 va_list ap;
641 char buf[2048];
642
643 va_start (ap, fmt);
644 SLvsnprintf (buf, sizeof (buf), fmt, ap);
645 va_end (ap);
646
647 if (now) flush_message (buf);
648 else message (buf);
649 }
650
jed_verror(char * fmt,...)651 void jed_verror (char *fmt, ...)
652 {
653 va_list ap;
654 char buf[2048];
655
656 va_start (ap, fmt);
657 SLvsnprintf (buf, sizeof (buf), fmt, ap);
658 va_end (ap);
659
660 msg_error (buf);
661 }
662
663 /* Since the interpreter deals mainly with hashed strings, and there is
664 * the possibility that the strings to be compared are the same, we
665 * will exploit this fact.
666 */
667
jed_case_strncmp(char * a,char * b,unsigned int n)668 int jed_case_strncmp (char *a, char *b, unsigned int n)
669 {
670 register unsigned char cha, chb;
671 char *bmax;
672
673 if (a == b) return 0;
674 bmax = b + n;
675 while (b < bmax)
676 {
677 cha = UPPER_CASE(*a);
678 chb = UPPER_CASE(*b);
679
680 if (cha != chb)
681 return (int) cha - (int) chb;
682 if (chb == 0) return 0;
683 a++;
684 b++;
685 }
686 return 0;
687 }
688
jed_case_strcmp(char * a,char * b)689 int jed_case_strcmp (char *a, char *b)
690 {
691 register unsigned char cha, chb;
692
693 if (a == b) return 0;
694 while (1)
695 {
696 cha = UPPER_CASE(*a);
697 chb = UPPER_CASE(*b);
698
699 if (cha != chb)
700 return (int) cha - (int) chb;
701 if (chb == 0) return 0;
702 a++;
703 b++;
704 }
705 }
706
jed_malloc0(unsigned int len)707 char *jed_malloc0 (unsigned int len)
708 {
709 char *s = SLmalloc (len);
710 if (s != NULL)
711 memset ((char *) s, 0, len);
712 return s;
713 }
714
jed_get_mini_action_buffer(void)715 Buffer *jed_get_mini_action_buffer (void)
716 {
717 Window_Type *w;
718
719 if (IN_MINI_WINDOW == 0)
720 return NULL;
721
722 w = Mini_Info.action_window;
723
724 if (w != NULL)
725 {
726 Buffer *b = w->buffer;
727 if (buffer_exists (b))
728 return b;
729 }
730 return NULL;
731 }
732
733 /* Returns 0, if the keysequence is valid, otherwise returns -1. */
jed_getkey_wchar(SLwchar_Type * wchp)734 int jed_getkey_wchar (SLwchar_Type *wchp)
735 {
736 int ch;
737 #if JED_HAS_UTF8_SUPPORT
738 SLuchar_Type buf[SLUTF8_MAX_MBLEN+1];
739 unsigned int i;
740 #endif
741
742 ch = jed_getkey ();
743 *wchp = (SLwchar_Type) ch;
744
745 #if JED_HAS_UTF8_SUPPORT
746 if ((ch < 128) || (Jed_UTF8_Mode == 0))
747 return 0;
748
749 buf[0] = (SLuchar_Type) ch;
750 i = 1;
751 while (1)
752 {
753 unsigned int n;
754 if (NULL != SLutf8_decode (buf, buf+i, wchp, &n))
755 break;
756 if ((i == SLUTF8_MAX_MBLEN) || (ch < 128))
757 {
758 ungetkey_string ((char *)buf + 1, i-1);
759 *wchp = buf[0];
760 return -1;
761 }
762 ch = jed_getkey ();
763 buf[i] = (SLuchar_Type) ch;
764 i++;
765 }
766 #endif
767 return 0;
768 }
769
jed_ungetkey_wchar(SLwchar_Type wc)770 void jed_ungetkey_wchar (SLwchar_Type wc)
771 {
772 #if JED_HAS_UTF8_SUPPORT
773 SLuchar_Type *b, buf[JED_MAX_MULTIBYTE_SIZE];
774
775 if (NULL == (b = jed_wchar_to_multibyte (wc, buf)))
776 return;
777
778 ungetkey_string ((char *)buf, (int)(b-buf));
779 #endif
780 }
781
782
783 #if SLANG_VERSION < 10410
SLang_get_error(void)784 int SLang_get_error (void)
785 {
786 return SLang_Error;
787 }
788
SLang_set_error(int e)789 int SLang_set_error (int e)
790 {
791 SLang_Error = e;
792 return 0;
793 }
794
795 #endif
796