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 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ 32 33 /*LINTLIBRARY*/ 34 35 #include <sys/types.h> 36 #include <stdlib.h> 37 #include "utility.h" 38 39 /* 40 * TYPE_ENUM standard type 41 * 42 * usage: 43 * set_field_type(f, TYPE_ENUM, list, checkcase, checkuniq); 44 * 45 * char ** list; list of acceptable strings 46 * int checkcase; TRUE - upper/lower case is significant 47 * int checkuniq; TRUE - unique match required 48 * 49 */ 50 typedef struct { 51 52 char ** list; 53 int checkcase; 54 int checkuniq; 55 int count; 56 } ENUM; 57 58 static char * make_enum(va_list *); 59 static char * copy_enum(char *); 60 static void free_enum(char *); 61 static int fcheck_enum(FIELD *, char *); 62 static int next_enum(FIELD *, char *); 63 static int prev_enum(FIELD *, char *); 64 65 static FIELDTYPE typeENUM = 66 { 67 ARGS | CHOICE, /* status */ 68 1, /* ref */ 69 (FIELDTYPE *) 0, /* left */ 70 (FIELDTYPE *) 0, /* right */ 71 make_enum, /* makearg */ 72 copy_enum, /* copyarg */ 73 free_enum, /* freearg */ 74 fcheck_enum, /* fcheck */ 75 (PTF_int) 0, /* ccheck */ 76 next_enum, /* next */ 77 prev_enum, /* prev */ 78 }; 79 80 FIELDTYPE * TYPE_ENUM = &typeENUM; 81 82 static char * 83 make_enum(va_list *ap) 84 { 85 ENUM * n; 86 87 if (Alloc(n, ENUM)) { 88 char ** v; 89 90 n -> list = va_arg(*ap, char **); 91 n -> checkcase = va_arg(*ap, int); 92 n -> checkuniq = va_arg(*ap, int); 93 94 for (v = n -> list; *v; ++v) 95 ; 96 n -> count = (int) (v - n -> list); 97 } 98 return ((char *) n); 99 } 100 101 static char * 102 copy_enum(char *arg) 103 { 104 ENUM * n; 105 106 if (Alloc(n, ENUM)) 107 *n = *((ENUM *) arg); 108 return ((char *) n); 109 } 110 111 static void 112 free_enum(char *arg) 113 { 114 Free(arg); 115 } 116 117 #define NO_MATCH 0 118 #define PARTIAL_MATCH 1 119 #define EXACT_MATCH 2 120 121 static int 122 cmp(char *x, char *v, int checkcase) 123 { 124 while (*v && *v == ' ') /* remove leading blanks */ 125 ++v; 126 while (*x && *x == ' ') /* remove leading blanks */ 127 ++x; 128 129 if (*v == '\0') 130 return (*x == '\0' ? EXACT_MATCH : NO_MATCH); 131 132 if (checkcase) { /* case is significant */ 133 while (*x++ == *v) 134 if (*v++ == '\0') 135 return (EXACT_MATCH); 136 } else { /* ignore case */ 137 while (toupper (*x++) == toupper (*v)) 138 if (*v++ == '\0') 139 return (EXACT_MATCH); 140 } 141 while (*v && *v == ' ') /* remove trailing blanks */ 142 ++v; 143 if (*v) 144 return (NO_MATCH); 145 else 146 return (*--x ? PARTIAL_MATCH : EXACT_MATCH); 147 } 148 149 static int 150 fcheck_enum(FIELD *f, char *arg) 151 { 152 ENUM * n = (ENUM *) arg; 153 char ** list = n -> list; 154 int checkcase = n -> checkcase; 155 int checkuniq = n -> checkuniq; 156 int m; 157 char * v = field_buffer(f, 0); 158 char * x; 159 160 while (x = *list++) 161 if (m = cmp(x, v, checkcase)) { 162 char * value = x; 163 164 if (checkuniq && m != EXACT_MATCH) 165 while (x = *list++) 166 if (m = cmp(x, v, checkcase)) { 167 if (m == EXACT_MATCH) { 168 value = x; 169 break; 170 } 171 else 172 value = (char *) 0; 173 } 174 if (! value) 175 return (FALSE); 176 177 (void) set_field_buffer(f, 0, value); 178 return (TRUE); 179 } 180 181 return (FALSE); 182 } 183 184 static int 185 next_enum(FIELD *f, char *arg) 186 { 187 ENUM * n = (ENUM *) arg; 188 char ** list = n -> list; 189 int checkcase = n -> checkcase; 190 int count = n -> count; 191 char * v = field_buffer(f, 0); 192 193 while (count--) 194 if (cmp(*list++, v, checkcase) == EXACT_MATCH) 195 break; 196 if (count <= 0) 197 list = n -> list; 198 199 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) { 200 (void) set_field_buffer(f, 0, *list); 201 return (TRUE); 202 } 203 return (FALSE); 204 } 205 206 static int 207 prev_enum(FIELD *f, char *arg) 208 { 209 ENUM * n = (ENUM *) arg; 210 char ** list = n -> list + n -> count - 1; 211 int checkcase = n -> checkcase; 212 int count = n -> count; 213 char * v = field_buffer(f, 0); 214 215 while (count--) 216 if (cmp(*list--, v, checkcase) == EXACT_MATCH) 217 break; 218 if (count <= 0) 219 list = n -> list + n -> count - 1; 220 221 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) { 222 (void) set_field_buffer(f, 0, *list); 223 return (TRUE); 224 } 225 return (FALSE); 226 } 227