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

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



/*
 * vimisc.c - pre-gnu-vi  rev. 0.3
 *
 * misc. vi routines
 */




#include "vi.h"

docount (lines, chars)

int *lines, *chars;

{
   auto int l, c, k;
   l = c = 0;
   for (k = 1; k < endl; ++k) {
      ++l;
      c = c + strlen (texts [k]) - 1;
   }
   *lines = l;
   *chars = c;
}
int dodot ()

{
   auto int n, oldl, oldc, newl, newc;
   auto char c;
   c = readch ();	/* skip '.' */
   switch (lastcmd) {
      case 'i' :
      case 'I' :
      case 'o' :
      case 'O' :
      case 'a' :
      case 'A' :
         if (lastcmd == 'a')
            ++curc;
         else if (lastcmd == 'A') {
            docureol (&newl, &newc);
            curc = newc + 1;
         } else if (lastcmd == 'I') {
            docurwhite (curl, &newl, &newc);
            curc = newc;
         } else if (lastcmd == 'o') {
    /*        insnewlinea ("\n\n", curl);*/
            ++curl;
            curc = 1;
         } else if (lastcmd == 'O') {
            /*insnewlinea ("\n\n", curl - 1);*/
            /*--curl;*/
            curc = 1;
         }
         n = reinsert (ibuf);
         break;
         
      case 'r' :
         if (texts [curl] [curc] != '\n') {
            texts [curl] [curc] = laststring [0];
            n = 0;
         } else {
            beep ();
            n = -1;
         }
         break;
         
      case '~' :
         if ( ('a' <= texts [curl] [curc]) && (texts [curl] [curc] <= 'z') )
            texts [curl] [curc] = texts [curl] [curc] - ('a' - 'A');
         else if ( ('A' <= texts [curl] [curc]) && (texts [curl] [curc] <= 'Z') )
            texts [curl] [curc] = texts [curl] [curc] + ('a' - 'A');
         n = 0;
         break;
         
      case 'p' :
      case 'P' :
         unreadch (lastcmd);
         doput ();
         n = 0;
         break;
         
      case '>' :
         unreadch ('>');
         unreadch ('>');
         n = dorshift (lastcount);
         break;
         
      case '<' :
         unreadch ('<');
         unreadch ('<');
         n = dolshift (lastcount);
         break;
         
      case 'c' :
         oldl = curl;
         oldc = curc;
         unreadch (laststring [0]);
         if (docursor (lastcount, &newl, &newc) ) {
            n = -1;
         } else {
            if (oldl == newl) {
               delinline (oldl, oldc, newc);
               reinsert (ibuf);
               n = 0;
            } else {
               n = -1;
            }
         }
         lastcmd = 'c';
         break;
         
      case 'd' :
         unreadch (laststring [0]);
         unreadch ('d');
         n = dodelete (lastcount);	
	 break;
      default :
	 n = -1;
	 break;
   }
   return (n);
}



dojoin (count)

int count;

{
   auto int cl, eol, bol2, newl, newc, k, blanks;
   auto char *newline, c;
   c = readch ();	/* skip 'J' */
   if ( (curl + count) >= (endl - 1) ) 
      return (-1);
   cl = curl;
   while (count > 0) {
      eol = strlen (texts [cl]) - 2;
      while ( (texts [cl] [eol] == ' ') || (texts [cl] [eol] == '\t') )
         --eol;
      docurwhite (cl + 1, &newl, &newc);
      bol2 = newc;
      if (texts [cl + 1] [bol2] == '\n') {
         /* Joining a second empty line, ignore secondline */
         dellines (cl + 1, cl + 1);
      } else if (texts [cl] [eol] == '\n') {
         /* Joining to an empty line, ignore first line */
         dellines (cl, cl);
      } else {
         if ( (texts [cl] [eol] == '.') || (texts [cl] [eol] == ':') )
            blanks = 2;
         else
            blanks = 1;
         if ( !(newline = malloc (strlen (&texts [cl + 1] [bol2]) + 
                                     eol + 4 + blanks) ) )
            nomem (40);
         for (k = 0; k <= eol; ++k)
            newline [k] = texts [cl] [k];
         newline [k] = '\0';
         for (k = 0; k < blanks; ++k) 
            strcat (newline, " ");
         strcat (newline, &texts [cl + 1] [bol2]);
         if (free (texts [cl]) )
            nofree (40);
         texts [cl] = newline;
         dellines (cl + 1, cl + 1);
      }
      --count;
   }
   modflag = 1;
   return (0);
}
      
      

dolshift (count)

int count;

