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