1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998 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 #include "kanji.h"
33 
34 /*}}}*/
35 
36 /*{{{ Global Variables */
37 
38 char Error_Buffer[256];
39 char Message_Buffer[256];
40 int Exit_From_MiniBuffer;
41 
42 #if defined(__unix__) || defined(VMS)
43 # define MACRO_SIZE 4096
44 #else
45 # define MACRO_SIZE 256
46 #endif
47 
48 char Macro_Buffer[MACRO_SIZE];
49 char *Macro_Buffer_Ptr = Macro_Buffer;
50 char *Macro_Ptr_Max = Macro_Buffer;
51 int Defining_Keyboard_Macro = 0;
52 int Executing_Keyboard_Macro = 0;
53 
54 MiniInfo_Type Mini_Info;
55 
56 /*}}}*/
57 
58 typedef struct /*{{{*/
59 {
60    jmp_buf b;
61 }
62 
63 /*}}}*/
64 jmp_buf_struct;
65 
66 extern jmp_buf_struct Jump_Buffer, *Jump_Buffer_Ptr;
67 
68 static struct /*{{{*/
69 {
70    int def;
71    int exe;
72 }
73 
74 /*}}}*/
75 Macro_State;
76 
macro_store_key(char ch)77 static void macro_store_key(char ch) /*{{{*/
78 {
79    /* I need to put something here to increase the size of the Macro_Buffer
80       in case of overflow */
81 
82    if (Macro_Buffer_Ptr - Macro_Buffer >= MACRO_SIZE) msg_error("Macro Size exceeded.");
83    else *Macro_Buffer_Ptr++ = ch;
84 }
85 
86 /*}}}*/
87 
restore_macro_state(void)88 static void restore_macro_state(void) /*{{{*/
89 {
90    Defining_Keyboard_Macro = Macro_State.def;
91    Executing_Keyboard_Macro = Macro_State.exe;
92 }
93 
94 /*}}}*/
95 
set_macro_state(void)96 static void set_macro_state(void) /*{{{*/
97 {
98    Macro_State.def = Defining_Keyboard_Macro;
99    Macro_State.exe = Executing_Keyboard_Macro;
100 }
101 
102 /*}}}*/
103 
104 /* if not in the mini buffer and if during keyboard macro, allow user to enter
105    different text each time macro is executed */
106 
macro_query()107 int macro_query() /*{{{*/
108 {
109    char *s;
110    int n;
111 
112    /* macro state is already set */
113    Defining_Keyboard_Macro = 0;
114    Executing_Keyboard_Macro = 0;
115 
116    if (!IS_MINIBUFFER)
117      {
118 	if (NULL == (s = read_from_minibuffer("Enter String:", (char *) NULL, NULL, &n))) return(0);
119 	ins_chars((unsigned char *) s, n);
120 	SLfree(s);
121      }
122 
123    /* exit from mini restores the state */
124    return(1);
125 }
126 
127 /*}}}*/
128 
jed_check_string_key_buffer(void)129 int jed_check_string_key_buffer (void)
130 {
131    int ch, ch1;
132 
133    if (Read_This_Character == NULL)
134      return -1;
135 
136    ch = *Read_This_Character++;
137    if (ch == 0)
138      {
139 	Read_This_Character = NULL;
140 	return -1;
141      }
142 
143    if ((ch1 = *Read_This_Character) == 0)
144      {
145 	Read_This_Character = NULL;
146 	return ch;
147      }
148 
149    if (ch == '^')
150      {
151 	if (ch1 == '?') ch = 127;
152 	else ch = ch1 - '@';
153 	Read_This_Character++;
154      }
155    else if (ch == '\\')
156      {
157 	ch = ch1;
158 	Read_This_Character++;
159      }
160    if (*Read_This_Character == 0) Read_This_Character = NULL;
161 
162    return ch;
163 }
164 
165 
166 
jed_getkey(void)167 int jed_getkey (void) /*{{{*/
168 {
169    int ch, diff;
170    static int mini_flag = 0;
171    int *srf;
172    static int kflg = FALSE;
173 
174    ch = jed_check_string_key_buffer ();
175    if (ch != -1)
176      return ch;
177 
178    if (Executing_Keyboard_Macro)
179      {
180 	if (Macro_Buffer_Ptr < Macro_Ptr_Max) return (*Macro_Buffer_Ptr++);
181 	Executing_Keyboard_Macro = 0;
182 #if JED_HAS_MENUS
183 	/* This means that the macro was stopped from a menu */
184 	if (Jed_Menus_Active)
185 	  (void) jed_exit_menu_bar ();
186 #endif
187 	update((Line *) NULL, 0, 0);
188      }
189 
190    diff = (int) (Key_Bufferp - Key_Buffer);
191    if (!SLang_Error && SLang_Key_TimeOut_Flag &&
192        ((mini_flag && (diff > 0))
193 	|| !input_pending(&Number_Ten)))
194      {
195 	message(Key_Buffer);
196 	strcat(Message_Buffer, "-");
197 
198 	/* This ensures that the update is performed if we are echoing from
199 	 * digit argument */
200 	srf = Repeat_Factor; Repeat_Factor = NULL;
201 	update((Line *)NULL, 0, 0);
202 	Repeat_Factor = srf;
203 	clear_message ();
204 	mini_flag = 1;
205      }
206    else (mini_flag = 0);
207 
208    ch = jed_kanji_getkey();
209    if(kflg) kflg = FALSE;
210    else if(iskanji(ch)) kflg = TRUE;
211 
212    if (diff < SLANG_MAX_KEYMAP_KEY_SEQ)
213      {
214 	if(kflg && diff == (SLANG_MAX_KEYMAP_KEY_SEQ - 1)) Key_Bufferp = Key_Buffer;
215 	*Key_Bufferp++ = (char) ch;
216 	*Key_Bufferp = 0;
217      }
218    else
219      {
220 	/* msg_error("KeyBuffer overflow!"); */
221 	Key_Bufferp = Key_Buffer;
222      }
223 
224 
225    if (Defining_Keyboard_Macro)
226      {
227 	/* starting a new keysequence to save this point */
228 	if (diff == 0)
229 	  {
230 	     Macro_Ptr_Max = Macro_Buffer_Ptr;
231 	  }
232 
233 	macro_store_key((char)ch);
234      }
235    return(ch);
236 }
237 
238 /*}}}*/
239 
msg_error(char * msg)240 void msg_error(char *msg) /*{{{*/
241 {
242    Defining_Keyboard_Macro = Executing_Keyboard_Macro = 0;
243    /* flush_input(); */
244    JWindow->trashed = 1;
245    Read_This_Character = NULL;
246    Repeat_Factor = NULL;
247    set_macro_state();
248    if (Batch) fprintf(stderr, "%s\n", msg);
249 
250    if (!SLang_Error) SLang_Error = INTRINSIC_ERROR;
251    if (Error_Buffer[0] == 0) safe_strcpy(Error_Buffer, msg, sizeof (Error_Buffer));
252 }
253 
254 /*}}}*/
255 
256 /* later I will do more with this-- for now, keep last one */
message(char * msg)257 void message (char *msg) /*{{{*/
258 {
259    char *p;
260    int i;
261 
262    if (Executing_Keyboard_Macro) return;
263    if (msg == NULL) msg = "";
264    i = strlen(msg);
265 
266    if (Batch)
267      {
268 	fprintf(stdout, "%s\n", msg);
269 	p = KanjiCodeConv(msg, &i, kSLcode, kSLdisplay_code, 0);
270 	fprintf(stderr, "%s\n", p);
271 	if(p != msg)	SLfree(p);
272      }
273    if (*msg == 0)
274      Mini_Ghost = 1;
275 
276    strncpy(Message_Buffer, msg, 255);
277    Message_Buffer[255] = 0;
278 }
279 
280 /*}}}*/
281 
282 /* read from minibuffer using prompt providing a default, and stuffing
283    the minibuffer with init if necessary */
284 /* I should make recursive mini buffers */
read_from_minibuffer(char * prompt,char * deflt,char * what,int * n)285 char *read_from_minibuffer (char *prompt, char *deflt, char *what, int *n) /*{{{*/
286 {
287    char buf[JED_MAX_PATH_LEN];
288    jmp_buf_struct *mini_jmp_save, mini_jmp_buf;
289    unsigned char *ps;
290    unsigned char *p, ch;
291 
292    static Window_Type *current_window;
293    /* may get changed if user leaves minibuffer and returns from other
294     * window which means that the new window becomes target
295     * of minibuffer action
296     */
297    Window_Type *w;
298    char *ret;
299    int len;
300 
301    if (!IS_MINIBUFFER) current_window = JWindow;
302    if (select_minibuffer()) return(NULL);   /* we should be on a new line of mini buffer */
303 
304    ps = Mini_Info.prompt;
305    p = (unsigned char *) prompt;
306    len = 0;
307 
308    if (p != NULL)
309      {
310 	while (0 != (ch = *p++))
311 	  {
312 	     *ps++ = ch;
313 	     len++;
314 	  }
315 	*ps++ =  ' ';
316 	len++;
317      }
318 
319    if ((deflt != NULL) && (*deflt != 0))
320      {
321 	sprintf(buf,"(default: %s) ", deflt);
322 	p = (unsigned char *) buf;
323 
324 	while (0 != (ch = *p++))
325 	  {
326 	     *ps++ = ch;
327 	     len++;
328 	  }
329      }
330    *ps = 0;
331 
332    Mini_Info.prompt_len = len;
333    Mini_Info.effective_prompt_len = jed_compute_effective_length (Mini_Info.prompt, Mini_Info.prompt + len);
334 
335    touch_window();
336    if (what != NULL) insert_string(what);
337    update((Line *) NULL, 0, 0);
338 
339    mini_jmp_save = Jump_Buffer_Ptr;
340    Jump_Buffer_Ptr = &mini_jmp_buf;
341 
342    if (setjmp(mini_jmp_buf.b) != 0)
343      {
344 	SLang_restart(1);   /* just in case */
345 	update((Line *) NULL, 0, 0);
346      }
347 
348    while(!Exit_From_MiniBuffer)
349      {
350 	do_jed();
351 	/* if (setjmp(Jump_Buffer) != 0)
352 	 * {
353 	 * Exit_From_MiniBuffer = 1;
354 	 * }  */
355 
356 	if (SLKeyBoard_Quit && IS_MINIBUFFER) break;
357 	update((Line *) NULL, 0, 0);
358      }
359 
360    if (Exit_From_MiniBuffer && !Executing_Keyboard_Macro
361        && (Repeat_Factor == NULL) && !JWindow->trashed && !input_pending(&Number_Zero))
362      {
363 	SLsmg_gotorc (Jed_Num_Screen_Rows - 1, 0);
364 	SLsmg_refresh ();
365      }
366 
367    Jump_Buffer_Ptr = mini_jmp_save;
368 
369    exit_minibuffer ();		       /* be graceful */
370 
371    Exit_From_MiniBuffer = 0;
372    MiniBuffer_Active = 0;
373    restore_macro_state();
374 
375    if (!SLKeyBoard_Quit)
376      {
377 	if (CLine->len == 0)
378 	  {
379 	     if (deflt != NULL) insert_string(deflt);
380 	  }
381 	bob();
382 	push_mark();
383 	eob();
384 	ret = make_buffer_substring(n);
385      }
386    else ret = NULL;
387 
388    /* we should be in minibuffer so delete marks and spots */
389    while (CBuf->spots) pop_spot();
390    while (CBuf->marks) pop_mark(&Number_Zero);
391    erase_buffer();
392 
393    /* Remove MiniWindow from the ring */
394    w = JWindow;
395    while (w->next != JWindow) w = w->next;
396    other_window();
397    w->next = JWindow;
398 
399    /* Note that by this time, current_window might be history. */
400    while((JWindow != current_window) && (JWindow != w)) other_window();
401    JWindow->trashed = 1;
402 
403    /* delete_buffer(MiniBuffer); */
404    MiniBuffer = NULL;
405    return(ret);
406 }
407 
408 /*}}}*/
409 
410 static int Macro_Illegal_Now = 0;
check_macro_legality(void)411 static int check_macro_legality(void) /*{{{*/
412 {
413    if (Macro_Illegal_Now)
414      {
415 	msg_error("Illegal context for Macro definition.");
416 	return (0);
417      }
418    return (1);
419 }
420 
421 /*}}}*/
422 
begin_keyboard_macro()423 int begin_keyboard_macro() /*{{{*/
424 {
425    if (!check_macro_legality()) return (0);
426 
427    Macro_Buffer_Ptr = Macro_Buffer;
428    message("Defining Macro.");
429    Defining_Keyboard_Macro = 1;
430    set_macro_state();
431    return(1);
432 }
433 
434 /*}}}*/
435 
end_keyboard_macro()436 int end_keyboard_macro() /*{{{*/
437 {
438 
439    if (Defining_Keyboard_Macro) message("Macro Defined.");
440    else
441      {
442 	if (!Executing_Keyboard_Macro) msg_error("Not defining Macro!");
443 	Executing_Keyboard_Macro = 0;
444 	return(1);
445      }
446 
447    /* Macro_Ptr_Max = Macro_Buffer_Ptr; */
448    Defining_Keyboard_Macro = 0;
449    set_macro_state();
450    return(1);
451 }
452 
453 /*}}}*/
454 
execute_keyboard_macro()455 int execute_keyboard_macro() /*{{{*/
456 {
457    int repeat = 0, *repeat_ptr;
458 
459    if (!check_macro_legality()) return (0);
460 
461    if (Defining_Keyboard_Macro)
462      {
463 	msg_error("Can't execute a macro while defining one.");
464 	return(0);
465      }
466 
467    Executing_Keyboard_Macro = 1;
468    set_macro_state();
469    Macro_Buffer_Ptr = Macro_Buffer;
470 
471    /* save the repeat context */
472    repeat_ptr = Repeat_Factor;
473    if (repeat_ptr != NULL) repeat = *repeat_ptr;
474 
475    JWindow->trashed = 1;
476    Macro_Illegal_Now = 1;
477    while ((Macro_Buffer_Ptr < Macro_Ptr_Max)
478 	  && Executing_Keyboard_Macro) /* since we might enter minibuffer
479 					and stop macro before returning
480 					here */
481      {
482 	Repeat_Factor = NULL;
483 	/* ch = *Macro_Buffer_Ptr++; */
484 	do_key();
485 	if (SLKeyBoard_Quit || (*Error_Buffer)) break;
486      }
487    Macro_Illegal_Now = 0;
488 
489    /* restore context */
490    Repeat_Factor = repeat_ptr;
491    if (repeat_ptr != NULL) *repeat_ptr = repeat;
492    Executing_Keyboard_Macro = 0;
493 #if JED_HAS_MENUS
494    /* This means that the macro was stopped from a menu */
495    if (Jed_Menus_Active)
496      (void) jed_exit_menu_bar ();
497 #endif
498    set_macro_state();
499    return(1);
500 }
501 
502 /*}}}*/
503 
get_last_macro()504 void get_last_macro () /*{{{*/
505 {
506    register char *m, *s, ch;
507    char buf[2 * MACRO_SIZE + 1];
508 
509    if (Defining_Keyboard_Macro)
510      {
511 	msg_error("Complete Macro first!");
512 	return;
513      }
514 
515    m = Macro_Buffer;
516    if (m == Macro_Ptr_Max)
517      {
518 	msg_error("Macro not defined.");
519 	return;
520      }
521 
522    s = buf;
523    while (m < Macro_Ptr_Max)
524      {
525 	ch = *m++;
526 	if ((ch < ' ') || (ch == 127))
527 	  {
528 	     *s++ = '^';
529 	     if (ch == 127) ch = '?'; else ch = '@' + ch;
530 	  }
531 	else if ((ch == '^') || (ch == '\\'))
532 	  {
533 	     *s++ = '\\';
534 	  }
535 
536 	*s++ = ch;
537      }
538    *s = 0;
539    SLang_push_string(buf);
540 }
541 
542 /*}}}*/
543 
safe_strcpy(char * a,char * b,unsigned int n)544 char *safe_strcpy (char *a, char *b, unsigned int n) /*{{{*/
545 {
546    if (n != 0)
547      {
548 	n--;
549 	strncpy (a, b, n);
550 	a[n] = 0;
551      }
552    return a;
553 }
554 
555 /*}}}*/
556 
safe_strcat(char * a,char * b,unsigned int n)557 char *safe_strcat (char *a, char *b, unsigned int n) /*{{{*/
558 {
559    unsigned int len = strlen (a);
560    unsigned int max;
561 
562    n--;
563 
564    if (n > len)
565      {
566 	max = n - len;
567 	strncpy (a + len, b, max);
568 	a[n] = 0;
569      }
570    return a;
571 }
572 
573 /*}}}*/
574 
clear_message(void)575 void clear_message (void) /*{{{*/
576 {
577    message (NULL);
578 }
579 
580 /*}}}*/
581 
582 
jed_vmessage(int now,char * fmt,...)583 void jed_vmessage (int now, char *fmt, ...)
584 {
585    va_list ap;
586    char buf[2048];
587 
588    va_start (ap, fmt);
589    vsprintf (buf, fmt, ap);
590    va_end (ap);
591 
592    if (now) flush_message (buf);
593    else message (buf);
594 }
595 
jed_verror(char * fmt,...)596 void jed_verror (char *fmt, ...)
597 {
598    va_list ap;
599    char buf[2048];
600 
601    va_start (ap, fmt);
602    vsprintf (buf, fmt, ap);
603    va_end (ap);
604 
605    msg_error (buf);
606 }
607 
608 #if !JED_FILE_PRESERVE_CASE
609 /* These two functions are used by the buffer and file name functions.
610  * Since the interpreter deals mainly with hashed strings, and there is
611  * the possibility that the strings to be compared are the same, we
612  * will exploit this fact.
613  */
jed_case_strncmp(char * a,char * b,unsigned int n)614 int jed_case_strncmp (char *a, char *b, unsigned int n)
615 {
616    register unsigned char cha, chb;
617    char *bmax;
618 
619    if (a == b) return 0;
620    bmax = b + n;
621    while (b < bmax)
622      {
623 	cha = UPPER_CASE(*a);
624 	chb = UPPER_CASE(*b);
625 
626 	if (cha != chb)
627 	  return (int) cha - (int) chb;
628 	if (chb == 0) return 0;
629 	a++;
630 	b++;
631      }
632    return 0;
633 }
634 
jed_case_strcmp(char * a,char * b)635 int jed_case_strcmp (char *a, char *b)
636 {
637    register unsigned char cha, chb;
638 
639    if (a == b) return 0;
640    while (1)
641      {
642 	cha = UPPER_CASE(*a);
643 	chb = UPPER_CASE(*b);
644 
645 	if (cha != chb)
646 	  return (int) cha - (int) chb;
647 	if (chb == 0) return 0;
648 	a++;
649 	b++;
650      }
651 }
652 #endif
653 
654