options-table.c revision 1.34
1/* $OpenBSD: options-table.c,v 1.34 2013/03/24 09:21:27 nicm Exp $ */
2
3/*
4 * Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <string.h>
22#include <paths.h>
23
24#include "tmux.h"
25
26/*
27 * This file has a tables with all the server, session and window
28 * options. These tables are the master copy of the options with their real
29 * (user-visible) types, range limits and default values. At start these are
30 * copied into the runtime global options trees (which only has number and
31 * string types). These tables are then used to loop up the real type when
32 * the user sets an option or its value needs to be shown.
33 */
34
35/* Choice option type lists. */
36const char *options_table_mode_keys_list[] = {
37	"emacs", "vi", NULL
38};
39const char *options_table_mode_mouse_list[] = {
40	"off", "on", "copy-mode", NULL
41};
42const char *options_table_clock_mode_style_list[] = {
43	"12", "24", NULL
44};
45const char *options_table_status_keys_list[] = {
46	"emacs", "vi", NULL
47};
48const char *options_table_status_justify_list[] = {
49	"left", "centre", "right", NULL
50};
51const char *options_table_status_position_list[] = {
52	"top", "bottom", NULL
53};
54const char *options_table_bell_action_list[] = {
55	"none", "any", "current", NULL
56};
57
58/* Server options. */
59const struct options_table_entry server_options_table[] = {
60	{ .name = "buffer-limit",
61	  .type = OPTIONS_TABLE_NUMBER,
62	  .minimum = 1,
63	  .maximum = INT_MAX,
64	  .default_num = 20
65	},
66
67	{ .name = "escape-time",
68	  .type = OPTIONS_TABLE_NUMBER,
69	  .minimum = 0,
70	  .maximum = INT_MAX,
71	  .default_num = 500
72	},
73
74	{ .name = "exit-unattached",
75	  .type = OPTIONS_TABLE_FLAG,
76	  .default_num = 0
77	},
78
79	{ .name = "quiet",
80	  .type = OPTIONS_TABLE_FLAG,
81	  .default_num = 0 /* overridden in main() */
82	},
83
84	{ .name = "set-clipboard",
85	  .type = OPTIONS_TABLE_FLAG,
86	  .default_num = 1
87	},
88
89	{ .name = NULL }
90};
91
92/* Session options. */
93const struct options_table_entry session_options_table[] = {
94	{ .name = "assume-paste-time",
95	  .type = OPTIONS_TABLE_NUMBER,
96	  .minimum = 0,
97	  .maximum = INT_MAX,
98	  .default_num = 1,
99	},
100
101	{ .name = "base-index",
102	  .type = OPTIONS_TABLE_NUMBER,
103	  .minimum = 0,
104	  .maximum = INT_MAX,
105	  .default_num = 0
106	},
107
108	{ .name = "bell-action",
109	  .type = OPTIONS_TABLE_CHOICE,
110	  .choices = options_table_bell_action_list,
111	  .default_num = BELL_ANY
112	},
113
114	{ .name = "bell-on-alert",
115	  .type = OPTIONS_TABLE_FLAG,
116	  .default_num = 0
117	},
118
119	{ .name = "default-command",
120	  .type = OPTIONS_TABLE_STRING,
121	  .default_str = ""
122	},
123
124	{ .name = "default-path",
125	  .type = OPTIONS_TABLE_STRING,
126	  .default_str = ""
127	},
128
129	{ .name = "default-shell",
130	  .type = OPTIONS_TABLE_STRING,
131	  .default_str = _PATH_BSHELL
132	},
133
134	{ .name = "default-terminal",
135	  .type = OPTIONS_TABLE_STRING,
136	  .default_str = "screen"
137	},
138
139	{ .name = "destroy-unattached",
140	  .type = OPTIONS_TABLE_FLAG,
141	  .default_num = 0
142	},
143
144	{ .name = "detach-on-destroy",
145	  .type = OPTIONS_TABLE_FLAG,
146	  .default_num = 1
147	},
148
149	{ .name = "display-panes-active-colour",
150	  .type = OPTIONS_TABLE_COLOUR,
151	  .default_num = 1
152	},
153
154	{ .name = "display-panes-colour",
155	  .type = OPTIONS_TABLE_COLOUR,
156	  .default_num = 4
157	},
158
159	{ .name = "display-panes-time",
160	  .type = OPTIONS_TABLE_NUMBER,
161	  .minimum = 1,
162	  .maximum = INT_MAX,
163	  .default_num = 1000
164	},
165
166	{ .name = "display-time",
167	  .type = OPTIONS_TABLE_NUMBER,
168	  .minimum = 1,
169	  .maximum = INT_MAX,
170	  .default_num = 750
171	},
172
173	{ .name = "history-limit",
174	  .type = OPTIONS_TABLE_NUMBER,
175	  .minimum = 0,
176	  .maximum = INT_MAX,
177	  .default_num = 2000
178	},
179
180	{ .name = "lock-after-time",
181	  .type = OPTIONS_TABLE_NUMBER,
182	  .minimum = 0,
183	  .maximum = INT_MAX,
184	  .default_num = 0
185	},
186
187	{ .name = "lock-command",
188	  .type = OPTIONS_TABLE_STRING,
189	  .default_str = "lock -np"
190	},
191
192	{ .name = "lock-server",
193	  .type = OPTIONS_TABLE_FLAG,
194	  .default_num = 1
195	},
196
197	{ .name = "message-attr",
198	  .type = OPTIONS_TABLE_ATTRIBUTES,
199	  .default_num = 0
200	},
201
202	{ .name = "message-bg",
203	  .type = OPTIONS_TABLE_COLOUR,
204	  .default_num = 3
205	},
206
207	{ .name = "message-command-attr",
208	  .type = OPTIONS_TABLE_ATTRIBUTES,
209	  .default_num = 0
210	},
211
212	{ .name = "message-command-bg",
213	  .type = OPTIONS_TABLE_COLOUR,
214	  .default_num = 0
215	},
216
217	{ .name = "message-command-fg",
218	  .type = OPTIONS_TABLE_COLOUR,
219	  .default_num = 3
220	},
221
222	{ .name = "message-fg",
223	  .type = OPTIONS_TABLE_COLOUR,
224	  .default_num = 0
225	},
226
227	{ .name = "message-limit",
228	  .type = OPTIONS_TABLE_NUMBER,
229	  .minimum = 0,
230	  .maximum = INT_MAX,
231	  .default_num = 20
232	},
233
234	{ .name = "mouse-resize-pane",
235	  .type = OPTIONS_TABLE_FLAG,
236	  .default_num = 0
237	},
238
239	{ .name = "mouse-select-pane",
240	  .type = OPTIONS_TABLE_FLAG,
241	  .default_num = 0
242	},
243
244	{ .name = "mouse-select-window",
245	  .type = OPTIONS_TABLE_FLAG,
246	  .default_num = 0
247	},
248
249	{ .name = "mouse-utf8",
250	  .type = OPTIONS_TABLE_FLAG,
251	  .default_num = 0
252	},
253
254	{ .name = "pane-active-border-bg",
255	  .type = OPTIONS_TABLE_COLOUR,
256	  .default_num = 8
257	},
258
259	{ .name = "pane-active-border-fg",
260	  .type = OPTIONS_TABLE_COLOUR,
261	  .default_num = 2
262	},
263
264	{ .name = "pane-border-bg",
265	  .type = OPTIONS_TABLE_COLOUR,
266	  .default_num = 8
267	},
268
269	{ .name = "pane-border-fg",
270	  .type = OPTIONS_TABLE_COLOUR,
271	  .default_num = 8
272	},
273
274	{ .name = "prefix",
275	  .type = OPTIONS_TABLE_KEY,
276	  .default_num = '\002',
277	},
278
279	{ .name = "prefix2",
280	  .type = OPTIONS_TABLE_KEY,
281	  .default_num = KEYC_NONE,
282	},
283
284	{ .name = "renumber-windows",
285	  .type = OPTIONS_TABLE_FLAG,
286	  .default_num = 0
287	},
288
289	{ .name = "repeat-time",
290	  .type = OPTIONS_TABLE_NUMBER,
291	  .minimum = 0,
292	  .maximum = SHRT_MAX,
293	  .default_num = 500
294	},
295
296	{ .name = "set-remain-on-exit",
297	  .type = OPTIONS_TABLE_FLAG,
298	  .default_num = 0
299	},
300
301	{ .name = "set-titles",
302	  .type = OPTIONS_TABLE_FLAG,
303	  .default_num = 0
304	},
305
306	{ .name = "set-titles-string",
307	  .type = OPTIONS_TABLE_STRING,
308	  .default_str = "#S:#I:#W - \"#T\""
309	},
310
311	{ .name = "status",
312	  .type = OPTIONS_TABLE_FLAG,
313	  .default_num = 1
314	},
315
316	{ .name = "status-attr",
317	  .type = OPTIONS_TABLE_ATTRIBUTES,
318	  .default_num = 0
319	},
320
321	{ .name = "status-bg",
322	  .type = OPTIONS_TABLE_COLOUR,
323	  .default_num = 2
324	},
325
326	{ .name = "status-fg",
327	  .type = OPTIONS_TABLE_COLOUR,
328	  .default_num = 0
329	},
330
331	{ .name = "status-interval",
332	  .type = OPTIONS_TABLE_NUMBER,
333	  .minimum = 0,
334	  .maximum = INT_MAX,
335	  .default_num = 15
336	},
337
338	{ .name = "status-justify",
339	  .type = OPTIONS_TABLE_CHOICE,
340	  .choices = options_table_status_justify_list,
341	  .default_num = 0
342	},
343
344	{ .name = "status-keys",
345	  .type = OPTIONS_TABLE_CHOICE,
346	  .choices = options_table_status_keys_list,
347	  .default_num = MODEKEY_EMACS
348	},
349
350	{ .name = "status-left",
351	  .type = OPTIONS_TABLE_STRING,
352	  .default_str = "[#S]"
353	},
354
355	{ .name = "status-left-attr",
356	  .type = OPTIONS_TABLE_ATTRIBUTES,
357	  .default_num = 0
358	},
359
360	{ .name = "status-left-bg",
361	  .type = OPTIONS_TABLE_COLOUR,
362	  .default_num = 8
363	},
364
365	{ .name = "status-left-fg",
366	  .type = OPTIONS_TABLE_COLOUR,
367	  .default_num = 8
368	},
369
370	{ .name = "status-left-length",
371	  .type = OPTIONS_TABLE_NUMBER,
372	  .minimum = 0,
373	  .maximum = SHRT_MAX,
374	  .default_num = 10
375	},
376
377	{ .name = "status-position",
378	  .type = OPTIONS_TABLE_CHOICE,
379	  .choices = options_table_status_position_list,
380	  .default_num = 1
381	},
382
383	{ .name = "status-right",
384	  .type = OPTIONS_TABLE_STRING,
385	  .default_str = "\"#22T\" %H:%M %d-%b-%y"
386	},
387
388	{ .name = "status-right-attr",
389	  .type = OPTIONS_TABLE_ATTRIBUTES,
390	  .default_num = 0
391	},
392
393	{ .name = "status-right-bg",
394	  .type = OPTIONS_TABLE_COLOUR,
395	  .default_num = 8
396	},
397
398	{ .name = "status-right-fg",
399	  .type = OPTIONS_TABLE_COLOUR,
400	  .default_num = 8
401	},
402
403	{ .name = "status-right-length",
404	  .type = OPTIONS_TABLE_NUMBER,
405	  .minimum = 0,
406	  .maximum = SHRT_MAX,
407	  .default_num = 40
408	},
409
410	{ .name = "status-utf8",
411	  .type = OPTIONS_TABLE_FLAG,
412	  .default_num = 0 /* overridden in main() */
413	},
414
415	{ .name = "terminal-overrides",
416	  .type = OPTIONS_TABLE_STRING,
417	  .default_str = "*88col*:colors=88,*256col*:colors=256"
418	                 ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
419	                 ":Cc=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
420			 ":Cs=\\E[%p1%d q:Csr=\\E[2 q,screen*:XT"
421	},
422
423	{ .name = "update-environment",
424	  .type = OPTIONS_TABLE_STRING,
425	  .default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID "
426	                 "SSH_CONNECTION WINDOWID XAUTHORITY"
427
428	},
429
430	{ .name = "visual-activity",
431	  .type = OPTIONS_TABLE_FLAG,
432	  .default_num = 0
433	},
434
435	{ .name = "visual-bell",
436	  .type = OPTIONS_TABLE_FLAG,
437	  .default_num = 0
438	},
439
440	{ .name = "visual-content",
441	  .type = OPTIONS_TABLE_FLAG,
442	  .default_num = 0
443	},
444
445	{ .name = "visual-silence",
446	  .type = OPTIONS_TABLE_FLAG,
447	  .default_num = 0
448	},
449
450	{ .name = "word-separators",
451	  .type = OPTIONS_TABLE_STRING,
452	  .default_str = " -_@"
453	},
454
455	{ .name = NULL }
456};
457
458/* Window options. */
459const struct options_table_entry window_options_table[] = {
460	{ .name = "aggressive-resize",
461	  .type = OPTIONS_TABLE_FLAG,
462	  .default_num = 0
463	},
464
465	{ .name = "allow-rename",
466	  .type = OPTIONS_TABLE_FLAG,
467	  .default_num = 1
468	},
469
470	{ .name = "alternate-screen",
471	  .type = OPTIONS_TABLE_FLAG,
472	  .default_num = 1
473	},
474
475	{ .name = "automatic-rename",
476	  .type = OPTIONS_TABLE_FLAG,
477	  .default_num = 1
478	},
479
480	{ .name = "c0-change-trigger",
481	  .type = OPTIONS_TABLE_NUMBER,
482	  .default_num = 250,
483	  .minimum = 0,
484	  .maximum = USHRT_MAX
485	},
486
487	{ .name = "c0-change-interval",
488	  .type = OPTIONS_TABLE_NUMBER,
489	  .default_num = 100,
490	  .minimum = 1,
491	  .maximum = USHRT_MAX
492	},
493
494	{ .name = "clock-mode-colour",
495	  .type = OPTIONS_TABLE_COLOUR,
496	  .default_num = 4
497	},
498
499	{ .name = "clock-mode-style",
500	  .type = OPTIONS_TABLE_CHOICE,
501	  .choices = options_table_clock_mode_style_list,
502	  .default_num = 1
503	},
504
505	{ .name = "command-prefix",
506	  .type = OPTIONS_TABLE_STRING,
507	  .default_str = "exec "
508	},
509
510	{ .name = "force-height",
511	  .type = OPTIONS_TABLE_NUMBER,
512	  .minimum = 0,
513	  .maximum = INT_MAX,
514	  .default_num = 0
515	},
516
517	{ .name = "force-width",
518	  .type = OPTIONS_TABLE_NUMBER,
519	  .minimum = 0,
520	  .maximum = INT_MAX,
521	  .default_num = 0
522	},
523
524	{ .name = "main-pane-height",
525	  .type = OPTIONS_TABLE_NUMBER,
526	  .minimum = 1,
527	  .maximum = INT_MAX,
528	  .default_num = 24
529	},
530
531	{ .name = "main-pane-width",
532	  .type = OPTIONS_TABLE_NUMBER,
533	  .minimum = 1,
534	  .maximum = INT_MAX,
535	  .default_num = 80
536	},
537
538	{ .name = "mode-attr",
539	  .type = OPTIONS_TABLE_ATTRIBUTES,
540	  .default_num = 0
541	},
542
543	{ .name = "mode-bg",
544	  .type = OPTIONS_TABLE_COLOUR,
545	  .default_num = 3
546	},
547
548	{ .name = "mode-fg",
549	  .type = OPTIONS_TABLE_COLOUR,
550	  .default_num = 0
551	},
552
553	{ .name = "mode-keys",
554	  .type = OPTIONS_TABLE_CHOICE,
555	  .choices = options_table_mode_keys_list,
556	  .default_num = MODEKEY_EMACS
557	},
558
559	{ .name = "mode-mouse",
560	  .type = OPTIONS_TABLE_CHOICE,
561	  .choices = options_table_mode_mouse_list,
562	  .default_num = 0
563	},
564
565	{ .name = "monitor-activity",
566	  .type = OPTIONS_TABLE_FLAG,
567	  .default_num = 0
568	},
569
570	{ .name = "monitor-content",
571	  .type = OPTIONS_TABLE_STRING,
572	  .default_str = ""
573	},
574
575	{ .name = "monitor-silence",
576	  .type = OPTIONS_TABLE_NUMBER,
577	  .minimum = 0,
578	  .maximum = INT_MAX,
579	  .default_num = 0
580	},
581
582	{ .name = "other-pane-height",
583	  .type = OPTIONS_TABLE_NUMBER,
584	  .minimum = 0,
585	  .maximum = INT_MAX,
586	  .default_num = 0
587	},
588
589	{ .name = "other-pane-width",
590	  .type = OPTIONS_TABLE_NUMBER,
591	  .minimum = 0,
592	  .maximum = INT_MAX,
593	  .default_num = 0
594	},
595
596	{ .name = "pane-base-index",
597	  .type = OPTIONS_TABLE_NUMBER,
598	  .minimum = 0,
599	  .maximum = USHRT_MAX,
600	  .default_num = 0
601	},
602
603	{ .name = "remain-on-exit",
604	  .type = OPTIONS_TABLE_FLAG,
605	  .default_num = 0
606	},
607
608	{ .name = "synchronize-panes",
609	  .type = OPTIONS_TABLE_FLAG,
610	  .default_num = 0
611	},
612
613	{ .name = "utf8",
614	  .type = OPTIONS_TABLE_FLAG,
615	  .default_num = 0 /* overridden in main() */
616	},
617
618	{ .name = "window-status-activity-attr",
619	  .type = OPTIONS_TABLE_ATTRIBUTES,
620	  .default_num = GRID_ATTR_REVERSE
621	},
622
623	{ .name = "window-status-activity-bg",
624	  .type = OPTIONS_TABLE_COLOUR,
625	  .default_num = 8
626	},
627
628	{ .name = "window-status-activity-fg",
629	  .type = OPTIONS_TABLE_COLOUR,
630	  .default_num = 8
631	},
632
633	{ .name = "window-status-bell-attr",
634	  .type = OPTIONS_TABLE_ATTRIBUTES,
635	  .default_num = GRID_ATTR_REVERSE
636	},
637
638	{ .name = "window-status-bell-bg",
639	  .type = OPTIONS_TABLE_COLOUR,
640	  .default_num = 8
641	},
642
643	{ .name = "window-status-bell-fg",
644	  .type = OPTIONS_TABLE_COLOUR,
645	  .default_num = 8
646	},
647
648	{ .name = "window-status-content-attr",
649	  .type = OPTIONS_TABLE_ATTRIBUTES,
650	  .default_num = GRID_ATTR_REVERSE
651	},
652
653	{ .name = "window-status-content-bg",
654	  .type = OPTIONS_TABLE_COLOUR,
655	  .default_num = 8
656	},
657
658	{ .name = "window-status-content-fg",
659	  .type = OPTIONS_TABLE_COLOUR,
660	  .default_num = 8
661	},
662
663	{ .name = "window-status-attr",
664	  .type = OPTIONS_TABLE_ATTRIBUTES,
665	  .default_num = 0
666	},
667
668	{ .name = "window-status-bg",
669	  .type = OPTIONS_TABLE_COLOUR,
670	  .default_num = 8
671	},
672
673	{ .name = "window-status-current-attr",
674	  .type = OPTIONS_TABLE_ATTRIBUTES,
675	  .default_num = 0
676	},
677
678	{ .name = "window-status-current-bg",
679	  .type = OPTIONS_TABLE_COLOUR,
680	  .default_num = 8
681	},
682
683	{ .name = "window-status-current-fg",
684	  .type = OPTIONS_TABLE_COLOUR,
685	  .default_num = 8
686	},
687
688	{ .name = "window-status-current-format",
689	  .type = OPTIONS_TABLE_STRING,
690	  .default_str = "#I:#W#F"
691	},
692
693	{ .name = "window-status-last-attr",
694	  .type = OPTIONS_TABLE_ATTRIBUTES,
695	  .default_num = 0
696	},
697
698	{ .name = "window-status-last-bg",
699	  .type = OPTIONS_TABLE_COLOUR,
700	  .default_num = 8
701	},
702
703	{ .name = "window-status-last-fg",
704	  .type = OPTIONS_TABLE_COLOUR,
705	  .default_num = 8
706	},
707
708	{ .name = "window-status-fg",
709	  .type = OPTIONS_TABLE_COLOUR,
710	  .default_num = 8
711	},
712
713	{ .name = "window-status-format",
714	  .type = OPTIONS_TABLE_STRING,
715	  .default_str = "#I:#W#F"
716	},
717
718	{ .name = "window-status-separator",
719	  .type = OPTIONS_TABLE_STRING,
720	  .default_str = " "
721	},
722
723	{ .name = "wrap-search",
724	  .type = OPTIONS_TABLE_FLAG,
725	  .default_num = 1
726	},
727
728	{ .name = "xterm-keys",
729	  .type = OPTIONS_TABLE_FLAG,
730	  .default_num = 0
731	},
732
733	{ .name = NULL }
734};
735
736/* Populate an options tree from a table. */
737void
738options_table_populate_tree(
739    const struct options_table_entry *table, struct options *oo)
740{
741	const struct options_table_entry	*oe;
742
743	for (oe = table; oe->name != NULL; oe++) {
744		if (oe->default_str != NULL)
745			options_set_string(oo, oe->name, "%s", oe->default_str);
746		else
747			options_set_number(oo, oe->name, oe->default_num);
748	}
749}
750
751/* Print an option using its type from the table. */
752const char *
753options_table_print_entry(const struct options_table_entry *oe,
754    struct options_entry *o, int no_quotes)
755{
756	static char	 out[BUFSIZ];
757	const char	*s;
758
759	*out = '\0';
760	switch (oe->type) {
761	case OPTIONS_TABLE_STRING:
762		if (no_quotes)
763			xsnprintf(out, sizeof out, "%s", o->str);
764		else
765			xsnprintf(out, sizeof out, "\"%s\"", o->str);
766		break;
767	case OPTIONS_TABLE_NUMBER:
768		xsnprintf(out, sizeof out, "%lld", o->num);
769		break;
770	case OPTIONS_TABLE_KEY:
771		xsnprintf(out, sizeof out, "%s",
772		    key_string_lookup_key(o->num));
773		break;
774	case OPTIONS_TABLE_COLOUR:
775		s = colour_tostring(o->num);
776		xsnprintf(out, sizeof out, "%s", s);
777		break;
778	case OPTIONS_TABLE_ATTRIBUTES:
779		s = attributes_tostring(o->num);
780		xsnprintf(out, sizeof out, "%s", s);
781		break;
782	case OPTIONS_TABLE_FLAG:
783		if (o->num)
784			strlcpy(out, "on", sizeof out);
785		else
786			strlcpy(out, "off", sizeof out);
787		break;
788	case OPTIONS_TABLE_CHOICE:
789		s = oe->choices[o->num];
790		xsnprintf(out, sizeof out, "%s", s);
791		break;
792	}
793	return (out);
794}
795
796/* Find an option. */
797int
798options_table_find(
799    const char *optstr, const struct options_table_entry **table,
800    const struct options_table_entry **oe)
801{
802	static const struct options_table_entry	*tables[] = {
803		server_options_table,
804		window_options_table,
805		session_options_table
806	};
807	const struct options_table_entry	*oe_loop;
808	u_int					 i;
809
810	for (i = 0; i < nitems(tables); i++) {
811		for (oe_loop = tables[i]; oe_loop->name != NULL; oe_loop++) {
812			if (strncmp(oe_loop->name, optstr, strlen(optstr)) != 0)
813				continue;
814
815			/* If already found, ambiguous. */
816			if (*oe != NULL)
817				return (-1);
818			*oe = oe_loop;
819			*table = tables[i];
820
821			/* Bail now if an exact match. */
822			if (strcmp((*oe)->name, optstr) == 0)
823				break;
824		}
825	}
826	return (0);
827}
828