xref: /csrg-svn/usr.bin/mail/names.c (revision 62083)
122461Sdist /*
2*62083Sbostic  * Copyright (c) 1980, 1993
3*62083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622461Sdist  */
722461Sdist 
834905Sbostic #ifndef lint
9*62083Sbostic static char sccsid[] = "@(#)names.c	8.1 (Berkeley) 06/06/93";
1034905Sbostic #endif /* not lint */
111241Skas 
121241Skas /*
131241Skas  * Mail -- a mail program
141241Skas  *
151241Skas  * Handle name lists.
161241Skas  */
171241Skas 
181241Skas #include "rcv.h"
1954505Sbostic #include <fcntl.h>
2054505Sbostic #include "extern.h"
211241Skas 
221241Skas /*
231241Skas  * Allocate a single element of a name list,
241241Skas  * initialize its name field to the passed
251241Skas  * name and return it.
261241Skas  */
271241Skas struct name *
nalloc(str,ntype)2834800Sedward nalloc(str, ntype)
291241Skas 	char str[];
3054505Sbostic 	int ntype;
311241Skas {
321241Skas 	register struct name *np;
331241Skas 
341241Skas 	np = (struct name *) salloc(sizeof *np);
351241Skas 	np->n_flink = NIL;
361241Skas 	np->n_blink = NIL;
3734800Sedward 	np->n_type = ntype;
381241Skas 	np->n_name = savestr(str);
391241Skas 	return(np);
401241Skas }
411241Skas 
421241Skas /*
431241Skas  * Find the tail of a list and return it.
441241Skas  */
451241Skas struct name *
tailof(name)461241Skas tailof(name)
471241Skas 	struct name *name;
481241Skas {
491241Skas 	register struct name *np;
501241Skas 
511241Skas 	np = name;
521241Skas 	if (np == NIL)
531241Skas 		return(NIL);
541241Skas 	while (np->n_flink != NIL)
551241Skas 		np = np->n_flink;
561241Skas 	return(np);
571241Skas }
581241Skas 
591241Skas /*
601241Skas  * Extract a list of names from a line,
611241Skas  * and make a list of names from it.
621241Skas  * Return the list or NIL if none found.
631241Skas  */
641241Skas struct name *
extract(line,ntype)651241Skas extract(line, ntype)
661241Skas 	char line[];
6754505Sbostic 	int ntype;
681241Skas {
691241Skas 	register char *cp;
701241Skas 	register struct name *top, *np, *t;
7134800Sedward 	char nbuf[BUFSIZ];
721241Skas 
7334800Sedward 	if (line == NOSTR || *line == '\0')
7434800Sedward 		return NIL;
751241Skas 	top = NIL;
761241Skas 	np = NIL;
771241Skas 	cp = line;
781241Skas 	while ((cp = yankword(cp, nbuf)) != NOSTR) {
7934800Sedward 		t = nalloc(nbuf, ntype);
801241Skas 		if (top == NIL)
811241Skas 			top = t;
821241Skas 		else
831241Skas 			np->n_flink = t;
841241Skas 		t->n_blink = np;
851241Skas 		np = t;
861241Skas 	}
8734800Sedward 	return top;
881241Skas }
891241Skas 
901241Skas /*
911241Skas  * Turn a list of names into a string of the same names.
921241Skas  */
931241Skas char *
detract(np,ntype)941241Skas detract(np, ntype)
951241Skas 	register struct name *np;
9654505Sbostic 	int ntype;
971241Skas {
981241Skas 	register int s;
991241Skas 	register char *cp, *top;
1001241Skas 	register struct name *p;
1011241Skas 	register int comma;
1021241Skas 
1031241Skas 	comma = ntype & GCOMMA;
1041241Skas 	if (np == NIL)
1051241Skas 		return(NOSTR);
1061241Skas 	ntype &= ~GCOMMA;
1071241Skas 	s = 0;
1081241Skas 	if (debug && comma)
1091241Skas 		fprintf(stderr, "detract asked to insert commas\n");
1101241Skas 	for (p = np; p != NIL; p = p->n_flink) {
1111241Skas 		if (ntype && (p->n_type & GMASK) != ntype)
1121241Skas 			continue;
1131241Skas 		s += strlen(p->n_name) + 1;
1141241Skas 		if (comma)
1151241Skas 			s++;
1161241Skas 	}
1171241Skas 	if (s == 0)
1181241Skas 		return(NOSTR);
1191241Skas 	s += 2;
1201241Skas 	top = salloc(s);
1211241Skas 	cp = top;
1221241Skas 	for (p = np; p != NIL; p = p->n_flink) {
1231241Skas 		if (ntype && (p->n_type & GMASK) != ntype)
1241241Skas 			continue;
1251241Skas 		cp = copy(p->n_name, cp);
1261241Skas 		if (comma && p->n_flink != NIL)
1271241Skas 			*cp++ = ',';
1281241Skas 		*cp++ = ' ';
1291241Skas 	}
1301241Skas 	*--cp = 0;
1311241Skas 	if (comma && *--cp == ',')
1321241Skas 		*cp = 0;
1331241Skas 	return(top);
1341241Skas }
1351241Skas 
1361241Skas /*
1371241Skas  * Grab a single word (liberal word)
13834800Sedward  * Throw away things between ()'s, and take anything between <>.
1391241Skas  */
1401241Skas char *
yankword(ap,wbuf)1411241Skas yankword(ap, wbuf)
1421241Skas 	char *ap, wbuf[];
1431241Skas {
1441241Skas 	register char *cp, *cp2;
1451241Skas 
14625459Sserge 	cp = ap;
14734800Sedward 	for (;;) {
14834800Sedward 		if (*cp == '\0')
14934800Sedward 			return NOSTR;
1501241Skas 		if (*cp == '(') {
15125459Sserge 			register int nesting = 0;
15225459Sserge 
15325459Sserge 			while (*cp != '\0') {
15425459Sserge 				switch (*cp++) {
15525459Sserge 				case '(':
15625459Sserge 					nesting++;
15725459Sserge 					break;
15825459Sserge 				case ')':
15925459Sserge 					--nesting;
16025459Sserge 					break;
16125459Sserge 				}
16225459Sserge 				if (nesting <= 0)
16325459Sserge 					break;
16425459Sserge 			}
16534800Sedward 		} else if (*cp == ' ' || *cp == '\t' || *cp == ',')
16634800Sedward 			cp++;
16734800Sedward 		else
16834800Sedward 			break;
16934800Sedward 	}
17034800Sedward 	if (*cp ==  '<')
17134800Sedward 		for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
17234800Sedward 			;
17334800Sedward 	else
17434987Sedward 		for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++)
17534800Sedward 			;
1761241Skas 	*cp2 = '\0';
17734800Sedward 	return cp;
1781241Skas }
1791241Skas 
1801241Skas /*
1811241Skas  * For each recipient in the passed name list with a /
1821241Skas  * in the name, append the message to the end of the named file
1831241Skas  * and remove him from the recipient list.
1841241Skas  *
1851241Skas  * Recipients whose name begins with | are piped through the given
1861241Skas  * program and removed.
1871241Skas  */
1881241Skas struct name *
outof(names,fo,hp)1891241Skas outof(names, fo, hp)
1901241Skas 	struct name *names;
1911241Skas 	FILE *fo;
1921241Skas 	struct header *hp;
1931241Skas {
1941241Skas 	register int c;
19531142Sedward 	register struct name *np, *top;
19631142Sedward 	time_t now, time();
19734976Sedward 	char *date, *fname, *ctime();
1981241Skas 	FILE *fout, *fin;
19931142Sedward 	int ispipe;
2001241Skas 	extern char tempEdit[];
2011241Skas 
2021241Skas 	top = names;
2031241Skas 	np = names;
20431144Sedward 	(void) time(&now);
2051241Skas 	date = ctime(&now);
2061241Skas 	while (np != NIL) {
2074365Skurt 		if (!isfileaddr(np->n_name) && np->n_name[0] != '|') {
2081241Skas 			np = np->n_flink;
2091241Skas 			continue;
2101241Skas 		}
2111241Skas 		ispipe = np->n_name[0] == '|';
2121241Skas 		if (ispipe)
2131241Skas 			fname = np->n_name+1;
2141241Skas 		else
2151241Skas 			fname = expand(np->n_name);
2161241Skas 
2171241Skas 		/*
2181241Skas 		 * See if we have copied the complete message out yet.
2191241Skas 		 * If not, do so.
2201241Skas 		 */
2211241Skas 
2221241Skas 		if (image < 0) {
22343865Sedward 			if ((fout = Fopen(tempEdit, "a")) == NULL) {
2241241Skas 				perror(tempEdit);
2251241Skas 				senderr++;
2261241Skas 				goto cant;
2271241Skas 			}
2281241Skas 			image = open(tempEdit, 2);
22931144Sedward 			(void) unlink(tempEdit);
2301241Skas 			if (image < 0) {
2311241Skas 				perror(tempEdit);
2321241Skas 				senderr++;
23343865Sedward 				(void) Fclose(fout);
2341241Skas 				goto cant;
2351241Skas 			}
23656291Sedward 			(void) fcntl(image, F_SETFD, 1);
23743865Sedward 			fprintf(fout, "From %s %s", myname, date);
23843865Sedward 			puthead(hp, fout, GTO|GSUBJECT|GCC|GNL);
23943865Sedward 			while ((c = getc(fo)) != EOF)
24043865Sedward 				(void) putc(c, fout);
24143865Sedward 			rewind(fo);
24243865Sedward 			(void) putc('\n', fout);
24343865Sedward 			(void) fflush(fout);
24443865Sedward 			if (ferror(fout))
24543865Sedward 				perror(tempEdit);
24643865Sedward 			(void) Fclose(fout);
2471241Skas 		}
2481241Skas 
2491241Skas 		/*
2501241Skas 		 * Now either copy "image" to the desired file
2511241Skas 		 * or give it as the standard input to the desired
2521241Skas 		 * program as appropriate.
2531241Skas 		 */
2541241Skas 
2551241Skas 		if (ispipe) {
25634976Sedward 			int pid;
25734976Sedward 			char *shell;
25834976Sedward 
25943865Sedward 			/*
26043865Sedward 			 * XXX
26143865Sedward 			 * We can't really reuse the same image file,
26243865Sedward 			 * because multiple piped recipients will
26343865Sedward 			 * share the same lseek location and trample
26443865Sedward 			 * on one another.
26543865Sedward 			 */
26634963Sedward 			if ((shell = value("SHELL")) == NOSTR)
26737870Sbostic 				shell = _PATH_CSHELL;
26834976Sedward 			pid = start_command(shell, sigmask(SIGHUP)|
26934976Sedward 					sigmask(SIGINT)|sigmask(SIGQUIT),
27034976Sedward 				image, -1, "-c", fname, NOSTR);
27134976Sedward 			if (pid < 0) {
2721241Skas 				senderr++;
2731241Skas 				goto cant;
2741241Skas 			}
27534976Sedward 			free_child(pid);
27634963Sedward 		} else {
27743865Sedward 			int f;
27843865Sedward 			if ((fout = Fopen(fname, "a")) == NULL) {
2791241Skas 				perror(fname);
2801241Skas 				senderr++;
2811241Skas 				goto cant;
2821241Skas 			}
28343865Sedward 			if ((f = dup(image)) < 0) {
28443865Sedward 				perror("dup");
28543865Sedward 				fin = NULL;
28643865Sedward 			} else
28743865Sedward 				fin = Fdopen(f, "r");
2881241Skas 			if (fin == NULL) {
2891241Skas 				fprintf(stderr, "Can't reopen image\n");
29043865Sedward 				(void) Fclose(fout);
2911241Skas 				senderr++;
2921241Skas 				goto cant;
2931241Skas 			}
2941241Skas 			rewind(fin);
2951241Skas 			while ((c = getc(fin)) != EOF)
29631144Sedward 				(void) putc(c, fout);
2971241Skas 			if (ferror(fout))
2981241Skas 				senderr++, perror(fname);
29943865Sedward 			(void) Fclose(fout);
30043865Sedward 			(void) Fclose(fin);
3011241Skas 		}
3021241Skas cant:
3031241Skas 		/*
3041241Skas 		 * In days of old we removed the entry from the
3051241Skas 		 * the list; now for sake of header expansion
3061241Skas 		 * we leave it in and mark it as deleted.
3071241Skas 		 */
3081241Skas 		np->n_type |= GDEL;
3091241Skas 		np = np->n_flink;
3101241Skas 	}
3111241Skas 	if (image >= 0) {
31231144Sedward 		(void) close(image);
3131241Skas 		image = -1;
3141241Skas 	}
3151241Skas 	return(top);
3161241Skas }
3171241Skas 
3181241Skas /*
3194365Skurt  * Determine if the passed address is a local "send to file" address.
3204365Skurt  * If any of the network metacharacters precedes any slashes, it can't
3214365Skurt  * be a filename.  We cheat with .'s to allow path names like ./...
3224365Skurt  */
32354505Sbostic int
isfileaddr(name)3244365Skurt isfileaddr(name)
3254365Skurt 	char *name;
3264365Skurt {
3274365Skurt 	register char *cp;
3284365Skurt 
3295967Skurt 	if (*name == '+')
33034800Sedward 		return 1;
3314365Skurt 	for (cp = name; *cp; cp++) {
33234800Sedward 		if (*cp == '!' || *cp == '%' || *cp == '@')
33334800Sedward 			return 0;
3344365Skurt 		if (*cp == '/')
33534800Sedward 			return 1;
3364365Skurt 	}
33734800Sedward 	return 0;
3384365Skurt }
3394365Skurt 
3404365Skurt /*
3411241Skas  * Map all of the aliased users in the invoker's mailrc
3421241Skas  * file and insert them into the list.
3431241Skas  * Changed after all these months of service to recursively
3441241Skas  * expand names (2/14/80).
3451241Skas  */
3461241Skas 
3471241Skas struct name *
usermap(names)3481241Skas usermap(names)
3491241Skas 	struct name *names;
3501241Skas {
3511241Skas 	register struct name *new, *np, *cp;
3521241Skas 	struct grouphead *gh;
3531241Skas 	register int metoo;
3541241Skas 
3551241Skas 	new = NIL;
3561241Skas 	np = names;
3571241Skas 	metoo = (value("metoo") != NOSTR);
3581241Skas 	while (np != NIL) {
3591241Skas 		if (np->n_name[0] == '\\') {
3601241Skas 			cp = np->n_flink;
3611241Skas 			new = put(new, np);
3621241Skas 			np = cp;
3631241Skas 			continue;
3641241Skas 		}
3651241Skas 		gh = findgroup(np->n_name);
3661241Skas 		cp = np->n_flink;
3671241Skas 		if (gh != NOGRP)
3681241Skas 			new = gexpand(new, gh, metoo, np->n_type);
3691241Skas 		else
3701241Skas 			new = put(new, np);
3711241Skas 		np = cp;
3721241Skas 	}
3731241Skas 	return(new);
3741241Skas }
3751241Skas 
3761241Skas /*
3771241Skas  * Recursively expand a group name.  We limit the expansion to some
3781241Skas  * fixed level to keep things from going haywire.
3791241Skas  * Direct recursion is not expanded for convenience.
3801241Skas  */
3811241Skas 
3821241Skas struct name *
gexpand(nlist,gh,metoo,ntype)3831241Skas gexpand(nlist, gh, metoo, ntype)
3841241Skas 	struct name *nlist;
3851241Skas 	struct grouphead *gh;
38654505Sbostic 	int metoo, ntype;
3871241Skas {
3881241Skas 	struct group *gp;
3891241Skas 	struct grouphead *ngh;
3901241Skas 	struct name *np;
3911241Skas 	static int depth;
3921241Skas 	char *cp;
3931241Skas 
3941241Skas 	if (depth > MAXEXP) {
3951241Skas 		printf("Expanding alias to depth larger than %d\n", MAXEXP);
3961241Skas 		return(nlist);
3971241Skas 	}
3981241Skas 	depth++;
3991241Skas 	for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) {
4001241Skas 		cp = gp->ge_name;
4011241Skas 		if (*cp == '\\')
4021241Skas 			goto quote;
4031241Skas 		if (strcmp(cp, gh->g_name) == 0)
4041241Skas 			goto quote;
4051241Skas 		if ((ngh = findgroup(cp)) != NOGRP) {
4061241Skas 			nlist = gexpand(nlist, ngh, metoo, ntype);
4071241Skas 			continue;
4081241Skas 		}
4091241Skas quote:
41034800Sedward 		np = nalloc(cp, ntype);
4111241Skas 		/*
4121241Skas 		 * At this point should allow to expand
4131241Skas 		 * to self if only person in group
4141241Skas 		 */
4151241Skas 		if (gp == gh->g_list && gp->ge_link == NOGE)
4161241Skas 			goto skip;
4171241Skas 		if (!metoo && strcmp(cp, myname) == 0)
4181241Skas 			np->n_type |= GDEL;
4191241Skas skip:
4201241Skas 		nlist = put(nlist, np);
4211241Skas 	}
4221241Skas 	depth--;
4231241Skas 	return(nlist);
4241241Skas }
4251241Skas 
4261241Skas /*
4271241Skas  * Concatenate the two passed name lists, return the result.
4281241Skas  */
4291241Skas struct name *
cat(n1,n2)4301241Skas cat(n1, n2)
4311241Skas 	struct name *n1, *n2;
4321241Skas {
4331241Skas 	register struct name *tail;
4341241Skas 
4351241Skas 	if (n1 == NIL)
4361241Skas 		return(n2);
4371241Skas 	if (n2 == NIL)
4381241Skas 		return(n1);
4391241Skas 	tail = tailof(n1);
4401241Skas 	tail->n_flink = n2;
4411241Skas 	n2->n_blink = tail;
4421241Skas 	return(n1);
4431241Skas }
4441241Skas 
4451241Skas /*
4461241Skas  * Unpack the name list onto a vector of strings.
4471241Skas  * Return an error if the name list won't fit.
4481241Skas  */
4491241Skas char **
unpack(np)4501241Skas unpack(np)
4511241Skas 	struct name *np;
4521241Skas {
4531241Skas 	register char **ap, **top;
4541241Skas 	register struct name *n;
45510582Sleres 	int t, extra, metoo, verbose;
4561241Skas 
4571241Skas 	n = np;
45834800Sedward 	if ((t = count(n)) == 0)
4591241Skas 		panic("No names to unpack");
4601241Skas 	/*
4611241Skas 	 * Compute the number of extra arguments we will need.
4621241Skas 	 * We need at least two extra -- one for "mail" and one for
4631241Skas 	 * the terminating 0 pointer.  Additional spots may be needed
46434783Sedward 	 * to pass along -f to the host mailer.
4651241Skas 	 */
4661241Skas 	extra = 2;
4671241Skas 	extra++;
4681241Skas 	metoo = value("metoo") != NOSTR;
4691241Skas 	if (metoo)
4701241Skas 		extra++;
47110582Sleres 	verbose = value("verbose") != NOSTR;
47210582Sleres 	if (verbose)
47310582Sleres 		extra++;
47431144Sedward 	top = (char **) salloc((t + extra) * sizeof *top);
4751241Skas 	ap = top;
4761241Skas 	*ap++ = "send-mail";
4771241Skas 	*ap++ = "-i";
4781241Skas 	if (metoo)
4791241Skas 		*ap++ = "-m";
48010582Sleres 	if (verbose)
48110582Sleres 		*ap++ = "-v";
48234976Sedward 	for (; n != NIL; n = n->n_flink)
48334976Sedward 		if ((n->n_type & GDEL) == 0)
48434976Sedward 			*ap++ = n->n_name;
4851241Skas 	*ap = NOSTR;
4861241Skas 	return(top);
4871241Skas }
4881241Skas 
4891241Skas /*
4901241Skas  * Remove all of the duplicates from the passed name list by
4911241Skas  * insertion sorting them, then checking for dups.
4921241Skas  * Return the head of the new list.
4931241Skas  */
4941241Skas struct name *
elide(names)4951241Skas elide(names)
4961241Skas 	struct name *names;
4971241Skas {
4981241Skas 	register struct name *np, *t, *new;
4991241Skas 	struct name *x;
5001241Skas 
5011241Skas 	if (names == NIL)
5021241Skas 		return(NIL);
5031241Skas 	new = names;
5041241Skas 	np = names;
5051241Skas 	np = np->n_flink;
5061241Skas 	if (np != NIL)
5071241Skas 		np->n_blink = NIL;
5081241Skas 	new->n_flink = NIL;
5091241Skas 	while (np != NIL) {
5101241Skas 		t = new;
51134987Sedward 		while (strcasecmp(t->n_name, np->n_name) < 0) {
5121241Skas 			if (t->n_flink == NIL)
5131241Skas 				break;
5141241Skas 			t = t->n_flink;
5151241Skas 		}
5161241Skas 
5171241Skas 		/*
5181241Skas 		 * If we ran out of t's, put the new entry after
5191241Skas 		 * the current value of t.
5201241Skas 		 */
5211241Skas 
52234987Sedward 		if (strcasecmp(t->n_name, np->n_name) < 0) {
5231241Skas 			t->n_flink = np;
5241241Skas 			np->n_blink = t;
5251241Skas 			t = np;
5261241Skas 			np = np->n_flink;
5271241Skas 			t->n_flink = NIL;
5281241Skas 			continue;
5291241Skas 		}
5301241Skas 
5311241Skas 		/*
5321241Skas 		 * Otherwise, put the new entry in front of the
5331241Skas 		 * current t.  If at the front of the list,
5341241Skas 		 * the new guy becomes the new head of the list.
5351241Skas 		 */
5361241Skas 
5371241Skas 		if (t == new) {
5381241Skas 			t = np;
5391241Skas 			np = np->n_flink;
5401241Skas 			t->n_flink = new;
5411241Skas 			new->n_blink = t;
5421241Skas 			t->n_blink = NIL;
5431241Skas 			new = t;
5441241Skas 			continue;
5451241Skas 		}
5461241Skas 
5471241Skas 		/*
5481241Skas 		 * The normal case -- we are inserting into the
5491241Skas 		 * middle of the list.
5501241Skas 		 */
5511241Skas 
5521241Skas 		x = np;
5531241Skas 		np = np->n_flink;
5541241Skas 		x->n_flink = t;
5551241Skas 		x->n_blink = t->n_blink;
5561241Skas 		t->n_blink->n_flink = x;
5571241Skas 		t->n_blink = x;
5581241Skas 	}
5591241Skas 
5601241Skas 	/*
5611241Skas 	 * Now the list headed up by new is sorted.
5621241Skas 	 * Go through it and remove duplicates.
5631241Skas 	 */
5641241Skas 
5651241Skas 	np = new;
5661241Skas 	while (np != NIL) {
5671241Skas 		t = np;
56834987Sedward 		while (t->n_flink != NIL &&
56934987Sedward 		       strcasecmp(np->n_name, t->n_flink->n_name) == 0)
5701241Skas 			t = t->n_flink;
5711241Skas 		if (t == np || t == NIL) {
5721241Skas 			np = np->n_flink;
5731241Skas 			continue;
5741241Skas 		}
5751241Skas 
5761241Skas 		/*
5771241Skas 		 * Now t points to the last entry with the same name
5781241Skas 		 * as np.  Make np point beyond t.
5791241Skas 		 */
5801241Skas 
5811241Skas 		np->n_flink = t->n_flink;
5821241Skas 		if (t->n_flink != NIL)
5831241Skas 			t->n_flink->n_blink = np;
5841241Skas 		np = np->n_flink;
5851241Skas 	}
5861241Skas 	return(new);
5871241Skas }
5881241Skas 
5891241Skas /*
5901241Skas  * Put another node onto a list of names and return
5911241Skas  * the list.
5921241Skas  */
5931241Skas struct name *
put(list,node)5941241Skas put(list, node)
5951241Skas 	struct name *list, *node;
5961241Skas {
5971241Skas 	node->n_flink = list;
5981241Skas 	node->n_blink = NIL;
5991241Skas 	if (list != NIL)
6001241Skas 		list->n_blink = node;
6011241Skas 	return(node);
6021241Skas }
6031241Skas 
6041241Skas /*
60534976Sedward  * Determine the number of undeleted elements in
6061241Skas  * a name list and return it.
6071241Skas  */
60854505Sbostic int
count(np)6091241Skas count(np)
6101241Skas 	register struct name *np;
6111241Skas {
61234800Sedward 	register int c;
6131241Skas 
61434976Sedward 	for (c = 0; np != NIL; np = np->n_flink)
61534976Sedward 		if ((np->n_type & GDEL) == 0)
61634976Sedward 			c++;
61734800Sedward 	return c;
6181241Skas }
6191241Skas 
6201241Skas /*
62134987Sedward  * Delete the given name from a namelist.
6221241Skas  */
6231241Skas struct name *
delname(np,name)62434987Sedward delname(np, name)
6251241Skas 	register struct name *np;
6261241Skas 	char name[];
6271241Skas {
6281241Skas 	register struct name *p;
6291241Skas 
6301241Skas 	for (p = np; p != NIL; p = p->n_flink)
63134987Sedward 		if (strcasecmp(p->n_name, name) == 0) {
6321241Skas 			if (p->n_blink == NIL) {
6331241Skas 				if (p->n_flink != NIL)
6341241Skas 					p->n_flink->n_blink = NIL;
6351241Skas 				np = p->n_flink;
6361241Skas 				continue;
6371241Skas 			}
6381241Skas 			if (p->n_flink == NIL) {
6391241Skas 				if (p->n_blink != NIL)
6401241Skas 					p->n_blink->n_flink = NIL;
6411241Skas 				continue;
6421241Skas 			}
6431241Skas 			p->n_blink->n_flink = p->n_flink;
6441241Skas 			p->n_flink->n_blink = p->n_blink;
6451241Skas 		}
64634987Sedward 	return np;
6471241Skas }
6481241Skas 
6491241Skas /*
6501241Skas  * Pretty print a name list
6511241Skas  * Uncomment it if you need it.
6521241Skas  */
6531241Skas 
65431142Sedward /*
65554505Sbostic void
6561241Skas prettyprint(name)
6571241Skas 	struct name *name;
6581241Skas {
6591241Skas 	register struct name *np;
6601241Skas 
6611241Skas 	np = name;
6621241Skas 	while (np != NIL) {
6631241Skas 		fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
6641241Skas 		np = np->n_flink;
6651241Skas 	}
6661241Skas 	fprintf(stderr, "\n");
6671241Skas }
66831142Sedward */
669