Logo Search packages:      
Sourcecode: jed version File versions

ledit.c

/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1992, 1998, 2000, 2002 John E. Davis
 * This file is part of JED editor library source.
 *
 * You may distribute this file under the terms the GNU General Public
 * License.  See the file COPYING for more information.
 */
#include "config.h"
#include "jed-feat.h"

/*{{{ Include Files */

#ifdef MSWINDOWS
# ifndef __WIN32__
#  include <toolhelp.h>
# else
#  include <windows.h>
# endif
#endif

#include <stdio.h>

#ifdef HAVE_SYS_WAIT_H
# include <sys/types.h>
# include <sys/wait.h>
#endif

#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif

#include <slang.h>
#include "jdmacros.h"

#include <string.h>

#ifdef IBMPC_SYSTEM
# include <fcntl.h>
#endif

#include <stdarg.h>

#include "buffer.h"
#include "keymap.h"
#include "file.h"
#include "ins.h"
#include "ledit.h"
#include "screen.h"
#include "window.h"
#include "display.h"
#include "search.h"
#include "misc.h"
#include "replace.h"
#include "paste.h"
#include "sysdep.h"
#include "cmds.h"
#include "text.h"
#include "hooks.h"
#include "undo.h"
#include "menu.h"
#include "userinfo.h"
#include "indent.h"

#ifdef __WIN32__
# include "win32.h"
#endif

#define JED_PROMPT "S-Lang>"

#if JED_HAS_SUBPROCESSES
# include "jprocess.h"
#endif


/*}}}*/

Buffer *MiniBuffer;
Buffer *The_MiniBuffer;     /* this never gets deleted since we may need it */
Window_Type *The_MiniWindow;

static Buffer *Last_Buffer;

extern char *get_cwd(void);
int Ignore_Beep = 0;
int MiniBuffer_Active = 0;

char *Jed_Library;

/* Do not change this value without changing sys_findfirst/next. */
#define JED_MAX_COMPLETION_LEN JED_MAX_PATH_LEN   

static int (*complete_open)(char *);
static int (*complete_next)(char *);
static int Buf_List_Len;
Buffer *Buf_Context;

static char *Expect_File_Error = "Expecting filename.";

static int next_bufflist(char *buf) /*{{{*/
{
   Buffer *tthis;
   while (1)
     {
      tthis = Buf_Context;
      if (tthis == MiniBuffer) return(0);
      Buf_Context = Buf_Context->next;

      if ((Buf_List_Len == 0)
#if JED_FILE_PRESERVE_CASE
          || (0 == strncmp (buf, tthis->name, Buf_List_Len))
#else
          || (0 == jed_case_strncmp (buf, tthis->name, Buf_List_Len))
#endif
          )
        {
           if (*tthis->name == ' ') continue;   /* internal buffers */
           safe_strcpy (buf, tthis->name, JED_MAX_COMPLETION_LEN);
           return 1;
        }
     }
}

/*}}}*/

static int open_bufflist(char *buf) /*{{{*/
{
   if ((Buf_Context = MiniBuffer) == NULL) return(0);
   Buf_Context = Buf_Context->next;
   Buf_List_Len = strlen(buf);
   return next_bufflist(buf);
}

/*}}}*/

char *what_buffer() /*{{{*/
{
   return (CBuf->name);
}

/*}}}*/

int bufferp(char *name) /*{{{*/
{
   if (NULL == find_buffer(name)) return(0); else return(1);
}

/*}}}*/

int insert_buffer_name(char *name) /*{{{*/
{
   Buffer *buf;
   
   if (NULL != (buf = find_buffer(name)))
     {
      insert_buffer(buf);
      return(1);
     }
   else msg_error("Unable to find buffer.");
   return(0);
}

/*}}}*/

int replace_cmd(char *old, char *neew) /*{{{*/
{
   int n = 0;
   
   CHECK_READ_ONLY
     push_spot ();
   if (search(old, 1, 0)) while(replace_next(old, neew)) n++;
   pop_spot();
   return n;
}

/*}}}*/

static Buffer *find_scratch_buffer (void) /*{{{*/
{
   char *sname = "*scratch*";
   Buffer *scratch;
   
   scratch = find_buffer (sname);
   if (NULL == scratch)
     scratch = make_buffer (sname, CBuf->dir, NULL);
   return scratch;
}

/*}}}*/


/* Try to find any other buffer but kill_buf such that the buffer is not
 * visible, not scratch and not buried.
 */
static Buffer *find_non_visible_buffer (Buffer *kill_buf) /*{{{*/
{
   Buffer *buf, *scratch;
   
   buf = kill_buf->next;
   scratch = find_scratch_buffer ();
   
   while ((buf != kill_buf) &&
        ((*buf->name == ' ') || (buf->flags & BURIED_BUFFER)
         || (buf == scratch) || (buffer_visible(buf))))
     {
      buf = buf->next;
     }
   if (buf == kill_buf) buf = scratch;
   return buf;
}

/*}}}*/



int kill_buffer_cmd(char *name) /*{{{*/
{
   Buffer *this_buf, *kill_buf, *scratch, *buf;
   Window_Type *w;
   int do_kill;
   
   if (NULL == (kill_buf = find_buffer(name)))
     {
      msg_error("Buffer does not exist.");
      return(0);
     }

   /* Do not allow the minibuffer to be deleted.  Otherwise, the whole 
    * minibuffer creation/selection needs to be cleaned up.
    */
   if (kill_buf == The_MiniBuffer)
     return 0;

   this_buf = CBuf;
   switch_to_buffer(kill_buf);
   
#if JED_HAS_SUBPROCESSES
   if (kill_buf->locked)
     {
      erase_buffer ();
      switch_to_buffer (this_buf);
      return 0;
     }
#endif
   
   do_kill = 1;
   if ((*name != ' ') && (kill_buf->flags & BUFFER_MODIFIED))
     {
      jed_vmessage (1, "Buffer %s modified. (K)ill, (S)ave first, (A)bort:",
                  name);

      /* This does not go through keyboard macro routines
       * on purpose! 
       */
      switch (my_getkey())
        {
         case 'k': case 'K': do_kill = 1; break;
         case 's': case 'S': do_kill = 2; break;
         default: msg_error("Aborted."); return(0);
        }
      clear_message ();
     }
   
   if (do_kill == 2)
     {
      jed_save_buffer_as_cmd ();
      if (SLang_Error)
        {
           switch_to_buffer(this_buf);
           return(0);
        }
     }
   
   /* if it is the scratch buffer, just erase it since we are going to 
      recreate it anyway. */
   
   scratch = find_scratch_buffer ();
   
   if (kill_buf == scratch)
     {
      erase_buffer();
#if JED_HAS_SUBPROCESSES
      if (kill_buf->subprocess) jed_kill_process (kill_buf->subprocess - 1);
#endif
      switch_to_buffer(this_buf);
      return 1;
     }

   buf = find_non_visible_buffer (kill_buf);

   /* search through windows looking for the buffer and replace it */
   w = JWindow;
   do
     {
      if (kill_buf == JWindow->buffer)
        {
           touch_window_hard (JWindow, 0);
           window_buffer(buf); 
           buf = find_non_visible_buffer (kill_buf);
        }
      JWindow = JWindow->next;
     }
   while (w != JWindow);

   if (kill_buf == Last_Buffer) Last_Buffer = NULL;
   if (kill_buf == this_buf) this_buf = buf;
   switch_to_buffer(this_buf);
   delete_buffer(kill_buf);
   return 1;
}

