#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.8 2025/09/18 21:26:44 rillig Exp $");
#endif
#endif
#include "rcv.h"
#include <util.h>
#include "extern.h"
#if 0
void showname(struct name *);
void
showname(struct name *np)
{
for (; 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
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;
}
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;
}
}
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 (; np; np = np->n_flink)
printsmopts(np->n_name);
return 0;
}
for (; 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 (; np; np = next_np) {
next_np = np->n_flink;
free(np);
}
}
static void
delsmopts(char *name)
{
struct smopts_s *sp, *next;
struct smopts_s **last_link;
last_link = &smoptstbl[hashcase(name)];
for (sp = *last_link; sp; sp = next) {
next = sp->s_link;
if (strcasecmp(sp->s_name, name) == 0) {
*last_link = sp->s_link;
free_name(sp->s_smopts);
free(sp);
}
}
}
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;
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;
}
PUBLIC int
Header(void *v)
{
struct name *np;
char *str;
char *p;
str = v;
if (str == NULL)
return 0;
(void)strip_WSP(str);
if (str[0] == '\0') {
for (np = extra_headers; np != NULL; np = np->n_flink)
(void)printf("%s\n", np->n_name);
return 0;
}
for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++)
continue;
if (p[0] == ':' && p[1] == '\0')
return free_Header(str);
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;
}