#ifndef _help_h_
#define _help_h_

#include <stdio.h>
#include "bool.h"

/*************************************************************************
   EXAMPLE OF HOW TO USE ALHELP FUNCTIONS : 
   ----------------------------------------

   char *notes[4] =
         {"The first non-switch argument is assumed to be the ruleset name.",
	  "The second non-switch argument is assumed to be the folder name.",
	  "If folder is not specified, standard input is used when possible.",
	  NULL};
   char *examples[4] = {"runrules archiverules +inbox",
                        "runrules -MSmh -RSmyrules -FOinbox",
			"runrules -MSrmail printrules < RMAIL",
			NULL};
   AlH_MASK optional_no_arg_switches      = ALH_help,
            required_no_arg_switches      = ALH_none,
            optional_fixed_arg_switches   = ALH_none,
            required_fixed_arg_switches   = ALH_none,
	    optional_object_arg_switches  = (ALH_folder | ALH_msgsrc),
            required_object_arg_switches  = ALH_ruleset; 

   int index = 1;
   AlH_MASK switch_type, switch_code;
   char *switch_arg;

 if (argc < 1)
   { AlHelp_non_standard_usage("runrules ruleset [folder]");
     AlHelp_usage("runrules",
                  optional_no_arg_switches, required_no_arg_switches,
                  optional_fixed_arg_switches, required_fixed_arg_switches,
		  optional_object_arg_switches, required_object_arg_switches);
   }
 else if (AlHelp_user_requested_help(argc, argv) == Bool_TRUE)
   { AlHelp_non_standard_usage("runrules ruleset [folder]");
     AlHelp_info("runrules",
                  optional_no_arg_switches, required_no_arg_switches,
                  optional_fixed_arg_switches, required_fixed_arg_switches,
		  optional_object_arg_switches, required_object_arg_switches,
		  notes,
		  examples,
                  "runrules -help");
   }
 else
  { while(Bool_TRUE == AlHelp_get_arg(argv, argc, &index,
                                      &switch_type, &switch_code, &switch_arg))
      { switch (switch_type)
          { case ALH_bad_switch: 

                  AlHelp_non_standard_usage("runrules ruleset [folder]");
                  AlHelp_usage("runrules",
                   optional_no_arg_switches, required_no_arg_switches,
                   optional_fixed_arg_switches, required_fixed_arg_switches,
		   optional_object_arg_switches, required_object_arg_switches);
                  Al_fatal_error2(
                     "%s :: Invalid switch or switch argument specified: %s\n",
		     argv[0], switch_arg);
	          break;
	  };
      };
  };

   RESULTS IN THE FOLLOWING FOR "-help" OPTION :
   ---------------------------------------------
Usage:     runrules ruleset folder
Usage:     runrules [-help] [-FOfolder] [-MSmsgsrc] -RSruleset

arguments:
   folder     The name of a message folder.
   msgsrc     A message source (ex: '-mh' or 'rmail').
   ruleset     The name of a rule set.

switches:
   -h
   -help      Lists this short documentation.
   -MS        Specify the message source (ex: '-MSmh' or '-MSrmail').
   -RS        Specify a ruleset.

notes:
   The first non-switch argument is assumed to be the ruleset name.
   The second non-switch argument is assumed to be the folder name.
   If folder is not specified, standard input is used when possible.

examples:
   runrules archiverules +inbox
   runrules -MSmh -RSmyrules -FOinbox
   runrules -MSrmail printrules < RMAIL

for help:  runrules -help

**************************************************************************/

/* ----------------------------------------
    Functions are prefixed by "AlHelp",
    Defined constants are prefixed by "ALH",
    and Macros are prefixed by "AlH".
   ---------------------------------------- */

#define AlH_MASK  unsigned   /* ??? */

/* ----------------------------------------------------------------- */
/*                         Functions                                 */
/* ----------------------------------------------------------------- */

#ifdef __STDC__

extern Bool AlHelp_user_requested_help(int, char**);
extern void AlHelp_usage(char *, AlH_MASK, AlH_MASK, AlH_MASK, AlH_MASK,
			 AlH_MASK, AlH_MASK);
