1 /* (C) Copyright 2002, 2003, 2004, 2005, 2006 Stijn van Dongen 2 * (C) Copyright 2007, 2008, 2009, 2010 Stijn van Dongen 3 * 4 * This file is part of tingea. You can redistribute and/or modify tingea 5 * under the terms of the GNU General Public License; either version 3 of the 6 * License or (at your option) any later version. You should have received a 7 * copy of the GPL along with tingea, in the file COPYING. 8 */ 9 10 11 /* TODO 12 * recode dispatch case 'no arguments supplied'. now ugly. 13 */ 14 15 #ifndef tingea_opt_h 16 #define tingea_opt_h 17 18 #include "types.h" 19 #include "ting.h" 20 #include "hash.h" 21 22 23 /* ************************************************************************** 24 * * 25 ** Implementation notes (a few). 26 * 27 * This interface munges and parses text presented to it, and creates 28 * arrays and optionally hashes from them. It does so by simply storing 29 * pointers to the data presented to it, and does not copy anything at all. 30 * 31 * It is the callers job to make sure that the data scrutinized by this 32 * interface stays constant during interface usage. 33 * 34 * Tentatively, this interface treats -I 3 and --I=3 as equivalent 35 * syntax. It is possible to define -I and --I= as separate options. 36 * (by defining -I with MCX_OPT_HASARG and --I with MCX_OPT_DEFAULT). 37 * 38 * TODO: 39 * implement newline/indent magic in option descriptions. 40 * 41 * The prefix thing, is it necessary? caller could pass argv+prefix .. 42 */ 43 44 #define MCX_OPT_DEFAULT 0 /* -a, xyz */ 45 #define MCX_OPT_HASARG 1 /* -a 10, xyz foo */ 46 #define MCX_OPT_REQUIRED 2 47 #define MCX_OPT_INFO 4 48 #define MCX_OPT_HIDDEN 16 49 #define MCX_OPT_UNUSED 32 50 51 52 enum 53 { MCX_OPT_STATUS_OK = 0 54 , MCX_OPT_STATUS_NOARG 55 , MCX_OPT_STATUS_UNKNOWN 56 , MCX_OPT_STATUS_NOMEM 57 } ; 58 59 60 /* struct mcxOptAnchor 61 * 62 * id 63 * When using mcxOptApropos, if the option MCX_OPT_DISPLAY_SKIP is used, 64 * an increment larger then one between successive ids (from the structs 65 * in the array presented to mcxOptApropos) causes an additional newline 66 * to be output before the option synopsis. 67 * This enables the creation of paragraphs in a simple manner. 68 * 69 * descr_usage 70 * By default, this just contains the description of what the option does 71 * It is possible to specify a mark to be printed in front of that 72 * description. This requires both the mark and the description 73 * (which are joined in the same string) to be proceded by a special 74 * sequence. For the mark this is "\tM" and for the description 75 * this is "\tD". The description string should be last. A valid entry is 76 * thus 77 * "\tM!\tDset the resource scheme" 78 * This will print the marker '!' inbetween the option tag and its 79 * description. 80 * 81 * Presumably, the legend to such markers is explained by the caller. 82 */ 83 84 typedef struct mcxOptAnchor 85 { char* tag /* '-foo' or '--expand-only' etc */ 86 ; int flags /* MCX_OPT_HASARG etc */ 87 ; int id /* ID */ 88 ; char* descr_arg /* "<fname>" or "<num>", NULL ok */ 89 ; char* descr_usage /* NULL allowed */ 90 ; 91 } mcxOptAnchor ; 92 93 94 void mcxOptAnchorSortByTag 95 ( mcxOptAnchor *anchors 96 , dim n_anchors 97 ) ; 98 99 100 void mcxOptAnchorSortById 101 ( mcxOptAnchor *anchors 102 , dim n_anchors 103 ) ; 104 105 106 /* 107 * An array of these is returned by parse routines below. 108 * An entry with .anch == NULL indicates end-of-array. 109 */ 110 111 typedef struct mcxOption 112 { mcxOptAnchor* anch 113 ; const char* val 114 ; 115 } mcxOption ; 116 117 118 119 /* 120 * these routines only use status MCX_OPT_NOARG. The interface 121 * is not yet frozen. 122 */ 123 124 /* This tries to find as many arguments as it can, and reports the 125 * number of array elements it skipped. 126 */ 127 128 mcxOption* mcxOptExhaust 129 ( mcxOptAnchor* anch 130 , char** argv 131 , int argc 132 , int prefix /* skip these */ 133 , int* n_elems_read 134 , mcxstatus* status 135 ) ; 136 137 138 /* This will never read past the last arguments (suffix of them). 139 * It does currently not enforce that the number of arguments left 140 * is exactly equal to suffix (fixme?). 141 */ 142 143 mcxOption* mcxOptParse 144 ( mcxOptAnchor* anch 145 , char** argv 146 , int argc 147 , int prefix /* skip these */ 148 , int suffix /* skip those too */ 149 , mcxstatus* status 150 ) ; 151 152 153 void mcxOptFree 154 ( mcxOption** optpp 155 ) ; 156 157 mcxbool mcxOptIsInfo 158 ( const char* arg 159 , mcxOptAnchor* options 160 ) ; 161 162 #define MCX_OPT_DISPLAY_DEFAULT 0 163 #define MCX_OPT_DISPLAY_BREAK_HARD 1 << 4 /* break overly long lines */ 164 #define MCX_OPT_DISPLAY_BREAK_SOFT 1 << 6 /* break overly long lines */ 165 #define MCX_OPT_DISPLAY_CAPTION 1 << 10 /* break after option */ 166 #define MCX_OPT_DISPLAY_PAR 1 << 12 /* ? useful ? paragraph mode */ 167 #define MCX_OPT_DISPLAY_SKIP 1 << 14 /* display enum skips as pars */ 168 #define MCX_OPT_DISPLAY_HIDDEN 1 << 16 /* do that */ 169 170 171 void mcxOptApropos 172 ( FILE* fp 173 , const char* me /* unused currently */ 174 , const char* syntax 175 , int width 176 , mcxbits display 177 , const mcxOptAnchor opt[] 178 ) ; 179 180 181 /* The ones below are for spreading responsibility for parsing 182 * argument over different modules. 183 * See the mcl implementation for an example. 184 */ 185 186 mcxOption* mcxHOptExhaust 187 ( mcxHash* opthash 188 , char** argv 189 , int argc 190 , int prefix /* skip these */ 191 , int* n_elems_read 192 , mcxstatus* status 193 ) ; 194 195 mcxOption* mcxHOptParse 196 ( mcxHash* opthash 197 , char** argv 198 , int argc 199 , int prefix /* skip these */ 200 , int suffix /* skip those too */ 201 , mcxstatus* status 202 ) ; 203 204 205 /* 206 * Creates a hash where the tag string is key, and the mcxOptAnchor is value. 207 */ 208 209 mcxHash* mcxOptHash 210 ( mcxOptAnchor* opts 211 , mcxHash* hash 212 ) ; 213 214 void mcxOptHashFree 215 ( mcxHash** hashpp 216 ) ; 217 218 mcxOptAnchor* mcxOptFind 219 ( char* tag 220 , mcxHash* hopts 221 ) ; 222 223 void mcxUsage 224 ( FILE* fp 225 , const char* caller 226 , const char** lines 227 ) ; 228 229 230 extern int mcxOptPrintDigits; 231 232 mcxbool mcxOptCheckBounds 233 ( const char* caller 234 , const char* flag 235 , unsigned char type 236 , void* var 237 , int (*lftRlt) (const void*, const void*) 238 , void* lftBound 239 , int (*rgtRlt) (const void*, const void*) 240 , void* rgtBound 241 ) ; 242 243 244 /* TODO 245 * provide escape mechanisms for delim; 246 * e.g. mcx tilde, UNIX backslash, or SGML percent sign based. 247 * -> smarter space-based separation. whitespace ? 248 * 249 * NOTE 250 * Separates on spaces, which are replaced with '\0'. 251 * src is modified ('\0' are written throughout). 252 * the char* members 'char* argv[]' all point to within src. 253 */ 254 255 char** mcxOptParseString 256 ( char* src 257 , int* argc 258 , unsigned char delim 259 ) ; 260 261 mcxTing* mcxOptArgLine 262 ( const char** argv 263 , int argc 264 , int quote /* '[' or '"' */ 265 ) ; 266 267 268 269 /* 270 * Severely undocumented stuff, but quite useful. 271 * This is used to write a program that 272 * - takes modes, e.g. 'clm dist' 'clm info' 'clm meet' 273 * - has a set of shared options 274 * - allows modes to have their own unique set of options 275 * - Program and mode options are not separated by the mode, 276 * but all are specified after the mode. 277 * Look at htpp://micans.org/mcl/src/mcl-latest/src/shcl/clm.c 278 * htpp://micans.org/mcl/src/mcl-latest/src/shmx/mcx.c 279 * for two fully functioning examples. 280 */ 281 282 #define MCX_DISP_DEFAULT 0 283 #define MCX_DISP_HIDDEN 1 284 #define MCX_DISP_MANUAL 2 285 286 typedef struct 287 { const char* name 288 ; const char* syntax 289 ; mcxOptAnchor* options 290 ; int n_options 291 ; mcxstatus (*arg_cb)(int optid, const char* val) 292 ; mcxstatus (*init)( void ) 293 ; mcxstatus (*main)(int argc, const char* argv[]) 294 ; int n_at_least /* trailing arguments */ 295 ; int n_at_most /* trailing arguments */ 296 ; mcxbits flags 297 ; 298 } mcxDispHook ; 299 300 301 typedef struct 302 { int id 303 ; mcxDispHook* (*get_hk)(void) 304 ; 305 } mcxDispEntry ; 306 307 308 309 typedef struct mcx_disp_bundle 310 { int disp_argc 311 ; const char** disp_argv 312 ; const char* disp_name 313 ; const char* disp_syntax 314 ; mcxOptAnchor* disp_shared 315 ; dim n_disp_shared 316 ; mcxstatus (*shared_handler)(int optid, const char* val, mcxDispHook*, struct mcx_disp_bundle*) 317 ; void (*disp_version)(const char* me) 318 ; mcxDispEntry* disp_table 319 ; 320 } mcxDispBundle ; 321 322 323 int mcxDispatch 324 ( mcxDispBundle* bundle 325 ) ; 326 327 328 #endif 329 330