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