/*
**  vsh.c - a shell (command interpreter) for VAX/VMS
**
**  written by C.Bongiovanni
*/

#include stdio
#define FIRST 1
#define LAST 2
#define ALL 3
#define NORM 0
#define SEQ 1
#define PIPE 2
#define WAIT 0
#define NOWAIT 1
#define SEQSYM '\\'
#define PIPESYM '|'
#define digit(x) (x>= '0' && x<='9')
#define letter(x) (x>='a' && x<='z')
#define SYSINPUT "SYS$COMMAND"
#define SYSOUTPUT "SYS$COMMAND"

char cmdline[132];
char newhent[132];
char inline[80];
char lhsb[30];
char trueline[132];
char hentsym[9] = "eventXXX";
char hentval[132];
char esym[4] = "cnt";
char eval[5] = "    ";
char hsym[5] = "hsym";
char hval[5];
long dschev[2];
long dsches[2] = {8,hentsym};
long dsces[2] = {3,esym};
long dscev[2] = {4,eval};
long ret_len, tbl_ind;
long dschs[2] = {4,hsym};
long dschv[2] = {4,hval};
long dsci[2];
long dscauxi[2];
long waitopt;
short ttchan;
long oldmask;
int eventno;
int histlen;
int hadhist;
int justprt;
char imbx[20];
char ombx[20];

main ()
{
   char *getl(), *substitute(), *parseword();
   char *line;
   initshell();
   while ((line=getl())==0)
/*
      fprintf (stderr," bad line received!\n");
*/
      ;
   setparm (line);
   if (!justprt)
      analyze (line,NORM,SYSINPUT,SYSOUTPUT);
}

inhibit ()
{
   int i;
   int func =0x0123;
   int ctrlc;
   int ast ();
   char s[80];
   ctrlc = 0x02000000;
   i = lib$disable_ctrl (&ctrlc,&oldmask);
   printf (" disable = %x\n",i);
   dschev[0] = strlen ("SYS$COMMAND");
   dschev[1] = "SYS$COMMAND";
   i = sys$assign (dschev,&ttchan,0,0);
   printf (" assign = %x\n",i);
   i = sys$qiow (0,ttchan,func,0,0,0,0,0,0,0,0,0);
   printf (" qiow = %x\n",i);
   i = sys$qiow (0,ttchan,func,0,0,0,&ast,0,0,0,0,0);
   printf (" qiow = %x\n",i);
   func = 0x0a3;
   i = sys$qiow (0,ttchan,func,0,0,0,0,0,0,0,0,0);
   printf (" qiow = %x\n",i);
   i = sys$qiow (0,ttchan,func,0,0,0,&ast,0,0,0,0,0);
   printf (" qiow = %x\n",i);
}

ast ()
{
   int i;
   printf (" ast in progress\n");
   i = lib$enable_ctrl (&oldmask);
   exit ();
}

initshell()
{
/*
   close (0);
   open ("sys$command",0);
   inhibit ();
*/
   if (lib$get_symbol (dsces,dscev,&ret_len,&tbl_ind) != 1)
      strcpy (eval,"1");
   else
      eval[ret_len] = '\0';
   eventno = atoi (eval);
   if (lib$get_symbol (dschs,dschv,&ret_len,&tbl_ind) != 1)
      strcpy (hval,"-1");
   else
      hval[ret_len] = '\0';
   histlen = atoi (hval);
}

lineok (s)
char *s;
{
   while (*s != '\0')
      if (*s++ != ' ')
         return (TRUE);
   return (FALSE);
}


char *getl()
{
   char *getexcl (), *substitute(), *parseword();
   justprt = hadhist = FALSE;
   printf ("\n%d> ",eventno);
   if (strchr ((gets (inline) ? inline : ""),'!'))
      return (getexcl (inline));
   else if (inline[0] == '^')
      return (substitute (inline));
   else
      return ( lineok (inline) ? inline : 0);
}

setparm (s)
char *s;
{
   if (hadhist)
      printf ("%s\n",s);
   /* setta nome logico `cnt' */
   sprintf (eval,"%d\0",eventno+1);
   dscev[0] = strlen (eval);
   lib$set_symbol (dsces,dscev);
   /* setta nome logico `eventXXX' (XXX=eventno) */
   sprintf (hentsym,"event%d\0",eventno);
   dsches[0] = strlen (hentsym);
   dschev[0] = strlen (s);
   dschev[1] = s;
   lib$set_symbol (dsches,dschev);
   /* eventualmente cancella il nome logico spirato (vedi history) */
   if (histlen >= 0) {
      sprintf (hentsym,"event%d\0",eventno-histlen);
      dsches[0] = strlen (hentsym);
      lib$delete_symbol (dsches);
   }
}