/*}}}*/

int jed_save_buffer_to_file (char *dir, char *file)
{
   int status;
   char *dirfile;

   if ((file == NULL) || (*file == 0))
     {
      file = CBuf->file;
      if (*file == 0)
        {        
           msg_error ("Filename Required.");
           return -1;
        }
     }

   if (NULL == (dirfile = jed_dir_file_merge (dir, file)))
     return -1;

   if (file_changed_on_disk (CBuf, dirfile) > 0)
     {
      if (0 == jed_get_yes_no("File changed on disk.  Save anyway?"))
        {
           SLfree (dirfile);
           return -1;
        }
     }

   if (-1 == jed_va_run_hooks ("_jed_save_buffer_before_hooks",
                         JED_HOOKS_RUN_ALL, 1, dirfile))
     {
      auto_save_buffer (CBuf);
      SLfree (dirfile);
      return -1;
     }

   if (((status = write_file_with_backup (dirfile)) >= 0)
       && (Batch != 2))
     jed_vmessage (0, "Wrote %d lines to %s", status, dirfile);

   if (status < 0)
     {
      jed_verror ("Error writing file %s", dirfile);
      SLfree (dirfile);
      return -1;
     }

      
   CBuf->flags |= AUTO_SAVE_BUFFER;
   CBuf->hits = 0;

#ifdef UNDO_HAS_REDO
   update_undo_unchanged ();
#endif
   visit_file (dir, file);

   if (-1 == jed_va_run_hooks ("_jed_save_buffer_after_hooks", JED_HOOKS_RUN_ALL,
                         1, dirfile))
     {
      SLfree (dirfile);
      return -1;
     }
   
   SLfree (dirfile);
   return 0;
}


int jed_save_buffer_as (char *filestr)
{
   char *dir, *file;
   int status;

   filestr = jed_expand_filename (filestr);
   
   if (-1 == jed_dirfile_to_dir_file (filestr, &dir, &file))
     {
      SLfree (filestr);
      return -1;
     }

   status = jed_save_buffer_to_file (dir, file);
   
   SLfree (filestr);
   SLfree (dir);
   SLfree (file);

   if (status == -1)
     return status;

   /* This function is an intrinsic and is documented to return the 
    * number of lines written out.
    * 
    */
   return 0;
}

int jed_save_buffer_cmd (void)
{
   if ((CBuf->file == NULL) || (CBuf->file[0] == 0))
     return jed_save_buffer_as_cmd ();
   
   return jed_save_buffer_to_file (CBuf->dir, CBuf->file);
}

#if defined(__BORLANDC__) && !defined(MSWINDOWS)
int show_memory() /*{{{*/
{
   struct farheapinfo hi;
   char *c;
   unsigned long total = 0, core, used = 0;
   unsigned long max = 0;
   int i = 0;
   
   hi.ptr = NULL;
   if (farheapcheck() == _HEAPCORRUPT) c = "corrupt"; else c = "ok";
   while (farheapwalk(&hi) == _HEAPOK)
     {
      if (hi.in_use)
        used += hi.size;
      else
        {
           total += hi.size;
           if (hi.size > max) max = hi.size;
           i++;
        }
     }
   core = farcoreleft();
   jed_vmessage (0, "used:%lu, core:%lu, free:%lu, grand:%lu, max:%lu, frag:%d (%s)",
             used, core, total, core + total, max, i, c);
   return 0;
}

/*}}}*/

#endif

#ifdef MSWINDOWS
int show_memory (void) /*{{{*/
{
#ifndef __WIN32__
   MEMMANINFO mmi;
   if (MemManInfo(&mmi))
     {
      jed_vmessage (0, "tot pages: %lu, free pages: %lu",
                  mmi.dwTotalLinearSpace, mmi.dwFreeLinearSpace);
     }
#else
   MEMORYSTATUS mst;
   GlobalMemoryStatus(&mst);
   jed_vmessage (0, "avail space: %lu, tot phys space: %lu, avail phys space: %lu",
             mst.dwAvailPhys + mst.dwAvailPageFile, mst.dwTotalPhys, mst.dwAvailPhys);
#endif
   
   return 0;
}

/*}}}*/

#endif

#ifdef __WATCOMC__
#include <malloc.h>
int show_memory() /*{{{*/
{
   jed_vmessage (0, "avail mem: %lu, tot phys pgs: ???, free lin space: %lu",
             _memavl (), _memmax ());
   return 0;
}

/*}}}*/

#endif

#ifdef __GO32__
#include <dpmi.h>

int show_memory() /*{{{*/
{
   unsigned long mem;
   _go32_dpmi_meminfo info;
   
   _go32_dpmi_get_free_memory_information(&info);
   
   if ((long)info.available_physical_pages != -1L)
     mem = info.available_physical_pages * 4096UL;
   else mem = info.available_memory;

   jed_vmessage (0, "avail mem: %lu, tot phys pgs: %lu, free lin space: %lu",
             mem, info.total_physical_pages, info.free_linear_space);
   return 0;
}

/*}}}*/

#endif

int set_buffer(char *name) /*{{{*/
{
   Buffer *buf;
   
   if ((name == NULL) || (*name == 0))
     {
      msg_error("set_buffer: Buffer name is NULL");
      return (0);
     }
   
    /* Last_Buffer = CBuf; */
   
   if (NULL == (buf = find_buffer(name)))
     buf = make_buffer (name, CBuf->dir, NULL);
   switch_to_buffer(buf);
   
   return 1;
}

/*}}}*/

int jed_get_mini_response (char *s)
{
   int ch;
   int len;

   if (Batch)
     {
      if (EOF == fputs (s, stdout))
        exit_error ("Failed to write to stdout", 0);
      
      return jed_getkey ();
     }
          
   len = strlen (s);
   if (len > Jed_Num_Screen_Cols)
     s += (len - Jed_Num_Screen_Cols);

   MiniBuf_Get_Response_String = s;
   update (NULL, 0, 0, 0);
   ch = jed_getkey ();
   MiniBuf_Get_Response_String = NULL;
   return ch;
}

static char *strcat_malloc (char *a, char *b)
{
   unsigned int len;
   char *c;

   len = strlen (a);

   if (NULL == (c = SLmalloc (len + strlen (b) + 1)))
     return NULL;

   strcpy (c, a);
   strcpy (c + len, b);
   return c;
}


int jed_get_y_n (char *question)
{
   int ans;
   char *yn_quest;

   if (NULL == (yn_quest = strcat_malloc (question, "? (y/n)")))
     return -1;

   ans = jed_get_mini_response (yn_quest);
   SLfree (yn_quest);

   if ((ans == 'y') || (ans == 'Y'))
     return 1;
   if ((ans == 'n') || (ans == 'N'))
     return 0;
   if (SLKeyBoard_Quit || (SLang_Error == SL_USER_BREAK))
     return -1;
   jed_beep ();
   flush_input ();
   return jed_get_yes_no (question);
}


