2 * Exports and types from dialog.c.
\r
6 * This will come in handy for generic control handlers. Anyone
\r
7 * knows how to make this more portable, let me know :-)
\r
9 #define ATOFFSET(data, offset) ( (void *) ( (char *)(data) + (offset) ) )
\r
12 * This is the big union which defines a single control, of any
\r
15 * General principles:
\r
16 * - _All_ pointers in this structure are expected to point to
\r
17 * dynamically allocated things, unless otherwise indicated.
\r
18 * - `char' fields giving keyboard shortcuts are expected to be
\r
19 * NO_SHORTCUT if no shortcut is desired for a particular control.
\r
20 * - The `label' field can often be NULL, which will cause the
\r
21 * control to not have a label at all. This doesn't apply to
\r
22 * checkboxes and push buttons, in which the label is not
\r
23 * separate from the control.
\r
26 #define NO_SHORTCUT '\0'
\r
29 CTRL_TEXT, /* just a static line of text */
\r
30 CTRL_EDITBOX, /* label plus edit box */
\r
31 CTRL_RADIO, /* label plus radio buttons */
\r
32 CTRL_CHECKBOX, /* checkbox (contains own label) */
\r
33 CTRL_BUTTON, /* simple push button (no label) */
\r
34 CTRL_LISTBOX, /* label plus list box */
\r
35 CTRL_COLUMNS, /* divide window into columns */
\r
36 CTRL_FILESELECT, /* label plus filename selector */
\r
37 CTRL_FONTSELECT, /* label plus font selector */
\r
38 CTRL_TABDELAY /* see `tabdelay' below */
\r
42 * Many controls have `intorptr' unions for storing user data,
\r
43 * since the user might reasonably want to store either an integer
\r
44 * or a void * pointer. Here I define a union, and two convenience
\r
45 * functions to create that union from actual integers or pointers.
\r
47 * The convenience functions are declared as inline if possible.
\r
48 * Otherwise, they're declared here and defined when this header is
\r
49 * included with DEFINE_INTORPTR_FNS defined. This is a total pain,
\r
52 typedef union { void *p; int i; } intorptr;
\r
56 intorptr P(void *p);
\r
59 #if defined DEFINE_INTORPTR_FNS || defined INLINE
\r
61 #define PREFIX INLINE
\r
65 PREFIX intorptr I(int i) { intorptr ret; ret.i = i; return ret; }
\r
66 PREFIX intorptr P(void *p) { intorptr ret; ret.p = p; return ret; }
\r
71 * Each control has an `int' field specifying which columns it
\r
72 * occupies in a multi-column part of the dialog box. These macros
\r
73 * pack and unpack that field.
\r
75 * If a control belongs in exactly one column, just specifying the
\r
76 * column number is perfectly adequate.
\r
78 #define COLUMN_FIELD(start, span) ( (((span)-1) << 16) + (start) )
\r
79 #define COLUMN_START(field) ( (field) & 0xFFFF )
\r
80 #define COLUMN_SPAN(field) ( (((field) >> 16) & 0xFFFF) + 1 )
\r
85 * The number of event types is being deliberately kept small, on
\r
86 * the grounds that not all platforms might be able to report a
\r
87 * large number of subtle events. We have:
\r
88 * - the special REFRESH event, called when a control's value
\r
90 * - the ACTION event, called when the user does something that
\r
91 * positively requests action (double-clicking a list box item,
\r
92 * or pushing a push-button)
\r
93 * - the VALCHANGE event, called when the user alters the setting
\r
94 * of the control in a way that is usually considered to alter
\r
95 * the underlying data (toggling a checkbox or radio button,
\r
96 * moving the items around in a drag-list, editing an edit
\r
98 * - the SELCHANGE event, called when the user alters the setting
\r
99 * of the control in a more minor way (changing the selected
\r
100 * item in a list box).
\r
101 * - the CALLBACK event, which happens after the handler routine
\r
102 * has requested a subdialog (file selector, font selector,
\r
103 * colour selector) and it has come back with information.
\r
112 typedef void (*handler_fn)(union control *ctrl, void *dlg,
\r
113 void *data, int event);
\r
115 #define STANDARD_PREFIX \
\r
120 handler_fn handler; \
\r
121 intorptr context; \
\r
126 * The first possibility in this union is the generic header
\r
127 * shared by all the structures, which we are therefore allowed
\r
128 * to access through any one of them.
\r
133 * Every control except CTRL_COLUMNS has _some_ sort of
\r
134 * label. By putting it in the `generic' union as well as
\r
135 * everywhere else, we avoid having to have an irritating
\r
136 * switch statement when we go through and deallocate all
\r
137 * the memory in a config-box structure.
\r
139 * Yes, this does mean that any non-NULL value in this
\r
140 * field is expected to be dynamically allocated and
\r
143 * For CTRL_COLUMNS, this field MUST be NULL.
\r
147 * If `tabdelay' is non-zero, it indicates that this
\r
148 * particular control should not yet appear in the tab
\r
149 * order. A subsequent CTRL_TABDELAY entry will place it.
\r
153 * Indicate which column(s) this control occupies. This can
\r
154 * be unpacked into starting column and column span by the
\r
155 * COLUMN macros above.
\r
159 * Most controls need to provide a function which gets
\r
160 * called when that control's setting is changed, or when
\r
161 * the control's setting needs initialising.
\r
163 * The `data' parameter points to the writable data being
\r
164 * modified as a result of the configuration activity; for
\r
165 * example, the PuTTY `Config' structure, although not
\r
168 * The `dlg' parameter is passed back to the platform-
\r
169 * specific routines to read and write the actual control
\r
172 handler_fn handler;
\r
174 * Almost all of the above functions will find it useful to
\r
175 * be able to store a piece of `void *' or `int' data.
\r
179 * For any control, we also allow the storage of a piece of
\r
180 * data for use by context-sensitive help. For example, on
\r
181 * Windows you can click the magic question mark and then
\r
182 * click a control, and help for that control should spring
\r
183 * up. Hence, here is a slot in which to store per-control
\r
184 * data that a particular platform-specific driver can use
\r
185 * to ensure it brings up the right piece of help text.
\r
191 union control *ctrl;
\r
198 char shortcut; /* keyboard shortcut */
\r
200 * Percentage of the dialog-box width used by the edit box.
\r
201 * If this is set to 100, the label is on its own line;
\r
202 * otherwise the label is on the same line as the box
\r
206 int password; /* details of input are hidden */
\r
208 * A special case of the edit box is the combo box, which
\r
209 * has a drop-down list built in. (Note that a _non_-
\r
210 * editable drop-down list is done as a special case of a
\r
213 * Don't try setting has_list and password on the same
\r
214 * control; front ends are not required to support that
\r
219 * Edit boxes tend to need two items of context, so here's
\r
227 * `shortcut' here is a single keyboard shortcut which is
\r
228 * expected to select the whole group of radio buttons. It
\r
229 * can be NO_SHORTCUT if required, and there is also a way
\r
230 * to place individual shortcuts on each button; see below.
\r
234 * There are separate fields for `ncolumns' and `nbuttons'
\r
235 * for several reasons.
\r
237 * Firstly, we sometimes want the last of a set of buttons
\r
238 * to have a longer label than the rest; we achieve this by
\r
239 * setting `ncolumns' higher than `nbuttons', and the
\r
240 * layout code is expected to understand that the final
\r
241 * button should be given all the remaining space on the
\r
242 * line. This sounds like a ludicrously specific special
\r
243 * case (if we're doing this sort of thing, why not have
\r
244 * the general ability to have a particular button span
\r
245 * more than one column whether it's the last one or not?)
\r
246 * but actually it's reasonably common for the sort of
\r
247 * three-way control you get a lot of in PuTTY: `yes'
\r
248 * versus `no' versus `some more complex way to decide'.
\r
250 * Secondly, setting `nbuttons' higher than `ncolumns' lets
\r
251 * us have more than one line of radio buttons for a single
\r
252 * setting. A very important special case of this is
\r
253 * setting `ncolumns' to 1, so that each button is on its
\r
259 * This points to a dynamically allocated array of `char *'
\r
260 * pointers, each of which points to a dynamically
\r
261 * allocated string.
\r
263 char **buttons; /* `nbuttons' button labels */
\r
265 * This points to a dynamically allocated array of `char'
\r
266 * giving the individual keyboard shortcuts for each radio
\r
267 * button. The array may be NULL if none are required.
\r
269 char *shortcuts; /* `nbuttons' shortcuts; may be NULL */
\r
271 * This points to a dynamically allocated array of
\r
272 * intorptr, giving helpful data for each button.
\r
274 intorptr *buttondata; /* `nbuttons' entries; may be NULL */
\r
284 * At least Windows has the concept of a `default push
\r
285 * button', which gets implicitly pressed when you hit
\r
286 * Return even if it doesn't have the input focus.
\r
290 * Also, the reverse of this: a default cancel-type button,
\r
291 * which is implicitly pressed when you hit Escape.
\r
297 char shortcut; /* keyboard shortcut */
\r
299 * Height of the list box, in approximate number of lines.
\r
300 * If this is zero, the list is a drop-down list.
\r
302 int height; /* height in lines */
\r
304 * If this is set, the list elements can be reordered by
\r
305 * the user (by drag-and-drop or by Up and Down buttons,
\r
306 * whatever the per-platform implementation feels
\r
307 * comfortable with). This is not guaranteed to work on a
\r
308 * drop-down list, so don't try it!
\r
312 * If this is non-zero, the list can have more than one
\r
313 * element selected at a time. This is not guaranteed to
\r
314 * work on a drop-down list, so don't try it!
\r
316 * Different non-zero values request slightly different
\r
317 * types of multi-selection (this may well be meaningful
\r
318 * only in GTK, so everyone else can ignore it if they
\r
319 * want). 1 means the list box expects to have individual
\r
320 * items selected, whereas 2 means it expects the user to
\r
321 * want to select a large contiguous range at a time.
\r
325 * Percentage of the dialog-box width used by the list box.
\r
326 * If this is set to 100, the label is on its own line;
\r
327 * otherwise the label is on the same line as the box
\r
328 * itself. Setting this to anything other than 100 is not
\r
329 * guaranteed to work on a _non_-drop-down list, so don't
\r
334 * Some list boxes contain strings that contain tab
\r
335 * characters. If `ncols' is greater than 0, then
\r
336 * `percentages' is expected to be non-zero and to contain
\r
337 * the respective widths of `ncols' columns, which together
\r
338 * will exactly fit the width of the list box. Otherwise
\r
339 * `percentages' must be NULL.
\r
341 * There should never be more than one column in a
\r
342 * drop-down list (one with height==0), because front ends
\r
343 * may have to implement it as a special case of an
\r
344 * editable combo box.
\r
346 int ncols; /* number of columns */
\r
347 int *percentages; /* % width of each column */
\r
353 * `filter' dictates what type of files will be selected by
\r
354 * default; for example, when selecting private key files
\r
355 * the file selector would do well to only show .PPK files
\r
356 * (on those systems where this is the chosen extension).
\r
358 * The precise contents of `filter' are platform-defined,
\r
359 * unfortunately. The special value NULL means `all files'
\r
360 * and is always a valid fallback.
\r
362 * Unlike almost all strings in this structure, this value
\r
363 * is NOT expected to require freeing (although of course
\r
364 * you can always use ctrl_alloc if you do need to create
\r
365 * one on the fly). This is because the likely mode of use
\r
366 * is to define string constants in a platform-specific
\r
367 * header file, and directly reference those. Or worse, a
\r
368 * particular platform might choose to cast integers into
\r
369 * this pointer type...
\r
371 char const *filter;
\r
373 * Some systems like to know whether a file selector is
\r
374 * choosing a file to read or one to write (and possibly
\r
379 * On at least some platforms, the file selector is a
\r
380 * separate dialog box, and contains a user-settable title.
\r
382 * This value _is_ expected to require freeing.
\r
387 /* In this variant, `label' MUST be NULL. */
\r
389 int ncols; /* number of columns */
\r
390 int *percentages; /* % width of each column */
\r
392 * Every time this control type appears, exactly one of
\r
393 * `ncols' and the previous number of columns MUST be one.
\r
394 * Attempting to allow a seamless transition from a four-
\r
395 * to a five-column layout, for example, would be way more
\r
396 * trouble than it was worth. If you must lay things out
\r
397 * like that, define eight unevenly sized columns and use
\r
398 * column-spanning a lot. But better still, just don't.
\r
400 * `percentages' may be NULL if ncols==1, to save space.
\r
409 #undef STANDARD_PREFIX
\r
412 * `controlset' is a container holding an array of `union control'
\r
413 * structures, together with a panel name and a title for the whole
\r
414 * set. In Windows and any similar-looking GUI, each `controlset'
\r
415 * in the config will be a container box within a panel.
\r
417 * Special case: if `boxname' is NULL, the control set gives an
\r
418 * overall title for an entire panel of controls.
\r
420 struct controlset {
\r
421 char *pathname; /* panel path, e.g. "SSH/Tunnels" */
\r
422 char *boxname; /* internal short name of controlset */
\r
423 char *boxtitle; /* title of container box */
\r
424 int ncolumns; /* current no. of columns at bottom */
\r
425 int ncontrols; /* number of `union control' in array */
\r
426 int ctrlsize; /* allocated size of array */
\r
427 union control **ctrls; /* actual array */
\r
431 * This is the container structure which holds a complete set of
\r
434 struct controlbox {
\r
435 int nctrlsets; /* number of ctrlsets */
\r
436 int ctrlsetsize; /* ctrlset size */
\r
437 struct controlset **ctrlsets; /* actual array of ctrlsets */
\r
440 void **frees; /* array of aux data areas to free */
\r
443 struct controlbox *ctrl_new_box(void);
\r
444 void ctrl_free_box(struct controlbox *);
\r
447 * Standard functions used for populating a controlbox structure.
\r
450 /* Set up a panel title. */
\r
451 struct controlset *ctrl_settitle(struct controlbox *,
\r
452 char *path, char *title);
\r
453 /* Retrieve a pointer to a controlset, creating it if absent. */
\r
454 struct controlset *ctrl_getset(struct controlbox *,
\r
455 char *path, char *name, char *boxtitle);
\r
456 void ctrl_free_set(struct controlset *);
\r
458 void ctrl_free(union control *);
\r
461 * This function works like `malloc', but the memory it returns
\r
462 * will be automatically freed when the controlbox is freed. Note
\r
463 * that a controlbox is a dialog-box _template_, not an instance,
\r
464 * and so data allocated through this function is better not used
\r
465 * to hold modifiable per-instance things. It's mostly here for
\r
466 * allocating structures to be passed as control handler params.
\r
468 void *ctrl_alloc(struct controlbox *b, size_t size);
\r
471 * Individual routines to create `union control' structures in a controlset.
\r
473 * Most of these routines allow the most common fields to be set
\r
474 * directly, and put default values in the rest. Each one returns a
\r
475 * pointer to the `union control' it created, so that final tweaks
\r
479 /* `ncolumns' is followed by that many percentages, as integers. */
\r
480 union control *ctrl_columns(struct controlset *, int ncolumns, ...);
\r
481 union control *ctrl_editbox(struct controlset *, char *label, char shortcut,
\r
482 int percentage, intorptr helpctx,
\r
483 handler_fn handler,
\r
484 intorptr context, intorptr context2);
\r
485 union control *ctrl_combobox(struct controlset *, char *label, char shortcut,
\r
486 int percentage, intorptr helpctx,
\r
487 handler_fn handler,
\r
488 intorptr context, intorptr context2);
\r
490 * `ncolumns' is followed by (alternately) radio button titles and
\r
491 * intorptrs, until a NULL in place of a title string is seen. Each
\r
492 * title is expected to be followed by a shortcut _iff_ `shortcut'
\r
495 union control *ctrl_radiobuttons(struct controlset *, char *label,
\r
496 char shortcut, int ncolumns,
\r
498 handler_fn handler, intorptr context, ...);
\r
499 union control *ctrl_pushbutton(struct controlset *,char *label,char shortcut,
\r
501 handler_fn handler, intorptr context);
\r
502 union control *ctrl_listbox(struct controlset *,char *label,char shortcut,
\r
504 handler_fn handler, intorptr context);
\r
505 union control *ctrl_droplist(struct controlset *, char *label, char shortcut,
\r
506 int percentage, intorptr helpctx,
\r
507 handler_fn handler, intorptr context);
\r
508 union control *ctrl_draglist(struct controlset *,char *label,char shortcut,
\r
510 handler_fn handler, intorptr context);
\r
511 union control *ctrl_filesel(struct controlset *,char *label,char shortcut,
\r
512 char const *filter, int write, char *title,
\r
514 handler_fn handler, intorptr context);
\r
515 union control *ctrl_fontsel(struct controlset *,char *label,char shortcut,
\r
517 handler_fn handler, intorptr context);
\r
518 union control *ctrl_text(struct controlset *, char *text, intorptr helpctx);
\r
519 union control *ctrl_checkbox(struct controlset *, char *label, char shortcut,
\r
521 handler_fn handler, intorptr context);
\r
522 union control *ctrl_tabdelay(struct controlset *, union control *);
\r
525 * Standard handler routines to cover most of the common cases in
\r
529 * The standard radio-button handler expects the main `context'
\r
530 * field to contain the `offsetof' of an int field in the structure
\r
531 * pointed to by `data', and expects each of the individual button
\r
532 * data to give a value for that int field.
\r
534 void dlg_stdradiobutton_handler(union control *ctrl, void *dlg,
\r
535 void *data, int event);
\r
537 * The standard checkbox handler expects the main `context' field
\r
538 * to contain the `offsetof' an int field in the structure pointed
\r
539 * to by `data', optionally ORed with CHECKBOX_INVERT to indicate
\r
540 * that the sense of the datum is opposite to the sense of the
\r
543 #define CHECKBOX_INVERT (1<<30)
\r
544 void dlg_stdcheckbox_handler(union control *ctrl, void *dlg,
\r
545 void *data, int event);
\r
547 * The standard edit-box handler expects the main `context' field
\r
548 * to contain the `offsetof' a field in the structure pointed to by
\r
549 * `data'. The secondary `context2' field indicates the type of
\r
552 * - if context2 > 0, the field is a char array and context2 gives
\r
554 * - if context2 == -1, the field is an int and the edit box is
\r
556 * - if context2 < -1, the field is an int and the edit box is
\r
557 * _floating_, and (-context2) gives the scale. (E.g. if
\r
558 * context2 == -1000, then typing 1.2 into the box will set the
\r
561 void dlg_stdeditbox_handler(union control *ctrl, void *dlg,
\r
562 void *data, int event);
\r
564 * The standard file-selector handler expects the main `context'
\r
565 * field to contain the `offsetof' a Filename field in the
\r
566 * structure pointed to by `data'.
\r
568 void dlg_stdfilesel_handler(union control *ctrl, void *dlg,
\r
569 void *data, int event);
\r
571 * The standard font-selector handler expects the main `context'
\r
572 * field to contain the `offsetof' a Font field in the structure
\r
573 * pointed to by `data'.
\r
575 void dlg_stdfontsel_handler(union control *ctrl, void *dlg,
\r
576 void *data, int event);
\r
579 * Routines the platform-independent dialog code can call to read
\r
580 * and write the values of controls.
\r
582 void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton);
\r
583 int dlg_radiobutton_get(union control *ctrl, void *dlg);
\r
584 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked);
\r
585 int dlg_checkbox_get(union control *ctrl, void *dlg);
\r
586 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text);
\r
587 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length);
\r
588 /* The `listbox' functions can also apply to combo boxes. */
\r
589 void dlg_listbox_clear(union control *ctrl, void *dlg);
\r
590 void dlg_listbox_del(union control *ctrl, void *dlg, int index);
\r
591 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text);
\r
593 * Each listbox entry may have a numeric id associated with it.
\r
594 * Note that some front ends only permit a string to be stored at
\r
595 * each position, which means that _if_ you put two identical
\r
596 * strings in any listbox then you MUST not assign them different
\r
597 * IDs and expect to get meaningful results back.
\r
599 void dlg_listbox_addwithid(union control *ctrl, void *dlg,
\r
600 char const *text, int id);
\r
601 int dlg_listbox_getid(union control *ctrl, void *dlg, int index);
\r
602 /* dlg_listbox_index returns <0 if no single element is selected. */
\r
603 int dlg_listbox_index(union control *ctrl, void *dlg);
\r
604 int dlg_listbox_issel(union control *ctrl, void *dlg, int index);
\r
605 void dlg_listbox_select(union control *ctrl, void *dlg, int index);
\r
606 void dlg_text_set(union control *ctrl, void *dlg, char const *text);
\r
607 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn);
\r
608 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn);
\r
609 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn);
\r
610 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn);
\r
612 * Bracketing a large set of updates in these two functions will
\r
613 * cause the front end (if possible) to delay updating the screen
\r
614 * until it's all complete, thus avoiding flicker.
\r
616 void dlg_update_start(union control *ctrl, void *dlg);
\r
617 void dlg_update_done(union control *ctrl, void *dlg);
\r
619 * Set input focus into a particular control.
\r
621 void dlg_set_focus(union control *ctrl, void *dlg);
\r
623 * Change the label text on a control.
\r
625 void dlg_label_change(union control *ctrl, void *dlg, char const *text);
\r
627 * Return the `ctrl' structure for the most recent control that had
\r
628 * the input focus apart from the one mentioned. This is NOT
\r
629 * GUARANTEED to work on all platforms, so don't base any critical
\r
630 * functionality on it!
\r
632 union control *dlg_last_focused(union control *ctrl, void *dlg);
\r
634 * During event processing, you might well want to give an error
\r
635 * indication to the user. dlg_beep() is a quick and easy generic
\r
636 * error; dlg_error() puts up a message-box or equivalent.
\r
638 void dlg_beep(void *dlg);
\r
639 void dlg_error_msg(void *dlg, char *msg);
\r
641 * This function signals to the front end that the dialog's
\r
642 * processing is completed, and passes an integer value (typically
\r
643 * a success status).
\r
645 void dlg_end(void *dlg, int value);
\r
648 * Routines to manage a (per-platform) colour selector.
\r
649 * dlg_coloursel_start() is called in an event handler, and
\r
650 * schedules the running of a colour selector after the event
\r
651 * handler returns. The colour selector will send EVENT_CALLBACK to
\r
652 * the control that spawned it, when it's finished;
\r
653 * dlg_coloursel_results() fetches the results, as integers from 0
\r
654 * to 255; it returns nonzero on success, or zero if the colour
\r
655 * selector was dismissed by hitting Cancel or similar.
\r
657 * dlg_coloursel_start() accepts an RGB triple which is used to
\r
658 * initialise the colour selector to its starting value.
\r
660 void dlg_coloursel_start(union control *ctrl, void *dlg,
\r
661 int r, int g, int b);
\r
662 int dlg_coloursel_results(union control *ctrl, void *dlg,
\r
663 int *r, int *g, int *b);
\r
666 * This routine is used by the platform-independent code to
\r
667 * indicate that the value of a particular control is likely to
\r
668 * have changed. It triggers a call of the handler for that control
\r
669 * with `event' set to EVENT_REFRESH.
\r
671 * If `ctrl' is NULL, _all_ controls in the dialog get refreshed
\r
672 * (for loading or saving entire sets of settings).
\r
674 void dlg_refresh(union control *ctrl, void *dlg);
\r
677 * It's perfectly possible that individual controls might need to
\r
678 * allocate or store per-dialog-instance data, so here's a
\r
681 * `dlg_get_privdata' and `dlg_set_privdata' allow the user to get
\r
682 * and set a void * pointer associated with the control in
\r
683 * question. `dlg_alloc_privdata' will allocate memory, store a
\r
684 * pointer to that memory in the private data field, and arrange
\r
685 * for it to be automatically deallocated on dialog cleanup.
\r
687 void *dlg_get_privdata(union control *ctrl, void *dlg);
\r
688 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr);
\r
689 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size);
\r
692 * Standard helper functions for reading a controlbox structure.
\r
696 * Find the index of next controlset in a controlbox for a given
\r
697 * path, or -1 if no such controlset exists. If -1 is passed as
\r
698 * input, finds the first. Intended usage is something like
\r
700 * for (index=-1; (index=ctrl_find_path(ctrlbox, index, path)) >= 0 ;) {
\r
701 * ... process this controlset ...
\r
704 int ctrl_find_path(struct controlbox *b, char *path, int index);
\r
705 int ctrl_path_elements(char *path);
\r
706 /* Return the number of matching path elements at the starts of p1 and p2,
\r
707 * or INT_MAX if the paths are identical. */
\r
708 int ctrl_path_compare(char *p1, char *p2);
\r