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
11 /*{{{ Include Files */
12
13 #ifdef MSWINDOWS
14 # ifndef __WIN32__
15 # include <toolhelp.h>
16 # else
17 # include <windows.h>
18 # endif
19 #endif
20
21 #include <stdio.h>
22
23 #ifdef HAVE_SYS_WAIT_H
24 # include <sys/types.h>
25 # include <sys/wait.h>
26 #endif
27
28 #ifndef WEXITSTATUS
29 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
30 #endif
31 #ifndef WIFEXITED
32 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
33 #endif
34
35 #include <slang.h>
36 #include "jdmacros.h"
37
38 #include <string.h>
39
40 #ifdef IBMPC_SYSTEM
41 # include <fcntl.h>
42 #endif
43
44 #include <stdarg.h>
45
46 #include "buffer.h"
47 #include "keymap.h"
48 #include "file.h"
49 #include "ins.h"
50 #include "ledit.h"
51 #include "screen.h"
52 #include "window.h"
53 #include "display.h"
54 #include "search.h"
55 #include "misc.h"
56 #include "replace.h"
57 #include "paste.h"
58 #include "sysdep.h"
59 #include "cmds.h"
60 #include "text.h"
61 #include "hooks.h"
62 #include "undo.h"
63 #include "menu.h"
64 #include "userinfo.h"
65 #include "indent.h"
66
67 #ifdef __WIN32__
68 # include "win32.h"
69 #endif
70
71 #define JED_PROMPT "S-Lang>"
72
73 #if JED_HAS_SUBPROCESSES
74 # include "jprocess.h"
75 #endif
76
77
78 /*}}}*/
79
80 Buffer *MiniBuffer;
81 Buffer *The_MiniBuffer; /* this never gets deleted since we may need it */
82
83 static Buffer *Last_Buffer;
84
85 /* extern char *get_cwd(void); */
86 int Ignore_Beep = 0;
87 int MiniBuffer_Active = 0;
88
89 /* Do not change this value without changing file_findfirst/next. */
90 #define JED_MAX_COMPLETION_LEN JED_MAX_PATH_LEN
91
92 static int (*complete_open)(char *);
93 static int (*complete_next)(char *);
94 static int Buf_List_Len;
95 Buffer *Buf_Context;
96
97 static char *Expect_File_Error = "Expecting filename.";
98
next_bufflist(char * buf)99 static int next_bufflist(char *buf) /*{{{*/
100 {
101 Buffer *tthis;
102 while (1)
103 {
104 tthis = Buf_Context;
105 if (tthis == MiniBuffer) return(0);
106 Buf_Context = Buf_Context->next;
107
108 if ((Buf_List_Len == 0)
109 #if JED_FILE_PRESERVE_CASE
110 || (0 == strncmp (buf, tthis->name, Buf_List_Len))
111 #else
112 || (0 == jed_case_strncmp (buf, tthis->name, Buf_List_Len))
113 #endif
114 )
115 {
116 if (*tthis->name == ' ') continue; /* internal buffers */
117 safe_strcpy (buf, tthis->name, JED_MAX_COMPLETION_LEN);
118 return 1;
119 }
120 }
121 }
122
123 /*}}}*/
124
open_bufflist(char * buf)125 static int open_bufflist(char *buf) /*{{{*/
126 {
127 if ((Buf_Context = MiniBuffer) == NULL) return(0);
128 Buf_Context = Buf_Context->next;
129 Buf_List_Len = strlen(buf);
130 return next_bufflist(buf);
131 }
132
133 /*}}}*/
134
what_buffer()135 char *what_buffer() /*{{{*/
136 {
137 return (CBuf->name);
138 }
139
140 /*}}}*/
141
bufferp(char * name)142 int bufferp(char *name) /*{{{*/
143 {
144 if (NULL == find_buffer(name)) return(0); else return(1);
145 }
146
147 /*}}}*/
148
insert_buffer_name(char * name)149 int insert_buffer_name(char *name) /*{{{*/
150 {
151 Buffer *buf;
152
153 if (NULL != (buf = find_buffer(name)))
154 {
155 insert_buffer(buf);
156 return(1);
157 }
158 else msg_error("Unable to find buffer.");
159 return(0);
160 }
161
162 /*}}}*/
163
find_scratch_buffer(void)164 static Buffer *find_scratch_buffer (void) /*{{{*/
165 {
166 char *sname = "*scratch*";
167 Buffer *scratch;
168
169 scratch = find_buffer (sname);
170 if (NULL == scratch)
171 scratch = make_buffer (sname, CBuf->dir, NULL);
172 return scratch;
173 }
174
175 /*}}}*/
176
177
178 /* Try to find any other buffer but kill_buf such that the buffer is not
179 * visible, not scratch and not buried.
180 */
find_non_visible_buffer(Buffer * kill_buf)181 static Buffer *find_non_visible_buffer (Buffer *kill_buf) /*{{{*/
182 {
183 Buffer *buf, *scratch;
184
185 buf = kill_buf->next;
186 scratch = find_scratch_buffer ();
187
188 while ((buf != kill_buf) &&
189 ((*buf->name == ' ') || (buf->flags & BURIED_BUFFER)
190 || (buf == scratch) || (buffer_visible(buf))))
191 {
192 buf = buf->next;
193 }
194 if ((buf == kill_buf) || (buf->flags & BURIED_BUFFER))
195 buf = scratch;
196 return buf;
197 }
198
199 /*}}}*/
200
201
202
kill_buffer_cmd(char * name)203 int kill_buffer_cmd(char *name) /*{{{*/
204 {
205 Buffer *this_buf, *kill_buf, *scratch, *buf;
206 Window_Type *w;
207 int do_kill;
208
209 if (NULL == (kill_buf = find_buffer(name)))
210 {
211 msg_error("Buffer does not exist.");
212 return(0);
213 }
214
215 /* Do not allow the minibuffer to be deleted. Otherwise, the whole
216 * minibuffer creation/selection needs to be cleaned up.
217 */
218 if (kill_buf == The_MiniBuffer)
219 return 0;
220
221 this_buf = CBuf;
222 switch_to_buffer(kill_buf);
223
224 #if JED_HAS_SUBPROCESSES
225 if (kill_buf->locked)
226 {
227 erase_buffer ();
228 switch_to_buffer (this_buf);
229 return 0;
230 }
231 #endif
232
233 do_kill = 1;
234 if ((*name != ' ') && (kill_buf->flags & BUFFER_MODIFIED))
235 {
236 jed_vmessage (1, "Buffer %s modified. (K)ill, (S)ave first, (A)bort:",
237 name);
238
239 /* This does not go through keyboard macro routines
240 * on purpose!
241 */
242 switch (my_getkey())
243 {
244 case 'k': case 'K': do_kill = 1; break;
245 case 's': case 'S': do_kill = 2; break;
246 default: msg_error("Aborted."); return(0);
247 }
248 clear_message ();
249 }
250
251 if (do_kill == 2)
252 {
253 jed_save_buffer_as_cmd ();
254 if (SLang_get_error ())
255 {
256 switch_to_buffer(this_buf);
257 return(0);
258 }
259 }
260
261 /* if it is the scratch buffer, just erase it since we are going to
262 recreate it anyway. */
263
264 scratch = find_scratch_buffer ();
265
266 if (kill_buf == scratch)
267 {
268 erase_buffer();
269 #if JED_HAS_SUBPROCESSES
270 if (kill_buf->subprocess) jed_kill_process (kill_buf->subprocess - 1);
271 kill_buf->subprocess = 0;
272 #endif
273 switch_to_buffer(this_buf);
274 return 1;
275 }
276
277 buf = find_non_visible_buffer (kill_buf);
278
279 /* search through windows looking for the buffer and replace it */
280 w = JWindow;
281 do
282 {
283 if (kill_buf == JWindow->buffer)
284 {
285 touch_window_hard (JWindow, 0);
286 window_buffer(buf);
287 buf = find_non_visible_buffer (kill_buf);
288 }
289 JWindow = JWindow->next;
290 }
291 while (w != JWindow);
292
293 if (kill_buf == Last_Buffer) Last_Buffer = NULL;
294 if (kill_buf == this_buf) this_buf = buf;
295 switch_to_buffer(this_buf);
296 delete_buffer(kill_buf);
297 return 1;
298 }
299
300 /*}}}*/
301
jed_save_buffer_to_file(char * dir,char * file)302 int jed_save_buffer_to_file (char *dir, char *file)
303 {
304 int status, state;
305 char *dirfile, *canonical_file;
306
307 if ((file == NULL) || (*file == 0))
308 {
309 file = CBuf->file;
310 if (*file == 0)
311 {
312 msg_error ("Filename Required.");
313 return -1;
314 }
315 }
316
317 if (NULL == (dirfile = jed_dir_file_merge (dir, file)))
318 return -1;
319
320 state = 0;
321
322 canonical_file = jed_get_canonical_pathname (dirfile);
323 if (canonical_file == NULL)
324 {
325 SLfree (dirfile);
326 return -1;
327 }
328
329 if (file_changed_on_disk (CBuf, dirfile) > 0)
330 state |= BUFFER_MODIFIED;
331 if (jed_file_is_readonly (canonical_file, 0))
332 state |= READ_ONLY;
333 if (0 != strcmp (canonical_file, CBuf->dirfile))
334 state |= OVERWRITE_MODE;
335
336 if (state)
337 {
338 char *prompt = NULL;
339
340 switch (state)
341 {
342 default:
343 case OVERWRITE_MODE:
344 prompt = NULL;
345 break;
346
347 case BUFFER_MODIFIED:
348 prompt = "File changed on disk. Save anyway?";
349 break;
350
351 case READ_ONLY:
352 prompt = "No permission to write to file. Try to save anyway?";
353 break;
354
355 case BUFFER_MODIFIED|READ_ONLY:
356 prompt = "File changed on disk and no permission to write. Save anyway?";
357 break;
358
359 case BUFFER_MODIFIED|OVERWRITE_MODE:
360 prompt = "File exists and changed on disk. Overwrite?";
361 break;
362
363 case READ_ONLY|OVERWRITE_MODE:
364 prompt = "File exists and no permission to write. Try to overwrite anyway?";
365 break;
366
367 case READ_ONLY|OVERWRITE_MODE|BUFFER_MODIFIED:
368 prompt = "File changed on disk and no permission to write. Overwrite anyway?";
369 break;
370 }
371
372 if ((prompt != NULL)
373 && (1 != jed_get_yes_no(prompt)))
374 {
375 SLfree (canonical_file);
376 SLfree (dirfile);
377 return -1;
378 }
379 }
380
381 SLfree (canonical_file);
382
383 if (-1 == jed_va_run_hooks ("_jed_save_buffer_before_hooks",
384 JED_HOOKS_RUN_ALL, 1, dirfile))
385 {
386 auto_save_buffer (CBuf);
387 SLfree (dirfile);
388 return -1;
389 }
390
391 if (((status = write_file_with_backup (dirfile)) >= 0)
392 && (Batch != 2))
393 jed_vmessage (0, "Wrote %d lines to %s", status, dirfile);
394
395 if (status < 0)
396 {
397 jed_verror ("Error writing file %s", dirfile);
398 SLfree (dirfile);
399 return -1;
400 }
401
402
403 CBuf->flags |= AUTO_SAVE_BUFFER;
404 CBuf->hits = 0;
405
406 #ifdef UNDO_HAS_REDO
407 update_undo_unchanged ();
408 #endif
409 visit_file (dir, file);
410
411 if (-1 == jed_va_run_hooks ("_jed_save_buffer_after_hooks", JED_HOOKS_RUN_ALL,
412 1, dirfile))
413 {
414 SLfree (dirfile);
415 return -1;
416 }
417
418 SLfree (dirfile);
419 return 0;
420 }
421
422
jed_save_buffer_as(char * filestr)423 int jed_save_buffer_as (char *filestr)
424 {
425 char *dir, *file;
426 int status;
427
428 filestr = jed_standardize_filename (filestr);
429
430 if (-1 == jed_dirfile_to_dir_file (filestr, &dir, &file))
431 {
432 SLfree (filestr);
433 return -1;
434 }
435
436 status = jed_save_buffer_to_file (dir, file);
437
438 SLfree (filestr);
439 SLfree (dir);
440 SLfree (file);
441
442 if (status == -1)
443 return status;
444
445 /* This function is an intrinsic and is documented to return the
446 * number of lines written out.
447 *
448 */
449 return 0;
450 }
451
jed_save_buffer_cmd(void)452 int jed_save_buffer_cmd (void)
453 {
454 if ((CBuf->file == NULL) || (CBuf->file[0] == 0))
455 return jed_save_buffer_as_cmd ();
456
457 return jed_save_buffer_to_file (CBuf->dir, CBuf->file);
458 }
459
460 #if defined(__BORLANDC__) && !defined(MSWINDOWS)
show_memory()461 int show_memory() /*{{{*/
462 {
463 struct farheapinfo hi;
464 char *c;
465 unsigned long total = 0, core, used = 0;
466 unsigned long max = 0;
467 int i = 0;
468
469 hi.ptr = NULL;
470 if (farheapcheck() == _HEAPCORRUPT) c = "corrupt"; else c = "ok";
471 while (farheapwalk(&hi) == _HEAPOK)
472 {
473 if (hi.in_use)
474 used += hi.size;
475 else
476 {
477 total += hi.size;
478 if (hi.size > max) max = hi.size;
479 i++;
480 }
481 }
482 core = farcoreleft();
483 jed_vmessage (0, "used:%lu, core:%lu, free:%lu, grand:%lu, max:%lu, frag:%d (%s)",
484 used, core, total, core + total, max, i, c);
485 return 0;
486 }
487
488 /*}}}*/
489
490 #endif
491
492 #ifdef MSWINDOWS
show_memory(void)493 int show_memory (void) /*{{{*/
494 {
495 #ifndef __WIN32__
496 MEMMANINFO mmi;
497 if (MemManInfo(&mmi))
498 {
499 jed_vmessage (0, "tot pages: %lu, free pages: %lu",
500 mmi.dwTotalLinearSpace, mmi.dwFreeLinearSpace);
501 }
502 #else
503 MEMORYSTATUS mst;
504 GlobalMemoryStatus(&mst);
505 jed_vmessage (0, "avail space: %lu, tot phys space: %lu, avail phys space: %lu",
506 mst.dwAvailPhys + mst.dwAvailPageFile, mst.dwTotalPhys, mst.dwAvailPhys);
507 #endif
508
509 return 0;
510 }
511
512 /*}}}*/
513
514 #endif
515
516 #ifdef __WATCOMC__
517 #include <malloc.h>
show_memory()518 int show_memory() /*{{{*/
519 {
520 jed_vmessage (0, "avail mem: %lu, tot phys pgs: ???, free lin space: %lu",
521 _memavl (), _memmax ());
522 return 0;
523 }
524
525 /*}}}*/
526
527 #endif
528
529 #ifdef __GO32__
530 #include <dpmi.h>
531
show_memory()532 int show_memory() /*{{{*/
533 {
534 unsigned long mem;
535 _go32_dpmi_meminfo info;
536
537 _go32_dpmi_get_free_memory_information(&info);
538
539 if ((long)info.available_physical_pages != -1L)
540 mem = info.available_physical_pages * 4096UL;
541 else mem = info.available_memory;
542
543 jed_vmessage (0, "avail mem: %lu, tot phys pgs: %lu, free lin space: %lu",
544 mem, info.total_physical_pages, info.free_linear_space);
545 return 0;
546 }
547
548 /*}}}*/
549
550 #endif
551
set_buffer(char * name)552 int set_buffer(char *name) /*{{{*/
553 {
554 Buffer *buf;
555
556 if ((name == NULL) || (*name == 0))
557 {
558 msg_error("set_buffer: Buffer name is NULL");
559 return (0);
560 }
561
562 /* Last_Buffer = CBuf; */
563
564 if (NULL == (buf = find_buffer(name)))
565 buf = make_buffer (name, CBuf->dir, NULL);
566 switch_to_buffer(buf);
567
568 return 1;
569 }
570
571 /*}}}*/
572
jed_get_mini_response(char * s)573 int jed_get_mini_response (char *s)
574 {
575 int ch;
576 int len;
577
578 if (Batch)
579 {
580 if (EOF == fputs (s, stdout))
581 exit_error ("Failed to write to stdout", 0);
582
583 return jed_getkey ();
584 }
585
586 len = strlen (s);
587 if (len > Jed_Num_Screen_Cols)
588 s += (len - Jed_Num_Screen_Cols);
589
590 MiniBuf_Get_Response_String = s;
591 update (NULL, 0, 0, 0);
592 ch = jed_getkey ();
593 MiniBuf_Get_Response_String = NULL;
594 return ch;
595 }
596
strcat_malloc(char * a,char * b)597 static char *strcat_malloc (char *a, char *b)
598 {
599 unsigned int len;
600 char *c;
601
602 len = strlen (a);
603
604 if (NULL == (c = SLmalloc (len + strlen (b) + 1)))
605 return NULL;
606
607 strcpy (c, a);
608 strcpy (c + len, b);
609 return c;
610 }
611
612
jed_get_y_n(char * question)613 int jed_get_y_n (char *question)
614 {
615 int ans;
616 char *yn_quest;
617
618 if (NULL == (yn_quest = strcat_malloc (question, "? (y/n)")))
619 return -1;
620
621 ans = jed_get_mini_response (yn_quest);
622 SLfree (yn_quest);
623
624 if ((ans == 'y') || (ans == 'Y'))
625 return 1;
626 if ((ans == 'n') || (ans == 'N'))
627 return 0;
628 if (SLKeyBoard_Quit || (SLang_get_error () == SL_USER_BREAK))
629 return -1;
630 jed_beep ();
631 flush_input ();
632 return jed_get_yes_no (question);
633 }
634
635
jed_vget_y_n(char * fmt,char * arg)636 int jed_vget_y_n (char *fmt, char *arg)
637 {
638 char msg [1024];
639
640 if (arg == NULL)
641 {
642 arg = fmt;
643 fmt = "%s";
644 }
645
646 SLsnprintf (msg, sizeof (msg), fmt, arg);
647
648 return jed_get_y_n (msg);
649 }
650
651
jed_get_yes_no(char * question)652 int jed_get_yes_no (char *question) /*{{{*/
653 {
654 char *yn_quest;
655 char *tmp;
656 int n;
657
658 if (NULL == (yn_quest = strcat_malloc (question, "? (yes or no)")))
659 return -1;
660
661 while (1)
662 {
663 if (NULL == (tmp = read_from_minibuffer(yn_quest, 0, NULL, &n)))
664 {
665 SLfree (yn_quest);
666 return -1;
667 }
668
669 if (!strcmp(tmp, "yes"))
670 {
671 SLfree(tmp);
672 SLfree (yn_quest);
673 return 1;
674 }
675
676 if (!strcmp(tmp, "no"))
677 {
678 SLfree(tmp);
679 SLfree (yn_quest);
680 return 0;
681 }
682 msg_error("Answer `yes' or `no'.");
683 SLfree(tmp);
684 }
685 }
686
687 /*}}}*/
688
find_file_cmd(char * filestr)689 int find_file_cmd (char *filestr) /* filestr is const ! */ /*{{{*/
690 {
691 Buffer *buf;
692 int status;
693 char *dirfile, *dir, *file;
694 char *name;
695
696 #ifdef REAL_UNIX_SYSTEM
697 char *dir1;
698
699 /* Handle the case where /foo/bar/../baz may not be the same as /foo/baz */
700 if (-1 == jed_dirfile_to_dir_file (filestr, &dir, &file))
701 return -1;
702
703 if (NULL == (dir1 = jed_expand_link (dir)))
704 {
705 SLfree (dir);
706 SLfree (file);
707 return -1;
708 }
709 SLfree (dir);
710 filestr = jed_dir_file_merge (dir1, file);
711 SLfree (dir1);
712 SLfree (file);
713 #else
714 filestr = jed_standardize_filename (filestr);
715 #endif
716 if (filestr == NULL)
717 return -1;
718
719 /* If this hook returns 1, then the file is considered to be found. */
720 if (1 == jed_va_run_hooks ("_jed_find_file_before_hooks", JED_HOOKS_RUN_UNTIL_NON_0,
721 1, filestr))
722 {
723 SLfree (filestr);
724 return 0;
725 }
726
727 dirfile = jed_expand_link(filestr);
728
729 if (dirfile == NULL)
730 {
731 SLfree (filestr);
732 return -1;
733 }
734
735 if (-1 == jed_dirfile_to_dir_file (filestr, &dir, &file))
736 {
737 SLfree (filestr);
738 SLfree (dirfile);
739 return -1;
740 }
741
742 status = -1;
743
744 if (*file == 0)
745 {
746 jed_verror (Expect_File_Error);
747 goto free_and_return;
748 }
749
750 check_buffers ();
751
752 /* search for the file in current buffer list */
753
754 if (NULL != (buf = find_file_buffer (dirfile)))
755 {
756 if ((file_changed_on_disk (buf, dirfile) > 0)
757 && (1 == jed_get_yes_no("File changed on disk. Read from disk")))
758 {
759 int n = (int) buf->linenum;
760 mark_buffer_modified (buf, 0, 1);
761 kill_buffer_cmd (buf->name);
762 status = find_file_cmd (filestr);
763 goto_line (&n);
764 goto free_and_return;
765 }
766
767 if (SLang_get_error ())
768 goto free_and_return;
769
770 status = 1;
771 switch_to_buffer (buf);
772 goto free_and_return;
773 }
774
775 /* Make a buffer but do not attach it to a file yet. */
776 name = extract_file (filestr);
777
778 buf = make_buffer (name, dir, NULL);
779 switch_to_buffer(buf);
780
781 status = read_file (dirfile);
782
783 switch (status)
784 {
785 case -2:
786 jed_verror ("File %s not readable.", dirfile);
787 status = -1;
788 break;
789
790 case -1:
791 if (Batch == 0)
792 message ("New file.");
793 status = 0;
794 break;
795
796 default:
797 if (Batch == 0)
798 jed_vmessage (0, "%d lines read", status);
799 status = 1;
800 }
801
802 if (buf == CBuf) /* check this in case the hook switches buffers */
803 {
804 mark_buffer_modified (CBuf, 0, 0);
805
806 /* Now attach it to a file */
807 visit_file (dir, file);
808 uniquely_name_buffer (CBuf, name);
809
810 (void) bob ();
811 set_file_modes();
812 CBuf->flags |= UNDO_ENABLED;
813 }
814
815 if (-1 == jed_va_run_hooks ("_jed_find_file_after_hooks", JED_HOOKS_RUN_ALL, 0))
816 status = -1;
817
818 free_and_return:
819
820 SLfree (dirfile);
821 SLfree (filestr);
822 SLfree (dir);
823 SLfree (file);
824
825 return status;
826 }
827
828 /*}}}*/
829
830
find_file_in_window(char * file)831 int find_file_in_window(char *file) /*{{{*/
832 {
833 int ret;
834 Buffer *b = CBuf;
835
836 ret = find_file_cmd (file);
837 if ((b != CBuf) && (*CBuf->name != ' ')) Last_Buffer = CBuf;
838 window_buffer(CBuf);
839 return(ret);
840 }
841
842 /*}}}*/
843
844
845 /* create a minibuffer with window and switch to it. */
create_minibuffer(void)846 static void create_minibuffer(void) /*{{{*/
847 {
848 Window_Type *w;
849 MiniBuffer = The_MiniBuffer;
850
851 /* We may get called before the keymap has been set up. Make sure that
852 * we have a keymap.
853 */
854 if ((The_MiniBuffer->keymap == NULL)
855 || (The_MiniBuffer->keymap == Global_Map))
856 jed_setup_minibuffer_keymap ();
857
858 /* I want to make Mini_Window->next = Current Window so that scroll other
859 window routines will scroll it. */
860
861 w = JWindow;
862 do other_window(); while (JWindow->next != w);
863 JWindow->next = JMiniWindow;
864 JMiniWindow->next = w;
865 JMiniWindow->hscroll_column = 1;
866 Mini_Info.action_window = w;
867 other_window(); /* now in minibuffer window */
868 window_buffer(MiniBuffer);
869 switch_to_buffer(MiniBuffer);
870 MiniBuffer_Active = 1;
871 erase_buffer ();
872
873 #if JED_HAS_MENUS
874 jed_notify_menu_buffer_changed ();
875 #endif
876
877 /* allow kill region to kill to beginning of minibuffer.
878 * Suggested by stefen@uni-paderborn.de */
879 jed_push_mark ();
880 }
881
882 /*}}}*/
883
884 char *Completion_Buffer = "*Completions*";
885
886 static char *Last_Completion_Buffer;
887 static int Last_Completion_Windows;
888
889 /* evaluate command in minibuffer and leave */
exit_minibuffer()890 int exit_minibuffer() /*{{{*/
891 {
892 if (IN_MINI_WINDOW)
893 {
894 if (Last_Completion_Buffer != NULL)
895 {
896 pop_to_buffer (Completion_Buffer);
897 mark_buffer_modified (CBuf, 0, 0);
898 switch_to_buffer_cmd (Last_Completion_Buffer);
899 kill_buffer_cmd (Completion_Buffer);
900 touch_window_hard (JWindow, 0);
901 if (Last_Completion_Windows == 1) one_window ();
902 }
903 select_minibuffer ();
904 Exit_From_MiniBuffer = 1;
905 }
906 Last_Completion_Buffer = NULL;
907 return(0);
908 }
909
910 /*}}}*/
911
912 /* return 1 if minibuffer already exists otherwise returns 0 */
select_minibuffer(void)913 int select_minibuffer (void) /*{{{*/
914 {
915 Window_Type *w;
916
917 /* Try to find active minibuffer and go there */
918 w = JWindow;
919 while (MiniBuffer != NULL)
920 {
921 if (IN_MINI_WINDOW) return(1);
922 other_window();
923 if (w == JWindow) exit_error("Internal Error: no window!", 1);
924 }
925
926 /* switchs to minibuffer too */
927 create_minibuffer();
928 return(0);
929 }
930
931 /*}}}*/
932
933 /* if cmd != NULL, insert it into minibuffer and then send the result to
934 the appropriate routine. */
935
ledit(void)936 static int ledit(void) /*{{{*/
937 {
938 int n;
939 char *tmp;
940
941 if (MiniBuffer == NULL) complete_open = NULL;
942 if (NULL == (tmp = read_from_minibuffer(JED_PROMPT, 0, NULL, &n))) return(0);
943
944 /* SLang_Error = 0; ??? Why? 0.99-16 and earlier */
945 Suspend_Screen_Update = 1;
946
947 SLang_load_string(tmp);
948 SLfree(tmp);
949
950 if (SLang_get_error () == SL_USER_BREAK)
951 msg_error("Quit!");
952
953 /* SLang_set_error (0); */
954
955 return(1);
956 }
957
958 /*}}}*/
959
960 static int File_Expansion_Happened = 0;
file_findfirst(char * buf)961 static int file_findfirst (char *buf)
962 {
963 char *file;
964
965 File_Expansion_Happened = 1;
966 if (NULL == (file = jed_expand_filename (buf)))
967 return -1;
968 safe_strcpy (buf, file, JED_MAX_COMPLETION_LEN);
969 SLfree (file);
970 return sys_findfirst (buf);
971 }
972
file_findnext(char * file)973 static int file_findnext (char *file)
974 {
975 return sys_findnext (file);
976 }
977
978
read_file_from_minibuffer(char * prompt,char * def,char * stuff)979 static char *read_file_from_minibuffer(char *prompt, char *def, char *stuff) /*{{{*/
980 {
981 int n;
982 char *file, *file1;
983
984 File_Expansion_Happened = 0;
985 complete_open = file_findfirst;
986 complete_next = file_findnext;
987
988 if ((stuff == NULL) || (*stuff == 0))
989 {
990 if (*CBuf->dir == 0)
991 buffer_filename (CBuf, NULL, CBuf->file);
992 stuff = CBuf->dir;
993 }
994
995 if (NULL == (file = read_from_minibuffer (prompt, def, stuff, &n)))
996 return NULL;
997
998 if (File_Expansion_Happened)
999 file1 = jed_standardize_filename (file);
1000 else
1001 file1 = jed_expand_filename (file);
1002
1003 SLfree (file);
1004 return file1;
1005 }
1006
1007 /*}}}*/
1008
1009 static char *String_Completion_Str;
1010 static char *String_Completion_Str_Next;
1011 static int String_Completion_Str_Len;
1012
1013
next_string_list(char * buf)1014 static int next_string_list (char *buf) /*{{{*/
1015 {
1016 register char *s = String_Completion_Str_Next;
1017 int len;
1018 while (*s)
1019 {
1020 while (*s && (*s != ',')) s++;
1021 len = (int) (s - String_Completion_Str_Next);
1022
1023 if (*s == ',') s++;
1024
1025 if (!len
1026 || strncmp (buf, String_Completion_Str_Next, String_Completion_Str_Len))
1027 {
1028 String_Completion_Str_Next = s;
1029 continue;
1030 }
1031 if (len >= JED_MAX_PATH_LEN) len = JED_MAX_PATH_LEN - 1;
1032 strncpy (buf, String_Completion_Str_Next, len);
1033 buf[len] = 0;
1034 String_Completion_Str_Next = s;
1035 return 1;
1036 }
1037 String_Completion_Str_Next = s;
1038 return 0;
1039 }
1040
1041 /*}}}*/
1042
open_string_list(char * buf)1043 static int open_string_list (char *buf) /*{{{*/
1044 {
1045 String_Completion_Str_Next = String_Completion_Str;
1046 String_Completion_Str_Len = strlen (buf);
1047 return next_string_list (buf);
1048 }
1049
1050 /*}}}*/
1051
1052
read_object_with_completion(char * prompt,char * dflt,char * stuff,int * typep)1053 void read_object_with_completion(char *prompt, char *dflt, char *stuff, int *typep) /*{{{*/
1054 {
1055 int type = *typep, n;
1056 char buf[JED_MAX_COMPLETION_LEN], *tmp;
1057 char *str = NULL;
1058
1059 *buf = 0;
1060 if (type == 'f') /* file */
1061 {
1062 char *file = read_file_from_minibuffer (prompt, dflt, stuff);
1063 if (file != NULL)
1064 (void) SLang_push_malloced_string (file);
1065 return;
1066 }
1067 else if (type == 'b') /* buffer */
1068 {
1069 complete_open = open_bufflist;
1070 complete_next = next_bufflist;
1071 }
1072 else if (type == 'F') /* function */
1073 {
1074 complete_open = open_function_list;
1075 complete_next = next_function_list;
1076 }
1077 else if (type == 's')
1078 {
1079 complete_open = open_string_list;
1080 complete_next = next_string_list;
1081 if (SLpop_string (&str)) return;
1082 String_Completion_Str = str;
1083 }
1084 else
1085 {
1086 complete_open = NULL;
1087 }
1088
1089 safe_strcat (buf, stuff, sizeof (buf));
1090
1091 if (NULL != (tmp = read_from_minibuffer(prompt, dflt, buf, &n)))
1092 {
1093 (void) SLang_push_string(tmp);
1094
1095 SLfree(tmp);
1096 if (str != NULL) SLfree (str);
1097 }
1098 }
1099
1100 /*}}}*/
1101
insert_file_cmd(void)1102 int insert_file_cmd (void) /*{{{*/
1103 {
1104 char *f, *file;
1105
1106 CHECK_READ_ONLY
1107
1108 if (NULL == (file = read_file_from_minibuffer("Insert file:", NULL, NULL)))
1109 return -1;
1110
1111 f = extract_file(file);
1112 if ((*file == 0) || (*f == 0))
1113 {
1114 SLfree (file);
1115 msg_error(Expect_File_Error);
1116 return(1);
1117 }
1118
1119 if (insert_file(file) < 0) msg_error("Error inserting file.");
1120 SLfree (file);
1121 return(1);
1122 }
1123
1124 /*}}}*/
1125
find_file(void)1126 int find_file (void) /*{{{*/
1127 {
1128 char *file, *f;
1129 int status;
1130
1131 if (NULL == (file = read_file_from_minibuffer("Find file:", NULL, NULL)))
1132 return 0;
1133
1134 f = extract_file (file);
1135 if (*f == 0)
1136 {
1137 char *dirfile = jed_dir_file_merge (file, CBuf->file);
1138 SLfree (file);
1139 if (dirfile == NULL)
1140 return -1;
1141 file = dirfile;
1142 }
1143
1144 status = find_file_in_window (file);
1145 SLfree (file);
1146 return status;
1147 }
1148
1149 /*}}}*/
1150
jed_save_buffer_as_cmd(void)1151 int jed_save_buffer_as_cmd (void) /*{{{*/
1152 {
1153 char *tmp;
1154
1155 if (NULL == (tmp = read_file_from_minibuffer("Save as:", NULL, NULL))) return(0);
1156 (void) jed_save_buffer_as (tmp);
1157 SLfree(tmp);
1158 return(1);
1159 }
1160
1161 /*}}}*/
1162
switch_to_buffer_cmd(char * name)1163 void switch_to_buffer_cmd (char *name) /*{{{*/
1164 {
1165 Buffer *tthis = CBuf;
1166
1167 set_buffer(name);
1168 window_buffer(CBuf);
1169 if ((CBuf != tthis) && (*CBuf->name != ' ')) Last_Buffer = tthis;
1170 }
1171
1172 /*}}}*/
1173
get_last_buffer(void)1174 static void get_last_buffer(void) /*{{{*/
1175 {
1176 if ((Last_Buffer == CBuf) || (Last_Buffer == NULL)
1177 || (*Last_Buffer->name == ' ')
1178 || (Last_Buffer->flags & BURIED_BUFFER))
1179 {
1180 Last_Buffer = find_non_visible_buffer (CBuf);
1181 }
1182 }
1183
1184 /*}}}*/
1185
get_buffer()1186 int get_buffer() /*{{{*/
1187 {
1188 char *tmp;
1189 int n;
1190 complete_open = open_bufflist;
1191 complete_next = next_bufflist;
1192
1193 get_last_buffer ();
1194
1195 if (NULL == (tmp = read_from_minibuffer("Switch to buffer:", Last_Buffer->name, NULL, &n))) return(0);
1196 switch_to_buffer_cmd(tmp);
1197 SLfree(tmp);
1198 return(1);
1199 }
1200
1201 /*}}}*/
1202
kill_buffer(void)1203 int kill_buffer (void) /*{{{*/
1204 {
1205 char *tmp;
1206 int n;
1207
1208 complete_open = open_bufflist;
1209 complete_next = next_bufflist;
1210 tmp = read_from_minibuffer("Kill buffer:", (char *) CBuf->name, NULL, &n);
1211 if (tmp != NULL)
1212 {
1213 #if JED_HAS_SUBPROCESSES
1214 Buffer *b = find_buffer(tmp);
1215 if ((b != NULL) && (b->subprocess))
1216 {
1217 if (0 == jed_get_yes_no("Buffer has a subprocess attached. Delete anyway"))
1218 {
1219 SLfree(tmp);
1220 return 0;
1221 }
1222 }
1223 #endif
1224 kill_buffer_cmd(tmp);
1225 SLfree(tmp);
1226 return(1);
1227 }
1228 return 0;
1229 }
1230
1231 /*}}}*/
1232
evaluate_cmd()1233 int evaluate_cmd() /*{{{*/
1234 {
1235 return(!ledit());
1236 }
1237
1238 /*}}}*/
1239
1240
pop_to_buffer(char * name)1241 char *pop_to_buffer(char *name) /*{{{*/
1242 {
1243 Window_Type *w, *action, *use_this;
1244 char *bname;
1245 Line *line, *oldline;
1246 int p, oldp, lnum, oldlnum;
1247 Buffer *b, *oldb;
1248
1249 if (!strcmp(name, " <mini>"))
1250 {
1251 select_minibuffer ();
1252 return CBuf->name;
1253 }
1254
1255 /* save position so we can pop back to it if buffer already exists in
1256 window */
1257 oldb = CBuf; oldline = CLine; oldp = Point; oldlnum = LineNum;
1258
1259 set_buffer(name);
1260 line = CLine; p = Point; lnum = LineNum;
1261
1262 use_this = NULL;
1263 if (MiniBuffer != NULL)
1264 {
1265 action = Mini_Info.action_window;
1266 }
1267 else action = NULL;
1268
1269 if (Batch) return CBuf->name;
1270
1271 w = JWindow;
1272 /* find a window to use */
1273 do
1274 {
1275 if (0 == (w->flags & MINIBUFFER_WINDOW))
1276 {
1277 if (action != NULL)
1278 {
1279 if (w != action) use_this = w;
1280 }
1281 else if (w != JWindow) use_this = w;
1282
1283 if (w->buffer == CBuf)
1284 {
1285 use_this = w;
1286 break;
1287 }
1288 }
1289 w = w->next;
1290 }
1291 while (w != JWindow);
1292
1293 b = CBuf;
1294 if (use_this != NULL)
1295 {
1296 while(JWindow != use_this) other_window();
1297 /* This is a good reason for haveing otherwindow avoid switching buffers */
1298 if (CBuf == oldb)
1299 {
1300 CLine = oldline; Point = oldp; LineNum = oldlnum;
1301 }
1302 }
1303 else
1304 {
1305 if (action != NULL) while(JWindow != action) other_window();
1306 split_window();
1307 /*
1308 * doing it this way makes screen update look better
1309 */
1310 w = JWindow;
1311 do
1312 {
1313 other_window();
1314 }
1315 while (JWindow->buffer != w->buffer);
1316 JWindow->hscroll_column = 1;
1317 }
1318
1319 bname = CBuf->name;
1320 switch_to_buffer(b);
1321 b->line = CLine = line;
1322 b->point = Point = p;
1323 b->linenum = LineNum = lnum;
1324 if (b != JWindow->buffer) window_buffer(b);
1325 return bname;
1326 }
1327
1328 /*}}}*/
1329
1330 #if defined (REAL_UNIX_SYSTEM) || defined(__WIN32__) || (defined (__os2__) && !defined(__WATCOMC__))
1331
1332 # if defined (__WIN32__) /* defined (__BORLANDC__) || defined (_MSC_VER) */
1333 # undef popen
1334 # undef pclose
1335 # define popen w32_popen
1336 # define pclose w32_pclose
1337 # endif
1338
1339 # ifdef __IBMC__
1340 extern FILE *popen(char *, char *);
1341 extern int pclose(FILE *);
1342 # endif
1343
1344 # if !JED_HAS_SUBPROCESSES
1345 # define jed_popen popen
1346 # define jed_pclose pclose
1347 # endif
1348
1349 static char *Process_Error = "Unable to open process.";
shell_command(char * cmd)1350 int shell_command(char *cmd) /*{{{*/
1351 {
1352 FILE *pp;
1353 VFILE *vp;
1354 int status;
1355
1356 if (Jed_Secure_Mode)
1357 {
1358 msg_error ("Access denied.");
1359 return -1;
1360 }
1361
1362 if (NULL == (pp = jed_popen(cmd, "r")))
1363 {
1364 msg_error(Process_Error);
1365 return -1;
1366 }
1367
1368 if (NULL != (vp = vstream(fileno(pp), 0, VFILE_TEXT)))
1369 {
1370 (void) insert_file_pointer(vp);
1371 SLfree(vp->buf);
1372 SLfree ((char *)vp);
1373 }
1374 else msg_error("Malloc Error.");
1375
1376 status = jed_pclose (pp);
1377
1378 #if defined(WIFEXITED) && defined(WEXITSTATUS)
1379 if ((status != -1) && WIFEXITED(status))
1380 {
1381 status = WEXITSTATUS(status);
1382 }
1383 #endif
1384 return status;
1385 }
1386
1387 /*}}}*/
pipe_region(char * cmd)1388 int pipe_region(char *cmd) /*{{{*/
1389 {
1390 FILE *pp;
1391 int n;
1392
1393 if (Jed_Secure_Mode)
1394 {
1395 msg_error ("Access denied.");
1396 return -1;
1397 }
1398
1399 if (NULL == (pp = jed_popen (cmd, "w")))
1400 {
1401 msg_error(Process_Error);
1402 return(-1);
1403 }
1404
1405 n = write_region_to_fp(fileno(pp));
1406 if (n == -1)
1407 msg_error ("pipe_region: write failed");
1408
1409 return jed_pclose (pp);
1410 }
1411
1412 /*}}}*/
1413 #endif
1414
1415 /*
1416 * Try to open a .slc then a .sl
1417 */
1418 #ifdef SIXTEEN_BIT_SYSTEM
1419 #define VFILE_BUF_SIZE 1024
1420 #else
1421 #define VFILE_BUF_SIZE 4096
1422 #endif
1423
1424
jed_open_lib_file(SLFUTURE_CONST char * file,char ** dirfile)1425 static VFILE *jed_open_lib_file (SLFUTURE_CONST char *file, char **dirfile) /*{{{*/
1426 {
1427 char libfsl[JED_MAX_PATH_LEN], libfslc[JED_MAX_PATH_LEN];
1428 SLFUTURE_CONST char *lib, *type, *libf;
1429 unsigned int n;
1430 VFILE *vp = NULL;
1431 int free_lib;
1432 int delimiter;
1433
1434 libf = file;
1435 lib = NULL;
1436 free_lib = 0;
1437
1438 /* If file begins with ./,then read it from the current directory */
1439 if ((0 == strncmp (file, "./", 2))
1440 #ifdef IBMPC_SYSTEM
1441 || (0 == strncmp (file, ".\\", 2))
1442 || (0 == strncmp (file, "..\\", 3))
1443 #endif
1444 || (0 == strncmp (file, "../", 3)))
1445 {
1446 if (NULL == (lib = jed_get_cwd ()))
1447 lib = "";
1448 }
1449 else if (SLpath_is_absolute_path (file))
1450 lib = "";
1451 else
1452 {
1453 lib = SLpath_get_load_path (); /* SLstring */
1454 free_lib = 1;
1455 if ((lib == NULL) || (*lib == 0))
1456 exit_error("The JED_ROOT environment variable needs set.", 0);
1457 }
1458
1459 if ((NULL != (type = file_type(file)))
1460 && ((*type == 0)
1461 || ((0 != strcmp (type, "sl")) && (0 != strcmp (type, "slc")))))
1462 type = NULL;
1463
1464 delimiter = SLpath_get_delimiter ();
1465 n = 0;
1466 while (0 == SLextract_list_element (lib, n, delimiter, libfsl, sizeof(libfsl)))
1467 {
1468 n++;
1469
1470 fixup_dir(libfsl);
1471 safe_strcat (libfsl, file, sizeof (libfsl));
1472 safe_strcpy (libfsl, jed_standardize_filename_static(libfsl), sizeof (libfsl));
1473
1474 libf = libfsl;
1475
1476 if ((1 == file_status (libf))
1477 && (NULL != (vp = vopen(libf, VFILE_BUF_SIZE, VFILE_TEXT))))
1478 break;
1479
1480 if (type == NULL)
1481 {
1482 #ifdef VMS
1483 int vmsn;
1484 /* remove trailing '.' */
1485 if (0 != (vmsn = strlen(libfsl)))
1486 {
1487 vmsn--;
1488 if (libfsl[vmsn] == '.') libfsl[vmsn] = 0;
1489 }
1490 #endif
1491
1492 /* Try .sl and .slc */
1493 safe_strcat (libfsl, ".sl", sizeof (libfsl));
1494 safe_strcpy (libfslc, libfsl, sizeof (libfslc));
1495 safe_strcat (libfslc, "c", sizeof (libfslc));
1496
1497 if (file_time_cmp(libfslc, libfsl) >= 0)
1498 libf = libfslc;
1499
1500 if ((1 == file_status (libf))
1501 && (NULL != (vp = vopen(libf, VFILE_BUF_SIZE, VFILE_TEXT))))
1502 break;
1503 }
1504 }
1505
1506 if (free_lib)
1507 SLang_free_slstring ((char *) lib);
1508
1509 if (vp == NULL)
1510 {
1511 *dirfile = NULL;
1512 return NULL;
1513 }
1514
1515 if (NULL == (*dirfile = SLang_create_slstring (libf)))
1516 {
1517 vclose (vp);
1518 return NULL;
1519 }
1520
1521 if (0 == Jed_Load_Quietly)
1522 jed_vmessage (1, "loading %s", libf);
1523
1524 return (vp);
1525 }
1526
1527 /*}}}*/
1528
jed_read_from_file(SLang_Load_Type * x)1529 static char *jed_read_from_file(SLang_Load_Type *x) /*{{{*/
1530 {
1531 char *s;
1532 unsigned int n;
1533
1534 if ((s = vgets((VFILE *) x->client_data, &n)) != NULL)
1535 {
1536 if (s[n - 1] != '\n') s[n] = 0;
1537 }
1538
1539 return s;
1540 }
1541
1542 /*}}}*/
1543
jed_ns_load_file(SLFUTURE_CONST char * file,SLFUTURE_CONST char * ns)1544 int jed_ns_load_file (SLFUTURE_CONST char *file, SLFUTURE_CONST char *ns)
1545 {
1546 VFILE *vp;
1547 SLang_Load_Type *x;
1548 int ret;
1549 char *dirfile;
1550
1551 if (NULL == (vp = jed_open_lib_file (file, &dirfile)))
1552 {
1553 SLang_verror (SL_OBJ_NOPEN, "Unable to open %s. Check the value of the S-Lang load path.", file);
1554 return -1;
1555 }
1556
1557 #if SLANG_VERSION >= 10409
1558 x = SLns_allocate_load_type (dirfile, ns);
1559 #else
1560 if ((ns != NULL)
1561 && (0 != strcmp (ns, "Global")))
1562 {
1563 SLang_verror (SL_NOT_IMPLEMENTED, "loading a file into a namespace is not supported");
1564 x = NULL;
1565 }
1566 else x = SLallocate_load_type (dirfile);
1567 #endif
1568 SLang_free_slstring (dirfile);
1569
1570 if (x == NULL)
1571 {
1572 vclose (vp);
1573 return -1;
1574 }
1575
1576 x->client_data = (VOID_STAR) vp;
1577 x->read = jed_read_from_file;
1578 ret = SLang_load_object (x);
1579 SLdeallocate_load_type (x);
1580 vclose (vp);
1581 return ret;
1582 }
1583 #if SLANG_VERSION < 10409
jed_load_file(char * file)1584 static int jed_load_file (char *file)
1585 {
1586 return jed_ns_load_file (file, NULL);
1587 }
1588 #endif
1589
1590 typedef struct
1591 {
1592 Line *l;
1593 char buf[256];
1594 }
1595 Buffer_Client_Type;
1596
jed_read_from_buffer(SLang_Load_Type * x)1597 static char *jed_read_from_buffer (SLang_Load_Type *x) /*{{{*/
1598 {
1599 Buffer_Client_Type *b;
1600 char *buf;
1601 Line *l;
1602 unsigned int len;
1603
1604 b = (Buffer_Client_Type *)x->client_data;
1605
1606 if (NULL == (l = b->l))
1607 return NULL;
1608
1609 len = (unsigned int) l->len;
1610 if (len > 255)
1611 {
1612 #if SLANG_VERSION >= 20000
1613 SLang_verror (SL_BUILTIN_LIMIT_EXCEEDED, "Line too long");
1614 #else
1615 SLang_verror (0, "Line too long");
1616 #endif
1617 return NULL;
1618 }
1619
1620 buf = b->buf;
1621 SLMEMCPY(buf, (char *) l->data, len);
1622 buf [len] = 0;
1623 b->l = l->next;
1624
1625 return buf;
1626 }
1627 /*}}}*/
1628
jed_load_buffer(char * ns)1629 void jed_load_buffer (char *ns) /*{{{*/
1630 {
1631 SLang_Load_Type *x;
1632 Buffer_Client_Type client_data;
1633 Buffer *cbuf = CBuf;
1634 int flags = CBuf->flags;
1635 Line *l, *lwant;
1636 char *file;
1637
1638 if (cbuf->file[0] == 0)
1639 file = cbuf->name;
1640 else
1641 file = cbuf->file;
1642
1643 file = jed_dir_file_merge (CBuf->dir, file);
1644 if (file == NULL)
1645 return;
1646
1647 x = SLns_allocate_load_type (file, ns);
1648 SLfree (file);
1649
1650 if (x == NULL)
1651 return;
1652
1653 x->read = jed_read_from_buffer;
1654 x->client_data = (VOID_STAR) &client_data;
1655 client_data.l = CBuf->beg;
1656
1657 cbuf->flags |= READ_ONLY;
1658 SLang_load_object(x);
1659 SLdeallocate_load_type (x);
1660
1661 if (buffer_exists (cbuf))
1662 cbuf->flags = flags;
1663 else cbuf = NULL;
1664
1665 if (SLang_get_error () == 0)
1666 return;
1667
1668 if (cbuf == NULL)
1669 return;
1670
1671 pop_to_buffer (cbuf->name);
1672 lwant = client_data.l;
1673
1674 if (lwant == NULL)
1675 {
1676 eob();
1677 return;
1678 }
1679
1680 bob();
1681 while (1)
1682 {
1683 l = CLine->next;
1684 if ((l == NULL) || (l == lwant)) break;
1685 (void) jed_down(1);
1686 }
1687 (void) jed_skip_whitespace();
1688 }
1689
1690 /*}}}*/
1691
1692 static SLang_Name_Type *Expand_File_Hook;
set_expansion_hook(char * s)1693 void set_expansion_hook (char *s) /*{{{*/
1694 {
1695 if (NULL == (Expand_File_Hook = SLang_get_function (s)))
1696 {
1697 msg_error ("The expansion hook has not been defined.");
1698 }
1699 }
1700
1701 /*}}}*/
1702
mini_complete(void)1703 int mini_complete (void) /*{{{*/
1704 {
1705 char *pl, *pb;
1706 char last[JED_MAX_PATH_LEN], buf[JED_MAX_PATH_LEN], *tmp;
1707 static char prev[JED_MAX_PATH_LEN];
1708 int n, last_key_char = SLang_Last_Key_Char;
1709 static int flag = 0; /* when flag goes 0, we call open */
1710
1711 if (complete_open == NULL) return ins_char_cmd();
1712
1713 bol ();
1714 jed_push_mark();
1715 eob();
1716 if (NULL == (tmp = make_buffer_substring(&n))) return(1);
1717
1718 safe_strcpy(buf, tmp, sizeof (buf));
1719 SLfree(tmp);
1720
1721 if ((last_key_char == ' ') && ((long) Last_Key_Function == (long) mini_complete))
1722 {
1723 if (flag)
1724 flag = (*complete_next)(buf);
1725 if (flag == 0)
1726 {
1727 safe_strcpy(buf, prev, sizeof (buf));
1728 flag = (*complete_open)(buf);
1729 }
1730 safe_strcpy(last, buf, sizeof (last));
1731 n = -1;
1732 }
1733 else
1734 {
1735 n = 0;
1736 safe_strcpy (prev, buf, sizeof (prev)); /* save this search context */
1737 }
1738
1739 if (!n)
1740 {
1741 if ((Repeat_Factor != NULL)
1742 || (complete_open != file_findfirst) || (Expand_File_Hook == NULL))
1743 flag = (*complete_open)(buf);
1744 else
1745 {
1746 int do_free;
1747 SLang_push_string (buf);
1748 SLexecute_function (Expand_File_Hook);
1749 if (SLang_get_error () == 0) SLang_pop_integer (&do_free);
1750 if (SLang_get_error () == 0)
1751 {
1752 if (do_free == 0)
1753 {
1754 flag = (*complete_open) (buf);
1755 goto start_loop;
1756 }
1757 }
1758
1759 if (SLang_get_error () || SLang_pop_slstring (&tmp))
1760 {
1761 msg_error ("Error encounter during expansion. Disabling expansion hook.");
1762 Expand_File_Hook = NULL;
1763 return 1;
1764 }
1765 safe_strcpy (last, tmp, sizeof (last));
1766 safe_strcpy (prev, last, sizeof (prev));
1767 SLang_free_slstring (tmp);
1768 flag = 0; /* So we do not call complete_next */
1769 n = -1;
1770 }
1771 }
1772
1773 start_loop:
1774
1775 if (!n && flag)
1776 {
1777 safe_strcpy(last, buf, sizeof (last));
1778
1779 /* This do loop tests all values from complete_next and returns the
1780 smallest length match of initial characters of buf */
1781 do
1782 {
1783 if ((n == 0) && (last_key_char == '\t'))
1784 {
1785 set_buffer (Completion_Buffer);
1786 erase_buffer ();
1787 CBuf->flags |= BURIED_BUFFER;
1788 (void) jed_insert_string ("!!! Use Page Up/Down keys to scroll this window. !!!\n");
1789 }
1790
1791 n++;
1792 pl = last;
1793 pb = buf;
1794
1795 #if !JED_FILE_PRESERVE_CASE
1796 if ((complete_open == open_bufflist)
1797 #if !JED_FILENAME_CASE_SENSITIVE
1798 || (complete_open == file_findfirst)
1799 #endif
1800 )
1801 while (*pl && (UPPER_CASE(*pl) == UPPER_CASE(*pb)))
1802 {
1803 pl++;
1804 pb++;
1805 }
1806 else /* next statement */
1807 #endif
1808 while (*pl && (*pl == *pb))
1809 {
1810 pl++;
1811 pb++;
1812 }
1813
1814
1815 *pl = 0;
1816
1817 if (last_key_char == '\t')
1818 {
1819 if (complete_open == file_findfirst)
1820 {
1821 char *file = jed_extract_file_or_dir (buf);
1822 (void) jed_quick_insert ((unsigned char *) file, strlen(file));
1823 }
1824 else
1825 {
1826 while (*pb) pb++;
1827 (void) jed_quick_insert ((unsigned char *)buf, (int) (pb - buf));
1828 }
1829 newline ();
1830 }
1831 }
1832 while(0 != (flag = (*complete_next)(buf)));
1833
1834 #if JED_FILE_PRESERVE_CASE
1835 /* OS/2 uses case-insensitive search on buffer-names. Set the
1836 * flag if there is an exact match, so that completion will
1837 * cycle without repeats through all the matches.
1838 */
1839 if (complete_open == open_bufflist)
1840 {
1841 safe_strcpy(buf, last, sizeof (buf));
1842 (*complete_open)(buf);
1843 do
1844 {
1845 if (!strcmp(buf, last))
1846 {
1847 flag = 1; break;
1848 }
1849 }
1850 while ((*complete_next)(buf));
1851 }
1852 #endif
1853 }
1854
1855 if ((n > 1) && (last_key_char == '\t') && (Last_Completion_Buffer == NULL))
1856 {
1857 Last_Completion_Windows = jed_num_windows () - 1; /* not including mini */
1858 Last_Completion_Buffer = pop_to_buffer (Completion_Buffer);
1859 bob ();
1860 }
1861
1862 while ((CBuf != MiniBuffer) || !IN_MINI_WINDOW) other_window ();
1863
1864 if (n)
1865 {
1866 erase_buffer();
1867 (void) jed_insert_string(last);
1868 if ((n == 1) && ((long) Last_Key_Function == (long) mini_complete))
1869 message("[Sole Completion.]");
1870 }
1871 else msg_error("No Match!");
1872
1873 return(1);
1874 }
1875
1876 /*}}}*/
1877
1878
copy_region_cmd(char * name)1879 void copy_region_cmd(char *name) /*{{{*/
1880 {
1881 Buffer *buf;
1882
1883 if (NULL != (buf = find_buffer(name)))
1884 {
1885 copy_region_to_buffer(buf);
1886 }
1887 else msg_error("Unable to find buffer.");
1888 }
1889
1890 /*}}}*/
1891
1892 #ifndef IBMPC_SYSTEM
1893
screen_w80(void)1894 void screen_w80 (void) /*{{{*/
1895 {
1896 tt_narrow_width ();
1897 jed_resize_display ();
1898 }
1899
1900 /*}}}*/
screen_w132(void)1901 void screen_w132 (void) /*{{{*/
1902 {
1903 tt_wide_width();
1904 jed_resize_display ();
1905 }
1906
1907 /*}}}*/
1908 #endif
1909
make_line_string(char * string,unsigned int buflen)1910 char *make_line_string(char *string, unsigned int buflen) /*{{{*/
1911 {
1912 unsigned char *tmp, *p1, *p2;
1913 unsigned int n;
1914
1915 if (CBuf->marks == NULL)
1916 {
1917 p1 = CLine->data + Point;
1918 p2 = CLine->data + CLine->len;
1919 }
1920 else
1921 {
1922 p1 = CLine->data + CBuf->marks->point;
1923 p2 = CLine->data + Point;
1924 if (p2 < p1)
1925 {
1926 tmp = p1; p1 = p2; p2 = tmp;
1927 }
1928 jed_pop_mark(0);
1929 }
1930 n = (unsigned int) (p2 - p1);
1931 if (n >= buflen) n = buflen - 1;
1932 SLMEMCPY(string, (char *) p1, n);
1933 string[n] = 0;
1934 return(string);
1935 }
1936
1937 /*}}}*/
1938
make_buffer_substring(int * np)1939 char *make_buffer_substring(int *np) /*{{{*/
1940 {
1941 Line *tthis, *beg;
1942 int n = 1, dn, thisp;
1943 unsigned char *buf;
1944
1945 if (!check_region(&n)) return (NULL); /* spot pushed */
1946 /* Point now at end of the region */
1947
1948 beg = tthis = CBuf->marks->line;
1949 thisp = CBuf->marks->point;
1950 n = 0;
1951 jed_pop_mark(0);
1952
1953 while (tthis != CLine)
1954 {
1955 n += tthis->len;
1956 tthis = tthis->next;
1957 }
1958 n -= thisp;
1959 n += Point;
1960
1961 if (NULL == (buf = (unsigned char *) SLmalloc (n + 1)))
1962 {
1963 pop_spot();
1964 return (NULL);
1965 }
1966
1967 if (CLine == (tthis = beg))
1968 {
1969 SLMEMCPY((char *)buf, (char *) (tthis->data + thisp), n);
1970 }
1971 else
1972 {
1973 n = 0;
1974 while (tthis != CLine)
1975 {
1976 dn = tthis->len - thisp;
1977 SLMEMCPY((char *)(buf + n), (char *) (tthis->data + thisp), dn);
1978 tthis = tthis->next;
1979 thisp = 0;
1980 n += dn;
1981 }
1982 SLMEMCPY((char *)(buf + n), (char *) tthis->data, Point);
1983 n += Point;
1984 }
1985 buf[n] = 0;
1986 *np = n;
1987 pop_spot();
1988 return ((char *) buf);
1989 }
1990
1991 /*}}}*/
1992
buffer_substring()1993 void buffer_substring() /*{{{*/
1994 {
1995 char *buf;
1996 int n;
1997 if (NULL == (buf = make_buffer_substring(&n))) return;
1998 SLang_push_malloced_string((char *)buf);
1999 }
2000
2001 /*}}}*/
2002
markp(void)2003 int markp(void) /*{{{*/
2004 {
2005 return (CBuf->marks != NULL);
2006 }
2007
2008 /*}}}*/
2009
dup_mark(void)2010 int dup_mark(void) /*{{{*/
2011 {
2012 if (CBuf->marks == NULL) return(0);
2013
2014 push_spot();
2015 jed_goto_mark(CBuf->marks);
2016 jed_push_mark();
2017 pop_spot();
2018 return(1);
2019 }
2020
2021 /*}}}*/
2022
mini_read(char * prompt,char * def,char * stuff)2023 void mini_read(char *prompt, char *def, char *stuff) /*{{{*/
2024 {
2025 char *buf;
2026 int n;
2027
2028 complete_open = NULL;
2029 if (NULL == (buf = read_from_minibuffer(prompt, def, stuff, &n)))
2030 SLang_push_string ("");
2031 else SLang_push_malloced_string(buf);
2032 }
2033
2034 /*}}}*/
2035
make_buffer_list(void)2036 void make_buffer_list(void) /*{{{*/
2037 {
2038 int n = 0;
2039 Buffer *b;
2040
2041 b = CBuf;
2042
2043 do
2044 {
2045 SLang_push_string(b->name);
2046 b = b->next;
2047 n++;
2048 }
2049 while (b != CBuf);
2050 SLang_push_integer(n);
2051 }
2052
2053 /*}}}*/
2054
jed_traceback(SLFUTURE_CONST char * s)2055 static void jed_traceback (SLFUTURE_CONST char *s) /*{{{*/
2056 {
2057 char *n;
2058
2059 if (Batch)
2060 {
2061 (void) fputs (s, stderr);
2062 return;
2063 }
2064
2065 n = CBuf->name;
2066 set_buffer("*traceback*");
2067 CBuf->flags |= BURIED_BUFFER;
2068 eob();
2069 (void) jed_insert_string(s);
2070 set_buffer(n);
2071 }
2072
2073 /*}}}*/
2074
2075 #if 0
2076 static struct /*{{{*/
2077 {
2078 int depth = 0;
2079 char *name[20];
2080 int marks[20];
2081 }
2082
2083 /*}}}*/
2084 FName_Stack;
2085
2086 void enter_function(char *name) /*{{{*/
2087 {
2088 if (depth > 20)
2089 {
2090 msg_error("Function Stack too deep.");
2091 return;
2092 }
2093 FName_Stack->name[depth] = name;
2094 FName_Stack->marks[depth] = 0;
2095 }
2096
2097 /*}}}*/
2098 void exit_function(char *name) /*{{{*/
2099 {
2100 int n = FName_Stack->marks[depth];
2101
2102 }
2103
2104 /*}}}*/
2105 #endif
2106
jed_clear_error(void)2107 static void jed_clear_error(void) /*{{{*/
2108 {
2109 *Error_Buffer = 0;
2110 SLKeyBoard_Quit = 0;
2111 }
2112
2113 /*}}}*/
2114
2115 typedef struct _Init_SLang_Hook_Type
2116 {
2117 int (*hook)(void);
2118 struct _Init_SLang_Hook_Type *next;
2119 }
2120 Init_SLang_Hook_Type;
2121
2122 static Init_SLang_Hook_Type *Init_SLang_Hooks;
2123
jed_add_init_slang_hook(int (* hook)(void))2124 int jed_add_init_slang_hook (int (*hook)(void))
2125 {
2126 Init_SLang_Hook_Type *h;
2127
2128 if (hook == NULL)
2129 return 0;
2130
2131 h = (Init_SLang_Hook_Type *)SLmalloc (sizeof (Init_SLang_Hook_Type));
2132 if (h == NULL)
2133 return -1;
2134
2135 h->hook = hook;
2136 h->next = Init_SLang_Hooks;
2137 Init_SLang_Hooks = h;
2138 return 0;
2139 }
2140
run_init_slang_hooks(void)2141 static int run_init_slang_hooks (void)
2142 {
2143 Init_SLang_Hook_Type *h;
2144
2145 h = Init_SLang_Hooks;
2146
2147 while (h != NULL)
2148 {
2149 if (-1 == (*h->hook)())
2150 return -1;
2151 h = h->next;
2152 }
2153
2154 while (Init_SLang_Hooks != NULL)
2155 {
2156 h = Init_SLang_Hooks->next;
2157 SLfree ((char *) Init_SLang_Hooks);
2158 Init_SLang_Hooks = h;
2159 }
2160
2161 return 0;
2162 }
2163
slang_exit_error_handler(SLFUTURE_CONST char * fmt,va_list ap)2164 static void slang_exit_error_handler (SLFUTURE_CONST char *fmt, va_list ap)
2165 {
2166 char buf [2048];
2167
2168 SLvsnprintf (buf, sizeof (buf), fmt, ap);
2169 exit_error (buf, 0);
2170 }
2171
vmsg_hook(SLFUTURE_CONST char * fmt,va_list ap)2172 static void vmsg_hook (SLFUTURE_CONST char *fmt, va_list ap)
2173 {
2174 char buf [2048];
2175 SLvsnprintf (buf, sizeof (buf), fmt, ap);
2176 message (buf);
2177 }
2178
jed_setup_minibuffer_keymap(void)2179 void jed_setup_minibuffer_keymap (void)
2180 {
2181 SLKeyMap_List_Type *m;
2182
2183 if (NULL == (m = SLang_find_keymap ("Mini_Map")))
2184 {
2185 if (NULL == (m = SLang_create_keymap("Mini_Map", Global_Map)))
2186 exit_error("Unable to create minibuffer keymap", 0);
2187
2188 SLang_undefine_key("\r", m);
2189 SLkm_define_key ("\r", (FVOID_STAR) exit_minibuffer, m);
2190 SLkm_define_key ("\t", (FVOID_STAR) mini_complete, m);
2191 SLkm_define_key (" ", (FVOID_STAR) mini_complete, m);
2192 }
2193 The_MiniBuffer->keymap = m;
2194 }
2195
2196
2197 #if SLANG_VERSION < 10405
2198 /* Work around a slang bug triggered by jed. Apps which use slang's
2199 * load_file function do not have this problem.
2200 */
2201 extern int (*_SLprep_eval_hook) (char *);
bug_fixed_prep_eval_expr(char * expr)2202 static int bug_fixed_prep_eval_expr (char *expr)
2203 {
2204 int ret;
2205 char *end;
2206
2207 end = strchr (expr, '\n');
2208 if (end == NULL)
2209 end = expr + strlen (expr);
2210 expr = SLmake_nstring (expr, (unsigned int) (end - expr));
2211 if (expr == NULL)
2212 return -1;
2213
2214 if ((0 != SLang_load_string (expr))
2215 || (-1 == SLang_pop_integer (&ret)))
2216 ret = -1;
2217 else
2218 ret = (ret != 0);
2219
2220 SLfree (expr);
2221 return ret;
2222 }
2223 #endif
2224
init_minibuffer()2225 void init_minibuffer() /*{{{*/
2226 {
2227 Buffer *tmp;
2228
2229 tmp = CBuf;
2230
2231 The_MiniBuffer = make_buffer (" <mini>", NULL, NULL);
2232 The_MiniBuffer->modes = 0;
2233 /* do some initializing */
2234 switch_to_buffer(The_MiniBuffer);
2235 remake_line(132);
2236 JMiniWindow = jed_create_minibuffer_window ();
2237 JMiniWindow->buffer = CBuf;
2238 Buffer_Local.tab = 0;
2239 switch_to_buffer(tmp);
2240 SLang_Dump_Routine = jed_traceback;
2241 SLang_Exit_Error_Hook = slang_exit_error_handler;
2242
2243 #ifdef __GO32__
2244 SLang_Interrupt = i386_check_kbd;
2245 #endif
2246
2247 #if 0
2248 SLang_Enter_Function = enter_function;
2249 SLang_Exit_Function = exit_function;
2250 #endif
2251 #if SLANG_VERSION < 10405
2252 _SLprep_eval_hook = bug_fixed_prep_eval_expr;
2253 #endif
2254
2255 if ((-1 == SLang_init_slang ())
2256 #ifndef SIXTEEN_BIT_SYSTEM
2257 || (-1 == SLang_init_slmath ())
2258 || (-1 == SLang_init_array ())
2259 #endif
2260 || (-1 == SLang_init_posix_process ())
2261 || (-1 == SLang_init_posix_dir ())
2262 /* || (-1 == SLang_init_slassoc ()) -- handled by SLang_init_slang */
2263 || (-1 == SLang_init_stdio ())
2264 || (-1 == SLang_init_posix_io ())
2265 || (-1 == SLang_init_ospath ())
2266 #if JED_HAS_IMPORT
2267 || (-1 == SLang_init_import ())
2268 #endif
2269 || (-1 == init_jed_intrinsics ())
2270 || (-1 == jed_init_userinfo ())
2271 #if JED_HAS_MENUS
2272 || (-1 == jed_init_menus ())
2273 #endif
2274 || (-1 == jed_init_syntax ())
2275 || (-1 == register_jed_classes ())
2276 || (-1 == jed_init_user_hooks ())
2277 || (-1 == run_init_slang_hooks ()))
2278 {
2279 exit_error("Unable to initialize S-Lang!", 0);
2280 }
2281
2282 /* use jed rouotines instead of default slang ones */
2283 SLang_Error_Hook = jed_error_hook;
2284 SLang_VMessage_Hook = vmsg_hook;
2285 SLang_User_Clear_Error = jed_clear_error;
2286 #if SLANG_VERSION < 10409
2287 SLang_Load_File_Hook = jed_load_file;
2288 #else
2289 SLns_Load_File_Hook = jed_ns_load_file;
2290 #endif
2291 }
2292
2293 /*}}}*/
2294