xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 23105)
122717Sdist /*
222717Sdist **  Sendmail
322717Sdist **  Copyright (c) 1983  Eric P. Allman
422717Sdist **  Berkeley, California
522717Sdist **
622717Sdist **  Copyright (c) 1983 Regents of the University of California.
722717Sdist **  All rights reserved.  The Berkeley software License Agreement
822717Sdist **  specifies the terms and conditions for redistribution.
922717Sdist */
1022717Sdist 
1122717Sdist #ifndef lint
12*23105Seric static char	SccsId[] = "@(#)util.c	5.4 (Berkeley) 06/08/85";
1322717Sdist #endif not lint
1422717Sdist 
153151Seric # include <stdio.h>
164538Seric # include <sys/types.h>
174538Seric # include <sys/stat.h>
18298Seric # include <sysexits.h>
196890Seric # include <errno.h>
202900Seric # include <ctype.h>
216890Seric # include "sendmail.h"
22298Seric 
23298Seric /*
24298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
25298Seric **
26298Seric **	Runs through a string and strips off unquoted quote
27298Seric **	characters and quote bits.  This is done in place.
28298Seric **
29298Seric **	Parameters:
30298Seric **		s -- the string to strip.
314101Seric **		qf -- if set, remove actual `` " '' characters
324101Seric **			as well as the quote bits.
33298Seric **
34298Seric **	Returns:
35298Seric **		none.
36298Seric **
37298Seric **	Side Effects:
38298Seric **		none.
39298Seric **
40298Seric **	Called By:
41298Seric **		deliver
42298Seric */
43298Seric 
444101Seric stripquotes(s, qf)
45298Seric 	char *s;
464101Seric 	bool qf;
47298Seric {
48298Seric 	register char *p;
49298Seric 	register char *q;
50298Seric 	register char c;
51298Seric 
524101Seric 	if (s == NULL)
534101Seric 		return;
544101Seric 
55298Seric 	for (p = q = s; (c = *p++) != '\0'; )
56298Seric 	{
574101Seric 		if (c != '"' || !qf)
58298Seric 			*q++ = c & 0177;
59298Seric 	}
60298Seric 	*q = '\0';
61298Seric }
62298Seric /*
639043Seric **  QSTRLEN -- give me the string length assuming 0200 bits add a char
649043Seric **
659043Seric **	Parameters:
669043Seric **		s -- the string to measure.
679043Seric **
689043Seric **	Reurns:
699043Seric **		The length of s, including space for backslash escapes.
709043Seric **
719043Seric **	Side Effects:
729043Seric **		none.
739043Seric */
749043Seric 
759043Seric qstrlen(s)
769043Seric 	register char *s;
779043Seric {
789043Seric 	register int l = 0;
799043Seric 	register char c;
809043Seric 
819043Seric 	while ((c = *s++) != '\0')
829043Seric 	{
839043Seric 		if (bitset(0200, c))
849043Seric 			l++;
859043Seric 		l++;
869043Seric 	}
879043Seric 	return (l);
889043Seric }
899043Seric /*
902900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
912900Seric **
922900Seric **	Parameters:
932900Seric **		s -- the string to capitalize.
942900Seric **
952900Seric **	Returns:
962900Seric **		a pointer to a properly capitalized string.
972900Seric **
982900Seric **	Side Effects:
992900Seric **		none.
1002900Seric */
1012900Seric 
1022900Seric char *
1032900Seric capitalize(s)
1042900Seric 	register char *s;
1052900Seric {
1062900Seric 	static char buf[50];
1072900Seric 	register char *p;
1082900Seric 
1092900Seric 	p = buf;
1102900Seric 
1112900Seric 	for (;;)
1122900Seric 	{
1132900Seric 		while (!isalpha(*s) && *s != '\0')
1142900Seric 			*p++ = *s++;
1152900Seric 		if (*s == '\0')
1162900Seric 			break;
1172900Seric 		*p++ = toupper(*s++);
1182900Seric 		while (isalpha(*s))
1192900Seric 			*p++ = *s++;
1202900Seric 	}
1212900Seric 
1222900Seric 	*p = '\0';
1232900Seric 	return (buf);
1242900Seric }
1252900Seric /*
126298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
127298Seric **
128298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
129298Seric **	error -- but after all, what can we do?
130298Seric **
131298Seric **	Parameters:
132298Seric **		sz -- size of area to allocate.
133298Seric **
134298Seric **	Returns:
135298Seric **		pointer to data region.
136298Seric **
137298Seric **	Side Effects:
138298Seric **		Memory is allocated.
139298Seric */
140298Seric 
141298Seric char *
142298Seric xalloc(sz)
1437007Seric 	register int sz;
144298Seric {
145298Seric 	register char *p;
146298Seric 
147298Seric 	p = malloc(sz);
148298Seric 	if (p == NULL)
149298Seric 	{
150298Seric 		syserr("Out of memory!!");
15110685Seric 		abort();
15210685Seric 		/* exit(EX_UNAVAILABLE); */
153298Seric 	}
154298Seric 	return (p);
155298Seric }
156298Seric /*
1573151Seric **  COPYPLIST -- copy list of pointers.
1583151Seric **
1593151Seric **	This routine is the equivalent of newstr for lists of
1603151Seric **	pointers.
1613151Seric **
1623151Seric **	Parameters:
1633151Seric **		list -- list of pointers to copy.
1643151Seric **			Must be NULL terminated.
1653151Seric **		copycont -- if TRUE, copy the contents of the vector
1663151Seric **			(which must be a string) also.
1673151Seric **
1683151Seric **	Returns:
1693151Seric **		a copy of 'list'.
1703151Seric **
1713151Seric **	Side Effects:
1723151Seric **		none.
1733151Seric */
1743151Seric 
1753151Seric char **
1763151Seric copyplist(list, copycont)
1773151Seric 	char **list;
1783151Seric 	bool copycont;
1793151Seric {
1803151Seric 	register char **vp;
1813151Seric 	register char **newvp;
1823151Seric 
1833151Seric 	for (vp = list; *vp != NULL; vp++)
1843151Seric 		continue;
1853151Seric 
1863151Seric 	vp++;
1873151Seric 
18816897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
18916897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1903151Seric 
1913151Seric 	if (copycont)
1923151Seric 	{
1933151Seric 		for (vp = newvp; *vp != NULL; vp++)
1943151Seric 			*vp = newstr(*vp);
1953151Seric 	}
1963151Seric 
1973151Seric 	return (newvp);
1983151Seric }
1993151Seric /*
2003151Seric **  PRINTAV -- print argument vector.
2013151Seric **
2023151Seric **	Parameters:
2033151Seric **		av -- argument vector.
2043151Seric **
2053151Seric **	Returns:
2063151Seric **		none.
2073151Seric **
2083151Seric **	Side Effects:
2093151Seric **		prints av.
2103151Seric */
2113151Seric 
2123151Seric printav(av)
2133151Seric 	register char **av;
2143151Seric {
2153151Seric 	while (*av != NULL)
2163151Seric 	{
2178063Seric 		if (tTd(0, 44))
2188063Seric 			printf("\n\t%08x=", *av);
2198063Seric 		else
220*23105Seric 			(void) putchar(' ');
2213151Seric 		xputs(*av++);
2223151Seric 	}
223*23105Seric 	(void) putchar('\n');
2243151Seric }
2253151Seric /*
2263151Seric **  LOWER -- turn letter into lower case.
2273151Seric **
2283151Seric **	Parameters:
2293151Seric **		c -- character to turn into lower case.
2303151Seric **
2313151Seric **	Returns:
2323151Seric **		c, in lower case.
2333151Seric **
2343151Seric **	Side Effects:
2353151Seric **		none.
2363151Seric */
2373151Seric 
2383151Seric char
2393151Seric lower(c)
2403151Seric 	register char c;
2413151Seric {
2423151Seric 	if (isascii(c) && isupper(c))
2433151Seric 		c = c - 'A' + 'a';
2443151Seric 	return (c);
2453151Seric }
2463151Seric /*
2473151Seric **  XPUTS -- put string doing control escapes.
2483151Seric **
2493151Seric **	Parameters:
2503151Seric **		s -- string to put.
2513151Seric **
2523151Seric **	Returns:
2533151Seric **		none.
2543151Seric **
2553151Seric **	Side Effects:
2563151Seric **		output to stdout
2573151Seric */
2583151Seric 
2593151Seric xputs(s)
2603151Seric 	register char *s;
2613151Seric {
2623151Seric 	register char c;
2633151Seric 
2648055Seric 	if (s == NULL)
2658055Seric 	{
2668055Seric 		printf("<null>");
2678055Seric 		return;
2688055Seric 	}
269*23105Seric 	(void) putchar('"');
2703151Seric 	while ((c = *s++) != '\0')
2713151Seric 	{
2723151Seric 		if (!isascii(c))
2733151Seric 		{
274*23105Seric 			(void) putchar('\\');
2753151Seric 			c &= 0177;
2763151Seric 		}
27710326Seric 		if (c < 040 || c >= 0177)
2783151Seric 		{
279*23105Seric 			(void) putchar('^');
28010326Seric 			c ^= 0100;
2813151Seric 		}
282*23105Seric 		(void) putchar(c);
2833151Seric 	}
284*23105Seric 	(void) putchar('"');
2854086Seric 	(void) fflush(stdout);
2863151Seric }
2873151Seric /*
2883151Seric **  MAKELOWER -- Translate a line into lower case
2893151Seric **
2903151Seric **	Parameters:
2913151Seric **		p -- the string to translate.  If NULL, return is
2923151Seric **			immediate.
2933151Seric **
2943151Seric **	Returns:
2953151Seric **		none.
2963151Seric **
2973151Seric **	Side Effects:
2983151Seric **		String pointed to by p is translated to lower case.
2993151Seric **
3003151Seric **	Called By:
3013151Seric **		parse
3023151Seric */
3033151Seric 
3043151Seric makelower(p)
3053151Seric 	register char *p;
3063151Seric {
3073151Seric 	register char c;
3083151Seric 
3093151Seric 	if (p == NULL)
3103151Seric 		return;
3113151Seric 	for (; (c = *p) != '\0'; p++)
3123151Seric 		if (isascii(c) && isupper(c))
3133151Seric 			*p = c - 'A' + 'a';
3143151Seric }
3154059Seric /*
3164059Seric **  SAMEWORD -- return TRUE if the words are the same
3174059Seric **
3184059Seric **	Ignores case.
3194059Seric **
3204059Seric **	Parameters:
3214059Seric **		a, b -- the words to compare.
3224059Seric **
3234059Seric **	Returns:
3244059Seric **		TRUE if a & b match exactly (modulo case)
3254059Seric **		FALSE otherwise.
3264059Seric **
3274059Seric **	Side Effects:
3284059Seric **		none.
3294059Seric */
3304059Seric 
3314059Seric bool
3324059Seric sameword(a, b)
3334059Seric 	register char *a, *b;
3344059Seric {
33517350Seric 	char ca, cb;
33617350Seric 
33717350Seric 	do
3384059Seric 	{
33917350Seric 		ca = *a++;
34017350Seric 		cb = *b++;
34117350Seric 		if (isascii(ca) && isupper(ca))
34217350Seric 			ca = ca - 'A' + 'a';
34317350Seric 		if (isascii(cb) && isupper(cb))
34417350Seric 			cb = cb - 'A' + 'a';
34517350Seric 	} while (ca != '\0' && ca == cb);
34617350Seric 	return (ca == cb);
3474059Seric }
3484086Seric /*
3495196Seric **  BUILDFNAME -- build full name from gecos style entry.
3504375Seric **
3515196Seric **	This routine interprets the strange entry that would appear
3525196Seric **	in the GECOS field of the password file.
3535196Seric **
3544375Seric **	Parameters:
3555196Seric **		p -- name to build.
3565196Seric **		login -- the login name of this user (for &).
3575196Seric **		buf -- place to put the result.
3584375Seric **
3594375Seric **	Returns:
3604375Seric **		none.
3614375Seric **
3624375Seric **	Side Effects:
3634375Seric **		none.
3644375Seric */
3654375Seric 
3665196Seric buildfname(p, login, buf)
3675196Seric 	register char *p;
3685196Seric 	char *login;
3694375Seric 	char *buf;
3704375Seric {
3714375Seric 	register char *bp = buf;
3724375Seric 
3734438Seric 	if (*p == '*')
3744438Seric 		p++;
3756278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3764375Seric 	{
3774375Seric 		if (*p == '&')
3784375Seric 		{
3795196Seric 			(void) strcpy(bp, login);
3804375Seric 			*bp = toupper(*bp);
3814375Seric 			while (*bp != '\0')
3824375Seric 				bp++;
3834375Seric 			p++;
3844375Seric 		}
3854375Seric 		else
3864375Seric 			*bp++ = *p++;
3874375Seric 	}
3884375Seric 	*bp = '\0';
3894375Seric }
3904375Seric /*
3914538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3924538Seric **
3934538Seric **	Parameters:
3944538Seric **		fn -- filename to check.
3954538Seric **		uid -- uid to compare against.
3964538Seric **		mode -- mode bits that must match.
3974538Seric **
3984538Seric **	Returns:
3994538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
4004538Seric **		FALSE otherwise.
4014538Seric **
4024538Seric **	Side Effects:
4034538Seric **		none.
4044538Seric */
4054538Seric 
4064538Seric bool
4074538Seric safefile(fn, uid, mode)
4084538Seric 	char *fn;
4094538Seric 	int uid;
4104538Seric 	int mode;
4114538Seric {
4124538Seric 	struct stat stbuf;
4134538Seric 
4144538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
4154538Seric 	    (stbuf.st_mode & mode) == mode)
4164538Seric 		return (TRUE);
41711936Seric 	errno = 0;
4184538Seric 	return (FALSE);
4194538Seric }
4204538Seric /*
4214557Seric **  FIXCRLF -- fix <CR><LF> in line.
4224557Seric **
4234557Seric **	Looks for the <CR><LF> combination and turns it into the
4244557Seric **	UNIX canonical <NL> character.  It only takes one line,
4254557Seric **	i.e., it is assumed that the first <NL> found is the end
4264557Seric **	of the line.
4274557Seric **
4284557Seric **	Parameters:
4294557Seric **		line -- the line to fix.
4304557Seric **		stripnl -- if true, strip the newline also.
4314557Seric **
4324557Seric **	Returns:
4334557Seric **		none.
4344557Seric **
4354557Seric **	Side Effects:
4364557Seric **		line is changed in place.
4374557Seric */
4384557Seric 
4394557Seric fixcrlf(line, stripnl)
4404557Seric 	char *line;
4414557Seric 	bool stripnl;
4424557Seric {
4434557Seric 	register char *p;
4444557Seric 
4454557Seric 	p = index(line, '\n');
4464557Seric 	if (p == NULL)
4474557Seric 		return;
4484794Seric 	if (p[-1] == '\r')
4494557Seric 		p--;
4504557Seric 	if (!stripnl)
4514557Seric 		*p++ = '\n';
4524557Seric 	*p = '\0';
4534557Seric }
4544557Seric /*
4556890Seric **  DFOPEN -- determined file open
4566890Seric **
4576890Seric **	This routine has the semantics of fopen, except that it will
4586890Seric **	keep trying a few times to make this happen.  The idea is that
4596890Seric **	on very loaded systems, we may run out of resources (inodes,
4606890Seric **	whatever), so this tries to get around it.
4616890Seric */
4626890Seric 
4636890Seric FILE *
4646890Seric dfopen(filename, mode)
4656890Seric 	char *filename;
4666890Seric 	char *mode;
4676890Seric {
4686890Seric 	register int tries;
4696890Seric 	register FILE *fp;
4706890Seric 
4716890Seric 	for (tries = 0; tries < 10; tries++)
4726890Seric 	{
4736890Seric 		sleep(10 * tries);
4746890Seric 		errno = 0;
4756890Seric 		fp = fopen(filename, mode);
4769376Seric 		if (fp != NULL)
4776890Seric 			break;
4789376Seric 		if (errno != ENFILE && errno != EINTR)
4799376Seric 			break;
4806890Seric 	}
48111936Seric 	errno = 0;
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 
5027753Seric # define SMTPLINELIM	990	/* maximum line length */
5037124Seric 
50410172Seric putline(l, fp, m)
5057753Seric 	register char *l;
5067124Seric 	FILE *fp;
50710172Seric 	MAILER *m;
5087124Seric {
5097124Seric 	register char *p;
5107753Seric 	char svchar;
5117124Seric 
51211275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
51311275Seric 	if (bitnset(M_LIMITS, m->m_flags))
51411275Seric 	{
51511275Seric 		p = l;
51611275Seric 		while ((*p++ &= ~0200) != 0)
51711275Seric 			continue;
51811275Seric 	}
51911275Seric 
5207753Seric 	do
5217124Seric 	{
5227753Seric 		/* find the end of the line */
5237753Seric 		p = index(l, '\n');
5247753Seric 		if (p == NULL)
5257753Seric 			p = &l[strlen(l)];
5267124Seric 
5277753Seric 		/* check for line overflow */
52811275Seric 		while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
5297753Seric 		{
5307753Seric 			register char *q = &l[SMTPLINELIM - 1];
5317124Seric 
5327753Seric 			svchar = *q;
5337753Seric 			*q = '\0';
53410685Seric 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
535*23105Seric 				(void) putc('.', fp);
5367753Seric 			fputs(l, fp);
537*23105Seric 			(void) putc('!', fp);
53810326Seric 			fputs(m->m_eol, fp);
5397753Seric 			*q = svchar;
5407753Seric 			l = q;
5417753Seric 		}
5427124Seric 
5437753Seric 		/* output last part */
5447753Seric 		svchar = *p;
5457753Seric 		*p = '\0';
54610685Seric 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
547*23105Seric 			(void) putc('.', fp);
5487124Seric 		fputs(l, fp);
54910326Seric 		fputs(m->m_eol, fp);
5507753Seric 		*p = svchar;
5517753Seric 		l = p;
5527753Seric 		if (*l == '\n')
5537753Seric 			l++;
5547753Seric 	} while (l[0] != '\0');
5557124Seric }
5567676Seric /*
5577676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5587676Seric **
5597676Seric **	Parameters:
5607676Seric **		f -- name of file to unlink.
5617676Seric **
5627676Seric **	Returns:
5637676Seric **		none.
5647676Seric **
5657676Seric **	Side Effects:
5667676Seric **		f is unlinked.
5677676Seric */
5687676Seric 
5697676Seric xunlink(f)
5707676Seric 	char *f;
5717676Seric {
5727676Seric 	register int i;
5737676Seric 
5747676Seric # ifdef LOG
5757676Seric 	if (LogLevel > 20)
5767812Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
5777676Seric # endif LOG
5787676Seric 
5797676Seric 	i = unlink(f);
5807676Seric # ifdef LOG
5817676Seric 	if (i < 0 && LogLevel > 21)
5827942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
5837676Seric # endif LOG
5847676Seric }
5857685Seric /*
58614885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
5877685Seric **
5887685Seric **	Parameters:
5897685Seric **		buf -- place to put the input line.
5907685Seric **		siz -- size of buf.
5917685Seric **		fp -- file to read from.
5927685Seric **
5937685Seric **	Returns:
59415533Seric **		NULL on error (including timeout).  This will also leave
59515533Seric **			buf containing a null string.
5967685Seric **		buf otherwise.
5977685Seric **
5987685Seric **	Side Effects:
5997685Seric **		none.
6007685Seric */
6017685Seric 
60214885Seric static jmp_buf	CtxReadTimeout;
6037685Seric 
60416138Seric #ifndef ETIMEDOUT
60516138Seric #define ETIMEDOUT	EINTR
60616138Seric #endif
60716138Seric 
6087685Seric char *
6097685Seric sfgets(buf, siz, fp)
6107685Seric 	char *buf;
6117685Seric 	int siz;
6127685Seric 	FILE *fp;
6137685Seric {
6147942Seric 	register EVENT *ev = NULL;
6157685Seric 	register char *p;
6167685Seric 	extern readtimeout();
6177685Seric 
61814885Seric 	/* set the timeout */
6197942Seric 	if (ReadTimeout != 0)
62014885Seric 	{
62114885Seric 		if (setjmp(CtxReadTimeout) != 0)
62214885Seric 		{
62316138Seric 			errno = ETIMEDOUT;
62414885Seric 			syserr("sfgets: timeout on read (mailer may be hung)");
62519037Seric 			buf[0] = '\0';
62614885Seric 			return (NULL);
62714885Seric 		}
62816138Seric 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
62914885Seric 	}
63014885Seric 
63114885Seric 	/* try to read */
63215533Seric 	p = NULL;
63315533Seric 	while (p == NULL && !feof(fp) && !ferror(fp))
6347942Seric 	{
6357942Seric 		errno = 0;
6367942Seric 		p = fgets(buf, siz, fp);
63715533Seric 		if (errno == EINTR)
63815533Seric 			clearerr(fp);
63915533Seric 	}
64014885Seric 
64114885Seric 	/* clear the event if it has not sprung */
6427685Seric 	clrevent(ev);
64314885Seric 
64414885Seric 	/* clean up the books and exit */
6458055Seric 	LineNumber++;
64615533Seric 	if (p == NULL)
64716880Seric 	{
64815533Seric 		buf[0] = '\0';
64916880Seric 		return (NULL);
65016880Seric 	}
65116880Seric 	for (p = buf; *p != '\0'; p++)
65216880Seric 		*p &= ~0200;
65316880Seric 	return (buf);
6547685Seric }
6557685Seric 
6567685Seric static
6577685Seric readtimeout()
6587685Seric {
65914885Seric 	longjmp(CtxReadTimeout, 1);
6607685Seric }
6617786Seric /*
6627786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
6637786Seric **
6647786Seric **	Parameters:
6657786Seric **		buf -- place to put result.
6667786Seric **		n -- bytes available.
6677786Seric **		f -- file to read from.
6687786Seric **
6697786Seric **	Returns:
6707786Seric **		buf on success, NULL on error or EOF.
6717786Seric **
6727786Seric **	Side Effects:
6737786Seric **		buf gets lines from f, with continuation lines (lines
6747786Seric **		with leading white space) appended.  CRLF's are mapped
6757786Seric **		into single newlines.  Any trailing NL is stripped.
6767786Seric */
6777786Seric 
6787786Seric char *
6797786Seric fgetfolded(buf, n, f)
6807786Seric 	char *buf;
6817786Seric 	register int n;
6827786Seric 	FILE *f;
6837786Seric {
6847786Seric 	register char *p = buf;
6857786Seric 	register int i;
6867786Seric 
6877786Seric 	n--;
68817350Seric 	while ((i = getc(f)) != EOF)
6897786Seric 	{
69017350Seric 		if (i == '\r')
69117350Seric 		{
69217350Seric 			i = getc(f);
69317350Seric 			if (i != '\n')
69417350Seric 			{
69517350Seric 				if (i != EOF)
696*23105Seric 					(void) ungetc(i, f);
69717350Seric 				i = '\r';
69817350Seric 			}
69917350Seric 		}
70017350Seric 		if (--n > 0)
70117350Seric 			*p++ = i;
70217350Seric 		if (i == '\n')
70317350Seric 		{
70417350Seric 			LineNumber++;
70517350Seric 			i = getc(f);
70617350Seric 			if (i != EOF)
707*23105Seric 				(void) ungetc(i, f);
70817350Seric 			if (i != ' ' && i != '\t')
70917350Seric 			{
71017350Seric 				*--p = '\0';
71117350Seric 				return (buf);
71217350Seric 			}
71317350Seric 		}
7147786Seric 	}
7157786Seric 	return (NULL);
7167786Seric }
7177860Seric /*
7187886Seric **  CURTIME -- return current time.
7197886Seric **
7207886Seric **	Parameters:
7217886Seric **		none.
7227886Seric **
7237886Seric **	Returns:
7247886Seric **		the current time.
7257886Seric **
7267886Seric **	Side Effects:
7277886Seric **		none.
7287886Seric */
7297886Seric 
7307886Seric time_t
7317886Seric curtime()
7327886Seric {
7337886Seric 	auto time_t t;
7347886Seric 
7357886Seric 	(void) time(&t);
7367886Seric 	return (t);
7377886Seric }
7388264Seric /*
7398264Seric **  ATOBOOL -- convert a string representation to boolean.
7408264Seric **
7418264Seric **	Defaults to "TRUE"
7428264Seric **
7438264Seric **	Parameters:
7448264Seric **		s -- string to convert.  Takes "tTyY" as true,
7458264Seric **			others as false.
7468264Seric **
7478264Seric **	Returns:
7488264Seric **		A boolean representation of the string.
7498264Seric **
7508264Seric **	Side Effects:
7518264Seric **		none.
7528264Seric */
7538264Seric 
7548264Seric bool
7558264Seric atobool(s)
7568264Seric 	register char *s;
7578264Seric {
7588264Seric 	if (*s == '\0' || index("tTyY", *s) != NULL)
7598264Seric 		return (TRUE);
7608264Seric 	return (FALSE);
7618264Seric }
7629048Seric /*
7639048Seric **  ATOOCT -- convert a string representation to octal.
7649048Seric **
7659048Seric **	Parameters:
7669048Seric **		s -- string to convert.
7679048Seric **
7689048Seric **	Returns:
7699048Seric **		An integer representing the string interpreted as an
7709048Seric **		octal number.
7719048Seric **
7729048Seric **	Side Effects:
7739048Seric **		none.
7749048Seric */
7759048Seric 
7769048Seric atooct(s)
7779048Seric 	register char *s;
7789048Seric {
7799048Seric 	register int i = 0;
7809048Seric 
7819048Seric 	while (*s >= '0' && *s <= '7')
7829048Seric 		i = (i << 3) | (*s++ - '0');
7839048Seric 	return (i);
7849048Seric }
7859376Seric /*
7869376Seric **  WAITFOR -- wait for a particular process id.
7879376Seric **
7889376Seric **	Parameters:
7899376Seric **		pid -- process id to wait for.
7909376Seric **
7919376Seric **	Returns:
7929376Seric **		status of pid.
7939376Seric **		-1 if pid never shows up.
7949376Seric **
7959376Seric **	Side Effects:
7969376Seric **		none.
7979376Seric */
7989376Seric 
7999376Seric waitfor(pid)
8009376Seric 	int pid;
8019376Seric {
8029376Seric 	auto int st;
8039376Seric 	int i;
8049376Seric 
8059376Seric 	do
8069376Seric 	{
8079376Seric 		errno = 0;
8089376Seric 		i = wait(&st);
8099376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
8109376Seric 	if (i < 0)
8119376Seric 		st = -1;
8129376Seric 	return (st);
8139376Seric }
8149376Seric /*
81510685Seric **  BITINTERSECT -- tell if two bitmaps intersect
81610685Seric **
81710685Seric **	Parameters:
81810685Seric **		a, b -- the bitmaps in question
81910685Seric **
82010685Seric **	Returns:
82110685Seric **		TRUE if they have a non-null intersection
82210685Seric **		FALSE otherwise
82310685Seric **
82410685Seric **	Side Effects:
82510685Seric **		none.
82610685Seric */
82710685Seric 
82810685Seric bool
82910685Seric bitintersect(a, b)
83010685Seric 	BITMAP a;
83110685Seric 	BITMAP b;
83210685Seric {
83310685Seric 	int i;
83410685Seric 
83510685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
83610685Seric 		if ((a[i] & b[i]) != 0)
83710685Seric 			return (TRUE);
83810685Seric 	return (FALSE);
83910685Seric }
84010685Seric /*
84110685Seric **  BITZEROP -- tell if a bitmap is all zero
84210685Seric **
84310685Seric **	Parameters:
84410685Seric **		map -- the bit map to check
84510685Seric **
84610685Seric **	Returns:
84710685Seric **		TRUE if map is all zero.
84810685Seric **		FALSE if there are any bits set in map.
84910685Seric **
85010685Seric **	Side Effects:
85110685Seric **		none.
85210685Seric */
85310685Seric 
85410685Seric bool
85510685Seric bitzerop(map)
85610685Seric 	BITMAP map;
85710685Seric {
85810685Seric 	int i;
85910685Seric 
86010685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
86110685Seric 		if (map[i] != 0)
86210685Seric 			return (FALSE);
86310685Seric 	return (TRUE);
86410685Seric }
865