/* Copyright (C) 1987 Free Software Foundation, Inc.

   This will be free software eventually,
   but not until it is finished.  */



/*
 * vicur.c - pre-gnu-vi  rev. 0.3
 *
 * vi cursor functions
 */




#include "vi.h"

int dobword (count, newl, newc)

int count, *newl, *newc;

{
   auto int cc, cl, k;
   cl = curl;
   cc = curc;
   while ( count && (cl > 0) ) {
      if (isalphanum (texts [cl] [cc]) ) {
         k = 0;
         while (isalphanum (texts [cl] [cc]) ) { 
            --cc;
            ++k;
         }
         if (k != 1) {
            ++cc;
	    --count;
	    continue;
 	 }
      } else if (isspecial (texts [cl] [cc]) ) {
         k = 0;
         while (isspecial (texts [cl] [cc]) ) {
            --cc;
            ++k;
         }
	 if (k != 1) {
	    ++cc;
	    --count;
	    continue;
	 }
      }
      if (cc < 1) {
         --cl;
         cc = strlen (texts [cl]) - 2;
      }
      while ( (cl > 0) && (iswhite (texts [cl] [cc]) ) ) {
         --cc;
         if (cc < 1) {
            --cl;
	    cc = strlen (texts [cl]) - 2;
         }
      }
      if (cl > 0) {
         if (isalphanum (texts [cl] [cc]) ) {
            while (isalphanum (texts [cl] [cc]) )
	       --cc;
            ++cc;
         } else if (isspecial (texts [cl] [cc]) ) {
	    while (isspecial (texts [cl] [cc]) )
	       --cc;
	    ++cc;
         }
      }   
      --count;
   }
   if (cl <= 0) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   *newl = cl;
   *newc = cc;
   return (0);
}      

   

int docurdown (count, newl, newc)

int count, *newl, *newc;	

{
   auto int col, col2, j;
   if ( (curl + count) >= endl) {
      *newl = curl;
      *newc = curc;
      return (-1);	
   }
   col = 0;
   for (j = 1; j < curc; ++j) 
      col = col + charwidth (texts [curl] [j], col);
   *newl = curl + count;
   *newc = 1;
   if (texts [*newl] [*newc] == '\n')
      return (0);
   col2 = 0;
   while ( (col > (col2 ) ) && (texts [*newl] [*newc] != '\n') ) {
      col2 = col2 + charwidth (texts [*newl] [*newc], col2);
      *newc = *newc + 1;
   }
   if (texts [*newl] [*newc] == '\n')
      *newc = *newc - 1;
   return (0);
}


int docureol (newl, newc)

int *newl, *newc;

{
   auto int j;
   j = curc;
   if (texts [curl] [curc] != '\n') {
      while (texts [curl] [j] != '\n')
               ++j;
      --j;
   }
   *newl = curl;
   *newc = j;
   return (0);
}	

   
int docurleft (count, newl, newc)

int count, *newl, *newc;

{
   auto int k;
   k = curc - 1;
   while (count && (texts [curl] [k] != '\n') ) {
      --k;
      --count;
   }
   *newc = k + 1;
   *newl = curl;
   return (0);
}


int docurmatch (count, newl, newc)

int count, *newl, *newc;

