text: /*	$OpenBSD: stringlist.c,v 1.3 2015/12/19 20:37:11 mmcc Exp $	*/
  
  /*
   * Copyright (c) 1994 Christos Zoulas
   * 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 Christos Zoulas.
   * 4. The name of the author may not be used to endorse or promote products
   *    derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
   */
  
  #include <sys/types.h>
  #include <stdio.h>
  #include <netgroup.h>
  #include <string.h>
  #include <stdlib.h>
  #include <ctype.h>
  #include "stringlist.h"
  
  static const char _ngstar[] = "*";
  
  static int		getstring(char **, int, char **);
  static struct netgroup	*getnetgroup(char **);
  
  /*
   * _ng_sl_init(): Initialize a string list
   */
  struct stringlist *
  _ng_sl_init(void)
  {
  	struct stringlist *sl = malloc(sizeof(struct stringlist));
  	if (sl == NULL)
  		return NULL;
  
  	sl->sl_cur = 0;
  	sl->sl_max = 20;
  	sl->sl_str = calloc(sl->sl_max, sizeof(char *));
  	if (sl->sl_str == NULL) {
  		free(sl);
  		return NULL;
  	}
  	return sl;
  }
  
  
  /*
   * _ng_sl_add(): Add an item to the string list
   */
  int
  _ng_sl_add(struct stringlist *sl, char *name)
  {
  	if (sl->sl_cur == sl->sl_max - 1) {
  		char **slstr;
  
  		sl->sl_max += 20;
  		slstr = reallocarray(sl->sl_str, sl->sl_max, sizeof(char *));
  		if (slstr == NULL) {
  			free(sl->sl_str);
  			sl->sl_str = NULL;
  			return -1;
  		}
  		sl->sl_str = slstr;
  	}
  	sl->sl_str[sl->sl_cur++] = name;
  	return 0;
  }
  
  
  /*
   * _ng_sl_free(): Free a stringlist
   */
  void
  _ng_sl_free(struct stringlist *sl, int all)
  {
  	size_t	i;
  
  	if (all)
  		for (i = 0; i < sl->sl_cur; i++)
  			free(sl->sl_str[i]);
  	free(sl->sl_str);
  	free(sl);
  }
  
  
  /*
   * sl_find(): Find a name in the string list
   */
  char *
  _ng_sl_find(struct stringlist *sl, char *name)
  {
  	size_t	i;
  
  	for (i = 0; i < sl->sl_cur; i++)
  		if (strcmp(sl->sl_str[i], name) == 0)
  			return sl->sl_str[i];
  
  	return NULL;
  }
  
  /*
   * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
   * line was empty or a comment _NG_GROUP: line had a netgroup definition,
   * returned in ng _NG_NAME:  line had a netgroup name, returned in name
   *
   * Public since used by netgroup_mkdb
   */
  int
  _ng_parse(char **p, char **name, struct netgroup **ng)
  {
  	while (**p) {
  		if (**p == '#')
  			/* comment */
  			return _NG_NONE;
  
  		while (**p && _NG_ISSPACE(**p))
  			/* skipblank */
  			(*p)++;
  
  		if (**p == '(') {
  			if ((*ng = getnetgroup(p)) == NULL)
  				return _NG_ERROR;
  			return _NG_GROUP;
  		} else {
  			char	*np;
  			int	i;
  
  			for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
  				continue;
  			if (np != *p) {
  				i = (*p - np) + 1;
  				*name = malloc(i);
  				if (*name == NULL)
  					return _NG_ERROR;
  				memcpy(*name, np, i);
  				(*name)[i - 1] = '\0';
  				return _NG_NAME;
  			}
  		}
  	}
  	return _NG_NONE;
  }
  
  /*
   * _ng_makekey(): Make a key from the two names given. The key is of the form
   * <name1>.<name2> Names strings are replaced with * if they are empty;
   */
  char *
  _ng_makekey(const char *s1, const char *s2, size_t len)
  {
  	char *buf = malloc(len);
  	int ret;
  
  	if (buf == NULL)
  		return NULL;
  	ret = snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
  	if (ret < 0 || ret >= len) {
  		free(buf);
  		return NULL;
  	}
  
  	return buf;
  }
  
  void
  _ng_print(char *buf, size_t len, const struct netgroup *ng)
  {
  	(void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
  	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
  }
  
  /*
   * getnetgroup(): Parse a netgroup, and advance the pointer
   */
  static struct netgroup *
  getnetgroup(char **pp)
  {
  	struct netgroup *ng = malloc(sizeof(struct netgroup));
  
  	if (ng == NULL)
  		return NULL;
  
  	(*pp)++;	/* skip '(' */
  	if (!getstring(pp, ',', &ng->ng_host))
  		goto badhost;
  
  	if (!getstring(pp, ',', &ng->ng_user))
  		goto baduser;
  
  	if (!getstring(pp, ')', &ng->ng_domain))
  		goto baddomain;
  
  #ifdef DEBUG_NG
  	{
  		char buf[1024];
  		_ng_print(buf, sizeof(buf), ng);
  		fprintf(stderr, "netgroup %s\n", buf);
  	}
  #endif
  	return ng;
  
  baddomain:
  	free(ng->ng_user);
  baduser:
  	free(ng->ng_host);
  badhost:
  	free(ng);
  	return NULL;
  }
  
  /*
   * getstring(): Get a string delimited by the character, skipping leading and
   * trailing blanks and advancing the pointer
   */
  static int
  getstring(char **pp, int del, char **str)
  {
  	char *sp, *ep, *dp;
  
  	/* skip leading blanks */
  	for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
  		continue;
  
  	/* accumulate till delimiter or space */
  	for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
  		continue;
  
  	/* hunt for the delimiter */
  	for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
  		continue;
  
  	if (*dp != del) {
  		*str = NULL;
  		return 0;
  	}
  
  	*pp = ++dp;
  
  	del = (ep - sp) + 1;
  	if (del > 1) {
  		dp = malloc(del);
  		if (dp == NULL)
  			return 0;
  		memcpy(dp, sp, del);
  		dp[del - 1] = '\0';
  	} else
  		dp = NULL;
  
  	*str = dp;
  	return 1;
  }
  