/*********************************************************************/
/* file: parse.c - some utility-functions                            */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include "tintin.h"

#if IRIX
  #include <stdlib.h>
#endif
struct session *parse_tintin_command();
void do_speedwalk();
char *get_arg_with_spaces();

extern struct listnode *searchnode_list_begin();
extern struct session *all_command();
extern struct session *read_command();
extern struct session *session_command();
extern struct session *write_command();
extern struct session *writesession_command();
extern struct session *zap_command();
extern struct completenode *complete_head;
extern char *space_out();
extern char *get_arg_in_braces();
void write_com_arg_mud();
void prompt();

extern char k_input[240];
extern struct session *sessionlist, *activesession;
extern struct listnode *common_aliases, *common_actions, *common_subs;
extern struct listnode *common_myvars, *common_antisubs;
extern char vars[10][BUFFER_SIZE]; /* the %0, %1, %2,....%9 variables */
extern char tintin_char, verbatim_char;
extern int term_echoing, verbatim;
extern int speedwalk, is_split, display_row, display_col, input_row, input_col;
extern char system_com[80];
extern void action_command();
extern void unhighlight_command();
extern char *get_arg_stop_spaces();
extern char *cryptkey;
extern char *get_arg_all();
extern void tstphandler();

/**************************************************************************/
/* parse input, check for TINTIN commands and aliases and send to session */
/**************************************************************************/
struct session *parse_input(input, ses)
     char *input;
     struct session *ses;
{
  char command[BUFFER_SIZE], arg[BUFFER_SIZE], result[BUFFER_SIZE];
  char *input2;
  struct listnode *ln;

  if(!term_echoing && activesession==ses) {
    term_echoing=TRUE;
  }

  if(*input=='\0') {
    if(ses)
      write_line_mud("", ses);
    else
      write_com_arg_mud("", "", ses);
    return ses; 
  }
  if (is_abrev(input+1, "verbatim") && *input==tintin_char) {
    verbatim_command();
    return ses;
  }
  if (verbatim && ses) {
    write_line_mud(input,ses);
    return ses;
  }
  
  if (*input==verbatim_char) {
    input++;
    write_line_mud(input,ses);
    return ses;
  }
  substitute_myvars(input, result,ses);
  input2=result;
  while(*input2) {
    if(*input2==';')
      input2++;
    input2=get_arg_stop_spaces(input2, command);
    input2=get_arg_all(input2, arg);


    if(*command==tintin_char) 
      ses=parse_tintin_command(command+1, arg, ses);

    else if((ln=searchnode_list_begin((ses) ? ses->aliases : common_aliases, command, ALPHA))!=NULL) {
      int i;
      char *cpsource, *cpsource2, newcommand[BUFFER_SIZE], end;

      strcpy(vars[0], arg);

      for(i=1, cpsource=arg; i<10; i++) {
        /* Next lines CHANGED to allow argument grouping with aliases */
        while (*cpsource == ' ')
          cpsource++;
        end = (*cpsource == '{') ? '}' : ' ';
        cpsource = (*cpsource == '{') ? cpsource+1 : cpsource;
        for(cpsource2=cpsource; *cpsource2 && *cpsource2!=end; cpsource2++);
        strncpy(vars[i], cpsource, cpsource2-cpsource);
        *(vars[i]+(cpsource2-cpsource))='\0';
        cpsource=(*cpsource2) ? cpsource2+1 : cpsource2;
      }
      prepare_actionalias(ln->right, newcommand, ses); 
      if(!strcmp(ln->right, newcommand) && *arg) {
        strcat(newcommand, " "); 
        strcat(newcommand, arg);
      }

      ses=parse_input(newcommand, ses);
    }
    else if(speedwalk && !*arg && is_speedwalk_dirs(command))
      do_speedwalk(command, ses);
    else {
      get_arg_with_spaces(arg,arg);
      write_com_arg_mud(command, arg, ses);
    }
  }
  return(ses);
}

/**********************************************************************/
/* return TRUE if commands only consists of capital letters N,S,E ... */
/**********************************************************************/
int is_speedwalk_dirs(cp)
     char *cp;
{
  int flag;
  flag=FALSE;
  while(*cp) {
    if(*cp!='n' && *cp!='e' && *cp!='s' && *cp!='w' && *cp!='u' && *cp!='d' &&
    !isdigit(*cp))
      return FALSE;
    if(!isdigit(*cp))
      flag=TRUE;
    cp++;
  }
  return flag;
}