{
   auto char c, c2;
   auto int n, cc, cl;
   if (count != 1) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   switch (c2 = texts [curl] [curc] ) {
      case '(' :
         c = ')';
	 break;
      case '[' :		
         c = ']';
	 break;
      case '{' :
         c = '}';
         break;
      case ')' :
         c = '(';
   	 break;
      case ']' :
	 c = '[';
	 break;
      case '}' :
	 c = '{';
	 break;
      default :
         *newl = curl;
         *newc = curc;
	 return (-1);
   }
   cl = curl;
   cc = curc;
   n = 0;
   if ( (c == '(') || (c == '[') || (c == '{') ) {
      /* backwards search */
      while ( (n != 1) || (texts [cl] [cc] != c) ) {
	 if (texts [cl] [cc] == c)
	    --n;
	 else if (texts [cl] [cc] == c2)
	    ++n;
	 if (cc <= 1) {
	    if (cl <= 1) {
	       *newl = curl;
	       *newc = curc;
	       return (-1);
	    }
	    --cl;
	    cc = strlen (texts [cl]) - 2;
	   } else
	    --cc;
      }
   } else {
      while ( (n != 1) || (texts [cl] [cc] != c) ) {
	 if (texts [cl] [cc] == c)
	    --n;
	 else if (texts [cl] [cc] == c2)
	    ++n;
	 if (texts [cl] [cc] == '\n') {
	    ++cl;
	    cc = 1;
	    if (cl == endl) {
	       *newl = curl;
	       *newc = curc;
	       return (-1);
	    }
         } else
	    ++cc;
      }
   }
   *newl = cl;
   *newc = cc;
   return (0);
}

	    

docurnull (newl, newc)

int *newl, *newc;

{
   auto int cl, cc;
   cl = curl;
   cc = curc;
   if (texts [cl] [cc] != '\n')
      ++cc;
   while (cl < endl) {
      if (texts [cl] [cc] == '\0') {
         *newl = cl;
         *newc = cc;
         return (0);
      }
      if (texts [cl] [cc] == '\n') {
         ++cl;
         cc = 1;
      } else {
         ++cc;
      }
   }
   *newl = curl;
   *newc = curc;
   return (-1);
}


int docursor (count, newl, newc)

int count, *newl, *newc;

{
   auto char c;
   auto int n, j;
   extern int docurdown (), docurup (), docurleft (), docurright (),
      docurzero (), docureol (), dofword (), dobword (), docurmatch (),
      dosearch (), dosection ();
   c = readch ();
   switch (c) {
      case 14 :
         n = docurnull (newl, newc);
         break;
         
      case '+' :
      case '\r' :
      case 'j' :
      case 5 :
         n = docurdown (count, newl, newc);
         if (!n) {
            if ( (c == '\r') || (c == '+') )
               docurwhite (*newl, newl, newc);
            else if (c == 5)
               bscrl = bscrl + count;
         }
	 break;
         
      case 4 :
	 n = docurdown (9 * count, newl, newc);
         if (!n)
            bscrl = bscrl + 9 * count;
         break;
         
      case '-' :
      case 'k' :
      case 25 :
         if (c == 25) {
            bscrl = bscrl - count;
            if (bscrl < 1) {
               bscrl = 1;
               n = -1;
               break;
            }
         }
	 n = docurup (count, newl, newc);
         if (!n && (c == '-') )
            docurwhite (*newl, newl, newc);
	 break;
         
      case 21 :
         n = docurup (9 * count, newl, newc);
         if (!n) {
            bscrl = bscrl - 9 * count;
            if (bscrl < 1)
               bscrl = 1;
         }
         break;
         
      case 'h' :
      case '\b' :
	 n = docurleft (count, newl, newc);
	 break;
         
      case ' ' :
      case 'l' :
	 n = docurright (count, newl, newc);
	 break;
         
      case 'f' :
      case 'F' :
      case 't' :
      case 'T' :
      case ';' :
      case ',' :
         unreadch (c);
         n = dofindchar (count, newl, newc);
         break;
         
      case 'w' :
      case 'e' :
         unreadch (c);
	 n = dofword (count, newl, newc);	
	 break;
         
      case 'b' :
	 n = dobword (count, newl, newc);
	 break;
         
      case 'G' :
         n = dogoto (count, newl, newc);
         break;
         
      case '0' :
         n = docurzero (newl, newc);
	 break;
         
      case '^' :
         n = docurwhite (curl, newl, newc);
         break;
         
      case '$' :
	 if (count == 1)
            n = docureol (newl, newc);
	 else {
	    beep ();
	    n = 1;
	 }
	 break;
         
      case '%' :
         n = docurmatch (count, newl, newc);
	 break;
         
      case 'n' :
   	 if (count == 1) {
            unreadch (lasts2);
	    n = dosearch (newl, newc);
	 } else {
	    n = -1;
         }
	 break;
         
      case 'N' :
	 if (count == 1) {
	    if (lasts2 == 'f')
	       lasts2 = 'b';
	    else
	       lasts2 = 'f';
            unreadch (lasts2);
	    n = dosearch (newl, newc);
	 } else {
	    n = -1;
	 }
	 break; 
  
      case 'H' :
         j = curl;
         *newl = curl = bscrl;
         n = 0;
         if (count > 0)
            n = docurdown (count, newl, newc);
         if (!n) 
            docurwhite (*newl, newl, newc);
         curl = j;
         break;
         
      case 'M' :
         j = curl;
         *newl = curl = bscrl + (escrl - bscrl) / 2;
         n = 0;
         if (count > 0)
            n = docurdown (count, newl, newc);
         if (!n) 
            docurwhite (*newl, newl, newc);
         curl = j;
         break;
         
      case 'L' :
         j = curl;
         *newl = curl = escrl - 1;
         n = 0;
         if (count > 0)
            n = docurup (count, newl, newc);
         if (!n)
            docurwhite (*newl, newl, newc);
         curl = j;
         break;
         
      case '`' :
      case '\'' :
         if (count == 1) {
            unreadch (c);
            n = domove (newl, newc);
         } else {
            n = -1;
         }
         break;
 	
      case ']' :
      case '[' :
         unreadch (c);
	 n = dosection (count, newl, newc);
	 break;
	
      case '/' :
      case '?' :
         if (count == 1) {
            unreadch (c);
	    n = dosearch (newl, newc);
	 } else {
	    n = -1;
	 }
	 break;

      default :
         n = -1;
   }
   return (n);
}


