/*
 * Routines for reading information from /etc/group.
 * Written by Eric Smith, based on Arnold Robbins' public domain
 * getpwent routines (see getpw.c).
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <grp.h>

static char *grpfile = "/etc/group";	/* default group file */
static FILE *fp;

static struct group curentry;		/* static data to return */

static int nextent __PROTO((void));

void setgrent ()
{
	if (fp)
		rewind (fp);
	else if ((fp = fopen (grpfile, "r")) == NULL)
	{
#ifdef VERBOSE
		fprintf (stderr,
			"setgrent: %s non-existant or unreadable.\n", grpfile);
#endif
	}
}

void endgrent ()
{
	if (fp)
	{
		fclose (fp);
		fp = NULL;
	}
}

struct group *getgrent ()
{
	if (!fp) setgrent();
	if (!fp) return NULL;

	if (! nextent ())
		return (NULL);
	else
		return (& curentry);
}

struct group *getgrgid (gid)
	int gid;
{
	setgrent();

	while (nextent ())
		if (curentry.gr_gid == gid)
			return (& curentry);

	return (NULL);
}

struct group *getgrnam (name)
register char *name;
{
	setgrent();

	while (nextent ())
		if (strcmp (curentry.gr_name, name) == 0)
			return (& curentry);

	return (NULL);
}

#define MAX_MEMBERS 128		/* max. number of members in a group */

static char savbuf[512];
static char *memb[MAX_MEMBERS];

static int nextent ()
{
	register char *cp;
	register int i;

	if (!fp) setgrent();
	if (!fp) return 0;

	if (fgets (savbuf, sizeof(savbuf), fp) != NULL)
	{
		for (cp = savbuf; *cp && *cp != ':'; cp++)
			;
		curentry.gr_name = savbuf;
		*cp++ = '\0';
		curentry.gr_passwd = cp;
		for (; *cp && *cp != ':'; cp++)
			;
		*cp++ = '\0';
		curentry.gr_gid = atoi (cp);
		for (; *cp && *cp != ':'; cp++)
			;

		*cp++ = '\0';

		i = 0;
		while( *cp ) {
			if (i >= MAX_MEMBERS-1) break;
			memb[i++] = cp;
			for(; *cp && *cp != ',' && *cp != '\n'; cp++)
				;
			if (*cp == '\n')
				*cp = 0;
			else if (*cp)
				*cp++ = 0;
		}
		memb[i] = NULL;
		curentry.gr_mem = memb;
		return (1);
	}
	return (0);
}

#ifdef TEST
int
main (argc, argv)
int argc;
char **argv;
{
	struct group *gr;
	char **m;

	if (argc > 1) {
		grpfile = argv[1];
	}

	setgrent ();
	while ((gr = getgrent ()) != NULL)
	{
		printf ("%s:[%s] %d\n",
			gr->gr_name,
			gr->gr_passwd,
			gr->gr_gid);
		for (m = gr->gr_mem; *m; m++) {
			printf("\t%s\n", *m);
		}
	}
	endgrent ();

	if (gr = getgrnam ("mail")) {
		printf ("%s:[%s] %d\n",
			gr->gr_name,
			gr->gr_passwd,
			gr->gr_gid);
		for (m = gr->gr_mem; *m; m++) {
			printf("\t%s\n", *m);
		}
	}
	if (gr = getgrgid (1)) {
		printf ("%s:[%s] %d\n",
			gr->gr_name,
			gr->gr_passwd,
			gr->gr_gid);
		for (m = gr->gr_mem; *m; m++) {
			printf("\t%s\n", *m);
		}
	}
	return 0;
}
#endif
