Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $	*/

/*-
 * Copyright (c) 2006 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Anon Ymous.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */


#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cmd3.c	8.2 (Berkeley) 4/20/95";
#else
__RCSID("$NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $");
#endif
#endif /* not lint */

#include "rcv.h"
#include <util.h>
#include "extern.h"

/*
 * Mail -- a mail program
 *
 * Still more user commands.
 * XXX - should this be renamed smopts.c?
 */

#if 0	/* XXX - debugging stuff - to be removed */
void showname(struct name *);
void
showname(struct name *np)
{

	for (/*EMPTY*/; np; np = np->n_flink)
		(void)printf("np: %p  np->n_type: %d  np->n_name: '%s' (%p)\n",
		    np, np->n_type, np->n_name, np->n_name);
}

__unused
static void
showsmopts(struct smopts_s *sp)
{

	(void)printf("%s (%p)\n", sp->s_name, sp);
	showname(sp->s_smopts);
}
#endif	/* XXX - debugging stuff - to be removed */


static int
hashcase(const char *key)
{
	char *lckey;

	lckey = salloc(strlen(key) + 1);
	istrcpy(lckey, key);
	return hash(lckey);
}

static struct smopts_s *
findsmopts_core(const char *name)
{
	struct smopts_s *sh;

	for (sh = smoptstbl[hashcase(name)]; sh; sh = sh->s_link)
		if (strcasecmp(sh->s_name, name) == 0)
			return sh;
	return NULL;
}

/*
 * The exported smopts lookup routine.
 */
PUBLIC struct smopts_s *
findsmopts(const char *name, int top_only)
{
	const char *cp;
	struct smopts_s *sh;

	if ((sh = findsmopts_core(name)) != NULL)
		return sh;

	if (top_only)
		return NULL;

	for (cp = strchr(name, '@'); cp; cp = strchr(cp + 1, '.'))
		if ((sh = findsmopts_core(cp)) != NULL)
			return sh;

	return findsmopts_core(".");
}

static void
printsmopts(const char *name)
{
	struct smopts_s *sp;

	if ((sp = findsmopts(name, 1)) == NULL) {
		(void)printf("%s:\n", name);
		return;
	}
	(void)printf("%s:\t%s\n", sp->s_name, detract(sp->s_smopts, GSMOPTS));
}

static void
printsmoptstbl(void)
{
	struct smopts_s *sp;
	const char **argv;
	const char **ap;
	int h;
	int cnt;

	cnt = 1;
	for (h = 0; h < (int)__arraycount(smoptstbl); h++)
		for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
			cnt++;

	argv = salloc(cnt * sizeof(*argv));
	ap = argv;
	for (h = 0; h < (int)__arraycount(smoptstbl); h++)
		for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
			*ap++ = sp->s_name;
	*ap = NULL;
	sort(argv);
	for (ap = argv; *ap != NULL; ap++)
		printsmopts(*ap);
}

static struct name *
name_expand(char *sname, int ntype)
{
	struct grouphead *gh;
	struct name *np;

	if ((gh = findgroup(sname)) != NULL) {
		np = gexpand(NULL, gh, 0, ntype);
	}
	else {
		np = csalloc(1, sizeof(*np));
		np->n_name = sname;
		np->n_type = ntype;
	}
	return np;
}

static struct name *
ncalloc(char *str, int ntype)
{
	struct name *np;

	np = ecalloc(1, sizeof(*np));
	np->n_type = ntype;
	np->n_name = vcopy(str);
	return np;
}

static void
smopts_core(const char *sname, char **argv)
{
	struct smopts_s *sp;
	struct name *np;
	struct name *t;
	int h;
	char **ap;

	if ((sp = findsmopts(sname, 1)) != NULL) {
		char *cp;
		cp = detract(sp->s_smopts, GSMOPTS);
		(void)printf("%s already defined as: %s\n", sname, cp);
		return;
	}
	h = hashcase(sname);
	sp = ecalloc(1, sizeof(*sp));
	sp->s_name = vcopy(sname);
	if (smoptstbl[h])
		sp->s_link = smoptstbl[h];
	smoptstbl[h] = sp;

	np = NULL;
	for (ap = argv + 1; *ap != NULL; ap++) {
		t = ncalloc(*ap, GSMOPTS);
		if (sp->s_smopts == NULL)
			sp->s_smopts = t;
		else
			np->n_flink = t;
		t->n_blink = np;
		np = t;
	}
}