{
   auto char ch, *newline, tmps [40];
   auto int cl, i, j, k, newl, newc, cc, wdel, ndel, nlines;
   ch = readch ();	/* skip first '<' */
   ch = readch ();
   if (count == -1)
      count = 1;
   if (ch != '<') {
      unreadch (ch);
      if (docursor (count, &newl, &newc) )
         return (-1);
      count = newl - curl + 1;
   }
   if (curl + count >= endl)
      return (-1);
   lastcmd = '<';
   lastcount = count;
   cl = curl;
   nlines = count;
   while (count > 0) {
      docurwhite (cl, &newl, &newc);
      cc = newc;
      wdel = shiftwidth;
      while ( (wdel > 0) && (cc > 1) ) {
         wdel = wdel - (textwidth (texts [cl], cc, 0) - 
                        textwidth (texts [cl], cc - 1, 0) );
         --cc;
      }
      ndel = newc - cc;
      if (wdel > 0)
         wdel = 0;
      if ( !(newline = malloc (strlen (texts [cl]) + 3 - ndel - wdel) ) )
         nomem (91);
      for (k = 0; k < cc; ++k) 
         newline [k] = texts [cl] [k];
      for (j = 0; j < - wdel; ++j)
         newline [cc + j] = ' ';
      for (i = newc; i < strlen (texts [cl]) + 1; ++i)
         newline [i - ndel - wdel] = texts [cl] [i];
      if (free (texts [cl]) )
         nofree (91);
      texts [cl] = newline;
      --count;
      if (cl == curl) 
         curc = curc - ndel;
      ++cl;
   }
   if (curc < 1)
      curc = 1;
   if (nlines > showchange) {
      movtobot ();
      cleareol ();
      sprintf (tmps, "%d lines <ed", nlines);
      writes (tmps);
      refscr ();
   }
   return (0);
}
   

domark ()

{
   auto char c;
   c = readch ();	/* skip 'm' */
   c = readch ();
   if (c < 128) {
      marks [c] = curl;
      return (0);
   }
   return (-1);
}


dorshift (count)

int count;

{
   auto char ch, *newline, tmps [40];
   auto int cl, j, k, newl, newc, nlines;
   ch = readch ();		/* skip the '>' */
   ch = readch ();
   if (count == -1)
      count = 1;
   if (ch != '>') {
      unreadch (ch);
      if (docursor (count, &newl, &newc) )
         return (-1);
      count = newl - curl + 1;
   }
   if (curl + count >= endl)
      return (-1);
   lastcmd = '>';
   lastcount = count;
   cl = curl;
   nlines = count;
   while (count > 0) {
      docurwhite (cl, &newl, &newc);
      if ( !(newline = malloc (strlen (texts [cl]) + 1 + shiftwidth) ) )
         nomem (81);
      for (k = 0; k < newc; ++k) 
         newline [k] = texts [cl] [k];
      for (j = 0; j < shiftwidth; ++j)
         newline [k + j] = ' ';
      for (j = k; j < strlen (texts [cl]) + 1; ++j)
         newline [j + shiftwidth] = texts [cl] [j];
      if (free (texts [cl]) )
         nofree (81);
      texts [cl] = newline;
      --count;
      if (cl == curl)
         curc = curc + shiftwidth;
      ++cl;
   }
   if (nlines > showchange) {
      movtobot ();
      cleareol ();
      sprintf (tmps, "%d lines >ed", nlines);
      writes (tmps);
      refscr ();
   }
   return (0);
}


int doundo ()

{

   auto int n;
   auto char c;
   c = readch ();	/* skip 'u' */
   switch (lastuncmd) {
      case 'd' :
         curl = lastdl;
         curc = lastdc;
         unreadch ('P');
         doput ();
         lastuncmd = 'i';
         lastl1 = lastdl;
         lastc1 = lastdc;
         ibuf = dbuf;
         n = 0;
         break;
      
      case 'i' :
      case 'o' :
      case 'O' :
      case 'a' :
         curl = lastl1;
         curc = lastc1;
         uninsert ();
         lastuncmd = ' ';
         n = 0;
         break;
         
      default :
         n = -1;
   }
   return (n);
}
        

nofree (k)

int k;

{
   auto char line [256];
   movtobot ();
   sprintf (line, "BAD FREE %d!!!", k);
   writes (line);
   refscr ();
}


nomem (k)

int k;

{
   auto char line [256];
   movtobot ();
   cleareol ();
   sprintf (line, "OUT OF MEMORY %d!!", k);
   writes (line);
   refscr ();
   beep ();
   readch ();
}