int docurright (count, newl, newc)

int count, *newl, *newc;

{
   auto int k;
   k = curc;
   if (texts [curl] [curc] != '\n') {
      while (count && (texts [curl] [k] != '\n') ) {
         ++k;
         --count;
      }
      if (texts [curl] [k] == '\n')
         --k;
   }
   *newl = curl;
   *newc = k;
   return (0);
}

      
int docurup (count, newl, newc)

int count, *newl, *newc;
  
{
   auto int col, col2, j;
   if ( (curl - count) < 1) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   col = 0;
   for (j = 1; j < curc; ++j) 
      col = col + charwidth (texts [curl] [j], col);
   *newl = curl - count;
   *newc = 1;
   if (texts [*newl] [*newc] == '\n')
      return (0);
   col2 = 0;
   while ( (col > (col2 ) ) && (texts [*newl] [*newc] != '\n') ) {
      col2 = col2 + charwidth (texts [*newl] [*newc], col2);
      *newc = *newc + 1;
   }
   if (texts [*newl] [*newc] == '\n')
      *newc = *newc - 1;
   return (0);
}

   
int docurwhite (online, newl, newc)

int online, *newl, *newc;

{
   auto int k;
   k = 1;
   while ( (texts [online] [k] == ' ') ||
           (texts [online] [k] == '\t') ) 
      ++k;
   if ( (texts [online] [k] == '\n') && (k > 1) )
      --k;
   *newl = online;
   *newc = k;
   return (0);
}

int docurzero (newl, newc)

int *newl, *newc;

{
   *newl = curl;
   *newc = 1;
   return (0);
}


dofindchar (count, newl, newc)

int count, *newl, *newc;

