1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2006,2008 Oracle. All rights reserved. 5 * 6 * $Id: code_parse.c,v 1.6 2008/01/08 20:58:12 bostic Exp $ 7 */ 8 9#include "db_codegen.h" 10 11static enum /* Parse state */ 12 { PS_UNSET, PS_ENV_SET, PS_DB_SET } parse_status; 13static ENV_OBJ *cur_env; /* Current objects */ 14static DB_OBJ *cur_db; 15 16static int parse_line __P((char *, int)); 17 18int 19parse_input(fp) 20 FILE *fp; 21{ 22 int lc; 23 char *p, *t, buf[256]; 24 25 parse_status = PS_UNSET; 26 27 for (lc = 1; fgets(buf, sizeof(buf), fp) != NULL; ++lc) { 28 if ((p = strchr(buf, '\n')) != NULL) 29 *p = '\0'; 30 else if (strlen(buf) + 1 == sizeof(buf)) { 31 fprintf(stderr, "%s: %d: line too long", progname, lc); 32 return (1); 33 } 34 35 /* Skip leading whitespace. */ 36 for (p = buf; *p != '\0' && isspace((int)*p); ++p) 37 ; 38 39 /* 40 * Any empty line or hash mark to the end of the line is 41 * a comment. 42 */ 43 if (*p == '\0' || *p == '#') 44 continue; 45 for (t = p; *t != '\0' && *t != '#'; ++t) 46 ; 47 *t = '\0'; 48 49 if (parse_line(p, lc)) 50 return (1); 51 } 52 (void)fclose(fp); 53 54 return (0); 55} 56 57#undef CONFIG_SLOTS 58#define CONFIG_SLOTS 10 59 60#undef CONFIG_GET_UINT32 61#define CONFIG_GET_UINT32(s, vp) do { \ 62 if (__db_getulong(NULL, progname, s, 0, UINT32_MAX, vp) != 0) \ 63 return (EINVAL); \ 64} while (0) 65 66static int 67parse_line(s, lc) 68 char *s; 69 int lc; 70{ 71 u_long uv; 72 int nf; 73 char *argv[CONFIG_SLOTS], *p; 74 75 nf = __config_split(s, argv); /* Split the line by white-space. */ 76 77 /* 78 * Environment keywords. 79 */ 80 if (strcasecmp(argv[0], "environment") == 0) { 81 if (nf != 3 || 82 strcmp(argv[2], "{") != 0 || parse_status != PS_UNSET) 83 goto format; 84 85 if (__os_calloc(NULL, 1, sizeof(*cur_env), &cur_env) || 86 __os_strdup(NULL, argv[1], &cur_env->prefix)) 87 goto memory; 88 TAILQ_INIT(&cur_env->dbq); 89 90 TAILQ_INSERT_TAIL(&env_tree, cur_env, q); 91 92 /* 93 * Default settings. 94 */ 95 cur_env->home = "."; 96 97 parse_status = PS_ENV_SET; 98 return (0); 99 } 100 if (strcasecmp(argv[0], "home") == 0) { 101 if (nf != 2 || parse_status != PS_ENV_SET) 102 goto format; 103 if (__os_strdup(NULL, argv[1], &cur_env->home)) 104 goto memory; 105 return (0); 106 } 107 if (strcasecmp(argv[0], "cachesize") == 0) { 108 if (nf != 4 || parse_status != PS_ENV_SET) 109 goto format; 110 CONFIG_GET_UINT32(argv[1], &uv); 111 cur_env->gbytes = uv; 112 CONFIG_GET_UINT32(argv[1], &uv); 113 cur_env->bytes = uv; 114 CONFIG_GET_UINT32(argv[1], &uv); 115 cur_env->ncache = uv; 116 return (0); 117 } 118 if (strcasecmp(argv[0], "private") == 0) { 119 if (nf != 1 || parse_status != PS_ENV_SET) 120 goto format; 121 cur_env->private = 1; 122 return (0); 123 } 124 125 /* 126 * Database keywords. 127 */ 128 if (strcasecmp(argv[0], "database") == 0) { 129 if (nf != 3 || 130 strcmp(argv[2], "{") != 0 || parse_status == PS_DB_SET) 131 goto format; 132 133 /* 134 * Databases can be specified standalone. If we don't have an 135 * environment, create a fake one to hold the information. 136 */ 137 if (parse_status == PS_UNSET) { 138 if (__os_calloc(NULL, 1, sizeof(*cur_env), &cur_env)) 139 goto memory; 140 TAILQ_INIT(&cur_env->dbq); 141 cur_env->standalone = 1; 142 143 TAILQ_INSERT_TAIL(&env_tree, cur_env, q); 144 } 145 146 if (__os_calloc(NULL, 1, sizeof(*cur_db), &cur_db) || 147 __os_strdup(NULL, argv[1], &cur_db->name)) 148 goto memory; 149 TAILQ_INSERT_TAIL(&cur_env->dbq, cur_db, q); 150 151 /* 152 * Default settings. 153 */ 154 cur_db->dbtype = "DB_BTREE"; 155 156 parse_status = PS_DB_SET; 157 return (0); 158 } 159 if (strcasecmp(argv[0], "custom") == 0) { 160 if (nf != 1 || parse_status != PS_DB_SET) 161 goto format; 162 cur_db->custom = 1; 163 return (0); 164 } 165 if (strcasecmp(argv[0], "dupsort") == 0) { 166 if (nf != 1 || parse_status != PS_DB_SET) 167 goto format; 168 cur_db->dupsort = 1; 169 return (0); 170 } 171 if (strcasecmp(argv[0], "extentsize") == 0) { 172 if (nf != 2 || parse_status != PS_DB_SET) 173 goto format; 174 CONFIG_GET_UINT32(argv[1], &uv); 175 cur_db->extentsize = uv; 176 return (0); 177 } 178 if (strcasecmp(argv[0], "key_type") == 0) { 179 if (nf != 2 || parse_status != PS_DB_SET) 180 goto format; 181 if (__os_strdup(NULL, argv[1], &cur_db->key_type)) 182 goto memory; 183 return (0); 184 } 185 if (strcasecmp(argv[0], "pagesize") == 0) { 186 if (nf != 2 || parse_status != PS_DB_SET) 187 goto format; 188 CONFIG_GET_UINT32(argv[1], &uv); 189 cur_db->pagesize = uv; 190 return (0); 191 } 192 if (strcasecmp(argv[0], "primary") == 0) { 193 if (nf != 2 || parse_status != PS_DB_SET) 194 goto format; 195 if (__os_strdup(NULL, argv[1], &cur_db->primary)) 196 goto memory; 197 return (0); 198 } 199 if (strcasecmp(argv[0], "recnum") == 0) { 200 if (nf != 1 || parse_status != PS_DB_SET) 201 goto format; 202 cur_db->recnum = 1; 203 return (0); 204 } 205 if (strcasecmp(argv[0], "re_len") == 0) { 206 if (nf != 2 || parse_status != PS_DB_SET) 207 goto format; 208 CONFIG_GET_UINT32(argv[1], &uv); 209 cur_db->re_len = uv; 210 return (0); 211 } 212 if (strcasecmp(argv[0], "secondary_offset") == 0) { 213 if (nf != 3 || parse_status != PS_DB_SET) 214 goto format; 215 CONFIG_GET_UINT32(argv[1], &uv); 216 cur_db->secondary_off = uv; 217 CONFIG_GET_UINT32(argv[2], &uv); 218 cur_db->secondary_len = uv; 219 return (0); 220 } 221 if (strcasecmp(argv[0], "transaction") == 0) { 222 if (nf != 1 || parse_status != PS_DB_SET) 223 goto format; 224 cur_env->transaction = cur_db->transaction = 1; 225 return (0); 226 } 227 if (strcasecmp(argv[0], "type") == 0) { 228 if (nf != 2 || parse_status != PS_DB_SET) 229 goto format; 230 if (strcasecmp(argv[1], "btree") == 0) 231 p = "DB_BTREE"; 232 else if (strcasecmp(argv[1], "hash") == 0) 233 p = "DB_HASH"; 234 else if (strcasecmp(argv[1], "queue") == 0) 235 p = "DB_QUEUE"; 236 else if (strcasecmp(argv[1], "recno") == 0) 237 p = "DB_RECNO"; 238 else 239 goto format; 240 if (__os_strdup(NULL, p, &cur_db->dbtype)) 241 goto memory; 242 return (0); 243 } 244 245 /* 246 * End block. 247 */ 248 if (strcmp(argv[0], "}") == 0) { 249 if (nf != 1) 250 goto format; 251 /* 252 * Pop up a level -- if we finished a database that's part of 253 * an environment, go back to the environment level; if we 254 * finished a standalone database or an environment, go back to 255 * unset. 256 */ 257 switch (parse_status) { 258 case PS_UNSET: 259 goto format; 260 case PS_DB_SET: 261 parse_status = 262 cur_env->standalone ? PS_UNSET : PS_ENV_SET; 263 break; 264 case PS_ENV_SET: 265 parse_status = PS_UNSET; 266 } 267 return (0); 268 } 269 270format: fprintf(stderr, 271 "%s: line %d: %s: invalid input\n", progname, lc, s); 272 return (1); 273 274memory: fprintf(stderr, "%s: %s\n", progname, db_strerror(errno)); 275 return (1); 276} 277 278#ifdef DEBUG 279int 280parse_dump() 281{ 282 TAILQ_FOREACH(cur_env, &env_tree, q) { 283 printf("environment: %s\n", 284 cur_env->standalone ? "standalone" : cur_env->prefix); 285 286 if (cur_env->home != NULL) 287 printf("\thome: %s\n", cur_env->home); 288 if (cur_env->gbytes != 0 || cur_env->bytes != 0) 289 printf("\tcachesize: %luGB, %luB, %lu\n", 290 (u_long)cur_env->gbytes, 291 (u_long)cur_env->bytes, 292 (u_long)cur_env->ncache); 293 294 if (cur_env->private) 295 printf("\tprivate: yes\n"); 296 if (cur_env->transaction) 297 printf("\ttransaction: yes\n"); 298 299 TAILQ_FOREACH(cur_db, &cur_env->dbq, q) { 300 printf("\tdatabase: %s\n", cur_db->name); 301 printf("\t\tdbtype: %s\n", cur_db->dbtype); 302 303 if (cur_db->extentsize) 304 printf("\t\textentsize: %lu\n", 305 (u_long)cur_db->extentsize); 306 if (cur_db->pagesize) 307 printf("\t\tpagesize: %lu\n", 308 (u_long)cur_db->pagesize); 309 if (cur_db->re_len) 310 printf("\t\tre_len: %lu\n", 311 (u_long)cur_db->re_len); 312 313 if (cur_db->key_type != NULL) 314 printf("\t\tkey_type: %s\n", 315 cur_db->key_type); 316 317 if (cur_db->primary != NULL) 318 printf("\t\tprimary: %s\n", 319 cur_db->primary); 320 if (cur_db->custom) 321 printf("\t\tcustom: yes\n"); 322 if (cur_db->secondary_off) 323 printf("\t\tsecondary_offset: %lu/%lu\n", 324 (u_long)cur_db->secondary_off, 325 (u_long)cur_db->secondary_len); 326 327 if (cur_db->dupsort) 328 printf("\t\tdupsort: yes\n"); 329 if (cur_db->recnum) 330 printf("\t\trecnum: yes\n"); 331 if (cur_db->transaction) 332 printf("\t\ttransaction: yes\n"); 333 } 334 } 335 336 return (0); 337} 338#endif 339