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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 32 */ 33 34 #include <stdio.h> 35 #include <err.h> 36 #include <sys/types.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <ctype.h> 40 #include <assert.h> 41 #include <libcustr.h> 42 #include "cron.h" 43 44 #ifdef PARSETEST 45 #define xstrdup(x) strdup((x)) 46 #endif 47 48 #define MAX_ELEMENTS 60 49 50 #define READNUMBER(x) \ 51 do { \ 52 (x) = (x) * 10 + (line[cursor] - '0'); \ 53 if ((x) > MAX_ELEMENTS) { \ 54 err = CFOUTOFBOUND; \ 55 goto out; \ 56 } \ 57 } while (isdigit(line[++cursor])) 58 59 #define ADDELEMENT(x) \ 60 do { \ 61 if (eindex >= MAX_ELEMENTS) { \ 62 err = CFEOVERFLOW; \ 63 goto out; \ 64 } \ 65 elements[eindex++] = (x); \ 66 } while (0) 67 68 /* A more restrictive version of isspace(3C) that only looks for space/tab */ 69 #define ISSPACE(x) \ 70 ((x) == ' ' || (x) == '\t') 71 72 cferror_t 73 next_field(uint_t lower, uint_t upper, char *line, int *cursorp, char **ret) 74 { 75 uint_t elements[MAX_ELEMENTS]; 76 uint_t eindex = 0, i; 77 int cursor = *cursorp; 78 cferror_t err = CFOK; 79 80 assert(upper - lower <= MAX_ELEMENTS); 81 82 if (ret != NULL) 83 *ret = NULL; 84 85 while (ISSPACE(line[cursor])) 86 cursor++; 87 88 if (line[cursor] == '\0') { 89 err = CFEOLN; 90 goto out; 91 } 92 93 for (;;) { 94 uint_t num = 0, num2 = 0, step = 0; 95 96 if (line[cursor] == '*') { 97 cursor++; 98 99 /* Short circuit for plain '*' */ 100 if (ISSPACE(line[cursor])) { 101 if (ret != NULL) 102 *ret = xstrdup("*"); 103 goto out; 104 } 105 106 /* 107 * '*' is only permitted alongside other elements if 108 * it has an associated step. 109 */ 110 111 if (line[cursor] != '/') { 112 err = CFUNEXPECT; 113 goto out; 114 } 115 116 /* Treat it as a range covering all values */ 117 num = lower; 118 num2 = upper; 119 } else { 120 if (!isdigit(line[cursor])) { 121 err = CFUNEXPECT; 122 goto out; 123 } 124 125 READNUMBER(num); 126 127 if (num < lower || num > upper) { 128 err = CFOUTOFBOUND; 129 goto out; 130 } 131 132 if (line[cursor] == '-') { 133 cursor++; 134 if (!isdigit(line[cursor])) { 135 err = CFUNEXPECT; 136 goto out; 137 } 138 139 READNUMBER(num2); 140 141 if (num2 < lower || num2 > upper) { 142 err = CFOUTOFBOUND; 143 goto out; 144 } 145 } else { 146 ADDELEMENT(num); 147 goto next; 148 } 149 } 150 151 /* Look for a step definition */ 152 if (line[cursor] == '/') { 153 cursor++; 154 if (!isdigit(line[cursor])) { 155 err = CFUNEXPECT; 156 goto out; 157 } 158 159 READNUMBER(step); 160 161 if (step == 0) { 162 err = CFOUTOFBOUND; 163 goto out; 164 } 165 } else { 166 step = 1; 167 } 168 169 if (num <= num2) { 170 for (i = num; i <= num2; i += step) { 171 ADDELEMENT(i); 172 } 173 } else { 174 /* Wrap-around range */ 175 for (i = num; i <= upper; i += step) { 176 ADDELEMENT(i); 177 } 178 179 i -= (upper - lower + 1); 180 for (; i <= num2; i += step) { 181 ADDELEMENT(i); 182 } 183 } 184 185 next: 186 187 if (line[cursor] != ',') 188 break; 189 190 cursor++; 191 } 192 193 if (line[cursor] == '\0') { 194 err = CFEOLN; 195 goto out; 196 } 197 198 if (!ISSPACE(line[cursor])) { 199 err = CFUNEXPECT; 200 goto out; 201 } 202 203 if (ret != NULL) { 204 custr_t *cs = NULL; 205 206 if (custr_alloc(&cs) != 0) { 207 err = CFENOMEM; 208 goto out; 209 } 210 211 for (i = 0; i < eindex; i++) { 212 if (custr_len(cs) > 0) { 213 if (custr_appendc(cs, ',') != 0) { 214 custr_free(cs); 215 err = CFENOMEM; 216 goto out; 217 } 218 } 219 if (custr_append_printf(cs, "%u", elements[i]) != 0) { 220 custr_free(cs); 221 err = CFENOMEM; 222 goto out; 223 } 224 } 225 226 if (custr_len(cs) != 0) 227 *ret = xstrdup(custr_cstr(cs)); 228 custr_free(cs); 229 } 230 231 out: 232 233 *cursorp = cursor; 234 235 return (err); 236 } 237 238 #ifdef PARSETEST 239 int 240 main(int argc, char **argv) 241 { 242 int lower, upper, cursor = 0; 243 char *ret; 244 245 if (argc != 4) 246 errx(1, "<lower> <upper> <string>"); 247 248 lower = atoi(argv[1]); 249 upper = atoi(argv[2]); 250 251 switch (next_field(lower, upper, argv[3], &cursor, &ret)) { 252 case CFOK: 253 (void) printf("%s\n", ret); 254 break; 255 case CFEOLN: 256 (void) printf("UnexpectedEOL\n"); 257 break; 258 case CFUNEXPECT: 259 (void) printf("UnexpectedChar\n"); 260 break; 261 case CFOUTOFBOUND: 262 (void) printf("OutOfBounds\n"); 263 break; 264 case CFEOVERFLOW: 265 (void) printf("Overflow\n"); 266 break; 267 case CFENOMEM: 268 (void) printf("OutOfMemory\n"); 269 break; 270 default: 271 (void) printf("UnknownError\n"); 272 break; 273 } 274 275 return (0); 276 } 277 #endif 278