{
   auto char c, cmd;
   auto int cl, cc;
   cmd = readch ();
   cl = curl;
   cc = curc;
   if (cmd == ';') {
      cmd = lastfcmd;
      c = lastfchar;
   } else if (cmd == ',') {
      if (lastfcmd == 'f')
         cmd = 'F';
      else if (lastfcmd == 'F')
         cmd = 'f';
      else if (lastfcmd == 't')
         cmd = 'T';
      else 
         cmd = 't';
      c = lastfchar;
   } else {
      c = readch ();
   }
   while (count > 0) {
      if ( (cmd == 'F') || (cmd == 'T') ) {
         /* Backwards search */
         --cc;
         while (texts [cl] [cc] != c) {
	    if (cc <= 1) {
	          *newl = curl;
	          *newc = curc;
	          return (-1);
	    } else {
	       --cc;
            }
         }
      } else {
         /* Forwards search */
         ++cc;
         while (texts [cl] [cc] != c) {
	    if (texts [cl] [cc] == '\n') {
	          *newl = curl;
	          *newc = curc;
	          return (-1);
            } else {
	       ++cc;
            }
         }
      }
      --count;
   }
   if (cmd == 't')  {
      if (cc != 1) 
         --cc;
   } else if (cmd == 'T') {
      ++cc;
      if (texts [cl] [cc] == '\n') 
         --cc;
   }
   lastfcmd = cmd;
   lastfchar = c;
   *newl = cl;
   *newc = cc;
   return (0);
}
      

int dofword (count, newl, newc)

int count, *newl, *newc;

{
   auto char cmd;
   auto int cl, cc;
   cmd = readch ();
   cc = curc;
   cl = curl;
   while (count && (cl != endl) ) {
      if (isalphanum (texts [cl] [cc]) ) {
         while (isalphanum (texts [cl] [cc]) )
	    ++cc;
      } else if (isspecial (texts [cl] [cc]) ) {
         while (isspecial (texts [cl] [cc]) )
	    ++cc;
      }
      if ( (cmd == 'w') || (count > 1) ) {
         while ( (cl != endl) && (iswhite (texts [cl] [cc]) ) ) {
            if (texts [cl] [cc] == '\n') {
 	       ++cl;
	       cc = 1;
            } else
              ++cc;
         }
      } else {
         --cc;
      }
      --count;
   }
   if (cl == endl) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   if (cc == 0)
      cc = 1;
   *newl = cl;
   *newc = cc;
   return (0);	
}


int dogoto (count, newl, newc)

int count, *newl, *newc;

{
   if (count >= endl) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   if (count == -1)
      *newl = (endl == 1) ? endl : endl - 1;
   else
      *newl = count;
   *newc = 1;
   marks ['\''] = curl;
   return (0);
}


domove (newl, newc)

int *newl, *newc;

{
   auto char c, cmd;
   cmd = readch ();
   c = readch ();
   if (c > 127) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   if ( ('0' <= c) && (c <= '9') ) {
      if (dowinn (c - '0') ) {
         return (-1);
      } else {
         *newl = curl;
         *newc = curc;
         curl = -1;
         return (0);
      }
   }
   if (marks [c] == 0) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }
   *newl = marks [c];
   if (cmd == '`') {
      docurwhite (*newl, newl, newc);
   } else {   
      if (strlen (texts [*newl]) == 2)
         *newc = 1;
      else if (curc > (strlen (texts [*newl]) - 2) )
         *newc = strlen (texts [*newl]) - 2;
      else
         *newc = curc;
   }
   marks ['\''] = curl;
   return (0);
}


int dosearch (newl, newc)

int *newl, *newc;

