xref: /csrg-svn/usr.bin/mail/aux.c (revision 42741)
122444Sdist /*
222444Sdist  * Copyright (c) 1980 Regents of the University of California.
333499Sbostic  * All rights reserved.
433499Sbostic  *
5*42741Sbostic  * %sccs.include.redist.c%
622444Sdist  */
722444Sdist 
834905Sbostic #ifndef lint
9*42741Sbostic static char sccsid[] = "@(#)aux.c	5.19 (Berkeley) 06/01/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);
481219Skas 	exit(1);
491219Skas }
501219Skas 
511219Skas /*
521219Skas  * Touch the named message by setting its MTOUCH flag.
531219Skas  * Touched messages have the effect of not being sent
541219Skas  * back to the system mailbox on exit.
551219Skas  */
5634987Sedward touch(mp)
5734987Sedward 	register struct message *mp;
581219Skas {
591479Skas 
601479Skas 	mp->m_flag |= MTOUCH;
611479Skas 	if ((mp->m_flag & MREAD) == 0)
621479Skas 		mp->m_flag |= MREAD|MSTATUS;
631219Skas }
641219Skas 
651219Skas /*
661219Skas  * Test to see if the passed file name is a directory.
671219Skas  * Return true if it is.
681219Skas  */
691219Skas isdir(name)
701219Skas 	char name[];
711219Skas {
721219Skas 	struct stat sbuf;
731219Skas 
741219Skas 	if (stat(name, &sbuf) < 0)
751219Skas 		return(0);
761219Skas 	return((sbuf.st_mode & S_IFMT) == S_IFDIR);
771219Skas }
781219Skas 
791219Skas /*
801219Skas  * Count the number of arguments in the given string raw list.
811219Skas  */
821219Skas argcount(argv)
831219Skas 	char **argv;
841219Skas {
851219Skas 	register char **ap;
861219Skas 
8731142Sedward 	for (ap = argv; *ap++ != NOSTR;)
881219Skas 		;
8931142Sedward 	return ap - argv - 1;
901219Skas }
911219Skas 
921219Skas /*
931219Skas  * Return the desired header line from the passed message
941219Skas  * pointer (or NOSTR if the desired header field is not available).
951219Skas  */
961219Skas char *
971219Skas hfield(field, mp)
981219Skas 	char field[];
991219Skas 	struct message *mp;
1001219Skas {
1011219Skas 	register FILE *ibuf;
1021219Skas 	char linebuf[LINESIZE];
1031219Skas 	register int lc;
10431142Sedward 	register char *hfield;
10531142Sedward 	char *colon;
1061219Skas 
1071219Skas 	ibuf = setinput(mp);
10831142Sedward 	if ((lc = mp->m_lines - 1) < 0)
10931142Sedward 		return NOSTR;
11036478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
11131142Sedward 		return NOSTR;
11231142Sedward 	while (lc > 0) {
11331142Sedward 		if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
11431142Sedward 			return NOSTR;
11531142Sedward 		if (hfield = ishfield(linebuf, colon, field))
11631142Sedward 			return savestr(hfield);
11731142Sedward 	}
11831142Sedward 	return NOSTR;
1191219Skas }
1201219Skas 
1211219Skas /*
1221219Skas  * Return the next header field found in the given message.
12331142Sedward  * Return >= 0 if something found, < 0 elsewise.
12431142Sedward  * "colon" is set to point to the colon in the header.
1251219Skas  * Must deal with \ continuations & other such fraud.
1261219Skas  */
12731142Sedward gethfield(f, linebuf, rem, colon)
1281219Skas 	register FILE *f;
1291219Skas 	char linebuf[];
1301219Skas 	register int rem;
13131142Sedward 	char **colon;
1321219Skas {
1331219Skas 	char line2[LINESIZE];
1341219Skas 	register char *cp, *cp2;
1351219Skas 	register int c;
1361219Skas 
1371219Skas 	for (;;) {
13831142Sedward 		if (--rem < 0)
13931142Sedward 			return -1;
14036478Sedward 		if ((c = readline(f, linebuf, LINESIZE)) <= 0)
14131142Sedward 			return -1;
14231142Sedward 		for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
14331142Sedward 		     cp++)
14431142Sedward 			;
14531142Sedward 		if (*cp != ':' || cp == linebuf)
1461219Skas 			continue;
1471219Skas 		/*
1481219Skas 		 * I guess we got a headline.
1491219Skas 		 * Handle wraparounding
1501219Skas 		 */
15131142Sedward 		*colon = cp;
15231142Sedward 		cp = linebuf + c;
1531219Skas 		for (;;) {
15431142Sedward 			while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
15531142Sedward 				;
15631142Sedward 			cp++;
1571219Skas 			if (rem <= 0)
1581219Skas 				break;
15931142Sedward 			ungetc(c = getc(f), f);
16031142Sedward 			if (c != ' ' && c != '\t')
1611219Skas 				break;
16236478Sedward 			if ((c = readline(f, line2, LINESIZE)) < 0)
1631219Skas 				break;
1641219Skas 			rem--;
16531142Sedward 			for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
1661219Skas 				;
16731142Sedward 			c -= cp2 - line2;
16831142Sedward 			if (cp + c >= linebuf + LINESIZE - 2)
1691219Skas 				break;
1701219Skas 			*cp++ = ' ';
17131142Sedward 			bcopy(cp2, cp, c);
17231142Sedward 			cp += c;
1731219Skas 		}
17431142Sedward 		*cp = 0;
17531142Sedward 		return rem;
1761219Skas 	}
1771219Skas 	/* NOTREACHED */
1781219Skas }
1791219Skas 
1801219Skas /*
1811219Skas  * Check whether the passed line is a header line of
18231142Sedward  * the desired breed.  Return the field body, or 0.
1831219Skas  */
1841219Skas 
18531142Sedward char*
18631142Sedward ishfield(linebuf, colon, field)
1871219Skas 	char linebuf[], field[];
18831142Sedward 	char *colon;
1891219Skas {
19031142Sedward 	register char *cp = colon;
1911219Skas 
1921219Skas 	*cp = 0;
19334987Sedward 	if (strcasecmp(linebuf, field) != 0) {
19431142Sedward 		*cp = ':';
19531142Sedward 		return 0;
1961219Skas 	}
19731142Sedward 	*cp = ':';
19831142Sedward 	for (cp++; *cp == ' ' || *cp == '\t'; cp++)
19931142Sedward 		;
20031142Sedward 	return cp;
2011219Skas }
2021219Skas 
2031219Skas /*
2047571Skurt  * Copy a string, lowercasing it as we go.
2057571Skurt  */
2067571Skurt istrcpy(dest, src)
20731142Sedward 	register char *dest, *src;
2087571Skurt {
2097571Skurt 
2107571Skurt 	do {
21131142Sedward 		if (isupper(*src))
21231142Sedward 			*dest++ = tolower(*src);
21331142Sedward 		else
21431142Sedward 			*dest++ = *src;
21531142Sedward 	} while (*src++ != 0);
2167571Skurt }
2177571Skurt 
2187571Skurt /*
2191219Skas  * The following code deals with input stacking to do source
2201219Skas  * commands.  All but the current file pointer are saved on
2211219Skas  * the stack.
2221219Skas  */
2231219Skas 
22434965Sedward static	int	ssp;			/* Top of file stack */
2251519Skas struct sstack {
2261519Skas 	FILE	*s_file;		/* File we were in. */
2271519Skas 	int	s_cond;			/* Saved state of conditionals */
2285785Skurt 	int	s_loading;		/* Loading .mailrc, etc. */
22918661Sserge } sstack[NOFILE];
2301219Skas 
2311219Skas /*
2321219Skas  * Pushdown current input file and switch to a new one.
2331219Skas  * Set the global flag "sourcing" so that others will realize
2341219Skas  * that they are no longer reading from a tty (in all probability).
2351219Skas  */
23634966Sedward source(arglist)
23734966Sedward 	char **arglist;
2381219Skas {
23934966Sedward 	FILE *fi;
24034966Sedward 	char *cp;
2411219Skas 
24234966Sedward 	if ((cp = expand(*arglist)) == NOSTR)
2431219Skas 		return(1);
2443914Skurt 	if ((fi = fopen(cp, "r")) == NULL) {
2453914Skurt 		perror(cp);
2463914Skurt 		return(1);
2471219Skas 	}
24834965Sedward 	if (ssp >= NOFILE - 1) {
2491219Skas 		printf("Too much \"sourcing\" going on.\n");
2501219Skas 		fclose(fi);
2511219Skas 		return(1);
2521219Skas 	}
25334965Sedward 	sstack[ssp].s_file = input;
2541519Skas 	sstack[ssp].s_cond = cond;
2555785Skurt 	sstack[ssp].s_loading = loading;
25634965Sedward 	ssp++;
2575785Skurt 	loading = 0;
2581519Skas 	cond = CANY;
2591219Skas 	input = fi;
2601219Skas 	sourcing++;
2611219Skas 	return(0);
2621219Skas }
2631219Skas 
2641219Skas /*
2651219Skas  * Pop the current input back to the previous level.
2661219Skas  * Update the "sourcing" flag as appropriate.
2671219Skas  */
2681219Skas unstack()
2691219Skas {
27034965Sedward 	if (ssp <= 0) {
2711219Skas 		printf("\"Source\" stack over-pop.\n");
2721219Skas 		sourcing = 0;
2731219Skas 		return(1);
2741219Skas 	}
2751219Skas 	fclose(input);
2761519Skas 	if (cond != CANY)
2771519Skas 		printf("Unmatched \"if\"\n");
27834965Sedward 	ssp--;
2791519Skas 	cond = sstack[ssp].s_cond;
2805785Skurt 	loading = sstack[ssp].s_loading;
28134965Sedward 	input = sstack[ssp].s_file;
28234965Sedward 	if (ssp == 0)
2835785Skurt 		sourcing = loading;
2841219Skas 	return(0);
2851219Skas }
2861219Skas 
2871219Skas /*
2881219Skas  * Touch the indicated file.
2891219Skas  * This is nifty for the shell.
2901219Skas  */
2911219Skas alter(name)
29238078Sbostic 	char *name;
2931219Skas {
29438078Sbostic 	struct stat sb;
29538078Sbostic 	struct timeval tv[2];
29638078Sbostic 	time_t time();
2971219Skas 
29838078Sbostic 	if (stat(name, &sb))
2991219Skas 		return;
30038078Sbostic 	tv[0].tv_sec = time((time_t *)0) + 1;
30138078Sbostic 	tv[1].tv_sec = sb.st_mtime;
30238078Sbostic 	tv[0].tv_usec = tv[1].tv_usec = 0;
30338078Sbostic 	(void)utimes(name, tv);
3041219Skas }
3051219Skas 
3061219Skas /*
3071219Skas  * Examine the passed line buffer and
3081219Skas  * return true if it is all blanks and tabs.
3091219Skas  */
3101219Skas blankline(linebuf)
3111219Skas 	char linebuf[];
3121219Skas {
3131219Skas 	register char *cp;
3141219Skas 
3151219Skas 	for (cp = linebuf; *cp; cp++)
31618661Sserge 		if (*cp != ' ' && *cp != '\t')
3171219Skas 			return(0);
3181219Skas 	return(1);
3191219Skas }
3201219Skas 
3211219Skas /*
3223195Skas  * Get sender's name from this message.  If the message has
3233195Skas  * a bunch of arpanet stuff in it, we may have to skin the name
3243195Skas  * before returning it.
3253195Skas  */
3263195Skas char *
3273195Skas nameof(mp, reptype)
3283195Skas 	register struct message *mp;
3293195Skas {
3305237Skurt 	register char *cp, *cp2;
3313195Skas 
3325237Skurt 	cp = skin(name1(mp, reptype));
3335237Skurt 	if (reptype != 0 || charcount(cp, '!') < 2)
3345237Skurt 		return(cp);
3355237Skurt 	cp2 = rindex(cp, '!');
3365237Skurt 	cp2--;
3375237Skurt 	while (cp2 > cp && *cp2 != '!')
3385237Skurt 		cp2--;
3395237Skurt 	if (*cp2 == '!')
3405237Skurt 		return(cp2 + 1);
3415237Skurt 	return(cp);
3423195Skas }
3433195Skas 
3443195Skas /*
34539763Sedward  * Start of a "comment".
34639763Sedward  * Ignore it.
34739763Sedward  */
34839763Sedward char *
34939763Sedward skip_comment(cp)
35039763Sedward 	register char *cp;
35139763Sedward {
35239763Sedward 	register nesting = 1;
35339763Sedward 
35439763Sedward 	for (; nesting > 0 && *cp; cp++) {
35539763Sedward 		switch (*cp) {
35639763Sedward 		case '\\':
35739763Sedward 			if (cp[1])
35839763Sedward 				cp++;
35939763Sedward 			break;
36039763Sedward 		case '(':
36139763Sedward 			nesting++;
36239763Sedward 			break;
36339763Sedward 		case ')':
36439763Sedward 			nesting--;
36539763Sedward 			break;
36639763Sedward 		}
36739763Sedward 	}
36839763Sedward 	return cp;
36939763Sedward }
37039763Sedward 
37139763Sedward /*
37225912Smckusick  * Skin an arpa net address according to the RFC 822 interpretation
3733195Skas  * of "host-phrase."
3743195Skas  */
3753195Skas char *
3763195Skas skin(name)
3773195Skas 	char *name;
3783195Skas {
3793195Skas 	register int c;
3803195Skas 	register char *cp, *cp2;
38125912Smckusick 	char *bufend;
3823195Skas 	int gotlt, lastsp;
3833195Skas 	char nbuf[BUFSIZ];
3843195Skas 
3853195Skas 	if (name == NOSTR)
3863195Skas 		return(NOSTR);
38712819Sleres 	if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
38831142Sedward 	    && index(name, ' ') == NOSTR)
3893195Skas 		return(name);
3903195Skas 	gotlt = 0;
3913195Skas 	lastsp = 0;
39225912Smckusick 	bufend = nbuf;
39325912Smckusick 	for (cp = name, cp2 = bufend; c = *cp++; ) {
3943195Skas 		switch (c) {
3953195Skas 		case '(':
39639763Sedward 			cp = skip_comment(cp);
39712819Sleres 			lastsp = 0;
3983195Skas 			break;
3993195Skas 
40025912Smckusick 		case '"':
40125912Smckusick 			/*
40225912Smckusick 			 * Start of a "quoted-string".
40325912Smckusick 			 * Copy it in its entirety.
40425912Smckusick 			 */
40539763Sedward 			while (c = *cp) {
40625912Smckusick 				cp++;
40739763Sedward 				if (c == '"')
40839763Sedward 					break;
40939763Sedward 				if (c != '\\')
41039763Sedward 					*cp2++ = c;
41139763Sedward 				else if (c = *cp) {
41239763Sedward 					*cp2++ = c;
41325912Smckusick 					cp++;
41425912Smckusick 				}
41525912Smckusick 			}
41625912Smckusick 			lastsp = 0;
41725912Smckusick 			break;
41825912Smckusick 
4193195Skas 		case ' ':
42012819Sleres 			if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
42112819Sleres 				cp += 3, *cp2++ = '@';
42212819Sleres 			else
42312819Sleres 			if (cp[0] == '@' && cp[1] == ' ')
42412819Sleres 				cp += 2, *cp2++ = '@';
42512819Sleres 			else
42612819Sleres 				lastsp = 1;
4273195Skas 			break;
4283195Skas 
4293195Skas 		case '<':
43025912Smckusick 			cp2 = bufend;
4313195Skas 			gotlt++;
4323195Skas 			lastsp = 0;
4333195Skas 			break;
4343195Skas 
4353195Skas 		case '>':
43625912Smckusick 			if (gotlt) {
43725912Smckusick 				gotlt = 0;
43839763Sedward 				while ((c = *cp) && c != ',') {
43925912Smckusick 					cp++;
44039763Sedward 					if (c == '(')
44139763Sedward 						cp = skip_comment(cp);
44239763Sedward 					else if (c == '"')
44339763Sedward 						while (c = *cp) {
44439763Sedward 							cp++;
44539763Sedward 							if (c == '"')
44639763Sedward 								break;
44739763Sedward 							if (c == '\\' && *cp)
44839763Sedward 								cp++;
44939763Sedward 						}
45039763Sedward 				}
45139763Sedward 				lastsp = 0;
45225912Smckusick 				break;
45325912Smckusick 			}
4543195Skas 			/* Fall into . . . */
4553195Skas 
4563195Skas 		default:
4573195Skas 			if (lastsp) {
4583195Skas 				lastsp = 0;
4593195Skas 				*cp2++ = ' ';
4603195Skas 			}
4613195Skas 			*cp2++ = c;
46239763Sedward 			if (c == ',' && !gotlt) {
46339763Sedward 				*cp2++ = ' ';
46439763Sedward 				for (; *cp == ' '; cp++)
46539763Sedward 					;
46639763Sedward 				lastsp = 0;
46739763Sedward 				bufend = cp2;
46839763Sedward 			}
4693195Skas 		}
4703195Skas 	}
4713195Skas 	*cp2 = 0;
4723195Skas 
4733195Skas 	return(savestr(nbuf));
4743195Skas }
4753195Skas 
4763195Skas /*
4771219Skas  * Fetch the sender's name from the passed message.
4783195Skas  * Reptype can be
4793195Skas  *	0 -- get sender's name for display purposes
4803195Skas  *	1 -- get sender's name for reply
4813195Skas  *	2 -- get sender's name for Reply
4821219Skas  */
4831219Skas char *
4843195Skas name1(mp, reptype)
4851219Skas 	register struct message *mp;
4861219Skas {
4871219Skas 	char namebuf[LINESIZE];
4881219Skas 	char linebuf[LINESIZE];
4891219Skas 	register char *cp, *cp2;
4901219Skas 	register FILE *ibuf;
4911219Skas 	int first = 1;
4921219Skas 
4933195Skas 	if ((cp = hfield("from", mp)) != NOSTR)
49431142Sedward 		return cp;
4953195Skas 	if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
49631142Sedward 		return cp;
4971219Skas 	ibuf = setinput(mp);
49831142Sedward 	namebuf[0] = 0;
49936478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5001219Skas 		return(savestr(namebuf));
5011219Skas newname:
50231142Sedward 	for (cp = linebuf; *cp && *cp != ' '; cp++)
5031219Skas 		;
50431142Sedward 	for (; *cp == ' ' || *cp == '\t'; cp++)
5051219Skas 		;
50631142Sedward 	for (cp2 = &namebuf[strlen(namebuf)];
50731142Sedward 	     *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
50831142Sedward 		*cp2++ = *cp++;
5091219Skas 	*cp2 = '\0';
51036478Sedward 	if (readline(ibuf, linebuf, LINESIZE) < 0)
5111219Skas 		return(savestr(namebuf));
5121219Skas 	if ((cp = index(linebuf, 'F')) == NULL)
5131219Skas 		return(savestr(namebuf));
5141219Skas 	if (strncmp(cp, "From", 4) != 0)
5151219Skas 		return(savestr(namebuf));
5161219Skas 	while ((cp = index(cp, 'r')) != NULL) {
5171219Skas 		if (strncmp(cp, "remote", 6) == 0) {
5181219Skas 			if ((cp = index(cp, 'f')) == NULL)
5191219Skas 				break;
5201219Skas 			if (strncmp(cp, "from", 4) != 0)
5211219Skas 				break;
5221219Skas 			if ((cp = index(cp, ' ')) == NULL)
5231219Skas 				break;
5241219Skas 			cp++;
5251219Skas 			if (first) {
52631142Sedward 				strcpy(namebuf, cp);
5271219Skas 				first = 0;
5281219Skas 			} else
5291219Skas 				strcpy(rindex(namebuf, '!')+1, cp);
5301219Skas 			strcat(namebuf, "!");
5311219Skas 			goto newname;
5321219Skas 		}
5331219Skas 		cp++;
5341219Skas 	}
5351219Skas 	return(savestr(namebuf));
5361219Skas }
5371219Skas 
5381219Skas /*
5395237Skurt  * Count the occurances of c in str
5405237Skurt  */
5415237Skurt charcount(str, c)
5425237Skurt 	char *str;
5435237Skurt {
5445237Skurt 	register char *cp;
5455237Skurt 	register int i;
5465237Skurt 
5475237Skurt 	for (i = 0, cp = str; *cp; cp++)
5485237Skurt 		if (*cp == c)
5495237Skurt 			i++;
5505237Skurt 	return(i);
5515237Skurt }
5525237Skurt 
5535237Skurt /*
55431142Sedward  * Are any of the characters in the two strings the same?
5551219Skas  */
55631142Sedward anyof(s1, s2)
55731142Sedward 	register char *s1, *s2;
5581219Skas {
5591219Skas 
56031142Sedward 	while (*s1)
56131142Sedward 		if (index(s2, *s1++))
56231142Sedward 			return 1;
56331142Sedward 	return 0;
5641219Skas }
5651219Skas 
5661219Skas /*
56731142Sedward  * Convert c to upper case
5681219Skas  */
56931142Sedward raise(c)
57031142Sedward 	register c;
57131142Sedward {
57231142Sedward 
57331142Sedward 	if (islower(c))
57431142Sedward 		return toupper(c);
57531142Sedward 	return c;
57631142Sedward }
57731142Sedward 
57831142Sedward /*
57931142Sedward  * Copy s1 to s2, return pointer to null in s2.
58031142Sedward  */
58131142Sedward char *
58231142Sedward copy(s1, s2)
5831219Skas 	register char *s1, *s2;
5841219Skas {
5851219Skas 
58631142Sedward 	while (*s2++ = *s1++)
58731142Sedward 		;
58831142Sedward 	return s2 - 1;
5891219Skas }
5901219Skas 
5911219Skas /*
5927571Skurt  * See if the given header field is supposed to be ignored.
5937571Skurt  */
59434692Sedward isign(field, ignore)
5957571Skurt 	char *field;
59634692Sedward 	struct ignoretab ignore[2];
5977571Skurt {
5987571Skurt 	char realfld[BUFSIZ];
5997571Skurt 
60034969Sedward 	if (ignore == ignoreall)
60134969Sedward 		return 1;
60218661Sserge 	/*
60318661Sserge 	 * Lower-case the string, so that "Status" and "status"
60418661Sserge 	 * will hash to the same place.
60518661Sserge 	 */
6067571Skurt 	istrcpy(realfld, field);
60734692Sedward 	if (ignore[1].i_count > 0)
60834692Sedward 		return (!member(realfld, ignore + 1));
60918661Sserge 	else
61018661Sserge 		return (member(realfld, ignore));
6117571Skurt }
61218661Sserge 
61318661Sserge member(realfield, table)
61418661Sserge 	register char *realfield;
61534692Sedward 	struct ignoretab *table;
61618661Sserge {
61718661Sserge 	register struct ignore *igp;
61818661Sserge 
61934692Sedward 	for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
62031142Sedward 		if (*igp->i_field == *realfield &&
62131142Sedward 		    equal(igp->i_field, realfield))
62218661Sserge 			return (1);
62318661Sserge 	return (0);
62418661Sserge }
625