Logo Search packages:      
Sourcecode: ksh version File versions  Download package

emacs.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1982-2008 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                  David Korn <dgk@research.att.com>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/* Original version by Michael T. Veach 
 * Adapted for ksh by David Korn */
/* EMACS_MODES: c tabstop=4 

One line screen editor for any program

*/


/*    The following is provided by:
 *
 *                Matthijs N. Melchior
 *                AT&T Network Systems International
 *                APT Nederland
 *                HV BZ335 x2962
 *                hvlpb!mmelchio
 *
 *  These are now on by default
 *
 *  ESH_NFIRST
 *    -  A ^N as first history related command after the prompt will move
 *       to the next command relative to the last known history position.
 *       It will not start at the position where the last command was entered
 *       as is done by the ^P command.  Every history related command will
 *       set both the current and last position.  Executing a command will
 *       only set the current position.
 *
 *  ESH_KAPPEND
 *    -  Successive kill and delete commands will accumulate their data
 *       in the kill buffer, by appending or prepending as appropriate.
 *       This mode will be reset by any command not adding something to the
 *       kill buffer.
 *
 *  ESH_BETTER
 *    -  Some enhancements:
 *          - argument for a macro is passed to its replacement
 *          - ^X^H command to find out about history position (debugging)
 *          - ^X^D command to show any debugging info
 *
 *  I do not pretend these for changes are completely independent,
 *  but you can use them to seperate features.
 */

#include    <ast.h>
#include    <ctype.h>
#include    "FEATURE/cmds"
#if KSHELL
#   include "defs.h"
#endif      /* KSHELL */
#include    "io.h"

#include    "history.h"
#include    "edit.h"
#include    "terminal.h"

#define ESH_NFIRST
#define ESH_KAPPEND
#define ESH_BETTER

#undef putchar
#define putchar(ed,c)   ed_putchar(ed,c)
#define beep()          ed_ringbell()


#if SHOPT_MULTIBYTE
#   define gencpy(a,b)  ed_gencpy(a,b)
#   define genncpy(a,b,n)     ed_genncpy(a,b,n)
#   define genlen(str)  ed_genlen(str)
    static int    print(int);
    static int    _isword(int);
#   define  isword(c)   _isword(out[c])

#else
#   define gencpy(a,b)  strcpy((char*)(a),(char*)(b))
#   define genncpy(a,b,n)     strncpy((char*)(a),(char*)(b),n)
#   define genlen(str)  strlen(str)
#   define print(c)     isprint(c)
#   define isword(c)    (isalnum(out[c]) || (out[c]=='_'))
#endif /*SHOPT_MULTIBYTE */

typedef struct _emacs_
{
      genchar *screen;  /* pointer to window buffer */
      genchar *cursor;  /* Cursor in real screen */
      int   mark;
      int   in_mult;
      char  cr_ok;
      char  CntrlO;
      char  overflow;         /* Screen overflow flag set */
      char  scvalid;          /* Screen is up to date */
      int   offset;           /* Screen offset */
      enum
      {
            CRT=0,      /* Crt terminal */
            PAPER /* Paper terminal */
      } terminal;
      Histloc_t _location;
      int   prevdirection; 
      Edit_t      *ed;  /* pointer to edit data */
} Emacs_t;

#define     editb       (*ep->ed)
#define eol       editb.e_eol
#define cur       editb.e_cur
#define hline           editb.e_hline
#define hloff           editb.e_hloff
#define hismin          editb.e_hismin
#define usrkill         editb.e_kill
#define usrlnext  editb.e_lnext
#define usreof          editb.e_eof
#define usrerase  editb.e_erase
#define crallowed editb.e_crlf
#define Prompt          editb.e_prompt
#define plen            editb.e_plen
#define kstack          editb.e_killbuf
#define lstring         editb.e_search
#define lookahead editb.e_lookahead
#define env       editb.e_env
#define raw       editb.e_raw
#define histlines editb.e_hismax
#define w_size          editb.e_wsize
#define drawbuff  editb.e_inbuf
#define killing         editb.e_mode
#define location  ep->_location

#define LBUF      100
#define KILLCHAR  UKILL
#define ERASECHAR UERASE
#define EOFCHAR         UEOF
#define LNEXTCHAR       ULNEXT
#define DELETE          ('a'==97?0177:7)

/**********************
A large lookahead helps when the user is inserting
characters in the middle of the line.
************************/


typedef enum
{
      FIRST,            /* First time thru for logical line, prompt on screen */
      REFRESH,    /* Redraw entire screen */
      APPEND,           /* Append char before cursor to screen */
      UPDATE,           /* Update the screen as need be */
      FINAL       /* Update screen even if pending look ahead */
} Draw_t;

static void draw(Emacs_t*,Draw_t);
static int escape(Emacs_t*,genchar*, int);
static void putstring(Emacs_t*,char*);
static void search(Emacs_t*,genchar*,int);
static void setcursor(Emacs_t*,int, int);
static void show_info(Emacs_t*,const char*);
static void xcommands(Emacs_t*,int);