int jed_vget_y_n (char *fmt, char *arg)
{
   char msg [1024];

   if (arg == NULL) 
     {
      arg = fmt;
      fmt = "%s";
     }
   
   _SLsnprintf (msg, sizeof (msg), fmt, arg);
   
   return jed_get_y_n (msg);
}


int jed_get_yes_no (char *question) /*{{{*/
{
   char *yn_quest;
   char *tmp;
   int n;
   
   if (NULL == (yn_quest = strcat_malloc (question, "? (yes or no)")))
     return -1;

   while (1)
     {
      if (NULL == (tmp = read_from_minibuffer(yn_quest, 0, NULL, &n))) 
        {
           SLfree (yn_quest);
           return -1;
        }

      if (!strcmp(tmp, "yes"))
        {
           SLfree(tmp);
           SLfree (yn_quest);
           return 1;
        }
      
      if (!strcmp(tmp, "no"))
        {
           SLfree(tmp);
           SLfree (yn_quest);
           return 0;
        }
      msg_error("Answer `yes' or `no'.");
      SLfree(tmp);
     }
}

/*}}}*/

int find_file_cmd (char *filestr)       /* filestr is const ! */ /*{{{*/
{
   Buffer *buf;
   int status;
   char *dirfile, *dir, *file;
   char *name;

   filestr = jed_expand_filename (filestr);
   if (filestr == NULL)
     return -1;

   /* If this hook returns 1, then the file is considered to be found. */
   if (1 == jed_va_run_hooks ("_jed_find_file_before_hooks", JED_HOOKS_RUN_UNTIL_NON_0,
                        1, filestr))
     {
      SLfree (filestr);
      return 0;
     }

   dirfile = jed_expand_link(filestr);

   if (dirfile == NULL)
     {
      SLfree (filestr);
      return -1;
     }

   if (-1 == jed_dirfile_to_dir_file (filestr, &dir, &file))
     {
      SLfree (filestr);
      SLfree (dirfile);
      return -1;
     }

   status = -1;
   
   if (*file == 0)
     {
      jed_verror (Expect_File_Error);
      goto free_and_return;
     }

   check_buffers ();
   
   /* search for the file in current buffer list */
   
   if (NULL != (buf = find_file_buffer (dirfile)))
     {
      if ((file_changed_on_disk (buf, dirfile) > 0)
          && (1 == jed_get_yes_no("File changed on disk.  Read From Disk")))
        {
           int n = (int) buf->linenum;
           mark_buffer_modified (buf, 0, 1);
           kill_buffer_cmd (buf->name);
           status = find_file_cmd (filestr);
           goto_line (&n);
           goto free_and_return;
        }

      if (SLang_Error)
        goto free_and_return;

      status = 1;
      switch_to_buffer (buf);
      goto free_and_return;
     }

   /* Make a buffer but do not attach it to a file yet. */
   name = extract_file (filestr);

   buf = make_buffer (name, dir, NULL);
   switch_to_buffer(buf);

   status = read_file (dirfile);
      
   switch (status)
     {
      case -2:
      jed_verror ("File %s not readable.", dirfile);
      status = -1;
      break;
           
      case -1:
      message ("New file.");
      status = 0;
      break;
           
      default:
      jed_vmessage (0, "%d lines read", status);
      status = 1;
     }

   if (buf == CBuf)                  /* check this in case the hook switches buffers */
     {
      mark_buffer_modified (CBuf, 0, 0);

      /* Now attach it to a file */
      visit_file (dir, file);
      uniquely_name_buffer (CBuf, name);

      (void) bob ();
      set_file_modes();
      CBuf->flags |= UNDO_ENABLED;
     }

   if (-1 == jed_va_run_hooks ("_jed_find_file_after_hooks", JED_HOOKS_RUN_ALL, 0))
     status = -1;

   free_and_return:

   SLfree (dirfile);
   SLfree (filestr);
   SLfree (dir);
   SLfree (file);

   return status;
}

/*}}}*/


int find_file_in_window(char *file) /*{{{*/
{
   int ret;
   Buffer *b = CBuf;
   
   ret = find_file_cmd (file);
   if ((b != CBuf) && (*CBuf->name != ' ')) Last_Buffer = CBuf;
   window_buffer(CBuf);
   return(ret);
}

/*}}}*/


/* create a minibuffer with window and switch to it. */
static void create_minibuffer(void) /*{{{*/
{
   Window_Type *w;
   MiniBuffer = The_MiniBuffer;
   
   /* We may get called before the keymap has been set up.  Make sure that
    * we have a keymap.
    */
   if ((The_MiniBuffer->keymap == NULL)
       || (The_MiniBuffer->keymap == Global_Map))
     jed_setup_minibuffer_keymap ();

   /* I want to make Mini_Window->next = Current Window so that scroll other
      window routines will scroll it. */
   
   w = JWindow;
   do other_window(); while (JWindow->next != w);
   JWindow->next = The_MiniWindow;
   The_MiniWindow->next = w;
   The_MiniWindow->hscroll_column = 1;
   Mini_Info.action_window = w;
   other_window();    /* now in minibuffer window */
   window_buffer(MiniBuffer);
   switch_to_buffer(MiniBuffer);
   MiniBuffer_Active = 1;
   erase_buffer ();

#if JED_HAS_TTY_MENUS
   jed_notify_menu_buffer_changed ();
#endif

   /* allow kill region to kill to beginning of minibuffer. 
    * Suggested by stefen@uni-paderborn.de */
   push_mark ();
}

/*}}}*/

char *Completion_Buffer = "*Completions*";

static char *Last_Completion_Buffer;
static int Last_Completion_Windows;

/* evaluate command in minibuffer and leave */
int exit_minibuffer() /*{{{*/
{
   if (IS_MINIBUFFER)
     {
      if (Last_Completion_Buffer != NULL)
        {
           pop_to_buffer (Completion_Buffer);
           mark_buffer_modified (CBuf, 0, 0);
           switch_to_buffer_cmd (Last_Completion_Buffer);
           kill_buffer_cmd (Completion_Buffer);
           touch_window_hard (JWindow, 0);
           if (Last_Completion_Windows == 1) one_window ();
        }
        select_minibuffer ();
      Exit_From_MiniBuffer = 1;
     }
   Last_Completion_Buffer = NULL;
   return(0);
}

/*}}}*/

/* return 1 if minibuffer already exists otherwise returns 0 */
int select_minibuffer() /*{{{*/
{
   Window_Type *w;
   
    /* Try to find active minibuffer and go there */
   w = JWindow;
   while (MiniBuffer != NULL)
     {
      if (JWindow->sy+1 == Jed_Num_Screen_Rows) return(1);
      other_window();
      if (w == JWindow) exit_error("Internal Error:  no window!", 1);
     }
   
    /* switchs to minibuffer too */
   create_minibuffer();
   return(0);
}

/*}}}*/

/* if cmd != NULL, insert it into minibuffer and then send the result to
   the appropriate routine. */