/**************************/
/* do the speedwalk thing */
/**************************/
void do_speedwalk(cp, ses)
     char *cp;
     struct session *ses;
{
  char sc[2];
  char *loc; 
  int multflag,loopcnt,i;
  strcpy(sc, "x");
  while(*cp) {
    loc=cp;
    multflag=FALSE;
    while(isdigit(*cp)) {
      cp++;
      multflag=TRUE;
    }
    if(multflag && *cp) {
      sscanf(loc,"%d%c",&loopcnt,sc);
      i=0;
      while(i++<loopcnt)
	write_com_arg_mud(sc, "", ses);
    }
    else if (*cp) {
      sc[0]=*cp;
      write_com_arg_mud(sc, "", ses);
    }
    cp++;
  }
}


/*************************************/
/* parse most of the tintin-commands */
/*************************************/
struct session *parse_tintin_command(command, arg, ses)
     char *command;
     char *arg;
     struct session *ses;
{
  struct session *sesptr;

  for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
    if(strcmp(sesptr->name, command)==0) {
      if(*arg){
        get_arg_with_spaces(arg, arg);
        parse_input(arg, sesptr);  /* was: #sessioname commands */
        return(ses);
      }
      else {
        char buf[BUFFER_SIZE];
        activesession=sesptr;
        sprintf(buf, "#SESSION '%s' ACTIVATED.", sesptr->name);
        tintin_puts(buf, sesptr);
        prompt(NULL);
        return(sesptr);
      }
    }
  
  if(isdigit(*command)) {
    int i=atoi(command);
    if(i>0) {
     get_arg_in_braces(arg, arg, 1);
     while(i-->0)
       ses=parse_input(arg, ses);
    }
    else {
      tintin_puts("#YEAH RIGHT! GO REPEAT THAT YOURSELF DUDE.", ses);
      prompt(NULL);
    }
    return(ses);
  }

  else if(is_abrev(command, "action"))
    action_command(arg, ses);
   
  else if(is_abrev(command, "alias"))
    alias_command(arg, ses);
   
  else if(is_abrev(command, "all"))
    ses=all_command(arg, ses);

  else if(is_abrev(command, "antisubstitute"))
    parse_antisub(arg,ses);
    
  else if(is_abrev(command, "bell"))
    bell_command(ses);

  else if(is_abrev(command, "boss")) 
    boss_command(ses);

  else if(is_abrev(command, "char"))
    char_command(arg, ses);

  else if(is_abrev(command, "cr"))
     cr_command(ses); 

  else if(is_abrev(command, "echo"))
    echo_command(ses);

  else if(is_abrev(command, "end")) 
    end_command(command, ses);

  else if(is_abrev(command, "help")) 
    help_command(arg);

  else if(is_abrev(command, "highlight"))
    parse_high(arg, ses);
    
  else if(is_abrev(command, "history")) 
    history_command(ses);

  else if(is_abrev(command, "if")) 
    if_command(arg, ses);

  else if(is_abrev(command, "ignore"))
    ignore_command(ses);
  
  else if(is_abrev(command, "info"))
    display_info(ses);
  
  else if(is_abrev(command, "killall"))
    kill_all(ses, CLEAN);

  else if(is_abrev(command, "log")) 
    log_command(arg, ses);

  else if(is_abrev(command, "loop"))
    loop_command(arg, ses);

  else if(is_abrev(command, "nop")); 

  else if(is_abrev(command, "map"))
    map_command(arg,ses);
  
  else if(is_abrev(command, "math")) 
    math_command(arg, ses);

  else if(is_abrev(command, "mark")) 
    mark_command(ses);

  else if(is_abrev(command, "message"))
    message_command(arg, ses);
    
  else if(is_abrev(command, "path")) 
    path_command(ses);
  
  else if(is_abrev(command, "pathdir")) 
    pathdir_command(arg, ses); 

  else if(is_abrev(command, "presub"))
    presub_command(ses);
  
  else if(is_abrev(command, "redraw"))
    redraw_command();