int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
{
      Edit_t *ed = (Edit_t*)context;
      register int c;
      register int i;
      register genchar *out;
      register int count;
      register Emacs_t *ep = ed->e_emacs;
      int adjust,oadjust;
      char backslash;
      genchar *kptr;
      char prompt[PRSIZE];
      genchar Screen[MAXLINE];
      if(!ep)
      {
            ep = ed->e_emacs = newof(0,Emacs_t,1,0);
            ep->ed = ed;
            ep->prevdirection =  1;
            location.hist_command =  -5;
      }
      Prompt = prompt;
      ep->screen = Screen;
      if(tty_raw(ERRIO,0) < 0)
      {
             return(reedit?reedit:ed_read(context, fd,buff,scend,0));
      }
      raw = 1;
      /* This mess in case the read system call fails */
      
      ed_setup(ep->ed,fd,reedit);
      out = (genchar*)buff;
#if SHOPT_MULTIBYTE
      out = (genchar*)roundof((char*)out-(char*)0,sizeof(genchar));
      ed_internal(buff,out);
#endif /* SHOPT_MULTIBYTE */
      if(!kstack)
      {
            kstack = (genchar*)malloc(CHARSIZE*MAXLINE);
            kstack[0] = '\0';
      }
      drawbuff = out;
#ifdef ESH_NFIRST
      if (location.hist_command == -5)          /* to be initialized */
      {
            kstack[0] = '\0';       /* also clear kstack... */
            location.hist_command = hline;
            location.hist_line = hloff;
      }
      if (location.hist_command <= hismin)      /* don't start below minimum */
      {
            location.hist_command = hismin + 1;
            location.hist_line = 0;
      }
      ep->in_mult = hloff;                /* save pos in last command */
#endif /* ESH_NFIRST */
      i = sigsetjmp(env,0);
      if (i !=0)
      {
            tty_cooked(ERRIO);
            if (i == UEOF)
            {
                  return(0); /* EOF */
            }
            return(-1); /* some other error */
      }
      out[reedit] = 0;
      if(scend+plen > (MAXLINE-2))
            scend = (MAXLINE-2)-plen;
      ep->mark = 0;
      cur = eol;
      draw(ep,reedit?REFRESH:FIRST);
      adjust = -1;
      backslash = 0;
      if (ep->CntrlO)
      {
#ifdef ESH_NFIRST
            ed_ungetchar(ep->ed,cntl('N'));
#else
            location = hist_locate(sh.hist_ptr,location.hist_command,location.hist_line,1);
            if (location.hist_command < histlines)
            {
                  hline = location.hist_command;
                  hloff = location.hist_line;
                  hist_copy((char*)kstack,MAXLINE, hline,hloff);
#   if SHOPT_MULTIBYTE
                  ed_internal((char*)kstack,kstack);
#   endif /* SHOPT_MULTIBYTE */
                  ed_ungetchar(ep->ed,cntl('Y'));
            }
#endif /* ESH_NFIRST */
      }
      ep->CntrlO = 0;
      while ((c = ed_getchar(ep->ed,0)) != (-1))
      {
            if (backslash)
            {
                  backslash = 0;
                  if (c==usrerase||c==usrkill||(!print(c) &&
                        (c!='\r'&&c!='\n')))
                  {
                        /* accept a backslashed character */
                        cur--;
                        out[cur++] = c;
                        out[eol] = '\0';
                        draw(ep,APPEND);
                        continue;
                  }
            }
            if (c == usrkill)
            {
                  c = KILLCHAR ;
            }
            else if (c == usrerase)
            {
                  c = ERASECHAR ;
            } 
            else if (c == usrlnext)
            {
                  c = LNEXTCHAR ;
            }
            else if ((c == usreof)&&(eol == 0))
            {
                  c = EOFCHAR;
            }
#ifdef ESH_KAPPEND
            if (--killing <= 0)     /* reset killing flag */
                  killing = 0;
#endif
            oadjust = count = adjust;
            if(count<0)
                  count = 1;
            adjust = -1;
            i = cur;
            switch(c)
            {
            case LNEXTCHAR:
                  c = ed_getchar(ep->ed,2);
                  goto do_default_processing;
            case cntl('V'):
                  show_info(ep,fmtident(e_version));
                  continue;
            case '\0':
                  ep->mark = i;
                  continue;
            case cntl('X'):
                  xcommands(ep,count);
                  continue;
            case EOFCHAR:
                  ed_flush(ep->ed);
                  tty_cooked(ERRIO);
                  return(0);
#ifdef u370
            case cntl('S') :
            case cntl('Q') :
                  continue;
#endif      /* u370 */
            case '\t':
                  if(cur>0  && ep->ed->sh->nextprompt)
                  {
                        if(ep->ed->e_tabcount==0)
                        {
                              ep->ed->e_tabcount=1;
                              ed_ungetchar(ep->ed,ESC);
                              goto do_escape;
                        }
                        else if(ep->ed->e_tabcount==1)
                        {
                              ed_ungetchar(ep->ed,'=');
                              goto do_escape;
                        }
                        ep->ed->e_tabcount = 0;
                  }
            do_default_processing:
            default:

                  if ((eol+1) >= (scend)) /*  will not fit on line */
                  {
                        ed_ungetchar(ep->ed,c); /* save character for next line */
                        goto process;
                  }
                  for(i= ++eol; i>cur; i--)
                        out[i] = out[i-1];
                  backslash =  (c == '\\');
                  out[cur++] = c;
                  draw(ep,APPEND);
                  continue;
            case cntl('Y') :
                  {
                        c = genlen(kstack);
                        if ((c + eol) > scend)
                        {
                              beep();
                              continue;
                        }
                        ep->mark = i;
                        for(i=eol;i>=cur;i--)
                              out[c+i] = out[i];
                        kptr=kstack;
                        while (i = *kptr++)
                              out[cur++] = i;
                        draw(ep,UPDATE);
                        eol = genlen(out);
                        continue;
                  }
            case '\n':
            case '\r':
                  c = '\n';
                  goto process;

            case DELETE:      /* delete char 0x7f */
            case '\b':  /* backspace, ^h */
            case ERASECHAR :
                  if (count > i)
                        count = i;
#ifdef ESH_KAPPEND
                  kptr = &kstack[count];  /* move old contents here */
                  if (killing)            /* prepend to killbuf */
                  {
                        c = genlen(kstack) + CHARSIZE; /* include '\0' */
                        while(c--)  /* copy stuff */
                              kptr[c] = kstack[c];
                  }
                  else
                        *kptr = 0;  /* this is end of data */
                  killing = 2;            /* we are killing */
                  i -= count;
                  eol -= count;
                  genncpy(kstack,out+i,cur-i);
#else
                  while ((count--)&&(i>0))
                  {
                        i--;
                        eol--;
                  }
                  genncpy(kstack,out+i,cur-i);
                  kstack[cur-i] = 0;
#endif /* ESH_KAPPEND */
                  gencpy(out+i,out+cur);
                  ep->mark = i;
                  goto update;
            case cntl('W') :
#ifdef ESH_KAPPEND
                  ++killing;        /* keep killing flag */
#endif
                  if (ep->mark > eol )
                        ep->mark = eol;
                  if (ep->mark == i)
                        continue;
                  if (ep->mark > i)
                  {
                        adjust = ep->mark - i;
                        ed_ungetchar(ep->ed,cntl('D'));
                        continue;
                  }
                  adjust = i - ep->mark;
                  ed_ungetchar(ep->ed,usrerase);
                  continue;
            case cntl('D') :
                  ep->mark = i;
#ifdef ESH_KAPPEND
                  if (killing)
                        kptr = &kstack[genlen(kstack)];     /* append here */
                  else
                        kptr = kstack;
                  killing = 2;                  /* we are now killing */
#else
                  kptr = kstack;
#endif /* ESH_KAPPEND */
                  while ((count--)&&(eol>0)&&(i<eol))
                  {
                        *kptr++ = out[i];
                        eol--;
                        while(1)
                        {
                              if ((out[i] = out[(i+1)])==0)
                                    break;
                              i++;
                        }
                        i = cur;
                  }
                  *kptr = '\0';
                  goto update;
            case cntl('C') :
            case cntl('F') :
            {
                  int cntlC = (c==cntl('C'));
                  while (count-- && eol>i)
                  {
                        if (cntlC)
                        {
                              c = out[i];
#if SHOPT_MULTIBYTE
                              if((c&~STRIP)==0 && islower(c))
#else
                              if(islower(c))
#endif /* SHOPT_MULTIBYTE */
                              {
                                    c += 'A' - 'a';
                                    out[i] = c;
                              }
                        }
                        i++;
                  }
                  goto update;
            }
            case cntl(']') :
                  c = ed_getchar(ep->ed,1);
                  if ((count == 0) || (count > eol))
                        {
                                beep();
                                continue;
                        }
                  if (out[i])
                        i++;
                  while (i < eol)
                  {
                        if (out[i] == c && --count==0)
                              goto update;
                        i++;
                  }
                  i = 0;
                  while (i < cur)
                  {
                        if (out[i] == c && --count==0)
                              break;
                        i++;
                  };

update:
                  cur = i;
                  draw(ep,UPDATE);
                  continue;

            case cntl('B') :
                  if (count > i)
                        count = i;
                  i -= count;
                  goto update;
            case cntl('T') :
                  if ((sh_isoption(SH_EMACS))&& (eol!=i))
                        i++;
                  if (i >= 2)
                  {
                        c = out[i - 1];
                        out[i-1] = out[i-2];
                        out[i-2] = c;
                  }
                  else
                  {
                        if(sh_isoption(SH_EMACS))
                              i--;
                        beep();
                        continue;
                  }
                  goto update;
            case cntl('A') :
                  i = 0;
                  goto update;
            case cntl('E') :
                  i = eol;
                  goto update;
            case cntl('U') :
                  adjust = 4*count;
                  continue;
            case KILLCHAR :
                  cur = 0;
                  oadjust = -1;
            case cntl('K') :
                  if(oadjust >= 0)
                  {
#ifdef ESH_KAPPEND
                        killing = 2;            /* set killing signal */
#endif
                        ep->mark = count;
                        ed_ungetchar(ep->ed,cntl('W'));
                        continue;
                  }
                  i = cur;
                  eol = i;
                  ep->mark = i;
#ifdef ESH_KAPPEND
                  if (killing)                  /* append to kill buffer */
                        gencpy(&kstack[genlen(kstack)], &out[i]);
                  else
                        gencpy(kstack,&out[i]);
                  killing = 2;                  /* set killing signal */
#else
                  gencpy(kstack,&out[i]);
#endif /* ESH_KAPPEND */
                  out[i] = 0;
                  draw(ep,UPDATE);
                  if (c == KILLCHAR)
                  {
                        if (ep->terminal == PAPER)
                        {
                              putchar(ep->ed,'\n');
                              putstring(ep,Prompt);
                        }
                        c = ed_getchar(ep->ed,0);
                        if (c != usrkill)
                        {
                              ed_ungetchar(ep->ed,c);
                              continue;
                        }
                        if (ep->terminal == PAPER)
                              ep->terminal = CRT;
                        else
                        {
                              ep->terminal = PAPER;
                              putchar(ep->ed,'\n');
                              putstring(ep,Prompt);
                        }
                  }
                  continue;
            case cntl('L'):
                  ed_crlf(ep->ed);
                  draw(ep,REFRESH);
                  continue;
            case cntl('[') :
            do_escape:
                  adjust = escape(ep,out,oadjust);
                  continue;
            case cntl('R') :
                  search(ep,out,count);
                  goto drawline;
            case cntl('P') :
                        if (count <= hloff)
                                hloff -= count;
                        else
                        {
                                hline -= count - hloff;
                                hloff = 0;
                        }
#ifdef ESH_NFIRST
                  if (hline <= hismin)
#else
                  if (hline < hismin)
#endif /* ESH_NFIRST */
                  {
                        hline = hismin+1;
                        beep();
#ifndef ESH_NFIRST
                        continue;
#endif
                  }
                  goto common;

            case cntl('O') :
                  location.hist_command = hline;
                  location.hist_line = hloff;
                  ep->CntrlO = 1;
                  c = '\n';
                  goto process;
            case cntl('N') :
#ifdef ESH_NFIRST
                  hline = location.hist_command;      /* start at saved position */
                  hloff = location.hist_line;
#endif /* ESH_NFIRST */
                  location = hist_locate(sh.hist_ptr,hline,hloff,count);
                  if (location.hist_command > histlines)
                  {
                        beep();
#ifdef ESH_NFIRST
                        location.hist_command = histlines;
                        location.hist_line = ep->in_mult;
#else
                        continue;
#endif /* ESH_NFIRST */
                  }
                  hline = location.hist_command;
                  hloff = location.hist_line;
            common:
#ifdef ESH_NFIRST
                  location.hist_command = hline;      /* save current position */
                  location.hist_line = hloff;
#endif
                  hist_copy((char*)out,MAXLINE, hline,hloff);
#if SHOPT_MULTIBYTE
                  ed_internal((char*)(out),out);
#endif /* SHOPT_MULTIBYTE */
            drawline:
                  eol = genlen(out);
                  cur = eol;
                  draw(ep,UPDATE);
                  continue;
            }
            
      }
      
process:

      if (c == (-1))
      {
            lookahead = 0;
            beep();
            *out = '\0';
      }
      draw(ep,FINAL);
      tty_cooked(ERRIO);
      if(ed->e_nlist)
      {
            ed->e_nlist = 0;
            stakset(ed->e_stkptr,ed->e_stkoff);
      }
      if(c == '\n')
      {
            out[eol++] = '\n';
            out[eol] = '\0';
            ed_crlf(ep->ed);
      }
#if SHOPT_MULTIBYTE
      ed_external(out,buff);
#endif /* SHOPT_MULTIBYTE */
      i = strlen(buff);
      if (i)
            return(i);
      return(-1);
}

