1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1997, by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 /*LINTLIBRARY*/ 32 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #include "utility.h" 36 37 /* 38 * TYPE_ENUM standard type 39 * 40 * usage: 41 * set_field_type(f, TYPE_ENUM, list, checkcase, checkuniq); 42 * 43 * char ** list; list of acceptable strings 44 * int checkcase; TRUE - upper/lower case is significant 45 * int checkuniq; TRUE - unique match required 46 * 47 */ 48 typedef struct { 49 50 char ** list; 51 int checkcase; 52 int checkuniq; 53 int count; 54 } ENUM; 55 56 static char * make_enum(va_list *); 57 static char * copy_enum(char *); 58 static void free_enum(char *); 59 static int fcheck_enum(FIELD *, char *); 60 static int next_enum(FIELD *, char *); 61 static int prev_enum(FIELD *, char *); 62 63 static FIELDTYPE typeENUM = 64 { 65 ARGS | CHOICE, /* status */ 66 1, /* ref */ 67 (FIELDTYPE *) 0, /* left */ 68 (FIELDTYPE *) 0, /* right */ 69 make_enum, /* makearg */ 70 copy_enum, /* copyarg */ 71 free_enum, /* freearg */ 72 fcheck_enum, /* fcheck */ 73 (PTF_int) 0, /* ccheck */ 74 next_enum, /* next */ 75 prev_enum, /* prev */ 76 }; 77 78 FIELDTYPE * TYPE_ENUM = &typeENUM; 79 80 static char * 81 make_enum(va_list *ap) 82 { 83 ENUM * n; 84 85 if (Alloc(n, ENUM)) { 86 char ** v; 87 88 n -> list = va_arg(*ap, char **); 89 n -> checkcase = va_arg(*ap, int); 90 n -> checkuniq = va_arg(*ap, int); 91 92 for (v = n -> list; *v; ++v) 93 ; 94 n -> count = (int) (v - n -> list); 95 } 96 return ((char *) n); 97 } 98 99 static char * 100 copy_enum(char *arg) 101 { 102 ENUM * n; 103 104 if (Alloc(n, ENUM)) 105 *n = *((ENUM *) arg); 106 return ((char *) n); 107 } 108 109 static void 110 free_enum(char *arg) 111 { 112 Free(arg); 113 } 114 115 #define NO_MATCH 0 116 #define PARTIAL_MATCH 1 117 #define EXACT_MATCH 2 118 119 static int 120 cmp(char *x, char *v, int checkcase) 121 { 122 while (*v && *v == ' ') /* remove leading blanks */ 123 ++v; 124 while (*x && *x == ' ') /* remove leading blanks */ 125 ++x; 126 127 if (*v == '\0') 128 return (*x == '\0' ? EXACT_MATCH : NO_MATCH); 129 130 if (checkcase) { /* case is significant */ 131 while (*x++ == *v) 132 if (*v++ == '\0') 133 return (EXACT_MATCH); 134 } else { /* ignore case */ 135 while (toupper (*x++) == toupper (*v)) 136 if (*v++ == '\0') 137 return (EXACT_MATCH); 138 } 139 while (*v && *v == ' ') /* remove trailing blanks */ 140 ++v; 141 if (*v) 142 return (NO_MATCH); 143 else 144 return (*--x ? PARTIAL_MATCH : EXACT_MATCH); 145 } 146 147 static int 148 fcheck_enum(FIELD *f, char *arg) 149 { 150 ENUM * n = (ENUM *) arg; 151 char ** list = n -> list; 152 int checkcase = n -> checkcase; 153 int checkuniq = n -> checkuniq; 154 int m; 155 char * v = field_buffer(f, 0); 156 char * x; 157 158 while (x = *list++) 159 if (m = cmp(x, v, checkcase)) { 160 char * value = x; 161 162 if (checkuniq && m != EXACT_MATCH) 163 while (x = *list++) 164 if (m = cmp(x, v, checkcase)) { 165 if (m == EXACT_MATCH) { 166 value = x; 167 break; 168 } 169 else 170 value = (char *) 0; 171 } 172 if (! value) 173 return (FALSE); 174 175 (void) set_field_buffer(f, 0, value); 176 return (TRUE); 177 } 178 179 return (FALSE); 180 } 181 182 static int 183 next_enum(FIELD *f, char *arg) 184 { 185 ENUM * n = (ENUM *) arg; 186 char ** list = n -> list; 187 int checkcase = n -> checkcase; 188 int count = n -> count; 189 char * v = field_buffer(f, 0); 190 191 while (count--) 192 if (cmp(*list++, v, checkcase) == EXACT_MATCH) 193 break; 194 if (count <= 0) 195 list = n -> list; 196 197 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) { 198 (void) set_field_buffer(f, 0, *list); 199 return (TRUE); 200 } 201 return (FALSE); 202 } 203 204 static int 205 prev_enum(FIELD *f, char *arg) 206 { 207 ENUM * n = (ENUM *) arg; 208 char ** list = n -> list + n -> count - 1; 209 int checkcase = n -> checkcase; 210 int count = n -> count; 211 char * v = field_buffer(f, 0); 212 213 while (count--) 214 if (cmp(*list--, v, checkcase) == EXACT_MATCH) 215 break; 216 if (count <= 0) 217 list = n -> list + n -> count - 1; 218 219 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) { 220 (void) set_field_buffer(f, 0, *list); 221 return (TRUE); 222 } 223 return (FALSE); 224 } 225