diff --git a/contrib/smbfs/lib/smb/mbuf.c b/contrib/smbfs/lib/smb/mbuf.c index 729b5c53d11e..ac3b94524683 100644 --- a/contrib/smbfs/lib/smb/mbuf.c +++ b/contrib/smbfs/lib/smb/mbuf.c @@ -1,471 +1,468 @@ /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: mbuf.c,v 1.6 2001/02/24 15:56:04 bp Exp $ */ -#include -__FBSDID("$FreeBSD$"); - #include #include #include #include #include #include #include #include #include #define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \ __LINE__ ,## args) static int m_get(size_t len, struct mbuf **mpp) { struct mbuf *m; len = M_ALIGN(len); if (len < M_MINSIZE) len = M_MINSIZE; m = malloc(M_BASESIZE + len); if (m == NULL) return ENOMEM; bzero(m, M_BASESIZE + len); m->m_maxlen = len; m->m_data = M_TOP(m); *mpp = m; return 0; } static void m_free(struct mbuf *m) { free(m); } static void m_freem(struct mbuf *m0) { struct mbuf *m; while (m0) { m = m0->m_next; m_free(m0); m0 = m; } } static size_t m_totlen(struct mbuf *m0) { struct mbuf *m = m0; int len = 0; while (m) { len += m->m_len; m = m->m_next; } return len; } int m_lineup(struct mbuf *m0, struct mbuf **mpp) { struct mbuf *nm, *m; char *dp; size_t len; int error; if (m0->m_next == NULL) { *mpp = m0; return 0; } if ((error = m_get(m_totlen(m0), &nm)) != 0) return error; dp = mtod(nm, char *); while (m0) { len = m0->m_len; bcopy(m0->m_data, dp, len); dp += len; m = m0->m_next; m_free(m0); m0 = m; } *mpp = nm; return 0; } int mb_init(struct mbdata *mbp, size_t size) { struct mbuf *m; int error; if ((error = m_get(size, &m)) != 0) return error; return mb_initm(mbp, m); } int mb_initm(struct mbdata *mbp, struct mbuf *m) { bzero(mbp, sizeof(*mbp)); mbp->mb_top = mbp->mb_cur = m; mbp->mb_pos = mtod(m, char *); return 0; } int mb_done(struct mbdata *mbp) { if (mbp->mb_top) { m_freem(mbp->mb_top); mbp->mb_top = NULL; } return 0; } /* int mb_fixhdr(struct mbdata *mbp) { struct mbuf *m = mbp->mb_top; int len = 0; while (m) { len += m->m_len; m = m->m_next; } mbp->mb_top->m_pkthdr.len = len; return len; } */ int m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) { struct mbuf *m, *mp; int error; for (mp = top; ; mp = mp->m_next) { len -= M_TRAILINGSPACE(mp); if (mp->m_next == NULL) break; } if (len > 0) { if ((error = m_get(len, &m)) != 0) return error; mp->m_next = m; } *mpp = top; return 0; } /* * Routines to put data in a buffer */ #define MB_PUT(t) int error; t *p; \ if ((error = mb_fit(mbp, sizeof(t), (char**)&p)) != 0) \ return error /* * Check if object of size 'size' fit to the current position and * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). * Return pointer to the object placeholder or NULL if any error occured. */ int mb_fit(struct mbdata *mbp, size_t size, char **pp) { struct mbuf *m, *mn; int error; m = mbp->mb_cur; if (M_TRAILINGSPACE(m) < (int)size) { if ((error = m_get(size, &mn)) != 0) return error; mbp->mb_pos = mtod(mn, char *); mbp->mb_cur = m->m_next = mn; m = mn; } m->m_len += size; *pp = mbp->mb_pos; mbp->mb_pos += size; mbp->mb_count += size; return 0; } int mb_put_uint8(struct mbdata *mbp, u_int8_t x) { MB_PUT(u_int8_t); *p = x; return 0; } int mb_put_uint16be(struct mbdata *mbp, u_int16_t x) { MB_PUT(u_int16_t); setwbe(p, 0, x); return 0; } int mb_put_uint16le(struct mbdata *mbp, u_int16_t x) { MB_PUT(u_int16_t); setwle(p, 0, x); return 0; } int mb_put_uint32be(struct mbdata *mbp, u_int32_t x) { MB_PUT(u_int32_t); setdbe(p, 0, x); return 0; } int mb_put_uint32le(struct mbdata *mbp, u_int32_t x) { MB_PUT(u_int32_t); setdle(p, 0, x); return 0; } int mb_put_int64be(struct mbdata *mbp, int64_t x) { MB_PUT(int64_t); *p = htobe64(x); return 0; } int mb_put_int64le(struct mbdata *mbp, int64_t x) { MB_PUT(int64_t); *p = htole64(x); return 0; } int mb_put_mem(struct mbdata *mbp, const char *source, size_t size) { struct mbuf *m; char * dst; size_t cplen; int error; if (size == 0) return 0; m = mbp->mb_cur; if ((error = m_getm(m, size, &m)) != 0) return error; while (size > 0) { cplen = M_TRAILINGSPACE(m); if (cplen == 0) { m = m->m_next; continue; } if (cplen > size) cplen = size; dst = mtod(m, char *) + m->m_len; if (source) { bcopy(source, dst, cplen); source += cplen; } else bzero(dst, cplen); size -= cplen; m->m_len += cplen; mbp->mb_count += cplen; } mbp->mb_pos = mtod(m, char *) + m->m_len; mbp->mb_cur = m; return 0; } int mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) { mbp->mb_cur->m_next = m; while (m) { mbp->mb_count += m->m_len; if (m->m_next == NULL) break; m = m->m_next; } mbp->mb_pos = mtod(m, char *) + m->m_len; mbp->mb_cur = m; return 0; } int mb_put_pstring(struct mbdata *mbp, const char *s) { int error, len = strlen(s); if (len > 255) { len = 255; } if ((error = mb_put_uint8(mbp, len)) != 0) return error; return mb_put_mem(mbp, s, len); } /* * Routines for fetching data from an mbuf chain */ #define mb_left(m,p) (mtod(m, char *) + (m)->m_len - (p)) int mb_get_uint8(struct mbdata *mbp, u_int8_t *x) { return mb_get_mem(mbp, x, 1); } int mb_get_uint16(struct mbdata *mbp, u_int16_t *x) { return mb_get_mem(mbp, (char *)x, 2); } int mb_get_uint16le(struct mbdata *mbp, u_int16_t *x) { u_int16_t v; int error = mb_get_uint16(mbp, &v); *x = le16toh(v); return error; } int mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) { u_int16_t v; int error = mb_get_uint16(mbp, &v); *x = be16toh(v); return error; } int mb_get_uint32(struct mbdata *mbp, u_int32_t *x) { return mb_get_mem(mbp, (char *)x, 4); } int mb_get_uint32be(struct mbdata *mbp, u_int32_t *x) { u_int32_t v; int error; error = mb_get_uint32(mbp, &v); *x = be32toh(v); return error; } int mb_get_uint32le(struct mbdata *mbp, u_int32_t *x) { u_int32_t v; int error; error = mb_get_uint32(mbp, &v); *x = le32toh(v); return error; } int mb_get_int64(struct mbdata *mbp, int64_t *x) { return mb_get_mem(mbp, (char *)x, 8); } int mb_get_int64be(struct mbdata *mbp, int64_t *x) { int64_t v; int error; error = mb_get_int64(mbp, &v); *x = be64toh(v); return error; } int mb_get_int64le(struct mbdata *mbp, int64_t *x) { int64_t v; int error; error = mb_get_int64(mbp, &v); *x = le64toh(v); return error; } int mb_get_mem(struct mbdata *mbp, char * target, size_t size) { struct mbuf *m = mbp->mb_cur; u_int count; while (size > 0) { if (m == NULL) { MBERROR("incomplete copy\n"); return EBADRPC; } count = mb_left(m, mbp->mb_pos); if (count == 0) { mbp->mb_cur = m = m->m_next; if (m) mbp->mb_pos = mtod(m, char *); continue; } if (count > size) count = size; size -= count; if (target) { if (count == 1) { *target++ = *mbp->mb_pos; } else { bcopy(mbp->mb_pos, target, count); target += count; } } mbp->mb_pos += count; } return 0; } diff --git a/contrib/smbfs/lib/smb/nb_name.c b/contrib/smbfs/lib/smb/nb_name.c index a953ce0a0a9c..319d3c353b01 100644 --- a/contrib/smbfs/lib/smb/nb_name.c +++ b/contrib/smbfs/lib/smb/nb_name.c @@ -1,197 +1,194 @@ /* * Copyright (c) 2000-2001, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: nb_name.c,v 1.2 2001/08/22 03:31:36 bp Exp $ */ -#include -__FBSDID("$FreeBSD$"); - #include #include #include #include #include #include #include #include #include #include #include #include int nb_snballoc(int namelen, struct sockaddr_nb **dst) { struct sockaddr_nb *snb; int slen; slen = namelen + sizeof(*snb) - sizeof(snb->snb_name); snb = malloc(slen); if (snb == NULL) return ENOMEM; bzero(snb, slen); snb->snb_family = AF_NETBIOS; snb->snb_len = slen; *dst = snb; return 0; } void nb_snbfree(struct sockaddr *snb) { free(snb); } /* * Create a full NETBIOS address */ int nb_sockaddr(struct sockaddr *peer, struct nb_name *np, struct sockaddr_nb **dst) { struct sockaddr_nb *snb; int nmlen, error; if (peer && (peer->sa_family != AF_INET && peer->sa_family != AF_IPX)) return EPROTONOSUPPORT; nmlen = nb_name_len(np); if (nmlen < NB_ENCNAMELEN) return EINVAL; error = nb_snballoc(nmlen, &snb); if (error) return error; if (nmlen != nb_name_encode(np, snb->snb_name)) printf("a bug somewhere in the nb_name* code\n"); if (peer) memcpy(&snb->snb_tran, peer, peer->sa_len); *dst = snb; return 0; } int nb_name_len(struct nb_name *np) { u_char *name; int len, sclen; len = 1 + NB_ENCNAMELEN; if (np->nn_scope == NULL) return len + 1; sclen = 0; for (name = np->nn_scope; *name; name++) { if (*name == '.') { sclen = 0; } else { if (sclen < NB_MAXLABLEN) { sclen++; len++; } } } return len + 1; } int nb_encname_len(const char *str) { const u_char *cp = (const u_char *)str; int len, blen; if ((cp[0] & 0xc0) == 0xc0) return -1; /* first two bytes are offset to name */ len = 1; for (;;) { blen = *cp; if (blen++ == 0) break; len += blen; cp += blen; } return len; } static inline void nb_char_encode(u_char **ptr, u_char c, int n) { while (n--) { *(*ptr)++ = 0x41 + (c >> 4); *(*ptr)++ = 0x41 + (c & 0x0f); } } int nb_name_encode(struct nb_name *np, u_char *dst) { u_char *name, *plen; u_char *cp = dst; int i, lblen; *cp++ = NB_ENCNAMELEN; name = np->nn_name; if (name[0] == '*' && name[1] == 0) { nb_char_encode(&cp, '*', 1); nb_char_encode(&cp, ' ', NB_NAMELEN - 1); } else { for (i = 0; i < NB_NAMELEN - 1; i++) if (*name != 0) nb_char_encode(&cp, toupper(*name++), 1); else nb_char_encode(&cp, ' ', 1); nb_char_encode(&cp, np->nn_type, 1); } *cp = 0; if (np->nn_scope == NULL) return nb_encname_len(dst); plen = cp++; lblen = 0; for (name = np->nn_scope; ; name++) { if (*name == '.' || *name == 0) { *plen = lblen; plen = cp++; *plen = 0; if (*name == 0) break; } else { if (lblen < NB_MAXLABLEN) { *cp++ = *name; lblen++; } } } return nb_encname_len(dst); } diff --git a/contrib/smbfs/lib/smb/nls.c b/contrib/smbfs/lib/smb/nls.c index b79d49c29c58..99693f3aba84 100644 --- a/contrib/smbfs/lib/smb/nls.c +++ b/contrib/smbfs/lib/smb/nls.c @@ -1,223 +1,220 @@ /* * Copyright (c) 2000-2001, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: nls.c,v 1.10 2002/07/22 08:33:59 bp Exp $ */ -#include -__FBSDID("$FreeBSD$"); - #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ICONV #include #endif u_char nls_lower[256]; u_char nls_upper[256]; #ifdef HAVE_ICONV static iconv_t nls_toext, nls_toloc; #endif int nls_setlocale(const char *name) { int i; if (setlocale(LC_CTYPE, name) == NULL) { warnx("can't set locale '%s'\n", name); return EINVAL; } for (i = 0; i < 256; i++) { nls_lower[i] = tolower(i); nls_upper[i] = toupper(i); } return 0; } int nls_setrecode(const char *local, const char *external) { #ifdef HAVE_ICONV iconv_t icd; if (nls_toext) iconv_close(nls_toext); if (nls_toloc) iconv_close(nls_toloc); nls_toext = nls_toloc = (iconv_t)0; icd = iconv_open(external, local); if (icd == (iconv_t)-1) return errno; nls_toext = icd; icd = iconv_open(local, external); if (icd == (iconv_t)-1) { iconv_close(nls_toext); nls_toext = (iconv_t)0; return errno; } nls_toloc = icd; return 0; #else return ENOENT; #endif } char * nls_str_toloc(char *dst, char *src) { #ifdef HAVE_ICONV char *p = dst; size_t inlen, outlen; if (nls_toloc == (iconv_t)0) return strcpy(dst, src); inlen = outlen = strlen(src); iconv(nls_toloc, NULL, NULL, &p, &outlen); while (iconv(nls_toloc, &src, &inlen, &p, &outlen) == -1) { *p++ = *src++; inlen--; outlen--; } *p = 0; return dst; #else return strcpy(dst, src); #endif } char * nls_str_toext(char *dst, char *src) { #ifdef HAVE_ICONV char *p = dst; size_t inlen, outlen; if (nls_toext == (iconv_t)0) return strcpy(dst, src); inlen = outlen = strlen(src); iconv(nls_toext, NULL, NULL, &p, &outlen); while (iconv(nls_toext, &src, &inlen, &p, &outlen) == -1) { *p++ = *src++; inlen--; outlen--; } *p = 0; return dst; #else return strcpy(dst, src); #endif } void * nls_mem_toloc(void *dst, void *src, int size) { #ifdef HAVE_ICONV char *p = dst; char *s = src; size_t inlen, outlen; if (size == 0) return NULL; if (nls_toloc == (iconv_t)0) return memcpy(dst, src, size); inlen = outlen = size; iconv(nls_toloc, NULL, NULL, &p, &outlen); while (iconv(nls_toloc, &s, &inlen, &p, &outlen) == -1) { *p++ = *s++; inlen--; outlen--; } return dst; #else return memcpy(dst, src, size); #endif } void * nls_mem_toext(void *dst, void *src, int size) { #ifdef HAVE_ICONV char *p = dst; char *s = src; size_t inlen, outlen; if (size == 0) return NULL; if (nls_toext == (iconv_t)0) return memcpy(dst, src, size); inlen = outlen = size; iconv(nls_toext, NULL, NULL, &p, &outlen); while (iconv(nls_toext, &s, &inlen, &p, &outlen) == -1) { *p++ = *s++; inlen--; outlen--; } return dst; #else return memcpy(dst, src, size); #endif } char * nls_str_upper(char *dst, const char *src) { char *p = dst; while (*src) *dst++ = toupper(*src++); *dst = 0; return p; } char * nls_str_lower(char *dst, const char *src) { char *p = dst; while (*src) *dst++ = tolower(*src++); *dst = 0; return p; } diff --git a/contrib/smbfs/lib/smb/rcfile.c b/contrib/smbfs/lib/smb/rcfile.c index 26a31d6f37ee..f97cb5abbf35 100644 --- a/contrib/smbfs/lib/smb/rcfile.c +++ b/contrib/smbfs/lib/smb/rcfile.c @@ -1,511 +1,508 @@ /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: rcfile.c,v 1.5 2001/04/16 12:46:46 bp Exp $ */ -#include -__FBSDID("$FreeBSD$"); - #include #include #include #include #include #include #include #include #include #include #include #include "rcfile_priv.h" SLIST_HEAD(rcfile_head, rcfile); static struct rcfile_head pf_head = {NULL}; static struct rcfile* rc_cachelookup(const char *filename); static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); static struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value); static void rc_key_free(struct rckey *p); static void rc_parse(struct rcfile *rcp); /* * open rcfile and load its content, if already open - return previous handle */ int rc_open(const char *filename, const char *mode, struct rcfile **rcfile) { struct rcfile *rcp; FILE *f; rcp = rc_cachelookup(filename); if (rcp) { *rcfile = rcp; return 0; } f = fopen(filename, mode); if (f == NULL) return errno; rcp = malloc(sizeof(struct rcfile)); if (rcp == NULL) { fclose(f); return ENOMEM; } bzero(rcp, sizeof(struct rcfile)); rcp->rf_name = strdup(filename); rcp->rf_f = f; SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); rc_parse(rcp); *rcfile = rcp; return 0; } int rc_merge(const char *filename, struct rcfile **rcfile) { struct rcfile *rcp = *rcfile; FILE *f, *t; if (rcp == NULL) { return rc_open(filename, "r", rcfile); } f = fopen (filename, "r"); if (f == NULL) return errno; t = rcp->rf_f; rcp->rf_f = f; rc_parse(rcp); rcp->rf_f = t; fclose(f); return 0; } int rc_close(struct rcfile *rcp) { struct rcsection *p, *n; fclose(rcp->rf_f); for(p = SLIST_FIRST(&rcp->rf_sect); p;) { n = p; p = SLIST_NEXT(p,rs_next); rc_freesect(rcp, n); } free(rcp->rf_name); SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); free(rcp); return 0; } static struct rcfile* rc_cachelookup(const char *filename) { struct rcfile *p; SLIST_FOREACH(p, &pf_head, rf_next) if (strcmp (filename, p->rf_name) == 0) return p; return 0; } static struct rcsection * rc_findsect(struct rcfile *rcp, const char *sectname) { struct rcsection *p; SLIST_FOREACH(p, &rcp->rf_sect, rs_next) if (strcmp(p->rs_name, sectname)==0) return p; return NULL; } static struct rcsection * rc_addsect(struct rcfile *rcp, const char *sectname) { struct rcsection *p; const char* sectletter = sectname; p = rc_findsect(rcp, sectname); if (p) return p; p = malloc(sizeof(*p)); if (!p) return NULL; for(sectletter = sectname; *sectletter; sectletter++) { if (islower(*sectletter)) { if (strcmp(sectname, "default")) dprintf(STDERR_FILENO, "warning: section name [%s] contains lower-case letters\n", sectname); break; } } p->rs_name = strdup(sectname); SLIST_INIT(&p->rs_keys); SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); return p; } static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp) { struct rckey *p,*n; SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); for(p = SLIST_FIRST(&rsp->rs_keys);p;) { n = p; p = SLIST_NEXT(p,rk_next); rc_key_free(n); } free(rsp->rs_name); free(rsp); return 0; } static struct rckey * rc_sect_findkey(struct rcsection *rsp, const char *keyname) { struct rckey *p; SLIST_FOREACH(p, &rsp->rs_keys, rk_next) if (strcmp(p->rk_name, keyname)==0) return p; return NULL; } static struct rckey * rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) { struct rckey *p; p = rc_sect_findkey(rsp, name); if (p) { free(p->rk_value); } else { p = malloc(sizeof(*p)); if (!p) return NULL; SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); p->rk_name = strdup(name); } p->rk_value = value ? strdup(value) : strdup(""); return p; } #if 0 void rc_sect_delkey(struct rcsection *rsp, struct rckey *p) { SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); rc_key_free(p); return; } #endif static void rc_key_free(struct rckey *p) { free(p->rk_value); free(p->rk_name); free(p); } enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; static void rc_parse(struct rcfile *rcp) { FILE *f = rcp->rf_f; int state = stNewLine, c; struct rcsection *rsp = NULL; struct rckey *rkp = NULL; char buf[2048]; char *next = buf, *last = &buf[sizeof(buf)-1]; while ((c = getc (f)) != EOF) { if (c == '\r') continue; if (state == stNewLine) { next = buf; if (isspace(c)) continue; /* skip leading junk */ if (c == '[') { state = stHeader; rsp = NULL; continue; } if (c == '#' || c == ';') { state = stSkipToEOL; } else { /* something meaningfull */ state = stGetKey; } } if (state == stSkipToEOL || next == last) {/* ignore long lines */ if (c == '\n'){ state = stNewLine; next = buf; } continue; } if (state == stHeader) { if (c == ']') { *next = 0; next = buf; rsp = rc_addsect(rcp, buf); state = stSkipToEOL; } else *next++ = c; continue; } if (state == stGetKey) { if (c == ' ' || c == '\t')/* side effect: 'key name='*/ continue; /* become 'keyname=' */ if (c == '\n') { /* silently ignore ... */ state = stNewLine; continue; } if (c != '=') { *next++ = c; continue; } *next = 0; if (rsp == NULL) { fprintf(stderr, "Key '%s' defined before section\n", buf); state = stSkipToEOL; continue; } rkp = rc_sect_addkey(rsp, buf, NULL); next = buf; state = stGetValue; continue; } /* only stGetValue left */ if (state != stGetValue) { fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name); state = stSkipToEOL; } if (c != '\n') { *next++ = c; continue; } *next = 0; rkp->rk_value = strdup(buf); state = stNewLine; rkp = NULL; } /* while */ if (c == EOF && state == stGetValue) { *next = 0; rkp->rk_value = strdup(buf); } return; } int rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, char **dest) { struct rcsection *rsp; struct rckey *rkp; *dest = NULL; rsp = rc_findsect(rcp, section); if (!rsp) return ENOENT; rkp = rc_sect_findkey(rsp,key); if (!rkp) return ENOENT; *dest = rkp->rk_value; return 0; } int rc_getstring(struct rcfile *rcp, const char *section, const char *key, size_t maxlen, char *dest) { char *value; int error; error = rc_getstringptr(rcp, section, key, &value); if (error) return error; if (strlen(value) >= maxlen) { warnx("line too long for key '%s' in section '%s', max = %zd\n", key, section, maxlen); return EINVAL; } strcpy(dest, value); return 0; } int rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) { struct rcsection *rsp; struct rckey *rkp; rsp = rc_findsect(rcp, section); if (!rsp) return ENOENT; rkp = rc_sect_findkey(rsp, key); if (!rkp) return ENOENT; errno = 0; *value = strtol(rkp->rk_value, NULL, 0); if (errno) { warnx("invalid int value '%s' for key '%s' in section '%s'\n", rkp->rk_value, key, section); return errno; } return 0; } /* * 1,yes,true * 0,no,false */ int rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) { struct rcsection *rsp; struct rckey *rkp; char *p; rsp = rc_findsect(rcp, section); if (!rsp) return ENOENT; rkp = rc_sect_findkey(rsp,key); if (!rkp) return ENOENT; p = rkp->rk_value; while (*p && isspace(*p)) p++; if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) { *value = 0; return 0; } if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) { *value = 1; return 0; } fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section); return EINVAL; } /* * Unified command line/rc file parser */ int opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, opt_callback_t *callback) { int len, error; for (; ap->opt; ap++) { switch (ap->type) { case OPTARG_STR: if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) break; len = strlen(ap->str); if (len > ap->ival) { warnx("rc: argument for option '%c' (%s) too long\n", ap->opt, ap->name); return EINVAL; } callback(ap); break; case OPTARG_BOOL: error = rc_getbool(rcp, sect, ap->name, &ap->ival); if (error == ENOENT) break; if (error) return EINVAL; callback(ap); break; case OPTARG_INT: if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) break; if (((ap->flag & OPTFL_HAVEMIN) && ap->ival < ap->min) || ((ap->flag & OPTFL_HAVEMAX) && ap->ival > ap->max)) { warnx("rc: argument for option '%c' (%s) should be in [%d-%d] range\n", ap->opt, ap->name, ap->min, ap->max); return EINVAL; } callback(ap); break; default: break; } } return 0; } int opt_args_parseopt(struct opt_args *ap, int opt, char *arg, opt_callback_t *callback) { int len; for (; ap->opt; ap++) { if (ap->opt != opt) continue; switch (ap->type) { case OPTARG_STR: ap->str = arg; if (arg) { len = strlen(ap->str); if (len > ap->ival) { warnx("opt: Argument for option '%c' (%s) too long\n", ap->opt, ap->name); return EINVAL; } callback(ap); } break; case OPTARG_BOOL: ap->ival = 0; callback(ap); break; case OPTARG_INT: errno = 0; ap->ival = strtol(arg, NULL, 0); if (errno) { warnx("opt: Invalid integer value for option '%c' (%s).\n",ap->opt,ap->name); return EINVAL; } if (((ap->flag & OPTFL_HAVEMIN) && (ap->ival < ap->min)) || ((ap->flag & OPTFL_HAVEMAX) && (ap->ival > ap->max))) { warnx("opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",ap->opt,ap->name,ap->min,ap->max); return EINVAL; } callback(ap); break; default: break; } break; } return 0; }