  else if(is_abrev(command, "retab"))
    read_complete();

  else if(is_abrev(command, "return"))
    return_command(ses);

  else if(is_abrev(command, "read"))
    ses=read_command(arg, ses);

  else if(is_abrev(command, "savepath"))
    savepath_command(arg, ses);

  else if(is_abrev(command, "session"))
    ses=session_command(arg, ses);

  else if(is_abrev(command, "showme"))
    showme_command(arg,ses);
    
  else if(is_abrev(command, "snoop"))
    snoop_command(arg, ses);

  else if(is_abrev(command, "speedwalk"))
    speedwalk_command(ses);

  else if(is_abrev(command, "split"))
    split_command(arg);

  /* CHANGED to allow suspending from within tintin. */
  /* I know, I know, this is a hack *yawn* */
  else if(is_abrev(command, "suspend"))
    tstphandler(SIGTSTP,0,NULL,NULL);
 
  else if(is_abrev(command, "tablist"))
    tablist(complete_head);

  else if(is_abrev(command, "tabadd"))
    tab_add(arg);

  else if(is_abrev(command, "tabdelete"))
    tab_delete(arg);

  else if(is_abrev(command, "textin"))
    read_file(arg, ses);  

  else if(is_abrev(command, "unsplit"))
    unsplit_command();  

  else if(is_abrev(command, "substitute"))
    parse_sub(arg, ses);

  else if(is_abrev(command, "gag")) {
    if (*arg!='{') {
      strcpy(command,arg);
      strcpy(arg,"{");
      strcat(arg,command);
      strcat(arg,"} ");
    }
    strcat(arg, " .");
    parse_sub(arg,ses);
  }
  
  else if(is_abrev(command, system_com))
    system_command(arg, ses);

  else if(is_abrev(command, "tick")) 
    tick_command(ses);

  else if(is_abrev(command, "tickoff")) 
    tickoff_command(ses);

  else if(is_abrev(command, "tickon")) 
    tickon_command(ses);

  else if(is_abrev(command, "tickset"))
    tickset_command(ses);

  else if(is_abrev(command, "ticksize")) 
    ticksize_command(arg, ses);

  else if(is_abrev(command, "togglesubs"))
    togglesubs_command(ses);

  else if(is_abrev(command, "unaction"))
    unaction_command(arg, ses);

  else if(is_abrev(command, "unalias"))
    unalias_command(arg, ses);

  else if(is_abrev(command, "unantisubstitute"))
    unantisubstitute_command(arg,ses);
    
  else if(is_abrev(command, "unhighlight"))
    unhighlight_command(arg,ses);
  
  else if(is_abrev(command, "unsubstitute"))
    unsubstitute_command(arg, ses);

  else if(is_abrev(command, "ungag"))
    unsubstitute_command(arg,ses);

  else if(is_abrev(command, "unpath")) 
    unpath_command(ses);

  else if(is_abrev(command, "variable"))
    var_command(arg,ses);

  else if(is_abrev(command, "version"))
    version_command();

  else if(is_abrev(command, "unvariable"))
    unvar_command(arg,ses);

  else if(is_abrev(command, "wizlist")) 
    wizlist_command(ses);

  else if(is_abrev(command, "write"))
    ses=write_command(arg, ses);

  else if(is_abrev(command, "writesession"))
    ses=writesession_command(arg, ses);

  else if(is_abrev(command, "zap"))
    ses=zap_command(ses);

  else {
    tintin_puts("#UNKNOWN TINTIN-COMMAND.", ses);
    prompt(NULL);
  }
  return(ses);
}


/**********************************************/
/* get all arguments - don't remove "s and \s */
/**********************************************/
char *get_arg_all(s, arg)
     char *s;
     char *arg;
{
  /* int inside=FALSE; */
  int nest=0;
  s=space_out(s);
  while(*s) {

    if(*s=='\\') {
      *arg++=*s++;
      if(*s)
	*arg++=*s++;
    }


    else if(*s==';' && nest<1) {
	break;
    }

    else if(*s==DEFAULT_OPEN) {
      nest++;
      *arg++=*s++;
    }

    else if(*s==DEFAULT_CLOSE) {
      nest--;
      *arg++=*s++;
    }

    else
      *arg++=*s++;
  }

  *arg='\0';
  return s;
}

