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

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



/*
 * viexs.c - pre-gnu-vi  rev. 0.3
 *
 * vi ex sub-command functions
 */




#include "vi.h"



comeqv (cmd, test)

char *cmd, *test;

{
   while ( (*cmd == *test) && *cmd) {
      ++cmd;
      ++test;
   }
   return (*cmd == '\0');
}
     


int docommand ()

{
   auto char c, line [256], cmd [256];
   auto int k, first, second, red;
   movtobot ();
   c = readch ();	/* read ':' */
   red = 0;
   do {
      cleareol ();
      writech (':');
      refscr ();
      if (reads (line, 1) )
         return (1);
      movtobot ();
      refscr ();
      k = parseaddrs (line, 0, &first, &second);
      k = parsecmd (line, k, cmd);
      k = doexcmd (first, second, cmd, &line [k]);
      if (k == 2) {
         red = 1;
         /*writech (TO_VR);*/
         puts ("[Press Return to Continue]");
         /*writech (TO_VN);*/
         c = getchar ();
         while ( (c != '\r') && (c != ':') && (c != '\n') )
            c = getchar ();
         if (c == ':') {
            writech ('\n');
            refscr ();
         } else {
            initscr ();
            noecho ();
            /* cbreak (); */
            k = 1;
         }
      }
   } while (k == 2);
   if (red) {
      unreadch ('\001');
      doredraw ();
      updwins ();
   }
   return (k);
}


doedit (first, second, line)

int first, second;
char line [];

{
   auto int lpt, ignmod;
   if ( (first != -1) || (second != -1) ) {
      beep ();
      return (-1);
   }
   lpt = 0;
   if (line [0] == '!') {
      ignmod = 0;
      ++lpt;
   } else {
      ignmod = 1;
   }
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   if (modflag && ignmod) {
      movtobot ();
      beep ();
      writes ("No write since last change (edit! overrides)");
      refscr ();
      return (-1);
   }
   newfile (&line [lpt]);
   return (1);
}
   

doexcmd (first, second, cmd, line)

int first, second;
char cmd [], line [];

{
   if ( (cmd [0] == '\0') && (first != -1) ) {
      if (line [0] == '\0') {
         if (first == 0) {
            marks ['\''] = curl;
            curl = 1;
            docurwhite (curl, &curl, &curc);
         } else if ( (1 <= first) && (first < endl) ) {
            marks ['\''] = curl;
            curl = first;
            docurwhite (curl, &curl, &curc);
         } else {
            beep ();
         }
      } else {
         beep ();
      }
   } else if ( (cmd [0] == '\0') && (line [0] == '!') ) {
      doshell (line, 1);
      return (2);
   } else if (cmd [0] == '\0') {
      beep ();
   } else if (comeqv (cmd, "file") ) { 
      dostat ();
   } else if (comeqv (cmd, "edit") ) {
      doedit (first, second, line);
   } else if (comeqv (cmd, "next") ) {
      donext (first, second, line);
   } else if (comeqv (cmd, "read") ) {
      doread (first, second, line);
   } else if (comeqv (cmd, "quit") ) {
      return (doquit (line) );
   } else if (comeqv (cmd, "set") ) {
      return (doset (line) );
   } else if (comeqv (cmd, "shell") ) {
      doshell (line, 0);
      return (2);
   } else if (comeqv (cmd, "write") ) {
      dowrite (first, second, line);
   } else if (comeqv (cmd, "window") ) {
      dowindow (line);
   } else if (comeqv (cmd, "xit") ) {
      if (dowrite (first, second, line) > 0)
         return (0);
   } else
      beep ();
   return (1);
}

donext (first, second, line)

int first, second;
char line [];
{
   auto int lpt, ignmod;
   if ( (first != -1) || (second != -1) ) {
      beep ();
      return (-1);
   }
   lpt = 0;
   if (line [0] == '!') {
      ignmod = 0;
      ++lpt;
   } else {
      ignmod = 1;
   }
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   if (modflag && ignmod) {
      movtobot ();
      beep ();
      writes ("No write since last change (next! overrides)");
      refscr ();
      return (-1);
   }
   newfile (&line [lpt]);
   return (1);
}

doquit (line)

char line [];

{
   if ( (line [0] == '!') || !modflag) 
      return (0);
   movtobot ();
   beep ();
   writes ("No write since last change (quit! overrides)");
   refscr ();
   return (1);
}