{
   auto char c, line [256];
   auto int cl, cc, k;
   movtobot ();
   cleareol ();
   c = readch ();
   line [0] = '\0'; 
   k = 0;
   if (c == 'f') {
      writech ('/');
      refscr ();
   } else if (c == 'b') {
      writech ('?');
      refscr ();
   } else {	
      writech (c);
      refscr ();
      if (reads (line, 1) ) {
         *newl = curl;
         *newc = curc;
         return (-1);
      }
   }
   movtobot ();
   refscr ();
   if (line [0]) 
      strcpy (lastsearch, line);
   else
      strcpy (line, lastsearch);
   lasts2 = c;
   cl = curl;
   cc = curc;
   if ( (c == '/') || (c == 'f') ) {
      lasts2 = 'f';
      if (texts [cl] [cc] != '\n')
         ++cc;
      while ( (cl != endl) && (searcmp (line, &texts [cl] [cc]) ) ) {
         if ( (texts [cl] [cc] == '\n') && cc) {
            ++cl;
            cc = 0;
         } else
	    ++cc;
      }
      if (!searcmp (line, &texts [cl] [cc]) ) {
         if (line [0] == '^')
            ++cc;
         *newl = cl;
	 *newc = cc;
         marks ['\''] = curl;
	 return (0);
      }
      if (wrapscan) {
         cl = 1;
         cc = 0;
         while ( (cl != curl) && (searcmp (line, &texts [cl] [cc]) ) ) {
            if ( (texts [cl] [cc] == '\n') && cc) {
               ++cl;
               cc = 0;
            } else
	       ++cc;
         }
      }
      if (!searcmp (line, &texts [cl] [cc]) ) {
         if (line [0] == '^')
            ++cc;
         *newl = cl;
	 *newc = cc;
         marks ['\''] = curl;
	 return (0);
      }
      *newl = curl;
      *newc = curc;
      return (-1);
   } else {
      lasts2 = 'b';
      --cc;
      while ( (cl != 0) && (searcmp (line, &texts [cl] [cc]) ) ) {
         if (cc < 1) {
            --cl;
	    cc = strlen (texts [cl]) - 1;
         } else
	    --cc;
      }
      if (!searcmp (line, &texts [cl] [cc]) ) {
         if (line [0] == '^')
            ++cc;
         *newl = cl;
	 *newc = cc;
         marks ['\''] = curl;
	 return (0);
      }
      if (wrapscan) {
         cl = endl;
         cc = strlen (texts [cl]) - 1;
         while ( (cl > curl) && (searcmp (line, &texts [cl] [cc]) ) ) {
	    if (cc < 1) {
	       --cl;
	       cc = strlen (texts [cl]) - 1;
            } else
	       --cc;
         }
      }
      if (!searcmp (line, &texts [cl] [cc]) ) {
         if (line [0] == '^')
            ++cc;
         *newl = cl;
	 *newc = cc;
         marks ['\''] = curl;
	 return (0);
      }
      *newl = curl;
      *newc = curc;
      return (-1);
   }
}


int dosection (count, newl, newc)

int count, *newl, *newc;

{


   auto char c, c2, line [4];
   auto int cl, cc;
   c = readch ();
   c2 = readch ();
   if (c2 != c) {
      *newl = curl;
      *newc = curc;
      return (-1);
   }	
   strcpy (line, STLFLBRACE);
   cl = curl; 
   cc = curc;
 while (count > 0) {
   if ( (c == ']') ) {
      /* forward search */
      ++cl;
      while (cl < endl) {
         if (texts [cl] [1] == ALBRACE)
	    break;
         ++cl;
      }
      if (cl >= endl) {
	 *newl = curl;
	 *newc = curc;
	 return (-1);
      }
   } else {
      --cl;	
      while (cl > 0) {
         if (texts [cl] [1] == ALBRACE)
	    break;
         --cl;
      }
      if (cl < 1) {
	 *newl = curl;
	 *newc = curc;
	 return (-1);
      }
   }
   --count;
 }
   *newl = cl;
   *newc = 1;
   marks ['\''] = curl;
   return (0);
}





/* Search for regexp s in t */

searcmp (s, t)

char *s, *t;

{
   if (*s == '^') {
      if (*t == '\n') {
         ++s;
         ++t;
      } else {
         return (-1);
      }
   }
   while ( (*s == *t) || 
           (ignorecase && (tolower (*s) == tolower (*t) ) ) ||
           (magic && (*s == '.') && (*t != '\n') ) ) {
      ++s;
      ++t;
   }
   if ( (*s == '$') && (s [1] == '\0') && 
        (*t == '\n') && (t [1] == '\0') )
      return (0);
   else
      return ((int) *s);
}

      
/* bottom */
