|
|
1.1 ! root 1: /* m_getfld.c - read/parse a message */ ! 2: ! 3: #include "../h/mh.h" ! 4: #include <stdio.h> ! 5: #include "../zotnet/mts.h" ! 6: #include <ctype.h> ! 7: ! 8: ! 9: /* This module has a long and checkered history. First, it didn't burst ! 10: maildrops correctly because it considered two CTRL-A:s in a row to be ! 11: an inter-message delimiter. It really is four CTRL-A:s followed by a ! 12: newline. Unfortunately, MMDF will convert this delimiter *inside* a ! 13: message to a CTRL-B followed by three CTRL-A:s and a newline. This ! 14: caused the old version of m_getfld() to declare eom prematurely. The ! 15: fix was a lot slower than ! 16: ! 17: c == '\001' && peekc (iob) == '\001' ! 18: ! 19: but it worked, and to increase generality, UUCP style maildrops could ! 20: be parsed as well. Unfortunately the speed issue finally caught up with ! 21: us since this routine is at the very heart of MH. ! 22: ! 23: To speed things up considerably, the routine Eom() was made an auxilary ! 24: function called by the macro eom(). Unless we are bursting a maildrop, ! 25: the eom() macro returns FALSE saying we aren't at the end of the ! 26: message. ! 27: ! 28: The next thing to do is to read the mtstailor file and initialize ! 29: delimiter[] and delimlen accordingly... ! 30: ! 31: After mhl was made a built-in in msh, m_getfld() worked just fine ! 32: (using m_unknown() at startup). Until one day: a message which was ! 33: the result of a bursting was shown. Then, since the burst boundaries ! 34: aren't CTRL-A:s, m_getfld() would blinding plunge on past the boundary. ! 35: Very sad. The solution: introduce m_eomsbr(). This hook gets called ! 36: after the end of each line (since testing for eom involves an fseek()). ! 37: This worked fine, until one day: a message with no body portion arrived. ! 38: Then the ! 39: ! 40: while (eom (c = Getc (iob), iob)) ! 41: continue; ! 42: ! 43: loop caused m_getfld() to return FMTERR. So, that logic was changed to ! 44: check for (*eom_action) and act accordingly. ! 45: ! 46: This worked fine, until one day: someone didn't use four CTRL:A's as ! 47: their delimiters. So, the bullet got bit and we read mts.h and ! 48: continue to struggle on. It's not that bad though, since the only time ! 49: the code gets executed is when inc (or msh) calls it, and both of these ! 50: have already called mts_init(). ! 51: ! 52: ------------------------ ! 53: (Written by Van Jacobson for the mh6 m_getfld, January, 1986): ! 54: ! 55: This routine was accounting for 60% of the cpu time used by most mh ! 56: programs. I spent a bit of time tuning and it now accounts for <10% ! 57: of the time used. Like any heavily tuned routine, it's a bit ! 58: complex and you want to be sure you understand everything that it's ! 59: doing before you start hacking on it. Let me try to emphasize ! 60: that: every line in this atrocity depends on every other line, ! 61: sometimes in subtle ways. You should understand it all, in detail, ! 62: before trying to change any part. If you do change it, test the ! 63: result thoroughly (I use a hand-constructed test file that exercises ! 64: all the ways a header name, header body, header continuation, ! 65: header-body separator, body line and body eom can align themselves ! 66: with respect to a buffer boundary). "Minor" bugs in this routine ! 67: result in garbaged or lost mail. ! 68: ! 69: If you hack on this and slow it down, I, my children and my ! 70: children's children will curse you. ! 71: ! 72: This routine gets used on three different types of files: normal, ! 73: single msg files, "packed" unix or mmdf mailboxs (when used by inc) ! 74: and packed, directoried bulletin board files (when used by msh). ! 75: The biggest impact of different file types is in "eom" testing. The ! 76: code has been carefully organized to test for eom at appropriate ! 77: times and at no other times (since the check is quite expensive). ! 78: I have tried to arrange things so that the eom check need only be ! 79: done on entry to this routine. Since an eom can only occur after a ! 80: newline, this is easy to manage for header fields. For the msg ! 81: body, we try to efficiently search the input buffer to see if ! 82: contains the eom delimiter. If it does, we take up to the ! 83: delimiter, otherwise we take everything in the buffer. (The change ! 84: to the body eom/copy processing produced the most noticeable ! 85: performance difference, particularly for "inc" and "show".) ! 86: ! 87: There are three qualitatively different things this routine busts ! 88: out of a message: field names, field text and msg bodies. Field ! 89: names are typically short (~8 char) and the loop that extracts them ! 90: might terminate on a colon, newline or max width. I considered ! 91: using a Vax "scanc" to locate the end of the field followed by a ! 92: "bcopy" but the routine call overhead on a Vax is too large for this ! 93: to work on short names. If Berkeley ever makes "inline" part of the ! 94: C optimiser (so things like "scanc" turn into inline instructions) a ! 95: change here would be worthwhile. ! 96: ! 97: Field text is typically 60 - 100 characters so there's (barely) ! 98: a win in doing a routine call to something that does a "locc" ! 99: followed by a "bmove". About 30% of the fields have continuations ! 100: (usually the 822 "received:" lines) and each continuation generates ! 101: another routine call. "Inline" would be a big win here, as well. ! 102: ! 103: Messages, as of this writing, seem to come in two flavors: small ! 104: (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers ! 105: so message bodies average at least a few hundred characters. ! 106: Assuming your system uses reasonably sized stdio buffers (1K or ! 107: more), this routine should be able to remove the body in large ! 108: (>500 byte) chunks. The makes the cost of a call to "bcopy" ! 109: small but there is a premium on checking for the eom in packed ! 110: maildrops. The eom pattern is always a simple string so we can ! 111: construct an efficient pattern matcher for it (e.g., a Vax "matchc" ! 112: instruction). Some thought went into recognizing the start of ! 113: an eom that has been split across two buffers. ! 114: ! 115: This routine wants to deal with large chunks of data so, rather ! 116: than "getc" into a local buffer, it uses stdio's buffer. If ! 117: you try to use it on a non-buffered file, you'll get what you ! 118: deserve. This routine "knows" that struct FILEs have a _ptr ! 119: and a _cnt to describe the current state of the buffer and ! 120: it knows that _filbuf ignores the _ptr & _cnt and simply fills ! 121: the buffer. If stdio on your system doesn't work this way, you ! 122: may have to make small changes in this routine. ! 123: ! 124: This routine also "knows" that an EOF indication on a stream is ! 125: "sticky" (i.e., you will keep getting EOF until you reposition the ! 126: stream). If your system doesn't work this way it is broken and you ! 127: should complain to the vendor. As a consequence of the sticky ! 128: EOF, this routine will never return any kind of EOF status when ! 129: there is data in "name" or "buf"). ! 130: */ ! 131: ! 132: ! 133: #define Getc(iob) getc(iob) ! 134: #define eom(c,iob) (msg_style != MS_DEFAULT && \ ! 135: (((c) == *msg_delim && m_Eom(c,iob)) ||\ ! 136: (eom_action && (*eom_action)(c)))) ! 137: ! 138: static char *matchc(); ! 139: static char *locc(); ! 140: ! 141: static char **pat_map; ! 142: ! 143: int msg_count = 0; /* disgusting hack for "inc" so it can ! 144: * know how many characters were stuffed ! 145: * in the buffer on the last call (see ! 146: * comments in uip/scansbr.c) */ ! 147: ! 148: int msg_style = MS_DEFAULT; ! 149: /* ! 150: * The "full" delimiter string for a packed maildrop consists ! 151: * of a newline followed by the actual delimiter. E.g., the ! 152: * full string for a Unix maildrop would be: "\n\nFrom ". ! 153: * "Fdelim" points to the start of the full string and is used ! 154: * in the BODY case of the main routine to search the buffer for ! 155: * a possible eom. Msg_delim points to the first character of ! 156: * the actual delim. string (i.e., fdelim+1). Edelim ! 157: * points to the 2nd character of actual delimiter string. It ! 158: * is used in m_Eom because the first character of the string ! 159: * has been read and matched before m_Eom is called. ! 160: */ ! 161: char *msg_delim = ""; ! 162: static char *fdelim; ! 163: static char *delimend; ! 164: static int fdelimlen; ! 165: static char *edelim; ! 166: static int edelimlen; ! 167: ! 168: static int (*eom_action) () = NULL; ! 169: ! 170: /* */ ! 171: ! 172: m_getfld (state, name, buf, bufsz, iob) ! 173: int state; ! 174: int bufsz; ! 175: char *name, ! 176: *buf; ! 177: register FILE *iob; ! 178: { ! 179: register char *cp; ! 180: register char *bp; ! 181: register int cnt; ! 182: register int c; ! 183: register int i; ! 184: register int j; ! 185: register char *ep; ! 186: register char *sp; ! 187: ! 188: if ((c = Getc(iob)) < 0) { ! 189: msg_count = 0; ! 190: *buf = 0; ! 191: return FILEEOF; ! 192: } ! 193: if (eom (c, iob)) { ! 194: if (! eom_action) { ! 195: /* flush null messages */ ! 196: while ((c = Getc(iob)) >= 0 && eom (c, iob)) ! 197: ; ! 198: if (c >= 0) ! 199: (void) ungetc(c, iob); ! 200: } ! 201: msg_count = 0; ! 202: *buf = 0; ! 203: return FILEEOF; ! 204: } ! 205: ! 206: switch (state) { ! 207: case FLDEOF: ! 208: case BODYEOF: ! 209: case FLD: ! 210: if (c == '\n' || c == '-') { ! 211: /* we hit the header/body separator */ ! 212: while (c != '\n' && (c = Getc(iob)) >= 0) ! 213: ; ! 214: ! 215: if (c < 0 || (c = Getc(iob)) < 0 || eom (c, iob)) { ! 216: if (! eom_action) { ! 217: /* flush null messages */ ! 218: while ((c = Getc(iob)) >= 0 && eom (c, iob)) ! 219: ; ! 220: if (c >= 0) ! 221: (void) ungetc(c, iob); ! 222: } ! 223: msg_count = 0; ! 224: *buf = 0; ! 225: return FILEEOF; ! 226: } ! 227: state = BODY; ! 228: goto body; ! 229: } ! 230: /* ! 231: * get the name of this component. take characters up ! 232: * to a ':', a newline or NAMESZ-1 characters, whichever ! 233: * comes first. ! 234: */ ! 235: cp = name; i = NAMESZ - 1; ! 236: for (;;) { ! 237: bp = sp = iob->_ptr - 1; ! 238: j = (cnt = iob->_cnt+1) < i ? cnt : i; ! 239: while ((c = *bp++) != ':' && c != '\n' && --j >= 0) ! 240: *cp++ = c; ! 241: ! 242: j = bp - sp; ! 243: if ((cnt -= j) <= 0) { ! 244: if (_filbuf(iob) == EOF) { ! 245: *cp = *buf = NULL; ! 246: advise (NULLCP, "eof encountered in field \"%s\"", ! 247: name); ! 248: return FMTERR; ! 249: } ! 250: } else { ! 251: iob->_ptr = bp + 1; ! 252: iob->_cnt = cnt - 1; ! 253: } ! 254: if (c == ':') ! 255: break; ! 256: ! 257: /* ! 258: * something went wrong. possibilities are: ! 259: * . hit a newline (error) ! 260: * . got more than namesz chars. (error) ! 261: * . hit the end of the buffer. (loop) ! 262: */ ! 263: if (c == '\n') { ! 264: *cp = *buf = NULL; ! 265: advise (NULLCP, "eol encountered in field \"%s\"", name); ! 266: state = FMTERR; ! 267: goto finish; ! 268: } ! 269: if ((i -= j) <= 0) { ! 270: *cp = *buf = NULL; ! 271: advise (NULLCP, "field name \"%s\" exceeds %d bytes", ! 272: name, NAMESZ - 1); ! 273: state = LENERR; ! 274: goto finish; ! 275: } ! 276: } ! 277: ! 278: while (isspace (*--cp) && cp >= name) ! 279: ; ! 280: *++cp = NULL; ! 281: /* fall through */ ! 282: ! 283: case FLDPLUS: ! 284: /* ! 285: * get (more of) the text of a field. take ! 286: * characters up to the end of this field (newline ! 287: * followed by non-blank) or bufsz-1 characters. ! 288: */ ! 289: cp = buf; i = bufsz-1; ! 290: for (;;) { ! 291: cnt = iob->_cnt++; bp = --iob->_ptr; ! 292: c = cnt < i ? cnt : i; ! 293: while (ep = locc( c, bp, '\n' )) { ! 294: /* ! 295: * if we hit the end of this field, return. ! 296: */ ! 297: if ((j = *++ep) != ' ' && j != '\t') { ! 298: j = ep - iob->_ptr; ! 299: (void) bcopy( iob->_ptr, cp, j); ! 300: iob->_ptr = ep; iob->_cnt -= j; ! 301: cp += j; ! 302: state = FLD; ! 303: goto finish; ! 304: } ! 305: c -= ep - bp; bp = ep; ! 306: } ! 307: /* ! 308: * end of input or dest buffer - copy what we've found. ! 309: */ ! 310: c += bp - iob->_ptr; ! 311: (void) bcopy( iob->_ptr, cp, c); ! 312: i -= c; cp += c; ! 313: if (i <= 0) { ! 314: /* the dest buffer is full */ ! 315: iob->_cnt -= c; iob->_ptr += c; ! 316: state = FLDPLUS; ! 317: break; ! 318: } ! 319: /* ! 320: * There's one character left in the input buffer. ! 321: * Copy it & fill the buffer. If the last char ! 322: * was a newline and the next char is not whitespace, ! 323: * this is the end of the field. Otherwise loop. ! 324: */ ! 325: --i; ! 326: *cp++ = j = *(iob->_ptr + c); ! 327: c = _filbuf(iob); ! 328: if (j == '\n' && c != ' ' && c != '\t') { ! 329: if (c != EOF) ! 330: --iob->_ptr, ++iob->_cnt; ! 331: state = FLD; ! 332: break; ! 333: } ! 334: } ! 335: break; ! 336: ! 337: case BODY: ! 338: body: ! 339: /* ! 340: * get the message body up to bufsz characters or the ! 341: * end of the message. Sleazy hack: if bufsz is negative ! 342: * we assume that we were called to copy directly into ! 343: * the output buffer and we don't add an eos. ! 344: */ ! 345: i = (bufsz < 0) ? -bufsz : bufsz-1; ! 346: bp = --iob->_ptr; cnt = ++iob->_cnt; ! 347: c = (cnt < i ? cnt : i); ! 348: if (msg_style != MS_DEFAULT && c > 1) { ! 349: /* ! 350: * packed maildrop - only take up to the (possible) ! 351: * start of the next message. This "matchc" should ! 352: * probably be a Boyer-Moore matcher for non-vaxen, ! 353: * particularly since we have the alignment table ! 354: * all built for the end-of-buffer test (next). ! 355: * But our vax timings indicate that the "matchc" ! 356: * instruction is 50% faster than a carefully coded ! 357: * B.M. matcher for most strings. (So much for elegant ! 358: * algorithms vs. brute force.) Since I (currently) ! 359: * run MH on a vax, we use the matchc instruction. --vj ! 360: */ ! 361: if (ep = matchc( fdelimlen, fdelim, c, bp ) ) ! 362: c = ep - bp + 1; ! 363: else { ! 364: /* ! 365: * There's no delim in the buffer but there may be ! 366: * a partial one at the end. If so, we want to leave ! 367: * it so the "eom" check on the next call picks it up. ! 368: * Use a modified Boyer-Moore matcher to make this ! 369: * check relatively cheap. The first "while" figures ! 370: * out what position in the pattern matches the last ! 371: * character in the buffer. The inner "while" matches ! 372: * the pattern against the buffer, backwards starting ! 373: * at that position. Note that unless the buffer ! 374: * ends with one of the characters in the pattern ! 375: * (excluding the first and last), we do only one test. ! 376: */ ! 377: sp = delimend; ! 378: ep = bp + c - 1; ! 379: while ((cp = pat_map[*ep]) < sp) { ! 380: ep = bp + c - 1; sp = cp; ! 381: while (*--ep == *--cp && cp > fdelim) ! 382: ; ! 383: if (cp == fdelim) { ! 384: if (*ep == *cp && ep > bp) ! 385: c = (ep - bp) + 1; ! 386: break; ! 387: } ! 388: } ! 389: } ! 390: } ! 391: (void) bcopy( bp, buf, c ); ! 392: iob->_cnt -= c; ! 393: iob->_ptr += c; ! 394: if (bufsz < 0) { ! 395: msg_count = c; ! 396: return (state); ! 397: } ! 398: cp = buf + c; ! 399: break; ! 400: ! 401: default: ! 402: adios (NULLCP, "m_getfld() called with bogus state of %d", state); ! 403: } ! 404: finish:; ! 405: *cp = NULL; ! 406: msg_count = cp - buf; ! 407: return (state); ! 408: } ! 409: ! 410: /* */ ! 411: ! 412: #ifdef RPATHS ! 413: static char unixbuf[BUFSIZ] = ""; ! 414: #endif RPATHS ! 415: ! 416: void m_unknown (iob) ! 417: register FILE *iob; ! 418: { ! 419: register int c; ! 420: register long pos; ! 421: char text[10]; ! 422: register char *cp; ! 423: ! 424: msg_style = MS_UNKNOWN; ! 425: ! 426: /* Figure out what the message delimitter string is for this ! 427: * maildrop. (This used to be part of m_Eom but I didn't like ! 428: * the idea of an "if" statement that could only succeed on the ! 429: * first call to m_Eom getting executed on each call, i.e., at ! 430: * every newline in the message). ! 431: * ! 432: * If the first line of the maildrop is a Unix "from" line, we say the ! 433: * style is UUCP and eat the rest of the line. Otherwise we say the style ! 434: * is MMDF & look for the delimiter string specified when MH was built ! 435: * (or from the mtstailor file). ! 436: */ ! 437: pos = ftell (iob); ! 438: if (fread (text, sizeof *text, 5, iob) == 5 ! 439: && strncmp (text, "From ", 5) == 0) { ! 440: msg_style = MS_UUCP; ! 441: fdelim = "\n\nFrom "; ! 442: #ifndef RPATHS ! 443: while ((c = getc (iob)) != '\n' && c >= 0) ! 444: ; ! 445: #else RPATHS ! 446: cp = unixbuf; ! 447: while ((c = getc (iob)) != '\n') ! 448: *cp++ = c; ! 449: *cp = NULL; ! 450: #endif RPATHS ! 451: } else { ! 452: /* not a Unix style maildrop */ ! 453: (void) fseek (iob, pos, 0); ! 454: if (mmdlm2 == NULLCP || *mmdlm2 == NULL) ! 455: mmdlm2 = "\001\001\001\001\n"; ! 456: fdelim = (char *)malloc((unsigned)strlen(mmdlm2)+2); ! 457: *fdelim = '\n'; ! 458: (void)strcpy(fdelim+1, mmdlm2); ! 459: msg_style = MS_MMDF; ! 460: } ! 461: fdelimlen = strlen(fdelim); ! 462: msg_delim = fdelim+1; ! 463: edelim = msg_delim+1; ! 464: edelimlen = fdelimlen-2; ! 465: delimend = msg_delim + edelimlen; ! 466: if (edelimlen <= 1) ! 467: adios (NULLCP, "maildrop delimiter must be at least 2 bytes"); ! 468: /* ! 469: * build a Boyer-Moore end-position map for the matcher in m_getfld. ! 470: * N.B. - we don't match just the first char (since it's the newline ! 471: * separator) or the last char (since the matchc would have found it ! 472: * if it was a real delim). ! 473: */ ! 474: pat_map = (char **) malloc( 256 * sizeof (char *)); ! 475: for (c = 256; c--; ) ! 476: pat_map[c] = delimend + 1; ! 477: ! 478: for (cp = fdelim + 1; cp < delimend; cp++ ) ! 479: pat_map[*cp] = cp; ! 480: ! 481: if (msg_style == MS_MMDF) { ! 482: /* flush extra msg hdrs */ ! 483: while ((c = Getc(iob)) >= 0 && eom (c, iob)) ! 484: ; ! 485: if (c >= 0) ! 486: (void) ungetc(c, iob); ! 487: } ! 488: } ! 489: ! 490: ! 491: void m_eomsbr (action) ! 492: int (*action) (); ! 493: { ! 494: if (eom_action = action) { ! 495: msg_style = MS_MSH; ! 496: *msg_delim = 0; ! 497: fdelimlen = 1; ! 498: delimend = fdelim; ! 499: } else { ! 500: msg_style = MS_MMDF; ! 501: msg_delim = fdelim + 1; ! 502: fdelimlen = strlen (fdelim); ! 503: delimend = msg_delim + edelimlen; ! 504: } ! 505: } ! 506: ! 507: /* */ ! 508: ! 509: /* test for msg delimiter string */ ! 510: ! 511: int m_Eom (c, iob) ! 512: register int c; ! 513: register FILE *iob; ! 514: { ! 515: register long pos = 0L; ! 516: register int i; ! 517: char text[10]; ! 518: #ifdef RPATHS ! 519: register char *cp; ! 520: #endif RPATHS ! 521: ! 522: pos = ftell (iob); ! 523: if ((i = fread (text, sizeof *text, edelimlen, iob)) != edelimlen ! 524: || strncmp (text, edelim, edelimlen)) { ! 525: if (i == 0 && msg_style == MS_UUCP) ! 526: /* the final newline in the (brain damaged) unix-format ! 527: * maildrop is part of the delimitter - delete it. ! 528: */ ! 529: return 1; ! 530: ! 531: (void) fseek (iob, pos, 0); ! 532: return 0; ! 533: } ! 534: ! 535: if (msg_style == MS_UUCP) { ! 536: #ifndef RPATHS ! 537: while ((c = getc (iob)) != '\n') ! 538: if (c < 0) ! 539: break; ! 540: #else RPATHS ! 541: cp = unixbuf; ! 542: while ((c = getc (iob)) != '\n' && c >= 0) ! 543: *cp++ = c; ! 544: *cp = NULL; ! 545: #endif RPATHS ! 546: } ! 547: ! 548: return 1; ! 549: } ! 550: ! 551: /* */ ! 552: ! 553: #ifdef RPATHS ! 554: char *unixline () { ! 555: register char *cp, ! 556: *dp, ! 557: *pp; ! 558: static char unixfrom[BUFSIZ]; ! 559: ! 560: pp = unixfrom; ! 561: if (cp = dp = index (unixbuf, ' ')) { ! 562: while (cp = index (cp + 1, 'r')) ! 563: if (strncmp (cp, "remote from ", 12) == 0) { ! 564: *cp = NULL; ! 565: (void) sprintf (pp, "%s!", cp + 12); ! 566: pp += strlen (pp); ! 567: break; ! 568: } ! 569: if (cp == NULL) ! 570: cp = unixbuf + strlen (unixbuf); ! 571: if ((cp -= 25) >= dp) ! 572: *cp = NULL; ! 573: } ! 574: ! 575: (void) sprintf (pp, "%s\n", unixbuf); ! 576: unixbuf[0] = NULL; ! 577: return unixfrom; ! 578: } ! 579: #endif RPATHS ! 580: ! 581: /* */ ! 582: ! 583: #if (vax && !lint) ! 584: asm(".align 1"); ! 585: asm("_matchc: .word 0"); ! 586: asm(" movq 4(ap),r0"); ! 587: asm(" movq 12(ap),r2"); ! 588: asm(" matchc r0,(r1),r2,(r3)"); ! 589: asm(" beql 1f"); ! 590: asm(" movl 4(ap),r3"); ! 591: asm("1: subl3 4(ap),r3,r0"); ! 592: asm(" ret"); ! 593: #else ! 594: static char * ! 595: matchc( patln, pat, strln, str ) ! 596: int patln; ! 597: char *pat; ! 598: int strln; ! 599: register char *str; ! 600: { ! 601: register char *es = str + strln - patln; ! 602: register char *sp; ! 603: register char *pp; ! 604: register char *ep = pat + patln; ! 605: register char pc = *pat++; ! 606: ! 607: for(;;) { ! 608: while (pc != *str++) ! 609: if (str > es) ! 610: return 0; ! 611: ! 612: sp = str; pp = pat; ! 613: while (pp < ep && *sp++ == *pp++) ! 614: ; ! 615: if (pp >= ep) ! 616: return (--str); ! 617: } ! 618: } ! 619: #endif ! 620: ! 621: /* */ ! 622: ! 623: /* ! 624: * Locate character "term" in the next "cnt" characters of "src". ! 625: * If found, return its address, otherwise return 0. ! 626: */ ! 627: #if (vax && !lint) ! 628: asm(".align 1"); ! 629: asm("_locc: .word 0"); ! 630: asm(" movq 4(ap),r0"); ! 631: asm(" locc 12(ap),r0,(r1)"); ! 632: asm(" beql 1f"); ! 633: asm(" movl r1,r0"); ! 634: asm("1: ret"); ! 635: #else ! 636: static char * ! 637: locc( cnt, src, term ) ! 638: register int cnt; ! 639: register char *src; ! 640: register char term; ! 641: { ! 642: while (*src++ != term && --cnt > 0); ! 643: ! 644: return (cnt > 0 ? --src : NULLCP); ! 645: } ! 646: #endif ! 647: ! 648: /* */ ! 649: ! 650: #if !defined (BSD42) && !defined (bcopy) ! 651: int bcmp (b1, b2, length) ! 652: register char *b1, ! 653: *b2; ! 654: register int length; ! 655: { ! 656: while (length-- > 0) ! 657: if (*b1++ != *b2++) ! 658: return 1; ! 659: ! 660: return 0; ! 661: } ! 662: ! 663: ! 664: bcopy (b1, b2, length) ! 665: register char *b1, ! 666: *b2; ! 667: register int length; ! 668: { ! 669: while (length-- > 0) ! 670: *b2++ = *b1++; ! 671: } ! 672: ! 673: ! 674: bzero (b, length) ! 675: register char *b; ! 676: register int length; ! 677: { ! 678: while (length-- > 0) ! 679: *b++ = NULL; ! 680: } ! 681: #endif not BSD42 or SYS5
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.