/*
 * Takes a list of entries, expands them, and adds the results to the
 * smopts table.
 */
PUBLIC int
smoptscmd(void *v)
{
	struct name *np;
	char **argv;

	argv = v;
	if (*argv == NULL) {
		printsmoptstbl();
		return 0;
	}
	np = name_expand(argv[0], GTO);

	if (argv[1] == NULL) {
		for (/*EMPTY*/; np; np = np->n_flink)
			printsmopts(np->n_name);
		return 0;
	}
	for (/*EMPTY*/; np; np = np->n_flink)
		smopts_core(np->n_name, argv);

	return 0;
}

static void
free_name(struct name *np)
{
	struct name *next_np;

	for (/*EMPTY*/; np; np = next_np) {
		next_np = np->n_flink;
		free(next_np);
	}
}

static void
delsmopts(char *name)
{
	struct smopts_s *sp;
	struct smopts_s **last_link;

	last_link = &smoptstbl[hashcase(name)];
	for (sp = *last_link; sp; sp = sp->s_link) {
		if (strcasecmp(sp->s_name, name) == 0) {
			*last_link = sp->s_link;
			free_name(sp->s_smopts);
			free(sp);
		}
	}
}

/*
 * Takes a list of entries and removes them from the smoptstbl.
 */
PUBLIC int
unsmoptscmd(void *v)
{
	struct name *np;
	char **ap;

	for (ap = v; *ap != NULL; ap++)
		for (np = name_expand(*ap, GTO); np; np = np->n_flink)
			delsmopts(np->n_name);
	return 0;
}

static struct name *
alloc_Header(char *str)
{
	struct name *np;

	/*
	 * Don't use salloc() routines here as these strings must persist.
	 */
	np = ecalloc(1, sizeof(*np));
	np->n_name = estrdup(str);
	np->n_type = GMISC;
	return np;
}

static int
free_Header(char *str)
{
	struct name *np;
	struct name *next_np;
	size_t len;

	len = strlen(str);
	for (np = extra_headers; np != NULL; np = next_np) {
		next_np = np->n_flink;
		if (strncasecmp(np->n_name, str, len) == 0) {
			if (np == extra_headers) {
				extra_headers = np->n_flink;
				if (extra_headers)
					extra_headers->n_blink = NULL;
			}
			else {
				struct name *bp;
				struct name *fp;

				bp = np->n_blink;
				fp = np->n_flink;
				if (bp)
					bp->n_flink = fp;
				if (fp)
					fp->n_blink = bp;
			}
			if (np->n_name)
				free(np->n_name);
			free(np);
		}
	}
	return 0;
}

/*
 * Takes a string and includes it in the header.
 */
PUBLIC int
Header(void *v)
{
	struct name *np;
	char *str;
	char *p;

	str = v;
	if (str == NULL)
		return 0;

	(void)strip_WSP(str);	/* strip trailing whitespace */

	if (str[0] == '\0') {	/* Show the extra headers */
		for (np = extra_headers; np != NULL; np = np->n_flink)
			(void)printf("%s\n", np->n_name);
		return 0;
	}

	/*
	 * Check for a valid header line: find the end of its name.
	 */
	for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++)
		continue;

	if (p[0] == ':' && p[1] == '\0') /* free headers of this type */
		return free_Header(str);

	/*
	 * Check for a valid header name.
	 */
	if (*p != ':' || !is_WSP(p[1])) {
		(void)printf("invalid header string: `%s'\n", str);
		return 0;
	}

	np = alloc_Header(str);
	if (extra_headers == NULL)
		extra_headers = np;
	else {
		struct name *tp;

		for (tp = extra_headers; tp->n_flink; tp = tp->n_flink)
			continue;
		tp->n_flink = np;
		np->n_blink = tp;
	}
	return 0;
}