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; 159f1b9d127SSheldon Hearn 160f1b9d127SSheldon Hearn p = rc_findsect(rcp, sectname); 161f1b9d127SSheldon Hearn if (p) return p; 162f1b9d127SSheldon Hearn p = malloc(sizeof(*p)); 163f1b9d127SSheldon Hearn if (!p) return NULL; 164f1b9d127SSheldon Hearn p->rs_name = strdup(sectname); 165f1b9d127SSheldon Hearn SLIST_INIT(&p->rs_keys); 166f1b9d127SSheldon Hearn SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 167f1b9d127SSheldon Hearn return p; 168f1b9d127SSheldon Hearn } 169f1b9d127SSheldon Hearn 170f1b9d127SSheldon Hearn static int 171f1b9d127SSheldon Hearn rc_freesect(struct rcfile *rcp, struct rcsection *rsp) 172f1b9d127SSheldon Hearn { 173f1b9d127SSheldon Hearn struct rckey *p,*n; 174f1b9d127SSheldon Hearn 175f1b9d127SSheldon Hearn SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); 176f1b9d127SSheldon Hearn for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 177f1b9d127SSheldon Hearn n = p; 178f1b9d127SSheldon Hearn p = SLIST_NEXT(p,rk_next); 179f1b9d127SSheldon Hearn rc_key_free(n); 180f1b9d127SSheldon Hearn } 181f1b9d127SSheldon Hearn free(rsp->rs_name); 182f1b9d127SSheldon Hearn free(rsp); 183f1b9d127SSheldon Hearn return 0; 184f1b9d127SSheldon Hearn } 185f1b9d127SSheldon Hearn 186f1b9d127SSheldon Hearn static struct rckey * 187f1b9d127SSheldon Hearn rc_sect_findkey(struct rcsection *rsp, const char *keyname) 188f1b9d127SSheldon Hearn { 189f1b9d127SSheldon Hearn struct rckey *p; 190f1b9d127SSheldon Hearn 191f1b9d127SSheldon Hearn SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 192f1b9d127SSheldon Hearn if (strcmp(p->rk_name, keyname)==0) 193f1b9d127SSheldon Hearn return p; 194f1b9d127SSheldon Hearn return NULL; 195f1b9d127SSheldon Hearn } 196f1b9d127SSheldon Hearn 197f1b9d127SSheldon Hearn static struct rckey * 198f1b9d127SSheldon Hearn rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) 199f1b9d127SSheldon Hearn { 200f1b9d127SSheldon Hearn struct rckey *p; 201f1b9d127SSheldon Hearn 202f1b9d127SSheldon Hearn p = rc_sect_findkey(rsp, name); 203f1b9d127SSheldon Hearn if (p) { 204f1b9d127SSheldon Hearn free(p->rk_value); 205f1b9d127SSheldon Hearn } else { 206f1b9d127SSheldon Hearn p = malloc(sizeof(*p)); 207f1b9d127SSheldon Hearn if (!p) return NULL; 208f1b9d127SSheldon Hearn SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 209f1b9d127SSheldon Hearn p->rk_name = strdup(name); 210f1b9d127SSheldon Hearn } 211f1b9d127SSheldon Hearn p->rk_value = value ? strdup(value) : strdup(""); 212f1b9d127SSheldon Hearn return p; 213f1b9d127SSheldon Hearn } 214f1b9d127SSheldon Hearn 215f1b9d127SSheldon Hearn #if 0 216f1b9d127SSheldon Hearn void 217f1b9d127SSheldon Hearn rc_sect_delkey(struct rcsection *rsp, struct rckey *p) 218f1b9d127SSheldon Hearn { 219f1b9d127SSheldon Hearn 220f1b9d127SSheldon Hearn SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); 221f1b9d127SSheldon Hearn rc_key_free(p); 222f1b9d127SSheldon Hearn return; 223f1b9d127SSheldon Hearn } 224f1b9d127SSheldon Hearn #endif 225f1b9d127SSheldon Hearn 226f1b9d127SSheldon Hearn static void 227f1b9d127SSheldon Hearn rc_key_free(struct rckey *p) 228f1b9d127SSheldon Hearn { 229f1b9d127SSheldon Hearn free(p->rk_value); 230f1b9d127SSheldon Hearn free(p->rk_name); 231f1b9d127SSheldon Hearn free(p); 232f1b9d127SSheldon Hearn } 233f1b9d127SSheldon Hearn 234f1b9d127SSheldon Hearn enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 235f1b9d127SSheldon Hearn 236f1b9d127SSheldon Hearn static void 237f1b9d127SSheldon Hearn rc_parse(struct rcfile *rcp) 238f1b9d127SSheldon Hearn { 239f1b9d127SSheldon Hearn FILE *f = rcp->rf_f; 240f1b9d127SSheldon Hearn int state = stNewLine, c; 241f1b9d127SSheldon Hearn struct rcsection *rsp = NULL; 242f1b9d127SSheldon Hearn struct rckey *rkp = NULL; 243f1b9d127SSheldon Hearn char buf[2048]; 244f1b9d127SSheldon Hearn char *next = buf, *last = &buf[sizeof(buf)-1]; 245f1b9d127SSheldon Hearn 246f1b9d127SSheldon Hearn while ((c = getc (f)) != EOF) { 247f1b9d127SSheldon Hearn if (c == '\r') 248f1b9d127SSheldon Hearn continue; 249f1b9d127SSheldon Hearn if (state == stNewLine) { 250f1b9d127SSheldon Hearn next = buf; 251f1b9d127SSheldon Hearn if (isspace(c)) 252f1b9d127SSheldon Hearn continue; /* skip leading junk */ 253f1b9d127SSheldon Hearn if (c == '[') { 254f1b9d127SSheldon Hearn state = stHeader; 255f1b9d127SSheldon Hearn rsp = NULL; 256f1b9d127SSheldon Hearn continue; 257f1b9d127SSheldon Hearn } 258f1b9d127SSheldon Hearn if (c == '#' || c == ';') { 259f1b9d127SSheldon Hearn state = stSkipToEOL; 260f1b9d127SSheldon Hearn } else { /* something meaningfull */ 261f1b9d127SSheldon Hearn state = stGetKey; 262f1b9d127SSheldon Hearn } 263f1b9d127SSheldon Hearn } 264f1b9d127SSheldon Hearn if (state == stSkipToEOL || next == last) {/* ignore long lines */ 265f1b9d127SSheldon Hearn if (c == '\n'){ 266f1b9d127SSheldon Hearn state = stNewLine; 267f1b9d127SSheldon Hearn next = buf; 268f1b9d127SSheldon Hearn } 269f1b9d127SSheldon Hearn continue; 270f1b9d127SSheldon Hearn } 271f1b9d127SSheldon Hearn if (state == stHeader) { 272f1b9d127SSheldon Hearn if (c == ']') { 273f1b9d127SSheldon Hearn *next = 0; 274f1b9d127SSheldon Hearn next = buf; 275f1b9d127SSheldon Hearn rsp = rc_addsect(rcp, buf); 276f1b9d127SSheldon Hearn state = stSkipToEOL; 277f1b9d127SSheldon Hearn } else 278f1b9d127SSheldon Hearn *next++ = c; 279f1b9d127SSheldon Hearn continue; 280f1b9d127SSheldon Hearn } 281f1b9d127SSheldon Hearn if (state == stGetKey) { 282f1b9d127SSheldon Hearn if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 283f1b9d127SSheldon Hearn continue; /* become 'keyname=' */ 284f1b9d127SSheldon Hearn if (c == '\n') { /* silently ignore ... */ 285f1b9d127SSheldon Hearn state = stNewLine; 286f1b9d127SSheldon Hearn continue; 287f1b9d127SSheldon Hearn } 288f1b9d127SSheldon Hearn if (c != '=') { 289f1b9d127SSheldon Hearn *next++ = c; 290f1b9d127SSheldon Hearn continue; 291f1b9d127SSheldon Hearn } 292f1b9d127SSheldon Hearn *next = 0; 293f1b9d127SSheldon Hearn if (rsp == NULL) { 294f1b9d127SSheldon Hearn fprintf(stderr, "Key '%s' defined before section\n", buf); 295f1b9d127SSheldon Hearn state = stSkipToEOL; 296f1b9d127SSheldon Hearn continue; 297f1b9d127SSheldon Hearn } 298f1b9d127SSheldon Hearn rkp = rc_sect_addkey(rsp, buf, NULL); 299f1b9d127SSheldon Hearn next = buf; 300f1b9d127SSheldon Hearn state = stGetValue; 301f1b9d127SSheldon Hearn continue; 302f1b9d127SSheldon Hearn } 303f1b9d127SSheldon Hearn /* only stGetValue left */ 304f1b9d127SSheldon Hearn if (state != stGetValue) { 305f1b9d127SSheldon Hearn fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 306f1b9d127SSheldon Hearn state = stSkipToEOL; 307f1b9d127SSheldon Hearn } 308f1b9d127SSheldon Hearn if (c != '\n') { 309f1b9d127SSheldon Hearn *next++ = c; 310f1b9d127SSheldon Hearn continue; 311f1b9d127SSheldon Hearn } 312f1b9d127SSheldon Hearn *next = 0; 313f1b9d127SSheldon Hearn rkp->rk_value = strdup(buf); 314f1b9d127SSheldon Hearn state = stNewLine; 315f1b9d127SSheldon Hearn rkp = NULL; 316f1b9d127SSheldon Hearn } /* while */ 317f1b9d127SSheldon Hearn if (c == EOF && state == stGetValue) { 318f1b9d127SSheldon Hearn *next = 0; 319f1b9d127SSheldon Hearn rkp->rk_value = strdup(buf); 320f1b9d127SSheldon Hearn } 321f1b9d127SSheldon Hearn return; 322f1b9d127SSheldon Hearn } 323f1b9d127SSheldon Hearn 324f1b9d127SSheldon Hearn int 325f1b9d127SSheldon Hearn rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, 326f1b9d127SSheldon Hearn char **dest) 327f1b9d127SSheldon Hearn { 328f1b9d127SSheldon Hearn struct rcsection *rsp; 329f1b9d127SSheldon Hearn struct rckey *rkp; 330f1b9d127SSheldon Hearn 331f1b9d127SSheldon Hearn *dest = NULL; 332f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 333f1b9d127SSheldon Hearn if (!rsp) return ENOENT; 334f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp,key); 335f1b9d127SSheldon Hearn if (!rkp) return ENOENT; 336f1b9d127SSheldon Hearn *dest = rkp->rk_value; 337f1b9d127SSheldon Hearn return 0; 338f1b9d127SSheldon Hearn } 339f1b9d127SSheldon Hearn 340f1b9d127SSheldon Hearn int 341f1b9d127SSheldon Hearn rc_getstring(struct rcfile *rcp, const char *section, const char *key, 342f1b9d127SSheldon Hearn size_t maxlen, char *dest) 343f1b9d127SSheldon Hearn { 344f1b9d127SSheldon Hearn char *value; 345f1b9d127SSheldon Hearn int error; 346f1b9d127SSheldon Hearn 347f1b9d127SSheldon Hearn error = rc_getstringptr(rcp, section, key, &value); 348f1b9d127SSheldon Hearn if (error) 349f1b9d127SSheldon Hearn return error; 350f1b9d127SSheldon Hearn if (strlen(value) >= maxlen) { 3511ac62e0bSDavid E. O'Brien warnx("line too long for key '%s' in section '%s', max = %zd\n", key, section, maxlen); 352f1b9d127SSheldon Hearn return EINVAL; 353f1b9d127SSheldon Hearn } 354f1b9d127SSheldon Hearn strcpy(dest, value); 355f1b9d127SSheldon Hearn return 0; 356f1b9d127SSheldon Hearn } 357f1b9d127SSheldon Hearn 358f1b9d127SSheldon Hearn int 359f1b9d127SSheldon Hearn rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) 360f1b9d127SSheldon Hearn { 361f1b9d127SSheldon Hearn struct rcsection *rsp; 362f1b9d127SSheldon Hearn struct rckey *rkp; 363f1b9d127SSheldon Hearn 364f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 365f1b9d127SSheldon Hearn if (!rsp) 366f1b9d127SSheldon Hearn return ENOENT; 367f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp, key); 368f1b9d127SSheldon Hearn if (!rkp) 369f1b9d127SSheldon Hearn return ENOENT; 370f1b9d127SSheldon Hearn errno = 0; 371f1b9d127SSheldon Hearn *value = strtol(rkp->rk_value, NULL, 0); 372f1b9d127SSheldon Hearn if (errno) { 373f1b9d127SSheldon Hearn warnx("invalid int value '%s' for key '%s' in section '%s'\n", rkp->rk_value, key, section); 374f1b9d127SSheldon Hearn return errno; 375f1b9d127SSheldon Hearn } 376f1b9d127SSheldon Hearn return 0; 377f1b9d127SSheldon Hearn } 378f1b9d127SSheldon Hearn 379f1b9d127SSheldon Hearn /* 380f1b9d127SSheldon Hearn * 1,yes,true 381f1b9d127SSheldon Hearn * 0,no,false 382f1b9d127SSheldon Hearn */ 383f1b9d127SSheldon Hearn int 384f1b9d127SSheldon Hearn rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) 385f1b9d127SSheldon Hearn { 386f1b9d127SSheldon Hearn struct rcsection *rsp; 387f1b9d127SSheldon Hearn struct rckey *rkp; 388f1b9d127SSheldon Hearn char *p; 389f1b9d127SSheldon Hearn 390f1b9d127SSheldon Hearn rsp = rc_findsect(rcp, section); 391f1b9d127SSheldon Hearn if (!rsp) return ENOENT; 392f1b9d127SSheldon Hearn rkp = rc_sect_findkey(rsp,key); 393f1b9d127SSheldon Hearn if (!rkp) return ENOENT; 394f1b9d127SSheldon Hearn p = rkp->rk_value; 395f1b9d127SSheldon Hearn while (*p && isspace(*p)) p++; 396f1b9d127SSheldon Hearn if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 397f1b9d127SSheldon Hearn *value = 0; 398f1b9d127SSheldon Hearn return 0; 399f1b9d127SSheldon Hearn } 400f1b9d127SSheldon Hearn if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 401f1b9d127SSheldon Hearn *value = 1; 402f1b9d127SSheldon Hearn return 0; 403f1b9d127SSheldon Hearn } 404f1b9d127SSheldon Hearn fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 405f1b9d127SSheldon Hearn return EINVAL; 406f1b9d127SSheldon Hearn } 407f1b9d127SSheldon Hearn 408f1b9d127SSheldon Hearn /* 409f1b9d127SSheldon Hearn * Unified command line/rc file parser 410f1b9d127SSheldon Hearn */ 411f1b9d127SSheldon Hearn int 412f1b9d127SSheldon Hearn opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, 413f1b9d127SSheldon Hearn opt_callback_t *callback) 414f1b9d127SSheldon Hearn { 415f1b9d127SSheldon Hearn int len, error; 416f1b9d127SSheldon Hearn 417f1b9d127SSheldon Hearn for (; ap->opt; ap++) { 418f1b9d127SSheldon Hearn switch (ap->type) { 419f1b9d127SSheldon Hearn case OPTARG_STR: 420f1b9d127SSheldon Hearn if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) 421f1b9d127SSheldon Hearn break; 422f1b9d127SSheldon Hearn len = strlen(ap->str); 423f1b9d127SSheldon Hearn if (len > ap->ival) { 424f1b9d127SSheldon Hearn warnx("rc: argument for option '%c' (%s) too long\n", ap->opt, ap->name); 425f1b9d127SSheldon Hearn return EINVAL; 426f1b9d127SSheldon Hearn } 427f1b9d127SSheldon Hearn callback(ap); 428f1b9d127SSheldon Hearn break; 429f1b9d127SSheldon Hearn case OPTARG_BOOL: 430f1b9d127SSheldon Hearn error = rc_getbool(rcp, sect, ap->name, &ap->ival); 431f1b9d127SSheldon Hearn if (error == ENOENT) 432f1b9d127SSheldon Hearn break; 433f1b9d127SSheldon Hearn if (error) 434f1b9d127SSheldon Hearn return EINVAL; 435f1b9d127SSheldon Hearn callback(ap); 436f1b9d127SSheldon Hearn break; 437f1b9d127SSheldon Hearn case OPTARG_INT: 438f1b9d127SSheldon Hearn if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) 439f1b9d127SSheldon Hearn break; 440f1b9d127SSheldon Hearn if (((ap->flag & OPTFL_HAVEMIN) && ap->ival < ap->min) || 441f1b9d127SSheldon Hearn ((ap->flag & OPTFL_HAVEMAX) && ap->ival > ap->max)) { 442f1b9d127SSheldon Hearn warnx("rc: argument for option '%c' (%s) should be in [%d-%d] range\n", 443f1b9d127SSheldon Hearn ap->opt, ap->name, ap->min, ap->max); 444f1b9d127SSheldon Hearn return EINVAL; 445f1b9d127SSheldon Hearn } 446f1b9d127SSheldon Hearn callback(ap); 447f1b9d127SSheldon Hearn break; 448f1b9d127SSheldon Hearn default: 449f1b9d127SSheldon Hearn break; 450f1b9d127SSheldon Hearn } 451f1b9d127SSheldon Hearn } 452f1b9d127SSheldon Hearn return 0; 453f1b9d127SSheldon Hearn } 454f1b9d127SSheldon Hearn 455f1b9d127SSheldon Hearn int 456f1b9d127SSheldon Hearn opt_args_parseopt(struct opt_args *ap, int opt, char *arg, 457f1b9d127SSheldon Hearn opt_callback_t *callback) 458f1b9d127SSheldon Hearn { 459f1b9d127SSheldon Hearn int len; 460f1b9d127SSheldon Hearn 461f1b9d127SSheldon Hearn for (; ap->opt; ap++) { 462f1b9d127SSheldon Hearn if (ap->opt != opt) 463f1b9d127SSheldon Hearn continue; 464f1b9d127SSheldon Hearn switch (ap->type) { 465f1b9d127SSheldon Hearn case OPTARG_STR: 466f1b9d127SSheldon Hearn ap->str = arg; 467f1b9d127SSheldon Hearn if (arg) { 468f1b9d127SSheldon Hearn len = strlen(ap->str); 469f1b9d127SSheldon Hearn if (len > ap->ival) { 470f1b9d127SSheldon Hearn warnx("opt: Argument for option '%c' (%s) too long\n", ap->opt, ap->name); 471f1b9d127SSheldon Hearn return EINVAL; 472f1b9d127SSheldon Hearn } 473f1b9d127SSheldon Hearn callback(ap); 474f1b9d127SSheldon Hearn } 475f1b9d127SSheldon Hearn break; 476f1b9d127SSheldon Hearn case OPTARG_BOOL: 477f1b9d127SSheldon Hearn ap->ival = 0; 478f1b9d127SSheldon Hearn callback(ap); 479f1b9d127SSheldon Hearn break; 480f1b9d127SSheldon Hearn case OPTARG_INT: 481f1b9d127SSheldon Hearn errno = 0; 482f1b9d127SSheldon Hearn ap->ival = strtol(arg, NULL, 0); 483f1b9d127SSheldon Hearn if (errno) { 484f1b9d127SSheldon Hearn warnx("opt: Invalid integer value for option '%c' (%s).\n",ap->opt,ap->name); 485f1b9d127SSheldon Hearn return EINVAL; 486f1b9d127SSheldon Hearn } 487f1b9d127SSheldon Hearn if (((ap->flag & OPTFL_HAVEMIN) && 488f1b9d127SSheldon Hearn (ap->ival < ap->min)) || 489f1b9d127SSheldon Hearn ((ap->flag & OPTFL_HAVEMAX) && 490f1b9d127SSheldon Hearn (ap->ival > ap->max))) { 491f1b9d127SSheldon Hearn warnx("opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",ap->opt,ap->name,ap->min,ap->max); 492f1b9d127SSheldon Hearn return EINVAL; 493f1b9d127SSheldon Hearn } 494f1b9d127SSheldon Hearn callback(ap); 495f1b9d127SSheldon Hearn break; 496f1b9d127SSheldon Hearn default: 497f1b9d127SSheldon Hearn break; 498f1b9d127SSheldon Hearn } 499f1b9d127SSheldon Hearn break; 500f1b9d127SSheldon Hearn } 501f1b9d127SSheldon Hearn return 0; 502f1b9d127SSheldon Hearn } 503f1b9d127SSheldon Hearn 504