xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 57384)
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*57384Seric static char sccsid[] = "@(#)util.c	6.2 (Berkeley) 01/01/93";
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"
1957135Seric /*
20298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
21298Seric **
22298Seric **	Runs through a string and strips off unquoted quote
23298Seric **	characters and quote bits.  This is done in place.
24298Seric **
25298Seric **	Parameters:
26298Seric **		s -- the string to strip.
27298Seric **
28298Seric **	Returns:
29298Seric **		none.
30298Seric **
31298Seric **	Side Effects:
32298Seric **		none.
33298Seric **
34298Seric **	Called By:
35298Seric **		deliver
36298Seric */
37298Seric 
3854983Seric stripquotes(s)
39298Seric 	char *s;
40298Seric {
41298Seric 	register char *p;
42298Seric 	register char *q;
43298Seric 	register char c;
44298Seric 
454101Seric 	if (s == NULL)
464101Seric 		return;
474101Seric 
4854983Seric 	p = q = s;
4954983Seric 	do
50298Seric 	{
5154983Seric 		c = *p++;
5254983Seric 		if (c == '\\')
5354983Seric 			c = *p++;
5454983Seric 		else if (c == '"')
5554983Seric 			continue;
5654983Seric 		*q++ = c;
5754983Seric 	} while (c != '\0');
58298Seric }
59298Seric /*
602900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
612900Seric **
622900Seric **	Parameters:
632900Seric **		s -- the string to capitalize.
642900Seric **
652900Seric **	Returns:
662900Seric **		a pointer to a properly capitalized string.
672900Seric **
682900Seric **	Side Effects:
692900Seric **		none.
702900Seric */
712900Seric 
722900Seric char *
732900Seric capitalize(s)
742900Seric 	register char *s;
752900Seric {
762900Seric 	static char buf[50];
772900Seric 	register char *p;
782900Seric 
792900Seric 	p = buf;
802900Seric 
812900Seric 	for (;;)
822900Seric 	{
832900Seric 		while (!isalpha(*s) && *s != '\0')
842900Seric 			*p++ = *s++;
852900Seric 		if (*s == '\0')
862900Seric 			break;
8740999Sbostic 		*p++ = toupper(*s);
8840999Sbostic 		s++;
892900Seric 		while (isalpha(*s))
902900Seric 			*p++ = *s++;
912900Seric 	}
922900Seric 
932900Seric 	*p = '\0';
942900Seric 	return (buf);
952900Seric }
962900Seric /*
97298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
98298Seric **
99298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
100298Seric **	error -- but after all, what can we do?
101298Seric **
102298Seric **	Parameters:
103298Seric **		sz -- size of area to allocate.
104298Seric **
105298Seric **	Returns:
106298Seric **		pointer to data region.
107298Seric **
108298Seric **	Side Effects:
109298Seric **		Memory is allocated.
110298Seric */
111298Seric 
112298Seric char *
113298Seric xalloc(sz)
1147007Seric 	register int sz;
115298Seric {
116298Seric 	register char *p;
117298Seric 
11823121Seric 	p = malloc((unsigned) sz);
119298Seric 	if (p == NULL)
120298Seric 	{
121298Seric 		syserr("Out of memory!!");
12210685Seric 		abort();
12310685Seric 		/* exit(EX_UNAVAILABLE); */
124298Seric 	}
125298Seric 	return (p);
126298Seric }
127298Seric /*
1283151Seric **  COPYPLIST -- copy list of pointers.
1293151Seric **
1303151Seric **	This routine is the equivalent of newstr for lists of
1313151Seric **	pointers.
1323151Seric **
1333151Seric **	Parameters:
1343151Seric **		list -- list of pointers to copy.
1353151Seric **			Must be NULL terminated.
1363151Seric **		copycont -- if TRUE, copy the contents of the vector
1373151Seric **			(which must be a string) also.
1383151Seric **
1393151Seric **	Returns:
1403151Seric **		a copy of 'list'.
1413151Seric **
1423151Seric **	Side Effects:
1433151Seric **		none.
1443151Seric */
1453151Seric 
1463151Seric char **
1473151Seric copyplist(list, copycont)
1483151Seric 	char **list;
1493151Seric 	bool copycont;
1503151Seric {
1513151Seric 	register char **vp;
1523151Seric 	register char **newvp;
1533151Seric 
1543151Seric 	for (vp = list; *vp != NULL; vp++)
1553151Seric 		continue;
1563151Seric 
1573151Seric 	vp++;
1583151Seric 
15916897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
16016897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1613151Seric 
1623151Seric 	if (copycont)
1633151Seric 	{
1643151Seric 		for (vp = newvp; *vp != NULL; vp++)
1653151Seric 			*vp = newstr(*vp);
1663151Seric 	}
1673151Seric 
1683151Seric 	return (newvp);
1693151Seric }
1703151Seric /*
1713151Seric **  PRINTAV -- print argument vector.
1723151Seric **
1733151Seric **	Parameters:
1743151Seric **		av -- argument vector.
1753151Seric **
1763151Seric **	Returns:
1773151Seric **		none.
1783151Seric **
1793151Seric **	Side Effects:
1803151Seric **		prints av.
1813151Seric */
1823151Seric 
1833151Seric printav(av)
1843151Seric 	register char **av;
1853151Seric {
1863151Seric 	while (*av != NULL)
1873151Seric 	{
1888063Seric 		if (tTd(0, 44))
1898063Seric 			printf("\n\t%08x=", *av);
1908063Seric 		else
19123105Seric 			(void) putchar(' ');
1923151Seric 		xputs(*av++);
1933151Seric 	}
19423105Seric 	(void) putchar('\n');
1953151Seric }
1963151Seric /*
1973151Seric **  LOWER -- turn letter into lower case.
1983151Seric **
1993151Seric **	Parameters:
2003151Seric **		c -- character to turn into lower case.
2013151Seric **
2023151Seric **	Returns:
2033151Seric **		c, in lower case.
2043151Seric **
2053151Seric **	Side Effects:
2063151Seric **		none.
2073151Seric */
2083151Seric 
2093151Seric char
2103151Seric lower(c)
2113151Seric 	register char c;
2123151Seric {
21333724Sbostic 	return(isascii(c) && isupper(c) ? tolower(c) : c);
2143151Seric }
2153151Seric /*
2163151Seric **  XPUTS -- put string doing control escapes.
2173151Seric **
2183151Seric **	Parameters:
2193151Seric **		s -- string to put.
2203151Seric **
2213151Seric **	Returns:
2223151Seric **		none.
2233151Seric **
2243151Seric **	Side Effects:
2253151Seric **		output to stdout
2263151Seric */
2273151Seric 
2283151Seric xputs(s)
2293151Seric 	register char *s;
2303151Seric {
2313151Seric 	register char c;
23251781Seric 	register struct metamac *mp;
23351781Seric 	extern struct metamac MetaMacros[];
2343151Seric 
2358055Seric 	if (s == NULL)
2368055Seric 	{
2378055Seric 		printf("<null>");
2388055Seric 		return;
2398055Seric 	}
24051781Seric 	c = *s;
24151781Seric 	if (c == MATCHREPL && isdigit(s[1]) && s[2] == '\0')
24251781Seric 	{
24351781Seric 		printf("$%c", s[1]);
24451781Seric 		return;
24551781Seric 	}
24651781Seric 	for (mp = MetaMacros; mp->metaname != NULL; mp++)
24751781Seric 	{
24851781Seric 		if (mp->metaval == c)
24951781Seric 		{
25051781Seric 			printf("$%c%s", mp->metaname, ++s);
25151781Seric 			return;
25251781Seric 		}
25351781Seric 	}
25423105Seric 	(void) putchar('"');
2553151Seric 	while ((c = *s++) != '\0')
2563151Seric 	{
2573151Seric 		if (!isascii(c))
2583151Seric 		{
25923105Seric 			(void) putchar('\\');
2603151Seric 			c &= 0177;
2613151Seric 		}
26210326Seric 		if (c < 040 || c >= 0177)
2633151Seric 		{
26452050Seric 			switch (c)
26552050Seric 			{
26652050Seric 			  case '\n':
26752050Seric 				c = 'n';
26852050Seric 				break;
26952050Seric 
27052050Seric 			  case '\r':
27152050Seric 				c = 'r';
27252050Seric 				break;
27352050Seric 
27452050Seric 			  case '\t':
27552050Seric 				c = 't';
27652050Seric 				break;
27752050Seric 
27852637Seric 			  case '\001':
27952637Seric 				(void) putchar('$');
28052637Seric 				continue;
28152637Seric 
28252050Seric 			  default:
28352050Seric 				(void) putchar('^');
28452050Seric 				(void) putchar(c ^ 0100);
28552050Seric 				continue;
28652050Seric 			}
28752050Seric 			(void) putchar('\\');
2883151Seric 		}
28923105Seric 		(void) putchar(c);
2903151Seric 	}
29123105Seric 	(void) putchar('"');
2924086Seric 	(void) fflush(stdout);
2933151Seric }
2943151Seric /*
2953151Seric **  MAKELOWER -- Translate a line into lower case
2963151Seric **
2973151Seric **	Parameters:
2983151Seric **		p -- the string to translate.  If NULL, return is
2993151Seric **			immediate.
3003151Seric **
3013151Seric **	Returns:
3023151Seric **		none.
3033151Seric **
3043151Seric **	Side Effects:
3053151Seric **		String pointed to by p is translated to lower case.
3063151Seric **
3073151Seric **	Called By:
3083151Seric **		parse
3093151Seric */
3103151Seric 
3113151Seric makelower(p)
3123151Seric 	register char *p;
3133151Seric {
3143151Seric 	register char c;
3153151Seric 
3163151Seric 	if (p == NULL)
3173151Seric 		return;
3183151Seric 	for (; (c = *p) != '\0'; p++)
3193151Seric 		if (isascii(c) && isupper(c))
32033724Sbostic 			*p = tolower(c);
3213151Seric }
3224059Seric /*
3235196Seric **  BUILDFNAME -- build full name from gecos style entry.
3244375Seric **
3255196Seric **	This routine interprets the strange entry that would appear
3265196Seric **	in the GECOS field of the password file.
3275196Seric **
3284375Seric **	Parameters:
3295196Seric **		p -- name to build.
3305196Seric **		login -- the login name of this user (for &).
3315196Seric **		buf -- place to put the result.
3324375Seric **
3334375Seric **	Returns:
3344375Seric **		none.
3354375Seric **
3364375Seric **	Side Effects:
3374375Seric **		none.
3384375Seric */
3394375Seric 
34054984Seric buildfname(gecos, login, buf)
34154984Seric 	register char *gecos;
3425196Seric 	char *login;
3434375Seric 	char *buf;
3444375Seric {
34554984Seric 	register char *p;
3464375Seric 	register char *bp = buf;
34754984Seric 	int l;
3484375Seric 
34954984Seric 	if (*gecos == '*')
35054984Seric 		gecos++;
35154984Seric 
35257123Seric 	/* find length of final string */
35354984Seric 	l = 0;
35454984Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
35554984Seric 	{
35654984Seric 		if (*p == '&')
35754984Seric 			l += strlen(login);
35854984Seric 		else
35954984Seric 			l++;
36054984Seric 	}
36154984Seric 
36254984Seric 	/* now fill in buf */
36355193Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
3644375Seric 	{
3654375Seric 		if (*p == '&')
3664375Seric 		{
3675196Seric 			(void) strcpy(bp, login);
3684375Seric 			*bp = toupper(*bp);
3694375Seric 			while (*bp != '\0')
3704375Seric 				bp++;
3714375Seric 		}
3724375Seric 		else
37355193Seric 			*bp++ = *p;
3744375Seric 	}
3754375Seric 	*bp = '\0';
3764375Seric }
3774375Seric /*
3784538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3794538Seric **
3804538Seric **	Parameters:
3814538Seric **		fn -- filename to check.
3824538Seric **		uid -- uid to compare against.
3834538Seric **		mode -- mode bits that must match.
3844538Seric **
3854538Seric **	Returns:
3864538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
3874538Seric **		FALSE otherwise.
3884538Seric **
3894538Seric **	Side Effects:
3904538Seric **		none.
3914538Seric */
3924538Seric 
3934538Seric bool
3944538Seric safefile(fn, uid, mode)
3954538Seric 	char *fn;
39655372Seric 	uid_t uid;
3974538Seric 	int mode;
3984538Seric {
3994538Seric 	struct stat stbuf;
4004538Seric 
4014538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
4024538Seric 	    (stbuf.st_mode & mode) == mode)
4034538Seric 		return (TRUE);
40411936Seric 	errno = 0;
4054538Seric 	return (FALSE);
4064538Seric }
4074538Seric /*
4084557Seric **  FIXCRLF -- fix <CR><LF> in line.
4094557Seric **
4104557Seric **	Looks for the <CR><LF> combination and turns it into the
4114557Seric **	UNIX canonical <NL> character.  It only takes one line,
4124557Seric **	i.e., it is assumed that the first <NL> found is the end
4134557Seric **	of the line.
4144557Seric **
4154557Seric **	Parameters:
4164557Seric **		line -- the line to fix.
4174557Seric **		stripnl -- if true, strip the newline also.
4184557Seric **
4194557Seric **	Returns:
4204557Seric **		none.
4214557Seric **
4224557Seric **	Side Effects:
4234557Seric **		line is changed in place.
4244557Seric */
4254557Seric 
4264557Seric fixcrlf(line, stripnl)
4274557Seric 	char *line;
4284557Seric 	bool stripnl;
4294557Seric {
4304557Seric 	register char *p;
4314557Seric 
43256795Seric 	p = strchr(line, '\n');
4334557Seric 	if (p == NULL)
4344557Seric 		return;
43536291Sbostic 	if (p > line && p[-1] == '\r')
4364557Seric 		p--;
4374557Seric 	if (!stripnl)
4384557Seric 		*p++ = '\n';
4394557Seric 	*p = '\0';
4404557Seric }
4414557Seric /*
4426890Seric **  DFOPEN -- determined file open
4436890Seric **
4446890Seric **	This routine has the semantics of fopen, except that it will
4456890Seric **	keep trying a few times to make this happen.  The idea is that
4466890Seric **	on very loaded systems, we may run out of resources (inodes,
4476890Seric **	whatever), so this tries to get around it.
4486890Seric */
4496890Seric 
4506890Seric FILE *
4516890Seric dfopen(filename, mode)
4526890Seric 	char *filename;
4536890Seric 	char *mode;
4546890Seric {
4556890Seric 	register int tries;
4566890Seric 	register FILE *fp;
4576890Seric 
4586890Seric 	for (tries = 0; tries < 10; tries++)
4596890Seric 	{
46025618Seric 		sleep((unsigned) (10 * tries));
4616890Seric 		errno = 0;
4626890Seric 		fp = fopen(filename, mode);
4639376Seric 		if (fp != NULL)
4646890Seric 			break;
4659376Seric 		if (errno != ENFILE && errno != EINTR)
4669376Seric 			break;
4676890Seric 	}
46856328Seric 	if (fp != NULL)
46956328Seric 	{
47056328Seric #ifdef FLOCK
47156328Seric 		int locktype;
47256328Seric 
47356328Seric 		/* lock the file to avoid accidental conflicts */
47456328Seric 		if (*mode == 'w' || *mode == 'a')
47556328Seric 			locktype = LOCK_EX;
47656328Seric 		else
47756328Seric 			locktype = LOCK_SH;
47856328Seric 		(void) flock(fileno(fp), locktype);
47956328Seric #endif
48056328Seric 		errno = 0;
48156328Seric 	}
4826890Seric 	return (fp);
4836890Seric }
4847124Seric /*
4857124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4867124Seric **
4877753Seric **	This routine always guarantees outputing a newline (or CRLF,
4887753Seric **	as appropriate) at the end of the string.
4897753Seric **
4907124Seric **	Parameters:
4917124Seric **		l -- line to put.
4927124Seric **		fp -- file to put it onto.
49310172Seric **		m -- the mailer used to control output.
4947124Seric **
4957124Seric **	Returns:
4967124Seric **		none
4977124Seric **
4987124Seric **	Side Effects:
4997124Seric **		output of l to fp.
5007124Seric */
5017124Seric 
50210172Seric putline(l, fp, m)
5037753Seric 	register char *l;
5047124Seric 	FILE *fp;
50510172Seric 	MAILER *m;
5067124Seric {
5077124Seric 	register char *p;
50847157Sbostic 	register char svchar;
5097124Seric 
51011275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
51152106Seric 	if (bitnset(M_7BITS, m->m_flags))
51211275Seric 	{
51347157Sbostic 		for (p = l; svchar = *p; ++p)
51447157Sbostic 			if (svchar & 0200)
51547157Sbostic 				*p = svchar &~ 0200;
51611275Seric 	}
51711275Seric 
5187753Seric 	do
5197124Seric 	{
5207753Seric 		/* find the end of the line */
52156795Seric 		p = strchr(l, '\n');
5227753Seric 		if (p == NULL)
5237753Seric 			p = &l[strlen(l)];
5247124Seric 
5257753Seric 		/* check for line overflow */
52652106Seric 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
5277753Seric 		{
52852106Seric 			register char *q = &l[m->m_linelimit - 1];
5297124Seric 
5307753Seric 			svchar = *q;
5317753Seric 			*q = '\0';
53210685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
53323105Seric 				(void) putc('.', fp);
5347753Seric 			fputs(l, fp);
53523105Seric 			(void) putc('!', fp);
53610326Seric 			fputs(m->m_eol, fp);
5377753Seric 			*q = svchar;
5387753Seric 			l = q;
5397753Seric 		}
5407124Seric 
5417753Seric 		/* output last part */
54210685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
54323105Seric 			(void) putc('.', fp);
54447157Sbostic 		for ( ; l < p; ++l)
54547157Sbostic 			(void) putc(*l, fp);
54610326Seric 		fputs(m->m_eol, fp);
5477753Seric 		if (*l == '\n')
54847157Sbostic 			++l;
5497753Seric 	} while (l[0] != '\0');
5507124Seric }
5517676Seric /*
5527676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5537676Seric **
5547676Seric **	Parameters:
5557676Seric **		f -- name of file to unlink.
5567676Seric **
5577676Seric **	Returns:
5587676Seric **		none.
5597676Seric **
5607676Seric **	Side Effects:
5617676Seric **		f is unlinked.
5627676Seric */
5637676Seric 
5647676Seric xunlink(f)
5657676Seric 	char *f;
5667676Seric {
5677676Seric 	register int i;
5687676Seric 
5697676Seric # ifdef LOG
5707676Seric 	if (LogLevel > 20)
5717812Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
57256795Seric # endif /* LOG */
5737676Seric 
5747676Seric 	i = unlink(f);
5757676Seric # ifdef LOG
5767676Seric 	if (i < 0 && LogLevel > 21)
5777942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
57856795Seric # endif /* LOG */
5797676Seric }
5807685Seric /*
58114885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
5827685Seric **
5837685Seric **	Parameters:
5847685Seric **		buf -- place to put the input line.
5857685Seric **		siz -- size of buf.
5867685Seric **		fp -- file to read from.
587*57384Seric **		timeout -- the timeout before error occurs.
5887685Seric **
5897685Seric **	Returns:
59015533Seric **		NULL on error (including timeout).  This will also leave
59115533Seric **			buf containing a null string.
5927685Seric **		buf otherwise.
5937685Seric **
5947685Seric **	Side Effects:
5957685Seric **		none.
5967685Seric */
5977685Seric 
59814885Seric static jmp_buf	CtxReadTimeout;
5997685Seric 
6007685Seric char *
601*57384Seric sfgets(buf, siz, fp, timeout)
6027685Seric 	char *buf;
6037685Seric 	int siz;
6047685Seric 	FILE *fp;
605*57384Seric 	time_t timeout;
6067685Seric {
6077942Seric 	register EVENT *ev = NULL;
6087685Seric 	register char *p;
60946928Sbostic 	static int readtimeout();
6107685Seric 
61114885Seric 	/* set the timeout */
612*57384Seric 	if (timeout != 0)
61314885Seric 	{
61414885Seric 		if (setjmp(CtxReadTimeout) != 0)
61514885Seric 		{
61636233Skarels # ifdef LOG
61736230Skarels 			syslog(LOG_NOTICE,
61836230Skarels 			    "timeout waiting for input from %s\n",
61940998Sbostic 			    RealHostName? RealHostName: "local");
62036233Skarels # endif
62136230Skarels 			errno = 0;
62240964Sbostic 			usrerr("451 timeout waiting for input");
62319037Seric 			buf[0] = '\0';
62414885Seric 			return (NULL);
62514885Seric 		}
626*57384Seric 		ev = setevent(timeout, readtimeout, 0);
62714885Seric 	}
62814885Seric 
62914885Seric 	/* try to read */
63015533Seric 	p = NULL;
63115533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6327942Seric 	{
6337942Seric 		errno = 0;
6347942Seric 		p = fgets(buf, siz, fp);
63515533Seric 		if (errno == EINTR)
63615533Seric 			clearerr(fp);
63715533Seric 	}
63814885Seric 
63914885Seric 	/* clear the event if it has not sprung */
6407685Seric 	clrevent(ev);
64114885Seric 
64214885Seric 	/* clean up the books and exit */
6438055Seric 	LineNumber++;
64415533Seric 	if (p == NULL)
64516880Seric 	{
64615533Seric 		buf[0] = '\0';
64716880Seric 		return (NULL);
64816880Seric 	}
64952106Seric 	if (!EightBit)
65052106Seric 		for (p = buf; *p != '\0'; p++)
65152106Seric 			*p &= ~0200;
65216880Seric 	return (buf);
6537685Seric }
6547685Seric 
6557685Seric static
6567685Seric readtimeout()
6577685Seric {
65814885Seric 	longjmp(CtxReadTimeout, 1);
6597685Seric }
6607786Seric /*
6617786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6627786Seric **
6637786Seric **	Parameters:
6647786Seric **		buf -- place to put result.
6657786Seric **		n -- bytes available.
6667786Seric **		f -- file to read from.
6677786Seric **
6687786Seric **	Returns:
66957135Seric **		input line(s) on success, NULL on error or EOF.
67057135Seric **		This will normally be buf -- unless the line is too
67157135Seric **			long, when it will be xalloc()ed.
6727786Seric **
6737786Seric **	Side Effects:
6747786Seric **		buf gets lines from f, with continuation lines (lines
6757786Seric **		with leading white space) appended.  CRLF's are mapped
6767786Seric **		into single newlines.  Any trailing NL is stripped.
6777786Seric */
6787786Seric 
6797786Seric char *
6807786Seric fgetfolded(buf, n, f)
6817786Seric 	char *buf;
6827786Seric 	register int n;
6837786Seric 	FILE *f;
6847786Seric {
6857786Seric 	register char *p = buf;
68657135Seric 	char *bp = buf;
6877786Seric 	register int i;
6887786Seric 
6897786Seric 	n--;
69017350Seric 	while ((i = getc(f)) != EOF)
6917786Seric 	{
69217350Seric 		if (i == '\r')
69317350Seric 		{
69417350Seric 			i = getc(f);
69517350Seric 			if (i != '\n')
69617350Seric 			{
69717350Seric 				if (i != EOF)
69823105Seric 					(void) ungetc(i, f);
69917350Seric 				i = '\r';
70017350Seric 			}
70117350Seric 		}
70257135Seric 		if (--n <= 0)
70357135Seric 		{
70457135Seric 			/* allocate new space */
70557135Seric 			char *nbp;
70657135Seric 			int nn;
70757135Seric 
70857135Seric 			nn = (p - bp);
70957232Seric 			if (nn < MEMCHUNKSIZE)
71057135Seric 				nn *= 2;
71157135Seric 			else
71257232Seric 				nn += MEMCHUNKSIZE;
71357135Seric 			nbp = xalloc(nn);
71457135Seric 			bcopy(bp, nbp, p - bp);
71557135Seric 			p = &nbp[p - bp];
71657135Seric 			if (bp != buf)
71757135Seric 				free(bp);
71857135Seric 			bp = nbp;
71957135Seric 			n = nn - (p - bp);
72057135Seric 		}
72157135Seric 		*p++ = i;
72217350Seric 		if (i == '\n')
72317350Seric 		{
72417350Seric 			LineNumber++;
72517350Seric 			i = getc(f);
72617350Seric 			if (i != EOF)
72723105Seric 				(void) ungetc(i, f);
72817350Seric 			if (i != ' ' && i != '\t')
72952647Seric 				break;
73017350Seric 		}
7317786Seric 	}
73257135Seric 	if (p == bp)
73352647Seric 		return (NULL);
73452647Seric 	*--p = '\0';
73557135Seric 	return (bp);
7367786Seric }
7377860Seric /*
7387886Seric **  CURTIME -- return current time.
7397886Seric **
7407886Seric **	Parameters:
7417886Seric **		none.
7427886Seric **
7437886Seric **	Returns:
7447886Seric **		the current time.
7457886Seric **
7467886Seric **	Side Effects:
7477886Seric **		none.
7487886Seric */
7497886Seric 
7507886Seric time_t
7517886Seric curtime()
7527886Seric {
7537886Seric 	auto time_t t;
7547886Seric 
7557886Seric 	(void) time(&t);
7567886Seric 	return (t);
7577886Seric }
7588264Seric /*
7598264Seric **  ATOBOOL -- convert a string representation to boolean.
7608264Seric **
7618264Seric **	Defaults to "TRUE"
7628264Seric **
7638264Seric **	Parameters:
7648264Seric **		s -- string to convert.  Takes "tTyY" as true,
7658264Seric **			others as false.
7668264Seric **
7678264Seric **	Returns:
7688264Seric **		A boolean representation of the string.
7698264Seric **
7708264Seric **	Side Effects:
7718264Seric **		none.
7728264Seric */
7738264Seric 
7748264Seric bool
7758264Seric atobool(s)
7768264Seric 	register char *s;
7778264Seric {
77856795Seric 	if (*s == '\0' || strchr("tTyY", *s) != NULL)
7798264Seric 		return (TRUE);
7808264Seric 	return (FALSE);
7818264Seric }
7829048Seric /*
7839048Seric **  ATOOCT -- convert a string representation to octal.
7849048Seric **
7859048Seric **	Parameters:
7869048Seric **		s -- string to convert.
7879048Seric **
7889048Seric **	Returns:
7899048Seric **		An integer representing the string interpreted as an
7909048Seric **		octal number.
7919048Seric **
7929048Seric **	Side Effects:
7939048Seric **		none.
7949048Seric */
7959048Seric 
7969048Seric atooct(s)
7979048Seric 	register char *s;
7989048Seric {
7999048Seric 	register int i = 0;
8009048Seric 
8019048Seric 	while (*s >= '0' && *s <= '7')
8029048Seric 		i = (i << 3) | (*s++ - '0');
8039048Seric 	return (i);
8049048Seric }
8059376Seric /*
8069376Seric **  WAITFOR -- wait for a particular process id.
8079376Seric **
8089376Seric **	Parameters:
8099376Seric **		pid -- process id to wait for.
8109376Seric **
8119376Seric **	Returns:
8129376Seric **		status of pid.
8139376Seric **		-1 if pid never shows up.
8149376Seric **
8159376Seric **	Side Effects:
8169376Seric **		none.
8179376Seric */
8189376Seric 
8199376Seric waitfor(pid)
8209376Seric 	int pid;
8219376Seric {
8229376Seric 	auto int st;
8239376Seric 	int i;
8249376Seric 
8259376Seric 	do
8269376Seric 	{
8279376Seric 		errno = 0;
8289376Seric 		i = wait(&st);
8299376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
8309376Seric 	if (i < 0)
8319376Seric 		st = -1;
8329376Seric 	return (st);
8339376Seric }
8349376Seric /*
83510685Seric **  BITINTERSECT -- tell if two bitmaps intersect
83610685Seric **
83710685Seric **	Parameters:
83810685Seric **		a, b -- the bitmaps in question
83910685Seric **
84010685Seric **	Returns:
84110685Seric **		TRUE if they have a non-null intersection
84210685Seric **		FALSE otherwise
84310685Seric **
84410685Seric **	Side Effects:
84510685Seric **		none.
84610685Seric */
84710685Seric 
84810685Seric bool
84910685Seric bitintersect(a, b)
85010685Seric 	BITMAP a;
85110685Seric 	BITMAP b;
85210685Seric {
85310685Seric 	int i;
85410685Seric 
85510685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
85610685Seric 		if ((a[i] & b[i]) != 0)
85710685Seric 			return (TRUE);
85810685Seric 	return (FALSE);
85910685Seric }
86010685Seric /*
86110685Seric **  BITZEROP -- tell if a bitmap is all zero
86210685Seric **
86310685Seric **	Parameters:
86410685Seric **		map -- the bit map to check
86510685Seric **
86610685Seric **	Returns:
86710685Seric **		TRUE if map is all zero.
86810685Seric **		FALSE if there are any bits set in map.
86910685Seric **
87010685Seric **	Side Effects:
87110685Seric **		none.
87210685Seric */
87310685Seric 
87410685Seric bool
87510685Seric bitzerop(map)
87610685Seric 	BITMAP map;
87710685Seric {
87810685Seric 	int i;
87910685Seric 
88010685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
88110685Seric 		if (map[i] != 0)
88210685Seric 			return (FALSE);
88310685Seric 	return (TRUE);
88410685Seric }
885