#include <exec/ports.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <clib/edlib.h>
#include "roguestar.h"

extern void *malloc();
extern void *AllocMem();
extern struct Task *FindTask();
extern struct MsgPort *CreatePort();
extern void *GetMsg();
extern char *find_var();
extern char **get_environ();
extern int set_var();
extern char *GetEnv();
extern char *strchr();

#define PNAMESIZ 30

char *progname;
extern char **environ;

struct var {
  struct var *vr_next;
  char *name;
  char *value;
  BYTE exported;
};

struct var *vars=NULL;

main(argc,argv)
int argc;
char *argv[];
{
  char *line;
  char *buf1;
  char **av;
  int  ac;
  int  wait;
  struct MsgPort *ReturnPort;
  struct Process *myproc;
  char *processname;

  progname=argv[0];

  line=(char *)malloc(1000);
  buf1=(char *)malloc(1000);
  av=(char **)malloc(100*sizeof(char *));
  processname=(char *)AllocMem(PNAMESIZ,MEMF_CLEAR|MEMF_PUBLIC);
  if(line==NULL || buf1==NULL || av==NULL || processname==NULL) exit(99);
  myproc=(struct Process *)FindTask(NULL);
  sprintf(processname,"%s%d",progname,myproc);
  ReturnPort=CreatePort(processname,NULL);

  printf("> ");
  while(gets(line)!=NULL) {
    ac=parse_line(line,buf1,av);
    if(strcmp(av[ac-1],"&")==0) {
      ac--;
      wait=0;
    }
    else wait=1;
    if(internal(av,ac,ReturnPort,wait)!=-1);
    else if(ex_run(av,ac,ReturnPort,wait)!=-1);
    printf("> ");
  }

  DeletePort(ReturnPort);
  FreeMem(processname,PNAMESIZ);
  free(av);
  free(line);
  free(buf1);
  exit(0);
}


int parse_line(line,buf,av)
char *line;
char *buf;
char **av;
{
  char c;
  int i;
  int ac,acc;
  char *p;

  ac=0;
  acc=0;
  i=0;
  av[ac]=buf;

  while(line[i]!='\0') {
    i=strspn(line+i," \t\n")+i;
    while(line[i]!=' ' && line[i]!='\t' && line[i]!='\n' && line[i]!='\0') {
      if(line[i]=='"') {
        i++;
        while(line[i]!='"' && line[i]!='\0') {
          if(line[i]=='$') {
            printf("Found var %s\n",line+i+1);
          }
          if(line[i]=='\\') {
            *buf++=line[++i];
          }
          else {
            *buf++=line[i];
          }
          i++;
        }
        if(line[i]=='\0') {
          printf("Unmatched \"\n");
          return 0;
        }
      }
      else if(line[i]=='$') {
        printf("Found var %s\n",line+i+1);
        i++;
        if(line[i]=='{') {
          while(line[i]!='}' && line[i]!='\0') {
            i++;
          }
        }
        else {
          int vs;

          vs=i;
          while(line[i]!='\0') {
            int j;
            char *special_set="() \t\n|[\"'";
            for(j=0; special_set[j]!='\0'; j++) {
              if(line[i]==special_set[j]) {
                break;
              }
            }
            i++;
          }
          if(i!=vs) {
            line[i]='\0';
            printf("looking for %s\n",&line[vs]);
            if((p=find_var(&line[vs]))==NULL) {
              fprintf(stderr,"Var %s not set\n",&line[vs]);
            }
            else {
              for(vs=0; p[vs]!='\0'; vs++) {
                *buf++=p[vs];
              }
            }
          }
        }
      }
      else {
        *buf++=line[i];
      }
      i++;
    }
    *buf++='\0';
    ac++;
    av[ac]=buf;
  }
  return(ac);
}

