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