names.c revision 8874
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); 2641590Srgrimes puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); 2651590Srgrimes while ((c = getc(fo)) != EOF) 2661590Srgrimes (void) putc(c, fout); 2671590Srgrimes rewind(fo); 2681590Srgrimes (void) putc('\n', fout); 2691590Srgrimes (void) fflush(fout); 2701590Srgrimes if (ferror(fout)) 2711590Srgrimes perror(tempEdit); 2721590Srgrimes (void) Fclose(fout); 2731590Srgrimes } 2741590Srgrimes 2751590Srgrimes /* 2761590Srgrimes * Now either copy "image" to the desired file 2771590Srgrimes * or give it as the standard input to the desired 2781590Srgrimes * program as appropriate. 2791590Srgrimes */ 2801590Srgrimes 2811590Srgrimes if (ispipe) { 2821590Srgrimes int pid; 2831590Srgrimes char *shell; 2841590Srgrimes 2851590Srgrimes /* 2861590Srgrimes * XXX 2871590Srgrimes * We can't really reuse the same image file, 2881590Srgrimes * because multiple piped recipients will 2891590Srgrimes * share the same lseek location and trample 2901590Srgrimes * on one another. 2911590Srgrimes */ 2921590Srgrimes if ((shell = value("SHELL")) == NOSTR) 2931590Srgrimes shell = _PATH_CSHELL; 2941590Srgrimes pid = start_command(shell, sigmask(SIGHUP)| 2951590Srgrimes sigmask(SIGINT)|sigmask(SIGQUIT), 2961590Srgrimes image, -1, "-c", fname, NOSTR); 2971590Srgrimes if (pid < 0) { 2981590Srgrimes senderr++; 2991590Srgrimes goto cant; 3001590Srgrimes } 3011590Srgrimes free_child(pid); 3021590Srgrimes } else { 3031590Srgrimes int f; 3041590Srgrimes if ((fout = Fopen(fname, "a")) == NULL) { 3051590Srgrimes perror(fname); 3061590Srgrimes senderr++; 3071590Srgrimes goto cant; 3081590Srgrimes } 3091590Srgrimes if ((f = dup(image)) < 0) { 3101590Srgrimes perror("dup"); 3111590Srgrimes fin = NULL; 3121590Srgrimes } else 3131590Srgrimes fin = Fdopen(f, "r"); 3141590Srgrimes if (fin == NULL) { 3151590Srgrimes fprintf(stderr, "Can't reopen image\n"); 3161590Srgrimes (void) Fclose(fout); 3171590Srgrimes senderr++; 3181590Srgrimes goto cant; 3191590Srgrimes } 3201590Srgrimes rewind(fin); 3211590Srgrimes while ((c = getc(fin)) != EOF) 3221590Srgrimes (void) putc(c, fout); 3231590Srgrimes if (ferror(fout)) 3241590Srgrimes senderr++, perror(fname); 3251590Srgrimes (void) Fclose(fout); 3261590Srgrimes (void) Fclose(fin); 3271590Srgrimes } 3281590Srgrimescant: 3291590Srgrimes /* 3301590Srgrimes * In days of old we removed the entry from the 3311590Srgrimes * the list; now for sake of header expansion 3321590Srgrimes * we leave it in and mark it as deleted. 3331590Srgrimes */ 3341590Srgrimes np->n_type |= GDEL; 3351590Srgrimes np = np->n_flink; 3361590Srgrimes } 3371590Srgrimes if (image >= 0) { 3381590Srgrimes (void) close(image); 3391590Srgrimes image = -1; 3401590Srgrimes } 3411590Srgrimes return(top); 3421590Srgrimes} 3431590Srgrimes 3441590Srgrimes/* 3451590Srgrimes * Determine if the passed address is a local "send to file" address. 3461590Srgrimes * If any of the network metacharacters precedes any slashes, it can't 3471590Srgrimes * be a filename. We cheat with .'s to allow path names like ./... 3481590Srgrimes */ 3491590Srgrimesint 3501590Srgrimesisfileaddr(name) 3511590Srgrimes char *name; 3521590Srgrimes{ 3531590Srgrimes register char *cp; 3541590Srgrimes 3551590Srgrimes if (*name == '+') 3561590Srgrimes return 1; 3571590Srgrimes for (cp = name; *cp; cp++) { 3581590Srgrimes if (*cp == '!' || *cp == '%' || *cp == '@') 3591590Srgrimes return 0; 3601590Srgrimes if (*cp == '/') 3611590Srgrimes return 1; 3621590Srgrimes } 3631590Srgrimes return 0; 3641590Srgrimes} 3651590Srgrimes 3661590Srgrimes/* 3671590Srgrimes * Map all of the aliased users in the invoker's mailrc 3681590Srgrimes * file and insert them into the list. 3691590Srgrimes * Changed after all these months of service to recursively 3701590Srgrimes * expand names (2/14/80). 3711590Srgrimes */ 3721590Srgrimes 3731590Srgrimesstruct name * 3741590Srgrimesusermap(names) 3751590Srgrimes struct name *names; 3761590Srgrimes{ 3771590Srgrimes register struct name *new, *np, *cp; 3781590Srgrimes struct grouphead *gh; 3791590Srgrimes register int metoo; 3801590Srgrimes 3811590Srgrimes new = NIL; 3821590Srgrimes np = names; 3831590Srgrimes metoo = (value("metoo") != NOSTR); 3841590Srgrimes while (np != NIL) { 3851590Srgrimes if (np->n_name[0] == '\\') { 3861590Srgrimes cp = np->n_flink; 3871590Srgrimes new = put(new, np); 3881590Srgrimes np = cp; 3891590Srgrimes continue; 3901590Srgrimes } 3911590Srgrimes gh = findgroup(np->n_name); 3921590Srgrimes cp = np->n_flink; 3931590Srgrimes if (gh != NOGRP) 3941590Srgrimes new = gexpand(new, gh, metoo, np->n_type); 3951590Srgrimes else 3961590Srgrimes new = put(new, np); 3971590Srgrimes np = cp; 3981590Srgrimes } 3991590Srgrimes return(new); 4001590Srgrimes} 4011590Srgrimes 4021590Srgrimes/* 4031590Srgrimes * Recursively expand a group name. We limit the expansion to some 4041590Srgrimes * fixed level to keep things from going haywire. 4051590Srgrimes * Direct recursion is not expanded for convenience. 4061590Srgrimes */ 4071590Srgrimes 4081590Srgrimesstruct name * 4091590Srgrimesgexpand(nlist, gh, metoo, ntype) 4101590Srgrimes struct name *nlist; 4111590Srgrimes struct grouphead *gh; 4121590Srgrimes int metoo, ntype; 4131590Srgrimes{ 4141590Srgrimes struct group *gp; 4151590Srgrimes struct grouphead *ngh; 4161590Srgrimes struct name *np; 4171590Srgrimes static int depth; 4181590Srgrimes char *cp; 4191590Srgrimes 4201590Srgrimes if (depth > MAXEXP) { 4211590Srgrimes printf("Expanding alias to depth larger than %d\n", MAXEXP); 4221590Srgrimes return(nlist); 4231590Srgrimes } 4241590Srgrimes depth++; 4251590Srgrimes for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { 4261590Srgrimes cp = gp->ge_name; 4271590Srgrimes if (*cp == '\\') 4281590Srgrimes goto quote; 4291590Srgrimes if (strcmp(cp, gh->g_name) == 0) 4301590Srgrimes goto quote; 4311590Srgrimes if ((ngh = findgroup(cp)) != NOGRP) { 4321590Srgrimes nlist = gexpand(nlist, ngh, metoo, ntype); 4331590Srgrimes continue; 4341590Srgrimes } 4351590Srgrimesquote: 4361590Srgrimes np = nalloc(cp, ntype); 4371590Srgrimes /* 4381590Srgrimes * At this point should allow to expand 4391590Srgrimes * to self if only person in group 4401590Srgrimes */ 4411590Srgrimes if (gp == gh->g_list && gp->ge_link == NOGE) 4421590Srgrimes goto skip; 4431590Srgrimes if (!metoo && strcmp(cp, myname) == 0) 4441590Srgrimes np->n_type |= GDEL; 4451590Srgrimesskip: 4461590Srgrimes nlist = put(nlist, np); 4471590Srgrimes } 4481590Srgrimes depth--; 4491590Srgrimes return(nlist); 4501590Srgrimes} 4511590Srgrimes 4521590Srgrimes/* 4531590Srgrimes * Concatenate the two passed name lists, return the result. 4541590Srgrimes */ 4551590Srgrimesstruct name * 4561590Srgrimescat(n1, n2) 4571590Srgrimes struct name *n1, *n2; 4581590Srgrimes{ 4591590Srgrimes register struct name *tail; 4601590Srgrimes 4611590Srgrimes if (n1 == NIL) 4621590Srgrimes return(n2); 4631590Srgrimes if (n2 == NIL) 4641590Srgrimes return(n1); 4651590Srgrimes tail = tailof(n1); 4661590Srgrimes tail->n_flink = n2; 4671590Srgrimes n2->n_blink = tail; 4681590Srgrimes return(n1); 4691590Srgrimes} 4701590Srgrimes 4711590Srgrimes/* 4721590Srgrimes * Unpack the name list onto a vector of strings. 4731590Srgrimes * Return an error if the name list won't fit. 4741590Srgrimes */ 4751590Srgrimeschar ** 4761590Srgrimesunpack(np) 4771590Srgrimes struct name *np; 4781590Srgrimes{ 4791590Srgrimes register char **ap, **top; 4801590Srgrimes register struct name *n; 4811590Srgrimes int t, extra, metoo, verbose; 4821590Srgrimes 4831590Srgrimes n = np; 4841590Srgrimes if ((t = count(n)) == 0) 4851590Srgrimes panic("No names to unpack"); 4861590Srgrimes /* 4871590Srgrimes * Compute the number of extra arguments we will need. 4881590Srgrimes * We need at least two extra -- one for "mail" and one for 4891590Srgrimes * the terminating 0 pointer. Additional spots may be needed 4901590Srgrimes * to pass along -f to the host mailer. 4911590Srgrimes */ 4921590Srgrimes extra = 2; 4931590Srgrimes extra++; 4941590Srgrimes metoo = value("metoo") != NOSTR; 4951590Srgrimes if (metoo) 4961590Srgrimes extra++; 4971590Srgrimes verbose = value("verbose") != NOSTR; 4981590Srgrimes if (verbose) 4991590Srgrimes extra++; 5001590Srgrimes top = (char **) salloc((t + extra) * sizeof *top); 5011590Srgrimes ap = top; 5021590Srgrimes *ap++ = "send-mail"; 5031590Srgrimes *ap++ = "-i"; 5041590Srgrimes if (metoo) 5051590Srgrimes *ap++ = "-m"; 5061590Srgrimes if (verbose) 5071590Srgrimes *ap++ = "-v"; 5081590Srgrimes for (; n != NIL; n = n->n_flink) 5091590Srgrimes if ((n->n_type & GDEL) == 0) 5101590Srgrimes *ap++ = n->n_name; 5111590Srgrimes *ap = NOSTR; 5121590Srgrimes return(top); 5131590Srgrimes} 5141590Srgrimes 5151590Srgrimes/* 5161590Srgrimes * Remove all of the duplicates from the passed name list by 5171590Srgrimes * insertion sorting them, then checking for dups. 5181590Srgrimes * Return the head of the new list. 5191590Srgrimes */ 5201590Srgrimesstruct name * 5211590Srgrimeselide(names) 5221590Srgrimes struct name *names; 5231590Srgrimes{ 5241590Srgrimes register struct name *np, *t, *new; 5251590Srgrimes struct name *x; 5261590Srgrimes 5271590Srgrimes if (names == NIL) 5281590Srgrimes return(NIL); 5291590Srgrimes new = names; 5301590Srgrimes np = names; 5311590Srgrimes np = np->n_flink; 5321590Srgrimes if (np != NIL) 5331590Srgrimes np->n_blink = NIL; 5341590Srgrimes new->n_flink = NIL; 5351590Srgrimes while (np != NIL) { 5361590Srgrimes t = new; 5371590Srgrimes while (strcasecmp(t->n_name, np->n_name) < 0) { 5381590Srgrimes if (t->n_flink == NIL) 5391590Srgrimes break; 5401590Srgrimes t = t->n_flink; 5411590Srgrimes } 5421590Srgrimes 5431590Srgrimes /* 5441590Srgrimes * If we ran out of t's, put the new entry after 5451590Srgrimes * the current value of t. 5461590Srgrimes */ 5471590Srgrimes 5481590Srgrimes if (strcasecmp(t->n_name, np->n_name) < 0) { 5491590Srgrimes t->n_flink = np; 5501590Srgrimes np->n_blink = t; 5511590Srgrimes t = np; 5521590Srgrimes np = np->n_flink; 5531590Srgrimes t->n_flink = NIL; 5541590Srgrimes continue; 5551590Srgrimes } 5561590Srgrimes 5571590Srgrimes /* 5581590Srgrimes * Otherwise, put the new entry in front of the 5591590Srgrimes * current t. If at the front of the list, 5601590Srgrimes * the new guy becomes the new head of the list. 5611590Srgrimes */ 5621590Srgrimes 5631590Srgrimes if (t == new) { 5641590Srgrimes t = np; 5651590Srgrimes np = np->n_flink; 5661590Srgrimes t->n_flink = new; 5671590Srgrimes new->n_blink = t; 5681590Srgrimes t->n_blink = NIL; 5691590Srgrimes new = t; 5701590Srgrimes continue; 5711590Srgrimes } 5721590Srgrimes 5731590Srgrimes /* 5741590Srgrimes * The normal case -- we are inserting into the 5751590Srgrimes * middle of the list. 5761590Srgrimes */ 5771590Srgrimes 5781590Srgrimes x = np; 5791590Srgrimes np = np->n_flink; 5801590Srgrimes x->n_flink = t; 5811590Srgrimes x->n_blink = t->n_blink; 5821590Srgrimes t->n_blink->n_flink = x; 5831590Srgrimes t->n_blink = x; 5841590Srgrimes } 5851590Srgrimes 5861590Srgrimes /* 5871590Srgrimes * Now the list headed up by new is sorted. 5881590Srgrimes * Go through it and remove duplicates. 5891590Srgrimes */ 5901590Srgrimes 5911590Srgrimes np = new; 5921590Srgrimes while (np != NIL) { 5931590Srgrimes t = np; 5941590Srgrimes while (t->n_flink != NIL && 5951590Srgrimes strcasecmp(np->n_name, t->n_flink->n_name) == 0) 5961590Srgrimes t = t->n_flink; 5971590Srgrimes if (t == np || t == NIL) { 5981590Srgrimes np = np->n_flink; 5991590Srgrimes continue; 6001590Srgrimes } 6018874Srgrimes 6021590Srgrimes /* 6031590Srgrimes * Now t points to the last entry with the same name 6041590Srgrimes * as np. Make np point beyond t. 6051590Srgrimes */ 6061590Srgrimes 6071590Srgrimes np->n_flink = t->n_flink; 6081590Srgrimes if (t->n_flink != NIL) 6091590Srgrimes t->n_flink->n_blink = np; 6101590Srgrimes np = np->n_flink; 6111590Srgrimes } 6121590Srgrimes return(new); 6131590Srgrimes} 6141590Srgrimes 6151590Srgrimes/* 6161590Srgrimes * Put another node onto a list of names and return 6171590Srgrimes * the list. 6181590Srgrimes */ 6191590Srgrimesstruct name * 6201590Srgrimesput(list, node) 6211590Srgrimes struct name *list, *node; 6221590Srgrimes{ 6231590Srgrimes node->n_flink = list; 6241590Srgrimes node->n_blink = NIL; 6251590Srgrimes if (list != NIL) 6261590Srgrimes list->n_blink = node; 6271590Srgrimes return(node); 6281590Srgrimes} 6291590Srgrimes 6301590Srgrimes/* 6311590Srgrimes * Determine the number of undeleted elements in 6321590Srgrimes * a name list and return it. 6331590Srgrimes */ 6341590Srgrimesint 6351590Srgrimescount(np) 6361590Srgrimes register struct name *np; 6371590Srgrimes{ 6381590Srgrimes register int c; 6391590Srgrimes 6401590Srgrimes for (c = 0; np != NIL; np = np->n_flink) 6411590Srgrimes if ((np->n_type & GDEL) == 0) 6421590Srgrimes c++; 6431590Srgrimes return c; 6441590Srgrimes} 6451590Srgrimes 6461590Srgrimes/* 6471590Srgrimes * Delete the given name from a namelist. 6481590Srgrimes */ 6491590Srgrimesstruct name * 6501590Srgrimesdelname(np, name) 6511590Srgrimes register struct name *np; 6521590Srgrimes char name[]; 6531590Srgrimes{ 6541590Srgrimes register struct name *p; 6551590Srgrimes 6561590Srgrimes for (p = np; p != NIL; p = p->n_flink) 6571590Srgrimes if (strcasecmp(p->n_name, name) == 0) { 6581590Srgrimes if (p->n_blink == NIL) { 6591590Srgrimes if (p->n_flink != NIL) 6601590Srgrimes p->n_flink->n_blink = NIL; 6611590Srgrimes np = p->n_flink; 6621590Srgrimes continue; 6631590Srgrimes } 6641590Srgrimes if (p->n_flink == NIL) { 6651590Srgrimes if (p->n_blink != NIL) 6661590Srgrimes p->n_blink->n_flink = NIL; 6671590Srgrimes continue; 6681590Srgrimes } 6691590Srgrimes p->n_blink->n_flink = p->n_flink; 6701590Srgrimes p->n_flink->n_blink = p->n_blink; 6711590Srgrimes } 6721590Srgrimes return np; 6731590Srgrimes} 6741590Srgrimes 6751590Srgrimes/* 6761590Srgrimes * Pretty print a name list 6771590Srgrimes * Uncomment it if you need it. 6781590Srgrimes */ 6791590Srgrimes 6801590Srgrimes/* 6811590Srgrimesvoid 6821590Srgrimesprettyprint(name) 6831590Srgrimes struct name *name; 6841590Srgrimes{ 6851590Srgrimes register struct name *np; 6861590Srgrimes 6871590Srgrimes np = name; 6881590Srgrimes while (np != NIL) { 6891590Srgrimes fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); 6901590Srgrimes np = np->n_flink; 6911590Srgrimes } 6921590Srgrimes fprintf(stderr, "\n"); 6931590Srgrimes} 6941590Srgrimes*/ 695