extern void AlHelp_info(char *, AlH_MASK, AlH_MASK, AlH_MASK, AlH_MASK,
			 AlH_MASK, AlH_MASK, char **, char **, char *);
extern char *AlHelp_mask_to_switch(AlH_MASK, AlH_MASK);
extern Bool AlHelp_get_arg(char **, int, int *,
			   AlH_MASK *, AlH_MASK *, char **);

#else

extern Bool AlHelp_user_requested_help();
extern void AlHelp_usage();
extern void AlHelp_info();
extern char *AlHelp_mask_to_switch();
extern Bool AlHelp_get_arg();

#endif          /* end of  #ifdef _STDC_  */
/* ----------------------------------------------------------------- */
/* ----------------------------------------------------------------- */

extern int AlH_count;      /* length of current line in usage output buffer */

/* --------------------------------------------------------- */
/*                         Codes for Switch Types            */
/* --------------------------------------------------------- */
#define ALH_bad_switch         ((AlH_MASK) 0)
#define ALH_no_arg_switch      ((AlH_MASK) 1)
#define ALH_fixed_arg_switch   ((AlH_MASK) 2)
#define ALH_object_arg_switch  ((AlH_MASK) 3)
#define ALH_not_a_switch       ((AlH_MASK) 4)


/* --------------------------------------------------------- */
/*                         MASKS for Switches                */
/* --------------------------------------------------------- */
#define ALH_none    ((AlH_MASK) 0) /* no parameters of  this type            */

/* Switches that don't take arguments */
/* ---------------------------------- */
#define ALH_create  ((AlH_MASK) 1) /* create new object (flags new ruleset)  */
#define ALH_eliminate ((AlH_MASK) 2) /* elimate (delete)                     */
#define ALH_force   ((AlH_MASK) 4) /* force (new ruleset created w/o asking) */
#define ALH_help    ((AlH_MASK) 8) /* User just wants to view help info      */
#define ALH_nest   ((AlH_MASK) 16) /* process nested subfolders, recursively */
#define ALH_output   ((AlH_MASK) 32) /* output information upon completion   */

/* Switches that take fixed arguments */
/* ---------------------------------- */
#define ALH_state   ((AlH_MASK) 1)  /* specifies is state is saved or not    */
#define ALH_uprop   ((AlH_MASK) 2)  /* specifies saving of user properties   */
#define ALH_data    ((AlH_MASK) 4)  /* specifies data collection info        */
#define ALH_warn    ((AlH_MASK) 8)  /* whether warning messages are viewed   */
#define ALH_after   ((AlH_MASK) 16) /* insert new rule after rule number     */
#define ALH_before  ((AlH_MASK) 32) /* insert new rule before rule number    */
#define ALH_rule    ((AlH_MASK) 64) /* specifies which rule number to use    */
#define ALH_traffic ((AlH_MASK) 128) /* specifies direction of msg traffic   */

/* Switches that take objects as arguments */
/* --------------------------------------- */
#define ALH_io_filename    ((AlH_MASK)  1) /* specify a filename for I/O     */
#define ALH_folder         ((AlH_MASK)  2) /* specify a folder object        */
#define ALH_std_msgtype    ((AlH_MASK)  4) /* spec standard existing msgtype */
#define ALH_new_msgtype    ((AlH_MASK)  8) /* spec new msgtype to be created */
#define ALH_load_filename  ((AlH_MASK) 16) /* specify a loading file         */
#define ALH_ruleset        ((AlH_MASK) 32) /* specify a ruleset              */
#define ALH_msgsrc         ((AlH_MASK) 64) /* spec message source (ex: 'mh') */
#define ALH_server        ((AlH_MASK) 128) /* spec which rule server to use  */

/* --------------------------------------------------------- */
/*                         Usage                             */
/* --------------------------------------------------------- */
#define ALH_usage   "Usage:     "

