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