/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/**
   s2sh: the s2 shell

   Intended uses of this code:

   1) A copy/paste bootstrap for creating new s2-using clients. To
   that end, this file "should" be commented relatively well.

   2) An extensible shell for use in running client-defined
   functionality. Extensibility comes in these forms:

   2.1) Via editing this and/or shell_common.c file (discourged, as i
   copy it amongst several trees ;). Note that shell_common.c is used
   by both this file and shell2.c (its successor).

   2.2) Editing shell_extend.c and defining S2_SHELL_EXTEND when
   building this file. Preferred, as this allows clients to statically
   link in their features to the shell.

   2.3) A platform for loading new s2 features via DLLs.

   2.4) provide an auto-load feature which clients can hook into to
   extend the script-side environment during shell startup.

   3) Running s2 script files in batch mode or via an interactive
   session (requires 3rd-party libs described later in these sources).

   The non-API s2 docs include much more detail on the above points:

   https://fossil.wanderinghorse.net/r/cwal/doc/trunk/s2/

   (Or, if you're reading this from the canonical s2 source tree, see
   index.md in this file's directory.)


   Concepts needed to make any sense of this file:

   - cwal is a separate lib (bundled with s2) which provides
   the core-most features: Value system, memory management/lifetime,
   and garbage collector.

   - s2 is a script language built on that engine.

   Thus clients will see many mixes of the two in this code. In
   practice, most client code uses only the cwal-level APIs, but this
   app's level of code uses the s2 API relatively often as well.

*/

#define S2SH_VERSION 1
#include "shell_common.c"