/* --------------------------------------------------------- */
/*                         Arguments (Argus Objects)         */
/* --------------------------------------------------------- */
/*
Object     Description
------     -----------
filename   a file name
folder     the name of a message folder
msgsrc     a message source (ex: 'mh', 'rmail', 'discuss')
msgtype    a message type (ex: 'bug-report', 'meeting', 'bug-fix')
ruleset    the name of a rule set
server     the name of a rule server

rulenum     an integer representing the position of a rule in a ruleset
*/

#define ALHobj_filename       "filename"
#define ALHinfo_filename      "   filename   A file name."

#define ALHobj_folder         "folder"
#define ALHinfo_folder        "   folder     The name of a message folder."

#define ALHobj_msgsrc         "msgsrc"
#define ALHinfo_msgsrc        \
"   msgsrc     A message source (ex: '-mh' or 'rmail')."

#define ALHobj_msgtype        "msgtype"
#define ALHinfo_msgtype       \
"   msgtype    A message type (ex: 'bug-report', 'meeting', 'bug-fix')."

#define ALHobj_ruleset        "ruleset"
#define ALHinfo_ruleset       \
"   ruleset    The name of a rule set."

#define ALHobj_server         "server"
#define ALHinfo_server        \
"   server     The name of a rule server."

#define ALHobj_rulenum        "rulenum"
#define ALHinfo_rulenum       \
"   rulenum     An integer representing the position of a rule in a ruleset."


/* --------------------------------------------------------- */
/*                         Switches                          */
/* --------------------------------------------------------- */

/* Switches that don't take arguments 
   ---------------------------------- 
Abbrev.  Full     Description
-------  ----     -----------
-c       -create  create something new (eg, flag if a ruleset is to be created)
-e       -elim    eliminate (delete)
-f       -force   force action (new ruleset to be created without asking)
-h       -help    User just wants to view help information
-n       -nest    process nested subfolders (recursively)
-o       -output  output additional information upon completion (to stdout)
*/

#define ALHfull_create    "-create"
#define ALHabbrev_create  "-c"
#define ALHstr_create  "   -c \n\
   -create    Create something new (eg, flag if a ruleset is to be created)."

#define ALHfull_elim    "-elim"
#define ALHabbrev_elim  "-e"
#define ALHstr_elim  "   -e \n\
   -elim      Eliminate (delete)."

#define ALHfull_force   "-force"
#define ALHabbrev_force "-f"
#define ALHstr_force "   -f \n\
   -force     Force action (create new ruleset without asking)."

#define ALHfull_help    "-help"
#define ALHabbrev_help  "-h"
#define ALHstr_help  "   -h \n\
   -help      Lists this short documentation."

#define ALHfull_nest    "-nest"
#define ALHabbrev_nest  "-n"
#define ALHstr_nest  "   -n \n\
   -nest      Process nested subfolders (recursively)."


#define ALHfull_output    "-output"
#define ALHabbrev_output  "-o"
#define ALHstr_output  "   -o \n\
   -output    Output additional information upon completion (to stdout)."


/* Switches that take fixed arguments
   ---------------------------------- 
Abbrev.  Full     Set of valid args     Description
 -------  ----     -----------------     -----------
-s       -state   [on | off]            specifies if states are saved or not
-u       -uprop   [on | off]            specifies saving of user properties
-d       -data    [all | none | msg | nomsg | rl | norl | ra | nora]
                                        specifies data collection info
-w       -warn    [on | off]            whether warning messages are viewed
-a       -after   rulenum               insert new rule after rule number
-b       -before  rulenum               insert new rule before rule number
-r       -rule    rulenum               specifies which rule number to use
-t       -traffic [incoming | outgoing | other]
                                        specifies direction of msg traffic
*/

#define ALHfull_state   "-state"
#define ALHabbrev_state "-s"
#define ALHstr_state "   -s \n\
   -state     Specifies if states are saved or not ('on' or 'off')."
#define ALHarg_state    "{on | off}"

#define ALHfull_uprop   "-uprop"
#define ALHabbrev_uprop "-u"
#define ALHstr_uprop "   -u \n\
   -uprop     Specifies if user properties are saved or not ('on' or 'off')."
#define ALHarg_uprop    "{on | off}"