static void show_info(Emacs_t *ep,const char *str)
{
      register genchar *out = drawbuff;
      register int c;
      genchar string[LBUF];
      int sav_cur = cur;
      /* save current line */
      genncpy(string,out,sizeof(string)/sizeof(*string));
      *out = 0;
      cur = 0;
#if SHOPT_MULTIBYTE
      ed_internal(str,out);
#else
      gencpy(out,str);
#endif      /* SHOPT_MULTIBYTE */
      draw(ep,UPDATE);
      c = ed_getchar(ep->ed,0);
      if(c!=' ')
            ed_ungetchar(ep->ed,c);
      /* restore line */
      cur = sav_cur;
      genncpy(out,string,sizeof(string)/sizeof(*string));
      draw(ep,UPDATE);
}

static void putstring(Emacs_t* ep,register char *sp)
{
      register int c;
      while (c= *sp++)
             putchar(ep->ed,c);
}


static int escape(register Emacs_t* ep,register genchar *out,int count)
{
      register int i,value;
      int digit,ch;
      digit = 0;
      value = 0;
      while ((i=ed_getchar(ep->ed,0)),isdigit(i))
      {
            value *= 10;
            value += (i - '0');
            digit = 1;
      }
      if (digit)
      {
            ed_ungetchar(ep->ed,i) ;
#ifdef ESH_KAPPEND
            ++killing;        /* don't modify killing signal */
#endif
            return(value);
      }
      value = count;
      if(value<0)
            value = 1;
      switch(ch=i)
      {
            case cntl('V'):
                  show_info(ep,fmtident(e_version));
                  return(-1);
            case ' ':
                  ep->mark = cur;
                  return(-1);

#ifdef ESH_KAPPEND
            case '+':         /* M-+ = append next kill */
                  killing = 2;
                  return -1;  /* no argument for next command */
#endif

            case 'p':   /* M-p == ^W^Y (copy stack == kill & yank) */
                  ed_ungetchar(ep->ed,cntl('Y'));
                  ed_ungetchar(ep->ed,cntl('W'));
#ifdef ESH_KAPPEND
                  killing = 0;      /* start fresh */
#endif
                  return(-1);

            case 'l':   /* M-l == lower-case */
            case 'd':
            case 'c':
            case 'f':
            {
                  i = cur;
                  while(value-- && i<eol)
                  {
                        while ((out[i])&&(!isword(i)))
                              i++;
                        while ((out[i])&&(isword(i)))
                              i++;
                  }
                  if(ch=='l')
                  {
                        value = i-cur;
                        while (value-- > 0)
                        {
                              i = out[cur];
#if SHOPT_MULTIBYTE
                              if((i&~STRIP)==0 && isupper(i))
#else
                              if(isupper(i))
#endif /* SHOPT_MULTIBYTE */
                              {
                                    i += 'a' - 'A';
                                    out[cur] = i;
                              }
                              cur++;
                        }
                        draw(ep,UPDATE);
                        return(-1);
                  }

                  else if(ch=='f')
                        goto update;
                  else if(ch=='c')
                  {
                        ed_ungetchar(ep->ed,cntl('C'));
                        return(i-cur);
                  }
                  else
                  {
                        if (i-cur)
                        {
                              ed_ungetchar(ep->ed,cntl('D'));
#ifdef ESH_KAPPEND
                              ++killing;  /* keep killing signal */
#endif
                              return(i-cur);
                        }
                        beep();
                        return(-1);
                  }
            }
            
            
            case 'b':
            case DELETE :
            case '\b':
            case 'h':
            {
                  i = cur;
                  while(value-- && i>0)
                  {
                        i--;
                        while ((i>0)&&(!isword(i)))
                              i--;
                        while ((i>0)&&(isword(i-1)))
                              i--;
                  }
                  if(ch=='b')
                        goto update;
                  else
                  {
                        ed_ungetchar(ep->ed,usrerase);
#ifdef ESH_KAPPEND
                        ++killing;
#endif
                        return(cur-i);
                  }
            }
            
            case '>':
                  ed_ungetchar(ep->ed,cntl('N'));
#ifdef ESH_NFIRST
                  if (ep->in_mult)
                  {
                        location.hist_command = histlines;
                        location.hist_line = ep->in_mult - 1;
                  }
                  else
                  {
                        location.hist_command = histlines - 1;
                        location.hist_line = 0;
                  }
#else
                  hline = histlines-1;
                  hloff = 0;
#endif /* ESH_NFIRST */
                  return(0);
            
            case '<':
                  ed_ungetchar(ep->ed,cntl('P'));
                  hloff = 0;
#ifdef ESH_NFIRST
                  hline = hismin + 1;
                  return 0;
#else
                  return(hline-hismin);
#endif /* ESH_NFIRST */


            case '#':
                  ed_ungetchar(ep->ed,'\n');
                  ed_ungetchar(ep->ed,(out[0]=='#')?cntl('D'):'#');
                  ed_ungetchar(ep->ed,cntl('A'));
                  return(-1);
            case '_' :
            case '.' :
            {
                  genchar name[MAXLINE];
                  char buf[MAXLINE];
                  char *ptr;
                  ptr = hist_word(buf,MAXLINE,(count?count:-1));
#if !KSHELL
                  if(ptr==0)
                  {
                        beep();
                        break;
                  }
#endif      /* KSHELL */
                  if ((eol - cur) >= sizeof(name))
                  {
                        beep();
                        return(-1);
                  }
                  ep->mark = cur;
                  gencpy(name,&out[cur]);
                  while(*ptr)
                  {
                        out[cur++] = *ptr++;
                        eol++;
                  }
                  gencpy(&out[cur],name);
                  draw(ep,UPDATE);
                  return(-1);
            }
#if KSHELL

            /* file name expansion */
            case cntl('[') :  /* filename completion */
                  i = '\\';
            case '*':         /* filename expansion */
            case '=':   /* escape = - list all matching file names */
                  ep->mark = cur;
                  if(ed_expand(ep->ed,(char*)out,&cur,&eol,i,count) < 0)
                  {
                        if(ep->ed->e_tabcount==1)
                        {
                              ep->ed->e_tabcount=2;
                              ed_ungetchar(ep->ed,cntl('\t'));
                              return(-1);
                        }
                        beep();
                  }
                  else if(i=='=')
                  {
                        draw(ep,REFRESH);
                        if(count>0)
                              ep->ed->e_tabcount=0;
                        else
                        {
                              i=ed_getchar(ep->ed,0);
                              ed_ungetchar(ep->ed,i);
                              if(isdigit(i))
                                    ed_ungetchar(ep->ed,ESC);
                        }
                  }
                  else
                  {
                        if(i=='\\' && cur>ep->mark && (out[cur-1]=='/' || out[cur-1]==' '))
                              ep->ed->e_tabcount=0;
                        draw(ep,UPDATE);
                  }
                  return(-1);

            /* search back for character */
            case cntl(']'):   /* feature not in book */
            {
                  int c = ed_getchar(ep->ed,1);
                  if ((value == 0) || (value > eol))
                  {
                        beep();
                        return(-1);
                  }
                  i = cur;
                  if (i > 0)
                        i--;
                  while (i >= 0)
                  {
                        if (out[i] == c && --value==0)
                              goto update;
                        i--;
                  }
                  i = eol;
                  while (i > cur)
                  {
                        if (out[i] == c && --value==0)
                              break;
                        i--;
                  };

            }
            update:
                  cur = i;
                  draw(ep,UPDATE);
                  return(-1);

#ifdef _cmd_tput
            case cntl('L'): /* clear screen */
                  sh_trap("tput clear", 0);
                  draw(ep,REFRESH);
                  return(-1);
#endif
            case '[':   /* feature not in book */
                  switch(i=ed_getchar(ep->ed,1))
                  {
                      case 'A':
                        ed_ungetchar(ep->ed,cntl('P'));
                        return(-1);
                      case 'B':
                        ed_ungetchar(ep->ed,cntl('N'));
                        return(-1);
                      case 'C':
                        ed_ungetchar(ep->ed,cntl('F'));
                        return(-1);
                      case 'D':
                        ed_ungetchar(ep->ed,cntl('B'));
                        return(-1);
                      case 'H':
                        ed_ungetchar(ep->ed,cntl('A'));
                        return(-1);
                      case 'Y':
                        ed_ungetchar(ep->ed,cntl('E'));
                        return(-1);
                      default:
                        ed_ungetchar(ep->ed,i);
                  }
                  i = '_';

            default:
                  /* look for user defined macro definitions */
                  if(ed_macro(ep->ed,i))
#   ifdef ESH_BETTER
                        return(count);    /* pass argument to macro */
#   else
                        return(-1);
#   endif /* ESH_BETTER */
#else
            update:
                  cur = i;
                  draw(ep,UPDATE);
                  return(-1);

            default:
#endif      /* KSHELL */
            beep();
            return(-1);
      }
}