static int ledit(void) /*{{{*/
{
   int n;
   char *tmp;
   
   if (MiniBuffer == NULL) complete_open = NULL;
   if (NULL == (tmp = read_from_minibuffer(JED_PROMPT, 0, NULL, &n))) return(0);
   SLang_Error = 0;
   Suspend_Screen_Update = 1;
   
   SLang_load_string(tmp);
   SLfree(tmp);
   
   if ((SLang_Error == -1) && SLKeyBoard_Quit)
     {
      msg_error("Quit!");
     }
   SLang_Error = 0;
   
   return(1);
}

/*}}}*/

static char *read_file_from_minibuffer(char *prompt, char *def) /*{{{*/
{
   int n;
   char *file;

   complete_open = sys_findfirst;
   complete_next = sys_findnext;
   
   if (*CBuf->dir == 0)
     buffer_filename (CBuf, NULL, CBuf->file);

   file = read_from_minibuffer (prompt, def, CBuf->dir, &n);
   return file;
}

/*}}}*/

static char *String_Completion_Str;
static char *String_Completion_Str_Next;
static int String_Completion_Str_Len;


static int next_string_list (char *buf) /*{{{*/
{
   register char *s = String_Completion_Str_Next;
   int len;
   while (*s)
     {
      while (*s && (*s != ',')) s++;
      len = (int) (s - String_Completion_Str_Next);
      
      if (*s == ',') s++;
      
      if (!len
          || strncmp (buf, String_Completion_Str_Next, String_Completion_Str_Len))
        {
           String_Completion_Str_Next = s;
           continue;
        }
      if (len >= JED_MAX_PATH_LEN) len = JED_MAX_PATH_LEN - 1;
      strncpy (buf, String_Completion_Str_Next, len);
      buf[len] = 0;
      String_Completion_Str_Next = s;
      return 1;
     }
   String_Completion_Str_Next = s;
   return 0;
}

/*}}}*/

static int open_string_list (char *buf) /*{{{*/
{
   String_Completion_Str_Next = String_Completion_Str;
   String_Completion_Str_Len = strlen (buf);
   return next_string_list (buf);
}

/*}}}*/


void read_object_with_completion(char *prompt, char *dflt, char *stuff, int *typep) /*{{{*/
{
   int type = *typep, n;
   char buf[JED_MAX_COMPLETION_LEN], *tmp;
   char *str = NULL;

   *buf = 0;
   if (type == 'f')                  /* file */
     {
      complete_open = sys_findfirst;
      complete_next = sys_findnext;
      if (*CBuf->dir == 0) 
        buffer_filename (CBuf, NULL, CBuf->file);
      safe_strcpy (buf, CBuf->dir, sizeof (buf));
     }
   else if (type == 'b')             /* buffer */
     {
      complete_open = open_bufflist;
      complete_next = next_bufflist;
     }
   else if (type == 'F')             /* function */
     {
      complete_open = open_function_list;
      complete_next = next_function_list;
     }
   else if (type == 's')
     {
      complete_open = open_string_list;
      complete_next = next_string_list;
      if (SLpop_string (&str)) return;
      String_Completion_Str = str;
     }
   else
     {
      complete_open = NULL;
     }
   
   safe_strcat (buf, stuff, sizeof (buf));
   
   if (NULL != (tmp = read_from_minibuffer(prompt, dflt, buf, &n)))
     {
      if (type == 'f') SLang_push_string(expand_filename(tmp));
      else SLang_push_string(tmp);
      
      SLfree(tmp);
      if (str != NULL) SLfree (str);
     }
}

/*}}}*/

int insert_file_cmd (void) /*{{{*/
{
   char *filebuf, *f, *file;
   
   CHECK_READ_ONLY
     
     if (NULL == (filebuf = read_file_from_minibuffer("Insert file:", NULL)))
       return -1;

   file = expand_filename(filebuf);
   SLfree (filebuf);
   f = extract_file(file);
   if ((*file == 0) || (*f == 0))
     {
      msg_error(Expect_File_Error);
      return(1);
     }
   
   if (insert_file(file) < 0) msg_error("Error inserting file.");
   return(1);
}

/*}}}*/

int find_file (void) /*{{{*/
{
   char *file, *f;
   int status;

   if (NULL == (file = read_file_from_minibuffer("Find file:", (char *) NULL))) 
     return 0;
   
   f = extract_file (file);
   if (*f == 0)
     {
      char *dirfile = jed_dir_file_merge (file, CBuf->file);
      SLfree (file);
      if (dirfile == NULL)
        return -1;
      file = dirfile;
     }

   status = find_file_in_window (file);
   SLfree (file);
   return status;
}

/*}}}*/

int jed_save_buffer_as_cmd (void) /*{{{*/
{
   char *tmp;
   
   if (NULL == (tmp = read_file_from_minibuffer("Save as:", (char *) NULL))) return(0);
   (void) jed_save_buffer_as (tmp);
   SLfree(tmp);
   return(1);
}

/*}}}*/

void switch_to_buffer_cmd (char *name) /*{{{*/
{
   Buffer *tthis = CBuf;
   
   set_buffer(name);
   window_buffer(CBuf);
   if ((CBuf != tthis) && (*CBuf->name != ' ')) Last_Buffer = tthis;
}

/*}}}*/

static void get_last_buffer(void) /*{{{*/
{
   if ((Last_Buffer == CBuf) || (Last_Buffer == NULL)
       || (*Last_Buffer->name == ' ')
       || (Last_Buffer->flags & BURIED_BUFFER))
     {
      Last_Buffer = find_non_visible_buffer (CBuf);
     }
}

/*}}}*/

int get_buffer() /*{{{*/
{
   char *tmp;
   int n;
   complete_open = open_bufflist;
   complete_next = next_bufflist;
   
   get_last_buffer ();
   
   if (NULL == (tmp = read_from_minibuffer("Switch to buffer:", Last_Buffer->name, NULL, &n))) return(0);
   switch_to_buffer_cmd(tmp);
   SLfree(tmp);
   return(1);
}

/*}}}*/

int kill_buffer (void) /*{{{*/
{
   char *tmp;
   int n;
   
   complete_open = open_bufflist;
   complete_next = next_bufflist;
   tmp = read_from_minibuffer("Kill buffer:", (char *) CBuf->name, NULL, &n);
   if (tmp != NULL)
     {
#if JED_HAS_SUBPROCESSES
      Buffer *b = find_buffer(tmp);
      if ((b != NULL) && (b->subprocess))
        {
           if (0 == jed_get_yes_no("Buffer has a subprocess attached.  Delete anyway"))
             {
              SLfree(tmp);
              return 0;
             }
        }
#endif
      kill_buffer_cmd(tmp);
      SLfree(tmp);
      return(1);
     }
   return 0;
}

/*}}}*/

int evaluate_cmd() /*{{{*/
{
   return(!ledit());
}

/*}}}*/


/* This is weird, Ultrix cc will not compile if set_key comes before unset_key */
void unset_key(char *key) /*{{{*/
{
   if (*key)
     SLang_undefine_key(key, Global_Map);
}

/*}}}*/

void set_key(char *function, char *key) /*{{{*/
{
   if (*key)
     SLang_define_key(key, function, Global_Map);
}

/*}}}*/

void unset_key_in_keymap(char *key, char *map) /*{{{*/
{
   SLKeyMap_List_Type *kmap;
   
   if (NULL == (kmap = SLang_find_keymap(map)))
     {
      jed_verror ("Unknown keymap: %s", map);
      return;
     }
   
   if (*key) SLang_undefine_key(key, kmap);
}