doread (first, second, fname)

int first, second;
char *fname;

{
   char line [256];
   FILE *fp;
   int newl;
   if (first == -1)
      first = endl - 1;
   if ( (second != -1) || (first < 1) || (first >= endl) ||
        (fname [0] != ' ') ) {
      beep ();
      return (-1);
   }
   fp = fopen (&fname [1], "r");
   if (!fp) {
      sprintf (line, "Unable to open%s.\n", fname);
      movtobot ();
      cleareol ();
      writes (line);
      refscr ();
      return (-1);
   }
   gj = gk = 0;
   newl = first;
   line [0] = '\n';
   while (fgets2 (&line [1], 256, fp) ) {
      insnewlinea (line, newl);
      ++newl;
   }
   fclose (fp);
   sprintf (line, "%d lines read", newl - first);
   movtobot ();
   cleareol ();
   writes (line);
   refscr ();
   modflag = 1;
   return (0);
}
   

doset (line)

char line [];

{
   auto char opt [64];
   auto int lpt, n, k, no;
   lpt = 0;
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   lpt = parsecmd (line, lpt, opt);
   skipblanks (line, lpt);
   if ( (opt [0] == 'n') && (opt [1] == 'o') ) {
      k = 1;
      while (opt [++k])
         opt [k - 2] = opt [k];
      opt [k - 2] = '\0';
      no = 1;
   } else {
      no = 0;
   }
   if (comeqv (opt, "all") ) {
      printsets ();
      n = 2;
   } else if (comeqv (opt, "autoindent") || comeqv (opt, "ai") ) {
      n = setai (&line [lpt], no);
   } else if (comeqv (opt, "ignorecase") || comeqv (opt, "ic") ) {
      n = setic (&line [lpt], no);
   } else if (comeqv (opt, "magic") ) {
      n = setmagic (&line [lpt], no);
   } else if (comeqv (opt, "shiftwidth") || comeqv (opt, "sw") ) {
      n = setsw (&line [lpt]);
   } else if (comeqv (opt, "tabstop") || comeqv (opt, "ts") ) {
      n = settabs (&line [lpt]);
   } else if (comeqv (opt, "wrapscan") || comeqv (opt, "ws") ) {
      n = setws (&line [lpt], no);
   } else {
      beep ();
      n = 1;
   }
   return (n);
}
   

doshell (line, flag)

char line [];
int flag;

{
   auto int j, k;
   echo ();
   endwin ();
   if (flag)
      j = forklp ("\\command", "command", "/C", &line [1], NULL);
   else
      j = forklp ("\\command", "command", NULL);
   k = wait ();
   if (j != 0)
      beep ();
}


dostat ()

{
   auto char line [128], tmps [128];
   auto int n;
   movtobot ();
   cleareol ();
   /*
   n = textwidth (texts [curl], curc, 0);
   if (n < 1)
      n = 1;
   */
   for (n = 0; n < MAXWINS; ++n) {
      if (wins [n] == curwin)
         break;
   }
   if (curfname [0] != '\0') 
      sprintf (line, "\"%s\" ", curfname);
   else
      strcpy (line, "No file ");
   if (modflag)
      strcat (line, "[Modified] ");
   if (endl == 1)
      sprintf (tmps, "line 0 of 0 --0%--  <%d>", n);
   else
      sprintf (tmps, "line %d of %d --%d--  <%d>", curl, endl - 1,
                            ( (100 * curl) / (endl - 1) ), n );
   strcat (line, tmps);
   writes (line);
   refscr ();
}

    
dowrite (first, second, line)
   
int first;
int second;
char line [];

