// $Id: parser.h,v 1.11 2013/03/22 17:37:17 lpoulsen Exp $
// Copyright (c) 2008 by Afar Communications Inc, Santa Barbara CA 93117 USA
//
// Data definitions for Afar's command parser
// Version for Windows PC programs
// Ported from embedded code tree May 2008
//
// $Log: parser.h,v $
// Revision 1.11  2013/03/22 17:37:17  lpoulsen
// Allow "econ -r name" to make one connection with the named radio
//     without ever entering the Econsole> command prompt.
//
// Revision 1.10  2011/06/30 22:21:54  lpoulsen
// Add parser_empty() call for use in "set" command.
//
// Revision 1.9  2011/03/22 00:26:10  lpoulsen
// Resolve sequence errors on very weak links
// Resolve hangs when Ctrl-C between "dir" and "download"
// Resolve conflicting build date information
//
// Revision 1.8  2011/02/08 01:39:03  lpoulsen
// Define END_ARGS
//
// Revision 1.7  2011/02/04 22:29:07  lpoulsen
// Many little fixes.
//
// Revision 1.6  2011/01/22 01:29:05  lpoulsen
// Release candidate:
// - allow "show first=1 max=45" to support large systems
// - allow "sort by=distance" to support "connect all reboot"
// - improve download efficiency
//
// Revision 1.5  2008/07/30 07:11:42  lpoulsen
// New option "Connect keyboard=yes"
// Fixes for timeout probelm at end of file.
//
// Revision 1.4  2008/07/11 20:14:10  lpoulsen
// Resolve many compiler warnings on Linux
//
// Revision 1.3  2008/07/11 16:28:46  lpoulsen
// Econ 4.00 release candidate supports UPDATE and SELECT commands.
//
// Revision 1.2  2008/06/10 00:06:10  lpoulsen
// New -X option is now working
// Updated -I and -O implementation
//
// Revision 1.1  2008/05/31 00:35:09  lpoulsen
// Econ 4.x preview - now with command shell
//

#ifndef _PARSER_H
#define _PARSER_H

#include "uciosess.h"

typedef enum {
    CMD_SUCCESS,
    CMD_RESTART,
    CMD_TRUNCATED,
    CMD_NOT_FOUND,
    CMD_AMBIGUOUS,
    CMD_BAD_ARG_NAME,
    CMD_BAD_ARG_VALUE,
    CMD_ARG_MISSING,
    CMD_FAILED,
    CMD_DISABLED,
} cmd_ret_t;

#ifdef __cplusplus

/* This class allows you to store and retrieve the value associated with
   a given parameter. Essentially, it is an associative array.
   The chararacter arrays are copied into memory managed by the class.
   You may add a value twice, but only the first value added can be retrieved.
*/
class Argument_List
   {
public:
   // Argument_List();
   // ~Argument_List();
   void *operator new(size_t);
   void  operator delete(void *, size_t);

   void add_value(
      const char p[],            // Parameter (lower case)
      const char v[]);           // Value

   boolean empty() const;

   const char *get_value(
      const char p[],            // Parameter (lower case)
      const char d[] = 0) const; // Default value if not found

protected:
   char *param;
   char *value;
   Argument_List *next;
   };
#else
typedef struct Argument_List {
    char *param;
    char *value;
    struct Argument_List *next;
} Argument_List;
#endif


// Data structures for values, arguments, and commands
// These are used "internally" by parser.cpp and command.cpp

typedef enum Parser_Value_Kind
{
    UNDEF_ARG = 0,
    INT_ARG,
    INT2_ARG,
    BOOL_ARG,
    CHOICE_ARG,
    STRING_ARG,
    IPADDR_ARG,
    ALIAS_ARG,
    SELECT_ARG,
    BITS_ARG,
} Parser_Value_Kind;

typedef struct Value
{
    Parser_Value_Kind kind;
    uint32 lo;
    uint32 hi;
} Value;

typedef struct Arg
{
    const char *param;
    Value       value;
    uint32      flags;
} Arg;

typedef struct Select
{
    const char *string;
    uint32      flags;
} Select;

#define NEWLINE_ARG 0x0001A

typedef cmd_ret_t (cmd_func)(Argument_List * a, ucio_session* s);

// We wanted to make cmd_func procedures non-mangled C functions, but
//    the compiler would not co-operate, so I have commented it out
//    until there may be time to try it again.
// So for now, the restriction remains that you MUST be a C++ module
//   in order to use this
#ifdef __cplusplus
const int COMMAND_LEN = 132;
#define extern_cmd_func extern "C" cmd_func
#else
#define COMMAND_LEN 132
#define extern_cmd_func extern cmd_func
#endif