/*}}}*/

int keymap_p(char *name) /*{{{*/
{
   return ! (NULL == SLang_find_keymap(name));
}

/*}}}*/

void set_key_in_keymap(char *f, char *key, char *map) /*{{{*/
{
   SLKeyMap_List_Type *kmap;
   
   if (NULL == (kmap = SLang_find_keymap(map)))
     {
      jed_verror ("Unknown keymap: %s", map);
      return;
     }
   
   if (*key) SLang_define_key(key, f, kmap);
}

/*}}}*/

char *pop_to_buffer(char *name) /*{{{*/
{
   Window_Type *w, *action, *use_this;
   char *bname;
   Line *line, *oldline;
   int p, oldp, lnum, oldlnum;
   Buffer *b, *oldb;
   
   if (!strcmp(name, " <mini>"))
     {
      select_minibuffer ();
      return CBuf->name;
     }
   
   /* save position so we can pop back to it if buffer already exists in 
      window */
   oldb = CBuf; oldline = CLine; oldp = Point; oldlnum = LineNum;
   
   set_buffer(name);
   line = CLine; p = Point; lnum = LineNum;
   
   use_this = NULL;
   if (MiniBuffer != NULL)
     {
      action = Mini_Info.action_window;
     }
   else action = NULL;

   if (Batch) return CBuf->name;

   w = JWindow;
   /* find a window to use */
   do
     {
      if (w->sy + 1 != Jed_Num_Screen_Rows)
        {
           if (action != NULL)
             {
              if (w != action) use_this = w;
             }
           else if (w != JWindow) use_this = w;
           
           if (w->buffer == CBuf)
             {
              use_this = w;
              break;
             }
        }
      w = w->next;
     }
   while (w != JWindow);
   
   b = CBuf;
   if (use_this != NULL)
     {
      while(JWindow != use_this) other_window();
      /* This is a good reason for haveing otherwindow avoid switching buffers */
      if (CBuf == oldb)
        {
           CLine = oldline; Point = oldp; LineNum = oldlnum;
        }
     }
   else
     {
      if (action != NULL) while(JWindow != action) other_window();
      split_window();
      /* 
       * doing it this way makes screen update look better
       */
      w = JWindow;
      do
        {
           other_window();
        }
      while (JWindow->buffer != w->buffer);
      JWindow->hscroll_column = 1;
     }
   
   bname = CBuf->name;
   switch_to_buffer(b);
   b->line = CLine = line;
   b->point = Point = p;
   b->linenum = LineNum = lnum;
   if (b != JWindow->buffer) window_buffer(b);
   return bname;
}

/*}}}*/

/* return number of windows */
int num_windows() /*{{{*/
{
   Window_Type *w;
   int i = 0;
   
   w = JWindow->next;
   while (i++, w != JWindow) w = w->next;
   return(i);
}

/*}}}*/

/* I need to make this take another parameter which indicates what to do 
 * with the cursor rather than sticking it at the end.  Call the parameter p.
 * Then try:
 * if (p <= 0) p = strlen(Message_Buffer) + 1;
 * tt_goto_rc(Screen_Height, p); */

void flush_message(char *m) /*{{{*/
{
   message(m);
   if (Batch || (JWindow == NULL)) return;
   do_dialog(Message_Buffer);
   SLsmg_gotorc (Jed_Num_Screen_Rows - 1, strlen(Message_Buffer));
   *Message_Buffer = 0;
   JWindow->trashed = 1;
   SLsmg_refresh ();
}

/*}}}*/

#if defined (REAL_UNIX_SYSTEM) || defined(__WIN32__) || (defined (__os2__) && !defined(__WATCOMC__))

# if defined (__WIN32__) /* defined (__BORLANDC__) || defined (_MSC_VER) */
#  undef popen
#  undef pclose
#  define popen w32_popen
#  define pclose w32_pclose
# endif

# ifdef     __IBMC__
extern FILE *popen(char *, char *);
extern int pclose(FILE *);
# endif

# if !JED_HAS_SUBPROCESSES
#  define jed_popen popen
#  define jed_pclose pclose
# endif

static char *Process_Error = "Unable to open process.";
int shell_command(char *cmd) /*{{{*/
{
   FILE *pp;
   VFILE *vp;
   int status;
   
   if (Jed_Secure_Mode)
     {
      msg_error ("Access denied.");
      return -1;
     }
   
   if (NULL == (pp = jed_popen(cmd, "r")))
     {
      msg_error(Process_Error);
      return -1;
     }
   
   if (NULL != (vp = vstream(fileno(pp), 0, VFILE_TEXT)))
     {
      (void) insert_file_pointer(vp);
      SLfree(vp->buf);
      SLfree ((char *)vp);
     }
   else     msg_error("Malloc Error.");
   
   status = jed_pclose (pp);
   
#if defined(WIFEXITED) && defined(WEXITSTATUS)
   if ((status != -1) && WIFEXITED(status))
     {
      status = WEXITSTATUS(status);
     }
#endif
   return status;
}

/*}}}*/
int pipe_region(char *cmd) /*{{{*/
{
   FILE *pp;
   int n;
   
   if (Jed_Secure_Mode)
     {
      msg_error ("Access denied.");
      return -1;
     }
   
   if (NULL == (pp = jed_popen (cmd, "w")))
     {
      msg_error(Process_Error);
      return(-1);
     }
   
   n = write_region_to_fp(fileno(pp));
   if (n == -1)
     msg_error ("pipe_region: write failed");
   
   return jed_pclose (pp);
}

/*}}}*/
#endif

/* 
 * Try to open a .slc then a .sl
 */
#ifdef SIXTEEN_BIT_SYSTEM
#define VFILE_BUF_SIZE 1024
#else
#define VFILE_BUF_SIZE 4096
#endif


static VFILE *jed_open_lib_file (char *file, char **dirfile) /*{{{*/
{
   char libfsl[JED_MAX_PATH_LEN], libfslc[JED_MAX_PATH_LEN];
   char *lib, *type, *libf;
   unsigned int n;
   VFILE *vp = NULL;

   libf = file;
   lib = Jed_Library;

   /* If file begins with ./,then read it from the current directory */
   if ((0 == strncmp (file, "./", 2))
#ifdef IBMPC_SYSTEM
       || (0 == strncmp (file, ".\\", 2))
       || (0 == strncmp (file, "..\\", 3))
#endif
       || (0 == strncmp (file, "../", 3)))
     {
      if (NULL == (lib = get_cwd ()))
        lib = "";
     }
   else if ((lib == NULL) || (*lib == 0))
     exit_error("JED_ROOT environment variable needs set.", 0);

   if ((NULL != (type = file_type(file)))
       && ((*type == 0) 
         || ((0 != strcmp (type, "sl")) && (0 != strcmp (type, "slc")))))
     type = NULL;

   n = 0;
   while (0 == SLextract_list_element (lib, n, ',', libfsl, sizeof(libfsl)))
     {
      n++;

      fixup_dir(libfsl);
      safe_strcat (libfsl, file, sizeof (libfsl));
      safe_strcpy (libfsl, expand_filename(libfsl), sizeof (libfsl));

      libf = libfsl;

      if ((1 == file_status (libf))
          && (NULL != (vp = vopen(libf, VFILE_BUF_SIZE, VFILE_TEXT))))
        break;

      if (type == NULL)
        {
#ifdef VMS
           int vmsn;
           /* remove trailing '.' */
           if (0 != (vmsn = strlen(libfsl)))
             {
              vmsn--;
              if (libfsl[vmsn] == '.') libfsl[vmsn] = 0;
             }
#endif
           
           /* Try .sl and .slc */
           safe_strcat (libfsl, ".sl", sizeof (libfsl));
           safe_strcpy (libfslc, libfsl, sizeof (libfslc));
           safe_strcat (libfslc, "c", sizeof (libfslc));

           if (file_time_cmp(libfslc, libfsl) >= 0)
             libf = libfslc;

           if ((1 == file_status (libf))
             && (NULL != (vp = vopen(libf, VFILE_BUF_SIZE, VFILE_TEXT))))
             break;
        }
     }
   
   if (NULL == (*dirfile = SLang_create_slstring (libf)))
     {
      vclose (vp);
      return NULL;
     }

   if (0 == Jed_Load_Quietly)
     jed_vmessage (1, "loading %s", libf);

   return (vp);
}

