Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libform / type_enum.c
blob838a1828a29df71b1335797eee8cfcd890d8dfb3
1 /* $NetBSD: type_enum.c,v 1.9 2004/04/23 02:58:27 simonb Exp $ */
3 /*-
4 * Copyright (c) 1998-1999 Brett Lymn
5 * (blymn@baea.com.au, brett_lymn@yahoo.com.au)
6 * All rights reserved.
8 * This code has been donated to The NetBSD Foundation by the Author.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: type_enum.c,v 1.9 2004/04/23 02:58:27 simonb Exp $");
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include "form.h"
39 #include "internals.h"
42 * Prototypes.
44 static int
45 trim_blanks(char *field);
48 * The enum type handling.
51 typedef struct
53 char **choices;
54 unsigned num_choices;
55 bool ignore_case;
56 bool exact;
57 } enum_args;
60 * Find the first non-blank character at the end of a field, return the
61 * index of that character.
63 static int
64 trim_blanks(char *field)
66 int i;
68 i = (int) strlen(field);
69 if (i > 0)
70 i--;
71 else
72 return 0;
74 while ((i > 0) && isblank(field[i]))
75 i--;
77 return i;
81 * Create the enum arguments structure from the given args. Return NULL
82 * if the call fails, otherwise return a pointer to the structure allocated.
84 static char *
85 create_enum_args(va_list *args)
87 enum_args *new;
88 char **choices;
90 new = (enum_args *) malloc(sizeof(enum_args));
92 if (new != NULL) {
93 new->choices = va_arg(*args, char **);
94 new->ignore_case = (va_arg(*args, int)) ? TRUE : FALSE;
95 new->exact = (va_arg(*args, int)) ? TRUE : FALSE;
97 #ifdef DEBUG
98 if (_formi_create_dbg_file() != E_OK)
99 return NULL;
100 fprintf(dbg,
101 "create_enum_args: ignore_case %d, no_blanks %d\n",
102 new->ignore_case, new->exact);
103 #endif
105 /* count the choices we have */
106 choices = new->choices;
107 new->num_choices = 0;
108 while (*choices != NULL) {
109 #ifdef DEBUG
110 fprintf(dbg, "create_enum_args: choice[%d] = \'%s\'\n",
111 new->num_choices,
112 new->choices[new->num_choices]);
113 #endif
114 new->num_choices++;
115 choices++;
117 #ifdef DEBUG
118 fprintf(dbg, "create_enum_args: have %d choices\n",
119 new->num_choices);
120 #endif
124 return (void *) new;
128 * Copy the enum argument structure.
130 static char *
131 copy_enum_args(char *args)
133 enum_args *new;
135 new = (enum_args *) malloc(sizeof(enum_args));
137 if (new != NULL)
138 bcopy(args, new, sizeof(enum_args));
140 return (void *) new;
144 * Free the allocated storage associated with the type arguments.
146 static void
147 free_enum_args(char *args)
149 if (args != NULL)
150 free(args);
154 * Attempt to match the string in this to the choices given. Returns
155 * TRUE if match found otherwise FALSE.
158 static bool
159 match_enum(char **choices, unsigned num_choices, bool ignore_case,
160 bool exact, char *this, unsigned *match_num)
162 unsigned i, start, end, enum_start, blen, elen, enum_end;
163 bool cur_match;
165 start = _formi_skip_blanks(this, 0);
166 end = trim_blanks(this);
168 if (end >= start)
169 blen = (unsigned) (strlen(&this[start])
170 - strlen(&this[end]) + 1);
171 else
172 blen = 0;
174 #ifdef DEBUG
175 fprintf(dbg, "match_enum: start %d, blen %d\n", start, blen);
176 #endif
177 for (i = 0; i < num_choices; i++) {
178 enum_start = _formi_skip_blanks(choices[i], 0);
179 enum_end = trim_blanks(choices[i]);
181 if (enum_end >= enum_start)
182 elen = (unsigned) (strlen(&choices[i][enum_start])
183 - strlen(&choices[i][enum_end]) + 1);
184 else
185 elen = 0;
187 #ifdef DEBUG
188 fprintf(dbg, "match_enum: checking choice \'%s\'\n",
189 choices[i]);
190 fprintf(dbg, "match_enum: enum_start %d, elen %d\n",
191 enum_start, elen);
192 #endif
194 /* don't bother if we are after an exact match
195 * and the test length is not equal to the enum
196 * in question - it will never match.
198 if ((exact == TRUE) && (blen != elen))
199 continue;
202 * If the test length is longer than the enum
203 * length then there is no chance of a match
204 * so we skip.
206 if ((exact != TRUE) && (blen > elen))
207 continue;
209 if (ignore_case)
210 cur_match = (strncasecmp(&choices[i][enum_start],
211 &this[start],
212 (size_t)blen) == 0) ?
213 TRUE : FALSE;
214 else
215 cur_match = (strncmp(&choices[i][enum_start],
216 &this[start],
217 (size_t) blen) == 0) ?
218 TRUE : FALSE;
220 #ifdef DEBUG
221 fprintf(dbg, "match_enum: curmatch is %s\n",
222 (cur_match == TRUE)? "TRUE" : "FALSE");
223 #endif
225 if (cur_match == TRUE) {
226 *match_num = i;
227 return TRUE;
232 #ifdef DEBUG
233 fprintf(dbg, "match_enum: no match found\n");
234 #endif
235 return FALSE;
239 * Check the contents of the field buffer match one of the enum strings only.
241 static int
242 enum_check_field(FIELD *field, char *args)
244 enum_args *ta;
245 unsigned match_num;
247 if (args == NULL)
248 return FALSE;
250 ta = (enum_args *) (void *) field->args;
252 if (match_enum(ta->choices, ta->num_choices, ta->ignore_case,
253 ta->exact, args, &match_num) == TRUE) {
254 #ifdef DEBUG
255 fprintf(dbg, "enum_check_field: We matched, match_num %d\n",
256 match_num);
257 fprintf(dbg, "enum_check_field: buffer is \'%s\'\n",
258 ta->choices[match_num]);
259 #endif
260 set_field_buffer(field, 0, ta->choices[match_num]);
261 return TRUE;
264 return FALSE;
268 * Get the next enum in the list of choices.
270 static int
271 next_enum(FIELD *field, char *args)
273 enum_args *ta;
274 unsigned cur_choice;
276 if (args == NULL)
277 return FALSE;
279 ta = (enum_args *) (void *) field->args;
281 #ifdef DEBUG
282 fprintf(dbg, "next_enum: attempt to match \'%s\'\n", args);
283 #endif
285 if (match_enum(ta->choices, ta->num_choices, ta->ignore_case,
286 ta->exact, args, &cur_choice) == FALSE) {
287 #ifdef DEBUG
288 fprintf(dbg, "next_enum: match failed\n");
289 #endif
290 return FALSE;
293 #ifdef DEBUG
294 fprintf(dbg, "next_enum: cur_choice is %d\n", cur_choice);
295 #endif
297 cur_choice++;
299 if (cur_choice >= ta->num_choices)
300 cur_choice = 0;
302 #ifdef DEBUG
303 fprintf(dbg, "next_enum: cur_choice is %d on exit\n",
304 cur_choice);
305 #endif
307 set_field_buffer(field, 0, ta->choices[cur_choice]);
308 return TRUE;
312 * Get the previous enum in the list of choices.
314 static int
315 prev_enum(FIELD *field, char *args)
317 enum_args *ta;
318 unsigned cur_choice;
320 if (args == NULL)
321 return FALSE;
323 ta = (enum_args *) (void *) field->args;
325 #ifdef DEBUG
326 fprintf(dbg, "prev_enum: attempt to match \'%s\'\n", args);
327 #endif
329 if (match_enum(ta->choices, ta->num_choices, ta->ignore_case,
330 ta->exact, args, &cur_choice) == FALSE) {
331 #ifdef DEBUG
332 fprintf(dbg, "prev_enum: match failed\n");
333 #endif
334 return FALSE;
337 #ifdef DEBUG
338 fprintf(dbg, "prev_enum: cur_choice is %d\n", cur_choice);
339 #endif
340 if (cur_choice == 0)
341 cur_choice = ta->num_choices - 1;
342 else
343 cur_choice--;
345 #ifdef DEBUG
346 fprintf(dbg, "prev_enum: cur_choice is %d on exit\n", cur_choice);
347 #endif
349 set_field_buffer(field, 0, ta->choices[cur_choice]);
350 return TRUE;
354 static FIELDTYPE builtin_enum = {
355 _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */
356 0, /* refcount */
357 NULL, /* link */
358 create_enum_args, /* make_args */
359 copy_enum_args, /* copy_args */
360 free_enum_args, /* free_args */
361 enum_check_field, /* field_check */
362 NULL, /* char_check */
363 next_enum, /* next_choice */
364 prev_enum /* prev_choice */
367 FIELDTYPE *TYPE_ENUM = &builtin_enum;