names.c revision 32189
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93"; 361590Srgrimes#endif /* not lint */ 371590Srgrimes 381590Srgrimes/* 391590Srgrimes * Mail -- a mail program 401590Srgrimes * 411590Srgrimes * Handle name lists. 421590Srgrimes */ 431590Srgrimes 441590Srgrimes#include "rcv.h" 451590Srgrimes#include <fcntl.h> 461590Srgrimes#include "extern.h" 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * Allocate a single element of a name list, 501590Srgrimes * initialize its name field to the passed 511590Srgrimes * name and return it. 521590Srgrimes */ 531590Srgrimesstruct name * 541590Srgrimesnalloc(str, ntype) 551590Srgrimes char str[]; 561590Srgrimes int ntype; 571590Srgrimes{ 581590Srgrimes register struct name *np; 591590Srgrimes 601590Srgrimes np = (struct name *) salloc(sizeof *np); 611590Srgrimes np->n_flink = NIL; 621590Srgrimes np->n_blink = NIL; 631590Srgrimes np->n_type = ntype; 641590Srgrimes np->n_name = savestr(str); 651590Srgrimes return(np); 661590Srgrimes} 671590Srgrimes 681590Srgrimes/* 691590Srgrimes * Find the tail of a list and return it. 701590Srgrimes */ 711590Srgrimesstruct name * 721590Srgrimestailof(name) 731590Srgrimes struct name *name; 741590Srgrimes{ 751590Srgrimes register struct name *np; 761590Srgrimes 771590Srgrimes np = name; 781590Srgrimes if (np == NIL) 791590Srgrimes return(NIL); 801590Srgrimes while (np->n_flink != NIL) 811590Srgrimes np = np->n_flink; 821590Srgrimes return(np); 831590Srgrimes} 841590Srgrimes 851590Srgrimes/* 861590Srgrimes * Extract a list of names from a line, 871590Srgrimes * and make a list of names from it. 881590Srgrimes * Return the list or NIL if none found. 891590Srgrimes */ 901590Srgrimesstruct name * 911590Srgrimesextract(line, ntype) 921590Srgrimes char line[]; 931590Srgrimes int ntype; 941590Srgrimes{ 951590Srgrimes register char *cp; 961590Srgrimes register struct name *top, *np, *t; 971590Srgrimes char nbuf[BUFSIZ]; 981590Srgrimes 991590Srgrimes if (line == NOSTR || *line == '\0') 1001590Srgrimes return NIL; 1011590Srgrimes top = NIL; 1021590Srgrimes np = NIL; 1031590Srgrimes cp = line; 1041590Srgrimes while ((cp = yankword(cp, nbuf)) != NOSTR) { 1051590Srgrimes t = nalloc(nbuf, ntype); 1061590Srgrimes if (top == NIL) 1071590Srgrimes top = t; 1081590Srgrimes else 1091590Srgrimes np->n_flink = t; 1101590Srgrimes t->n_blink = np; 1111590Srgrimes np = t; 1121590Srgrimes } 1131590Srgrimes return top; 1141590Srgrimes} 1151590Srgrimes 1161590Srgrimes/* 1171590Srgrimes * Turn a list of names into a string of the same names. 1181590Srgrimes */ 1191590Srgrimeschar * 1201590Srgrimesdetract(np, ntype) 1211590Srgrimes register struct name *np; 1221590Srgrimes int ntype; 1231590Srgrimes{ 1241590Srgrimes register int s; 1251590Srgrimes register char *cp, *top; 1261590Srgrimes register struct name *p; 1271590Srgrimes register int comma; 1281590Srgrimes 1291590Srgrimes comma = ntype & GCOMMA; 1301590Srgrimes if (np == NIL) 1311590Srgrimes return(NOSTR); 1321590Srgrimes ntype &= ~GCOMMA; 1331590Srgrimes s = 0; 1341590Srgrimes if (debug && comma) 1351590Srgrimes fprintf(stderr, "detract asked to insert commas\n"); 1361590Srgrimes for (p = np; p != NIL; p = p->n_flink) { 1371590Srgrimes if (ntype && (p->n_type & GMASK) != ntype) 1381590Srgrimes continue; 1391590Srgrimes s += strlen(p->n_name) + 1; 1401590Srgrimes if (comma) 1411590Srgrimes s++; 1421590Srgrimes } 1431590Srgrimes if (s == 0) 1441590Srgrimes return(NOSTR); 1451590Srgrimes s += 2; 1461590Srgrimes top = salloc(s); 1471590Srgrimes cp = top; 1481590Srgrimes for (p = np; p != NIL; p = p->n_flink) { 1491590Srgrimes if (ntype && (p->n_type & GMASK) != ntype) 1501590Srgrimes continue; 1511590Srgrimes cp = copy(p->n_name, cp); 1521590Srgrimes if (comma && p->n_flink != NIL) 1531590Srgrimes *cp++ = ','; 1541590Srgrimes *cp++ = ' '; 1551590Srgrimes } 1561590Srgrimes *--cp = 0; 1571590Srgrimes if (comma && *--cp == ',') 1581590Srgrimes *cp = 0; 1591590Srgrimes return(top); 1601590Srgrimes} 1611590Srgrimes 1621590Srgrimes/* 1631590Srgrimes * Grab a single word (liberal word) 1641590Srgrimes * Throw away things between ()'s, and take anything between <>. 1651590Srgrimes */ 1661590Srgrimeschar * 1671590Srgrimesyankword(ap, wbuf) 1681590Srgrimes char *ap, wbuf[]; 1691590Srgrimes{ 1701590Srgrimes register char *cp, *cp2; 1711590Srgrimes 1721590Srgrimes cp = ap; 1731590Srgrimes for (;;) { 1741590Srgrimes if (*cp == '\0') 1751590Srgrimes return NOSTR; 1761590Srgrimes if (*cp == '(') { 1771590Srgrimes register int nesting = 0; 1781590Srgrimes 1791590Srgrimes while (*cp != '\0') { 1801590Srgrimes switch (*cp++) { 1811590Srgrimes case '(': 1821590Srgrimes nesting++; 1831590Srgrimes break; 1841590Srgrimes case ')': 1851590Srgrimes --nesting; 1861590Srgrimes break; 1871590Srgrimes } 1881590Srgrimes if (nesting <= 0) 1891590Srgrimes break; 1901590Srgrimes } 1911590Srgrimes } else if (*cp == ' ' || *cp == '\t' || *cp == ',') 1921590Srgrimes cp++; 1931590Srgrimes else 1941590Srgrimes break; 1951590Srgrimes } 1961590Srgrimes if (*cp == '<') 1971590Srgrimes for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';) 1981590Srgrimes ; 1991590Srgrimes else 2001590Srgrimes for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++) 2011590Srgrimes ; 2021590Srgrimes *cp2 = '\0'; 2031590Srgrimes return cp; 2041590Srgrimes} 2051590Srgrimes 2061590Srgrimes/* 2071590Srgrimes * For each recipient in the passed name list with a / 2081590Srgrimes * in the name, append the message to the end of the named file 2091590Srgrimes * and remove him from the recipient list. 2101590Srgrimes * 2111590Srgrimes * Recipients whose name begins with | are piped through the given 2121590Srgrimes * program and removed. 2131590Srgrimes */ 2141590Srgrimesstruct name * 2151590Srgrimesoutof(names, fo, hp) 2161590Srgrimes struct name *names; 2171590Srgrimes FILE *fo; 2181590Srgrimes struct header *hp; 2191590Srgrimes{ 2201590Srgrimes register int c; 2211590Srgrimes register struct name *np, *top; 2221590Srgrimes time_t now, time(); 2231590Srgrimes char *date, *fname, *ctime(); 2241590Srgrimes FILE *fout, *fin; 2251590Srgrimes int ispipe; 2261590Srgrimes extern char tempEdit[]; 2271590Srgrimes 2281590Srgrimes top = names; 2291590Srgrimes np = names; 2301590Srgrimes (void) time(&now); 2311590Srgrimes date = ctime(&now); 2321590Srgrimes while (np != NIL) { 2331590Srgrimes if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { 2341590Srgrimes np = np->n_flink; 2351590Srgrimes continue; 2361590Srgrimes } 2371590Srgrimes ispipe = np->n_name[0] == '|'; 2381590Srgrimes if (ispipe) 2391590Srgrimes fname = np->n_name+1; 2401590Srgrimes else 2411590Srgrimes fname = expand(np->n_name); 2421590Srgrimes 2431590Srgrimes /* 2441590Srgrimes * See if we have copied the complete message out yet. 2451590Srgrimes * If not, do so. 2461590Srgrimes */ 2471590Srgrimes 2481590Srgrimes if (image < 0) { 2491590Srgrimes if ((fout = Fopen(tempEdit, "a")) == NULL) { 2501590Srgrimes perror(tempEdit); 2511590Srgrimes senderr++; 2521590Srgrimes goto cant; 2531590Srgrimes } 2541590Srgrimes image = open(tempEdit, 2); 2551590Srgrimes (void) unlink(tempEdit); 2561590Srgrimes if (image < 0) { 2571590Srgrimes perror(tempEdit); 2581590Srgrimes senderr++; 2591590Srgrimes (void) Fclose(fout); 2601590Srgrimes goto cant; 2611590Srgrimes } 2621590Srgrimes (void) fcntl(image, F_SETFD, 1); 2631590Srgrimes fprintf(fout, "From %s %s", myname, date); 26432189Sjoerg puthead(hp, fout, 26532189Sjoerg GTO|GSUBJECT|GCC|GREPLYTO|GINREPLYTO|GNL); 2661590Srgrimes while ((c = getc(fo)) != EOF) 2671590Srgrimes (void) putc(c, fout); 2681590Srgrimes rewind(fo); 2691590Srgrimes (void) putc('\n', fout); 2701590Srgrimes (void) fflush(fout); 2711590Srgrimes if (ferror(fout)) 2721590Srgrimes perror(tempEdit); 2731590Srgrimes (void) Fclose(fout); 2741590Srgrimes } 2751590Srgrimes 2761590Srgrimes /* 2771590Srgrimes * Now either copy "image" to the desired file 2781590Srgrimes * or give it as the standard input to the desired 2791590Srgrimes * program as appropriate. 2801590Srgrimes */ 2811590Srgrimes 2821590Srgrimes if (ispipe) { 2831590Srgrimes int pid; 2841590Srgrimes char *shell; 2851590Srgrimes 2861590Srgrimes /* 2871590Srgrimes * XXX 2881590Srgrimes * We can't really reuse the same image file, 2891590Srgrimes * because multiple piped recipients will 2901590Srgrimes * share the same lseek location and trample 2911590Srgrimes * on one another. 2921590Srgrimes */ 2931590Srgrimes if ((shell = value("SHELL")) == NOSTR) 2941590Srgrimes shell = _PATH_CSHELL; 2951590Srgrimes pid = start_command(shell, sigmask(SIGHUP)| 2961590Srgrimes sigmask(SIGINT)|sigmask(SIGQUIT), 2971590Srgrimes image, -1, "-c", fname, NOSTR); 2981590Srgrimes if (pid < 0) { 2991590Srgrimes senderr++; 3001590Srgrimes goto cant; 3011590Srgrimes } 3021590Srgrimes free_child(pid); 3031590Srgrimes } else { 3041590Srgrimes int f; 3051590Srgrimes if ((fout = Fopen(fname, "a")) == NULL) { 3061590Srgrimes perror(fname); 3071590Srgrimes senderr++; 3081590Srgrimes goto cant; 3091590Srgrimes } 3101590Srgrimes if ((f = dup(image)) < 0) { 3111590Srgrimes perror("dup"); 3121590Srgrimes fin = NULL; 3131590Srgrimes } else 3141590Srgrimes fin = Fdopen(f, "r"); 3151590Srgrimes if (fin == NULL) { 3161590Srgrimes fprintf(stderr, "Can't reopen image\n"); 3171590Srgrimes (void) Fclose(fout); 3181590Srgrimes senderr++; 3191590Srgrimes goto cant; 3201590Srgrimes } 3211590Srgrimes rewind(fin); 3221590Srgrimes while ((c = getc(fin)) != EOF) 3231590Srgrimes (void) putc(c, fout); 3241590Srgrimes if (ferror(fout)) 3251590Srgrimes senderr++, perror(fname); 3261590Srgrimes (void) Fclose(fout); 3271590Srgrimes (void) Fclose(fin); 3281590Srgrimes } 3291590Srgrimescant: 3301590Srgrimes /* 3311590Srgrimes * In days of old we removed the entry from the 3321590Srgrimes * the list; now for sake of header expansion 3331590Srgrimes * we leave it in and mark it as deleted. 3341590Srgrimes */ 3351590Srgrimes np->n_type |= GDEL; 3361590Srgrimes np = np->n_flink; 3371590Srgrimes } 3381590Srgrimes if (image >= 0) { 3391590Srgrimes (void) close(image); 3401590Srgrimes image = -1; 3411590Srgrimes } 3421590Srgrimes return(top); 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimes/* 3461590Srgrimes * Determine if the passed address is a local "send to file" address. 3471590Srgrimes * If any of the network metacharacters precedes any slashes, it can't 3481590Srgrimes * be a filename. We cheat with .'s to allow path names like ./... 3491590Srgrimes */ 3501590Srgrimesint 3511590Srgrimesisfileaddr(name) 3521590Srgrimes char *name; 3531590Srgrimes{ 3541590Srgrimes register char *cp; 3551590Srgrimes 3561590Srgrimes if (*name == '+') 3571590Srgrimes return 1; 3581590Srgrimes for (cp = name; *cp; cp++) { 3591590Srgrimes if (*cp == '!' || *cp == '%' || *cp == '@') 3601590Srgrimes return 0; 3611590Srgrimes if (*cp == '/') 3621590Srgrimes return 1; 3631590Srgrimes } 3641590Srgrimes return 0; 3651590Srgrimes} 3661590Srgrimes 3671590Srgrimes/* 3681590Srgrimes * Map all of the aliased users in the invoker's mailrc 3691590Srgrimes * file and insert them into the list. 3701590Srgrimes * Changed after all these months of service to recursively 3711590Srgrimes * expand names (2/14/80). 3721590Srgrimes */ 3731590Srgrimes 3741590Srgrimesstruct name * 3751590Srgrimesusermap(names) 3761590Srgrimes struct name *names; 3771590Srgrimes{ 3781590Srgrimes register struct name *new, *np, *cp; 3791590Srgrimes struct grouphead *gh; 3801590Srgrimes register int metoo; 3811590Srgrimes 3821590Srgrimes new = NIL; 3831590Srgrimes np = names; 3841590Srgrimes metoo = (value("metoo") != NOSTR); 3851590Srgrimes while (np != NIL) { 3861590Srgrimes if (np->n_name[0] == '\\') { 3871590Srgrimes cp = np->n_flink; 3881590Srgrimes new = put(new, np); 3891590Srgrimes np = cp; 3901590Srgrimes continue; 3911590Srgrimes } 3921590Srgrimes gh = findgroup(np->n_name); 3931590Srgrimes cp = np->n_flink; 3941590Srgrimes if (gh != NOGRP) 3951590Srgrimes new = gexpand(new, gh, metoo, np->n_type); 3961590Srgrimes else 3971590Srgrimes new = put(new, np); 3981590Srgrimes np = cp; 3991590Srgrimes } 4001590Srgrimes return(new); 4011590Srgrimes} 4021590Srgrimes 4031590Srgrimes/* 4041590Srgrimes * Recursively expand a group name. We limit the expansion to some 4051590Srgrimes * fixed level to keep things from going haywire. 4061590Srgrimes * Direct recursion is not expanded for convenience. 4071590Srgrimes */ 4081590Srgrimes 4091590Srgrimesstruct name * 4101590Srgrimesgexpand(nlist, gh, metoo, ntype) 4111590Srgrimes struct name *nlist; 4121590Srgrimes struct grouphead *gh; 4131590Srgrimes int metoo, ntype; 4141590Srgrimes{ 4151590Srgrimes struct group *gp; 4161590Srgrimes struct grouphead *ngh; 4171590Srgrimes struct name *np; 4181590Srgrimes static int depth; 4191590Srgrimes char *cp; 4201590Srgrimes 4211590Srgrimes if (depth > MAXEXP) { 4221590Srgrimes printf("Expanding alias to depth larger than %d\n", MAXEXP); 4231590Srgrimes return(nlist); 4241590Srgrimes } 4251590Srgrimes depth++; 4261590Srgrimes for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { 4271590Srgrimes cp = gp->ge_name; 4281590Srgrimes if (*cp == '\\') 4291590Srgrimes goto quote; 4301590Srgrimes if (strcmp(cp, gh->g_name) == 0) 4311590Srgrimes goto quote; 4321590Srgrimes if ((ngh = findgroup(cp)) != NOGRP) { 4331590Srgrimes nlist = gexpand(nlist, ngh, metoo, ntype); 4341590Srgrimes continue; 4351590Srgrimes } 4361590Srgrimesquote: 4371590Srgrimes np = nalloc(cp, ntype); 4381590Srgrimes /* 4391590Srgrimes * At this point should allow to expand 4401590Srgrimes * to self if only person in group 4411590Srgrimes */ 4421590Srgrimes if (gp == gh->g_list && gp->ge_link == NOGE) 4431590Srgrimes goto skip; 4441590Srgrimes if (!metoo && strcmp(cp, myname) == 0) 4451590Srgrimes np->n_type |= GDEL; 4461590Srgrimesskip: 4471590Srgrimes nlist = put(nlist, np); 4481590Srgrimes } 4491590Srgrimes depth--; 4501590Srgrimes return(nlist); 4511590Srgrimes} 4521590Srgrimes 4531590Srgrimes/* 4541590Srgrimes * Concatenate the two passed name lists, return the result. 4551590Srgrimes */ 4561590Srgrimesstruct name * 4571590Srgrimescat(n1, n2) 4581590Srgrimes struct name *n1, *n2; 4591590Srgrimes{ 4601590Srgrimes register struct name *tail; 4611590Srgrimes 4621590Srgrimes if (n1 == NIL) 4631590Srgrimes return(n2); 4641590Srgrimes if (n2 == NIL) 4651590Srgrimes return(n1); 4661590Srgrimes tail = tailof(n1); 4671590Srgrimes tail->n_flink = n2; 4681590Srgrimes n2->n_blink = tail; 4691590Srgrimes return(n1); 4701590Srgrimes} 4711590Srgrimes 4721590Srgrimes/* 4731590Srgrimes * Unpack the name list onto a vector of strings. 4741590Srgrimes * Return an error if the name list won't fit. 4751590Srgrimes */ 4761590Srgrimeschar ** 4771590Srgrimesunpack(np) 4781590Srgrimes struct name *np; 4791590Srgrimes{ 4801590Srgrimes register char **ap, **top; 4811590Srgrimes register struct name *n; 4821590Srgrimes int t, extra, metoo, verbose; 4831590Srgrimes 4841590Srgrimes n = np; 4851590Srgrimes if ((t = count(n)) == 0) 4861590Srgrimes panic("No names to unpack"); 4871590Srgrimes /* 4881590Srgrimes * Compute the number of extra arguments we will need. 4891590Srgrimes * We need at least two extra -- one for "mail" and one for 4901590Srgrimes * the terminating 0 pointer. Additional spots may be needed 4911590Srgrimes * to pass along -f to the host mailer. 4921590Srgrimes */ 4931590Srgrimes extra = 2; 4941590Srgrimes extra++; 4951590Srgrimes metoo = value("metoo") != NOSTR; 4961590Srgrimes if (metoo) 4971590Srgrimes extra++; 4981590Srgrimes verbose = value("verbose") != NOSTR; 4991590Srgrimes if (verbose) 5001590Srgrimes extra++; 5011590Srgrimes top = (char **) salloc((t + extra) * sizeof *top); 5021590Srgrimes ap = top; 5031590Srgrimes *ap++ = "send-mail"; 5041590Srgrimes *ap++ = "-i"; 5051590Srgrimes if (metoo) 5061590Srgrimes *ap++ = "-m"; 5071590Srgrimes if (verbose) 5081590Srgrimes *ap++ = "-v"; 5091590Srgrimes for (; n != NIL; n = n->n_flink) 5101590Srgrimes if ((n->n_type & GDEL) == 0) 5111590Srgrimes *ap++ = n->n_name; 5121590Srgrimes *ap = NOSTR; 5131590Srgrimes return(top); 5141590Srgrimes} 5151590Srgrimes 5161590Srgrimes/* 5171590Srgrimes * Remove all of the duplicates from the passed name list by 5181590Srgrimes * insertion sorting them, then checking for dups. 5191590Srgrimes * Return the head of the new list. 5201590Srgrimes */ 5211590Srgrimesstruct name * 5221590Srgrimeselide(names) 5231590Srgrimes struct name *names; 5241590Srgrimes{ 5251590Srgrimes register struct name *np, *t, *new; 5261590Srgrimes struct name *x; 5271590Srgrimes 5281590Srgrimes if (names == NIL) 5291590Srgrimes return(NIL); 5301590Srgrimes new = names; 5311590Srgrimes np = names; 5321590Srgrimes np = np->n_flink; 5331590Srgrimes if (np != NIL) 5341590Srgrimes np->n_blink = NIL; 5351590Srgrimes new->n_flink = NIL; 5361590Srgrimes while (np != NIL) { 5371590Srgrimes t = new; 5381590Srgrimes while (strcasecmp(t->n_name, np->n_name) < 0) { 5391590Srgrimes if (t->n_flink == NIL) 5401590Srgrimes break; 5411590Srgrimes t = t->n_flink; 5421590Srgrimes } 5431590Srgrimes 5441590Srgrimes /* 5451590Srgrimes * If we ran out of t's, put the new entry after 5461590Srgrimes * the current value of t. 5471590Srgrimes */ 5481590Srgrimes 5491590Srgrimes if (strcasecmp(t->n_name, np->n_name) < 0) { 5501590Srgrimes t->n_flink = np; 5511590Srgrimes np->n_blink = t; 5521590Srgrimes t = np; 5531590Srgrimes np = np->n_flink; 5541590Srgrimes t->n_flink = NIL; 5551590Srgrimes continue; 5561590Srgrimes } 5571590Srgrimes 5581590Srgrimes /* 5591590Srgrimes * Otherwise, put the new entry in front of the 5601590Srgrimes * current t. If at the front of the list, 5611590Srgrimes * the new guy becomes the new head of the list. 5621590Srgrimes */ 5631590Srgrimes 5641590Srgrimes if (t == new) { 5651590Srgrimes t = np; 5661590Srgrimes np = np->n_flink; 5671590Srgrimes t->n_flink = new; 5681590Srgrimes new->n_blink = t; 5691590Srgrimes t->n_blink = NIL; 5701590Srgrimes new = t; 5711590Srgrimes continue; 5721590Srgrimes } 5731590Srgrimes 5741590Srgrimes /* 5751590Srgrimes * The normal case -- we are inserting into the 5761590Srgrimes * middle of the list. 5771590Srgrimes */ 5781590Srgrimes 5791590Srgrimes x = np; 5801590Srgrimes np = np->n_flink; 5811590Srgrimes x->n_flink = t; 5821590Srgrimes x->n_blink = t->n_blink; 5831590Srgrimes t->n_blink->n_flink = x; 5841590Srgrimes t->n_blink = x; 5851590Srgrimes } 5861590Srgrimes 5871590Srgrimes /* 5881590Srgrimes * Now the list headed up by new is sorted. 5891590Srgrimes * Go through it and remove duplicates. 5901590Srgrimes */ 5911590Srgrimes 5921590Srgrimes np = new; 5931590Srgrimes while (np != NIL) { 5941590Srgrimes t = np; 5951590Srgrimes while (t->n_flink != NIL && 5961590Srgrimes strcasecmp(np->n_name, t->n_flink->n_name) == 0) 5971590Srgrimes t = t->n_flink; 5981590Srgrimes if (t == np || t == NIL) { 5991590Srgrimes np = np->n_flink; 6001590Srgrimes continue; 6011590Srgrimes } 6028874Srgrimes 6031590Srgrimes /* 6041590Srgrimes * Now t points to the last entry with the same name 6051590Srgrimes * as np. Make np point beyond t. 6061590Srgrimes */ 6071590Srgrimes 6081590Srgrimes np->n_flink = t->n_flink; 6091590Srgrimes if (t->n_flink != NIL) 6101590Srgrimes t->n_flink->n_blink = np; 6111590Srgrimes np = np->n_flink; 6121590Srgrimes } 6131590Srgrimes return(new); 6141590Srgrimes} 6151590Srgrimes 6161590Srgrimes/* 6171590Srgrimes * Put another node onto a list of names and return 6181590Srgrimes * the list. 6191590Srgrimes */ 6201590Srgrimesstruct name * 6211590Srgrimesput(list, node) 6221590Srgrimes struct name *list, *node; 6231590Srgrimes{ 6241590Srgrimes node->n_flink = list; 6251590Srgrimes node->n_blink = NIL; 6261590Srgrimes if (list != NIL) 6271590Srgrimes list->n_blink = node; 6281590Srgrimes return(node); 6291590Srgrimes} 6301590Srgrimes 6311590Srgrimes/* 6321590Srgrimes * Determine the number of undeleted elements in 6331590Srgrimes * a name list and return it. 6341590Srgrimes */ 6351590Srgrimesint 6361590Srgrimescount(np) 6371590Srgrimes register struct name *np; 6381590Srgrimes{ 6391590Srgrimes register int c; 6401590Srgrimes 6411590Srgrimes for (c = 0; np != NIL; np = np->n_flink) 6421590Srgrimes if ((np->n_type & GDEL) == 0) 6431590Srgrimes c++; 6441590Srgrimes return c; 6451590Srgrimes} 6461590Srgrimes 6471590Srgrimes/* 6481590Srgrimes * Delete the given name from a namelist. 6491590Srgrimes */ 6501590Srgrimesstruct name * 6511590Srgrimesdelname(np, name) 6521590Srgrimes register struct name *np; 6531590Srgrimes char name[]; 6541590Srgrimes{ 6551590Srgrimes register struct name *p; 6561590Srgrimes 6571590Srgrimes for (p = np; p != NIL; p = p->n_flink) 6581590Srgrimes if (strcasecmp(p->n_name, name) == 0) { 6591590Srgrimes if (p->n_blink == NIL) { 6601590Srgrimes if (p->n_flink != NIL) 6611590Srgrimes p->n_flink->n_blink = NIL; 6621590Srgrimes np = p->n_flink; 6631590Srgrimes continue; 6641590Srgrimes } 6651590Srgrimes if (p->n_flink == NIL) { 6661590Srgrimes if (p->n_blink != NIL) 6671590Srgrimes p->n_blink->n_flink = NIL; 6681590Srgrimes continue; 6691590Srgrimes } 6701590Srgrimes p->n_blink->n_flink = p->n_flink; 6711590Srgrimes p->n_flink->n_blink = p->n_blink; 6721590Srgrimes } 6731590Srgrimes return np; 6741590Srgrimes} 6751590Srgrimes 6761590Srgrimes/* 6771590Srgrimes * Pretty print a name list 6781590Srgrimes * Uncomment it if you need it. 6791590Srgrimes */ 6801590Srgrimes 6811590Srgrimes/* 6821590Srgrimesvoid 6831590Srgrimesprettyprint(name) 6841590Srgrimes struct name *name; 6851590Srgrimes{ 6861590Srgrimes register struct name *np; 6871590Srgrimes 6881590Srgrimes np = name; 6891590Srgrimes while (np != NIL) { 6901590Srgrimes fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); 6911590Srgrimes np = np->n_flink; 6921590Srgrimes } 6931590Srgrimes fprintf(stderr, "\n"); 6941590Srgrimes} 6951590Srgrimes*/ 696