char **get_environ()
{
  static char env[1000];
  static char *envs[100];
  struct var *step;
  char *t;
  int num;

  t=env;
  num=0;
  if(vars) {
    for(step=vars; step!=NULL; step=step->vr_next) {
      if(step->exported==TRUE) {
        sprintf(t,"%s=%s",step->name,step->value);
        envs[num]=t;
        t+=strlen(t)+1;
        num++;
      }
    }
    envs[num]=NULL;
    return(envs);
  }
  else {
    return(NULL);
  }
}

char *find_var(var)
char *var;
{
  struct var *step;

  step=vars;
  while(step) {
    if(strcmp(step->name,var)==0) {
      return(step->value);
    }
    step=step->vr_next;
  }
  return(GetEnv(var));
}

int set_var(var,value,export)
char *var;
char *value;
int export;
{
  struct var *step;

  step=vars;
  while(step) {
    if(strcmp(step->name,var)==0) {
      free(step->value);
      if((step->value=malloc(strlen(value)+1))==NULL) {
        fprintf(stderr,"Can't malloc in set_var\n");
        return(1);
      }
      strcpy(step->value,value);
      step->exported=export;
      return(0);
    }
    step=step->vr_next;
  }
  if((step=malloc(sizeof(struct var)))==NULL) {
   bad:
    fprintf(stderr,"Can't malloc a new var\n");
    return(1);
  }
  step->vr_next=vars;
  vars=step;
  if((step->name=malloc(strlen(var)+1))==NULL ||
      (step->value=malloc(strlen(value)+1))==NULL) {
    goto bad;
  }
  strcpy(step->name,var);
  strcpy(step->value,value);
  step->exported=export;
  return(0);
}

int ex_run(av,ac,port,wait)
char **av;
int ac;
struct MsgPort *port;
{
  long mask;
  long rmask;
  void *mychild;
  void *achild;
  int code,mycode;
  long process;

  rmask=1L << port->mp_SigBit;

  if((mychild=RogueLaunch(port,av[0],av,ac,get_environ(),0,NULL,8000,
                         Input(),Output(),Output()))==NULL) {
    printf("Could not run %s IoErr %d\n",av[0],IoErr());
    return(-1);
  }
  while(wait) {
    mask=Wait(rmask|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_C);
    if(mask&rmask) {
      while((achild=GetMsg(port))!=NULL) {
        if(achild!=mychild) {
          process=(long)achild;
          code=RogueFreeStartup(achild);
          if(code==0) {
            fprintf(stderr,"Process [%d] done\n",process);
          }
          else {
            fprintf(stderr,"Process [%d] exited with %d\n",process,code);
          }
        }
        else {
          mycode=RogueFreeStartup(achild);
          return(mycode);
        }
      }
    }
    else if(mask&SIGBREAKF_CTRL_D) {
      fprintf(stderr,"Putting process [%d] in background\n",process);
      wait=0;
    }
    else if(mask&SIGBREAKF_CTRL_C) {
      fprintf(stderr,"Process [%d] received a ^C\n",process);
    }
  }
  return(0);
}

int internal(av,ac,port,wait)
char *av[];
int ac;
struct MsgPort *port;
{
  if(strcmp(av[0],"cd")==0 || strcmp(av[0],"chdir")==0) {
    if(ac!=2) {
     badnum:
      fprintf(stderr,"Bad number of arguments\n");
    }
    else {
      return(chdir(av[1]));
    }
  }
  else if(strcmp(av[0],"setenv")==0) {
    if(ac==3) {
      return(set_var(av[1],av[2],TRUE));
    }
    else goto badnum;
  }
  else if(strcmp(av[0],"set")==0) {
    if(ac==3) {
      return(set_var(av[1],av[2],FALSE));
    }
    else if(ac==2) {
      char *n;
      char *v;
      v=strchr(av[1],'=')+1;
      n=strtok(av[1],"=");
      return(set_var(n,v,FALSE));
    }
    else goto badnum;
  }
  else {
    return(-1);
  }
}