#define ALHfull_traffic   "-traffic"
#define ALHabbrev_traffic "-t"
#define ALHstr_traffic "   -t \n\
   -traffic   Direction of msg traffic ('incoming', 'outgoing', or 'other')."
#define ALHarg_traffic    "{incoming | outgoing | other}"


#define ALHfull_data    "-data"
#define ALHabbrev_data  "-d"
#define ALHstr_data  "   -d \n\
   -data      Specifies what types of data collection info to trace \n\
              ('all', 'none', 'msg', 'nomsg', 'rl', 'norl', 'ra', or 'nora')."
#define ALHarg_data     "{all | none | msg | nomsg | rl | norl | ra | nora}"

#define ALHfull_warn    "-warn"
#define ALHabbrev_warn  "-w"
#define ALHstr_warn  "   -w \n\
   -warn      Specifies whether warning messages are viewed ('on' or 'off')."
#define ALHarg_warn     "{on | off}"

#define ALHfull_after   "-after"
#define ALHabbrev_after "-a"
#define ALHstr_after "   -a \n\
   -after     Insert new rule After rule number specified (takes an integer)."
/* Instead of ALHarg_after use =>  ALHobj_rulenum */

#define ALHfull_before   "-before"
#define ALHabbrev_before "-b"
#define ALHstr_before "   -b \n\
   -before    Insert new rule Before rule number specified (takes an integer)."
/* Instead of ALHarg_before use =>  ALHobj_rulenum */

#define ALHfull_rule    "-rule"
#define ALHabbrev_rule  "-r"
#define ALHstr_rule  "   -r \n\
   -rule      Specifies which rule number to use (takes an integer)."
/* Instead of ALHarg_rule use =>  ALHobj_rulenum */


/* Switches that take objects as arguments 
   --------------------------------------- 
Switch & Arg    Description
 ------------    -----------
-FNfilename     specify a filename for I/O
-FOfolder       specify a folder object
-LFfilename     specify a loading file
-MSmsgsrc       specify the message source (ex: 'mh', 'rmail', 'discuss')
-MTmsgtype      specify an existing message type
-NMmsgtype      specify a new message type to be created
-RSruleset      specify a ruleset
-SVserver       specifies which rule server to use
*/

#define ALHfull_io_filename     "-FN"
#define ALHstr_io_filename      "   -FN        Specify a filename for I/O."

#define ALHfull_folder          "-FO"
#define ALHstr_folder           "   -FO        Specify a folder object."

#define ALHfull_load_filename   "-LF"
#define ALHstr_load_filename    "   -LF        Specify a loading file."

#define ALHfull_msgsrc          "-MS"
#define ALHstr_msgsrc           \
 "   -MS        Specify the message source (ex: '-MSmh' or '-MSrmail')."

#define ALHfull_std_msgtype     "-MT"
#define ALHstr_std_msgtype      \
 "   -MT        Specify an existing message type."

#define ALHfull_new_msgtype     "-NM"
#define ALHstr_new_msgtype      \
 "   -NM        Specify a new message type to be created."

#define ALHfull_ruleset         "-RS"
#define ALHstr_ruleset          "   -RS        Specify a ruleset."

#define ALHfull_server          "-SV"
#define ALHstr_server           \
 "   -SV        Specify which rule server to use."



/***********************************************************************/

/* ----------------- */
/* Define All Macros */
/* ----------------- */

#define AlHelp_non_standard_usage(usage_str) \
                                printf("%s%s\n", ALH_usage, usage_str);
#define AlH_arguments()         printf("\narguments:\n");
#define AlH_switches()          printf("\nswitches:\n");
#define AlH_notes()             printf("\nnotes:\n");
#define AlH_examples()          printf("\nexamples:\n");
#define AlH_for_help(help_str)  printf("\nfor help:  %s\n\n", help_str);


#define AlHpr_no_arg_switch(optional_flags, required_flags, mask, switch_str) \
  if ((optional_flags & mask) != 0) \
    { if ((AlH_count + strlen(switch_str) + 3) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" [%s]", switch_str);  \
      AlH_count += (3 + strlen(switch_str)); \
    } \
  else if ((required_flags & mask) != 0)  \
    { if ((AlH_count + strlen(switch_str) + 1) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" %s", switch_str);  \
      AlH_count += (1 + strlen(switch_str)); \
    };