/*}}}*/

static char *jed_read_from_file(SLang_Load_Type *x) /*{{{*/
{
   char *s;
   unsigned int n;

   if ((s = vgets((VFILE *) x->client_data, &n)) != NULL)
     {
      if (s[n - 1] != '\n') s[n] = 0;
     }
   
   return s;
}

/*}}}*/

int jed_load_file (char *file)
{
   VFILE *vp;
   SLang_Load_Type *x;
   int ret;

   if (NULL == (vp = jed_open_lib_file (file, &file)))
     {
      SLang_verror (SL_OBJ_NOPEN, "Unable to load %s", file);
      return -1;
     }

   x = SLallocate_load_type (file);
   SLang_free_slstring (file);
   
   if (x == NULL)
     {
      vclose (vp);
      return -1;
     }

   x->client_data = (VOID_STAR) vp;
   x->read = jed_read_from_file;
   ret = SLang_load_object (x);
   SLdeallocate_load_type (x);
   vclose (vp);
   return ret;
}


typedef struct
{
   Line *l;
   char buf[256];
}
Buffer_Client_Type;

static char *jed_read_from_buffer (SLang_Load_Type *x) /*{{{*/
{
   Buffer_Client_Type *b;
   char *buf;
   Line *l;
   unsigned int len;

   b = (Buffer_Client_Type *)x->client_data;

   if (NULL == (l = b->l))
     return NULL;

   len = (unsigned int) l->len;
   if (len > 255)
     {
      SLang_doerror ("Line len too long");
      return NULL;
     }

   buf = b->buf;
   SLMEMCPY(buf, (char *) l->data, len);
   buf [len] = 0;
   b->l = l->next;

   return buf;
}
/*}}}*/

void load_buffer (void) /*{{{*/
{
   SLang_Load_Type *x;
   Buffer_Client_Type client_data;
   Buffer *cbuf = CBuf;
   int flags = CBuf->flags;
   Line *l, *lwant;
   char *file;

   if (cbuf->file[0] == 0)
     file = cbuf->name;
   else
     file = cbuf->file;
   
   file = jed_dir_file_merge (CBuf->dir, file);
   if (file == NULL)
     return;
      
   x = SLallocate_load_type (file);
   SLfree (file);
   
   if (x == NULL)
     return;

   x->read = jed_read_from_buffer;
   x->client_data = (VOID_STAR) &client_data;
   client_data.l = CBuf->beg;

   cbuf->flags |= READ_ONLY;
   SLang_load_object(x);
   SLdeallocate_load_type (x);
   
   if (buffer_exists (cbuf))
     cbuf->flags = flags;
   else cbuf = NULL;

   if ((SLang_Error == 0)
       && (*Error_Buffer == 0))
     return;
   
   SLang_doerror(NULL);
   if (cbuf == NULL)
     return;

   pop_to_buffer (cbuf->name);
   lwant = client_data.l;

   if (lwant == NULL)
     {
      eob();
      return;
     }
   
   bob();
   while (1)
     {
      l = CLine->next;
      if ((l == NULL) || (l == lwant)) break;
      CLine = l; LineNum++;
     }
   (void) skip_whitespace();
}

/*}}}*/

static SLang_Name_Type *Expand_File_Hook;
void set_expansion_hook (char *s) /*{{{*/
{
   if (NULL == (Expand_File_Hook = SLang_get_function (s)))
     {
      msg_error ("The expansion hook has not been defined.");
     }
}

/*}}}*/

int mini_complete (void) /*{{{*/
{
   char *pl, *pb;
   char last[JED_MAX_PATH_LEN], buf[JED_MAX_PATH_LEN], *tmp;
   static char prev[JED_MAX_PATH_LEN];
   int n, last_key_char = SLang_Last_Key_Char;
   static int flag = 0;  /* when flag goes 0, we call open */
   
   if (complete_open == NULL) return ins_char_cmd();
   
   Point = 0;
   push_mark();
   eob();
   if (NULL == (tmp = make_buffer_substring(&n))) return(1);
   
   safe_strcpy(buf, tmp, sizeof (buf));
   SLfree(tmp);
   
   if ((last_key_char == ' ') && ((long) Last_Key_Function == (long) mini_complete))
     {
      if (flag)
        flag = (*complete_next)(buf);
      if (flag == 0)
        {
           safe_strcpy(buf, prev, sizeof (buf));
           flag = (*complete_open)(buf);
        }
      safe_strcpy(last, buf, sizeof (last));
      n = -1;
     }
   else
     {
      n = 0;
      safe_strcpy (prev, buf, sizeof (prev));  /* save this search context */
     }
   
   if (!n)
     {
      if ((Repeat_Factor != NULL)
          || (complete_open != sys_findfirst) || (Expand_File_Hook == NULL))
        flag = (*complete_open)(buf);
      else
        {
           int do_free;
           SLang_push_string (buf);
           SLexecute_function (Expand_File_Hook);
           if (SLang_Error == 0) SLang_pop_integer (&do_free);
           if (SLang_Error == 0)
             {
              if (do_free == 0)
                {
                   flag = (*complete_open) (buf);
                   goto start_loop;
                }
             }
           
           if (SLang_Error || SLang_pop_slstring (&tmp))
             {
              msg_error ("Error encounter during expansion.  Disabling expansion hook.");
              Expand_File_Hook = NULL;
              return 1;
             }
           safe_strcpy (last, tmp, sizeof (last));
           safe_strcpy (prev, last, sizeof (prev));
           SLang_free_slstring (tmp);
           flag = 0;                 /* So we do not call complete_next */
           n = -1;
        }
     }
   
   start_loop:
   
   if (!n && flag)
     {
      safe_strcpy(last, buf, sizeof (last));
      
      /* This do loop tests all values from complete_next and returns the
         smallest length match of initial characters of buf */
      do
        {
           if ((n == 0) && (last_key_char == '\t'))
             {
              set_buffer (Completion_Buffer);
              erase_buffer ();
              CBuf->flags |= BURIED_BUFFER;
              (void) jed_insert_string ("!!! Use Page Up/Down keys to scroll this window. !!!\n");
             }
           
           n++;
           pl = last;
           pb = buf;

#if !JED_FILE_PRESERVE_CASE
           if ((complete_open == open_bufflist)
#if !JED_FILENAME_CASE_SENSITIVE
             || (complete_open == sys_findfirst)
#endif
             )
             while (*pl && (UPPER_CASE(*pl) == UPPER_CASE(*pb)))
             {
                pl++;
                pb++;
             }
           else  /* next statement */
#endif
             while (*pl && (*pl == *pb)) 
             {
              pl++;
              pb++;
             }
           

           *pl = 0;
           
           if (last_key_char == '\t')
             {
              while (*pb) pb++;
              (void) jed_quick_insert ((unsigned char *)buf, (int) (pb - buf));
              newline ();
             }
        }
      while(0 != (flag = (*complete_next)(buf)));
      
#if JED_FILE_PRESERVE_CASE
      /* OS/2 uses case-insensitive search on buffer-names. Set the 
       * flag if there is an exact match, so that completion will
       * cycle without repeats through all the matches. 
       */
      if (complete_open == open_bufflist) 
        {
           safe_strcpy(buf, last, sizeof (buf));
           (*complete_open)(buf);
           do 
             {
              if (!strcmp(buf, last)) 
                {
                   flag = 1; break;
                }
             }
           while ((*complete_next)(buf));
        }
#endif
     }
   
   if ((n > 1) && (last_key_char == '\t') && (Last_Completion_Buffer == NULL))
     {
      Last_Completion_Windows = num_windows () - 1;   /* not including mini */
      Last_Completion_Buffer = pop_to_buffer (Completion_Buffer);
      bob ();
     }
   
   while ((CBuf != MiniBuffer) || !IS_MINIBUFFER) other_window ();
   
   if (n)
     {
      erase_buffer();
      (void) jed_insert_string(last);
      if ((n == 1) && ((long) Last_Key_Function == (long) mini_complete))
        message("[Sole Completion.]");
     }
   else msg_error("No Match!");
   
   return(1);
}

