xref: /csrg-svn/usr.bin/mail/aux.c (revision 38078)
122444Sdist /*
222444Sdist  * Copyright (c) 1980 Regents of the University of California.
333499Sbostic  * All rights reserved.
433499Sbostic  *
533499Sbostic  * Redistribution and use in source and binary forms are permitted
634905Sbostic  * provided that the above copyright notice and this paragraph are
734905Sbostic  * duplicated in all such forms and that any documentation,
834905Sbostic  * advertising materials, and other materials related to such
934905Sbostic  * distribution and use acknowledge that the software was developed
1034905Sbostic  * by the University of California, Berkeley.  The name of the
1134905Sbostic  * University may not be used to endorse or promote products derived
1234905Sbostic  * from this software without specific prior written permission.
1334905Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434905Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534905Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622444Sdist  */
1722444Sdist 
1834905Sbostic #ifndef lint
19*38078Sbostic static char sccsid[] = "@(#)aux.c	5.17 (Berkeley) 05/19/89";
2034905Sbostic #endif /* not lint */
211219Skas 
221219Skas #include "rcv.h"
231219Skas #include <sys/stat.h>
24*38078Sbostic #include <sys/time.h>
251219Skas 
261219Skas /*
271219Skas  * Mail -- a mail program
281219Skas  *
291219Skas  * Auxiliary functions.
301219Skas  */
311219Skas 
321219Skas /*
331219Skas  * Return a pointer to a dynamic copy of the argument.
341219Skas  */
351219Skas char *
361219Skas savestr(str)
371219Skas 	char *str;
381219Skas {
3934987Sedward 	char *new;
4034987Sedward 	int size = strlen(str) + 1;
411219Skas 
4234987Sedward 	if ((new = salloc(size)) != NOSTR)
4334987Sedward 		bcopy(str, new, size);
4434987Sedward 	return new;
451219Skas }
461219Skas 
471219Skas /*
481219Skas  * Announce a fatal error and die.
491219Skas  */
501219Skas 
5131142Sedward /*VARARGS1*/
5231142Sedward panic(fmt, a, b)
5331142Sedward 	char *fmt;
541219Skas {
5531142Sedward 	fprintf(stderr, "panic: ");
5631142Sedward 	fprintf(stderr, fmt, a, b);
5731142Sedward 	putc('\n', stderr);
581219Skas 	exit(1);
591219Skas }
601219Skas 
611219Skas /*
621219Skas  * Touch the named message by setting its MTOUCH flag.
631219Skas  * Touched messages have the effect of not being sent
641219Skas  * back to the system mailbox on exit.
651219Skas  */
6634987Sedward touch(mp)
6734987Sedward 	register struct message *mp;
681219Skas {
691479Skas 
701479Skas 	mp->m_flag |= MTOUCH;
711479Skas 	if ((mp->m_flag & MREAD) == 0)
721479Skas 		mp->m_flag |= MREAD|MSTATUS;
731219Skas }
741219Skas 
751219Skas /*
761219Skas  * Test to see if the passed file name is a directory.
771219Skas  * Return true if it is.
781219Skas  */
791219Skas isdir(name)
801219Skas 	char name[];
811219Skas {
821219Skas 	struct stat sbuf;
831219Skas 
841219Skas 	if (stat(name, &sbuf) < 0)
851219Skas 		return(0);
861219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
871219Skas }
881219Skas 
891219Skas /*
901219Skas  * Count the number of arguments in the given string raw list.
911219Skas  */
921219Skas argcount(argv)
931219Skas 	char **argv;
941219Skas {
951219Skas 	register char **ap;
961219Skas 
9731142Sedward 	for (ap = argv; *ap++ != NOSTR;)
981219Skas 		;
9931142Sedward 	return ap - argv - 1;
1001219Skas }
1011219Skas 
1021219Skas /*
1031219Skas  * Return the desired header line from the passed message
1041219Skas  * pointer (or NOSTR if the desired header field is not available).
1051219Skas  */
1061219Skas char *
1071219Skas hfield(field, mp)
1081219Skas 	char field[];
1091219Skas 	struct message *mp;
1101219Skas {
1111219Skas 	register FILE *ibuf;
1121219Skas 	char linebuf[LINESIZE];
1131219Skas 	register int lc;
11431142Sedward 	register char *hfield;
11531142Sedward 	char *colon;
1161219Skas 
1171219Skas 	ibuf = setinput(mp);
11831142Sedward 	if ((lc = mp->m_lines - 1) < 0)
11931142Sedward 		return NOSTR;
12036478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
12131142Sedward 		return NOSTR;
12231142Sedward 	while (lc > 0) {
12331142Sedward 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
12431142Sedward 			return NOSTR;
12531142Sedward 		if (hfield = ishfield(linebuf, colon, field))
12631142Sedward 			return savestr(hfield);
12731142Sedward 	}
12831142Sedward 	return NOSTR;
1291219Skas }
1301219Skas 
1311219Skas /*
1321219Skas  * Return the next header field found in the given message.
13331142Sedward  * Return >= 0 if something found, < 0 elsewise.
13431142Sedward  * "colon" is set to point to the colon in the header.
1351219Skas  * Must deal with \ continuations & other such fraud.
1361219Skas  */
13731142Sedward gethfield(f, linebuf, rem, colon)
1381219Skas 	register FILE *f;
1391219Skas 	char linebuf[];
1401219Skas 	register int rem;
14131142Sedward 	char **colon;
1421219Skas {
1431219Skas 	char line2[LINESIZE];
1441219Skas 	register char *cp, *cp2;
1451219Skas 	register int c;
1461219Skas 
1471219Skas 	for (;;) {
14831142Sedward 		if (--rem < 0)
14931142Sedward 			return -1;
15036478Sedward 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
15131142Sedward 			return -1;
15231142Sedward 		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
15331142Sedward 		     cp++)
15431142Sedward 			;
15531142Sedward 		if (*cp != ':' || cp == linebuf)
1561219Skas 			continue;
1571219Skas 		/*
1581219Skas 		 * I guess we got a headline.
1591219Skas 		 * Handle wraparounding
1601219Skas 		 */
16131142Sedward 		*colon = cp;
16231142Sedward 		cp = linebuf + c;
1631219Skas 		for (;;) {
16431142Sedward 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
16531142Sedward 				;
16631142Sedward 			cp++;
1671219Skas 			if (rem <= 0)
1681219Skas 				break;
16931142Sedward 			ungetc(c = getc(f), f);
17031142Sedward 			if (c != ' ' && c != '\t')
1711219Skas 				break;
17236478Sedward 			if ((c = readline(f, line2, LINESIZE)) < 0)
1731219Skas 				break;
1741219Skas 			rem--;
17531142Sedward 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1761219Skas 				;
17731142Sedward 			c -= cp2 - line2;
17831142Sedward 			if (cp + c >= linebuf + LINESIZE - 2)
1791219Skas 				break;
1801219Skas 			*cp++ = ' ';
18131142Sedward 			bcopy(cp2, cp, c);
18231142Sedward 			cp += c;
1831219Skas 		}
18431142Sedward 		*cp = 0;
18531142Sedward 		return rem;
1861219Skas 	}
1871219Skas 	/* NOTREACHED */
1881219Skas }
1891219Skas 
1901219Skas /*
1911219Skas  * Check whether the passed line is a header line of
19231142Sedward  * the desired breed.  Return the field body, or 0.
1931219Skas  */
1941219Skas 
19531142Sedward char*
19631142Sedward ishfield(linebuf, colon, field)
1971219Skas 	char linebuf[], field[];
19831142Sedward 	char *colon;
1991219Skas {
20031142Sedward 	register char *cp = colon;
2011219Skas 
2021219Skas 	*cp = 0;
20334987Sedward 	if (strcasecmp(linebuf, field) != 0) {
20431142Sedward 		*cp = ':';
20531142Sedward 		return 0;
2061219Skas 	}
20731142Sedward 	*cp = ':';
20831142Sedward 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
20931142Sedward 		;
21031142Sedward 	return cp;
2111219Skas }
2121219Skas 
2131219Skas /*
2147571Skurt  * Copy a string, lowercasing it as we go.
2157571Skurt  */
2167571Skurt istrcpy(dest, src)
21731142Sedward 	register char *dest, *src;
2187571Skurt {
2197571Skurt 
2207571Skurt 	do {
22131142Sedward 		if (isupper(*src))
22231142Sedward 			*dest++ = tolower(*src);
22331142Sedward 		else
22431142Sedward 			*dest++ = *src;
22531142Sedward 	} while (*src++ != 0);
2267571Skurt }
2277571Skurt 
2287571Skurt /*
2291219Skas  * The following code deals with input stacking to do source
2301219Skas  * commands.  All but the current file pointer are saved on
2311219Skas  * the stack.
2321219Skas  */
2331219Skas 
23434965Sedward static	int	ssp;			/* Top of file stack */
2351519Skas struct sstack {
2361519Skas 	FILE	*s_file;		/* File we were in. */
2371519Skas 	int	s_cond;			/* Saved state of conditionals */
2385785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
23918661Sserge } sstack[NOFILE];
2401219Skas 
2411219Skas /*
2421219Skas  * Pushdown current input file and switch to a new one.
2431219Skas  * Set the global flag "sourcing" so that others will realize
2441219Skas  * that they are no longer reading from a tty (in all probability).
2451219Skas  */
24634966Sedward source(arglist)
24734966Sedward 	char **arglist;
2481219Skas {
24934966Sedward 	FILE *fi;
25034966Sedward 	char *cp;
2511219Skas 
25234966Sedward 	if ((cp = expand(*arglist)) == NOSTR)
2531219Skas 		return(1);
2543914Skurt 	if ((fi = fopen(cp, "r")) == NULL) {
2553914Skurt 		perror(cp);
2563914Skurt 		return(1);
2571219Skas 	}
25834965Sedward 	if (ssp >= NOFILE - 1) {
2591219Skas 		printf("Too much \"sourcing\" going on.\n");
2601219Skas 		fclose(fi);
2611219Skas 		return(1);
2621219Skas 	}
26334965Sedward 	sstack[ssp].s_file = input;
2641519Skas 	sstack[ssp].s_cond = cond;
2655785Skurt 	sstack[ssp].s_loading = loading;
26634965Sedward 	ssp++;
2675785Skurt 	loading = 0;
2681519Skas 	cond = CANY;
2691219Skas 	input = fi;
2701219Skas 	sourcing++;
2711219Skas 	return(0);
2721219Skas }
2731219Skas 
2741219Skas /*
2751219Skas  * Pop the current input back to the previous level.
2761219Skas  * Update the "sourcing" flag as appropriate.
2771219Skas  */
2781219Skas unstack()
2791219Skas {
28034965Sedward 	if (ssp <= 0) {
2811219Skas 		printf("\"Source\" stack over-pop.\n");
2821219Skas 		sourcing = 0;
2831219Skas 		return(1);
2841219Skas 	}
2851219Skas 	fclose(input);
2861519Skas 	if (cond != CANY)
2871519Skas 		printf("Unmatched \"if\"\n");
28834965Sedward 	ssp--;
2891519Skas 	cond = sstack[ssp].s_cond;
2905785Skurt 	loading = sstack[ssp].s_loading;
29134965Sedward 	input = sstack[ssp].s_file;
29234965Sedward 	if (ssp == 0)
2935785Skurt 		sourcing = loading;
2941219Skas 	return(0);
2951219Skas }
2961219Skas 
2971219Skas /*
2981219Skas  * Touch the indicated file.
2991219Skas  * This is nifty for the shell.
3001219Skas  */
3011219Skas alter(name)
302*38078Sbostic 	char *name;
3031219Skas {
304*38078Sbostic 	struct stat sb;
305*38078Sbostic 	struct timeval tv[2];
306*38078Sbostic 	time_t time();
3071219Skas 
308*38078Sbostic 	if (stat(name, &sb))
3091219Skas 		return;
310*38078Sbostic 	tv[0].tv_sec = time((time_t *)0) + 1;
311*38078Sbostic 	tv[1].tv_sec = sb.st_mtime;
312*38078Sbostic 	tv[0].tv_usec = tv[1].tv_usec = 0;
313*38078Sbostic 	(void)utimes(name, tv);
3141219Skas }
3151219Skas 
3161219Skas /*
3171219Skas  * Examine the passed line buffer and
3181219Skas  * return true if it is all blanks and tabs.
3191219Skas  */
3201219Skas blankline(linebuf)
3211219Skas 	char linebuf[];
3221219Skas {
3231219Skas 	register char *cp;
3241219Skas 
3251219Skas 	for (cp = linebuf; *cp; cp++)
32618661Sserge 		if (*cp != ' ' && *cp != '\t')
3271219Skas 			return(0);
3281219Skas 	return(1);
3291219Skas }
3301219Skas 
3311219Skas /*
3323195Skas  * Get sender's name from this message.  If the message has
3333195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
3343195Skas  * before returning it.
3353195Skas  */
3363195Skas char *
3373195Skas nameof(mp, reptype)
3383195Skas 	register struct message *mp;
3393195Skas {
3405237Skurt 	register char *cp, *cp2;
3413195Skas 
3425237Skurt 	cp = skin(name1(mp, reptype));
3435237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
3445237Skurt 		return(cp);
3455237Skurt 	cp2 = rindex(cp, '!');
3465237Skurt 	cp2--;
3475237Skurt 	while (cp2 > cp && *cp2 != '!')
3485237Skurt 		cp2--;
3495237Skurt 	if (*cp2 == '!')
3505237Skurt 		return(cp2 + 1);
3515237Skurt 	return(cp);
3523195Skas }
3533195Skas 
3543195Skas /*
35525912Smckusick  * Skin an arpa net address according to the RFC 822 interpretation
3563195Skas  * of "host-phrase."
3573195Skas  */
3583195Skas char *
3593195Skas skin(name)
3603195Skas 	char *name;
3613195Skas {
3623195Skas 	register int c;
3633195Skas 	register char *cp, *cp2;
36425912Smckusick 	char *bufend;
3653195Skas 	int gotlt, lastsp;
3663195Skas 	char nbuf[BUFSIZ];
36718661Sserge 	int nesting;
3683195Skas 
3693195Skas 	if (name == NOSTR)
3703195Skas 		return(NOSTR);
37112819Sleres 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
37231142Sedward 	    && index(name, ' ') == NOSTR)
3733195Skas 		return(name);
3743195Skas 	gotlt = 0;
3753195Skas 	lastsp = 0;
37625912Smckusick 	bufend = nbuf;
37725912Smckusick 	for (cp = name, cp2 = bufend; c = *cp++; ) {
3783195Skas 		switch (c) {
3793195Skas 		case '(':
38025912Smckusick 			/*
38125912Smckusick 			 * Start of a "comment".
38225912Smckusick 			 * Ignore it.
38325912Smckusick 			 */
38418661Sserge 			nesting = 1;
38525912Smckusick 			while ((c = *cp) != 0) {
38625912Smckusick 				cp++;
38725912Smckusick 				switch (c) {
38825912Smckusick 				case '\\':
38925912Smckusick 					if (*cp == 0)
39025912Smckusick 						goto outcm;
39125912Smckusick 					cp++;
39225912Smckusick 					break;
39318661Sserge 				case '(':
39418661Sserge 					nesting++;
39518661Sserge 					break;
39618661Sserge 
39718661Sserge 				case ')':
39818661Sserge 					--nesting;
39918661Sserge 					break;
40018661Sserge 				}
40118661Sserge 
40218661Sserge 				if (nesting <= 0)
40318661Sserge 					break;
40418661Sserge 			}
40525912Smckusick 		outcm:
40612819Sleres 			lastsp = 0;
4073195Skas 			break;
4083195Skas 
40925912Smckusick 		case '"':
41025912Smckusick 			/*
41125912Smckusick 			 * Start of a "quoted-string".
41225912Smckusick 			 * Copy it in its entirety.
41325912Smckusick 			 */
41425912Smckusick 			while ((c = *cp) != 0) {
41525912Smckusick 				cp++;
41625912Smckusick 				switch (c) {
41725912Smckusick 				case '\\':
41825912Smckusick 					if ((c = *cp) == 0)
41925912Smckusick 						goto outqs;
42025912Smckusick 					cp++;
42125912Smckusick 					break;
42225912Smckusick 				case '"':
42325912Smckusick 					goto outqs;
42425912Smckusick 				}
42525912Smckusick 				*cp2++ = c;
42625912Smckusick 			}
42725912Smckusick 		outqs:
42825912Smckusick 			lastsp = 0;
42925912Smckusick 			break;
43025912Smckusick 
4313195Skas 		case ' ':
43212819Sleres 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
43312819Sleres 				cp += 3, *cp2++ = '@';
43412819Sleres 			else
43512819Sleres 			if (cp[0] == '@' && cp[1] == ' ')
43612819Sleres 				cp += 2, *cp2++ = '@';
43712819Sleres 			else
43812819Sleres 				lastsp = 1;
4393195Skas 			break;
4403195Skas 
4413195Skas 		case '<':
44225912Smckusick 			cp2 = bufend;
4433195Skas 			gotlt++;
4443195Skas 			lastsp = 0;
4453195Skas 			break;
4463195Skas 
4473195Skas 		case '>':
44825912Smckusick 			if (gotlt) {
44925912Smckusick 				gotlt = 0;
45025912Smckusick 				while (*cp != ',' && *cp != 0)
45125912Smckusick 					cp++;
45225912Smckusick 				if (*cp == 0 )
45325912Smckusick 					goto done;
45425912Smckusick 				*cp2++ = ',';
45525912Smckusick 				*cp2++ = ' ';
45625912Smckusick 				bufend = cp2;
45725912Smckusick 				break;
45825912Smckusick 			}
4593195Skas 
4603195Skas 			/* Fall into . . . */
4613195Skas 
4623195Skas 		default:
4633195Skas 			if (lastsp) {
4643195Skas 				lastsp = 0;
4653195Skas 				*cp2++ = ' ';
4663195Skas 			}
4673195Skas 			*cp2++ = c;
4683195Skas 			break;
4693195Skas 		}
4703195Skas 	}
4713195Skas done:
4723195Skas 	*cp2 = 0;
4733195Skas 
4743195Skas 	return(savestr(nbuf));
4753195Skas }
4763195Skas 
4773195Skas /*
4781219Skas  * Fetch the sender's name from the passed message.
4793195Skas  * Reptype can be
4803195Skas  *	0 -- get sender's name for display purposes
4813195Skas  *	1 -- get sender's name for reply
4823195Skas  *	2 -- get sender's name for Reply
4831219Skas  */
4841219Skas char *
4853195Skas name1(mp, reptype)
4861219Skas 	register struct message *mp;
4871219Skas {
4881219Skas 	char namebuf[LINESIZE];
4891219Skas 	char linebuf[LINESIZE];
4901219Skas 	register char *cp, *cp2;
4911219Skas 	register FILE *ibuf;
4921219Skas 	int first = 1;
4931219Skas 
4943195Skas 	if ((cp = hfield("from", mp)) != NOSTR)
49531142Sedward 		return cp;
4963195Skas 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
49731142Sedward 		return cp;
4981219Skas 	ibuf = setinput(mp);
49931142Sedward 	namebuf[0] = 0;
50036478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5011219Skas 		return(savestr(namebuf));
5021219Skas newname:
50331142Sedward 	for (cp = linebuf; *cp && *cp != ' '; cp++)
5041219Skas 		;
50531142Sedward 	for (; *cp == ' ' || *cp == '\t'; cp++)
5061219Skas 		;
50731142Sedward 	for (cp2 = &namebuf[strlen(namebuf)];
50831142Sedward 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
50931142Sedward 		*cp2++ = *cp++;
5101219Skas 	*cp2 = '\0';
51136478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5121219Skas 		return(savestr(namebuf));
5131219Skas 	if ((cp = index(linebuf, 'F')) == NULL)
5141219Skas 		return(savestr(namebuf));
5151219Skas 	if (strncmp(cp, "From", 4) != 0)
5161219Skas 		return(savestr(namebuf));
5171219Skas 	while ((cp = index(cp, 'r')) != NULL) {
5181219Skas 		if (strncmp(cp, "remote", 6) == 0) {
5191219Skas 			if ((cp = index(cp, 'f')) == NULL)
5201219Skas 				break;
5211219Skas 			if (strncmp(cp, "from", 4) != 0)
5221219Skas 				break;
5231219Skas 			if ((cp = index(cp, ' ')) == NULL)
5241219Skas 				break;
5251219Skas 			cp++;
5261219Skas 			if (first) {
52731142Sedward 				strcpy(namebuf, cp);
5281219Skas 				first = 0;
5291219Skas 			} else
5301219Skas 				strcpy(rindex(namebuf, '!')+1, cp);
5311219Skas 			strcat(namebuf, "!");
5321219Skas 			goto newname;
5331219Skas 		}
5341219Skas 		cp++;
5351219Skas 	}
5361219Skas 	return(savestr(namebuf));
5371219Skas }
5381219Skas 
5391219Skas /*
5405237Skurt  * Count the occurances of c in str
5415237Skurt  */
5425237Skurt charcount(str, c)
5435237Skurt 	char *str;
5445237Skurt {
5455237Skurt 	register char *cp;
5465237Skurt 	register int i;
5475237Skurt 
5485237Skurt 	for (i = 0, cp = str; *cp; cp++)
5495237Skurt 		if (*cp == c)
5505237Skurt 			i++;
5515237Skurt 	return(i);
5525237Skurt }
5535237Skurt 
5545237Skurt /*
55531142Sedward  * Are any of the characters in the two strings the same?
5561219Skas  */
55731142Sedward anyof(s1, s2)
55831142Sedward 	register char *s1, *s2;
5591219Skas {
5601219Skas 
56131142Sedward 	while (*s1)
56231142Sedward 		if (index(s2, *s1++))
56331142Sedward 			return 1;
56431142Sedward 	return 0;
5651219Skas }
5661219Skas 
5671219Skas /*
56831142Sedward  * Convert c to upper case
5691219Skas  */
57031142Sedward raise(c)
57131142Sedward 	register c;
57231142Sedward {
57331142Sedward 
57431142Sedward 	if (islower(c))
57531142Sedward 		return toupper(c);
57631142Sedward 	return c;
57731142Sedward }
57831142Sedward 
57931142Sedward /*
58031142Sedward  * Copy s1 to s2, return pointer to null in s2.
58131142Sedward  */
58231142Sedward char *
58331142Sedward copy(s1, s2)
5841219Skas 	register char *s1, *s2;
5851219Skas {
5861219Skas 
58731142Sedward 	while (*s2++ = *s1++)
58831142Sedward 		;
58931142Sedward 	return s2 - 1;
5901219Skas }
5911219Skas 
5921219Skas /*
5937571Skurt  * See if the given header field is supposed to be ignored.
5947571Skurt  */
59534692Sedward isign(field, ignore)
5967571Skurt 	char *field;
59734692Sedward 	struct ignoretab ignore[2];
5987571Skurt {
5997571Skurt 	char realfld[BUFSIZ];
6007571Skurt 
60134969Sedward 	if (ignore == ignoreall)
60234969Sedward 		return 1;
60318661Sserge 	/*
60418661Sserge 	 * Lower-case the string, so that "Status" and "status"
60518661Sserge 	 * will hash to the same place.
60618661Sserge 	 */
6077571Skurt 	istrcpy(realfld, field);
60834692Sedward 	if (ignore[1].i_count > 0)
60934692Sedward 		return (!member(realfld, ignore + 1));
61018661Sserge 	else
61118661Sserge 		return (member(realfld, ignore));
6127571Skurt }
61318661Sserge 
61418661Sserge member(realfield, table)
61518661Sserge 	register char *realfield;
61634692Sedward 	struct ignoretab *table;
61718661Sserge {
61818661Sserge 	register struct ignore *igp;
61918661Sserge 
62034692Sedward 	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
62131142Sedward 		if (*igp->i_field == *realfield &&
62231142Sedward 		    equal(igp->i_field, realfield))
62318661Sserge 			return (1);
62418661Sserge 	return (0);
62518661Sserge }
626