util.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 891 行
C
891 行
#ifndef lintstatic char *sccsid = "@(#)util.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1987 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************/# include <stdio.h># include <sys/types.h># include <sys/stat.h># include <sysexits.h># include <errno.h># include <ctype.h># include "sendmail.h"/*** STRIPQUOTES -- Strip quotes & quote bits from a string.**** Runs through a string and strips off unquoted quote** characters and quote bits. This is done in place.**** Parameters:** s -- the string to strip.** qf -- if set, remove actual `` " '' characters** as well as the quote bits.**** Returns:** none.**** Side Effects:** none.**** Called By:** deliver*/stripquotes(s, qf) char *s; bool qf;{ register char *p; register char *q; register char c; if (s == NULL) return; for (p = q = s; (c = *p++) != '\0'; ) { if (c != '"' || !qf) *q++ = c & 0177; } *q = '\0';}/*** QSTRLEN -- give me the string length assuming 0200 bits add a char**** Parameters:** s -- the string to measure.**** Reurns:** The length of s, including space for backslash escapes.**** Side Effects:** none.*/qstrlen(s) register char *s;{ register int l = 0; register char c; while ((c = *s++) != '\0') { if (bitset(0200, c)) l++; l++; } return (l);}/*** CAPITALIZE -- return a copy of a string, properly capitalized.**** Parameters:** s -- the string to capitalize.**** Returns:** a pointer to a properly capitalized string.**** Side Effects:** none.*/char *capitalize(s) register char *s;{ static char buf[50]; register char *p; p = buf; for (;;) { while (!isalpha(*s) && *s != '\0') *p++ = *s++; if (*s == '\0') break; *p++ = toupper(*s++); while (isalpha(*s)) *p++ = *s++; } *p = '\0'; return (buf);}/*** XALLOC -- Allocate memory and bitch wildly on failure.**** THIS IS A CLUDGE. This should be made to give a proper** error -- but after all, what can we do?**** Parameters:** sz -- size of area to allocate.**** Returns:** pointer to data region.**** Side Effects:** Memory is allocated.*/char *xalloc(sz) register int sz;{ register char *p; extern char *malloc(); p = malloc((unsigned) sz); if (p == NULL) { syserr("Out of memory!!"); abort(); /* exit(EX_UNAVAILABLE); */ } return (p);}/*** COPYPLIST -- copy list of pointers.**** This routine is the equivalent of newstr for lists of** pointers.**** Parameters:** list -- list of pointers to copy.** Must be NULL terminated.** copycont -- if TRUE, copy the contents of the vector** (which must be a string) also.**** Returns:** a copy of 'list'.**** Side Effects:** none.*/char **copyplist(list, copycont) char **list; bool copycont;{ register char **vp; register char **newvp; for (vp = list; *vp != NULL; vp++) continue; vp++; newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); if (copycont) { for (vp = newvp; *vp != NULL; vp++) *vp = newstr(*vp); } return (newvp);}/*** PRINTAV -- print argument vector.**** Parameters:** av -- argument vector.**** Returns:** none.**** Side Effects:** prints av.*/printav(av) register char **av;{ while (*av != NULL) { if (tTd(0, 44)) printf("\n\t%08x=", *av); else (void) putchar(' '); xputs(*av++); } (void) putchar('\n');}/*** LOWER -- turn letter into lower case.**** Parameters:** c -- character to turn into lower case.**** Returns:** c, in lower case.**** Side Effects:** none.*/charlower(c) register char c;{ if (isascii(c) && isupper(c)) c = c - 'A' + 'a'; return (c);}/*** XPUTS -- put string doing control escapes.**** Parameters:** s -- string to put.**** Returns:** none.**** Side Effects:** output to stdout*/xputs(s) register char *s;{ register char c; if (s == NULL) { printf("<null>"); return; } (void) putchar('"'); while ((c = *s++) != '\0') { if (!isascii(c)) { (void) putchar('\\'); c &= 0177; } if (c < 040 || c >= 0177) { (void) putchar('^'); c ^= 0100; } (void) putchar(c); } (void) putchar('"'); (void) fflush(stdout);}/*** MAKELOWER -- Translate a line into lower case**** Parameters:** p -- the string to translate. If NULL, return is** immediate.**** Returns:** none.**** Side Effects:** String pointed to by p is translated to lower case.**** Called By:** parse*/makelower(p) register char *p;{ register char c; if (p == NULL) return; for (; (c = *p) != '\0'; p++) if (isascii(c) && isupper(c)) *p = c - 'A' + 'a';}/*** SAMEWORD -- return TRUE if the words are the same**** Ignores case.**** Parameters:** a, b -- the words to compare.**** Returns:** TRUE if a & b match exactly (modulo case)** FALSE otherwise.**** Side Effects:** none.*/boolsameword(a, b) register char *a, *b;{ char ca, cb; do { ca = *a++; cb = *b++; if (isascii(ca) && isupper(ca)) ca = ca - 'A' + 'a'; if (isascii(cb) && isupper(cb)) cb = cb - 'A' + 'a'; } while (ca != '\0' && ca == cb); return (ca == cb);}/*** BUILDFNAME -- build full name from gecos style entry.**** This routine interprets the strange entry that would appear** in the GECOS field of the password file.**** Parameters:** p -- name to build.** login -- the login name of this user (for &).** buf -- place to put the result.**** Returns:** none.**** Side Effects:** none.*/buildfname(p, login, buf) register char *p; char *login; char *buf;{ register char *bp = buf; if (*p == '*') p++; while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') { if (*p == '&') { (void) strcpy(bp, login); *bp = toupper(*bp); while (*bp != '\0') bp++; p++; } else *bp++ = *p++; } *bp = '\0';}/*** SAFEFILE -- return true if a file exists and is safe for a user.**** Parameters:** fn -- filename to check.** uid -- uid to compare against.** mode -- mode bits that must match.**** Returns:** TRUE if fn exists, is owned by uid, and matches mode.** FALSE otherwise.**** Side Effects:** none.*/boolsafefile(fn, uid, mode) char *fn; int uid; int mode;{ struct stat stbuf; if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) return (TRUE); errno = 0; return (FALSE);}/*** FIXCRLF -- fix <CR><LF> in line.**** Looks for the <CR><LF> combination and turns it into the** UNIX canonical <NL> character. It only takes one line,** i.e., it is assumed that the first <NL> found is the end** of the line.**** Parameters:** line -- the line to fix.** stripnl -- if true, strip the newline also.**** Returns:** none.**** Side Effects:** line is changed in place.*/fixcrlf(line, stripnl) char *line; bool stripnl;{ register char *p; p = index(line, '\n'); if (p == NULL) return;/* * Fix handling of blank lines .. p[-1] in this case might be trash. * * if (p[-1] == '\r') */ if (p != line && p[-1] == '\r') p--; if (!stripnl) *p++ = '\n'; *p = '\0';}/*** DFOPEN -- determined file open**** This routine has the semantics of fopen, except that it will** keep trying a few times to make this happen. The idea is that** on very loaded systems, we may run out of resources (inodes,** whatever), so this tries to get around it.*/FILE *dfopen(filename, mode) char *filename; char *mode;{ register int tries; register FILE *fp; for (tries = 0; tries < 10; tries++) { sleep((unsigned) (10 * tries)); errno = 0; fp = fopen(filename, mode); if (fp != NULL) break; if (errno != ENFILE && errno != EINTR) break; } errno = 0; return (fp);}/*** PUTLINE -- put a line like fputs obeying SMTP conventions**** This routine always guarantees outputing a newline (or CRLF,** as appropriate) at the end of the string.**** Parameters:** l -- line to put.** fp -- file to put it onto.** m -- the mailer used to control output.**** Returns:** none**** Side Effects:** output of l to fp.*/# define SMTPLINELIM 990 /* maximum line length */putline(l, fp, m) register char *l; FILE *fp; MAILER *m;{ register char *p; char svchar; /* strip out 0200 bits -- these can look like TELNET protocol */ if (bitnset(M_LIMITS, m->m_flags)) { p = l; while ((*p++ &= ~0200) != 0) continue; } do { /* find the end of the line */ p = index(l, '\n'); if (p == NULL) p = &l[strlen(l)]; /* check for line overflow */ while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) { register char *q = &l[SMTPLINELIM - 1]; svchar = *q; *q = '\0'; if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) (void) putc('.', fp); fputs(l, fp); (void) putc('!', fp); fputs(m->m_eol, fp); *q = svchar; l = q; } /* output last part */ svchar = *p; *p = '\0'; if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) (void) putc('.', fp); fputs(l, fp); fputs(m->m_eol, fp); *p = svchar; l = p; if (*l == '\n') l++; } while (l[0] != '\0');}/*** XUNLINK -- unlink a file, doing logging as appropriate.**** Parameters:** f -- name of file to unlink.**** Returns:** none.**** Side Effects:** f is unlinked.*/xunlink(f) char *f;{ register int i;# ifdef LOG if (LogLevel > 20) syslog(LOG_INFO, "%s: unlink %s\n", CurEnv->e_id, f);# endif LOG i = unlink(f);# ifdef LOG if (i < 0 && LogLevel > 21) syslog(LOG_INFO, "%s: unlink-fail %d", f, errno);# endif LOG}/*** SFGETS -- "safe" fgets -- times out and ignores random interrupts.**** Parameters:** buf -- place to put the input line.** siz -- size of buf.** fp -- file to read from.**** Returns:** NULL on error (including timeout). This will also leave** buf containing a null string.** buf otherwise.**** Side Effects:** none.*/static jmp_buf CtxReadTimeout;#ifndef ETIMEDOUT#define ETIMEDOUT EINTR#endifchar *sfgets(buf, siz, fp) char *buf; int siz; FILE *fp;{ register EVENT *ev = NULL; register char *p; extern readtimeout(); /* set the timeout */ if (ReadTimeout != 0) { if (setjmp(CtxReadTimeout) != 0) { errno = ETIMEDOUT; syserr("net timeout"); buf[0] = '\0'; return (NULL); } ev = setevent((time_t) ReadTimeout, readtimeout, 0); } /* try to read */ p = NULL; while (p == NULL && !feof(fp) && !ferror(fp)) { errno = 0; p = fgets(buf, siz, fp); if (errno == EINTR) clearerr(fp); } /* clear the event if it has not sprung */ clrevent(ev); /* clean up the books and exit */ LineNumber++; if (p == NULL) { buf[0] = '\0'; return (NULL); } for (p = buf; *p != '\0'; p++) *p &= ~0200; return (buf);}staticreadtimeout(){ longjmp(CtxReadTimeout, 1);}/*** FGETFOLDED -- like fgets, but know about folded lines.**** Parameters:** buf -- place to put result.** n -- bytes available.** f -- file to read from.**** Returns:** buf on success, NULL on error or EOF.**** Side Effects:** buf gets lines from f, with continuation lines (lines** with leading white space) appended. CRLF's are mapped** into single newlines. Any trailing NL is stripped.*/char *fgetfolded(buf, n, f) char *buf; register int n; FILE *f;{ register char *p = buf; register int i; n--; while ((i = getc(f)) != EOF) { if (i == '\r') { i = getc(f); if (i != '\n') { if (i != EOF) (void) ungetc(i, f); i = '\r'; } } if (--n > 0) *p++ = i; if (i == '\n') { LineNumber++; i = getc(f); if (i != EOF) (void) ungetc(i, f); if (i != ' ' && i != '\t') { *--p = '\0'; return (buf); } } } return (NULL);}/*** CURTIME -- return current time.**** Parameters:** none.**** Returns:** the current time.**** Side Effects:** none.*/time_tcurtime(){ auto time_t t; (void) time(&t); return (t);}/*** ATOBOOL -- convert a string representation to boolean.**** Defaults to "TRUE"**** Parameters:** s -- string to convert. Takes "tTyY" as true,** others as false.**** Returns:** A boolean representation of the string.**** Side Effects:** none.*/boolatobool(s) register char *s;{ if (*s == '\0' || index("tTyY", *s) != NULL) return (TRUE); return (FALSE);}/*** ATOOCT -- convert a string representation to octal.**** Parameters:** s -- string to convert.**** Returns:** An integer representing the string interpreted as an** octal number.**** Side Effects:** none.*/atooct(s) register char *s;{ register int i = 0; while (*s >= '0' && *s <= '7') i = (i << 3) | (*s++ - '0'); return (i);}/*** WAITFOR -- wait for a particular process id.**** Parameters:** pid -- process id to wait for.**** Returns:** status of pid.** -1 if pid never shows up.**** Side Effects:** none.*/waitfor(pid) int pid;{ auto int st; int i; do { errno = 0; i = wait(&st); } while ((i >= 0 || errno == EINTR) && i != pid); if (i < 0) st = -1; return (st);}/*** BITINTERSECT -- tell if two bitmaps intersect**** Parameters:** a, b -- the bitmaps in question**** Returns:** TRUE if they have a non-null intersection** FALSE otherwise**** Side Effects:** none.*/boolbitintersect(a, b) BITMAP a; BITMAP b;{ int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) if ((a[i] & b[i]) != 0) return (TRUE); return (FALSE);}/*** BITZEROP -- tell if a bitmap is all zero**** Parameters:** map -- the bit map to check**** Returns:** TRUE if map is all zero.** FALSE if there are any bits set in map.**** Side Effects:** none.*/boolbitzerop(map) BITMAP map;{ int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) if (map[i] != 0) return (FALSE); return (TRUE);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?