/*
 * This routine process all commands starting with ^X
 */

static void xcommands(register Emacs_t *ep,int count)
{
        register int i = ed_getchar(ep->ed,0);
      NOT_USED(count);
        switch(i)
        {
                case cntl('X'):     /* exchange dot and mark */
                        if (ep->mark > eol)
                                ep->mark = eol;
                        i = ep->mark;
                        ep->mark = cur;
                        cur = i;
                        draw(ep,UPDATE);
                        return;

#if KSHELL
#   ifdef ESH_BETTER
                case cntl('E'):     /* invoke emacs on current command */
                  if(ed_fulledit(ep->ed)==-1)
                        beep();
                  else
                  {
#if SHOPT_MULTIBYTE
                        ed_internal((char*)drawbuff,drawbuff);
#endif /* SHOPT_MULTIBYTE */
                        ed_ungetchar(ep->ed,'\n');
                  }
                  return;

#     define itos(i)    fmtbase((long)(i),0,0)/* want signed conversion */

            case cntl('H'):         /* ^X^H show history info */
                  {
                        char hbuf[MAXLINE];

                        strcpy(hbuf, "Current command ");
                        strcat(hbuf, itos(hline));
                        if (hloff)
                        {
                              strcat(hbuf, " (line ");
                              strcat(hbuf, itos(hloff+1));
                              strcat(hbuf, ")");
                        }
                        if ((hline != location.hist_command) ||
                            (hloff != location.hist_line))
                        {
                              strcat(hbuf, "; Previous command ");
                              strcat(hbuf, itos(location.hist_command));
                              if (location.hist_line)
                              {
                                    strcat(hbuf, " (line ");
                                    strcat(hbuf, itos(location.hist_line+1));
                                    strcat(hbuf, ")");
                              }
                        }
                        show_info(ep,hbuf);
                        return;
                  }
#     if 0  /* debugging, modify as required */
            case cntl('D'):         /* ^X^D show debugging info */
                  {
                        char debugbuf[MAXLINE];

                        strcpy(debugbuf, "count=");
                        strcat(debugbuf, itos(count));
                        strcat(debugbuf, " eol=");
                        strcat(debugbuf, itos(eol));
                        strcat(debugbuf, " cur=");
                        strcat(debugbuf, itos(cur));
                        strcat(debugbuf, " crallowed=");
                        strcat(debugbuf, itos(crallowed));
                        strcat(debugbuf, " plen=");
                        strcat(debugbuf, itos(plen));
                        strcat(debugbuf, " w_size=");
                        strcat(debugbuf, itos(w_size));

                        show_info(ep,debugbuf);
                        return;
                  }
#     endif /* debugging code */
#   endif /* ESH_BETTER */
#endif /* KSHELL */

                default:
                        beep();
                        return;
      }
}

