1 /* $NetBSD: type_enum.c,v 1.9 2004/04/23 02:58:27 simonb Exp $ */
4 * Copyright (c) 1998-1999 Brett Lymn
5 * (blymn@baea.com.au, brett_lymn@yahoo.com.au)
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
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 $");
39 #include "internals.h"
45 trim_blanks(char *field
);
48 * The enum type handling.
60 * Find the first non-blank character at the end of a field, return the
61 * index of that character.
64 trim_blanks(char *field
)
68 i
= (int) strlen(field
);
74 while ((i
> 0) && isblank(field
[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.
85 create_enum_args(va_list *args
)
90 new = (enum_args
*) malloc(sizeof(enum_args
));
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
;
98 if (_formi_create_dbg_file() != E_OK
)
101 "create_enum_args: ignore_case %d, no_blanks %d\n",
102 new->ignore_case
, new->exact
);
105 /* count the choices we have */
106 choices
= new->choices
;
107 new->num_choices
= 0;
108 while (*choices
!= NULL
) {
110 fprintf(dbg
, "create_enum_args: choice[%d] = \'%s\'\n",
112 new->choices
[new->num_choices
]);
118 fprintf(dbg
, "create_enum_args: have %d choices\n",
128 * Copy the enum argument structure.
131 copy_enum_args(char *args
)
135 new = (enum_args
*) malloc(sizeof(enum_args
));
138 bcopy(args
, new, sizeof(enum_args
));
144 * Free the allocated storage associated with the type arguments.
147 free_enum_args(char *args
)
154 * Attempt to match the string in this to the choices given. Returns
155 * TRUE if match found otherwise FALSE.
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
;
165 start
= _formi_skip_blanks(this, 0);
166 end
= trim_blanks(this);
169 blen
= (unsigned) (strlen(&this[start
])
170 - strlen(&this[end
]) + 1);
175 fprintf(dbg
, "match_enum: start %d, blen %d\n", start
, blen
);
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);
188 fprintf(dbg
, "match_enum: checking choice \'%s\'\n",
190 fprintf(dbg
, "match_enum: enum_start %d, elen %d\n",
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
))
202 * If the test length is longer than the enum
203 * length then there is no chance of a match
206 if ((exact
!= TRUE
) && (blen
> elen
))
210 cur_match
= (strncasecmp(&choices
[i
][enum_start
],
212 (size_t)blen
) == 0) ?
215 cur_match
= (strncmp(&choices
[i
][enum_start
],
217 (size_t) blen
) == 0) ?
221 fprintf(dbg
, "match_enum: curmatch is %s\n",
222 (cur_match
== TRUE
)? "TRUE" : "FALSE");
225 if (cur_match
== TRUE
) {
233 fprintf(dbg
, "match_enum: no match found\n");
239 * Check the contents of the field buffer match one of the enum strings only.
242 enum_check_field(FIELD
*field
, char *args
)
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
) {
255 fprintf(dbg
, "enum_check_field: We matched, match_num %d\n",
257 fprintf(dbg
, "enum_check_field: buffer is \'%s\'\n",
258 ta
->choices
[match_num
]);
260 set_field_buffer(field
, 0, ta
->choices
[match_num
]);
268 * Get the next enum in the list of choices.
271 next_enum(FIELD
*field
, char *args
)
279 ta
= (enum_args
*) (void *) field
->args
;
282 fprintf(dbg
, "next_enum: attempt to match \'%s\'\n", args
);
285 if (match_enum(ta
->choices
, ta
->num_choices
, ta
->ignore_case
,
286 ta
->exact
, args
, &cur_choice
) == FALSE
) {
288 fprintf(dbg
, "next_enum: match failed\n");
294 fprintf(dbg
, "next_enum: cur_choice is %d\n", cur_choice
);
299 if (cur_choice
>= ta
->num_choices
)
303 fprintf(dbg
, "next_enum: cur_choice is %d on exit\n",
307 set_field_buffer(field
, 0, ta
->choices
[cur_choice
]);
312 * Get the previous enum in the list of choices.
315 prev_enum(FIELD
*field
, char *args
)
323 ta
= (enum_args
*) (void *) field
->args
;
326 fprintf(dbg
, "prev_enum: attempt to match \'%s\'\n", args
);
329 if (match_enum(ta
->choices
, ta
->num_choices
, ta
->ignore_case
,
330 ta
->exact
, args
, &cur_choice
) == FALSE
) {
332 fprintf(dbg
, "prev_enum: match failed\n");
338 fprintf(dbg
, "prev_enum: cur_choice is %d\n", cur_choice
);
341 cur_choice
= ta
->num_choices
- 1;
346 fprintf(dbg
, "prev_enum: cur_choice is %d on exit\n", cur_choice
);
349 set_field_buffer(field
, 0, ta
->choices
[cur_choice
]);
354 static FIELDTYPE builtin_enum
= {
355 _TYPE_HAS_ARGS
| _TYPE_IS_BUILTIN
, /* flags */
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
;