/*}}}*/

int what_char() /*{{{*/
{
   if (eobp()) return(0);
   return( (int) *(CLine->data + Point) );
}

/*}}}*/


void copy_region_cmd(char *name) /*{{{*/
{
   Buffer *buf;
   
   if (NULL != (buf = find_buffer(name)))
     {
      copy_region_to_buffer(buf);
     }
   else msg_error("Unable to find buffer.");
}

/*}}}*/

#ifndef IBMPC_SYSTEM

void screen_w80 (void) /*{{{*/
{
   tt_narrow_width ();
   jed_resize_display ();
}

/*}}}*/
void screen_w132 (void) /*{{{*/
{
   tt_wide_width();
   jed_resize_display ();
}

/*}}}*/
#endif

char *make_line_string(char *string, unsigned int buflen) /*{{{*/
{
   unsigned char *tmp, *p1, *p2;
   unsigned int n;
   
   if (CBuf->marks == NULL)
     {
      p1 = CLine->data + Point;
      p2 = CLine->data + CLine->len;
     }
   else
     {
      p1 = CLine->data + CBuf->marks->point;
      p2 = CLine->data + Point;
      if (p2 < p1)
        {
           tmp = p1; p1 = p2; p2 = tmp;
        }
      pop_mark(&Number_Zero);
     }
   n = (unsigned int) (p2 - p1);
   if (n >= buflen) n = buflen - 1;
   SLMEMCPY(string, (char *) p1, n);
   string[n] = 0;
   return(string);
}

/*}}}*/

char *make_buffer_substring(int *np) /*{{{*/
{
   Line *tthis, *beg;
   int n = 1, dn, thisp;
   unsigned char *buf;
   
   if (!check_region(&n)) return (NULL);      /* spot pushed */
   /* Point now at end of the region */
   
   beg = tthis = CBuf->marks->line;
   thisp = CBuf->marks->point;
   n = 0;
   pop_mark(&n);
   
   while (tthis != CLine)
     {
      n += tthis->len;
      tthis = tthis->next;
     }
   n -= thisp;
   n += Point;
   
   if (NULL == (buf = (unsigned char *) SLmalloc (n + 1)))
     {
      pop_spot();
      return (NULL);
     }
   
   if (CLine == (tthis = beg))
     {
      SLMEMCPY((char *)buf, (char *) (tthis->data + thisp), n);
     }
   else
     {
      n = 0;
      while (tthis != CLine)
        {
           dn = tthis->len - thisp;
           SLMEMCPY((char *)(buf + n), (char *) (tthis->data + thisp), dn);
           tthis = tthis->next;
           thisp = 0;
           n += dn;
        }
      SLMEMCPY((char *)(buf + n), (char *) tthis->data, Point);
      n += Point;
     }
   buf[n] = 0;
   *np = n;
   pop_spot();
   return ((char *) buf);
}

/*}}}*/

void buffer_substring() /*{{{*/
{
   char *buf;
   int n;
   if (NULL == (buf = make_buffer_substring(&n))) return;
   SLang_push_malloced_string((char *)buf);
}

/*}}}*/

int markp(void) /*{{{*/
{
   return (CBuf->marks != NULL);
}

/*}}}*/

int dup_mark(void) /*{{{*/
{
   if (CBuf->marks == NULL) return(0);
   
   push_spot();
   jed_goto_mark(CBuf->marks);
   push_mark();
   pop_spot();
   return(1);
}

/*}}}*/

void mini_read(char *prompt, char *def, char *stuff) /*{{{*/
{
   char *buf;
   int n;
   
   complete_open = NULL;
   if (NULL == (buf = read_from_minibuffer(prompt, def, stuff, &n)))
     SLang_push_string ("");
   else SLang_push_malloced_string(buf);
}

/*}}}*/

void make_buffer_list(void) /*{{{*/
{
   int n = 0;
   Buffer *b;
   
   b = CBuf;
   
   do
     {
      SLang_push_string(b->name);
      b = b->next;
      n++;
     }
   while (b != CBuf);
   SLang_push_integer(n);
}

/*}}}*/

int window_size_intrinsic(int *what) /*{{{*/
{
   register int n = 0;
   switch (*what)
     {
      case 'x': n = JWindow->sx; break;
      case 'y': n = JWindow->sy; break;
      case 'r': n = JWindow->rows; break;
      case 'c': n = JWindow->hscroll_column; break;
      case 't': n = JWindow->sy + 1; break;
      case 'w': n = JWindow->width; break;
      default: SLang_Error = SL_UNKNOWN_ERROR;
     }
   return (n);
}

/*}}}*/

/* This has been moved to slang */
#if 0
/* Given a file name with wildcards return expanded list to S-Lang stack
 *  with number.  This does NOT work on unix with wild cards.  Instead the 
 *  expansion is file* (completion) */
int expand_wildcards (char *file) /*{{{*/
{
   char buf[JED_MAX_PATH_LEN];
   int n = 0;
   
   safe_strcpy(buf, file, sizeof (buf));
   
   if (sys_findfirst(buf))
     {
      do
        {
           n++;
           SLang_push_string(buf);
        }
      while (sys_findnext(buf));
     }
   return (n);
}

