JRB lprev(JRB n) { if (ishead(n)) return n; while (!isroot(n)) { if (isright(n)) return n->parent; n = n->parent; } return n->parent; }
Rb_node lprev(Rb_node n) { if (ishead(n)) return n; while (!isroot(n)) { if (isright(n)) return n->p.parent; n = n->p.parent; } return n->p.parent; }
JRB rprev(JRB n) { if (ishead(n)) return n; while (!isroot(n)) { if (isleft(n)) return n->parent; n = n->parent; } return n->parent; }
void jrb_free_tree(JRB n) { if (!ishead(n)) { fprintf(stderr, "ERROR: Rb_free_tree called on a non-head node\n"); exit(1); } while(jrb_first(n) != jrb_nil(n)) { jrb_delete_node(jrb_first(n)); } free(n); }
void jrb_print_tree(JRB t, int level) { int i; if (ishead(t) && t->parent == t) { printf("tree 0x%x is empty\n", t); } else if (ishead(t)) { printf("Head: 0x%x. Root = 0x%x\n", t, t->parent); jrb_print_tree(t->parent, 0); } else { if (isext(t)) { for (i = 0; i < level; i++) putchar(' '); printf("Ext node 0x%x: %c,%c: p=0x%x, k=%s\n", t, isred(t)?'R':'B', isleft(t)?'l':'r', t->parent, t->key.s); } else { jrb_print_tree(t->flink, level+2); jrb_print_tree(t->blink, level+2); for (i = 0; i < level; i++) putchar(' '); printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%s,%s)\n", t, isred(t)?'R':'B', isleft(t)?'l':'r', t->flink, t->blink, t->parent, getlext(t)->key.s, getrext(t)->key.s); } } }
static JRB jrb_insert_b(JRB n, Jval key, Jval val) { JRB newleft, newright, newnode, list, p; if (ishead(n)) { if (n->parent == n) { /* Tree is empty */ mk_new_ext(newnode, key, val); insert(newnode, n); n->parent = newnode; newnode->parent = n; setroot(newnode); return newnode; } else { mk_new_ext(newright, key, val); insert(newright, n); newleft = newright->blink; setnormal(newleft); mk_new_int(newleft, newright, newleft->parent, isleft(newleft)); p = rprev(newright); if (!ishead(p)) setlext(p, newright); return newright; } } else { mk_new_ext(newleft, key, val); insert(newleft, n); setnormal(n); mk_new_int(newleft, n, n->parent, isleft(n)); p = lprev(newleft); if (!ishead(p)) setrext(p, newleft); return newleft; } }
JRB jrb_find_gte_vptr(JRB n, void *vkey, int *fnd) { *fnd = 0; if (!ishead(n)) { fprintf(stderr, "jrb_find_gte_int called on non-head 0x%p\n", (void *)n); exit(1); } if (n->parent == n) return n; if ((char *)vkey == (char *)n->blink->key.v) { *fnd = 1; return n->blink; } if ((char *)vkey > (char *)n->blink->key.v) return n; else n = n->parent; while (1) { if (isext(n)) return n; if ((char *)vkey == (char *)getlext(n)->key.v) { *fnd = 1; return getlext(n); } n = ((char *)vkey < (char *)getlext(n)->key.v) ? n->flink : n->blink; } }
JRB jrb_find_gte_int(JRB n, int ikey, int *fnd) { *fnd = 0; if (!ishead(n)) { fprintf(stderr, "jrb_find_gte_int called on non-head 0x%p\n", (void *)n); exit(1); } if (n->parent == n) return n; if (ikey == n->blink->key.i) { *fnd = 1; return n->blink; } if (ikey > n->blink->key.i) return n; else n = n->parent; while (1) { if (isext(n)) return n; if (ikey == getlext(n)->key.i) { *fnd = 1; return getlext(n); } n = (ikey < getlext(n)->key.i) ? n->flink : n->blink; } }
JRB jrb_find_gte_dbl(JRB n, double dkey, int *fnd) { *fnd = 0; if (!ishead(n)) { fprintf(stderr, "jrb_find_gte_dbl called on non-head 0x%x\n", n); exit(1); } if (n->parent == n) return n; if (dkey == n->blink->key.d) { *fnd = 1; return n->blink; } if (dkey > n->blink->key.d) return n; else n = n->parent; while (1) { if (isext(n)) return n; if (dkey == getlext(n)->key.d) { *fnd = 1; return getlext(n); } n = (dkey < getlext(n)->key.d) ? n->flink : n->blink; } }
Rb_node rb_find_ikey_n(Rb_node n, unsigned int ikey, int *fnd) { *fnd = 0; if (!ishead(n)) { fprintf(stderr, "rb_find_ikey_n called on non-head 0x%p \n", (void *) n); exit(1); } if (n->p.root == n) return n; if (ikey == n->c.list.blink->k.ikey) { *fnd = 1; return n->c.list.blink; } if (ikey > n->c.list.blink->k.ikey) return n; else n = n->p.root; while (1) { if (isext(n)) return n; if (ikey == n->k.lext->k.ikey) { *fnd = 1; return n->k.lext; } n = (ikey < n->k.lext->k.ikey) ? n->c.child.left : n->c.child.right; } }
void jrb_delete_node(JRB n) { JRB s, p, gp; char ir; if (isint(n)) { fprintf(stderr, "Cannot delete an internal node: 0x%p\n", (void *)n); exit(1); } if (ishead(n)) { fprintf(stderr, "Cannot delete the head of an jrb_tree: 0x%p\n", (void *)n); exit(1); } delete_item(n); /* Delete it from the list */ p = n->parent; /* The only node */ if (isroot(n)) { p->parent = p; free(n); return; } s = sibling(n); /* The only node after deletion */ if (isroot(p)) { s->parent = p->parent; s->parent->parent = s; setroot(s); free(p); free(n); return; } gp = p->parent; /* Set parent to sibling */ s->parent = gp; if (isleft(p)) { gp->flink = s; setleft(s); } else { gp->blink = s; setright(s); } ir = isred(p); free(p); free(n); if (isext(s)) { /* Update proper rext and lext values */ p = lprev(s); if (!ishead(p)) setrext(p, s); p = rprev(s); if (!ishead(p)) setlext(p, s); } else if (isblack(s)) { fprintf(stderr, "DELETION PROB -- sib is black, internal\n"); exit(1); } else { p = lprev(s); if (!ishead(p)) setrext(p, s->flink); p = rprev(s); if (!ishead(p)) setlext(p, s->blink); setblack(s); return; } if (ir) return; /* Recolor */ n = s; p = n->parent; s = sibling(n); while(isblack(p) && isblack(s) && isint(s) && isblack(s->flink) && isblack(s->blink)) { setred(s); n = p; if (isroot(n)) return; p = n->parent; s = sibling(n); } if (isblack(p) && isred(s)) { /* Rotation 2.3b */ single_rotate(p, isright(n)); setred(p); setblack(s); s = sibling(n); } { JRB x, z; char il; if (isext(s)) { fprintf(stderr, "DELETION ERROR: sibling not internal\n"); exit(1); } il = isleft(n); x = il ? s->flink : s->blink ; z = sibling(x); if (isred(z)) { /* Rotation 2.3f */ single_rotate(p, !il); setblack(z); if (isred(p)) setred(s); else setblack(s); setblack(p); } else if (isblack(x)) { /* Recoloring only (2.3c) */ if (isred(s) || isblack(p)) { fprintf(stderr, "DELETION ERROR: 2.3c not quite right\n"); exit(1); } setblack(p); setred(s); return; } else if (isred(p)) { /* 2.3d */ single_rotate(s, il); single_rotate(p, !il); setblack(x); setred(s); return; } else { /* 2.3e */ single_rotate(s, il); single_rotate(p, !il); setblack(x); return; } } }
/* * Set up the input pointers while copying the mail file into /tmp. */ void setptr(FILE *ibuf, off_t offset) { int c, count; char *cp, *cp2; struct message this; FILE *mestmp; int maybe, inhead; char linebuf[LINESIZE], pathbuf[PATHSIZE]; int omsgCount; /* Get temporary file. */ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir); if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL) err(1, "can't open %s", pathbuf); (void)rm(pathbuf); if (offset == 0) { msgCount = 0; } else { /* Seek into the file to get to the new messages */ (void)fseeko(ibuf, offset, SEEK_SET); /* * We need to make "offset" a pointer to the end of * the temp file that has the copy of the mail file. * If any messages have been edited, this will be * different from the offset into the mail file. */ (void)fseeko(otf, (off_t)0, SEEK_END); offset = ftello(otf); } omsgCount = msgCount; maybe = 1; inhead = 0; this.m_flag = MUSED|MNEW; this.m_size = 0; this.m_lines = 0; this.m_block = 0; this.m_offset = 0; for (;;) { if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) { if (append(&this, mestmp)) errx(1, "temporary file"); makemessage(mestmp, omsgCount); return; } count = strlen(linebuf); /* * Transforms lines ending in <CR><LF> to just <LF>. * This allows mail to be able to read Eudora mailboxes. */ if (count >= 2 && linebuf[count - 1] == '\n' && linebuf[count - 2] == '\r') { count--; linebuf[count - 1] = '\n'; } (void)fwrite(linebuf, sizeof(*linebuf), count, otf); if (ferror(otf)) errx(1, "/tmp"); if (count) linebuf[count - 1] = '\0'; if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { msgCount++; if (append(&this, mestmp)) errx(1, "temporary file"); this.m_flag = MUSED|MNEW; this.m_size = 0; this.m_lines = 0; this.m_block = blockof(offset); this.m_offset = boffsetof(offset); inhead = 1; } else if (linebuf[0] == 0) { inhead = 0; } else if (inhead) { for (cp = linebuf, cp2 = "status";; cp++) { if ((c = *cp2++) == '\0') { while (isspace((unsigned char)*cp++)) ; if (cp[-1] != ':') break; while ((c = *cp++) != '\0') if (c == 'R') this.m_flag |= MREAD; else if (c == 'O') this.m_flag &= ~MNEW; inhead = 0; break; } if (*cp != c && *cp != toupper((unsigned char)c)) break; } } offset += count; this.m_size += count; this.m_lines++; maybe = linebuf[0] == 0; } }
/* * Set up the input pointers while copying the mail file into /tmp. */ PUBLIC void setptr(FILE *ibuf, off_t offset) { int c; size_t len; char *cp; const char *cp2; struct message this; FILE *mestmp; int maybe, inhead; char linebuf[LINESIZE]; int omsgCount; #ifdef THREAD_SUPPORT int nmsgCount; #else # define nmsgCount msgCount #endif /* Get temporary file. */ (void)snprintf(linebuf, LINESIZE, "%s/mail.XXXXXX", tmpdir); if ((c = mkstemp(linebuf)) == -1 || (mestmp = Fdopen(c, "re+")) == NULL) { (void)fprintf(stderr, "mail: can't open %s\n", linebuf); exit(1); } (void)unlink(linebuf); nmsgCount = get_abs_msgCount(); if (offset == 0) { nmsgCount = 0; } else { /* Seek into the file to get to the new messages */ (void)fseeko(ibuf, offset, 0); /* * We need to make "offset" a pointer to the end of * the temp file that has the copy of the mail file. * If any messages have been edited, this will be * different from the offset into the mail file. */ (void)fseek(otf, 0L, SEEK_END); offset = ftell(otf); } omsgCount = nmsgCount; maybe = 1; inhead = 0; message_init(&this, (off_t)0, MUSED|MNEW); for (;;) { if (fgets(linebuf, LINESIZE, ibuf) == NULL) { if (append(&this, mestmp)) err(EXIT_FAILURE, "temporary file"); makemessage(mestmp, omsgCount, nmsgCount); return; } len = strlen(linebuf); /* * Transforms lines ending in <CR><LF> to just <LF>. * This allows mail to be able to read Eudora mailboxes * that reside on a DOS partition. */ if (len >= 2 && linebuf[len - 1] == '\n' && linebuf[len - 2] == '\r') { linebuf[len - 2] = '\n'; len--; } (void)fwrite(linebuf, sizeof(*linebuf), len, otf); if (ferror(otf)) err(EXIT_FAILURE, "/tmp"); if (len) linebuf[len - 1] = 0; if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { nmsgCount++; if (append(&this, mestmp)) err(EXIT_FAILURE, "temporary file"); message_init(&this, offset, MUSED|MNEW); inhead = 1; } else if (linebuf[0] == 0) { inhead = 0; } else if (inhead) { for (cp = linebuf, cp2 = "status";; cp++) { if ((c = *cp2++) == 0) { while (isspace((unsigned char)*cp++)) continue; if (cp[-1] != ':') break; while ((c = *cp++) != '\0') if (c == 'R') this.m_flag |= MREAD; else if (c == 'O') this.m_flag &= ~MNEW; inhead = 0; break; } if (*cp != c && *cp != toupper(c)) break; } } offset += len; this.m_size += len; this.m_lines++; if (!inhead) { int lines_plus_wraps = 1; int linelen = (int)strlen(linebuf); if (screenwidth && (int)linelen > screenwidth) { lines_plus_wraps = linelen / screenwidth; if (linelen % screenwidth != 0) ++lines_plus_wraps; } this.m_blines += lines_plus_wraps; } maybe = linebuf[0] == 0; } }
static void fmt(FILE *fi) { wchar_t linebuf[BUFSIZ], canonb[BUFSIZ]; wchar_t *cp, *cp2; int col; wchar_t c; char cbuf[BUFSIZ]; /* stores wchar_t string as char string */ c = getwc(fi); while (c != EOF) { /* * Collect a line, doing ^H processing. * Leave tabs for now. */ cp = linebuf; while (c != L'\n' && c != EOF && cp-linebuf < BUFSIZ-1) { if (c == L'\b') { if (cp > linebuf) cp--; c = getwc(fi); continue; } if (!(iswprint(c)) && c != L'\t') { c = getwc(fi); continue; } *cp++ = c; c = getwc(fi); } *cp = L'\0'; /* * Toss anything remaining on the input line. */ while (c != L'\n' && c != EOF) c = getwc(fi); /* * Expand tabs on the way to canonb. */ col = 0; cp = linebuf; cp2 = canonb; while (c = *cp++) { if (c != L'\t') { col += scrwidth(c); if (cp2-canonb < BUFSIZ-1) *cp2++ = c; continue; } do { if (cp2-canonb < BUFSIZ-1) *cp2++ = L' '; col++; } while ((col & 07) != 0); } /* * Swipe trailing blanks from the line. */ for (cp2--; cp2 >= canonb && *cp2 == L' '; cp2--); *++cp2 = '\0'; /* special processing to look for mail header lines */ switch (hdr_state) { case off: prefix(canonb); case not_in_hdr: /* look for an initial mail header line */ /* skip initial blanks */ for (cp = canonb; *cp == L' '; cp++); /* * Need to convert string from wchar_t to char, * since this is what ishead() expects. Since we * only want to make sure cp points to a "From" line * of the email, we don't have to alloc * BUFSIZ * MB_LEN_MAX to cbuf. */ wcstombs(cbuf, cp, (BUFSIZ - 1)); if (ishead(cbuf)) { hdr_state = in_hdr; fill_hdrbuf(canonb); } else { /* no mail header line; process normally */ prefix(canonb); } break; case in_hdr: /* already saw 1st mail header line; look for more */ if (canonb[0] == L'\0') { /* * blank line means end of mail header; * verify current mail header buffer * then process it accordingly */ header_chk(); process_hdrbuf(); /* now process the current blank line */ prefix(canonb); } else /* * not a blank line--save this line as * a potential mail header line */ fill_hdrbuf(canonb); break; } if (c != EOF) c = getwc(fi); } /* * end of this file--make sure we process the stuff in * hdrbuf before we're finished */ if (hdr_state == in_hdr) { header_chk(); process_hdrbuf(); } }