|
|
1.1 ! root 1: /* ! 2: ** Sendmail ! 3: ** Copyright (c) 1983 Eric P. Allman ! 4: ** Berkeley, California ! 5: ** ! 6: ** Copyright (c) 1983 Regents of the University of California. ! 7: ** All rights reserved. The Berkeley software License Agreement ! 8: ** specifies the terms and conditions for redistribution. ! 9: */ ! 10: ! 11: #ifndef lint ! 12: static char SccsId[] = "@(#)util.c 5.9 (Berkeley) 12/17/86"; ! 13: #endif not lint ! 14: ! 15: # include <stdio.h> ! 16: # include <sys/types.h> ! 17: # include <sys/stat.h> ! 18: # include <sysexits.h> ! 19: # include <errno.h> ! 20: # include "sendmail.h" ! 21: ! 22: /* ! 23: ** STRIPQUOTES -- Strip quotes & quote bits from a string. ! 24: ** ! 25: ** Runs through a string and strips off unquoted quote ! 26: ** characters and quote bits. This is done in place. ! 27: ** ! 28: ** Parameters: ! 29: ** s -- the string to strip. ! 30: ** qf -- if set, remove actual `` " '' characters ! 31: ** as well as the quote bits. ! 32: ** ! 33: ** Returns: ! 34: ** none. ! 35: ** ! 36: ** Side Effects: ! 37: ** none. ! 38: ** ! 39: ** Called By: ! 40: ** deliver ! 41: */ ! 42: ! 43: stripquotes(s, qf) ! 44: char *s; ! 45: bool qf; ! 46: { ! 47: register char *p; ! 48: register char *q; ! 49: register char c; ! 50: ! 51: if (s == NULL) ! 52: return; ! 53: ! 54: for (p = q = s; (c = *p++) != '\0'; ) ! 55: { ! 56: if (c != '"' || !qf) ! 57: *q++ = c & 0177; ! 58: } ! 59: *q = '\0'; ! 60: } ! 61: /* ! 62: ** QSTRLEN -- give me the string length assuming 0200 bits add a char ! 63: ** ! 64: ** Parameters: ! 65: ** s -- the string to measure. ! 66: ** ! 67: ** Reurns: ! 68: ** The length of s, including space for backslash escapes. ! 69: ** ! 70: ** Side Effects: ! 71: ** none. ! 72: */ ! 73: ! 74: qstrlen(s) ! 75: register char *s; ! 76: { ! 77: register int l = 0; ! 78: register char c; ! 79: ! 80: while ((c = *s++) != '\0') ! 81: { ! 82: if (bitset(0200, c)) ! 83: l++; ! 84: l++; ! 85: } ! 86: return (l); ! 87: } ! 88: /* ! 89: ** CAPITALIZE -- return a copy of a string, properly capitalized. ! 90: ** ! 91: ** Parameters: ! 92: ** s -- the string to capitalize. ! 93: ** ! 94: ** Returns: ! 95: ** a pointer to a properly capitalized string. ! 96: ** ! 97: ** Side Effects: ! 98: ** none. ! 99: */ ! 100: ! 101: char * ! 102: capitalize(s) ! 103: register char *s; ! 104: { ! 105: static char buf[50]; ! 106: register char *p; ! 107: ! 108: p = buf; ! 109: ! 110: for (;;) ! 111: { ! 112: while (!isalpha(*s) && *s != '\0') ! 113: *p++ = *s++; ! 114: if (*s == '\0') ! 115: break; ! 116: *p++ = toupper(*s++); ! 117: while (isalpha(*s)) ! 118: *p++ = *s++; ! 119: } ! 120: ! 121: *p = '\0'; ! 122: return (buf); ! 123: } ! 124: /* ! 125: ** XALLOC -- Allocate memory and bitch wildly on failure. ! 126: ** ! 127: ** THIS IS A CLUDGE. This should be made to give a proper ! 128: ** error -- but after all, what can we do? ! 129: ** ! 130: ** Parameters: ! 131: ** sz -- size of area to allocate. ! 132: ** ! 133: ** Returns: ! 134: ** pointer to data region. ! 135: ** ! 136: ** Side Effects: ! 137: ** Memory is allocated. ! 138: */ ! 139: ! 140: char * ! 141: xalloc(sz) ! 142: register int sz; ! 143: { ! 144: register char *p; ! 145: extern char *malloc(); ! 146: ! 147: p = malloc((unsigned) sz); ! 148: if (p == NULL) ! 149: { ! 150: syserr("Out of memory!!"); ! 151: abort(); ! 152: /* exit(EX_UNAVAILABLE); */ ! 153: } ! 154: return (p); ! 155: } ! 156: /* ! 157: ** COPYPLIST -- copy list of pointers. ! 158: ** ! 159: ** This routine is the equivalent of newstr for lists of ! 160: ** pointers. ! 161: ** ! 162: ** Parameters: ! 163: ** list -- list of pointers to copy. ! 164: ** Must be NULL terminated. ! 165: ** copycont -- if TRUE, copy the contents of the vector ! 166: ** (which must be a string) also. ! 167: ** ! 168: ** Returns: ! 169: ** a copy of 'list'. ! 170: ** ! 171: ** Side Effects: ! 172: ** none. ! 173: */ ! 174: ! 175: char ** ! 176: copyplist(list, copycont) ! 177: char **list; ! 178: bool copycont; ! 179: { ! 180: register char **vp; ! 181: register char **newvp; ! 182: ! 183: for (vp = list; *vp != NULL; vp++) ! 184: continue; ! 185: ! 186: vp++; ! 187: ! 188: newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); ! 189: bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); ! 190: ! 191: if (copycont) ! 192: { ! 193: for (vp = newvp; *vp != NULL; vp++) ! 194: *vp = newstr(*vp); ! 195: } ! 196: ! 197: return (newvp); ! 198: } ! 199: /* ! 200: ** PRINTAV -- print argument vector. ! 201: ** ! 202: ** Parameters: ! 203: ** av -- argument vector. ! 204: ** ! 205: ** Returns: ! 206: ** none. ! 207: ** ! 208: ** Side Effects: ! 209: ** prints av. ! 210: */ ! 211: ! 212: printav(av) ! 213: register char **av; ! 214: { ! 215: while (*av != NULL) ! 216: { ! 217: if (tTd(0, 44)) ! 218: printf("\n\t%08x=", *av); ! 219: else ! 220: (void) putchar(' '); ! 221: xputs(*av++); ! 222: } ! 223: (void) putchar('\n'); ! 224: } ! 225: /* ! 226: ** LOWER -- turn letter into lower case. ! 227: ** ! 228: ** Parameters: ! 229: ** c -- character to turn into lower case. ! 230: ** ! 231: ** Returns: ! 232: ** c, in lower case. ! 233: ** ! 234: ** Side Effects: ! 235: ** none. ! 236: */ ! 237: ! 238: char ! 239: lower(c) ! 240: register char c; ! 241: { ! 242: if (isascii(c) && isupper(c)) ! 243: c = c - 'A' + 'a'; ! 244: return (c); ! 245: } ! 246: /* ! 247: ** XPUTS -- put string doing control escapes. ! 248: ** ! 249: ** Parameters: ! 250: ** s -- string to put. ! 251: ** ! 252: ** Returns: ! 253: ** none. ! 254: ** ! 255: ** Side Effects: ! 256: ** output to stdout ! 257: */ ! 258: ! 259: xputs(s) ! 260: register char *s; ! 261: { ! 262: register char c; ! 263: ! 264: if (s == NULL) ! 265: { ! 266: printf("<null>"); ! 267: return; ! 268: } ! 269: (void) putchar('"'); ! 270: while ((c = *s++) != '\0') ! 271: { ! 272: if (!isascii(c)) ! 273: { ! 274: (void) putchar('\\'); ! 275: c &= 0177; ! 276: } ! 277: if (c < 040 || c >= 0177) ! 278: { ! 279: (void) putchar('^'); ! 280: c ^= 0100; ! 281: } ! 282: (void) putchar(c); ! 283: } ! 284: (void) putchar('"'); ! 285: (void) fflush(stdout); ! 286: } ! 287: /* ! 288: ** MAKELOWER -- Translate a line into lower case ! 289: ** ! 290: ** Parameters: ! 291: ** p -- the string to translate. If NULL, return is ! 292: ** immediate. ! 293: ** ! 294: ** Returns: ! 295: ** none. ! 296: ** ! 297: ** Side Effects: ! 298: ** String pointed to by p is translated to lower case. ! 299: ** ! 300: ** Called By: ! 301: ** parse ! 302: */ ! 303: ! 304: makelower(p) ! 305: register char *p; ! 306: { ! 307: register char c; ! 308: ! 309: if (p == NULL) ! 310: return; ! 311: for (; (c = *p) != '\0'; p++) ! 312: if (isascii(c) && isupper(c)) ! 313: *p = c - 'A' + 'a'; ! 314: } ! 315: /* ! 316: ** SAMEWORD -- return TRUE if the words are the same ! 317: ** ! 318: ** Ignores case. ! 319: ** ! 320: ** Parameters: ! 321: ** a, b -- the words to compare. ! 322: ** ! 323: ** Returns: ! 324: ** TRUE if a & b match exactly (modulo case) ! 325: ** FALSE otherwise. ! 326: ** ! 327: ** Side Effects: ! 328: ** none. ! 329: */ ! 330: ! 331: bool ! 332: sameword(a, b) ! 333: register char *a, *b; ! 334: { ! 335: char ca, cb; ! 336: ! 337: do ! 338: { ! 339: ca = *a++; ! 340: cb = *b++; ! 341: if (isascii(ca) && isupper(ca)) ! 342: ca = ca - 'A' + 'a'; ! 343: if (isascii(cb) && isupper(cb)) ! 344: cb = cb - 'A' + 'a'; ! 345: } while (ca != '\0' && ca == cb); ! 346: return (ca == cb); ! 347: } ! 348: /* ! 349: ** BUILDFNAME -- build full name from gecos style entry. ! 350: ** ! 351: ** This routine interprets the strange entry that would appear ! 352: ** in the GECOS field of the password file. ! 353: ** ! 354: ** Parameters: ! 355: ** p -- name to build. ! 356: ** login -- the login name of this user (for &). ! 357: ** buf -- place to put the result. ! 358: ** ! 359: ** Returns: ! 360: ** none. ! 361: ** ! 362: ** Side Effects: ! 363: ** none. ! 364: */ ! 365: ! 366: buildfname(p, login, buf) ! 367: register char *p; ! 368: char *login; ! 369: char *buf; ! 370: { ! 371: register char *bp = buf; ! 372: ! 373: if (*p == '*') ! 374: p++; ! 375: while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') ! 376: { ! 377: if (*p == '&') ! 378: { ! 379: (void) strcpy(bp, login); ! 380: *bp = toupper(*bp); ! 381: while (*bp != '\0') ! 382: bp++; ! 383: p++; ! 384: } ! 385: else ! 386: *bp++ = *p++; ! 387: } ! 388: *bp = '\0'; ! 389: } ! 390: /* ! 391: ** SAFEFILE -- return true if a file exists and is safe for a user. ! 392: ** ! 393: ** Parameters: ! 394: ** fn -- filename to check. ! 395: ** uid -- uid to compare against. ! 396: ** mode -- mode bits that must match. ! 397: ** ! 398: ** Returns: ! 399: ** TRUE if fn exists, is owned by uid, and matches mode. ! 400: ** FALSE otherwise. ! 401: ** ! 402: ** Side Effects: ! 403: ** none. ! 404: */ ! 405: ! 406: bool ! 407: safefile(fn, uid, mode) ! 408: char *fn; ! 409: int uid; ! 410: int mode; ! 411: { ! 412: struct stat stbuf; ! 413: ! 414: if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && ! 415: (stbuf.st_mode & mode) == mode) ! 416: return (TRUE); ! 417: errno = 0; ! 418: return (FALSE); ! 419: } ! 420: /* ! 421: ** FIXCRLF -- fix <CR><LF> in line. ! 422: ** ! 423: ** Looks for the <CR><LF> combination and turns it into the ! 424: ** UNIX canonical <NL> character. It only takes one line, ! 425: ** i.e., it is assumed that the first <NL> found is the end ! 426: ** of the line. ! 427: ** ! 428: ** Parameters: ! 429: ** line -- the line to fix. ! 430: ** stripnl -- if true, strip the newline also. ! 431: ** ! 432: ** Returns: ! 433: ** none. ! 434: ** ! 435: ** Side Effects: ! 436: ** line is changed in place. ! 437: */ ! 438: ! 439: fixcrlf(line, stripnl) ! 440: char *line; ! 441: bool stripnl; ! 442: { ! 443: register char *p; ! 444: ! 445: p = index(line, '\n'); ! 446: if (p == NULL) ! 447: return; ! 448: if (p[-1] == '\r') ! 449: p--; ! 450: if (!stripnl) ! 451: *p++ = '\n'; ! 452: *p = '\0'; ! 453: } ! 454: /* ! 455: ** DFOPEN -- determined file open ! 456: ** ! 457: ** This routine has the semantics of fopen, except that it will ! 458: ** keep trying a few times to make this happen. The idea is that ! 459: ** on very loaded systems, we may run out of resources (inodes, ! 460: ** whatever), so this tries to get around it. ! 461: */ ! 462: ! 463: FILE * ! 464: dfopen(filename, mode) ! 465: char *filename; ! 466: char *mode; ! 467: { ! 468: register int tries; ! 469: register FILE *fp; ! 470: ! 471: for (tries = 0; tries < 10; tries++) ! 472: { ! 473: sleep((unsigned) (10 * tries)); ! 474: errno = 0; ! 475: fp = fopen(filename, mode); ! 476: if (fp != NULL) ! 477: break; ! 478: if (errno != ENFILE && errno != EINTR) ! 479: break; ! 480: } ! 481: errno = 0; ! 482: return (fp); ! 483: } ! 484: /* ! 485: ** PUTLINE -- put a line like fputs obeying SMTP conventions ! 486: ** ! 487: ** This routine always guarantees outputing a newline (or CRLF, ! 488: ** as appropriate) at the end of the string. ! 489: ** ! 490: ** Parameters: ! 491: ** l -- line to put. ! 492: ** fp -- file to put it onto. ! 493: ** m -- the mailer used to control output. ! 494: ** ! 495: ** Returns: ! 496: ** none ! 497: ** ! 498: ** Side Effects: ! 499: ** output of l to fp. ! 500: */ ! 501: ! 502: # define SMTPLINELIM 990 /* maximum line length */ ! 503: ! 504: putline(l, fp, m) ! 505: register char *l; ! 506: FILE *fp; ! 507: MAILER *m; ! 508: { ! 509: register char *p; ! 510: char svchar; ! 511: ! 512: /* strip out 0200 bits -- these can look like TELNET protocol */ ! 513: if (bitnset(M_LIMITS, m->m_flags)) ! 514: { ! 515: p = l; ! 516: while ((*p++ &= ~0200) != 0) ! 517: continue; ! 518: } ! 519: ! 520: do ! 521: { ! 522: /* find the end of the line */ ! 523: p = index(l, '\n'); ! 524: if (p == NULL) ! 525: p = &l[strlen(l)]; ! 526: ! 527: /* check for line overflow */ ! 528: while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) ! 529: { ! 530: register char *q = &l[SMTPLINELIM - 1]; ! 531: ! 532: svchar = *q; ! 533: *q = '\0'; ! 534: if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) ! 535: (void) putc('.', fp); ! 536: fputs(l, fp); ! 537: (void) putc('!', fp); ! 538: fputs(m->m_eol, fp); ! 539: *q = svchar; ! 540: l = q; ! 541: } ! 542: ! 543: /* output last part */ ! 544: svchar = *p; ! 545: *p = '\0'; ! 546: if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) ! 547: (void) putc('.', fp); ! 548: fputs(l, fp); ! 549: fputs(m->m_eol, fp); ! 550: *p = svchar; ! 551: l = p; ! 552: if (*l == '\n') ! 553: l++; ! 554: } while (l[0] != '\0'); ! 555: } ! 556: /* ! 557: ** XUNLINK -- unlink a file, doing logging as appropriate. ! 558: ** ! 559: ** Parameters: ! 560: ** f -- name of file to unlink. ! 561: ** ! 562: ** Returns: ! 563: ** none. ! 564: ** ! 565: ** Side Effects: ! 566: ** f is unlinked. ! 567: */ ! 568: ! 569: xunlink(f) ! 570: char *f; ! 571: { ! 572: register int i; ! 573: ! 574: # ifdef LOG ! 575: if (LogLevel > 20) ! 576: syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); ! 577: # endif LOG ! 578: ! 579: i = unlink(f); ! 580: # ifdef LOG ! 581: if (i < 0 && LogLevel > 21) ! 582: syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); ! 583: # endif LOG ! 584: } ! 585: /* ! 586: ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. ! 587: ** ! 588: ** Parameters: ! 589: ** buf -- place to put the input line. ! 590: ** siz -- size of buf. ! 591: ** fp -- file to read from. ! 592: ** ! 593: ** Returns: ! 594: ** NULL on error (including timeout). This will also leave ! 595: ** buf containing a null string. ! 596: ** buf otherwise. ! 597: ** ! 598: ** Side Effects: ! 599: ** none. ! 600: */ ! 601: ! 602: static jmp_buf CtxReadTimeout; ! 603: ! 604: #ifndef ETIMEDOUT ! 605: #define ETIMEDOUT EINTR ! 606: #endif ! 607: ! 608: char * ! 609: sfgets(buf, siz, fp) ! 610: char *buf; ! 611: int siz; ! 612: FILE *fp; ! 613: { ! 614: register EVENT *ev = NULL; ! 615: register char *p; ! 616: extern readtimeout(); ! 617: ! 618: /* set the timeout */ ! 619: if (ReadTimeout != 0) ! 620: { ! 621: if (setjmp(CtxReadTimeout) != 0) ! 622: { ! 623: errno = ETIMEDOUT; ! 624: syserr("net timeout"); ! 625: buf[0] = '\0'; ! 626: return (NULL); ! 627: } ! 628: ev = setevent((time_t) ReadTimeout, readtimeout, 0); ! 629: } ! 630: ! 631: /* try to read */ ! 632: p = NULL; ! 633: while (p == NULL && !feof(fp) && !ferror(fp)) ! 634: { ! 635: errno = 0; ! 636: p = fgets(buf, siz, fp); ! 637: if (errno == EINTR) ! 638: clearerr(fp); ! 639: } ! 640: ! 641: /* clear the event if it has not sprung */ ! 642: clrevent(ev); ! 643: ! 644: /* clean up the books and exit */ ! 645: LineNumber++; ! 646: if (p == NULL) ! 647: { ! 648: buf[0] = '\0'; ! 649: return (NULL); ! 650: } ! 651: for (p = buf; *p != '\0'; p++) ! 652: *p &= ~0200; ! 653: return (buf); ! 654: } ! 655: ! 656: static ! 657: readtimeout() ! 658: { ! 659: longjmp(CtxReadTimeout, 1); ! 660: } ! 661: /* ! 662: ** FGETFOLDED -- like fgets, but know about folded lines. ! 663: ** ! 664: ** Parameters: ! 665: ** buf -- place to put result. ! 666: ** n -- bytes available. ! 667: ** f -- file to read from. ! 668: ** ! 669: ** Returns: ! 670: ** buf on success, NULL on error or EOF. ! 671: ** ! 672: ** Side Effects: ! 673: ** buf gets lines from f, with continuation lines (lines ! 674: ** with leading white space) appended. CRLF's are mapped ! 675: ** into single newlines. Any trailing NL is stripped. ! 676: */ ! 677: ! 678: char * ! 679: fgetfolded(buf, n, f) ! 680: char *buf; ! 681: register int n; ! 682: FILE *f; ! 683: { ! 684: register char *p = buf; ! 685: register int i; ! 686: ! 687: n--; ! 688: while ((i = getc(f)) != EOF) ! 689: { ! 690: if (i == '\r') ! 691: { ! 692: i = getc(f); ! 693: if (i != '\n') ! 694: { ! 695: if (i != EOF) ! 696: (void) ungetc(i, f); ! 697: i = '\r'; ! 698: } ! 699: } ! 700: if (--n > 0) ! 701: *p++ = i; ! 702: if (i == '\n') ! 703: { ! 704: LineNumber++; ! 705: i = getc(f); ! 706: if (i != EOF) ! 707: (void) ungetc(i, f); ! 708: if (i != ' ' && i != '\t') ! 709: { ! 710: *--p = '\0'; ! 711: return (buf); ! 712: } ! 713: } ! 714: } ! 715: return (NULL); ! 716: } ! 717: /* ! 718: ** CURTIME -- return current time. ! 719: ** ! 720: ** Parameters: ! 721: ** none. ! 722: ** ! 723: ** Returns: ! 724: ** the current time. ! 725: ** ! 726: ** Side Effects: ! 727: ** none. ! 728: */ ! 729: ! 730: time_t ! 731: curtime() ! 732: { ! 733: auto time_t t; ! 734: ! 735: (void) time(&t); ! 736: return (t); ! 737: } ! 738: /* ! 739: ** ATOBOOL -- convert a string representation to boolean. ! 740: ** ! 741: ** Defaults to "TRUE" ! 742: ** ! 743: ** Parameters: ! 744: ** s -- string to convert. Takes "tTyY" as true, ! 745: ** others as false. ! 746: ** ! 747: ** Returns: ! 748: ** A boolean representation of the string. ! 749: ** ! 750: ** Side Effects: ! 751: ** none. ! 752: */ ! 753: ! 754: bool ! 755: atobool(s) ! 756: register char *s; ! 757: { ! 758: if (*s == '\0' || index("tTyY", *s) != NULL) ! 759: return (TRUE); ! 760: return (FALSE); ! 761: } ! 762: /* ! 763: ** ATOOCT -- convert a string representation to octal. ! 764: ** ! 765: ** Parameters: ! 766: ** s -- string to convert. ! 767: ** ! 768: ** Returns: ! 769: ** An integer representing the string interpreted as an ! 770: ** octal number. ! 771: ** ! 772: ** Side Effects: ! 773: ** none. ! 774: */ ! 775: ! 776: atooct(s) ! 777: register char *s; ! 778: { ! 779: register int i = 0; ! 780: ! 781: while (*s >= '0' && *s <= '7') ! 782: i = (i << 3) | (*s++ - '0'); ! 783: return (i); ! 784: } ! 785: /* ! 786: ** WAITFOR -- wait for a particular process id. ! 787: ** ! 788: ** Parameters: ! 789: ** pid -- process id to wait for. ! 790: ** ! 791: ** Returns: ! 792: ** status of pid. ! 793: ** -1 if pid never shows up. ! 794: ** ! 795: ** Side Effects: ! 796: ** none. ! 797: */ ! 798: ! 799: waitfor(pid) ! 800: int pid; ! 801: { ! 802: auto int st; ! 803: int i; ! 804: ! 805: do ! 806: { ! 807: errno = 0; ! 808: i = wait(&st); ! 809: } while ((i >= 0 || errno == EINTR) && i != pid); ! 810: if (i < 0) ! 811: st = -1; ! 812: return (st); ! 813: } ! 814: /* ! 815: ** BITINTERSECT -- tell if two bitmaps intersect ! 816: ** ! 817: ** Parameters: ! 818: ** a, b -- the bitmaps in question ! 819: ** ! 820: ** Returns: ! 821: ** TRUE if they have a non-null intersection ! 822: ** FALSE otherwise ! 823: ** ! 824: ** Side Effects: ! 825: ** none. ! 826: */ ! 827: ! 828: bool ! 829: bitintersect(a, b) ! 830: BITMAP a; ! 831: BITMAP b; ! 832: { ! 833: int i; ! 834: ! 835: for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) ! 836: if ((a[i] & b[i]) != 0) ! 837: return (TRUE); ! 838: return (FALSE); ! 839: } ! 840: /* ! 841: ** BITZEROP -- tell if a bitmap is all zero ! 842: ** ! 843: ** Parameters: ! 844: ** map -- the bit map to check ! 845: ** ! 846: ** Returns: ! 847: ** TRUE if map is all zero. ! 848: ** FALSE if there are any bits set in map. ! 849: ** ! 850: ** Side Effects: ! 851: ** none. ! 852: */ ! 853: ! 854: bool ! 855: bitzerop(map) ! 856: BITMAP map; ! 857: { ! 858: int i; ! 859: ! 860: for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) ! 861: if (map[i] != 0) ! 862: return (FALSE); ! 863: return (TRUE); ! 864: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.