1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
/*@ S-nail - a mail user agent derived from Berkeley Mail.
*@ Actual command table, `help', `list', etc., and the cmd_arg() parser.
*
* Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
* SPDX-License-Identifier: ISC
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef mx_CMD_H
#define mx_CMD_H
#include <mx/nail.h>
#define mx_HEADER
#include <su/code-in.h>
enum mx_cmd_arg_flags{ /* TODO Most of these need to change, in fact in v15
* TODO i rather see the mechanism that is used in c_bind() extended and used
* TODO anywhere, i.e. n_cmd_arg_parse().
* TODO Note we may NOT support arguments with su_cs_len()>=U32_MAX (?) */
mx_CMD_ARG_TYPE_MSGLIST = 0, /* Message list type */
mx_CMD_ARG_TYPE_NDMLIST = 1, /* Message list, no defaults */
mx_CMD_ARG_TYPE_RAWDAT = 2, /* The plain string in an argv[] */
mx_CMD_ARG_TYPE_STRING = 3, /* A pure string TODO obsolete */
mx_CMD_ARG_TYPE_WYSH = 4, /* getrawlist(), sh(1) compatible */
mx_CMD_ARG_TYPE_RAWLIST = 5, /* getrawlist(), old style TODO obsolete */
mx_CMD_ARG_TYPE_WYRA = 6, /* _RAWLIST or _WYSH (with `wysh') TODO obs. */
mx_CMD_ARG_TYPE_ARG = 7, /* n_cmd_arg_desc/n_cmd_arg() new-style */
mx_CMD_ARG_TYPE_MASK = 7, /* Mask of the above */
mx_CMD_ARG_A = 1u<<4, /* Needs an active mailbox */
mx_CMD_ARG_F = 1u<<5, /* Is a conditional command */
mx_CMD_ARG_G = 1u<<6, /* Is supposed to produce "gabby" history */
mx_CMD_ARG_H = 1u<<7, /* Never place in `history' */
mx_CMD_ARG_I = 1u<<8, /* Interactive command bit */
mx_CMD_ARG_L = 1u<<9, /* Supports `local' prefix (only WYSH/WYRA) */
mx_CMD_ARG_M = 1u<<10, /* Legal from send mode bit */
mx_CMD_ARG_O = 1u<<11, /* n_OBSOLETE()d command */
mx_CMD_ARG_P = 1u<<12, /* Autoprint dot after command */
mx_CMD_ARG_R = 1u<<13, /* Forbidden in compose mode recursion */
mx_CMD_ARG_SC = 1u<<14, /* Forbidden pre-n_PSO_STARTED_CONFIG */
mx_CMD_ARG_S = 1u<<15, /* Forbidden pre-n_PSO_STARTED (POSIX) */
mx_CMD_ARG_T = 1u<<16, /* Is a transparent command */
mx_CMD_ARG_V = 1u<<17, /* Supports `vput' prefix (only WYSH/WYRA) */
mx_CMD_ARG_W = 1u<<18, /* Invalid when read only bit */
mx_CMD_ARG_X = 1u<<19, /* Valid command in n_PS_COMPOSE_FORKHOOK mode */
/* XXX Note that CMD_ARG_EM implies a _real_ return value for $! */
mx_CMD_ARG_EM = 1u<<30 /* If error: n_pstate_err_no (4 $! aka. ok_v___em) */
};
enum mx_cmd_arg_desc_flags{
/* - A type */
mx_CMD_ARG_DESC_SHEXP = 1u<<0, /* sh(1)ell-style token */
/* TODO All MSGLIST arguments can only be used last and are always greedy
* TODO (but MUST be _GREEDY, and MUST NOT be _OPTION too!).
* MSGLIST_AND_TARGET may create a NULL target */
mx_CMD_ARG_DESC_MSGLIST = 1u<<1, /* Message specification(s) */
mx_CMD_ARG_DESC_NDMSGLIST = 1u<<2,
mx_CMD_ARG_DESC_MSGLIST_AND_TARGET = 1u<<3,
mx__CMD_ARG_DESC_TYPE_MASK = mx_CMD_ARG_DESC_SHEXP |
mx_CMD_ARG_DESC_MSGLIST | mx_CMD_ARG_DESC_NDMSGLIST |
mx_CMD_ARG_DESC_MSGLIST_AND_TARGET,
/* - Optional flags */
/* It is not an error if an optional argument is missing; once an argument
* has been declared optional only optional arguments may follow */
mx_CMD_ARG_DESC_OPTION = 1u<<16,
/* GREEDY: parse as many of that type as possible; must be last entry */
mx_CMD_ARG_DESC_GREEDY = 1u<<17,
/* If greedy, join all given arguments separated by ASCII SP right away */
mx_CMD_ARG_DESC_GREEDY_JOIN = 1u<<18,
/* Honour an overall "stop" request in one of the arguments (\c@ or #) */
mx_CMD_ARG_DESC_HONOUR_STOP = 1u<<19,
/* With any MSGLIST, only one message may be give or ERR_NOTSUP (default) */
mx_CMD_ARG_DESC_MSGLIST_NEEDS_SINGLE = 1u<<20,
mx__CMD_ARG_DESC_FLAG_MASK = mx_CMD_ARG_DESC_OPTION |
mx_CMD_ARG_DESC_GREEDY | mx_CMD_ARG_DESC_GREEDY_JOIN |
mx_CMD_ARG_DESC_HONOUR_STOP |
mx_CMD_ARG_DESC_MSGLIST_NEEDS_SINGLE,
/* We may include something for n_pstate_err_no */
mx_CMD_ARG_DESC_ERRNO_SHIFT = 21u,
mx_CMD_ARG_DESC_ERRNO_MASK = (1u<<10) - 1
};
#define mx_CMD_ARG_DESC_ERRNO_TO_ORBITS(ENO) \
(S(u32,ENO) << mx_CMD_ARG_DESC_ERRNO)
#define mx_CMD_ARG_DESC_TO_ERRNO(FLAGCARRIER) \
((S(u32,FLAGCARRIER) >> mx_CMD_ARG_DESC_ERRNO_SHIFT) &\
mx_CMD_ARG_DESC_ERRNO_MASK)
struct mx_cmd_arg_desc{
char cad_name[12]; /* Name of command */
u32 cad_no; /* Number of entries in cad_ent_flags */
/* [enum cmd_arg_desc_flags,arg-dep] */
u32 cad_ent_flags[VFIELD_SIZE(0)][2];
};
/* ISO C(99) does not allow initialization of "flex array" */
#define mx_CMD_ARG_DESC_SUBCLASS_DEF(CMD,NO,VAR) \
mx_CMD_ARG_DESC_SUBCLASS_DEF_NAME(CMD, su_STRING(CMD), NO, VAR)
#define mx_CMD_ARG_DESC_SUBCLASS_DEF_NAME(CMD,NAME,NO,VAR) \
static struct mx_cmd_arg_desc_ ## CMD {\
char cad_name[12];\
u32 cad_no;\
u32 cad_ent_flags[NO][2];\
} const VAR = { NAME "\0", NO,
#define mx_CMD_ARG_DESC_SUBCLASS_DEF_END }
#define mx_CMD_ARG_DESC_SUBCLASS_CAST(P) su_R(struct mx_cmd_arg_desc const*,P)
struct mx_cmd_arg_ctx{
struct mx_cmd_arg_desc const *cac_desc; /* Input: description of command */
char const *cac_indat; /* Input that shall be parsed */
uz cac_inlen; /* Input length (UZ_MAX: do a su_cs_len()) */
u32 cac_msgflag; /* Input (option): required flags of messages */
u32 cac_msgmask; /* Input (option): relevant flags of messages */
uz cac_no; /* Output: number of parsed arguments */
struct mx_cmd_arg *cac_arg; /* Output: parsed arguments */
char const *cac_vput; /* "Output": vput prefix used: varname */
};
struct mx_cmd_arg{
struct mx_cmd_arg *ca_next;
char const *ca_indat; /*[PRIV] Pointer into cmd_arg_ctx.cac_indat */
uz ca_inlen; /*[PRIV] of .ca_indat of this arg (no NUL) */
u32 ca_ent_flags[2]; /* Copy of cmd_arg_desc.cad_ent_flags[X] */
u32 ca_arg_flags; /* [Output: _WYSH: copy of parse result flags] */
u8 ca__dummy[4];
union{
struct str ca_str; /* _CMD_ARG_DESC_SHEXP */
int *ca_msglist; /* _CMD_ARG_DESC_MSGLIST+ */
} ca_arg; /* Output: parsed result */
};
struct mx_cmd_desc{
char const *cd_name; /* Name of command */
int (*cd_func)(void*); /* Implementor of command */
enum mx_cmd_arg_flags cd_caflags;
u32 cd_mflags_o_minargs; /* Message flags or min. args WYSH/WYRA/RAWLIST */
u32 cd_mmask_o_maxargs; /* Ditto, mask or max. args */
/* XXX requires cmd.h initializer changes u8 cd__pad[4];*/
struct mx_cmd_arg_desc const *cd_cadp;
#ifdef mx_HAVE_DOCSTRINGS
char const *cd_doc; /* One line doc for command */
#endif
};
/* Isolate the command from the arguments, return pointer to end of cmd name */
EXPORT char const *mx_cmd_isolate_name(char const *cmd);
/* Whether cmd is a valid command name (and not a modifier, for example) */
EXPORT boole mx_cmd_is_valid_name(char const *cmd);
/* First command which fits for cmd, or NULL */
EXPORT struct mx_cmd_desc const *mx_cmd_firstfit(char const *cmd);
/* Get the default command for the empty line */
EXPORT struct mx_cmd_desc const *mx_cmd_default(void);
/* Or NIL if cmd is invalid, or su_empty if !HAVE_DOCSTRINGS */
INLINE char const *mx_cmd_get_brief_doc(struct mx_cmd_desc const *cdp_or_nil){
char const *rv;
if(cdp_or_nil != NIL){
#ifdef mx_HAVE_DOCSTRINGS
rv = cdp_or_nil->cd_doc;
#else
rv = su_empty;
#endif
}else
rv = NIL;
return rv;
}
/* True if I/O succeeded (or nothing was printed).
* If fp is NIL we dump via err(), and return true. */
EXPORT boole mx_cmd_print_synopsis(struct mx_cmd_desc const *cdp_or_nil,
FILE *fp_or_nil);
/* Scan an entire command argument line, return whether result can be used,
* otherwise no resources are allocated (in ->cac_arg).
* For _WYSH arguments the flags _TRIM_SPACE (v15 _not_ _TRIM_IFSSPACE) and
* _LOG are implicit, _META_SEMICOLON is starting with the last (non-optional)
* argument, and then a trailing empty argument is ignored, too */
EXPORT boole mx_cmd_arg_parse(struct mx_cmd_arg_ctx *cacp);
/* Save away the data from autorec memory, and restore it to that.
* The heap storage is a single pointer to be n_free() by users */
EXPORT void *mx_cmd_arg_save_to_heap(struct mx_cmd_arg_ctx const *cacp);
EXPORT struct mx_cmd_arg_ctx *mx_cmd_arg_restore_from_heap(void *vp);
/* Scan out the list of string arguments according to rm, return -1 on error;
* res_dat is NULL terminated unless res_size is 0 or error occurred */
EXPORT int /* TODO v15*/ getrawlist(boole wysh, char **res_dat, uz res_size,
char const *line, uz linesize);
#include <su/code-ou.h>
#endif /* mx_CMD_H */
/* s-it-mode */
|