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