char *substitute (s)
char *s;
{
   char *gethent();
/*
   fprintf (stderr," dovrei sostituire in %s\n",s);
*/
   hadhist = TRUE;
   return (gethent("-1") && dosub(hentval,s,FIRST,newhent) ? newhent : 0);
}

findev (s)
char *s;
{
   int i;
   int firsthent;
   firsthent = (histlen == -1) ? 1 : eventno - histlen + 1;
   for (i = eventno ; i >= firsthent ; i--) {
      sprintf (hentsym,"event%d\0",i);
      dsches[0] = strlen (hentsym);
      dschev[0] = 131;
      dschev[1] = hentval;
      if (lib$get_symbol (dsches,dschev,&ret_len,&tbl_ind) == 1) {
         hentval[ret_len] = '\0';
         if (strncmp(hentval,s,strlen(s)) == 0)
            return (TRUE);
      }
   }
   return (FALSE);
}

any (c,s)
char c;
char *s;
{
   for ( ; *s ; s++)
      if (c == *s)
         return (TRUE);
   return (FALSE);
}


char * gethent (sc)
char *sc;
{
   int back = 0;
   int event;
   char *np;
   char c;
   c = *sc++;
   switch (c) {

   case '!': sc++;
   case '^':
   case '$':
   case '*':
      event = eventno-1;
      break;

   case '-':
      back = 1;
      c = *sc++;
      if (!digit(c)) {
         fprintf (stderr,"!-%c : invalid syntax\n",c);
         return (0);
      }

   case '0':
   case '1':
   case '2':
   case '3':
   case '4':
   case '5':
   case '6':
   case '7':
   case '8':
   case '9':
      event = 0;
      while (digit(c)) {
         event = event * 10 + c - '0';
         c = *sc++;
      }
      if (back)
         event = eventno - event;
      break;

   default:
      np = lhsb;
      while ((!any(c,"!: \t\n")) && c != '\0') {
         if (np < &lhsb[sizeof(lhsb) - 2])
            *np++ = c;
         c = *sc++;
      }
      if (np == lhsb) {
         fprintf (stderr,"!%c : invalid syntax\n",c);
         return (0);
      }
      *np++ = '\0';
/*
      fprintf (stderr," trying to find hentval beginning with %s\n",lhsb);
*/
      if (!findev(lhsb)) {
         fprintf (stderr,"!%s : event not found\n",lhsb);
         return (0);
      } else
         return (--sc);

   } /* end of switch */
/*
   fprintf (stderr," trying to find event %d, line =%s\n",event,sc-1);
*/
   sprintf (hentsym,"event%d\0",event);
   dsches[0] = strlen (hentsym);
   dschev[0] = 131;
   dschev[1] = hentval;
   if (lib$get_symbol (dsches,dschev,&ret_len,&tbl_ind) == 1) {
      hentval[ret_len] = '\0';
      return (--sc);
   } else {
      fprintf (stderr,"!%d : event not found\n",event);
      return (0);
   }
}

char newword[30];


char *getword (s,n)
char *s;
{
   char *parseword ();
   int i;
   strcpy (newword,"");
   for (i=0 ; i<=n ; i++)
      s = parseword (s,newword);
   return (newword);
}

char *getfirstw (s)
char *s;
{
   char *parseword ();
   parseword (s,newword);
   return (newword);
}

char *getnofirst (s)
char *s;
{
   char *parseword ();
   strcpy (newword,parseword(s,newword));
   return (newword);
}

char *getlastw (s)
char *s;
{
   char *parseword ();
   char *first;
   while (*s != '\0')
      s = parseword (s,newword);
   return (newword);
}

char *findpat (s,pat)
char *s, *pat;
{
   for ( ; *s ; s++)
      if (strncmp(s,pat,strlen(pat)) == 0)
         return (s);
   return (0);
}