#define AlHpr_fixed_arg_switch(optional_flags, required_flags, mask, switch_str, switch_args) \
  if ((optional_flags & mask) != 0) \
    { if ((AlH_count + strlen(switch_str) + strlen(switch_args) + 4) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" [%s %s]", switch_str, switch_args);  \
      AlH_count += (4 + strlen(switch_str) + strlen(switch_args)); \
    } \
  else if ((required_flags & mask) != 0)  \
    { if ((AlH_count + strlen(switch_str) + strlen(switch_args) + 2) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" %s %s", switch_str, switch_args);  \
      AlH_count += (2 + strlen(switch_str) + strlen(switch_args)); \
    };


#define AlHpr_object_arg_switch(optional_flags, required_flags, mask, switch_str, switch_arg) \
  if ((optional_flags & mask) != 0) \
    { if ((AlH_count + strlen(switch_str) + strlen(switch_arg) + 3) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" [%s%s]", switch_str, switch_arg);  \
      AlH_count += (3 + strlen(switch_str) + strlen(switch_arg)); \
    } \
  else if ((required_flags & mask) != 0)  \
    { if ((AlH_count + strlen(switch_str) + strlen(switch_arg) + 1) > 79)  \
        { printf("\n               ");  \
          AlH_count = 15; \
        };  \
      printf(" %s%s", switch_str, switch_arg);  \
      AlH_count += (1 + strlen(switch_str) + strlen(switch_arg)); \
    };

/**************************************************************************/

/* ----------------------------------------------------------------------- */
/* Bool AlHelp_get_arg(argv, argc, index,                                  */
/*		       switch_type, switch_code, switch_arg)               */
/*  char *argv[];   <= the argv containing command line strings for main() */
/*  int argc;       <= the argc indicating # of argv strings for main()    */
/*  int *index;     <= an index into argv, managed by AlHelp_get_arg()     */
/*  AlH_MASK                                                               */
/*    *switch_type, <= returned mask, for type of switch (ex: fixed_arg )  */
/*    *switch_code; <= returned mask, for a switch code (ex: ALH_state )   */
/*  char                                                                   */
/*    **switch_arg; <= returns string, for the switch's argument (or NULL) */
/* ----------------------------------------------------------------------- */
/*  while(Bool_TRUE == AlHelp_get_arg(argv, argc, &index,                  */
/*                               &switch_type, &switch_code, &switch_arg)) */
/*    { ......                                                             */
/*    };                                                                   */
/* ----------------------------------------------------------------------- */
/* This function updates: index, switch_type, switch_code, & switch_arg    */
/* It identifies with command-line switch was processed (argv[index]).     */
/* It returns:  Bool_TRUE   if a command was processed                     */
/*              Bool_FALSE  if there were no more options left to process  */
/* It alters the following variables passed to it:                         */
/*         index          <= ready to process next argv string             */
/*         switch_type    <= As one of the following masks:                */
/*                               ALH_bad_switch                            */
/*                               ALH_no_arg_switch                         */
/*                               ALH_fixed_arg_switch                      */
/*                               ALH_object_arg_switch                     */
/*                               ALH_not_a_switch                          */
/*         switch_code    <= A mask representing which switch was found,   */
/*                           or ALH_none if no valid switch  was found.    */
/*         switch_arg     <= The string which was the argument to the      */
/*                           switch, or NULL if switch takes no arguments  */
/*                           If a bad switch or switch argument was        */
/*                           specified, then switch_arg is set to the bad  */
/*                           string (for debugging purposes for user).     */
/*                                                                         */
/* The calling program should check for  (switch_type == ALH_bad_switch)   */
/* and print a usage message, followed by a fatal error message, and exit  */
/* ----------------------------------------------------------------------- */

/***************************************************************************/
#endif          /* end of ifndef _help_h  :: DO NOT WRITE BELOW THIS LINE. */