{
   auto char tmpfname [64], bckfname [64], tmps [64];
   auto int j, k, n, lines, chars;
   FILE *fp;
   if ( (first == -1) && (second == -1) ) {
      first = 1;
      second = endl - 1;
   } else if (first == -1) {
      first = second;
   } else if (second == -1) {
      second = first;
   }
   if ( (first >= endl) || (second >= endl) || (first < 1) ||
        (second < 1) ) {
      beep ();
      return (-1);
   }
   if (line [0] == ' ') {
      strcpy (curfname, &line [1]);
   }
   n = strlen (curfname) - 1;
   if (n < 0) {
      movtobot ();
      beep ();
      cleareol ();
      writes ("No current filename");
      refscr ();
      return (-1);
   }
   while ( (curfname [n] != '.') && (curfname [n] != '\\') &&
               (n > 0) )
      --n;
   if (curfname [n] == '.') {
      for (k = 0; k < n; ++k)
         bckfname [k] = curfname [k];
      bckfname [k] = '\0';
   } else {
      strcpy (bckfname, curfname);
   }
   strcpy (tmpfname, bckfname);
   strcat (tmpfname, ".$$V");
   strcat (bckfname, ".BCK");
   unlink (tmpfname);
      
   fp = fopen (tmpfname, "w");
   if (!fp) {
      movtobot ();
      beep ();
      cleareol ();
      writes ("Unable to open ");
      writes (curfname);
      refscr ();
      return (-1);
   }
   for (j = first; j <= second ; ++j)  {
      k = fputs (&texts [j] [1], fp);
      if (k < 0)
         break;
   }
   fclose (fp);
   if (k < 0) {
      movtobot ();
      beep ();
      cleareol ();
      writes ("Unable to write file");
      refscr ();
      return (-1);
   }
   unlink (bckfname);
   rename (curfname, bckfname);
   rename (tmpfname, curfname);
   modflag = 0;
   docount (&lines, &chars);
   sprintf (tmps, "\"%s\" %d lines, %d characters", curfname, lines, chars);
   movtobot ();
   cleareol ();
   writes (tmps);
   refscr ();
   return (1);
}
  

fgets2 (s, len, fp)

char *s;
int len;
FILE *fp;

{
   static char buf [4096], *p;
   p = s;
   while (1) {
      if (gj >= gk) {
         if ( (gk = fread (buf, sizeof (char), 4096, fp) ) <= 0) {
            *s = '\0';
            return ( (int) (s - p) );
         }
	 gj = 0;
      }
      while ( (buf [gj] != '\n') && (gj < gk) ) 
         *s++ = buf [gj++];
      if (gj < gk) {
         *s++ = '\n';
	 ++gj;
         *s = '\0';
         break;
      }
   }
   return ( (int) (s - p) );
}
   

newfile (fname)

char fname [];

{
   auto char line [512];
   auto int j, n;
   FILE *fp;
   /* Free old buffers */
   for (j = 0; j < endl; ++j) {
      if (free (texts [j]) )
         nofree (72);
   }
   if ( !(texts[0] = malloc (7) ) )
      nomem (1);
   strcpy (texts [0], "\n\n");
   curl = curc = bscrl = endl = 1;
   dbuf = malloc (1);
   strcpy (dbuf, "");
   if (strcmp (fname, "") )
      fp = fopen (fname, "r");
   if (!fp || !strcmp (fname, "") ) {
      if ( !(texts[1] = malloc (7) ) )
         nomem (2);
      strcpy (texts [1], "\n\n");
      movtobot ();
      writes ("[New File] ");
      writes (fname);
      refscr ();
   } else {
      n = 1;
      while (fgets2 (line, 256, fp) ) {
         if ( !(texts [n] = malloc (strlen (line) + 7) ) )
	    nomem (3);
         texts [n] [0] = '\n';
         strcpy (&texts [n] [1], line);
	 ++n;
      }
      if ( !(texts [n] = malloc (7) ) )
	 nomem (4); 
      strcpy (texts [0], "\n\n");
      endl = n - 1;  
      fclose (fp);
   }
   curl = bscrl = 1;
   curc = 1;
   for (j = 0; j < 128; ++j)
      marks [j] = 0;
   strcpy (curfname, fname);
   modflag = 0;
}



parse1addr (line, lpt, addr)

char line [];
int lpt, *addr;

{
   auto int n;
   n = 0;
   if ( ('0' <= line [lpt]) && (line [lpt] <= '9') ) {
      while ( ('0' <= line [lpt]) && (line [lpt] <= '9') )
         n = 10 * n + line [lpt++] - '0';
      *addr = n;
   } else if (line [lpt] == '.') {
      *addr = curl;
      ++lpt;
   } else if (line [lpt] == '$') {
      *addr = endl - 1;
      ++lpt;
   }
   return (lpt);
}
   

parseaddrs (line, lpt, first, second)

char line [];
int lpt, *first, *second;

{
   *first = *second = -1;
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   lpt = parse1addr (line, lpt, first);
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   if (line [lpt] == ',') {
      ++lpt;
      while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
         ++lpt;
      lpt = parse1addr (line, lpt, second);
   }
   return (lpt);
}