subword (s,old,new,flag,ns)
char *s, *old, *new, *ns;
int flag;
{
   char *s1, *s2;
   if ((s1=findpat(s,old)) == 0) {
      fprintf (stderr,"bad substitution\n");
      return (FALSE);
   }
   while (s<s1)
      *ns++ = *s++;
   if (flag != FIRST) {
      while (s1=findpat(s1,old)) {
         while (s<s1)
            *ns++ = *s++;
         if (flag == ALL) {
            s += strlen (old);
            s2 = new;
            while (*s2)
               *ns++ = *s2++;
            s1 += strlen (old);
         } else
            s1++;
      }
   }
   if (flag != ALL) {
      s += strlen (old);
      s1 = new;
      while (*s1)
         *ns++ = *s1++;
   }
   while (*s)
      *ns++ = *s++;
   *ns = '\0';
   return (TRUE);
}

dosub (s,cmd,flag,ns)
char *s, *cmd, *ns;
{
   char olds[10];
   char news[10];
   char *np, *op;
   char delim;
   delim = *cmd++;
   op = olds;
   while (*cmd != delim && *cmd)
      *op++ = *cmd++;
   if (*cmd == '\0') {
      fprintf (stderr,"bad substitution\n");
      return (FALSE);
   }
   *op = '\0';
   cmd++;
   np = news;
   while (*cmd != delim && *cmd)
      *np++ = *cmd++;
   *np = '\0';
/*
   fprintf (stderr," subst %s with %s in %s\n",olds,news,s);
*/
   return (subword(s,olds,news,flag,ns));
}

char *getsub (s)
char *s;
{
   char *parseword ();
/*
   fprintf (stderr," devo sostituire in %s utilizzando %s\n",hentval,s);
*/
   switch (*s++) {

   case 's':
      return( dosub(hentval,s,FIRST,newhent) ? newhent : 0);

   case 'l':
      return( dosub(hentval,s,LAST,newhent) ? newhent : 0);

   case 'g':
      return( dosub(hentval,s,ALL,newhent) ? newhent : 0);

   case 'p':
      justprt = TRUE;
      return (hentval);

   default:
      return (0);

   }
}

char *getexcl (line)
char *line;
{
   char *separe ();
   char c;
   char *first;
   strcpy (trueline,"");
   hadhist = TRUE;
   while (strchr (line,'!')) {
      first = line;
      line = separe (line,'!');
      strcpy (trueline,strcat(trueline,first));
/*
      fprintf (stderr," trueline=%s,line=%s<\n",trueline,line);
*/
      if ((line=gethent(line)) == 0)
         return (0);
/*
      fprintf (stderr," hentval = %s\ (len=%d)\n",hentval,strlen(hentval));
      fprintf (stderr," line = %s\n",line);
*/
      if (any(c=(*line++),":^$*0123456789")) {
         if (c == ':') {
            if (letter(*line)) {
               if ((line=getsub(line))) {
                  strcpy (trueline,strcat(trueline,newword));
/*
                  fprintf (stderr," trueline=%s,line=%s<\n",trueline,line);
*/
                  continue;
               } else {
                  fprintf (stderr,"bad substitution\n");
                  return (0);
               }
            } else
               c = *line++;
         }
         switch (c) {

         case '$':
            strcpy (trueline,strcat(trueline,getlastw(hentval)));
            break;

         case '*':
            strcpy (trueline,strcat(trueline,getnofirst(hentval)));
            break;

         case '^':
            strcpy (trueline,strcat(trueline,getfirstw(hentval)));
            break;

         case '0':
         case '1':
         case '2':
         case '3':
         case '4':
         case '5':
         case '6':
         case '7':
         case '8':
         case '9':
            strcpy (trueline,strcat(trueline,getword(hentval,c-'0')));
            break;

         default:
            break;
         }
      } else {
         line--;
         strcpy (trueline,strcat(trueline,hentval));
      }
   }
   strcpy (trueline,strcat(trueline,line));
/*
   fprintf (stderr," trueline=%s,line=%s<\n",trueline,line);
*/
   return (trueline);
}

char *flushblanks (s)
char *s;
{
   while (*s == ' ')
      s++;
   return (s);
}