static void search(Emacs_t* ep,genchar *out,int direction)
{
#ifndef ESH_NFIRST
      Histloc_t location;
#endif
      register int i,sl;
      genchar str_buff[LBUF];
      register genchar *string = drawbuff;
      /* save current line */
      int sav_cur = cur;
      genncpy(str_buff,string,sizeof(str_buff)/sizeof(*str_buff));
      string[0] = '^';
      string[1] = 'R';
      string[2] = '\0';
      sl = 2;
      cur = sl;
      draw(ep,UPDATE);
      while ((i = ed_getchar(ep->ed,1))&&(i != '\r')&&(i != '\n'))
      {
            if (i==usrerase || i==DELETE || i=='\b' || i==ERASECHAR)
            {
                  if (sl > 2)
                  {
                        string[--sl] = '\0';
                        cur = sl;
                        draw(ep,UPDATE);
                  }
                  else
                        beep();
                  continue;
            }
            if (i==usrkill)
            {
                  beep();
                  goto restore;
            }
            if (i == '\\')
            {
                  string[sl++] = '\\';
                  string[sl] = '\0';
                  cur = sl;
                  draw(ep,APPEND);
                  i = ed_getchar(ep->ed,1);
                  string[--sl] = '\0';
            }
            string[sl++] = i;
            string[sl] = '\0';
            cur = sl;
            draw(ep,APPEND);
      }
      i = genlen(string);
      
      if (direction < 1)
      {
            ep->prevdirection = -ep->prevdirection;
            direction = 1;
      }
      else
            direction = -1;
      if (i != 2)
      {
#if SHOPT_MULTIBYTE
            ed_external(string,(char*)string);
#endif /* SHOPT_MULTIBYTE */
            strncpy(lstring,((char*)string)+2,SEARCHSIZE);
            ep->prevdirection = direction;
      }
      else
            direction = ep->prevdirection ;
      location = hist_find(sh.hist_ptr,(char*)lstring,hline,1,direction);
      i = location.hist_command;
      if(i>0)
      {
            hline = i;
#ifdef ESH_NFIRST
            hloff = location.hist_line = 0;     /* display first line of multi line command */
#else
            hloff = location.hist_line;
#endif /* ESH_NFIRST */
            hist_copy((char*)out,MAXLINE, hline,hloff);
#if SHOPT_MULTIBYTE
            ed_internal((char*)out,out);
#endif /* SHOPT_MULTIBYTE */
            return;
      }
      if (i < 0)
      {
            beep();
#ifdef ESH_NFIRST
            location.hist_command = hline;
            location.hist_line = hloff;
#else
            hloff = 0;
            hline = histlines;
#endif /* ESH_NFIRST */
      }
restore:
      genncpy(string,str_buff,sizeof(str_buff)/sizeof(*str_buff));
      cur = sav_cur;
      return;
}


