1f1b9d127SSheldon Hearn /* 2f1b9d127SSheldon Hearn * Copyright (c) 2000, Boris Popov 3f1b9d127SSheldon Hearn * All rights reserved. 4f1b9d127SSheldon Hearn * 5f1b9d127SSheldon Hearn * Redistribution and use in source and binary forms, with or without 6f1b9d127SSheldon Hearn * modification, are permitted provided that the following conditions 7f1b9d127SSheldon Hearn * are met: 8f1b9d127SSheldon Hearn * 1. Redistributions of source code must retain the above copyright 9f1b9d127SSheldon Hearn * notice, this list of conditions and the following disclaimer. 10f1b9d127SSheldon Hearn * 2. Redistributions in binary form must reproduce the above copyright 11f1b9d127SSheldon Hearn * notice, this list of conditions and the following disclaimer in the 12f1b9d127SSheldon Hearn * documentation and/or other materials provided with the distribution. 13f1b9d127SSheldon Hearn * 3. All advertising materials mentioning features or use of this software 14f1b9d127SSheldon Hearn * must display the following acknowledgement: 15f1b9d127SSheldon Hearn * This product includes software developed by Boris Popov. 16f1b9d127SSheldon Hearn * 4. Neither the name of the author nor the names of any co-contributors 17f1b9d127SSheldon Hearn * may be used to endorse or promote products derived from this software 18f1b9d127SSheldon Hearn * without specific prior written permission. 19f1b9d127SSheldon Hearn * 20f1b9d127SSheldon Hearn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21f1b9d127SSheldon Hearn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22f1b9d127SSheldon Hearn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23f1b9d127SSheldon Hearn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24f1b9d127SSheldon Hearn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25f1b9d127SSheldon Hearn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26f1b9d127SSheldon Hearn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27f1b9d127SSheldon Hearn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28f1b9d127SSheldon Hearn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29f1b9d127SSheldon Hearn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30f1b9d127SSheldon Hearn * SUCH DAMAGE. 31f1b9d127SSheldon Hearn * 32f1b9d127SSheldon Hearn * $Id: rcfile.c,v 1.5 2001/04/16 12:46:46 bp Exp $ 33f1b9d127SSheldon Hearn */ 341ac62e0bSDavid E. O'Brien 351ac62e0bSDavid E. O'Brien #include <sys/cdefs.h> 361ac62e0bSDavid E. O'Brien __FBSDID("$FreeBSD$"); 371ac62e0bSDavid E. O'Brien 38f1b9d127SSheldon Hearn #include <sys/types.h> 39f1b9d127SSheldon Hearn #include <sys/queue.h> 40f1b9d127SSheldon Hearn #include <ctype.h> 41f1b9d127SSheldon Hearn #include <errno.h> 42f1b9d127SSheldon Hearn #include <stdio.h> 43f1b9d127SSheldon Hearn #include <string.h> 44f1b9d127SSheldon Hearn #include <stdlib.h> 45f1b9d127SSheldon Hearn #include <pwd.h> 46f1b9d127SSheldon Hearn #include <unistd.h> 47f1b9d127SSheldon Hearn #include <err.h> 48f1b9d127SSheldon Hearn 49f1b9d127SSheldon Hearn #include <cflib.h> 50f1b9d127SSheldon Hearn #include "rcfile_priv.h" 51f1b9d127SSheldon Hearn 52f1b9d127SSheldon Hearn SLIST_HEAD(rcfile_head, rcfile); 53f1b9d127SSheldon Hearn static struct rcfile_head pf_head = {NULL}; 54f1b9d127SSheldon Hearn 55f1b9d127SSheldon Hearn static struct rcfile* rc_cachelookup(const char *filename); 56f1b9d127SSheldon Hearn static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); 57f1b9d127SSheldon Hearn static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); 58f1b9d127SSheldon Hearn static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); 59f1b9d127SSheldon Hearn static struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); 60f1b9d127SSheldon Hearn static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value); 61f1b9d127SSheldon Hearn static void rc_key_free(struct rckey *p); 62f1b9d127SSheldon Hearn static void rc_parse(struct rcfile *rcp); 63f1b9d127SSheldon Hearn 64f1b9d127SSheldon Hearn 65f1b9d127SSheldon Hearn /* 66f1b9d127SSheldon Hearn * open rcfile and load its content, if already open - return previous handle 67f1b9d127SSheldon Hearn */ 68f1b9d127SSheldon Hearn int 69f1b9d127SSheldon Hearn rc_open(const char *filename, const char *mode, struct rcfile **rcfile) 70f1b9d127SSheldon Hearn { 71f1b9d127SSheldon Hearn struct rcfile *rcp; 72f1b9d127SSheldon Hearn FILE *f; 73f1b9d127SSheldon Hearn 74f1b9d127SSheldon Hearn rcp = rc_cachelookup(filename); 75f1b9d127SSheldon Hearn if (rcp) { 76f1b9d127SSheldon Hearn *rcfile = rcp; 77f1b9d127SSheldon Hearn return 0; 78f1b9d127SSheldon Hearn } 79f1b9d127SSheldon Hearn f = fopen(filename, mode); 80f1b9d127SSheldon Hearn if (f == NULL) 81f1b9d127SSheldon Hearn return errno; 82f1b9d127SSheldon Hearn rcp = malloc(sizeof(struct rcfile)); 83f1b9d127SSheldon Hearn if (rcp == NULL) { 84f1b9d127SSheldon Hearn fclose(f); 85f1b9d127SSheldon Hearn return ENOMEM; 86f1b9d127SSheldon Hearn } 87f1b9d127SSheldon Hearn bzero(rcp, sizeof(struct rcfile)); 88f1b9d127SSheldon Hearn rcp->rf_name = strdup(filename); 89f1b9d127SSheldon Hearn rcp->rf_f = f; 90f1b9d127SSheldon Hearn SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 91f1b9d127SSheldon Hearn rc_parse(rcp); 92f1b9d127SSheldon Hearn *rcfile = rcp; 93f1b9d127SSheldon Hearn return 0; 94f1b9d127SSheldon Hearn } 95f1b9d127SSheldon Hearn 96f1b9d127SSheldon Hearn int 97f1b9d127SSheldon Hearn rc_merge(const char *filename, struct rcfile **rcfile) 98f1b9d127SSheldon Hearn { 99f1b9d127SSheldon Hearn struct rcfile *rcp = *rcfile; 100f1b9d127SSheldon Hearn FILE *f, *t; 101f1b9d127SSheldon Hearn 102f1b9d127SSheldon Hearn if (rcp == NULL) { 103f1b9d127SSheldon Hearn return rc_open(filename, "r", rcfile); 104f1b9d127SSheldon Hearn } 105f1b9d127SSheldon Hearn f = fopen (filename, "r"); 106f1b9d127SSheldon Hearn if (f == NULL) 107f1b9d127SSheldon Hearn return errno; 108f1b9d127SSheldon Hearn t = rcp->rf_f; 109f1b9d127SSheldon Hearn rcp->rf_f = f; 110f1b9d127SSheldon Hearn rc_parse(rcp); 111f1b9d127SSheldon Hearn rcp->rf_f = t; 112f1b9d127SSheldon Hearn fclose(f); 113f1b9d127SSheldon Hearn return 0; 114f1b9d127SSheldon Hearn } 115f1b9d127SSheldon Hearn 116f1b9d127SSheldon Hearn int 117f1b9d127SSheldon Hearn rc_close(struct rcfile *rcp) 118f1b9d127SSheldon Hearn { 119f1b9d127SSheldon Hearn struct rcsection *p, *n; 120f1b9d127SSheldon Hearn 121f1b9d127SSheldon Hearn fclose(rcp->rf_f); 122f1b9d127SSheldon Hearn for(p = SLIST_FIRST(&rcp->rf_sect); p;) { 123f1b9d127SSheldon Hearn n = p; 124f1b9d127SSheldon Hearn p = SLIST_NEXT(p,rs_next); 125f1b9d127SSheldon Hearn rc_freesect(rcp, n); 126f1b9d127SSheldon Hearn } 127f1b9d127SSheldon Hearn free(rcp->rf_name); 128f1b9d127SSheldon Hearn SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 129f1b9d127SSheldon Hearn free(rcp); 130f1b9d127SSheldon Hearn return 0; 131f1b9d127SSheldon Hearn } 132f1b9d127SSheldon Hearn 133f1b9d127SSheldon Hearn static struct rcfile* 134f1b9d127SSheldon Hearn rc_cachelookup(const char *filename) 135f1b9d127SSheldon Hearn { 136f1b9d127SSheldon Hearn struct rcfile *p; 137f1b9d127SSheldon Hearn 138f1b9d127SSheldon Hearn SLIST_FOREACH(p, &pf_head, rf_next) 139f1b9d127SSheldon Hearn if (strcmp (filename, p->rf_name) == 0) 140f1b9d127SSheldon Hearn return p; 141f1b9d127SSheldon Hearn return 0; 142f1b9d127SSheldon Hearn } 143f1b9d127SSheldon Hearn 144f1b9d127SSheldon Hearn static struct rcsection * 145f1b9d127SSheldon Hearn rc_findsect(struct rcfile *rcp, const char *sectname) 146f1b9d127SSheldon Hearn { 147f1b9d127SSheldon Hearn struct rcsection *p; 148f1b9d127SSheldon Hearn 149f1b9d127SSheldon Hearn SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 150f1b9d127SSheldon Hearn if (strcmp(p->rs_name, sectname)==0) 151f1b9d127SSheldon Hearn return p; 152f1b9d127SSheldon Hearn return NULL; 153f1b9d127SSheldon Hearn } 154f1b9d127SSheldon Hearn 155f1b9d127SSheldon Hearn static struct rcsection * 156f1b9d127SSheldon Hearn rc_addsect(struct rcfile *rcp, const char *sectname) 157f1b9d127SSheldon Hearn { 158f1b9d127SSheldon Hearn struct rcsection *p; 159*4d6e5658SGleb Popov const char* sectletter = sectname; 160f1b9d127SSheldon Hearn 161f1b9d127SSheldon Hearn p = rc_findsect(rcp, sectname); 162f1b9d127SSheldon Hearn if (p) return p; 163f1b9d127SSheldon Hearn p = malloc(sizeof(*p)); 164f1b9d127SSheldon Hearn if (!p) return NULL; 165*4d6e5658SGleb Popov for(sectletter = sectname; *sectletter; sectletter++) { 166*4d6e5658SGleb Popov if (islower(*sectletter)) { 167*4d6e5658SGleb Popov if (strcmp(sectname, "default")) 168*4d6e5658SGleb Popov dprintf(STDERR_FILENO, "warning: section name [%s] contains lower-case letters\n", sectname); 169*4d6e5658SGleb Popov break; 170*4d6e5658SGleb Popov } 171*4d6e5658SGleb Popov } 172f1b9d127SSheldon Hearn p->rs_name = strdup(sectname); 173f1b9d127SSheldon Hearn SLIST_INIT(&p->rs_keys); 174f1b9d127SSheldon Hearn SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 175f1b9d127SSheldon Hearn return p; 176f1b9d127SSheldon Hearn } 177f1b9d127SSheldon Hearn 178f1b9d127SSheldon Hearn static int 179f1b9d127SSheldon Hearn rc_freesect(struct rcfile *rcp, struct rcsection *rsp) 180f1b9d127SSheldon Hearn { 181f1b9d127SSheldon Hearn struct rckey *p,*n; 182f1b9d127SSheldon Hearn 183f1b9d127SSheldon Hearn SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); 184f1b9d127SSheldon Hearn for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 185f1b9d127SSheldon Hearn n = p; 186f1b9d127SSheldon Hearn p = SLIST_NEXT(p,rk_next); 187f1b9d127SSheldon Hearn rc_key_free(n); 188f1b9d127SSheldon Hearn } 189f1b9d127SSheldon Hearn free(rsp->rs_name); 190f1b9d127SSheldon Hearn free(rsp); 191f1b9d127SSheldon Hearn return 0; 192f1b9d127SSheldon Hearn } 193f1b9d127SSheldon Hearn 194f1b9d127SSheldon Hearn static struct rckey * 195f1b9d127SSheldon Hearn rc_sect_findkey(struct rcsection *rsp, const char *keyname) 196f1b9d127SSheldon Hearn { 197f1b9d127SSheldon Hearn struct rckey *p; 198f1b9d127SSheldon Hearn 199f1b9d127SSheldon Hearn SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 200f1b9d127SSheldon Hearn if (strcmp(p->rk_name, keyname)==0) 201f1b9d127SSheldon Hearn return p; 202f1b9d127SSheldon Hearn return NULL; 203f1b9d127SSheldon Hearn } 204f1b9d127SSheldon Hearn 205f1b9d127SSheldon Hearn static struct rckey * 206f1b9d127SSheldon Hearn rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) 207f1b9d127SSheldon Hearn { 208f1b9d127SSheldon Hearn struct rckey *p; 209f1b9d127SSheldon Hearn 210f1b9d127SSheldon Hearn p = rc_sect_findkey(rsp, name); 211f1b9d127SSheldon Hearn if (p) { 212f1b9d127SSheldon Hearn free(p->rk_value); 213f1b9d127SSheldon Hearn } else { 214f1b9d127SSheldon Hearn p = malloc(sizeof(*p)); 215f1b9d127SSheldon Hearn if (!p) return NULL; 216f1b9d127SSheldon Hearn SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 217f1b9d127SSheldon Hearn p->rk_name = strdup(name); 218f1b9d127SSheldon Hearn } 219f1b9d127SSheldon Hearn p->rk_value = value ? strdup(value) : strdup(""); 220f1b9d127SSheldon Hearn return p; 221f1b9d127SSheldon Hearn } 222f1b9d127SSheldon Hearn 223f1b9d127SSheldon Hearn #if 0 224f1b9d127SSheldon Hearn void 225f1b9d127SSheldon Hearn rc_sect_delkey(struct rcsection *rsp, struct rckey *p) 226f1b9d127SSheldon Hearn { 227f1b9d127SSheldon Hearn 228f1b9d127SSheldon Hearn SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); 229f1b9d127SSheldon Hearn rc_key_free(p); 230f1b9d127SSheldon Hearn return; 231f1b9d127SSheldon Hearn } 232f1b9d127SSheldon Hearn #endif 233f1b9d127SSheldon Hearn 234f1b9d127SSheldon Hearn static void 235f1b9d127SSheldon Hearn rc_key_free(struct rckey *p) 236f1b9d127SSheldon Hearn { 237f1b9d127SSheldon Hearn free(p->rk_value); 238f1b9d127SSheldon Hearn free(p->rk_name); 239f1b9d127SSheldon Hearn free(p); 240f1b9d127SSheldon Hearn } 241f1b9d127SSheldon Hearn 242f1b9d127SSheldon Hearn enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 243f1b9d127SSheldon Hearn 244f1b9d127SSheldon Hearn static void 245f1b9d127SSheldon Hearn rc_parse(struct rcfile *rcp) 246f1b9d127SSheldon Hearn { 247f1b9d127SSheldon Hearn FILE *f = rcp->rf_f; 248f1b9d127SSheldon Hearn int state = stNewLine, c; 249f1b9d127SSheldon Hearn struct rcsection *rsp = NULL; 250f1b9d127SSheldon Hearn struct rckey *rkp = NULL; 251f1b9d127SSheldon Hearn char buf[2048]; 252f1b9d127SSheldon Hearn char *next = buf, *last = &buf[sizeof(buf)-1]; 253f1b9d127SSheldon Hearn 254f1b9d127SSheldon Hearn while ((c = getc (f)) != EOF) { 255f1b9d127SSheldon Hearn if (c == '\r') 256f1b9d127SSheldon Hearn continue; 257f1b9d127SSheldon Hearn if (state == stNewLine) { 258f1b9d127SSheldon Hearn next = buf; 259f1b9d127SSheldon Hearn if (isspace(c)) 260f1b9d127SSheldon Hearn continue; /* skip leading junk */ 261f1b9d127SSheldon Hearn if (c == '[') { 262f1b9d127SSheldon Hearn state = stHeader; 263f1b9d127SSheldon Hearn rsp = NULL; 264f1b9d127SSheldon Hearn continue; 265f1b9d127SSheldon Hearn } 266f1b9d127SSheldon Hearn if (c == '#' || c == ';') { 267f1b9d127SSheldon Hearn state = stSkipToEOL; 268f1b9d127SSheldon Hearn } else { /* something meaningfull */ 269f1b9d127SSheldon Hearn state = stGetKey; 270f1b9d127SSheldon Hearn } 271f1b9d127SSheldon Hearn } 272f1b9d127SSheldon Hearn if (state == stSkipToEOL || next == last) {/* ignore long lines */ 273f1b9d127SSheldon Hearn if (c == '\n'){ 274f1b9d127SSheldon Hearn state = stNewLine; 275f1b9d127SSheldon Hearn next = buf; 276f1b9d127SSheldon Hearn } 277f1b9d127SSheldon Hearn continue; 278f1b9d127SSheldon Hearn } 279f1b9d127SSheldon Hearn if (state == stHeader) { 280f1b9d127SSheldon Hearn if (c == ']') { 281f1b9d127SSheldon Hearn *next = 0; 282f1b9d127SSheldon Hearn next = buf; 283f1b9d127SSheldon Hearn rsp = rc_addsect(rcp, buf); 284f1b9d127SSheldon Hearn state = stSkipToEOL; 285f1b9d127SSheldon Hearn } else 286f1b9d127SSheldon Hearn *next++ = c; 287f1b9d127SSheldon Hearn continue; 288f1b9d127SSheldon Hearn } 289f1b9d127SSheldon Hearn if (state == stGetKey) { 290f1b9d127SSheldon Hearn if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 291f1b9d127SSheldon Hearn continue; /* become 'keyname=' */ 292f1b9d127SSheldon Hearn if (c == '\n') { /* silently ignore ... */ 293f1b9d127SSheldon Hearn state = stNewLine; 294f1b9d127SSheldon Hearn continue; 295f1b9d127SSheldon Hearn } 296f1b9d127SSheldon Hearn if (c != '=') { 297f1b9d127SSheldon Hearn *next++ = c; 298f1b9d127SSheldon Hearn continue; 299f1b9d127SSheldon Hearn } 300f1b9d127SSheldon Hearn *next = 0; 301f1b9d127SSheldon Hearn if (rsp == NULL) { 302f1b9d127SSheldon Hearn fprintf(stderr, "Key '%s' defined before section\n", buf); 303f1b9d127SSheldon Hearn state = stSkipToEOL; 304f1b9d127SSheldon Hearn continue; 305f1b9d127SSheldon Hearn } 306f1b9d127SSheldon Hearn rkp = rc_sect_addkey(rsp, buf, NULL); 307f1b9d127SSheldon Hearn next = buf; 308f1b9d127SSheldon Hearn state = stGetValue; 309f1b9d127SSheldon Hearn continue; 310f1b9d127SSheldon Hearn } 311f1b9d127SSheldon Hearn /* only stGetValue left */ 312f1b9d127SSheldon Hearn if (state != stGetValue) { 313f1b9d127SSheldon Hearn fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 314f1b9d127SSheldon Hearn state = stSkipToEOL; 315f1b9d127SSheldon Hearn } 316f1b9d127SSheldon Hearn if (c != '\n') { 317f1b9d127SSheldon Hearn *next++ = c; 318f1b9d127SSheldon Hearn continue; 319f1b9d127SSheldon Hearn } 320f1b9d127SSheldon Hearn *next = 0; 321f1b9d127SSheldon Hearn rkp->rk_value = strdup(buf); 322f1b9d127SSheldon Hearn state = stNewLine; 323f1b9d127SSheldon Hearn rkp = NULL; 324f1b9d127SSheldon Hearn } /* while */ 325f1b9d127SSheldon Hearn if (c == EOF && state == stGetValue) { 326f1b9d127SSheldon Hearn *next = 0; 327f1b9d127SSheldon Hearn rkp->rk_value = strdup(buf); 328f1b9d127SSheldon Hearn } 329f1b9d127SSheldon Hearn return; 330f1b9d127SSheldon Hearn } 331f1b9d127SSheldon Hearn 332f1b9d127SSheldon Hearn int 333f1b9d127SSheldon Hearn rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, 334f1b9d127SSheldon Hearn char **dest) 335f1b9d127SSheldon Hearn { 336f1b9d127SSheldon Hearn struct rcsection *rsp; 337f1b9d127SSheldon Hearn struct rckey *rkp; 338f1b9d127SSheldon Hearn 339f1b9d127SSheldon Hearn *dest = NULL; 340f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 341f1b9d127SSheldon Hearn if (!rsp) return ENOENT; 342f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp,key); 343f1b9d127SSheldon Hearn if (!rkp) return ENOENT; 344f1b9d127SSheldon Hearn *dest = rkp->rk_value; 345f1b9d127SSheldon Hearn return 0; 346f1b9d127SSheldon Hearn } 347f1b9d127SSheldon Hearn 348f1b9d127SSheldon Hearn int 349f1b9d127SSheldon Hearn rc_getstring(struct rcfile *rcp, const char *section, const char *key, 350f1b9d127SSheldon Hearn size_t maxlen, char *dest) 351f1b9d127SSheldon Hearn { 352f1b9d127SSheldon Hearn char *value; 353f1b9d127SSheldon Hearn int error; 354f1b9d127SSheldon Hearn 355f1b9d127SSheldon Hearn error = rc_getstringptr(rcp, section, key, &value); 356f1b9d127SSheldon Hearn if (error) 357f1b9d127SSheldon Hearn return error; 358f1b9d127SSheldon Hearn if (strlen(value) >= maxlen) { 3591ac62e0bSDavid E. O'Brien warnx("line too long for key '%s' in section '%s', max = %zd\n", key, section, maxlen); 360f1b9d127SSheldon Hearn return EINVAL; 361f1b9d127SSheldon Hearn } 362f1b9d127SSheldon Hearn strcpy(dest, value); 363f1b9d127SSheldon Hearn return 0; 364f1b9d127SSheldon Hearn } 365f1b9d127SSheldon Hearn 366f1b9d127SSheldon Hearn int 367f1b9d127SSheldon Hearn rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) 368f1b9d127SSheldon Hearn { 369f1b9d127SSheldon Hearn struct rcsection *rsp; 370f1b9d127SSheldon Hearn struct rckey *rkp; 371f1b9d127SSheldon Hearn 372f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 373f1b9d127SSheldon Hearn if (!rsp) 374f1b9d127SSheldon Hearn return ENOENT; 375f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp, key); 376f1b9d127SSheldon Hearn if (!rkp) 377f1b9d127SSheldon Hearn return ENOENT; 378f1b9d127SSheldon Hearn errno = 0; 379f1b9d127SSheldon Hearn *value = strtol(rkp->rk_value, NULL, 0); 380f1b9d127SSheldon Hearn if (errno) { 381f1b9d127SSheldon Hearn warnx("invalid int value '%s' for key '%s' in section '%s'\n", rkp->rk_value, key, section); 382f1b9d127SSheldon Hearn return errno; 383f1b9d127SSheldon Hearn } 384f1b9d127SSheldon Hearn return 0; 385f1b9d127SSheldon Hearn } 386f1b9d127SSheldon Hearn 387f1b9d127SSheldon Hearn /* 388f1b9d127SSheldon Hearn * 1,yes,true 389f1b9d127SSheldon Hearn * 0,no,false 390f1b9d127SSheldon Hearn */ 391f1b9d127SSheldon Hearn int 392f1b9d127SSheldon Hearn rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) 393f1b9d127SSheldon Hearn { 394f1b9d127SSheldon Hearn struct rcsection *rsp; 395f1b9d127SSheldon Hearn struct rckey *rkp; 396f1b9d127SSheldon Hearn char *p; 397f1b9d127SSheldon Hearn 398f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 399f1b9d127SSheldon Hearn if (!rsp) return ENOENT; 400f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp,key); 401f1b9d127SSheldon Hearn if (!rkp) return ENOENT; 402f1b9d127SSheldon Hearn p = rkp->rk_value; 403f1b9d127SSheldon Hearn while (*p && isspace(*p)) p++; 404f1b9d127SSheldon Hearn if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 405f1b9d127SSheldon Hearn *value = 0; 406f1b9d127SSheldon Hearn return 0; 407f1b9d127SSheldon Hearn } 408f1b9d127SSheldon Hearn if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 409f1b9d127SSheldon Hearn *value = 1; 410f1b9d127SSheldon Hearn return 0; 411f1b9d127SSheldon Hearn } 412f1b9d127SSheldon Hearn fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 413f1b9d127SSheldon Hearn return EINVAL; 414f1b9d127SSheldon Hearn } 415f1b9d127SSheldon Hearn 416f1b9d127SSheldon Hearn /* 417f1b9d127SSheldon Hearn * Unified command line/rc file parser 418f1b9d127SSheldon Hearn */ 419f1b9d127SSheldon Hearn int 420f1b9d127SSheldon Hearn opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, 421f1b9d127SSheldon Hearn opt_callback_t *callback) 422f1b9d127SSheldon Hearn { 423f1b9d127SSheldon Hearn int len, error; 424f1b9d127SSheldon Hearn 425f1b9d127SSheldon Hearn for (; ap->opt; ap++) { 426f1b9d127SSheldon Hearn switch (ap->type) { 427f1b9d127SSheldon Hearn case OPTARG_STR: 428f1b9d127SSheldon Hearn if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) 429f1b9d127SSheldon Hearn break; 430f1b9d127SSheldon Hearn len = strlen(ap->str); 431f1b9d127SSheldon Hearn if (len > ap->ival) { 432f1b9d127SSheldon Hearn warnx("rc: argument for option '%c' (%s) too long\n", ap->opt, ap->name); 433f1b9d127SSheldon Hearn return EINVAL; 434f1b9d127SSheldon Hearn } 435f1b9d127SSheldon Hearn callback(ap); 436f1b9d127SSheldon Hearn break; 437f1b9d127SSheldon Hearn case OPTARG_BOOL: 438f1b9d127SSheldon Hearn error = rc_getbool(rcp, sect, ap->name, &ap->ival); 439f1b9d127SSheldon Hearn if (error == ENOENT) 440f1b9d127SSheldon Hearn break; 441f1b9d127SSheldon Hearn if (error) 442f1b9d127SSheldon Hearn return EINVAL; 443f1b9d127SSheldon Hearn callback(ap); 444f1b9d127SSheldon Hearn break; 445f1b9d127SSheldon Hearn case OPTARG_INT: 446f1b9d127SSheldon Hearn if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) 447f1b9d127SSheldon Hearn break; 448f1b9d127SSheldon Hearn if (((ap->flag & OPTFL_HAVEMIN) && ap->ival < ap->min) || 449f1b9d127SSheldon Hearn ((ap->flag & OPTFL_HAVEMAX) && ap->ival > ap->max)) { 450f1b9d127SSheldon Hearn warnx("rc: argument for option '%c' (%s) should be in [%d-%d] range\n", 451f1b9d127SSheldon Hearn ap->opt, ap->name, ap->min, ap->max); 452f1b9d127SSheldon Hearn return EINVAL; 453f1b9d127SSheldon Hearn } 454f1b9d127SSheldon Hearn callback(ap); 455f1b9d127SSheldon Hearn break; 456f1b9d127SSheldon Hearn default: 457f1b9d127SSheldon Hearn break; 458f1b9d127SSheldon Hearn } 459f1b9d127SSheldon Hearn } 460f1b9d127SSheldon Hearn return 0; 461f1b9d127SSheldon Hearn } 462f1b9d127SSheldon Hearn 463f1b9d127SSheldon Hearn int 464f1b9d127SSheldon Hearn opt_args_parseopt(struct opt_args *ap, int opt, char *arg, 465f1b9d127SSheldon Hearn opt_callback_t *callback) 466f1b9d127SSheldon Hearn { 467f1b9d127SSheldon Hearn int len; 468f1b9d127SSheldon Hearn 469f1b9d127SSheldon Hearn for (; ap->opt; ap++) { 470f1b9d127SSheldon Hearn if (ap->opt != opt) 471f1b9d127SSheldon Hearn continue; 472f1b9d127SSheldon Hearn switch (ap->type) { 473f1b9d127SSheldon Hearn case OPTARG_STR: 474f1b9d127SSheldon Hearn ap->str = arg; 475f1b9d127SSheldon Hearn if (arg) { 476f1b9d127SSheldon Hearn len = strlen(ap->str); 477f1b9d127SSheldon Hearn if (len > ap->ival) { 478f1b9d127SSheldon Hearn warnx("opt: Argument for option '%c' (%s) too long\n", ap->opt, ap->name); 479f1b9d127SSheldon Hearn return EINVAL; 480f1b9d127SSheldon Hearn } 481f1b9d127SSheldon Hearn callback(ap); 482f1b9d127SSheldon Hearn } 483f1b9d127SSheldon Hearn break; 484f1b9d127SSheldon Hearn case OPTARG_BOOL: 485f1b9d127SSheldon Hearn ap->ival = 0; 486f1b9d127SSheldon Hearn callback(ap); 487f1b9d127SSheldon Hearn break; 488f1b9d127SSheldon Hearn case OPTARG_INT: 489f1b9d127SSheldon Hearn errno = 0; 490f1b9d127SSheldon Hearn ap->ival = strtol(arg, NULL, 0); 491f1b9d127SSheldon Hearn if (errno) { 492f1b9d127SSheldon Hearn warnx("opt: Invalid integer value for option '%c' (%s).\n",ap->opt,ap->name); 493f1b9d127SSheldon Hearn return EINVAL; 494f1b9d127SSheldon Hearn } 495f1b9d127SSheldon Hearn if (((ap->flag & OPTFL_HAVEMIN) && 496f1b9d127SSheldon Hearn (ap->ival < ap->min)) || 497f1b9d127SSheldon Hearn ((ap->flag & OPTFL_HAVEMAX) && 498f1b9d127SSheldon Hearn (ap->ival > ap->max))) { 499f1b9d127SSheldon Hearn warnx("opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",ap->opt,ap->name,ap->min,ap->max); 500f1b9d127SSheldon Hearn return EINVAL; 501f1b9d127SSheldon Hearn } 502f1b9d127SSheldon Hearn callback(ap); 503f1b9d127SSheldon Hearn break; 504f1b9d127SSheldon Hearn default: 505f1b9d127SSheldon Hearn break; 506f1b9d127SSheldon Hearn } 507f1b9d127SSheldon Hearn break; 508f1b9d127SSheldon Hearn } 509f1b9d127SSheldon Hearn return 0; 510f1b9d127SSheldon Hearn } 511f1b9d127SSheldon Hearn 512