xref: /csrg-svn/usr.bin/mail/aux.c (revision 43865)
122444Sdist /*
222444Sdist  * Copyright (c) 1980 Regents of the University of California.
333499Sbostic  * All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622444Sdist  */
722444Sdist 
834905Sbostic #ifndef lint
9*43865Sedward static char sccsid[] = "@(#)aux.c	5.20 (Berkeley) 06/25/90";
1034905Sbostic #endif /* not lint */
111219Skas 
121219Skas #include "rcv.h"
131219Skas #include <sys/stat.h>
1438078Sbostic #include <sys/time.h>
151219Skas 
161219Skas /*
171219Skas  * Mail -- a mail program
181219Skas  *
191219Skas  * Auxiliary functions.
201219Skas  */
211219Skas 
221219Skas /*
231219Skas  * Return a pointer to a dynamic copy of the argument.
241219Skas  */
251219Skas char *
261219Skas savestr(str)
271219Skas 	char *str;
281219Skas {
2934987Sedward 	char *new;
3034987Sedward 	int size = strlen(str) + 1;
311219Skas 
3234987Sedward 	if ((new = salloc(size)) != NOSTR)
3334987Sedward 		bcopy(str, new, size);
3434987Sedward 	return new;
351219Skas }
361219Skas 
371219Skas /*
381219Skas  * Announce a fatal error and die.
391219Skas  */
401219Skas 
4131142Sedward /*VARARGS1*/
4231142Sedward panic(fmt, a, b)
4331142Sedward 	char *fmt;
441219Skas {
4531142Sedward 	fprintf(stderr, "panic: ");
4631142Sedward 	fprintf(stderr, fmt, a, b);
4731142Sedward 	putc('\n', stderr);
48*43865Sedward 	fflush(stdout);
49*43865Sedward 	abort();
501219Skas }
511219Skas 
521219Skas /*
531219Skas  * Touch the named message by setting its MTOUCH flag.
541219Skas  * Touched messages have the effect of not being sent
551219Skas  * back to the system mailbox on exit.
561219Skas  */
5734987Sedward touch(mp)
5834987Sedward 	register struct message *mp;
591219Skas {
601479Skas 
611479Skas 	mp->m_flag |= MTOUCH;
621479Skas 	if ((mp->m_flag & MREAD) == 0)
631479Skas 		mp->m_flag |= MREAD|MSTATUS;
641219Skas }
651219Skas 
661219Skas /*
671219Skas  * Test to see if the passed file name is a directory.
681219Skas  * Return true if it is.
691219Skas  */
701219Skas isdir(name)
711219Skas 	char name[];
721219Skas {
731219Skas 	struct stat sbuf;
741219Skas 
751219Skas 	if (stat(name, &sbuf) < 0)
761219Skas 		return(0);
771219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
781219Skas }
791219Skas 
801219Skas /*
811219Skas  * Count the number of arguments in the given string raw list.
821219Skas  */
831219Skas argcount(argv)
841219Skas 	char **argv;
851219Skas {
861219Skas 	register char **ap;
871219Skas 
8831142Sedward 	for (ap = argv; *ap++ != NOSTR;)
891219Skas 		;
9031142Sedward 	return ap - argv - 1;
911219Skas }
921219Skas 
931219Skas /*
941219Skas  * Return the desired header line from the passed message
951219Skas  * pointer (or NOSTR if the desired header field is not available).
961219Skas  */
971219Skas char *
981219Skas hfield(field, mp)
991219Skas 	char field[];
1001219Skas 	struct message *mp;
1011219Skas {
1021219Skas 	register FILE *ibuf;
1031219Skas 	char linebuf[LINESIZE];
1041219Skas 	register int lc;
10531142Sedward 	register char *hfield;
10631142Sedward 	char *colon;
1071219Skas 
1081219Skas 	ibuf = setinput(mp);
10931142Sedward 	if ((lc = mp->m_lines - 1) < 0)
11031142Sedward 		return NOSTR;
11136478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
11231142Sedward 		return NOSTR;
11331142Sedward 	while (lc > 0) {
11431142Sedward 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
11531142Sedward 			return NOSTR;
11631142Sedward 		if (hfield = ishfield(linebuf, colon, field))
11731142Sedward 			return savestr(hfield);
11831142Sedward 	}
11931142Sedward 	return NOSTR;
1201219Skas }
1211219Skas 
1221219Skas /*
1231219Skas  * Return the next header field found in the given message.
12431142Sedward  * Return >= 0 if something found, < 0 elsewise.
12531142Sedward  * "colon" is set to point to the colon in the header.
1261219Skas  * Must deal with \ continuations & other such fraud.
1271219Skas  */
12831142Sedward gethfield(f, linebuf, rem, colon)
1291219Skas 	register FILE *f;
1301219Skas 	char linebuf[];
1311219Skas 	register int rem;
13231142Sedward 	char **colon;
1331219Skas {
1341219Skas 	char line2[LINESIZE];
1351219Skas 	register char *cp, *cp2;
1361219Skas 	register int c;
1371219Skas 
1381219Skas 	for (;;) {
13931142Sedward 		if (--rem < 0)
14031142Sedward 			return -1;
14136478Sedward 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
14231142Sedward 			return -1;
14331142Sedward 		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
14431142Sedward 		     cp++)
14531142Sedward 			;
14631142Sedward 		if (*cp != ':' || cp == linebuf)
1471219Skas 			continue;
1481219Skas 		/*
1491219Skas 		 * I guess we got a headline.
1501219Skas 		 * Handle wraparounding
1511219Skas 		 */
15231142Sedward 		*colon = cp;
15331142Sedward 		cp = linebuf + c;
1541219Skas 		for (;;) {
15531142Sedward 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
15631142Sedward 				;
15731142Sedward 			cp++;
1581219Skas 			if (rem <= 0)
1591219Skas 				break;
16031142Sedward 			ungetc(c = getc(f), f);
16131142Sedward 			if (c != ' ' && c != '\t')
1621219Skas 				break;
16336478Sedward 			if ((c = readline(f, line2, LINESIZE)) < 0)
1641219Skas 				break;
1651219Skas 			rem--;
16631142Sedward 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1671219Skas 				;
16831142Sedward 			c -= cp2 - line2;
16931142Sedward 			if (cp + c >= linebuf + LINESIZE - 2)
1701219Skas 				break;
1711219Skas 			*cp++ = ' ';
17231142Sedward 			bcopy(cp2, cp, c);
17331142Sedward 			cp += c;
1741219Skas 		}
17531142Sedward 		*cp = 0;
17631142Sedward 		return rem;
1771219Skas 	}
1781219Skas 	/* NOTREACHED */
1791219Skas }
1801219Skas 
1811219Skas /*
1821219Skas  * Check whether the passed line is a header line of
18331142Sedward  * the desired breed.  Return the field body, or 0.
1841219Skas  */
1851219Skas 
18631142Sedward char*
18731142Sedward ishfield(linebuf, colon, field)
1881219Skas 	char linebuf[], field[];
18931142Sedward 	char *colon;
1901219Skas {
19131142Sedward 	register char *cp = colon;
1921219Skas 
1931219Skas 	*cp = 0;
19434987Sedward 	if (strcasecmp(linebuf, field) != 0) {
19531142Sedward 		*cp = ':';
19631142Sedward 		return 0;
1971219Skas 	}
19831142Sedward 	*cp = ':';
19931142Sedward 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
20031142Sedward 		;
20131142Sedward 	return cp;
2021219Skas }
2031219Skas 
2041219Skas /*
2057571Skurt  * Copy a string, lowercasing it as we go.
2067571Skurt  */
2077571Skurt istrcpy(dest, src)
20831142Sedward 	register char *dest, *src;
2097571Skurt {
2107571Skurt 
2117571Skurt 	do {
21231142Sedward 		if (isupper(*src))
21331142Sedward 			*dest++ = tolower(*src);
21431142Sedward 		else
21531142Sedward 			*dest++ = *src;
21631142Sedward 	} while (*src++ != 0);
2177571Skurt }
2187571Skurt 
2197571Skurt /*
2201219Skas  * The following code deals with input stacking to do source
2211219Skas  * commands.  All but the current file pointer are saved on
2221219Skas  * the stack.
2231219Skas  */
2241219Skas 
22534965Sedward static	int	ssp;			/* Top of file stack */
2261519Skas struct sstack {
2271519Skas 	FILE	*s_file;		/* File we were in. */
2281519Skas 	int	s_cond;			/* Saved state of conditionals */
2295785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
23018661Sserge } sstack[NOFILE];
2311219Skas 
2321219Skas /*
2331219Skas  * Pushdown current input file and switch to a new one.
2341219Skas  * Set the global flag "sourcing" so that others will realize
2351219Skas  * that they are no longer reading from a tty (in all probability).
2361219Skas  */
23734966Sedward source(arglist)
23834966Sedward 	char **arglist;
2391219Skas {
24034966Sedward 	FILE *fi;
24134966Sedward 	char *cp;
2421219Skas 
24334966Sedward 	if ((cp = expand(*arglist)) == NOSTR)
2441219Skas 		return(1);
245*43865Sedward 	if ((fi = Fopen(cp, "r")) == NULL) {
2463914Skurt 		perror(cp);
2473914Skurt 		return(1);
2481219Skas 	}
24934965Sedward 	if (ssp >= NOFILE - 1) {
2501219Skas 		printf("Too much \"sourcing\" going on.\n");
251*43865Sedward 		Fclose(fi);
2521219Skas 		return(1);
2531219Skas 	}
25434965Sedward 	sstack[ssp].s_file = input;
2551519Skas 	sstack[ssp].s_cond = cond;
2565785Skurt 	sstack[ssp].s_loading = loading;
25734965Sedward 	ssp++;
2585785Skurt 	loading = 0;
2591519Skas 	cond = CANY;
2601219Skas 	input = fi;
2611219Skas 	sourcing++;
2621219Skas 	return(0);
2631219Skas }
2641219Skas 
2651219Skas /*
2661219Skas  * Pop the current input back to the previous level.
2671219Skas  * Update the "sourcing" flag as appropriate.
2681219Skas  */
2691219Skas unstack()
2701219Skas {
27134965Sedward 	if (ssp <= 0) {
2721219Skas 		printf("\"Source\" stack over-pop.\n");
2731219Skas 		sourcing = 0;
2741219Skas 		return(1);
2751219Skas 	}
276*43865Sedward 	Fclose(input);
2771519Skas 	if (cond != CANY)
2781519Skas 		printf("Unmatched \"if\"\n");
27934965Sedward 	ssp--;
2801519Skas 	cond = sstack[ssp].s_cond;
2815785Skurt 	loading = sstack[ssp].s_loading;
28234965Sedward 	input = sstack[ssp].s_file;
28334965Sedward 	if (ssp == 0)
2845785Skurt 		sourcing = loading;
2851219Skas 	return(0);
2861219Skas }
2871219Skas 
2881219Skas /*
2891219Skas  * Touch the indicated file.
2901219Skas  * This is nifty for the shell.
2911219Skas  */
2921219Skas alter(name)
29338078Sbostic 	char *name;
2941219Skas {
29538078Sbostic 	struct stat sb;
29638078Sbostic 	struct timeval tv[2];
29738078Sbostic 	time_t time();
2981219Skas 
29938078Sbostic 	if (stat(name, &sb))
3001219Skas 		return;
30138078Sbostic 	tv[0].tv_sec = time((time_t *)0) + 1;
30238078Sbostic 	tv[1].tv_sec = sb.st_mtime;
30338078Sbostic 	tv[0].tv_usec = tv[1].tv_usec = 0;
30438078Sbostic 	(void)utimes(name, tv);
3051219Skas }
3061219Skas 
3071219Skas /*
3081219Skas  * Examine the passed line buffer and
3091219Skas  * return true if it is all blanks and tabs.
3101219Skas  */
3111219Skas blankline(linebuf)
3121219Skas 	char linebuf[];
3131219Skas {
3141219Skas 	register char *cp;
3151219Skas 
3161219Skas 	for (cp = linebuf; *cp; cp++)
31718661Sserge 		if (*cp != ' ' && *cp != '\t')
3181219Skas 			return(0);
3191219Skas 	return(1);
3201219Skas }
3211219Skas 
3221219Skas /*
3233195Skas  * Get sender's name from this message.  If the message has
3243195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
3253195Skas  * before returning it.
3263195Skas  */
3273195Skas char *
3283195Skas nameof(mp, reptype)
3293195Skas 	register struct message *mp;
3303195Skas {
3315237Skurt 	register char *cp, *cp2;
3323195Skas 
3335237Skurt 	cp = skin(name1(mp, reptype));
3345237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
3355237Skurt 		return(cp);
3365237Skurt 	cp2 = rindex(cp, '!');
3375237Skurt 	cp2--;
3385237Skurt 	while (cp2 > cp && *cp2 != '!')
3395237Skurt 		cp2--;
3405237Skurt 	if (*cp2 == '!')
3415237Skurt 		return(cp2 + 1);
3425237Skurt 	return(cp);
3433195Skas }
3443195Skas 
3453195Skas /*
34639763Sedward  * Start of a "comment".
34739763Sedward  * Ignore it.
34839763Sedward  */
34939763Sedward char *
35039763Sedward skip_comment(cp)
35139763Sedward 	register char *cp;
35239763Sedward {
35339763Sedward 	register nesting = 1;
35439763Sedward 
35539763Sedward 	for (; nesting > 0 && *cp; cp++) {
35639763Sedward 		switch (*cp) {
35739763Sedward 		case '\\':
35839763Sedward 			if (cp[1])
35939763Sedward 				cp++;
36039763Sedward 			break;
36139763Sedward 		case '(':
36239763Sedward 			nesting++;
36339763Sedward 			break;
36439763Sedward 		case ')':
36539763Sedward 			nesting--;
36639763Sedward 			break;
36739763Sedward 		}
36839763Sedward 	}
36939763Sedward 	return cp;
37039763Sedward }
37139763Sedward 
37239763Sedward /*
37325912Smckusick  * Skin an arpa net address according to the RFC 822 interpretation
3743195Skas  * of "host-phrase."
3753195Skas  */
3763195Skas char *
3773195Skas skin(name)
3783195Skas 	char *name;
3793195Skas {
3803195Skas 	register int c;
3813195Skas 	register char *cp, *cp2;
38225912Smckusick 	char *bufend;
3833195Skas 	int gotlt, lastsp;
3843195Skas 	char nbuf[BUFSIZ];
3853195Skas 
3863195Skas 	if (name == NOSTR)
3873195Skas 		return(NOSTR);
38812819Sleres 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
38931142Sedward 	    && index(name, ' ') == NOSTR)
3903195Skas 		return(name);
3913195Skas 	gotlt = 0;
3923195Skas 	lastsp = 0;
39325912Smckusick 	bufend = nbuf;
39425912Smckusick 	for (cp = name, cp2 = bufend; c = *cp++; ) {
3953195Skas 		switch (c) {
3963195Skas 		case '(':
39739763Sedward 			cp = skip_comment(cp);
39812819Sleres 			lastsp = 0;
3993195Skas 			break;
4003195Skas 
40125912Smckusick 		case '"':
40225912Smckusick 			/*
40325912Smckusick 			 * Start of a "quoted-string".
40425912Smckusick 			 * Copy it in its entirety.
40525912Smckusick 			 */
40639763Sedward 			while (c = *cp) {
40725912Smckusick 				cp++;
40839763Sedward 				if (c == '"')
40939763Sedward 					break;
41039763Sedward 				if (c != '\\')
41139763Sedward 					*cp2++ = c;
41239763Sedward 				else if (c = *cp) {
41339763Sedward 					*cp2++ = c;
41425912Smckusick 					cp++;
41525912Smckusick 				}
41625912Smckusick 			}
41725912Smckusick 			lastsp = 0;
41825912Smckusick 			break;
41925912Smckusick 
4203195Skas 		case ' ':
42112819Sleres 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
42212819Sleres 				cp += 3, *cp2++ = '@';
42312819Sleres 			else
42412819Sleres 			if (cp[0] == '@' && cp[1] == ' ')
42512819Sleres 				cp += 2, *cp2++ = '@';
42612819Sleres 			else
42712819Sleres 				lastsp = 1;
4283195Skas 			break;
4293195Skas 
4303195Skas 		case '<':
43125912Smckusick 			cp2 = bufend;
4323195Skas 			gotlt++;
4333195Skas 			lastsp = 0;
4343195Skas 			break;
4353195Skas 
4363195Skas 		case '>':
43725912Smckusick 			if (gotlt) {
43825912Smckusick 				gotlt = 0;
43939763Sedward 				while ((c = *cp) && c != ',') {
44025912Smckusick 					cp++;
44139763Sedward 					if (c == '(')
44239763Sedward 						cp = skip_comment(cp);
44339763Sedward 					else if (c == '"')
44439763Sedward 						while (c = *cp) {
44539763Sedward 							cp++;
44639763Sedward 							if (c == '"')
44739763Sedward 								break;
44839763Sedward 							if (c == '\\' && *cp)
44939763Sedward 								cp++;
45039763Sedward 						}
45139763Sedward 				}
45239763Sedward 				lastsp = 0;
45325912Smckusick 				break;
45425912Smckusick 			}
4553195Skas 			/* Fall into . . . */
4563195Skas 
4573195Skas 		default:
4583195Skas 			if (lastsp) {
4593195Skas 				lastsp = 0;
4603195Skas 				*cp2++ = ' ';
4613195Skas 			}
4623195Skas 			*cp2++ = c;
46339763Sedward 			if (c == ',' && !gotlt) {
46439763Sedward 				*cp2++ = ' ';
46539763Sedward 				for (; *cp == ' '; cp++)
46639763Sedward 					;
46739763Sedward 				lastsp = 0;
46839763Sedward 				bufend = cp2;
46939763Sedward 			}
4703195Skas 		}
4713195Skas 	}
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