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: stable/11/contrib/smbfs/lib/smb/rcfile.c 356599 2020-01-10 12:20:25Z pluknet $"); 37136700Sobrien 3887866Ssheldonh#include <sys/types.h> 3987866Ssheldonh#include <sys/queue.h> 4087866Ssheldonh#include <ctype.h> 4187866Ssheldonh#include <errno.h> 42356599Spluknet#define _WITH_DPRINTF 4387866Ssheldonh#include <stdio.h> 4487866Ssheldonh#include <string.h> 4587866Ssheldonh#include <stdlib.h> 4687866Ssheldonh#include <pwd.h> 4787866Ssheldonh#include <unistd.h> 4887866Ssheldonh#include <err.h> 4987866Ssheldonh 5087866Ssheldonh#include <cflib.h> 5187866Ssheldonh#include "rcfile_priv.h" 5287866Ssheldonh 5387866SsheldonhSLIST_HEAD(rcfile_head, rcfile); 5487866Ssheldonhstatic struct rcfile_head pf_head = {NULL}; 5587866Ssheldonh 5687866Ssheldonhstatic struct rcfile* rc_cachelookup(const char *filename); 5787866Ssheldonhstatic struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); 5887866Ssheldonhstatic struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); 5987866Ssheldonhstatic int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); 6087866Ssheldonhstatic struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); 6187866Ssheldonhstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value); 6287866Ssheldonhstatic void rc_key_free(struct rckey *p); 6387866Ssheldonhstatic void rc_parse(struct rcfile *rcp); 6487866Ssheldonh 6587866Ssheldonh 6687866Ssheldonh/* 6787866Ssheldonh * open rcfile and load its content, if already open - return previous handle 6887866Ssheldonh */ 6987866Ssheldonhint 7087866Ssheldonhrc_open(const char *filename, const char *mode, struct rcfile **rcfile) 7187866Ssheldonh{ 7287866Ssheldonh struct rcfile *rcp; 7387866Ssheldonh FILE *f; 7487866Ssheldonh 7587866Ssheldonh rcp = rc_cachelookup(filename); 7687866Ssheldonh if (rcp) { 7787866Ssheldonh *rcfile = rcp; 7887866Ssheldonh return 0; 7987866Ssheldonh } 8087866Ssheldonh f = fopen(filename, mode); 8187866Ssheldonh if (f == NULL) 8287866Ssheldonh return errno; 8387866Ssheldonh rcp = malloc(sizeof(struct rcfile)); 8487866Ssheldonh if (rcp == NULL) { 8587866Ssheldonh fclose(f); 8687866Ssheldonh return ENOMEM; 8787866Ssheldonh } 8887866Ssheldonh bzero(rcp, sizeof(struct rcfile)); 8987866Ssheldonh rcp->rf_name = strdup(filename); 9087866Ssheldonh rcp->rf_f = f; 9187866Ssheldonh SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 9287866Ssheldonh rc_parse(rcp); 9387866Ssheldonh *rcfile = rcp; 9487866Ssheldonh return 0; 9587866Ssheldonh} 9687866Ssheldonh 9787866Ssheldonhint 9887866Ssheldonhrc_merge(const char *filename, struct rcfile **rcfile) 9987866Ssheldonh{ 10087866Ssheldonh struct rcfile *rcp = *rcfile; 10187866Ssheldonh FILE *f, *t; 10287866Ssheldonh 10387866Ssheldonh if (rcp == NULL) { 10487866Ssheldonh return rc_open(filename, "r", rcfile); 10587866Ssheldonh } 10687866Ssheldonh f = fopen (filename, "r"); 10787866Ssheldonh if (f == NULL) 10887866Ssheldonh return errno; 10987866Ssheldonh t = rcp->rf_f; 11087866Ssheldonh rcp->rf_f = f; 11187866Ssheldonh rc_parse(rcp); 11287866Ssheldonh rcp->rf_f = t; 11387866Ssheldonh fclose(f); 11487866Ssheldonh return 0; 11587866Ssheldonh} 11687866Ssheldonh 11787866Ssheldonhint 11887866Ssheldonhrc_close(struct rcfile *rcp) 11987866Ssheldonh{ 12087866Ssheldonh struct rcsection *p, *n; 12187866Ssheldonh 12287866Ssheldonh fclose(rcp->rf_f); 12387866Ssheldonh for(p = SLIST_FIRST(&rcp->rf_sect); p;) { 12487866Ssheldonh n = p; 12587866Ssheldonh p = SLIST_NEXT(p,rs_next); 12687866Ssheldonh rc_freesect(rcp, n); 12787866Ssheldonh } 12887866Ssheldonh free(rcp->rf_name); 12987866Ssheldonh SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 13087866Ssheldonh free(rcp); 13187866Ssheldonh return 0; 13287866Ssheldonh} 13387866Ssheldonh 13487866Ssheldonhstatic struct rcfile* 13587866Ssheldonhrc_cachelookup(const char *filename) 13687866Ssheldonh{ 13787866Ssheldonh struct rcfile *p; 13887866Ssheldonh 13987866Ssheldonh SLIST_FOREACH(p, &pf_head, rf_next) 14087866Ssheldonh if (strcmp (filename, p->rf_name) == 0) 14187866Ssheldonh return p; 14287866Ssheldonh return 0; 14387866Ssheldonh} 14487866Ssheldonh 14587866Ssheldonhstatic struct rcsection * 14687866Ssheldonhrc_findsect(struct rcfile *rcp, const char *sectname) 14787866Ssheldonh{ 14887866Ssheldonh struct rcsection *p; 14987866Ssheldonh 15087866Ssheldonh SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 15187866Ssheldonh if (strcmp(p->rs_name, sectname)==0) 15287866Ssheldonh return p; 15387866Ssheldonh return NULL; 15487866Ssheldonh} 15587866Ssheldonh 15687866Ssheldonhstatic struct rcsection * 15787866Ssheldonhrc_addsect(struct rcfile *rcp, const char *sectname) 15887866Ssheldonh{ 15987866Ssheldonh struct rcsection *p; 160356566Sbapt const char* sectletter = sectname; 16187866Ssheldonh 16287866Ssheldonh p = rc_findsect(rcp, sectname); 16387866Ssheldonh if (p) return p; 16487866Ssheldonh p = malloc(sizeof(*p)); 16587866Ssheldonh if (!p) return NULL; 166356566Sbapt for(sectletter = sectname; *sectletter; sectletter++) { 167356566Sbapt if (islower(*sectletter)) { 168356566Sbapt if (strcmp(sectname, "default")) 169356566Sbapt dprintf(STDERR_FILENO, "warning: section name [%s] contains lower-case letters\n", sectname); 170356566Sbapt break; 171356566Sbapt } 172356566Sbapt } 17387866Ssheldonh p->rs_name = strdup(sectname); 17487866Ssheldonh SLIST_INIT(&p->rs_keys); 17587866Ssheldonh SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 17687866Ssheldonh return p; 17787866Ssheldonh} 17887866Ssheldonh 17987866Ssheldonhstatic int 18087866Ssheldonhrc_freesect(struct rcfile *rcp, struct rcsection *rsp) 18187866Ssheldonh{ 18287866Ssheldonh struct rckey *p,*n; 18387866Ssheldonh 18487866Ssheldonh SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); 18587866Ssheldonh for(p = SLIST_FIRST(&rsp->rs_keys);p;) { 18687866Ssheldonh n = p; 18787866Ssheldonh p = SLIST_NEXT(p,rk_next); 18887866Ssheldonh rc_key_free(n); 18987866Ssheldonh } 19087866Ssheldonh free(rsp->rs_name); 19187866Ssheldonh free(rsp); 19287866Ssheldonh return 0; 19387866Ssheldonh} 19487866Ssheldonh 19587866Ssheldonhstatic struct rckey * 19687866Ssheldonhrc_sect_findkey(struct rcsection *rsp, const char *keyname) 19787866Ssheldonh{ 19887866Ssheldonh struct rckey *p; 19987866Ssheldonh 20087866Ssheldonh SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 20187866Ssheldonh if (strcmp(p->rk_name, keyname)==0) 20287866Ssheldonh return p; 20387866Ssheldonh return NULL; 20487866Ssheldonh} 20587866Ssheldonh 20687866Ssheldonhstatic struct rckey * 20787866Ssheldonhrc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) 20887866Ssheldonh{ 20987866Ssheldonh struct rckey *p; 21087866Ssheldonh 21187866Ssheldonh p = rc_sect_findkey(rsp, name); 21287866Ssheldonh if (p) { 21387866Ssheldonh free(p->rk_value); 21487866Ssheldonh } else { 21587866Ssheldonh p = malloc(sizeof(*p)); 21687866Ssheldonh if (!p) return NULL; 21787866Ssheldonh SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 21887866Ssheldonh p->rk_name = strdup(name); 21987866Ssheldonh } 22087866Ssheldonh p->rk_value = value ? strdup(value) : strdup(""); 22187866Ssheldonh return p; 22287866Ssheldonh} 22387866Ssheldonh 22487866Ssheldonh#if 0 22587866Ssheldonhvoid 22687866Ssheldonhrc_sect_delkey(struct rcsection *rsp, struct rckey *p) 22787866Ssheldonh{ 22887866Ssheldonh 22987866Ssheldonh SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); 23087866Ssheldonh rc_key_free(p); 23187866Ssheldonh return; 23287866Ssheldonh} 23387866Ssheldonh#endif 23487866Ssheldonh 23587866Ssheldonhstatic void 23687866Ssheldonhrc_key_free(struct rckey *p) 23787866Ssheldonh{ 23887866Ssheldonh free(p->rk_value); 23987866Ssheldonh free(p->rk_name); 24087866Ssheldonh free(p); 24187866Ssheldonh} 24287866Ssheldonh 24387866Ssheldonhenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 24487866Ssheldonh 24587866Ssheldonhstatic void 24687866Ssheldonhrc_parse(struct rcfile *rcp) 24787866Ssheldonh{ 24887866Ssheldonh FILE *f = rcp->rf_f; 24987866Ssheldonh int state = stNewLine, c; 25087866Ssheldonh struct rcsection *rsp = NULL; 25187866Ssheldonh struct rckey *rkp = NULL; 25287866Ssheldonh char buf[2048]; 25387866Ssheldonh char *next = buf, *last = &buf[sizeof(buf)-1]; 25487866Ssheldonh 25587866Ssheldonh while ((c = getc (f)) != EOF) { 25687866Ssheldonh if (c == '\r') 25787866Ssheldonh continue; 25887866Ssheldonh if (state == stNewLine) { 25987866Ssheldonh next = buf; 26087866Ssheldonh if (isspace(c)) 26187866Ssheldonh continue; /* skip leading junk */ 26287866Ssheldonh if (c == '[') { 26387866Ssheldonh state = stHeader; 26487866Ssheldonh rsp = NULL; 26587866Ssheldonh continue; 26687866Ssheldonh } 26787866Ssheldonh if (c == '#' || c == ';') { 26887866Ssheldonh state = stSkipToEOL; 26987866Ssheldonh } else { /* something meaningfull */ 27087866Ssheldonh state = stGetKey; 27187866Ssheldonh } 27287866Ssheldonh } 27387866Ssheldonh if (state == stSkipToEOL || next == last) {/* ignore long lines */ 27487866Ssheldonh if (c == '\n'){ 27587866Ssheldonh state = stNewLine; 27687866Ssheldonh next = buf; 27787866Ssheldonh } 27887866Ssheldonh continue; 27987866Ssheldonh } 28087866Ssheldonh if (state == stHeader) { 28187866Ssheldonh if (c == ']') { 28287866Ssheldonh *next = 0; 28387866Ssheldonh next = buf; 28487866Ssheldonh rsp = rc_addsect(rcp, buf); 28587866Ssheldonh state = stSkipToEOL; 28687866Ssheldonh } else 28787866Ssheldonh *next++ = c; 28887866Ssheldonh continue; 28987866Ssheldonh } 29087866Ssheldonh if (state == stGetKey) { 29187866Ssheldonh if (c == ' ' || c == '\t')/* side effect: 'key name='*/ 29287866Ssheldonh continue; /* become 'keyname=' */ 29387866Ssheldonh if (c == '\n') { /* silently ignore ... */ 29487866Ssheldonh state = stNewLine; 29587866Ssheldonh continue; 29687866Ssheldonh } 29787866Ssheldonh if (c != '=') { 29887866Ssheldonh *next++ = c; 29987866Ssheldonh continue; 30087866Ssheldonh } 30187866Ssheldonh *next = 0; 30287866Ssheldonh if (rsp == NULL) { 30387866Ssheldonh fprintf(stderr, "Key '%s' defined before section\n", buf); 30487866Ssheldonh state = stSkipToEOL; 30587866Ssheldonh continue; 30687866Ssheldonh } 30787866Ssheldonh rkp = rc_sect_addkey(rsp, buf, NULL); 30887866Ssheldonh next = buf; 30987866Ssheldonh state = stGetValue; 31087866Ssheldonh continue; 31187866Ssheldonh } 31287866Ssheldonh /* only stGetValue left */ 31387866Ssheldonh if (state != stGetValue) { 31487866Ssheldonh fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); 31587866Ssheldonh state = stSkipToEOL; 31687866Ssheldonh } 31787866Ssheldonh if (c != '\n') { 31887866Ssheldonh *next++ = c; 31987866Ssheldonh continue; 32087866Ssheldonh } 32187866Ssheldonh *next = 0; 32287866Ssheldonh rkp->rk_value = strdup(buf); 32387866Ssheldonh state = stNewLine; 32487866Ssheldonh rkp = NULL; 32587866Ssheldonh } /* while */ 32687866Ssheldonh if (c == EOF && state == stGetValue) { 32787866Ssheldonh *next = 0; 32887866Ssheldonh rkp->rk_value = strdup(buf); 32987866Ssheldonh } 33087866Ssheldonh return; 33187866Ssheldonh} 33287866Ssheldonh 33387866Ssheldonhint 33487866Ssheldonhrc_getstringptr(struct rcfile *rcp, const char *section, const char *key, 33587866Ssheldonh char **dest) 33687866Ssheldonh{ 33787866Ssheldonh struct rcsection *rsp; 33887866Ssheldonh struct rckey *rkp; 33987866Ssheldonh 34087866Ssheldonh *dest = NULL; 34187866Ssheldonh rsp = rc_findsect(rcp, section); 34287866Ssheldonh if (!rsp) return ENOENT; 34387866Ssheldonh rkp = rc_sect_findkey(rsp,key); 34487866Ssheldonh if (!rkp) return ENOENT; 34587866Ssheldonh *dest = rkp->rk_value; 34687866Ssheldonh return 0; 34787866Ssheldonh} 34887866Ssheldonh 34987866Ssheldonhint 35087866Ssheldonhrc_getstring(struct rcfile *rcp, const char *section, const char *key, 35187866Ssheldonh size_t maxlen, char *dest) 35287866Ssheldonh{ 35387866Ssheldonh char *value; 35487866Ssheldonh int error; 35587866Ssheldonh 35687866Ssheldonh error = rc_getstringptr(rcp, section, key, &value); 35787866Ssheldonh if (error) 35887866Ssheldonh return error; 35987866Ssheldonh if (strlen(value) >= maxlen) { 360136700Sobrien warnx("line too long for key '%s' in section '%s', max = %zd\n", key, section, maxlen); 36187866Ssheldonh return EINVAL; 36287866Ssheldonh } 36387866Ssheldonh strcpy(dest, value); 36487866Ssheldonh return 0; 36587866Ssheldonh} 36687866Ssheldonh 36787866Ssheldonhint 36887866Ssheldonhrc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) 36987866Ssheldonh{ 37087866Ssheldonh struct rcsection *rsp; 37187866Ssheldonh struct rckey *rkp; 37287866Ssheldonh 37387866Ssheldonh rsp = rc_findsect(rcp, section); 37487866Ssheldonh if (!rsp) 37587866Ssheldonh return ENOENT; 37687866Ssheldonh rkp = rc_sect_findkey(rsp, key); 37787866Ssheldonh if (!rkp) 37887866Ssheldonh return ENOENT; 37987866Ssheldonh errno = 0; 38087866Ssheldonh *value = strtol(rkp->rk_value, NULL, 0); 38187866Ssheldonh if (errno) { 38287866Ssheldonh warnx("invalid int value '%s' for key '%s' in section '%s'\n", rkp->rk_value, key, section); 38387866Ssheldonh return errno; 38487866Ssheldonh } 38587866Ssheldonh return 0; 38687866Ssheldonh} 38787866Ssheldonh 38887866Ssheldonh/* 38987866Ssheldonh * 1,yes,true 39087866Ssheldonh * 0,no,false 39187866Ssheldonh */ 39287866Ssheldonhint 39387866Ssheldonhrc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) 39487866Ssheldonh{ 39587866Ssheldonh struct rcsection *rsp; 39687866Ssheldonh struct rckey *rkp; 39787866Ssheldonh char *p; 39887866Ssheldonh 39987866Ssheldonh rsp = rc_findsect(rcp, section); 40087866Ssheldonh if (!rsp) return ENOENT; 40187866Ssheldonh rkp = rc_sect_findkey(rsp,key); 40287866Ssheldonh if (!rkp) return ENOENT; 40387866Ssheldonh p = rkp->rk_value; 40487866Ssheldonh while (*p && isspace(*p)) p++; 40587866Ssheldonh if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { 40687866Ssheldonh *value = 0; 40787866Ssheldonh return 0; 40887866Ssheldonh } 40987866Ssheldonh if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { 41087866Ssheldonh *value = 1; 41187866Ssheldonh return 0; 41287866Ssheldonh } 41387866Ssheldonh fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); 41487866Ssheldonh return EINVAL; 41587866Ssheldonh} 41687866Ssheldonh 41787866Ssheldonh/* 41887866Ssheldonh * Unified command line/rc file parser 41987866Ssheldonh */ 42087866Ssheldonhint 42187866Ssheldonhopt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, 42287866Ssheldonh opt_callback_t *callback) 42387866Ssheldonh{ 42487866Ssheldonh int len, error; 42587866Ssheldonh 42687866Ssheldonh for (; ap->opt; ap++) { 42787866Ssheldonh switch (ap->type) { 42887866Ssheldonh case OPTARG_STR: 42987866Ssheldonh if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) 43087866Ssheldonh break; 43187866Ssheldonh len = strlen(ap->str); 43287866Ssheldonh if (len > ap->ival) { 43387866Ssheldonh warnx("rc: argument for option '%c' (%s) too long\n", ap->opt, ap->name); 43487866Ssheldonh return EINVAL; 43587866Ssheldonh } 43687866Ssheldonh callback(ap); 43787866Ssheldonh break; 43887866Ssheldonh case OPTARG_BOOL: 43987866Ssheldonh error = rc_getbool(rcp, sect, ap->name, &ap->ival); 44087866Ssheldonh if (error == ENOENT) 44187866Ssheldonh break; 44287866Ssheldonh if (error) 44387866Ssheldonh return EINVAL; 44487866Ssheldonh callback(ap); 44587866Ssheldonh break; 44687866Ssheldonh case OPTARG_INT: 44787866Ssheldonh if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) 44887866Ssheldonh break; 44987866Ssheldonh if (((ap->flag & OPTFL_HAVEMIN) && ap->ival < ap->min) || 45087866Ssheldonh ((ap->flag & OPTFL_HAVEMAX) && ap->ival > ap->max)) { 45187866Ssheldonh warnx("rc: argument for option '%c' (%s) should be in [%d-%d] range\n", 45287866Ssheldonh ap->opt, ap->name, ap->min, ap->max); 45387866Ssheldonh return EINVAL; 45487866Ssheldonh } 45587866Ssheldonh callback(ap); 45687866Ssheldonh break; 45787866Ssheldonh default: 45887866Ssheldonh break; 45987866Ssheldonh } 46087866Ssheldonh } 46187866Ssheldonh return 0; 46287866Ssheldonh} 46387866Ssheldonh 46487866Ssheldonhint 46587866Ssheldonhopt_args_parseopt(struct opt_args *ap, int opt, char *arg, 46687866Ssheldonh opt_callback_t *callback) 46787866Ssheldonh{ 46887866Ssheldonh int len; 46987866Ssheldonh 47087866Ssheldonh for (; ap->opt; ap++) { 47187866Ssheldonh if (ap->opt != opt) 47287866Ssheldonh continue; 47387866Ssheldonh switch (ap->type) { 47487866Ssheldonh case OPTARG_STR: 47587866Ssheldonh ap->str = arg; 47687866Ssheldonh if (arg) { 47787866Ssheldonh len = strlen(ap->str); 47887866Ssheldonh if (len > ap->ival) { 47987866Ssheldonh warnx("opt: Argument for option '%c' (%s) too long\n", ap->opt, ap->name); 48087866Ssheldonh return EINVAL; 48187866Ssheldonh } 48287866Ssheldonh callback(ap); 48387866Ssheldonh } 48487866Ssheldonh break; 48587866Ssheldonh case OPTARG_BOOL: 48687866Ssheldonh ap->ival = 0; 48787866Ssheldonh callback(ap); 48887866Ssheldonh break; 48987866Ssheldonh case OPTARG_INT: 49087866Ssheldonh errno = 0; 49187866Ssheldonh ap->ival = strtol(arg, NULL, 0); 49287866Ssheldonh if (errno) { 49387866Ssheldonh warnx("opt: Invalid integer value for option '%c' (%s).\n",ap->opt,ap->name); 49487866Ssheldonh return EINVAL; 49587866Ssheldonh } 49687866Ssheldonh if (((ap->flag & OPTFL_HAVEMIN) && 49787866Ssheldonh (ap->ival < ap->min)) || 49887866Ssheldonh ((ap->flag & OPTFL_HAVEMAX) && 49987866Ssheldonh (ap->ival > ap->max))) { 50087866Ssheldonh warnx("opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",ap->opt,ap->name,ap->min,ap->max); 50187866Ssheldonh return EINVAL; 50287866Ssheldonh } 50387866Ssheldonh callback(ap); 50487866Ssheldonh break; 50587866Ssheldonh default: 50687866Ssheldonh break; 50787866Ssheldonh } 50887866Ssheldonh break; 50987866Ssheldonh } 51087866Ssheldonh return 0; 51187866Ssheldonh} 51287866Ssheldonh 513