/**
   gcc bug: if this function is marked static here, it does
   not recognize that shell_common.c uses it and declares that
   it's unused.
*/
CliAppSwitch const * s2sh_cliapp_switches(){
  static const CliAppSwitch cliAppSwitches[] = {
#define F6(IDFLAGS,DASHES,KEY,VAL,BRIEF,PFLAGS)     \
  {IDFLAGS, DASHES, KEY, VAL, BRIEF, 0, 0, PFLAGS}
#define F5(IDFLAGS,DASHES,KEY,VAL,BRIEF)        \
  F6(IDFLAGS,DASHES,KEY,VAL,BRIEF,0)
  /** Continues the help text for the previous entry. */
#define FCONTINUE(LABEL) {SW_CONTINUE, 0, 0, 0, LABEL, 0, 0, 0}
  /** Adds an "additional info" line, not indented. */
#define FINFOLINE(LABEL) {SW_INFOLINE, 0, 0, 0, LABEL, 0, 0, 0}
  /** -short | --long[=VALUE]*/
#define FX(IDFLAGS,SHORT,LONG,VALUE,BRIEF,PFLAGS)   \
  F6(IDFLAGS,2,LONG,VALUE,BRIEF,PFLAGS),            \
  F6(IDFLAGS,1,SHORT,VALUE,0,PFLAGS)
  /** -short, --long on/off switches ...*/
#define F01(IDFLAGS,KEY,BRIEF)                          \
  {IDFLAGS,   2, KEY, 0, "Disable "  BRIEF, 0, 0, 0},   \
  {IDFLAGS+1, 1, KEY, 0, "Enable "  BRIEF, 0, 0, 0}
  /** Start the next group (for --help grouping). */
#define GROUP(GID,DESC) {GID, 0, 0, 0, DESC, 0, 0, 0}

  /***********************************************************************/
  GROUP(SW_GROUP_0,0),

  F5(SW_HELP, 2, "help", 0,
     "Send help text to stdout and exit with code 0."),
  F5(SW_HELP, 1, "?", 0, 0),
  F5(SW_HELP | SW_UNDOCUMENTED, 1, "help", 0, 0),
  FCONTINUE("The -v flag can be used to get more info."),
  
  F5(SW_VERBOSE, 1, "v", 0, "Increase verbosity level by one."),
  FCONTINUE("Use with -?/--help to increase help info level."),

  F5(SW_VERSION,2,"version",0,
     "Show version info and exit with code 0. "),
  FCONTINUE("Use with -v for more details."),

  F6(SW_OUTFILE,1,"o","outfile",
     "Sets the engine's default output channel. Default=stdout.",
     CLIAPP_F_SPACE_VALUE | CLIAPP_F_ONCE),

  F6(SW_INFILE,1, "f", "infile",
     "Runs the given script file in a new scope.",
     CLIAPP_F_SPACE_VALUE | CLIAPP_F_ONCE),
  FCONTINUE("Defaults to the first non-flag argument."),

  FX(SW_ESCRIPT,"e","eval","SCRIPT",
     "Evaluates the given script code in the global scope. "
     "May be used multiple times.", CLIAPP_F_SPACE_VALUE),

  /***********************************************************************/
  GROUP(SW_GROUP_1,"Less-common options:"),

  F01(SW_ASSERT_0,"A","assert tracing."),
  FCONTINUE("Enable twice to also trace affirm calls."),

  F5(SW_INTERACTIVE,1,"i",0,
     "Enter interactive mode even if -e/-f disable it."),

  F01(SW_AUTOLOAD_0,"a","autoloading of init script."),
  FCONTINUE("Init script name = same as this binary plus \".s2\" "),
  FCONTINUE("or set via the S2SH_INIT_SCRIPT environment variable."),

  /***********************************************************************/
  GROUP(SW_GROUP_2,"Esoteric options:"),

  F5(SW_METRICS, 1, "m", 0, "Dump cwal/s2 metrics before shutdown."),
  FCONTINUE("Use -v 1-3 times for more information."),

  F01(SW_MOD_INIT_0,"M","initialization of built-in static modules."),
  F01(SW_SHELL_API_0,"s2.shell","installation of s2.shell API."),
  FCONTINUE("By default s2.shell is only installed in interactive mode."),

  F01(SW_SCOPE_H0,"H","hashes for scope storage (else objects)."),

  F6(SW_HIST_FILE_1,1,"h","filename", "Set editing history file.",
     CLIAPP_F_SPACE_VALUE | CLIAPP_F_ONCE),
  F5(SW_HIST_FILE_0,2,"h",0, "Disable editing history file."),

  F5(SW_CLEANROOM, 1, "cleanroom", 0,
     "Do not install any global/prototype-level functionality."),
  FCONTINUE("Disables the s2 global object and auto-loading of the "
            "init script."),

  F5(SW_SHOW_SIZEOFS,1,"z",0,"Dump various sizeof() values."),

  F5(SW_INTERNAL_FU,1,"fu",0,
     "May or may not enable some internal testing. Only for use in developing this app."),

  F5(SW_CLAMPDOWN,-1,"clampdown",0,"No longer available: use --s2-disable instead."),

  F6(SW_DISABLE, 2, "s2-disable", "comma,list",
     "Disables certain s2 API features by name.",0),
  FCONTINUE("Use a comma-and/or-space-separated list with any of "
            "the following entries:"),
  FCONTINUE("fs-stat, fs-read, fs-write, fs-io, fs-all"),

  F5(SW_SWEEP_INTERVAL,1,"w",0,"Increase sweep interval by 1."),
  F5(SW_VAC_INTERVAL,-1,"w",0, "Increase vacuum interval by 1."),
  F01(SW_TRACE_STACKS_0,"T","stack machine tracing."),
  F01(SW_TRACE_SWEEP_0,"W","sweep tracking."),
  FCONTINUE("Enable multiple times for (possibly) more detail."),

  FINFOLINE("Recycling-related options:"),
  F01(SW_RE_V0,"R","value recycling."),
  F01(SW_RE_S0,"S","string interning."),
  F01(SW_RE_C0,"C","the chunk recyler."),

  FINFOLINE("Memory-tracking/capping options:"),
  
  F6(SW_MCAP_TOTAL_ALLOCS, 1, "cap-ta", "N",
     "* Limit the (T)otal number of (A)llocations to N.",
     CLIAPP_F_SPACE_VALUE),
  F6(SW_MCAP_TOTAL_ALLOCS, 1, "cap-tb", "N",
     "* Limit the (T)otal number of allocated (B)ytes to N.",
     CLIAPP_F_SPACE_VALUE),
  F6(SW_MCAP_TOTAL_ALLOCS, 1, "cap-ca", "N",
     "Limit the (C)oncurrent number of (A)llocations to N.",
     CLIAPP_F_SPACE_VALUE),
  F6(SW_MCAP_TOTAL_ALLOCS, 1, "cap-cb", "N",
     "Limit the (C)oncurrent number of allocated (B)ytes to N.",
     CLIAPP_F_SPACE_VALUE),
  F6(SW_MCAP_TOTAL_ALLOCS, 1, "cap-sb", "N",
     "Limit the size of any (S)ingle allocation to N (B)ytes.",
     CLIAPP_F_SPACE_VALUE),
  FINFOLINE("The allocator starts failing (returning NULL) when a capping constraint is violated."),
  FCONTINUE("The 'tb' and 'ta' constraint violations are permanent (recovery requires resetting the engine)."),
  FCONTINUE("The 'ca' and 'cb' constraints are recoverable once some cwal-managed memory gets freed."),
  FCONTINUE("Capping only applies to memory allocated by/via the scripting\n"
            "engine, not 3rd-party APIs."),

  F01(SW_MEM_FAST0, "fst", "(F)orced alloc (S)ize (T)racking."),
  FCONTINUE("Enabled implicitly by some -cap flags."),

#undef GROUP
#undef F01
#undef F5
#undef F6
#undef FX
#undef FPLUS
#undef FPLUSX
#undef FINFOLINE
  CliAppSwitch_sentinel /* MUST be the last entry in the list */

  };
  return cliAppSwitches;
}