typedef struct Command
   {
   const char  *name;
   const Arg   *arg;
   cmd_func    *func;
   uint32       flags;
   } Command;

// Command.flags bit values
#define PARSER_COMMENT     0x0001  // Display heading only
#define PARSER_NOHELP	   0x0002  // Do not display but it works
#define PARSER_DEBUG 	   0x0004  // Debugging command
#define PARSER_HIDDEN	   0x0004  // Debugging command
                                   // Can only be used after unlock key=<passwd>
                                   // or if debug_level is non-zero
                                   // These commands are for support only
#define PARSER_HIDDEN_CCFG 0x0008  // Configuration command (Privileged)
                                   // Can only be used after 
                                   //    unlock enable-configuration=<passwd>
                                   // These commands change system configuration
#define PARSER_LOCAL_ONLY  0x0010  // Can only be used from the TTY,
                                   //   not remotely (e.g. monitor commands,
                                   //   which check for keyboard activity)
#define PARSER_DISABLED    0x0020  // For commands that are only active
                                   //   when a license key is installed

// List the commands that match the given command
extern cmd_ret_t parse_list_matching_commands(
   const char command[],
   const Command cmd_list[],
   ucio_session *session, boolean fullmode);

#ifdef __cplusplus

// Parse command and return an index into the command array
// Returns ~AOK if the command is not recognized
// The position returned is the first character of the first argument
extern int parse_command( const char cmd[], int &pos, const Command cmd_list[],
   ucio_session *session);

// Parse the arguments and return a pointer into the argument list
// Returns 0 if we ran out of memory or an argument was bad
// The position returned is the end of the string
// When done with the argument list, 'delete' it
extern Argument_List *parse_arguments(
   const int cmd_index,
   const char cmd[],
   int &pos,
   const Command cmd_list[],
   ucio_session *session);

/* Parse a 32-bit signed or unsigned number in ip address format xxx.xxx.xxx.xxx octal (0DDD)
*/
extern int32 parse_ipaddr(
   const char number[], // The number in string form (can be null string)
   const int32 def = 0, // Default value in case of error or null string
   boolean *errorp = 0);   // Location for returned error flag (can be null)


/* Parse a 32-bit signed or unsigned number in decimal, octal (0DDD)
        hexadecimal (0xDDD), or binary (0bDDD).
   A number that overflows a uint32 is an error, as is a number with
        a negative sign that is so large it is positive as an int32,
        a number that is not in one of the above forms, any digits that
        are not in the correct base, or junk at the end of the number.
*/
extern "C" int32 parse_number(
   const char number[], // The number in string form (can be null string)
   const int32 def = 0, // Default value in case of error or null string
   boolean *errorp = 0);   // Location for returned error flag (can be null)

inline int parse_int(
   const char number[],
   const int def = 0,
   boolean *errorp = 0)
   {
   return (int)parse_number(number, def, errorp);
   }

extern boolean parse_bool(
   const char number[],
   const boolean def = false,
   boolean *errorp = 0);

#else
extern int32 parse_number(const char number[], const int32 def, boolean *errp);
#endif

/* Use this as the argument of a command to make the current command
   an alias of the previous command.
 */
#ifdef __cplusplus
extern "C" const Arg CMD_ALIAS[];
extern "C" const Arg no_args[];
extern "C" const Arg parser_help_args[];
extern "C" Command  *current_command_table;
extern "C" boolean parse_boolean(const char *s);
#else
extern const Arg CMD_ALIAS[];
extern const Arg no_args[];
extern const Arg parser_help_args[];
extern Command  *current_command_table;
extern boolean parse_boolean(const char *s);
#endif

#define INT(lo, hi)              { INT_ARG,     lo, hi }
#define INT2(p, q)               { INT2_ARG,     p,  q }
#define CHOICE(c)                { CHOICE_ARG,   (uint32)c,  0 }
#define STRING                   { STRING_ARG,   1,  0 }
#define PARAM_ALIAS              { ALIAS_ARG,    1,  0 }
#define IPADDRESS                { IPADDR_ARG,   1,  0 }
#define SELECT(c)                { SELECT_ARG,   (uint32)c,  0 }
#define BITFLAGS(c)              { BITS_ARG,     (uint32)c,  0 }
#define BOOL_VALUE               { BOOL_ARG,     0,  1 }
#define END_ARGS                 { UNDEF_ARG,    0,  0 }

// #define BOOL { BOOL_ARG, 0, 1 }

// #define BYTE INT(0, 0xFF)
// #define WORD INT(0, 0xFFFF)
// #define LONG INT(0, 0xFFFFFFFF)

