187866Ssheldonh/* 287866Ssheldonh * Copyright (c) 2000, Boris Popov 387866Ssheldonh * All rights reserved. 487866Ssheldonh * 587866Ssheldonh * Redistribution and use in source and binary forms, with or without 687866Ssheldonh * modification, are permitted provided that the following conditions 787866Ssheldonh * are met: 887866Ssheldonh * 1. Redistributions of source code must retain the above copyright 987866Ssheldonh * notice, this list of conditions and the following disclaimer. 1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright 1187866Ssheldonh * notice, this list of conditions and the following disclaimer in the 1287866Ssheldonh * documentation and/or other materials provided with the distribution. 1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software 1487866Ssheldonh * must display the following acknowledgement: 1587866Ssheldonh * This product includes software developed by Boris Popov. 1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors 1787866Ssheldonh * may be used to endorse or promote products derived from this software 1887866Ssheldonh * without specific prior written permission. 1987866Ssheldonh * 2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2387866Ssheldonh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3087866Ssheldonh * SUCH DAMAGE. 3187866Ssheldonh * 3287866Ssheldonh * $Id: rcfile.c,v 1.5 2001/04/16 12:46:46 bp Exp $ 3387866Ssheldonh */ 34136700Sobrien 35136700Sobrien#include <sys/cdefs.h> 36136700Sobrien__FBSDID("$FreeBSD: releng/11.0/contrib/smbfs/lib/smb/rcfile.c 136700 2004-10-19 17:44:31Z obrien $"); 37136700Sobrien 3887866Ssheldonh#include <sys/types.h> 3987866Ssheldonh#include <sys/queue.h> 4087866Ssheldonh#include <ctype.h> 4187866Ssheldonh#include <errno.h> 4287866Ssheldonh#include <stdio.h> 4387866Ssheldonh#include <string.h> 4487866Ssheldonh#include <stdlib.h> 4587866Ssheldonh#include <pwd.h> 4687866Ssheldonh#include <unistd.h> 4787866Ssheldonh#include <err.h> 4887866Ssheldonh 4987866Ssheldonh#include <cflib.h> 5087866Ssheldonh#include "rcfile_priv.h" 5187866Ssheldonh 5287866SsheldonhSLIST_HEAD(rcfile_head, rcfile); 5387866Ssheldonhstatic struct rcfile_head pf_head = {NULL}; 5487866Ssheldonh 5587866Ssheldonhstatic struct rcfile* rc_cachelookup(const char *filename); 5687866Ssheldonhstatic struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); 5787866Ssheldonhstatic struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); 5887866Ssheldonhstatic int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); 5987866Ssheldonhstatic struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); 6087866Ssheldonhstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value); 6187866Ssheldonhstatic void rc_key_free(struct rckey *p); 6287866Ssheldonhstatic void rc_parse(struct rcfile *rcp); 6387866Ssheldonh 6487866Ssheldonh 6587866Ssheldonh/* 6687866Ssheldonh * open rcfile and load its content, if already open - return previous handle 6787866Ssheldonh */ 6887866Ssheldonhint 6987866Ssheldonhrc_open(const char *filename, const char *mode, struct rcfile **rcfile) 7087866Ssheldonh{ 7187866Ssheldonh struct rcfile *rcp; 7287866Ssheldonh FILE *f; 7387866Ssheldonh 7487866Ssheldonh rcp = rc_cachelookup(filename); 7587866Ssheldonh if (rcp) { 7687866Ssheldonh *rcfile = rcp; 7787866Ssheldonh return 0; 7887866Ssheldonh } 7987866Ssheldonh f = fopen(filename, mode); 8087866Ssheldonh if (f == NULL) 8187866Ssheldonh return errno; 8287866Ssheldonh rcp = malloc(sizeof(struct rcfile)); 8387866Ssheldonh if (rcp == NULL) { 8487866Ssheldonh fclose(f); 8587866Ssheldonh return ENOMEM; 8687866Ssheldonh } 8787866Ssheldonh bzero(rcp, sizeof(struct rcfile)); 8887866Ssheldonh rcp->rf_name = strdup(filename); 8987866Ssheldonh rcp->rf_f = f; 9087866Ssheldonh SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 9187866Ssheldonh rc_parse(rcp); 9287866Ssheldonh *rcfile = rcp; 9387866Ssheldonh return 0; 9487866Ssheldonh} 9587866Ssheldonh 9687866Ssheldonhint 9787866Ssheldonhrc_merge(const char *filename, struct rcfile **rcfile) 9887866Ssheldonh{ 9987866Ssheldonh struct rcfile *rcp = *rcfile; 10087866Ssheldonh FILE *f, *t; 10187866Ssheldonh 10287866Ssheldonh if (rcp == NULL) { 10387866Ssheldonh return rc_open(filename, "r", rcfile); 10487866Ssheldonh } 10587866Ssheldonh f = fopen (filename, "r"); 10687866Ssheldonh if (f == NULL) 10787866Ssheldonh return errno; 10887866Ssheldonh t = rcp->rf_f; 10987866Ssheldonh rcp->rf_f = f; 11087866Ssheldonh rc_parse(rcp); 11187866Ssheldonh rcp->rf_f = t; 11287866Ssheldonh fclose(f); 11387866Ssheldonh return 0; 11487866Ssheldonh} 11587866Ssheldonh 11687866Ssheldonhint 11787866Ssheldonhrc_close(struct rcfile *rcp) 11887866Ssheldonh{ 11987866Ssheldonh struct rcsection *p, *n; 12087866Ssheldonh 12187866Ssheldonh fclose(rcp->rf_f); 12287866Ssheldonh for(p = SLIST_FIRST(&rcp->rf_sect); p;) { 12387866Ssheldonh n = p; 12487866Ssheldonh p = SLIST_NEXT(p,rs_next); 12587866Ssheldonh rc_freesect(rcp, n); 12687866Ssheldonh } 12787866Ssheldonh free(rcp->rf_name); 12887866Ssheldonh SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 12987866Ssheldonh free(rcp); 13087866Ssheldonh return 0; 13187866Ssheldonh} 13287866Ssheldonh 13387866Ssheldonhstatic struct rcfile* 13487866Ssheldonhrc_cachelookup(const char *filename) 13587866Ssheldonh{ 13687866Ssheldonh struct rcfile *p; 13787866Ssheldonh 13887866Ssheldonh SLIST_FOREACH(p, &pf_head, rf_next) 13987866Ssheldonh if (strcmp (filename, p->rf_name) == 0) 14087866Ssheldonh return p; 14187866Ssheldonh return 0; 14287866Ssheldonh} 14387866Ssheldonh 14487866Ssheldonhstatic struct rcsection * 14587866Ssheldonhrc_findsect(struct rcfile *rcp, const char *sectname) 14687866Ssheldonh{ 14787866Ssheldonh struct rcsection *p; 14887866Ssheldonh 14987866Ssheldonh SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 15087866Ssheldonh if (strcmp(p->rs_name, sectname)==0) 15187866Ssheldonh return p; 15287866Ssheldonh return NULL; 15387866Ssheldonh} 15487866Ssheldonh 15587866Ssheldonhstatic struct rcsection * 15687866Ssheldonhrc_addsect(struct rcfile *rcp, const char *sectname) 15787866Ssheldonh{ 15887866Ssheldonh struct rcsection *p; 15987866Ssheldonh 16087866Ssheldonh p = rc_findsect(rcp, sectname); 16187866Ssheldonh if (p) return p; 16287866Ssheldonh p = malloc(sizeof(*p)); 16387866Ssheldonh if (!p) return NULL; 16487866Ssheldonh p->rs_name = strdup(sectname); 16587866Ssheldonh SLIST_INIT(&p->rs_keys); 16687866Ssheldonh SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 16787866Ssheldonh return p; 16887866Ssheldonh} 16987866Ssheldonh 17087866Ssheldonhstatic int 17187866Ssheldonhrc_freesect(struct rcfile *rcp, struct rcsection *rsp) 17287866Ssheldonh{ 17387866Ssheldonh struct rckey *p,*n; 17487866Ssheldonh 17587866Ssheldonh SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); 17687866Ssheldonh for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 17787866Ssheldonh n = p; 17887866Ssheldonh p = SLIST_NEXT(p,rk_next); 17987866Ssheldonh rc_key_free(n); 18087866Ssheldonh } 18187866Ssheldonh free(rsp->rs_name); 18287866Ssheldonh free(rsp); 18387866Ssheldonh return 0; 18487866Ssheldonh} 18587866Ssheldonh 18687866Ssheldonhstatic struct rckey * 18787866Ssheldonhrc_sect_findkey(struct rcsection *rsp, const char *keyname) 18887866Ssheldonh{ 18987866Ssheldonh struct rckey *p; 19087866Ssheldonh 19187866Ssheldonh SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 19287866Ssheldonh if (strcmp(p->rk_name, keyname)==0) 19387866Ssheldonh return p; 19487866Ssheldonh return NULL; 19587866Ssheldonh} 19687866Ssheldonh 19787866Ssheldonhstatic struct rckey * 19887866Ssheldonhrc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) 19987866Ssheldonh{ 20087866Ssheldonh struct rckey *p; 20187866Ssheldonh 20287866Ssheldonh p = rc_sect_findkey(rsp, name); 20387866Ssheldonh if (p) { 20487866Ssheldonh free(p->rk_value); 20587866Ssheldonh } else { 20687866Ssheldonh p = malloc(sizeof(*p)); 20787866Ssheldonh if (!p) return NULL; 20887866Ssheldonh SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 20987866Ssheldonh p->rk_name = strdup(name); 21087866Ssheldonh } 21187866Ssheldonh p->rk_value = value ? strdup(value) : strdup(""); 21287866Ssheldonh return p; 21387866Ssheldonh} 21487866Ssheldonh 21587866Ssheldonh#if 0 21687866Ssheldonhvoid 21787866Ssheldonhrc_sect_delkey(struct rcsection *rsp, struct rckey *p) 21887866Ssheldonh{ 21987866Ssheldonh 22087866Ssheldonh SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); 22187866Ssheldonh rc_key_free(p); 22287866Ssheldonh return; 22387866Ssheldonh} 22487866Ssheldonh#endif 22587866Ssheldonh 22687866Ssheldonhstatic void 22787866Ssheldonhrc_key_free(struct rckey *p) 22887866Ssheldonh{ 22987866Ssheldonh free(p->rk_value); 23087866Ssheldonh free(p->rk_name); 23187866Ssheldonh free(p); 23287866Ssheldonh} 23387866Ssheldonh 23487866Ssheldonhenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 23587866Ssheldonh 23687866Ssheldonhstatic void 23787866Ssheldonhrc_parse(struct rcfile *rcp) 23887866Ssheldonh{ 23987866Ssheldonh FILE *f = rcp->rf_f; 24087866Ssheldonh int state = stNewLine, c; 24187866Ssheldonh struct rcsection *rsp = NULL; 24287866Ssheldonh struct rckey *rkp = NULL; 24387866Ssheldonh char buf[2048]; 24487866Ssheldonh char *next = buf, *last = &buf[sizeof(buf)-1]; 24587866Ssheldonh 24687866Ssheldonh while ((c = getc (f)) != EOF) { 24787866Ssheldonh if (c == '\r') 24887866Ssheldonh continue; 24987866Ssheldonh if (state == stNewLine) { 25087866Ssheldonh next = buf; 25187866Ssheldonh if (isspace(c)) 25287866Ssheldonh continue; /* skip leading junk */ 25387866Ssheldonh if (c == '[') { 25487866Ssheldonh state = stHeader; 25587866Ssheldonh rsp = NULL; 25687866Ssheldonh continue; 25787866Ssheldonh } 25887866Ssheldonh if (c == '#' || c == ';') { 25987866Ssheldonh state = stSkipToEOL; 26087866Ssheldonh } else { /* something meaningfull */ 26187866Ssheldonh state = stGetKey; 26287866Ssheldonh } 26387866Ssheldonh } 26487866Ssheldonh if (state == stSkipToEOL || next == last) {/* ignore long lines */ 26587866Ssheldonh if (c == '\n'){ 26687866Ssheldonh state = stNewLine; 26787866Ssheldonh next = buf; 26887866Ssheldonh } 26987866Ssheldonh continue; 27087866Ssheldonh } 27187866Ssheldonh if (state == stHeader) { 27287866Ssheldonh if (c == ']') { 27387866Ssheldonh *next = 0; 27487866Ssheldonh next = buf; 27587866Ssheldonh rsp = rc_addsect(rcp, buf); 27687866Ssheldonh state = stSkipToEOL; 27787866Ssheldonh } else 27887866Ssheldonh *next++ = c; 27987866Ssheldonh continue; 28087866Ssheldonh } 28187866Ssheldonh if (state == stGetKey) { 28287866Ssheldonh if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 28387866Ssheldonh continue; /* become 'keyname=' */ 28487866Ssheldonh if (c == '\n') { /* silently ignore ... */ 28587866Ssheldonh state = stNewLine; 28687866Ssheldonh continue; 28787866Ssheldonh } 28887866Ssheldonh if (c != '=') { 28987866Ssheldonh *next++ = c; 29087866Ssheldonh continue; 29187866Ssheldonh } 29287866Ssheldonh *next = 0; 29387866Ssheldonh if (rsp == NULL) { 29487866Ssheldonh fprintf(stderr, "Key '%s' defined before section\n", buf); 29587866Ssheldonh state = stSkipToEOL; 29687866Ssheldonh continue; 29787866Ssheldonh } 29887866Ssheldonh rkp = rc_sect_addkey(rsp, buf, NULL); 29987866Ssheldonh next = buf; 30087866Ssheldonh state = stGetValue; 30187866Ssheldonh continue; 30287866Ssheldonh } 30387866Ssheldonh /* only stGetValue left */ 30487866Ssheldonh if (state != stGetValue) { 30587866Ssheldonh fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 30687866Ssheldonh state = stSkipToEOL; 30787866Ssheldonh } 30887866Ssheldonh if (c != '\n') { 30987866Ssheldonh *next++ = c; 31087866Ssheldonh continue; 31187866Ssheldonh } 31287866Ssheldonh *next = 0; 31387866Ssheldonh rkp->rk_value = strdup(buf); 31487866Ssheldonh state = stNewLine; 31587866Ssheldonh rkp = NULL; 31687866Ssheldonh } /* while */ 31787866Ssheldonh if (c == EOF && state == stGetValue) { 31887866Ssheldonh *next = 0; 31987866Ssheldonh rkp->rk_value = strdup(buf); 32087866Ssheldonh } 32187866Ssheldonh return; 32287866Ssheldonh} 32387866Ssheldonh 32487866Ssheldonhint 32587866Ssheldonhrc_getstringptr(struct rcfile *rcp, const char *section, const char *key, 32687866Ssheldonh char **dest) 32787866Ssheldonh{ 32887866Ssheldonh struct rcsection *rsp; 32987866Ssheldonh struct rckey *rkp; 33087866Ssheldonh 33187866Ssheldonh *dest = NULL; 33287866Ssheldonh rsp = rc_findsect(rcp, section); 33387866Ssheldonh if (!rsp) return ENOENT; 33487866Ssheldonh rkp = rc_sect_findkey(rsp,key); 33587866Ssheldonh if (!rkp) return ENOENT; 33687866Ssheldonh *dest = rkp->rk_value; 33787866Ssheldonh return 0; 33887866Ssheldonh} 33987866Ssheldonh 34087866Ssheldonhint 34187866Ssheldonhrc_getstring(struct rcfile *rcp, const char *section, const char *key, 34287866Ssheldonh size_t maxlen, char *dest) 34387866Ssheldonh{ 34487866Ssheldonh char *value; 34587866Ssheldonh int error; 34687866Ssheldonh 34787866Ssheldonh error = rc_getstringptr(rcp, section, key, &value); 34887866Ssheldonh if (error) 34987866Ssheldonh return error; 35087866Ssheldonh if (strlen(value) >= maxlen) { 351136700Sobrien warnx("line too long for key '%s' in section '%s', max = %zd\n", key, section, maxlen); 35287866Ssheldonh return EINVAL; 35387866Ssheldonh } 35487866Ssheldonh strcpy(dest, value); 35587866Ssheldonh return 0; 35687866Ssheldonh} 35787866Ssheldonh 35887866Ssheldonhint 35987866Ssheldonhrc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) 36087866Ssheldonh{ 36187866Ssheldonh struct rcsection *rsp; 36287866Ssheldonh struct rckey *rkp; 36387866Ssheldonh 36487866Ssheldonh rsp = rc_findsect(rcp, section); 36587866Ssheldonh if (!rsp) 36687866Ssheldonh return ENOENT; 36787866Ssheldonh rkp = rc_sect_findkey(rsp, key); 36887866Ssheldonh if (!rkp) 36987866Ssheldonh return ENOENT; 37087866Ssheldonh errno = 0; 37187866Ssheldonh *value = strtol(rkp->rk_value, NULL, 0); 37287866Ssheldonh if (errno) { 37387866Ssheldonh warnx("invalid int value '%s' for key '%s' in section '%s'\n", rkp->rk_value, key, section); 37487866Ssheldonh return errno; 37587866Ssheldonh } 37687866Ssheldonh return 0; 37787866Ssheldonh} 37887866Ssheldonh 37987866Ssheldonh/* 38087866Ssheldonh * 1,yes,true 38187866Ssheldonh * 0,no,false 38287866Ssheldonh */ 38387866Ssheldonhint 38487866Ssheldonhrc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) 38587866Ssheldonh{ 38687866Ssheldonh struct rcsection *rsp; 38787866Ssheldonh struct rckey *rkp; 38887866Ssheldonh char *p; 38987866Ssheldonh 39087866Ssheldonh rsp = rc_findsect(rcp, section); 39187866Ssheldonh if (!rsp) return ENOENT; 39287866Ssheldonh rkp = rc_sect_findkey(rsp,key); 39387866Ssheldonh if (!rkp) return ENOENT; 39487866Ssheldonh p = rkp->rk_value; 39587866Ssheldonh while (*p && isspace(*p)) p++; 39687866Ssheldonh if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 39787866Ssheldonh *value = 0; 39887866Ssheldonh return 0; 39987866Ssheldonh } 40087866Ssheldonh if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 40187866Ssheldonh *value = 1; 40287866Ssheldonh return 0; 40387866Ssheldonh } 40487866Ssheldonh fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 40587866Ssheldonh return EINVAL; 40687866Ssheldonh} 40787866Ssheldonh 40887866Ssheldonh/* 40987866Ssheldonh * Unified command line/rc file parser 41087866Ssheldonh */ 41187866Ssheldonhint 41287866Ssheldonhopt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, 41387866Ssheldonh opt_callback_t *callback) 41487866Ssheldonh{ 41587866Ssheldonh int len, error; 41687866Ssheldonh 41787866Ssheldonh for (; ap->opt; ap++) { 41887866Ssheldonh switch (ap->type) { 41987866Ssheldonh case OPTARG_STR: 42087866Ssheldonh if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) 42187866Ssheldonh break; 42287866Ssheldonh len = strlen(ap->str); 42387866Ssheldonh if (len > ap->ival) { 42487866Ssheldonh warnx("rc: argument for option '%c' (%s) too long\n", ap->opt, ap->name); 42587866Ssheldonh return EINVAL; 42687866Ssheldonh } 42787866Ssheldonh callback(ap); 42887866Ssheldonh break; 42987866Ssheldonh case OPTARG_BOOL: 43087866Ssheldonh error = rc_getbool(rcp, sect, ap->name, &ap->ival); 43187866Ssheldonh if (error == ENOENT) 43287866Ssheldonh break; 43387866Ssheldonh if (error) 43487866Ssheldonh return EINVAL; 43587866Ssheldonh callback(ap); 43687866Ssheldonh break; 43787866Ssheldonh case OPTARG_INT: 43887866Ssheldonh if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) 43987866Ssheldonh break; 44087866Ssheldonh if (((ap->flag & OPTFL_HAVEMIN) && ap->ival < ap->min) || 44187866Ssheldonh ((ap->flag & OPTFL_HAVEMAX) && ap->ival > ap->max)) { 44287866Ssheldonh warnx("rc: argument for option '%c' (%s) should be in [%d-%d] range\n", 44387866Ssheldonh ap->opt, ap->name, ap->min, ap->max); 44487866Ssheldonh return EINVAL; 44587866Ssheldonh } 44687866Ssheldonh callback(ap); 44787866Ssheldonh break; 44887866Ssheldonh default: 44987866Ssheldonh break; 45087866Ssheldonh } 45187866Ssheldonh } 45287866Ssheldonh return 0; 45387866Ssheldonh} 45487866Ssheldonh 45587866Ssheldonhint 45687866Ssheldonhopt_args_parseopt(struct opt_args *ap, int opt, char *arg, 45787866Ssheldonh opt_callback_t *callback) 45887866Ssheldonh{ 45987866Ssheldonh int len; 46087866Ssheldonh 46187866Ssheldonh for (; ap->opt; ap++) { 46287866Ssheldonh if (ap->opt != opt) 46387866Ssheldonh continue; 46487866Ssheldonh switch (ap->type) { 46587866Ssheldonh case OPTARG_STR: 46687866Ssheldonh ap->str = arg; 46787866Ssheldonh if (arg) { 46887866Ssheldonh len = strlen(ap->str); 46987866Ssheldonh if (len > ap->ival) { 47087866Ssheldonh warnx("opt: Argument for option '%c' (%s) too long\n", ap->opt, ap->name); 47187866Ssheldonh return EINVAL; 47287866Ssheldonh } 47387866Ssheldonh callback(ap); 47487866Ssheldonh } 47587866Ssheldonh break; 47687866Ssheldonh case OPTARG_BOOL: 47787866Ssheldonh ap->ival = 0; 47887866Ssheldonh callback(ap); 47987866Ssheldonh break; 48087866Ssheldonh case OPTARG_INT: 48187866Ssheldonh errno = 0; 48287866Ssheldonh ap->ival = strtol(arg, NULL, 0); 48387866Ssheldonh if (errno) { 48487866Ssheldonh warnx("opt: Invalid integer value for option '%c' (%s).\n",ap->opt,ap->name); 48587866Ssheldonh return EINVAL; 48687866Ssheldonh } 48787866Ssheldonh if (((ap->flag & OPTFL_HAVEMIN) && 48887866Ssheldonh (ap->ival < ap->min)) || 48987866Ssheldonh ((ap->flag & OPTFL_HAVEMAX) && 49087866Ssheldonh (ap->ival > ap->max))) { 49187866Ssheldonh warnx("opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",ap->opt,ap->name,ap->min,ap->max); 49287866Ssheldonh return EINVAL; 49387866Ssheldonh } 49487866Ssheldonh callback(ap); 49587866Ssheldonh break; 49687866Ssheldonh default: 49787866Ssheldonh break; 49887866Ssheldonh } 49987866Ssheldonh break; 50087866Ssheldonh } 50187866Ssheldonh return 0; 50287866Ssheldonh} 50387866Ssheldonh 504