parsecmd (line, lpt, cmd)

char line [], cmd [];
int lpt;

{
   auto int k;
   k = 0;
   while ( (line [lpt] == ' ') || (line [lpt] == '\t') )
      ++lpt;
   while ( ('a' <= line [lpt]) && (line [lpt] <= 'z') )
      cmd [k++] = line [lpt++];
   cmd [k] = '\0';
   return (lpt);
}

 
int parseval (line)

char line [];

{
   auto int lpt, n;
   lpt = 0;
   skipblanks (line, lpt);
   if (line [lpt++] != '=')
      return (-1);
   skipblanks (line, lpt);
   if ( (line [lpt] < '0') || ('9' < line [lpt]) )
      return (-1);
   n = 0;
   while (isdigit (line [lpt]) )
      n = 10 * n + line [lpt++] - '0';
   skipblanks (line, lpt);
   if (line [lpt] == '\0')
      return (n);
   return (-1);
}
   

printsets ()

{
   auto char tmps [80];
   if (autoindent)
      strcpy (tmps, "\nautoindent\n");
   else
      strcpy (tmps, "\nnoautoindent\n");
   writes (tmps);
   if (ignorecase)
      strcpy (tmps, "ignorecase\n");
   else
      strcpy (tmps, "noignorecase\n");
   writes (tmps);
   if (magic)
      strcpy (tmps, "magic\n");
   else
      strcpy (tmps, "nomagic\n");
   writes (tmps);
   sprintf (tmps, "shiftwidth = %d\n", shiftwidth);
   writes (tmps);
   sprintf (tmps, "tabs = %d\n", tabstop);
   writes (tmps);
   if (wrapscan)
      strcpy (tmps, "wrapscan\n");
   else
      strcpy (tmps, "nowrapscan\n");
   writes (tmps);
   refscr ();
   return (2);
}


setai (line, no)

char line [];
int no;

{
   auto char tmps [32];
   if (no) {
      autoindent = 0;
      return (1);
   }
   if (line [0] == '?') {
      if (autoindent)
         strcpy (tmps, "\nautoindent\n");
      else
         strcpy (tmps, "\nnoautoindent\n");
      writes (tmps);
      refscr ();
      return (2);
   }
   autoindent = 1;
   return (1);
}


setic (line, no)

char line [];
int no;

{
   auto char tmps [32];
   if (no) {
      ignorecase = 0;
      return (1);
   }
   if (line [0] == '?') {
      if (ignorecase)
         strcpy (tmps, "\nignorecase\n");
      else
         strcpy (tmps, "\nnoignorecase\n");
      writes (tmps);
      refscr ();
      return (2);
   }
   ignorecase = 1;
   return (1);
}


setmagic (line, no)

char line [];
int no;

{
   auto char tmps [32];
   if (no) {
      magic = 0;
      return (1);
   }
   if (line [0] == '?') {
      if (magic)
         strcpy (tmps, "\nmagic\n");
      else
         strcpy (tmps, "\nnomagic\n");
      writes (tmps);
      refscr ();
      return (2);
   }
   magic = 1;
   return (1);
}


setsw (line)

char line [];

{
   auto char tmps [64];
   auto int n;
   if (line [0] == '?') {
      sprintf (tmps, "\nshiftwidth = %d\n", shiftwidth);
      writes (tmps);
      refscr ();
      return (2);
   }
   n = parseval (line);
   if (n >= 0)
      shiftwidth = n;
   else
      beep ();
   return (1);
}
         

settabs (line)

char line [];

{
   auto char tmps [64];
   auto int n;
   if (line [0] == '?') {
      sprintf (tmps, "\ntabstop = %d\n", tabstop);
      writes (tmps);
      refscr ();
      return (2);
   }
   n = parseval (line);
   if (n >= 0)
      tabstop = n;
   else
      beep ();
   return (1);
}
   
setws (line, no)

char line [];
int no;

{
   auto char tmps [32];
   if (no) {
      wrapscan = 0;
      return (1);
   }
   if (line [0] == '?') {
      if (wrapscan)
         strcpy (tmps, "\nwrapscan\n");
      else
         strcpy (tmps, "\nnowrapscan\n");
      writes (tmps);
      refscr ();
      return (2);
   }
   wrapscan = 1;
   return (1);
}