analyze (string,action,ins,outs)
char *string, *ins, *outs;
{
   char *parseword(), *creatembx(), *separe();
   int i;
   char *first;
   char fname[80];
/*
   fprintf (stderr," entering analyze\n");
   fprintf (stderr," string=%s, action=%d\n",string,action);
   fprintf (stderr," input = %s\n",ins);
   fprintf (stderr," output = %s\n",outs);
*/
   if (strchr(string,SEQSYM)!=0) {
      while (strchr(string,SEQSYM)!=0) {
         first = string;
         string = separe (string,SEQSYM);
         analyze (first,SEQ,ins,outs);
      }
      analyze (string,SEQ,ins,outs);
   } else if (strchr(string,PIPESYM)!=0) {
      strcpy (imbx,SYSINPUT);
      while (strchr(string,PIPESYM)!=0) {
         first = string;
         string = separe (string,PIPESYM);
         strcpy (ombx,creatembx());
         analyze (first,PIPE,imbx,ombx);
         strcpy (imbx,ombx);
      }
      analyze (string,SEQ,imbx,SYSOUTPUT);
   } else if (strchr(string,'<')!=0) {
      first = string;
      string = separe (string,'<');
      string = parseword (string,fname);
      analyze (strcat(first,string),action,fname,outs);
   } else if (strchr(string,'>')!=0) {
      first = string;
      string = separe (string,'>');
      string = parseword (string,fname);
      analyze (strcat(first,string),action,ins,fname);
   } else {
      string = flushblanks (string);
      switch (action) {

      case NORM:
/*
         fprintf (stderr,"EXEC %s (i=%s,o=%s)\n",string,ins,outs);
*/
         dsci[0] = strlen (ins);
         dsci[1] = ins;
         dscauxi[0] = strlen ("SYS$INPUT");
         dscauxi[1] = "SYS$INPUT";
/*
         fprintf (stderr,"assign %s to %s\n",dsci[1],dscauxi[1]);
         fprintf (stderr,"insym = %x\n",lib$set_logical (dscauxi,dsci));
*/
         lib$set_logical (dscauxi,dsci);
         dsci[0] = strlen (outs);
         dsci[1] = outs;
         dscauxi[0] = strlen ("SYS$OUTPUT");
         dscauxi[1] = "SYS$OUTPUT";
/*
         fprintf (stderr,"assign %s to %s\n",dsci[1],dscauxi[1]);
         fprintf (stderr,"outsymb = %x\n",lib$set_logical (dscauxi,dsci));
*/
         lib$set_logical (dscauxi,dsci);
         dschev[0] = strlen (string);
         dschev[1] = string;
         lib$do_command (dschev);
         break;

      case SEQ:
         sprintf (cmdline,"pp %s \"-I/O\" %s %s\0",string,ins,outs);
/*
         fprintf (stderr,"SEQ %s (i %s o %s)\n",string,ins,outs);
         fprintf (stderr," executing %s\n",cmdline);
*/
         dschev[0] = strlen (cmdline);
         dschev[1] = cmdline;
         waitopt = WAIT;
         i = lib$spawn (dschev,0,0,&waitopt);
/*
         fprintf (stderr,"\n\n spawn returned %x\n",i);
*/
         break;

      case PIPE:
         sprintf (cmdline,"pp %s \"-I/O\" %s %s\0",string,ins,outs);
/*
         fprintf (stderr,"PIPE %s (i %s o %s)\n",string,ins,outs);
         fprintf (stderr," executing %s\n",cmdline);
*/
         dschev[0] = strlen (cmdline);
         dschev[1] = cmdline;
         waitopt = NOWAIT;
         i = lib$spawn (dschev,0,0,&waitopt);
/*
         fprintf (stderr,"\n\n spawn returned %x\n",i);
*/
         break;


      default: ;

      }
   }
} /* end of activate */

char *parseword (s,f)
char *s, *f;
{
   while (*s==' ') s++;
   while (*s!=' ' && *s!='\0') *f++ = *s++;
   *f = '\0';
   if (*s==' ') *s++ = '\0';
   return (s);
}

char *separe (s1,c)
char *s1, c;
{
   while (*s1 != c) s1++;
   *s1++ = '\0';
   return (s1);
}

int mbxnum = 0;

char *creatembx()
{
   int i;
   char mbxname[10];
   long dscm[2];
   short chan;
   sprintf (mbxname,"MBA%d\0",mbxnum++);
   dscm[0] = strlen (mbxname);
   dscm[1] = mbxname;
   i = sys$crembx (0,&chan,0,0,0,0,dscm);
/*
   fprintf (stderr," creatembx returned %x, mbxname=%s\n",i,dscm[1]);
*/
   return (mbxname);
}