/* Adjust screen to agree with inputs: logical line and cursor */
/* If 'first' assume screen is blank */
/* Prompt is always kept on the screen */

static void draw(register Emacs_t *ep,Draw_t option)
{
#define     NORMAL ' '
#define     LOWER  '<'
#define     BOTH   '*'
#define     UPPER  '>'

      register genchar *sptr;       /* Pointer within screen */
      genchar nscreen[2*MAXLINE];   /* New entire screen */
      genchar *ncursor;       /* New cursor */
      register genchar *nptr;       /* Pointer to New screen */
      char  longline;               /* Line overflow */
      genchar *logcursor;
      genchar *nscend;        /* end of logical screen */
      register int i;
      
      nptr = nscreen;
      sptr = drawbuff;
      logcursor = sptr + cur;
      longline = NORMAL;
      
      if (option == FIRST || option == REFRESH)
      {
            ep->overflow = NORMAL;
            ep->cursor = ep->screen;
            ep->offset = 0;
            ep->cr_ok = crallowed;
            if (option == FIRST)
            {
                  ep->scvalid = 1;
                  return;
            }
            *ep->cursor = '\0';
            putstring(ep,Prompt);   /* start with prompt */
      }
      
      /*********************
       Do not update screen if pending characters
      **********************/
      
      if ((lookahead)&&(option != FINAL))
      {
            
            ep->scvalid = 0; /* Screen is out of date, APPEND will not work */
            
            return;
      }
      
      /***************************************
      If in append mode, cursor at end of line, screen up to date,
      the previous character was a 'normal' character,
      and the window has room for another character.
      Then output the character and adjust the screen only.
      *****************************************/
      

      i = *(logcursor-1);     /* last character inserted */
      
      if ((option == APPEND)&&(ep->scvalid)&&(*logcursor == '\0')&&
          print(i)&&((ep->cursor-ep->screen)<(w_size-1)))
      {
            putchar(ep->ed,i);
            *ep->cursor++ = i;
            *ep->cursor = '\0';
            return;
      }

      /* copy the line */
      ncursor = nptr + ed_virt_to_phys(ep->ed,sptr,nptr,cur,0,0);
      nptr += genlen(nptr);
      sptr += genlen(sptr);
      nscend = nptr - 1;
      if(sptr == logcursor)
            ncursor = nptr;
      
      /*********************
       Does ncursor appear on the screen?
       If not, adjust the screen offset so it does.
      **********************/
      
      i = ncursor - nscreen;
      
      if ((ep->offset && i<=ep->offset)||(i >= (ep->offset+w_size)))
      {
            /* Center the cursor on the screen */
            ep->offset = i - (w_size>>1);
            if (--ep->offset < 0)
                  ep->offset = 0;
      }
                  
      /*********************
       Is the range of screen[0] thru screen[w_size] up-to-date
       with nscreen[offset] thru nscreen[offset+w_size] ?
       If not, update as need be.
      ***********************/
      
      nptr = &nscreen[ep->offset];
      sptr = ep->screen;
      
      i = w_size;
      
      while (i-- > 0)
      {
            
            if (*nptr == '\0')
            {
                  *(nptr + 1) = '\0';
                  *nptr = ' ';
            }
            if (*sptr == '\0')
            {
                  *(sptr + 1) = '\0';
                  *sptr = ' ';
            }
            if (*nptr == *sptr)
            {
                  nptr++;
                  sptr++;
                  continue;
            }
            setcursor(ep,sptr-ep->screen,*nptr);
            *sptr++ = *nptr++;
#if SHOPT_MULTIBYTE
            while(*nptr==MARKER)
            {
                  if(*sptr=='\0')
                        *(sptr + 1) = '\0';
                  *sptr++ = *nptr++;
                  i--;
                  ep->cursor++;
            }
#endif /* SHOPT_MULTIBYTE */
      }
      
      /******************
      
      Screen overflow checks 
      
      ********************/
      
      if (nscend >= &nscreen[ep->offset+w_size])
      {
            if (ep->offset > 0)
                  longline = BOTH;
            else
                  longline = UPPER;
      }
      else
      {
            if (ep->offset > 0)
                  longline = LOWER;
      }
      
      /* Update screen overflow indicator if need be */
      
      if (longline != ep->overflow)
      {
            setcursor(ep,w_size,longline);
            ep->overflow = longline;
      }
      i = (ncursor-nscreen) - ep->offset;
      setcursor(ep,i,0);
      if(option==FINAL && ep->ed->e_multiline)
            setcursor(ep,nscend+1-nscreen,0);
      ep->scvalid = 1;
      return;
}

/*
 * put the cursor to the <newp> position within screen buffer
 * if <c> is non-zero then output this character
 * cursor is set to reflect the change
 */

static void setcursor(register Emacs_t *ep,register int newp,int c)
{
      register int oldp = ep->cursor - ep->screen;
      newp  = ed_setcursor(ep->ed, ep->screen, oldp, newp, 0);
      if(c)
      {
            putchar(ep->ed,c);
            newp++;
      }
      ep->cursor = ep->screen+newp;
      return;
}

#if SHOPT_MULTIBYTE
static int print(register int c)
{
      return((c&~STRIP)==0 && isprint(c));
}

static int _isword(register int c)
{
      return((c&~STRIP) || isalnum(c) || c=='_');
}
#endif /* SHOPT_MULTIBYTE */

Generated by  Doxygen 1.6.0   Back to index