13151Seric # include <stdio.h> 24538Seric # include <sys/types.h> 34538Seric # include <sys/stat.h> 4298Seric # include <sysexits.h> 56890Seric # include <errno.h> 62900Seric # include <ctype.h> 76890Seric # include "sendmail.h" 8298Seric 9*8264Seric SCCSID(@(#)util.c 3.32 09/26/82); 10409Seric 11298Seric /* 12298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 13298Seric ** 14298Seric ** Runs through a string and strips off unquoted quote 15298Seric ** characters and quote bits. This is done in place. 16298Seric ** 17298Seric ** Parameters: 18298Seric ** s -- the string to strip. 194101Seric ** qf -- if set, remove actual `` " '' characters 204101Seric ** as well as the quote bits. 21298Seric ** 22298Seric ** Returns: 23298Seric ** none. 24298Seric ** 25298Seric ** Side Effects: 26298Seric ** none. 27298Seric ** 28298Seric ** Called By: 29298Seric ** deliver 30298Seric */ 31298Seric 324101Seric stripquotes(s, qf) 33298Seric char *s; 344101Seric bool qf; 35298Seric { 36298Seric register char *p; 37298Seric register char *q; 38298Seric register char c; 39298Seric 404101Seric if (s == NULL) 414101Seric return; 424101Seric 43298Seric for (p = q = s; (c = *p++) != '\0'; ) 44298Seric { 454101Seric if (c != '"' || !qf) 46298Seric *q++ = c & 0177; 47298Seric } 48298Seric *q = '\0'; 49298Seric } 50298Seric /* 512900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 522900Seric ** 532900Seric ** Parameters: 542900Seric ** s -- the string to capitalize. 552900Seric ** 562900Seric ** Returns: 572900Seric ** a pointer to a properly capitalized string. 582900Seric ** 592900Seric ** Side Effects: 602900Seric ** none. 612900Seric */ 622900Seric 632900Seric char * 642900Seric capitalize(s) 652900Seric register char *s; 662900Seric { 672900Seric static char buf[50]; 682900Seric register char *p; 692900Seric 702900Seric p = buf; 712900Seric 722900Seric for (;;) 732900Seric { 742900Seric while (!isalpha(*s) && *s != '\0') 752900Seric *p++ = *s++; 762900Seric if (*s == '\0') 772900Seric break; 782900Seric *p++ = toupper(*s++); 792900Seric while (isalpha(*s)) 802900Seric *p++ = *s++; 812900Seric } 822900Seric 832900Seric *p = '\0'; 842900Seric return (buf); 852900Seric } 862900Seric /* 87298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 88298Seric ** 89298Seric ** THIS IS A CLUDGE. This should be made to give a proper 90298Seric ** error -- but after all, what can we do? 91298Seric ** 92298Seric ** Parameters: 93298Seric ** sz -- size of area to allocate. 94298Seric ** 95298Seric ** Returns: 96298Seric ** pointer to data region. 97298Seric ** 98298Seric ** Side Effects: 99298Seric ** Memory is allocated. 100298Seric */ 101298Seric 102298Seric char * 103298Seric xalloc(sz) 1047007Seric register int sz; 105298Seric { 106298Seric register char *p; 107298Seric 108298Seric p = malloc(sz); 109298Seric if (p == NULL) 110298Seric { 111298Seric syserr("Out of memory!!"); 1121598Seric exit(EX_UNAVAILABLE); 113298Seric } 114298Seric return (p); 115298Seric } 116298Seric /* 1172900Seric ** NEWSTR -- make copy of string. 1182900Seric ** 1192900Seric ** Space is allocated for it using xalloc. 1202900Seric ** 1212900Seric ** Parameters: 1222900Seric ** string to copy. 1232900Seric ** 1242900Seric ** Returns: 1252900Seric ** pointer to new string. 1262900Seric ** 1272900Seric ** Side Effects: 1282900Seric ** none. 1292900Seric */ 1302900Seric 1312900Seric char * 1322900Seric newstr(s) 1332900Seric register char *s; 1342900Seric { 1352900Seric register char *p; 1362900Seric 1377007Seric p = xalloc(strlen(s) + 1); 1387007Seric (void) strcpy(p, s); 1392900Seric return (p); 1402900Seric } 1413151Seric /* 1423151Seric ** COPYPLIST -- copy list of pointers. 1433151Seric ** 1443151Seric ** This routine is the equivalent of newstr for lists of 1453151Seric ** pointers. 1463151Seric ** 1473151Seric ** Parameters: 1483151Seric ** list -- list of pointers to copy. 1493151Seric ** Must be NULL terminated. 1503151Seric ** copycont -- if TRUE, copy the contents of the vector 1513151Seric ** (which must be a string) also. 1523151Seric ** 1533151Seric ** Returns: 1543151Seric ** a copy of 'list'. 1553151Seric ** 1563151Seric ** Side Effects: 1573151Seric ** none. 1583151Seric */ 1593151Seric 1603151Seric char ** 1613151Seric copyplist(list, copycont) 1623151Seric char **list; 1633151Seric bool copycont; 1643151Seric { 1653151Seric register char **vp; 1663151Seric register char **newvp; 1673151Seric 1683151Seric for (vp = list; *vp != NULL; vp++) 1693151Seric continue; 1703151Seric 1713151Seric vp++; 1723151Seric 1737007Seric newvp = (char **) xalloc((vp - list) * sizeof *vp); 1744086Seric bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 1753151Seric 1763151Seric if (copycont) 1773151Seric { 1783151Seric for (vp = newvp; *vp != NULL; vp++) 1793151Seric *vp = newstr(*vp); 1803151Seric } 1813151Seric 1823151Seric return (newvp); 1833151Seric } 1843151Seric /* 1853151Seric ** PRINTAV -- print argument vector. 1863151Seric ** 1873151Seric ** Parameters: 1883151Seric ** av -- argument vector. 1893151Seric ** 1903151Seric ** Returns: 1913151Seric ** none. 1923151Seric ** 1933151Seric ** Side Effects: 1943151Seric ** prints av. 1953151Seric */ 1963151Seric 1973151Seric # ifdef DEBUG 1983151Seric printav(av) 1993151Seric register char **av; 2003151Seric { 2013151Seric while (*av != NULL) 2023151Seric { 2038063Seric if (tTd(0, 44)) 2048063Seric printf("\n\t%08x=", *av); 2058063Seric else 2068063Seric putchar(' '); 2073151Seric xputs(*av++); 2083151Seric } 2098063Seric putchar('\n'); 2103151Seric } 2113151Seric # endif DEBUG 2123151Seric /* 2133151Seric ** LOWER -- turn letter into lower case. 2143151Seric ** 2153151Seric ** Parameters: 2163151Seric ** c -- character to turn into lower case. 2173151Seric ** 2183151Seric ** Returns: 2193151Seric ** c, in lower case. 2203151Seric ** 2213151Seric ** Side Effects: 2223151Seric ** none. 2233151Seric */ 2243151Seric 2253151Seric char 2263151Seric lower(c) 2273151Seric register char c; 2283151Seric { 2293151Seric if (isascii(c) && isupper(c)) 2303151Seric c = c - 'A' + 'a'; 2313151Seric return (c); 2323151Seric } 2333151Seric /* 2343151Seric ** XPUTS -- put string doing control escapes. 2353151Seric ** 2363151Seric ** Parameters: 2373151Seric ** s -- string to put. 2383151Seric ** 2393151Seric ** Returns: 2403151Seric ** none. 2413151Seric ** 2423151Seric ** Side Effects: 2433151Seric ** output to stdout 2443151Seric */ 2453151Seric 2463151Seric # ifdef DEBUG 2473151Seric xputs(s) 2483151Seric register char *s; 2493151Seric { 2503151Seric register char c; 2513151Seric 2528055Seric if (s == NULL) 2538055Seric { 2548055Seric printf("<null>"); 2558055Seric return; 2568055Seric } 2578063Seric putchar('"'); 2583151Seric while ((c = *s++) != '\0') 2593151Seric { 2603151Seric if (!isascii(c)) 2613151Seric { 2623151Seric putchar('\\'); 2633151Seric c &= 0177; 2643151Seric } 2653151Seric if (iscntrl(c)) 2663151Seric { 2673151Seric putchar('^'); 2683151Seric c |= 0100; 2693151Seric } 2703151Seric putchar(c); 2713151Seric } 2728063Seric putchar('"'); 2734086Seric (void) fflush(stdout); 2743151Seric } 2753151Seric # endif DEBUG 2763151Seric /* 2773151Seric ** MAKELOWER -- Translate a line into lower case 2783151Seric ** 2793151Seric ** Parameters: 2803151Seric ** p -- the string to translate. If NULL, return is 2813151Seric ** immediate. 2823151Seric ** 2833151Seric ** Returns: 2843151Seric ** none. 2853151Seric ** 2863151Seric ** Side Effects: 2873151Seric ** String pointed to by p is translated to lower case. 2883151Seric ** 2893151Seric ** Called By: 2903151Seric ** parse 2913151Seric */ 2923151Seric 2933151Seric makelower(p) 2943151Seric register char *p; 2953151Seric { 2963151Seric register char c; 2973151Seric 2983151Seric if (p == NULL) 2993151Seric return; 3003151Seric for (; (c = *p) != '\0'; p++) 3013151Seric if (isascii(c) && isupper(c)) 3023151Seric *p = c - 'A' + 'a'; 3033151Seric } 3044059Seric /* 3054059Seric ** SAMEWORD -- return TRUE if the words are the same 3064059Seric ** 3074059Seric ** Ignores case. 3084059Seric ** 3094059Seric ** Parameters: 3104059Seric ** a, b -- the words to compare. 3114059Seric ** 3124059Seric ** Returns: 3134059Seric ** TRUE if a & b match exactly (modulo case) 3144059Seric ** FALSE otherwise. 3154059Seric ** 3164059Seric ** Side Effects: 3174059Seric ** none. 3184059Seric */ 3194059Seric 3204059Seric bool 3214059Seric sameword(a, b) 3224059Seric register char *a, *b; 3234059Seric { 3244059Seric while (lower(*a) == lower(*b)) 3254059Seric { 3264059Seric if (*a == '\0') 3274059Seric return (TRUE); 3284059Seric a++; 3294059Seric b++; 3304059Seric } 3314059Seric return (FALSE); 3324059Seric } 3334086Seric /* 3344101Seric ** CLEAR -- clear a block of memory 3354101Seric ** 3364101Seric ** Parameters: 3374101Seric ** p -- location to clear. 3384101Seric ** l -- number of bytes to clear. 3394101Seric ** 3404101Seric ** Returns: 3414101Seric ** none. 3424101Seric ** 3434101Seric ** Side Effects: 3444101Seric ** none. 3454101Seric */ 3464101Seric 3474101Seric clear(p, l) 3484101Seric register char *p; 3494101Seric register int l; 3504101Seric { 3514101Seric while (l-- > 0) 3524101Seric *p++ = 0; 3534101Seric } 3544101Seric /* 3555196Seric ** BUILDFNAME -- build full name from gecos style entry. 3564375Seric ** 3575196Seric ** This routine interprets the strange entry that would appear 3585196Seric ** in the GECOS field of the password file. 3595196Seric ** 3604375Seric ** Parameters: 3615196Seric ** p -- name to build. 3625196Seric ** login -- the login name of this user (for &). 3635196Seric ** buf -- place to put the result. 3644375Seric ** 3654375Seric ** Returns: 3664375Seric ** none. 3674375Seric ** 3684375Seric ** Side Effects: 3694375Seric ** none. 3704375Seric */ 3714375Seric 3725196Seric buildfname(p, login, buf) 3735196Seric register char *p; 3745196Seric char *login; 3754375Seric char *buf; 3764375Seric { 3774375Seric register char *bp = buf; 3784375Seric 3794438Seric if (*p == '*') 3804438Seric p++; 3816278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3824375Seric { 3834375Seric if (*p == '&') 3844375Seric { 3855196Seric (void) strcpy(bp, login); 3864375Seric *bp = toupper(*bp); 3874375Seric while (*bp != '\0') 3884375Seric bp++; 3894375Seric p++; 3904375Seric } 3914375Seric else 3924375Seric *bp++ = *p++; 3934375Seric } 3944375Seric *bp = '\0'; 3954375Seric } 3964375Seric /* 3974538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3984538Seric ** 3994538Seric ** Parameters: 4004538Seric ** fn -- filename to check. 4014538Seric ** uid -- uid to compare against. 4024538Seric ** mode -- mode bits that must match. 4034538Seric ** 4044538Seric ** Returns: 4054538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 4064538Seric ** FALSE otherwise. 4074538Seric ** 4084538Seric ** Side Effects: 4094538Seric ** none. 4104538Seric */ 4114538Seric 4124538Seric bool 4134538Seric safefile(fn, uid, mode) 4144538Seric char *fn; 4154538Seric int uid; 4164538Seric int mode; 4174538Seric { 4184538Seric struct stat stbuf; 4194538Seric 4204538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4214538Seric (stbuf.st_mode & mode) == mode) 4224538Seric return (TRUE); 4234538Seric return (FALSE); 4244538Seric } 4254538Seric /* 4264557Seric ** FIXCRLF -- fix <CR><LF> in line. 4274557Seric ** 4284557Seric ** Looks for the <CR><LF> combination and turns it into the 4294557Seric ** UNIX canonical <NL> character. It only takes one line, 4304557Seric ** i.e., it is assumed that the first <NL> found is the end 4314557Seric ** of the line. 4324557Seric ** 4334557Seric ** Parameters: 4344557Seric ** line -- the line to fix. 4354557Seric ** stripnl -- if true, strip the newline also. 4364557Seric ** 4374557Seric ** Returns: 4384557Seric ** none. 4394557Seric ** 4404557Seric ** Side Effects: 4414557Seric ** line is changed in place. 4424557Seric */ 4434557Seric 4444557Seric fixcrlf(line, stripnl) 4454557Seric char *line; 4464557Seric bool stripnl; 4474557Seric { 4484557Seric register char *p; 4494557Seric 4504557Seric p = index(line, '\n'); 4514557Seric if (p == NULL) 4524557Seric return; 4534794Seric if (p[-1] == '\r') 4544557Seric p--; 4554557Seric if (!stripnl) 4564557Seric *p++ = '\n'; 4574557Seric *p = '\0'; 4584557Seric } 4594557Seric /* 4604086Seric ** SYSLOG -- fake entry to fool lint 4614086Seric */ 4624086Seric 4634086Seric # ifdef LOG 4644086Seric # ifdef lint 4654086Seric 4664086Seric /*VARARGS2*/ 4674086Seric syslog(pri, fmt, args) 4684086Seric int pri; 4694086Seric char *fmt; 4704086Seric { 4714086Seric pri = *fmt; 4724086Seric args = pri; 4734086Seric pri = args; 4744086Seric } 4754086Seric 4764086Seric # endif lint 4774086Seric # endif LOG 4786890Seric /* 4796890Seric ** DFOPEN -- determined file open 4806890Seric ** 4816890Seric ** This routine has the semantics of fopen, except that it will 4826890Seric ** keep trying a few times to make this happen. The idea is that 4836890Seric ** on very loaded systems, we may run out of resources (inodes, 4846890Seric ** whatever), so this tries to get around it. 4856890Seric */ 4866890Seric 4876890Seric FILE * 4886890Seric dfopen(filename, mode) 4896890Seric char *filename; 4906890Seric char *mode; 4916890Seric { 4926890Seric register int tries; 4936890Seric register FILE *fp; 4946890Seric extern int errno; 4956890Seric 4966890Seric for (tries = 0; tries < 10; tries++) 4976890Seric { 4986890Seric sleep(10 * tries); 4996890Seric errno = 0; 5006890Seric fp = fopen(filename, mode); 5016890Seric if (fp != NULL || errno != ENFILE) 5026890Seric break; 5036890Seric } 5046890Seric return (fp); 5056890Seric } 5067124Seric /* 5077124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 5087124Seric ** 5097753Seric ** This routine always guarantees outputing a newline (or CRLF, 5107753Seric ** as appropriate) at the end of the string. 5117753Seric ** 5127124Seric ** Parameters: 5137124Seric ** l -- line to put. 5147124Seric ** fp -- file to put it onto. 5157124Seric ** fullsmtp -- if set, obey strictest SMTP conventions. 5167124Seric ** 5177124Seric ** Returns: 5187124Seric ** none 5197124Seric ** 5207124Seric ** Side Effects: 5217124Seric ** output of l to fp. 5227124Seric */ 5237124Seric 5247753Seric # define SMTPLINELIM 990 /* maximum line length */ 5257124Seric 5267124Seric putline(l, fp, fullsmtp) 5277753Seric register char *l; 5287124Seric FILE *fp; 5297124Seric bool fullsmtp; 5307124Seric { 5317124Seric register char *p; 5327753Seric char svchar; 5337124Seric 5347753Seric do 5357124Seric { 5367753Seric /* find the end of the line */ 5377753Seric p = index(l, '\n'); 5387753Seric if (p == NULL) 5397753Seric p = &l[strlen(l)]; 5407124Seric 5417753Seric /* check for line overflow */ 5427753Seric while (fullsmtp && (p - l) > SMTPLINELIM) 5437753Seric { 5447753Seric register char *q = &l[SMTPLINELIM - 1]; 5457124Seric 5467753Seric svchar = *q; 5477753Seric *q = '\0'; 5487753Seric fputs(l, fp); 5497753Seric fputs("!\r\n", fp); 5507753Seric *q = svchar; 5517753Seric l = q; 5527753Seric } 5537124Seric 5547753Seric /* output last part */ 5557753Seric svchar = *p; 5567753Seric *p = '\0'; 5577124Seric fputs(l, fp); 5587753Seric if (fullsmtp) 5597753Seric fputc('\r', fp); 5607753Seric fputc('\n', fp); 5617753Seric *p = svchar; 5627753Seric l = p; 5637753Seric if (*l == '\n') 5647753Seric l++; 5657753Seric } while (l[0] != '\0'); 5667124Seric } 5677676Seric /* 5687676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5697676Seric ** 5707676Seric ** Parameters: 5717676Seric ** f -- name of file to unlink. 5727676Seric ** 5737676Seric ** Returns: 5747676Seric ** none. 5757676Seric ** 5767676Seric ** Side Effects: 5777676Seric ** f is unlinked. 5787676Seric */ 5797676Seric 5807676Seric xunlink(f) 5817676Seric char *f; 5827676Seric { 5837676Seric register int i; 5847676Seric 5857676Seric # ifdef LOG 5867676Seric if (LogLevel > 20) 5877812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5887676Seric # endif LOG 5897676Seric 5907676Seric i = unlink(f); 5917676Seric # ifdef LOG 5927676Seric if (i < 0 && LogLevel > 21) 5937942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 5947676Seric # endif LOG 5957676Seric } 5967685Seric /* 5977685Seric ** SFGETS -- "safe" fgets -- times out. 5987685Seric ** 5997685Seric ** Parameters: 6007685Seric ** buf -- place to put the input line. 6017685Seric ** siz -- size of buf. 6027685Seric ** fp -- file to read from. 6037685Seric ** 6047685Seric ** Returns: 6057685Seric ** NULL on error (including timeout). 6067685Seric ** buf otherwise. 6077685Seric ** 6087685Seric ** Side Effects: 6097685Seric ** none. 6107685Seric */ 6117685Seric 6127942Seric static bool TimeoutFlag; 6137685Seric 6147685Seric char * 6157685Seric sfgets(buf, siz, fp) 6167685Seric char *buf; 6177685Seric int siz; 6187685Seric FILE *fp; 6197685Seric { 6207942Seric register EVENT *ev = NULL; 6217685Seric register char *p; 6227685Seric extern readtimeout(); 6237685Seric 6247942Seric if (ReadTimeout != 0) 6257942Seric ev = setevent(ReadTimeout, readtimeout, 0); 6267942Seric TimeoutFlag = FALSE; 6277942Seric do 6287942Seric { 6297942Seric errno = 0; 6307942Seric p = fgets(buf, siz, fp); 6317942Seric } while (!(p != NULL || TimeoutFlag || errno != EINTR)); 6327685Seric clrevent(ev); 6338055Seric LineNumber++; 6347685Seric return (p); 6357685Seric } 6367685Seric 6377685Seric static 6387685Seric readtimeout() 6397685Seric { 6407942Seric TimeoutFlag = TRUE; 6417685Seric } 6427786Seric /* 6437786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6447786Seric ** 6457786Seric ** Parameters: 6467786Seric ** buf -- place to put result. 6477786Seric ** n -- bytes available. 6487786Seric ** f -- file to read from. 6497786Seric ** 6507786Seric ** Returns: 6517786Seric ** buf on success, NULL on error or EOF. 6527786Seric ** 6537786Seric ** Side Effects: 6547786Seric ** buf gets lines from f, with continuation lines (lines 6557786Seric ** with leading white space) appended. CRLF's are mapped 6567786Seric ** into single newlines. Any trailing NL is stripped. 6577786Seric */ 6587786Seric 6597786Seric char * 6607786Seric fgetfolded(buf, n, f) 6617786Seric char *buf; 6627786Seric register int n; 6637786Seric FILE *f; 6647786Seric { 6657786Seric register char *p = buf; 6667786Seric register int i; 6677786Seric 6687786Seric n--; 6698055Seric while (sfgets(p, n, f) != NULL) 6707786Seric { 6717786Seric fixcrlf(p, TRUE); 6727786Seric i = fgetc(f); 6737786Seric if (i != EOF) 6747786Seric ungetc(i, f); 6757786Seric if (i != ' ' && i != '\t') 6767786Seric return (buf); 6777786Seric i = strlen(p); 6787786Seric p += i; 6797786Seric *p++ = '\n'; 6807786Seric n -= i + 1; 6817786Seric } 6827786Seric return (NULL); 6837786Seric } 6847860Seric /* 6857860Seric ** PINTVL -- produce printable version of a time interval 6867860Seric ** 6877860Seric ** Parameters: 6887860Seric ** intvl -- the interval to be converted 6897860Seric ** brief -- if TRUE, print this in an extremely compact form 6907860Seric ** (basically used for logging). 6917860Seric ** 6927860Seric ** Returns: 6937860Seric ** A pointer to a string version of intvl suitable for 6947860Seric ** printing or framing. 6957860Seric ** 6967860Seric ** Side Effects: 6977860Seric ** none. 6987860Seric ** 6997860Seric ** Warning: 7007860Seric ** The string returned is in a static buffer. 7017860Seric */ 7027860Seric 7037860Seric # define PLURAL(n) ((n) == 1 ? "" : "s") 7047860Seric 7057860Seric char * 7067860Seric pintvl(intvl, brief) 7077860Seric time_t intvl; 7087860Seric bool brief; 7097860Seric { 7107860Seric static char buf[MAXNAME]; 7117860Seric register char *p; 7127860Seric int wk, dy, hr, mi, se; 7137860Seric 7147860Seric if (intvl == 0 && !brief) 7157860Seric return ("zero seconds"); 7167860Seric 7177860Seric /* decode the interval into weeks, days, hours, minutes, seconds */ 7187860Seric se = intvl % 60; 7197860Seric intvl /= 60; 7207860Seric mi = intvl % 60; 7217860Seric intvl /= 60; 7227860Seric hr = intvl % 24; 7237860Seric intvl /= 24; 7247860Seric if (brief) 7257860Seric dy = intvl; 7267860Seric else 7277860Seric { 7287860Seric dy = intvl % 7; 7297860Seric intvl /= 7; 7307860Seric wk = intvl; 7317860Seric } 7327860Seric 7337860Seric /* now turn it into a sexy form */ 7347860Seric p = buf; 7357860Seric if (brief) 7367860Seric { 7377860Seric if (dy > 0) 7387860Seric { 7397860Seric (void) sprintf(p, "%d+", dy); 7407860Seric p += strlen(p); 7417860Seric } 7427860Seric (void) sprintf(p, "%02d:%02d:%02d", hr, mi, se); 7437860Seric return (buf); 7447860Seric } 7457860Seric 7467860Seric /* use the verbose form */ 7477860Seric if (wk > 0) 7487860Seric { 7497860Seric (void) sprintf(p, ", %d week%s", wk, PLURAL(wk)); 7507860Seric p += strlen(p); 7517860Seric } 7527860Seric if (dy > 0) 7537860Seric { 7547860Seric (void) sprintf(p, ", %d day%s", dy, PLURAL(dy)); 7557860Seric p += strlen(p); 7567860Seric } 7577860Seric if (hr > 0) 7587860Seric { 7597860Seric (void) sprintf(p, ", %d hour%s", hr, PLURAL(hr)); 7607860Seric p += strlen(p); 7617860Seric } 7627860Seric if (mi > 0) 7637860Seric { 7647860Seric (void) sprintf(p, ", %d minute%s", mi, PLURAL(mi)); 7657860Seric p += strlen(p); 7667860Seric } 7677860Seric if (se > 0) 7687860Seric { 7697860Seric (void) sprintf(p, ", %d second%s", se, PLURAL(se)); 7707860Seric p += strlen(p); 7717860Seric } 7727860Seric 7737860Seric return (buf + 2); 7747860Seric } 7757886Seric /* 7767886Seric ** CURTIME -- return current time. 7777886Seric ** 7787886Seric ** Parameters: 7797886Seric ** none. 7807886Seric ** 7817886Seric ** Returns: 7827886Seric ** the current time. 7837886Seric ** 7847886Seric ** Side Effects: 7857886Seric ** none. 7867886Seric */ 7877886Seric 7887886Seric time_t 7897886Seric curtime() 7907886Seric { 7917886Seric auto time_t t; 7927886Seric 7937886Seric (void) time(&t); 7947886Seric return (t); 7957886Seric } 796*8264Seric /* 797*8264Seric ** ATOBOOL -- convert a string representation to boolean. 798*8264Seric ** 799*8264Seric ** Defaults to "TRUE" 800*8264Seric ** 801*8264Seric ** Parameters: 802*8264Seric ** s -- string to convert. Takes "tTyY" as true, 803*8264Seric ** others as false. 804*8264Seric ** 805*8264Seric ** Returns: 806*8264Seric ** A boolean representation of the string. 807*8264Seric ** 808*8264Seric ** Side Effects: 809*8264Seric ** none. 810*8264Seric */ 811*8264Seric 812*8264Seric bool 813*8264Seric atobool(s) 814*8264Seric register char *s; 815*8264Seric { 816*8264Seric if (*s == '\0' || index("tTyY", *s) != NULL) 817*8264Seric return (TRUE); 818*8264Seric return (FALSE); 819*8264Seric } 820