%token ENVIRONMENT
%token MENU 
%token STRING
%token COMMAND
%token OBRACE
%token CBRACE
%token COMMA 
%token OPAREN
%token CPAREN
%token ID_NAME
%token INTEGER
%token ERROR

%{
#include <stdio.h>
#include "client.h"

extern char *get_yytext() ;
extern int yyleng ;
%}

%start commands

%union {
  int ival ;
  char * sval ;
  NMENUITEM *mival ;
  NMENU *mval ;
}

%type <ival> integer name ident
%type <sval> string
%type <mival> menulist menuitem command commandentry

%%

commands :
    | commands menudef
    | error

menudef :  MENU string COMMA string COMMA string COMMA string OBRACE menulist CBRACE
{
    NMENU *mkmenu(), *mp ;

    if(mp = mkmenu($10)) {
        mp->menu_id = $2 ;
        mp->menu_title = $4 ;
        mp->menu_prompt = $6 ;
        mp->menu_default = $8 ;
        pushmenu(mp) ;
    }
}
| ENVIRONMENT OPAREN string CPAREN
{
    extern char *default_env ;
    default_env = $3 ;
    parse_default() ;
}

menulist : menuitem
{
    $$ = $1 ;
}
      | menulist menuitem
{
    if($1)
      $2->next = $1 ;
    $$ = $2 ;
}

menuitem : OPAREN string COMMA string COMMA string COMMA ident COMMA commandentry COMMA string CPAREN
{
    register NMENUITEM *mip ;

    if(mip = $10) {
        mip->name = $2 ;
        mip->enabled = $8 ;
        mip->default_action = $4 ;
        mip->error_action = $6 ;
        mip->help = $12 ;
    }
    $$ = mip ;
}

ident: integer
{ $$ = $1 ; }
| name
{ $$ = $1 ; }

command : COMMAND
{
    NMENUITEM *mkmenuitem() ;
    char buf[512] ;
    strncpy(buf,get_yytext(),yyleng) ;
    buf[yyleng] = '\0' ;

    $$ = mkmenuitem(buf+1) ;
}

commandentry: command
{ $$ = $1; }
   | command string
{
    NMENUITEM *mip = $1 ;

    if(mip)
      mip->action_arg = $2 ;
    $$ = mip ;
}
string : STRING
{
    char *mkstring() ;
    char *ExpandString() ;
    char buf[512] ;
    
    strncpy(buf,get_yytext(),yyleng) ;
    buf[yyleng-1] = '\0' ;
    $$ = mkstring(ExpandString(buf+1)) ;
}

integer : INTEGER
{
    int atoi() ;

    $$ = atoi(get_yytext()) ;
}

name : ID_NAME
{
    int convert_cmd_to_int() ;
    char buf[512] ;
    
    strncpy(buf,get_yytext(),yyleng) ;
    buf[yyleng] = '\0' ;
    $$ = convert_cmd_to_int(buf) ;
}
%%

char *mkstring(s)
register char *s ;
{
    register char *p ;

    p = (char *) malloc(strlen(s)+1) ;
    strcpy(p,s) ;
    return p ;
}

menuerror()
{
    do_echo("WARNING, invalid function in Menu definition\n") ;
    return 0 ;
}

NMENUITEM *
mkmenuitem(s)
char *s ;
{
    NMENUITEM *mip ;
    extern int line_num ;
    extern int (*findfunc())() ;
    if(!(mip = (NMENUITEM *) malloc(sizeof(NMENUITEM))))
      return NULL ;
    memset(mip,0,sizeof(NMENUITEM)) ;
    if(!(mip->action_func = findfunc(s))) {
        char buf[512] ;
        sprintf(buf,"WARNING, invalid function in menu file\nfunction = '%s' LINE %d\n",s,line_num) ;
        do_echo(buf) ;
        mip->action_func = menuerror ;
    }
    return mip ;
}

int
getmenuindex(t)
unsigned int t ;
{
    t = (t | 0x20) - 'a' ;
    return t % MAXMENUSZ ;
}

NMENU *
mkmenu(mip)
NMENUITEM *mip ;
{
    NMENU *mp ;
    NMENUITEM *tp ;

    if(!(mp = (NMENU *)malloc(sizeof(NMENU))))
      return NULL ;
    memset(mp,0,sizeof(NMENU)) ;
    mp->commlist = mip ;
    for(tp = mip;tp;tp = tp->next) {
        register int menuindex = GetMenuIndex(*(tp->name)) ;
        if(mp->menucommands[menuindex]) {
            char buf[512] ;
            extern int line_num ;
            sprintf(buf,
         "Warning Menu command %s attempting to use filled slot!\nLINE %d\n",
                    tp->name,line_num) ;
            do_echo(buf) ;
            continue ;
        }
        mp->menucommands[menuindex] = tp ;
    }
    return mp ;
}

NMENU *bigMenuList = NULL ;

pushmenu(mp)
NMENU *mp ;
{
    NMENUITEM *mip = NULL ;
    NMENUITEM *tmp, *next ;
    
    for(tmp=mp->commlist;tmp;tmp = next) {
        next = tmp->next ;
        tmp->next = mip ;
        mip = tmp ;
    }
    mp->commlist = mip ;
    mp->next = bigMenuList ;
    bigMenuList = mp ;
}