/**************************************/
/* get all arguments - remove "s etc. */
/* Example:                           */
/* In: "this is it" way way hmmm;     */
/* Out: this is it way way hmmm       */ 
/**************************************/
char *get_arg_with_spaces(s, arg)
     char *s;
     char *arg;
{
  int nest=0;
  /* int inside=FALSE; */

  s=space_out(s);
  while(*s) {

    if(*s=='\\') {
      if(*++s)
	*arg++=*s++;
    }


    else if(*s==';' && nest==0) {
	break;
    }
    else if(*s==DEFAULT_OPEN) {
      nest++;
      *arg++=*s++;
    }
    else if(*s==DEFAULT_CLOSE) {
      *arg++=*s++;
      nest--;
    }
    else
      *arg++=*s++;
  }
*arg='\0'; 
return s;
}
/********************/
/* my own routine   */
/********************/
char *get_arg_in_braces(s, arg, flag)
     char *s;
     char *arg;
     int flag;
{
   int nest=0;
   char *ptr;
   s=space_out(s);
   ptr=s;
   if (*s!=DEFAULT_OPEN) {
     if (flag==0) 
       s=get_arg_stop_spaces(ptr,arg);
     else
       s=get_arg_with_spaces(ptr,arg);
     return s;
   }
   s++;
     while(*s!='\0' && !(*s==DEFAULT_CLOSE && nest==0)) {
       if(*s==DEFAULT_OPEN) {
         nest++;
       }
     
       else if(*s==DEFAULT_CLOSE) {
         nest--;
       } 
       *arg++=*s++;
     }
   if (!*s)
     tintin_puts2("#Unmatched braces error!", (struct session *)NULL);
   else
     s++;
   *arg='\0';
   return s;
   
}
/**********************************************/
/* get one arg, stop at spaces                */
/* remove quotes                              */
/**********************************************/
char *get_arg_stop_spaces(s, arg)
     char *s;
     char *arg;
{
  int inside=FALSE;
  s=space_out(s);
  
  while(*s) {
    if(*s=='\\') {
      if(*++s)
	*arg++=*s++;
    }
    else if(*s=='"') {
      s++;
      inside=!inside;
    }

    else if(*s==';') {
      if(inside)
	*arg++=*s++;
      else
	break;
    }

    else if(!inside && *s==' ')
      break;
    else
      *arg++=*s++;
  }

  *arg='\0';
  return s;
}

/*********************************************/
/* spaceout - advance ptr to next none-space */
/* return: ptr to the first none-space       */
/*********************************************/ 
char *space_out(s)
     char *s;
{
  while(isspace(*s))
    s++;
  return s;
}

/************************************/
/* send command+argument to the mud */
/************************************/
void write_com_arg_mud(command, argument, ses)
     char *command;
     char *argument;
     struct session *ses;
{
  char outtext[BUFFER_SIZE];
  int i;

  if(!ses) {
    char buf[100];
    sprintf(buf, "#NO SESSION ACTIVE. USE THE %cSESSION-COMMAND TO START ONE.", tintin_char);
    tintin_puts(buf, ses);
    prompt(NULL);
  }
  else {
    check_insert_path(command, ses);
    strncpy(outtext, command, BUFFER_SIZE);
    if(*argument) {
      strncat(outtext, " ", BUFFER_SIZE-strlen(command)-1); 
      strncat(outtext, argument, BUFFER_SIZE-strlen(command)-2);
    }
    write_line_mud(outtext, ses);
    outtext[i=strlen(outtext)]='\n';
    if(ses->logfile)
      fwrite(outtext, i+1, 1, ses->logfile);
  }
}


/***************************************************************/
/* show a prompt - mud prompt if we're connected/else just a > */
/***************************************************************/
void prompt(ses)
     struct session *ses;
{
  char strng[80];
  if(ses && !PSEUDO_PROMPT)
    write_line_mud("", ses);
  else if (!is_split)
    write(1,"> ", 3);
  else {
    sprintf(strng,"8> 7[%d;%df", input_row, input_col);
    write(1,strng, strlen(strng)+1);
    display_col+=2;
  } 
}