extern int       parser_key;

extern int       parser_keyhash(const char key[]);

extern_cmd_func  parser_help;
extern_cmd_func  session_logout;

#if 0
extern_cmd_func  bridge_show;
extern_cmd_func  change_password;
extern_cmd_func  clear_log;
extern_cmd_func  eeprom_program;
extern_cmd_func  eeprom_show;
extern_cmd_func  event_log;
extern_cmd_func  ether_quit;
extern_cmd_func  evtlog_clear_restart_log;
extern_cmd_func  ip_config;
extern_cmd_func  ip_ping;
extern_cmd_func  ip_snmp;
extern_cmd_func  ip_system_id;
extern_cmd_func  mactable_timers;
extern_cmd_func  parser_disable_cmd;
extern_cmd_func  parser_enable_cmd;
extern_cmd_func  parser_history;
extern_cmd_func  parser_lock_all;
extern_cmd_func  parser_unlock;
extern_cmd_func  time_and_date;
extern_cmd_func  ucio_bootload;
extern_cmd_func  ucio_copy_file;
extern_cmd_func  ucio_create_file;
extern_cmd_func  ucio_delete_file;
extern_cmd_func  ucio_download;
extern_cmd_func  ucio_eeprom_setboot;
extern_cmd_func  ucio_flash_dumpall;
extern_cmd_func  ucio_flash_erase;
extern_cmd_func  ucio_flash_files;
extern_cmd_func  ucio_flash_newbootrom;
extern_cmd_func  ucio_flash_setboot;
extern_cmd_func  ucio_show_devices;
extern_cmd_func  ucio_ttyspeed;
extern_cmd_func  ucio_type_file;
extern_cmd_func  ucw_license;
extern_cmd_func  ucw_meminfo;
extern_cmd_func  ucw_peek;
extern_cmd_func  ucw_poke;
extern_cmd_func  ucw_reboot;
extern_cmd_func  verbosity;

extern const Arg bridge_show_args[];
extern const Arg change_password_args[];
extern const Arg clear_log_args[];
extern const Arg date_args[];
extern const Arg eeprom_program_args[];
extern const Arg eeprom_show_args[];
extern const Arg event_log_args[];
extern const Arg ip_config_args[];
extern const Arg ip_ping_args[];
extern const Arg ip_snmp_args[];
extern const Arg ip_system_id_args[];
extern const Arg mactable_timers_args[];
extern const Arg no_args[];
extern const Arg parser_enable_args[];
extern const Arg parser_help_args[];
extern const Arg parser_unlock_args[];
extern const Arg peek_args[];
extern const Arg poke_args[];
extern const Arg time_args[];
extern const Arg ucio_1file_args[];
extern const Arg ucio_bootload_args[];
extern const Arg ucio_copy_file_args[];
extern const Arg ucio_download_args[];
extern const Arg ucio_erase_args[];
extern const Arg ucio_list_args[];
extern const Arg ucio_ttyspeed_args[];
extern const Arg ucw_license_args[];
extern const Arg ucw_reboot_args[];
extern const Arg verbos_args[];
#endif

extern Select      enet_interface_settings[];

extern struct Command *current_command_table;

#ifdef __cplusplus
extern "C" {
#endif

// Returns the index (zero-based) of the string in the array that
//      matches the given string.
// The array of strings must be zero-terminated.
int parse_string_match(const char *string, const char * const strings[]);
int parse_select_match(const char *string, const Select *sel_tab);

uint32 parse_bitmask(const char *string, const Select *sel_tab);

extern cmd_ret_t  parser_disable_command(const char *c);
extern cmd_ret_t  parser_enable_command(const char *c);
extern cmd_ret_t  parser_enable_argument(const char *c, const char *a);
extern cmd_ret_t  parser_disable_argument(const char *c, const char *a);
extern cmd_ret_t  parser_enable_arg_value(const char *c, const char *a,
                                                         const char *v);
extern cmd_ret_t  parser_disable_arg_value(const char *c, const char *a,
                                                         const char *v);
extern cmd_ret_t  parser_enable_selection(const Select *sel_tab, const char *c);

extern char      *parser_get_value(Argument_List *a, char *name);
extern boolean    parser_empty(Argument_List *a);

extern cmd_ret_t  ucio_take_file(char *filename, ucio_session *session);
extern cmd_ret_t  ucio_do_command(char *filename, ucio_session *session);
extern void       cmd_loop(char *prompt);
extern boolean    parse_bool(const char *c);
extern char      *parser_format_bitflags(int value, Select sel_tab[]);

#ifdef __cplusplus
}
#endif

#endif

//
