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