xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 52106)
122717Sdist /*
242833Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642833Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822717Sdist 
922717Sdist #ifndef lint
10*52106Seric static char sccsid[] = "@(#)util.c	5.23 (Berkeley) 01/04/92";
1133731Sbostic #endif /* not lint */
1222717Sdist 
133151Seric # include <stdio.h>
144538Seric # include <sys/types.h>
154538Seric # include <sys/stat.h>
16298Seric # include <sysexits.h>
176890Seric # include <errno.h>
186890Seric # include "sendmail.h"
19298Seric 
20298Seric /*
21298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
22298Seric **
23298Seric **	Runs through a string and strips off unquoted quote
24298Seric **	characters and quote bits.  This is done in place.
25298Seric **
26298Seric **	Parameters:
27298Seric **		s -- the string to strip.
284101Seric **		qf -- if set, remove actual `` " '' characters
294101Seric **			as well as the quote bits.
30298Seric **
31298Seric **	Returns:
32298Seric **		none.
33298Seric **
34298Seric **	Side Effects:
35298Seric **		none.
36298Seric **
37298Seric **	Called By:
38298Seric **		deliver
39298Seric */
40298Seric 
414101Seric stripquotes(s, qf)
42298Seric 	char *s;
434101Seric 	bool qf;
44298Seric {
45298Seric 	register char *p;
46298Seric 	register char *q;
47298Seric 	register char c;
48298Seric 
494101Seric 	if (s == NULL)
504101Seric 		return;
514101Seric 
52298Seric 	for (p = q = s; (c = *p++) != '\0'; )
53298Seric 	{
544101Seric 		if (c != '"' || !qf)
55298Seric 			*q++ = c & 0177;
56298Seric 	}
57298Seric 	*q = '\0';
58298Seric }
59298Seric /*
609043Seric **  QSTRLEN -- give me the string length assuming 0200 bits add a char
619043Seric **
629043Seric **	Parameters:
639043Seric **		s -- the string to measure.
649043Seric **
659043Seric **	Reurns:
669043Seric **		The length of s, including space for backslash escapes.
679043Seric **
689043Seric **	Side Effects:
699043Seric **		none.
709043Seric */
719043Seric 
729043Seric qstrlen(s)
739043Seric 	register char *s;
749043Seric {
759043Seric 	register int l = 0;
769043Seric 	register char c;
779043Seric 
789043Seric 	while ((c = *s++) != '\0')
799043Seric 	{
809043Seric 		if (bitset(0200, c))
819043Seric 			l++;
829043Seric 		l++;
839043Seric 	}
849043Seric 	return (l);
859043Seric }
869043Seric /*
872900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
882900Seric **
892900Seric **	Parameters:
902900Seric **		s -- the string to capitalize.
912900Seric **
922900Seric **	Returns:
932900Seric **		a pointer to a properly capitalized string.
942900Seric **
952900Seric **	Side Effects:
962900Seric **		none.
972900Seric */
982900Seric 
992900Seric char *
1002900Seric capitalize(s)
1012900Seric 	register char *s;
1022900Seric {
1032900Seric 	static char buf[50];
1042900Seric 	register char *p;
1052900Seric 
1062900Seric 	p = buf;
1072900Seric 
1082900Seric 	for (;;)
1092900Seric 	{
1102900Seric 		while (!isalpha(*s) && *s != '\0')
1112900Seric 			*p++ = *s++;
1122900Seric 		if (*s == '\0')
1132900Seric 			break;
11440999Sbostic 		*p++ = toupper(*s);
11540999Sbostic 		s++;
1162900Seric 		while (isalpha(*s))
1172900Seric 			*p++ = *s++;
1182900Seric 	}
1192900Seric 
1202900Seric 	*p = '\0';
1212900Seric 	return (buf);
1222900Seric }
1232900Seric /*
124298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
125298Seric **
126298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
127298Seric **	error -- but after all, what can we do?
128298Seric **
129298Seric **	Parameters:
130298Seric **		sz -- size of area to allocate.
131298Seric **
132298Seric **	Returns:
133298Seric **		pointer to data region.
134298Seric **
135298Seric **	Side Effects:
136298Seric **		Memory is allocated.
137298Seric */
138298Seric 
139298Seric char *
140298Seric xalloc(sz)
1417007Seric 	register int sz;
142298Seric {
143298Seric 	register char *p;
14423121Seric 	extern char *malloc();
145298Seric 
14623121Seric 	p = malloc((unsigned) sz);
147298Seric 	if (p == NULL)
148298Seric 	{
149298Seric 		syserr("Out of memory!!");
15010685Seric 		abort();
15110685Seric 		/* exit(EX_UNAVAILABLE); */
152298Seric 	}
153298Seric 	return (p);
154298Seric }
155298Seric /*
1563151Seric **  COPYPLIST -- copy list of pointers.
1573151Seric **
1583151Seric **	This routine is the equivalent of newstr for lists of
1593151Seric **	pointers.
1603151Seric **
1613151Seric **	Parameters:
1623151Seric **		list -- list of pointers to copy.
1633151Seric **			Must be NULL terminated.
1643151Seric **		copycont -- if TRUE, copy the contents of the vector
1653151Seric **			(which must be a string) also.
1663151Seric **
1673151Seric **	Returns:
1683151Seric **		a copy of 'list'.
1693151Seric **
1703151Seric **	Side Effects:
1713151Seric **		none.
1723151Seric */
1733151Seric 
1743151Seric char **
1753151Seric copyplist(list, copycont)
1763151Seric 	char **list;
1773151Seric 	bool copycont;
1783151Seric {
1793151Seric 	register char **vp;
1803151Seric 	register char **newvp;
1813151Seric 
1823151Seric 	for (vp = list; *vp != NULL; vp++)
1833151Seric 		continue;
1843151Seric 
1853151Seric 	vp++;
1863151Seric 
18716897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
18816897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1893151Seric 
1903151Seric 	if (copycont)
1913151Seric 	{
1923151Seric 		for (vp = newvp; *vp != NULL; vp++)
1933151Seric 			*vp = newstr(*vp);
1943151Seric 	}
1953151Seric 
1963151Seric 	return (newvp);
1973151Seric }
1983151Seric /*
1993151Seric **  PRINTAV -- print argument vector.
2003151Seric **
2013151Seric **	Parameters:
2023151Seric **		av -- argument vector.
2033151Seric **
2043151Seric **	Returns:
2053151Seric **		none.
2063151Seric **
2073151Seric **	Side Effects:
2083151Seric **		prints av.
2093151Seric */
2103151Seric 
2113151Seric printav(av)
2123151Seric 	register char **av;
2133151Seric {
2143151Seric 	while (*av != NULL)
2153151Seric 	{
2168063Seric 		if (tTd(0, 44))
2178063Seric 			printf("\n\t%08x=", *av);
2188063Seric 		else
21923105Seric 			(void) putchar(' ');
2203151Seric 		xputs(*av++);
2213151Seric 	}
22223105Seric 	(void) putchar('\n');
2233151Seric }
2243151Seric /*
2253151Seric **  LOWER -- turn letter into lower case.
2263151Seric **
2273151Seric **	Parameters:
2283151Seric **		c -- character to turn into lower case.
2293151Seric **
2303151Seric **	Returns:
2313151Seric **		c, in lower case.
2323151Seric **
2333151Seric **	Side Effects:
2343151Seric **		none.
2353151Seric */
2363151Seric 
2373151Seric char
2383151Seric lower(c)
2393151Seric 	register char c;
2403151Seric {
24133724Sbostic 	return(isascii(c) && isupper(c) ? tolower(c) : c);
2423151Seric }
2433151Seric /*
2443151Seric **  XPUTS -- put string doing control escapes.
2453151Seric **
2463151Seric **	Parameters:
2473151Seric **		s -- string to put.
2483151Seric **
2493151Seric **	Returns:
2503151Seric **		none.
2513151Seric **
2523151Seric **	Side Effects:
2533151Seric **		output to stdout
2543151Seric */
2553151Seric 
2563151Seric xputs(s)
2573151Seric 	register char *s;
2583151Seric {
2593151Seric 	register char c;
26051781Seric 	register struct metamac *mp;
26151781Seric 	extern struct metamac MetaMacros[];
2623151Seric 
2638055Seric 	if (s == NULL)
2648055Seric 	{
2658055Seric 		printf("<null>");
2668055Seric 		return;
2678055Seric 	}
26851781Seric 	c = *s;
26951781Seric 	if (c == MATCHREPL && isdigit(s[1]) && s[2] == '\0')
27051781Seric 	{
27151781Seric 		printf("$%c", s[1]);
27251781Seric 		return;
27351781Seric 	}
27451781Seric 	for (mp = MetaMacros; mp->metaname != NULL; mp++)
27551781Seric 	{
27651781Seric 		if (mp->metaval == c)
27751781Seric 		{
27851781Seric 			printf("$%c%s", mp->metaname, ++s);
27951781Seric 			return;
28051781Seric 		}
28151781Seric 	}
28223105Seric 	(void) putchar('"');
2833151Seric 	while ((c = *s++) != '\0')
2843151Seric 	{
2853151Seric 		if (!isascii(c))
2863151Seric 		{
28723105Seric 			(void) putchar('\\');
2883151Seric 			c &= 0177;
2893151Seric 		}
29010326Seric 		if (c < 040 || c >= 0177)
2913151Seric 		{
29252050Seric 			switch (c)
29352050Seric 			{
29452050Seric 			  case '\n':
29552050Seric 				c = 'n';
29652050Seric 				break;
29752050Seric 
29852050Seric 			  case '\r':
29952050Seric 				c = 'r';
30052050Seric 				break;
30152050Seric 
30252050Seric 			  case '\t':
30352050Seric 				c = 't';
30452050Seric 				break;
30552050Seric 
30652050Seric 			  default:
30752050Seric 				(void) putchar('^');
30852050Seric 				(void) putchar(c ^ 0100);
30952050Seric 				continue;
31052050Seric 			}
31152050Seric 			(void) putchar('\\');
3123151Seric 		}
31323105Seric 		(void) putchar(c);
3143151Seric 	}
31523105Seric 	(void) putchar('"');
3164086Seric 	(void) fflush(stdout);
3173151Seric }
3183151Seric /*
3193151Seric **  MAKELOWER -- Translate a line into lower case
3203151Seric **
3213151Seric **	Parameters:
3223151Seric **		p -- the string to translate.  If NULL, return is
3233151Seric **			immediate.
3243151Seric **
3253151Seric **	Returns:
3263151Seric **		none.
3273151Seric **
3283151Seric **	Side Effects:
3293151Seric **		String pointed to by p is translated to lower case.
3303151Seric **
3313151Seric **	Called By:
3323151Seric **		parse
3333151Seric */
3343151Seric 
3353151Seric makelower(p)
3363151Seric 	register char *p;
3373151Seric {
3383151Seric 	register char c;
3393151Seric 
3403151Seric 	if (p == NULL)
3413151Seric 		return;
3423151Seric 	for (; (c = *p) != '\0'; p++)
3433151Seric 		if (isascii(c) && isupper(c))
34433724Sbostic 			*p = tolower(c);
3453151Seric }
3464059Seric /*
3475196Seric **  BUILDFNAME -- build full name from gecos style entry.
3484375Seric **
3495196Seric **	This routine interprets the strange entry that would appear
3505196Seric **	in the GECOS field of the password file.
3515196Seric **
3524375Seric **	Parameters:
3535196Seric **		p -- name to build.
3545196Seric **		login -- the login name of this user (for &).
3555196Seric **		buf -- place to put the result.
3564375Seric **
3574375Seric **	Returns:
3584375Seric **		none.
3594375Seric **
3604375Seric **	Side Effects:
3614375Seric **		none.
3624375Seric */
3634375Seric 
3645196Seric buildfname(p, login, buf)
3655196Seric 	register char *p;
3665196Seric 	char *login;
3674375Seric 	char *buf;
3684375Seric {
3694375Seric 	register char *bp = buf;
3704375Seric 
3714438Seric 	if (*p == '*')
3724438Seric 		p++;
3736278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3744375Seric 	{
3754375Seric 		if (*p == '&')
3764375Seric 		{
3775196Seric 			(void) strcpy(bp, login);
3784375Seric 			*bp = toupper(*bp);
3794375Seric 			while (*bp != '\0')
3804375Seric 				bp++;
3814375Seric 			p++;
3824375Seric 		}
3834375Seric 		else
3844375Seric 			*bp++ = *p++;
3854375Seric 	}
3864375Seric 	*bp = '\0';
3874375Seric }
3884375Seric /*
3894538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3904538Seric **
3914538Seric **	Parameters:
3924538Seric **		fn -- filename to check.
3934538Seric **		uid -- uid to compare against.
3944538Seric **		mode -- mode bits that must match.
3954538Seric **
3964538Seric **	Returns:
3974538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
3984538Seric **		FALSE otherwise.
3994538Seric **
4004538Seric **	Side Effects:
4014538Seric **		none.
4024538Seric */
4034538Seric 
4044538Seric bool
4054538Seric safefile(fn, uid, mode)
4064538Seric 	char *fn;
4074538Seric 	int uid;
4084538Seric 	int mode;
4094538Seric {
4104538Seric 	struct stat stbuf;
4114538Seric 
4124538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
4134538Seric 	    (stbuf.st_mode & mode) == mode)
4144538Seric 		return (TRUE);
41511936Seric 	errno = 0;
4164538Seric 	return (FALSE);
4174538Seric }
4184538Seric /*
4194557Seric **  FIXCRLF -- fix <CR><LF> in line.
4204557Seric **
4214557Seric **	Looks for the <CR><LF> combination and turns it into the
4224557Seric **	UNIX canonical <NL> character.  It only takes one line,
4234557Seric **	i.e., it is assumed that the first <NL> found is the end
4244557Seric **	of the line.
4254557Seric **
4264557Seric **	Parameters:
4274557Seric **		line -- the line to fix.
4284557Seric **		stripnl -- if true, strip the newline also.
4294557Seric **
4304557Seric **	Returns:
4314557Seric **		none.
4324557Seric **
4334557Seric **	Side Effects:
4344557Seric **		line is changed in place.
4354557Seric */
4364557Seric 
4374557Seric fixcrlf(line, stripnl)
4384557Seric 	char *line;
4394557Seric 	bool stripnl;
4404557Seric {
4414557Seric 	register char *p;
4424557Seric 
4434557Seric 	p = index(line, '\n');
4444557Seric 	if (p == NULL)
4454557Seric 		return;
44636291Sbostic 	if (p > line && p[-1] == '\r')
4474557Seric 		p--;
4484557Seric 	if (!stripnl)
4494557Seric 		*p++ = '\n';
4504557Seric 	*p = '\0';
4514557Seric }
4524557Seric /*
4536890Seric **  DFOPEN -- determined file open
4546890Seric **
4556890Seric **	This routine has the semantics of fopen, except that it will
4566890Seric **	keep trying a few times to make this happen.  The idea is that
4576890Seric **	on very loaded systems, we may run out of resources (inodes,
4586890Seric **	whatever), so this tries to get around it.
4596890Seric */
4606890Seric 
4616890Seric FILE *
4626890Seric dfopen(filename, mode)
4636890Seric 	char *filename;
4646890Seric 	char *mode;
4656890Seric {
4666890Seric 	register int tries;
4676890Seric 	register FILE *fp;
4686890Seric 
4696890Seric 	for (tries = 0; tries < 10; tries++)
4706890Seric 	{
47125618Seric 		sleep((unsigned) (10 * tries));
4726890Seric 		errno = 0;
4736890Seric 		fp = fopen(filename, mode);
4749376Seric 		if (fp != NULL)
4756890Seric 			break;
4769376Seric 		if (errno != ENFILE && errno != EINTR)
4779376Seric 			break;
4786890Seric 	}
47911936Seric 	errno = 0;
4806890Seric 	return (fp);
4816890Seric }
4827124Seric /*
4837124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4847124Seric **
4857753Seric **	This routine always guarantees outputing a newline (or CRLF,
4867753Seric **	as appropriate) at the end of the string.
4877753Seric **
4887124Seric **	Parameters:
4897124Seric **		l -- line to put.
4907124Seric **		fp -- file to put it onto.
49110172Seric **		m -- the mailer used to control output.
4927124Seric **
4937124Seric **	Returns:
4947124Seric **		none
4957124Seric **
4967124Seric **	Side Effects:
4977124Seric **		output of l to fp.
4987124Seric */
4997124Seric 
50010172Seric putline(l, fp, m)
5017753Seric 	register char *l;
5027124Seric 	FILE *fp;
50310172Seric 	MAILER *m;
5047124Seric {
5057124Seric 	register char *p;
50647157Sbostic 	register char svchar;
5077124Seric 
50811275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
509*52106Seric 	if (bitnset(M_7BITS, m->m_flags))
51011275Seric 	{
51147157Sbostic 		for (p = l; svchar = *p; ++p)
51247157Sbostic 			if (svchar & 0200)
51347157Sbostic 				*p = svchar &~ 0200;
51411275Seric 	}
51511275Seric 
5167753Seric 	do
5177124Seric 	{
5187753Seric 		/* find the end of the line */
5197753Seric 		p = index(l, '\n');
5207753Seric 		if (p == NULL)
5217753Seric 			p = &l[strlen(l)];
5227124Seric 
5237753Seric 		/* check for line overflow */
524*52106Seric 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
5257753Seric 		{
526*52106Seric 			register char *q = &l[m->m_linelimit - 1];
5277124Seric 
5287753Seric 			svchar = *q;
5297753Seric 			*q = '\0';
53010685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
53123105Seric 				(void) putc('.', fp);
5327753Seric 			fputs(l, fp);
53323105Seric 			(void) putc('!', fp);
53410326Seric 			fputs(m->m_eol, fp);
5357753Seric 			*q = svchar;
5367753Seric 			l = q;
5377753Seric 		}
5387124Seric 
5397753Seric 		/* output last part */
54010685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
54123105Seric 			(void) putc('.', fp);
54247157Sbostic 		for ( ; l < p; ++l)
54347157Sbostic 			(void) putc(*l, fp);
54410326Seric 		fputs(m->m_eol, fp);
5457753Seric 		if (*l == '\n')
54647157Sbostic 			++l;
5477753Seric 	} while (l[0] != '\0');
5487124Seric }
5497676Seric /*
5507676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5517676Seric **
5527676Seric **	Parameters:
5537676Seric **		f -- name of file to unlink.
5547676Seric **
5557676Seric **	Returns:
5567676Seric **		none.
5577676Seric **
5587676Seric **	Side Effects:
5597676Seric **		f is unlinked.
5607676Seric */
5617676Seric 
5627676Seric xunlink(f)
5637676Seric 	char *f;
5647676Seric {
5657676Seric 	register int i;
5667676Seric 
5677676Seric # ifdef LOG
5687676Seric 	if (LogLevel > 20)
5697812Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
5707676Seric # endif LOG
5717676Seric 
5727676Seric 	i = unlink(f);
5737676Seric # ifdef LOG
5747676Seric 	if (i < 0 && LogLevel > 21)
5757942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
5767676Seric # endif LOG
5777676Seric }
5787685Seric /*
57914885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
5807685Seric **
5817685Seric **	Parameters:
5827685Seric **		buf -- place to put the input line.
5837685Seric **		siz -- size of buf.
5847685Seric **		fp -- file to read from.
5857685Seric **
5867685Seric **	Returns:
58715533Seric **		NULL on error (including timeout).  This will also leave
58815533Seric **			buf containing a null string.
5897685Seric **		buf otherwise.
5907685Seric **
5917685Seric **	Side Effects:
5927685Seric **		none.
5937685Seric */
5947685Seric 
59514885Seric static jmp_buf	CtxReadTimeout;
5967685Seric 
5977685Seric char *
5987685Seric sfgets(buf, siz, fp)
5997685Seric 	char *buf;
6007685Seric 	int siz;
6017685Seric 	FILE *fp;
6027685Seric {
6037942Seric 	register EVENT *ev = NULL;
6047685Seric 	register char *p;
60546928Sbostic 	static int readtimeout();
6067685Seric 
60714885Seric 	/* set the timeout */
6087942Seric 	if (ReadTimeout != 0)
60914885Seric 	{
61014885Seric 		if (setjmp(CtxReadTimeout) != 0)
61114885Seric 		{
61236233Skarels # ifdef LOG
61336230Skarels 			syslog(LOG_NOTICE,
61436230Skarels 			    "timeout waiting for input from %s\n",
61540998Sbostic 			    RealHostName? RealHostName: "local");
61636233Skarels # endif
61736230Skarels 			errno = 0;
61840964Sbostic 			usrerr("451 timeout waiting for input");
61919037Seric 			buf[0] = '\0';
62014885Seric 			return (NULL);
62114885Seric 		}
62216138Seric 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
62314885Seric 	}
62414885Seric 
62514885Seric 	/* try to read */
62615533Seric 	p = NULL;
62715533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6287942Seric 	{
6297942Seric 		errno = 0;
6307942Seric 		p = fgets(buf, siz, fp);
63115533Seric 		if (errno == EINTR)
63215533Seric 			clearerr(fp);
63315533Seric 	}
63414885Seric 
63514885Seric 	/* clear the event if it has not sprung */
6367685Seric 	clrevent(ev);
63714885Seric 
63814885Seric 	/* clean up the books and exit */
6398055Seric 	LineNumber++;
64015533Seric 	if (p == NULL)
64116880Seric 	{
64215533Seric 		buf[0] = '\0';
64316880Seric 		return (NULL);
64416880Seric 	}
645*52106Seric 	if (!EightBit)
646*52106Seric 		for (p = buf; *p != '\0'; p++)
647*52106Seric 			*p &= ~0200;
64816880Seric 	return (buf);
6497685Seric }
6507685Seric 
6517685Seric static
6527685Seric readtimeout()
6537685Seric {
65414885Seric 	longjmp(CtxReadTimeout, 1);
6557685Seric }
6567786Seric /*
6577786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6587786Seric **
6597786Seric **	Parameters:
6607786Seric **		buf -- place to put result.
6617786Seric **		n -- bytes available.
6627786Seric **		f -- file to read from.
6637786Seric **
6647786Seric **	Returns:
6657786Seric **		buf on success, NULL on error or EOF.
6667786Seric **
6677786Seric **	Side Effects:
6687786Seric **		buf gets lines from f, with continuation lines (lines
6697786Seric **		with leading white space) appended.  CRLF's are mapped
6707786Seric **		into single newlines.  Any trailing NL is stripped.
6717786Seric */
6727786Seric 
6737786Seric char *
6747786Seric fgetfolded(buf, n, f)
6757786Seric 	char *buf;
6767786Seric 	register int n;
6777786Seric 	FILE *f;
6787786Seric {
6797786Seric 	register char *p = buf;
6807786Seric 	register int i;
6817786Seric 
6827786Seric 	n--;
68317350Seric 	while ((i = getc(f)) != EOF)
6847786Seric 	{
68517350Seric 		if (i == '\r')
68617350Seric 		{
68717350Seric 			i = getc(f);
68817350Seric 			if (i != '\n')
68917350Seric 			{
69017350Seric 				if (i != EOF)
69123105Seric 					(void) ungetc(i, f);
69217350Seric 				i = '\r';
69317350Seric 			}
69417350Seric 		}
69517350Seric 		if (--n > 0)
69617350Seric 			*p++ = i;
69717350Seric 		if (i == '\n')
69817350Seric 		{
69917350Seric 			LineNumber++;
70017350Seric 			i = getc(f);
70117350Seric 			if (i != EOF)
70223105Seric 				(void) ungetc(i, f);
70317350Seric 			if (i != ' ' && i != '\t')
70417350Seric 			{
70517350Seric 				*--p = '\0';
706*52106Seric 				if (!EightBit)
707*52106Seric 				{
708*52106Seric 					/* headers always have to be 7-bit */
709*52106Seric 					for (p = buf; (i = *p) != '\0'; *p++)
710*52106Seric 						if (bitset(0200, i))
711*52106Seric 							*p = i & ~0200;
712*52106Seric 				}
71317350Seric 				return (buf);
71417350Seric 			}
71517350Seric 		}
7167786Seric 	}
7177786Seric 	return (NULL);
7187786Seric }
7197860Seric /*
7207886Seric **  CURTIME -- return current time.
7217886Seric **
7227886Seric **	Parameters:
7237886Seric **		none.
7247886Seric **
7257886Seric **	Returns:
7267886Seric **		the current time.
7277886Seric **
7287886Seric **	Side Effects:
7297886Seric **		none.
7307886Seric */
7317886Seric 
7327886Seric time_t
7337886Seric curtime()
7347886Seric {
7357886Seric 	auto time_t t;
7367886Seric 
7377886Seric 	(void) time(&t);
7387886Seric 	return (t);
7397886Seric }
7408264Seric /*
7418264Seric **  ATOBOOL -- convert a string representation to boolean.
7428264Seric **
7438264Seric **	Defaults to "TRUE"
7448264Seric **
7458264Seric **	Parameters:
7468264Seric **		s -- string to convert.  Takes "tTyY" as true,
7478264Seric **			others as false.
7488264Seric **
7498264Seric **	Returns:
7508264Seric **		A boolean representation of the string.
7518264Seric **
7528264Seric **	Side Effects:
7538264Seric **		none.
7548264Seric */
7558264Seric 
7568264Seric bool
7578264Seric atobool(s)
7588264Seric 	register char *s;
7598264Seric {
7608264Seric 	if (*s == '\0' || index("tTyY", *s) != NULL)
7618264Seric 		return (TRUE);
7628264Seric 	return (FALSE);
7638264Seric }
7649048Seric /*
7659048Seric **  ATOOCT -- convert a string representation to octal.
7669048Seric **
7679048Seric **	Parameters:
7689048Seric **		s -- string to convert.
7699048Seric **
7709048Seric **	Returns:
7719048Seric **		An integer representing the string interpreted as an
7729048Seric **		octal number.
7739048Seric **
7749048Seric **	Side Effects:
7759048Seric **		none.
7769048Seric */
7779048Seric 
7789048Seric atooct(s)
7799048Seric 	register char *s;
7809048Seric {
7819048Seric 	register int i = 0;
7829048Seric 
7839048Seric 	while (*s >= '0' && *s <= '7')
7849048Seric 		i = (i << 3) | (*s++ - '0');
7859048Seric 	return (i);
7869048Seric }
7879376Seric /*
7889376Seric **  WAITFOR -- wait for a particular process id.
7899376Seric **
7909376Seric **	Parameters:
7919376Seric **		pid -- process id to wait for.
7929376Seric **
7939376Seric **	Returns:
7949376Seric **		status of pid.
7959376Seric **		-1 if pid never shows up.
7969376Seric **
7979376Seric **	Side Effects:
7989376Seric **		none.
7999376Seric */
8009376Seric 
8019376Seric waitfor(pid)
8029376Seric 	int pid;
8039376Seric {
8049376Seric 	auto int st;
8059376Seric 	int i;
8069376Seric 
8079376Seric 	do
8089376Seric 	{
8099376Seric 		errno = 0;
8109376Seric 		i = wait(&st);
8119376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
8129376Seric 	if (i < 0)
8139376Seric 		st = -1;
8149376Seric 	return (st);
8159376Seric }
8169376Seric /*
81710685Seric **  BITINTERSECT -- tell if two bitmaps intersect
81810685Seric **
81910685Seric **	Parameters:
82010685Seric **		a, b -- the bitmaps in question
82110685Seric **
82210685Seric **	Returns:
82310685Seric **		TRUE if they have a non-null intersection
82410685Seric **		FALSE otherwise
82510685Seric **
82610685Seric **	Side Effects:
82710685Seric **		none.
82810685Seric */
82910685Seric 
83010685Seric bool
83110685Seric bitintersect(a, b)
83210685Seric 	BITMAP a;
83310685Seric 	BITMAP b;
83410685Seric {
83510685Seric 	int i;
83610685Seric 
83710685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
83810685Seric 		if ((a[i] & b[i]) != 0)
83910685Seric 			return (TRUE);
84010685Seric 	return (FALSE);
84110685Seric }
84210685Seric /*
84310685Seric **  BITZEROP -- tell if a bitmap is all zero
84410685Seric **
84510685Seric **	Parameters:
84610685Seric **		map -- the bit map to check
84710685Seric **
84810685Seric **	Returns:
84910685Seric **		TRUE if map is all zero.
85010685Seric **		FALSE if there are any bits set in map.
85110685Seric **
85210685Seric **	Side Effects:
85310685Seric **		none.
85410685Seric */
85510685Seric 
85610685Seric bool
85710685Seric bitzerop(map)
85810685Seric 	BITMAP map;
85910685Seric {
86010685Seric 	int i;
86110685Seric 
86210685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
86310685Seric 		if (map[i] != 0)
86410685Seric 			return (FALSE);
86510685Seric 	return (TRUE);
86610685Seric }
867