/*}}}*/
#endif
static void jed_traceback(char *s) /*{{{*/
{
   char *n;
   if (!Batch)
     {
      n = CBuf->name;
      set_buffer("*traceback*");
      eob();
      (void) jed_insert_string(s);
      set_buffer(n);
     }
   else fprintf(stderr, s);
}

/*}}}*/

#if 0
static struct /*{{{*/
{
   int depth = 0;
   char *name[20];
   int marks[20];
}

/*}}}*/
FName_Stack;

void enter_function(char *name) /*{{{*/
{
   if (depth > 20)
     {
      msg_error("Function Stack too deep.");
      return;
     }
   FName_Stack->name[depth] = name;
   FName_Stack->marks[depth] = 0;
}

/*}}}*/
void exit_function(char *name) /*{{{*/
{
   int n = FName_Stack->marks[depth];
   
}

/*}}}*/
#endif



void count_chars(void) /*{{{*/
{
   unsigned long n = 0, m = 0;
   int ch;
   char buf[64];
   Line *l = CBuf->beg;
   
   while (l != NULL)
     {
      n += l->len;
      l = l->next;
     }
   l = CBuf->beg;
   while (l != CLine)
     {
      m += l->len;
      l = l->next;
     }
   m += Point + 1;
   ch = eobp() ? 0 : (int) *(CLine->data + Point);
   sprintf(buf, "'@'=%d/0x%x/%#o, point %lu of %lu", ch, ch, ch, m, n);
   if (ch != 0) buf[1] = ch;
   else buf[0] = '^';
   SLang_push_string(buf);
}

/*}}}*/

static void jed_clear_error(void) /*{{{*/
{
   *Error_Buffer = 0;
   SLKeyBoard_Quit = 0;
}

/*}}}*/

typedef struct _Init_SLang_Hook_Type
{
   int (*hook)(void);
   struct _Init_SLang_Hook_Type *next;
}
Init_SLang_Hook_Type;

static Init_SLang_Hook_Type *Init_SLang_Hooks;

int jed_add_init_slang_hook (int (*hook)(void))
{
   Init_SLang_Hook_Type *h;

   if (hook == NULL)
     return 0;
   
   h = (Init_SLang_Hook_Type *)SLmalloc (sizeof (Init_SLang_Hook_Type));
   if (h == NULL)
     return -1;
   
   h->hook = hook;
   h->next = Init_SLang_Hooks;
   Init_SLang_Hooks = h;
   return 0;
}

static int run_init_slang_hooks (void)
{
   Init_SLang_Hook_Type *h;
   
   h = Init_SLang_Hooks;

   while (h != NULL)
     {
      if (-1 == (*h->hook)())
        return -1;
      h = h->next;
     }

   while (Init_SLang_Hooks != NULL)
     {
      h = Init_SLang_Hooks->next;
      SLfree ((char *) Init_SLang_Hooks);
      Init_SLang_Hooks = h;
     }
   
   return 0;
}

static void slang_exit_error_handler (char *fmt, va_list ap)
{
   char buf [2048];
   
   _SLvsnprintf (buf, sizeof (buf), fmt, ap);
   exit_error (buf, 0);
}

static void vmsg_hook (char *fmt, va_list ap)
{
   char buf [2048];
   _SLvsnprintf (buf, sizeof (buf), fmt, ap);
   message (buf);
}

void jed_setup_minibuffer_keymap (void)
{
   SLKeyMap_List_Type *m;

   if (NULL == (m = SLang_find_keymap ("Mini_Map")))
     {
      if (NULL == (m = SLang_create_keymap("Mini_Map", Global_Map))) 
        exit_error("Unable to create minibuffer keymap", 0);

      SLang_undefine_key("\r", m);
      SLkm_define_key ("\r", (FVOID_STAR) exit_minibuffer, m);
      SLkm_define_key ("\t", (FVOID_STAR) mini_complete, m);
      SLkm_define_key (" ", (FVOID_STAR) mini_complete, m);
     }
   The_MiniBuffer->keymap = m;
}


#if SLANG_VERSION < 10405
/* Work around a slang bug triggered by jed. Apps which use slang's 
 * load_file function do not have this problem.
 */
extern int (*_SLprep_eval_hook) (char *);
static int bug_fixed_prep_eval_expr (char *expr)
{
   int ret;
   char *end;

   end = strchr (expr, '\n');
   if (end == NULL)
     end = expr + strlen (expr);
   expr = SLmake_nstring (expr, (unsigned int) (end - expr));
   if (expr == NULL)
     return -1;
      
   if ((0 != SLang_load_string (expr))
       || (-1 == SLang_pop_integer (&ret)))
     ret = -1;
   else
     ret = (ret != 0);

   SLfree (expr);
   return ret;
}
#endif

void init_minibuffer() /*{{{*/
{
   Buffer *tmp;
   
   tmp = CBuf;
   
   The_MiniBuffer = make_buffer (" <mini>", NULL, NULL);
   The_MiniBuffer->modes = 0;
   /* do some initializing */
   switch_to_buffer(The_MiniBuffer);
   remake_line(132);
   The_MiniWindow = create_window(Jed_Num_Screen_Rows-1, 0, 1, 1, Jed_Num_Screen_Cols);
   The_MiniWindow->buffer = CBuf;
   Buffer_Local.tab = 0;
   switch_to_buffer(tmp);
   SLang_Dump_Routine = jed_traceback;
   SLang_Exit_Error_Hook = slang_exit_error_handler;

#ifdef __GO32__
   SLang_Interrupt = i386_check_kbd;
#endif
   
#if 0
   SLang_Enter_Function = enter_function;
   SLang_Exit_Function = exit_function;
#endif
#if SLANG_VERSION < 10405
   _SLprep_eval_hook = bug_fixed_prep_eval_expr;
#endif

   if ((-1 == SLang_init_slang ())
#ifndef SIXTEEN_BIT_SYSTEM
       || (-1 == SLang_init_slmath ())
#endif
       || (-1 == SLang_init_posix_process ())
       || (-1 == SLang_init_posix_dir ())
       || (-1 == SLang_init_slassoc ())
       || (-1 == SLang_init_stdio ())
       || (-1 == SLang_init_posix_io ())
       || (-1 == SLang_init_ospath ())
       /* || (-1 == SLang_init_import ()) */
       || (-1 == init_jed_intrinsics ())
       || (-1 == jed_init_userinfo ())
#if JED_HAS_TTY_MENUS
       || (-1 == jed_init_menus ())
#endif
       || (-1 == jed_init_syntax ())
       || (-1 == register_jed_classes ())
       || (-1 == jed_init_user_hooks ())
       || (-1 == run_init_slang_hooks ()))
     {
      exit_error("Unable to initialize S-Lang!", 0);
     }
   
   /* use jed rouotines instead of default slang ones */
   SLang_Error_Hook = msg_error;
   SLang_VMessage_Hook = vmsg_hook;
   SLang_User_Clear_Error = jed_clear_error;
   SLang_Load_File_Hook = jed_load_file;
}

/*}}}*/

Generated by  Doxygen 1.6.0   Back to index