/** rectangle algorithm **/ void rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg, texplay_sync sync_mode, bool primary, action_struct * payload) { action_struct cur; bool fill = false; int thickness = 1; draw_prologue(&cur, tex, x1, y1, x2, y2, &hash_arg, sync_mode, primary, &payload); if(is_a_hash(hash_arg)) { /* make our private copy of the hash so we can mess with it */ hash_arg = rb_obj_dup(hash_arg); if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) { fill = true; /* since we're filling the rect, line thickness is irrelevant */ delete_from_hash(hash_arg, "thickness"); } else if(RTEST(get_from_hash(hash_arg, "thickness"))) { thickness = NUM2INT(get_from_hash(hash_arg, "thickness")); /* TO DO: find a better way of doing this */ if(thickness > 1) { cur.xmin = x1 - thickness / 2; cur.ymin = y1 - thickness / 2; cur.xmax = x2 + thickness / 2 + 1; cur.ymax = y2 + thickness / 2 + 1; } } } if(!fill) { line_do_action(x1, y1, x2, y1, tex, hash_arg, no_sync, false, payload); line_do_action(x1, y1, x1, y2, tex, hash_arg, no_sync, false, payload); line_do_action(x1, y2, x2, y2, tex, hash_arg, no_sync, false, payload); line_do_action(x2, y1, x2, y2, tex, hash_arg, no_sync, false, payload); } else { if(y1 > y2) SWAP(y1, y2); for(int y = y1; y <= y2; y++) line_do_action(x1, y, x2, y, tex, hash_arg, no_sync, false, payload); } draw_epilogue(&cur, tex, primary); }
enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key) { tdb_off_t off; struct tdb_used_record rec; struct hash_info h; enum TDB_ERROR ecode; if (tdb->flags & TDB_VERSION1) { if (tdb1_delete(tdb, key) == -1) return tdb->last_error; return TDB_SUCCESS; } off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { return tdb->last_error = TDB_OFF_TO_ERR(off); } if (!off) { ecode = TDB_ERR_NOEXIST; goto unlock; } ecode = delete_from_hash(tdb, &h); if (ecode != TDB_SUCCESS) { goto unlock; } /* Free the deleted entry. */ tdb->stats.frees++; ecode = add_free_record(tdb, off, sizeof(struct tdb_used_record) + rec_key_length(&rec) + rec_data_length(&rec) + rec_extra_padding(&rec), TDB_LOCK_WAIT, true); if (tdb->flags & TDB_SEQNUM) tdb_inc_seqnum(tdb); unlock: tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK); return tdb->last_error = ecode; }
_PUBLIC_ enum NTDB_ERROR ntdb_delete(struct ntdb_context *ntdb, NTDB_DATA key) { ntdb_off_t off; struct ntdb_used_record rec; struct hash_info h; enum NTDB_ERROR ecode; off = find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL); if (NTDB_OFF_IS_ERR(off)) { return NTDB_OFF_TO_ERR(off); } if (!off) { ecode = NTDB_ERR_NOEXIST; goto unlock; } ecode = delete_from_hash(ntdb, &h); if (ecode != NTDB_SUCCESS) { goto unlock; } /* Free the deleted entry. */ ntdb->stats.frees++; ecode = add_free_record(ntdb, off, sizeof(struct ntdb_used_record) + rec_key_length(&rec) + rec_data_length(&rec) + rec_extra_padding(&rec), NTDB_LOCK_WAIT, true); if (ntdb->flags & NTDB_SEQNUM) ntdb_inc_seqnum(ntdb); unlock: ntdb_unlock_hash(ntdb, h.h, F_WRLCK); return ecode; }
/* * Calculates the threading relationships for a list of messages */ Container *calculate_threads(apr_pool_t *p, MBOX_LIST *l) { apr_hash_t *h, *rootSet, *subjectSet; apr_hash_index_t *hashIndex; MBOX_LIST *current = l; const apr_array_header_t *refHdr; apr_table_entry_t *refEnt; Message *m; Container *c, *subjectPair, *realParent, *curParent, *tmp; void *hashKey, *hashVal, *subjectVal; char *subject; int msgIDLen, refLen, i; apr_ssize_t hashLen, subjectLen; /* FIXME: Use APR_HASH_KEY_STRING instead? Maybe slower. */ h = apr_hash_make(p); while (current != NULL) { m = (Message *) current->value; msgIDLen = strlen(m->msgID); c = (Container *) apr_hash_get(h, m->msgID, msgIDLen); if (c) { c->message = m; } else { c = (Container *) apr_pcalloc(p, sizeof(Container)); c->message = m; c->parent = NULL; c->child = NULL; c->next = NULL; apr_hash_set(h, m->msgID, msgIDLen, c); } realParent = NULL; if (m->references) { refHdr = apr_table_elts(m->references); refEnt = (apr_table_entry_t *) refHdr->elts; for (i = 0; i < refHdr->nelts; i++) { refLen = strlen(refEnt[i].key); curParent = (Container *) apr_hash_get(h, refEnt[i].key, refLen); /* Create a dummy node to store the message we haven't * yet seen. */ if (!curParent) { curParent = (Container *) apr_pcalloc(p, sizeof(Container)); apr_hash_set(h, refEnt[i].key, refLen, curParent); } /* Check to make sure we are not going to create a loop * by adding this parent to our list. */ if (realParent && !detect_loop(curParent, realParent) && !detect_loop(realParent, curParent)) { /* Update the parent */ if (curParent->parent) unlink_parent(curParent); curParent->parent = realParent; curParent->next = realParent->child; realParent->child = curParent; } /* We now have a new parent */ realParent = curParent; } } /* The last parent we saw is our parent UNLESS it causes a loop. */ if (realParent && !detect_loop(c, realParent) && !detect_loop(realParent, c)) { /* We need to unlink our parent's link to us. */ if (c->parent) unlink_parent(c); c->parent = realParent; c->next = realParent->child; realParent->child = c; } current = current->next; } /* Find the root set */ rootSet = apr_hash_make(p); for (hashIndex = apr_hash_first(p, h); hashIndex; hashIndex = apr_hash_next(hashIndex)) { apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal); c = (Container *) hashVal; if (!c->parent) apr_hash_set(rootSet, hashKey, hashLen, c); } /* Prune empty containers */ for (hashIndex = apr_hash_first(p, rootSet); hashIndex; hashIndex = apr_hash_next(hashIndex)) { apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal); c = (Container *) hashVal; prune_container(c); if (!c->message && !c->child) apr_hash_set(rootSet, hashKey, hashLen, NULL); } /* Merge root set by subjects */ subjectSet = apr_hash_make(p); for (hashIndex = apr_hash_first(p, rootSet); hashIndex; hashIndex = apr_hash_next(hashIndex)) { apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal); c = (Container *) hashVal; /* If we don't have a message, our child will. */ if (!c->message) c = c->child; subject = strip_subject(p, c->message); subjectLen = strlen(subject); /* FIXME: Match what JWZ says */ subjectVal = apr_hash_get(subjectSet, subject, subjectLen); if (subjectVal) { if (!c->message) apr_hash_set(subjectSet, subject, strlen(subject), hashVal); else { subjectPair = (Container *) subjectVal; if (!is_reply(c->message) && is_reply(subjectPair->message)) apr_hash_set(subjectSet, subject, strlen(subject), hashVal); } } else apr_hash_set(subjectSet, subject, strlen(subject), hashVal); } /* Subject table now populated */ for (hashIndex = apr_hash_first(p, rootSet); hashIndex; hashIndex = apr_hash_next(hashIndex)) { apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal); c = (Container *) hashVal; /* If we don't have a message, our child will. */ if (c->message) subject = strip_subject(p, c->message); else subject = strip_subject(p, c->child->message); subjectLen = strlen(subject); subjectVal = apr_hash_get(subjectSet, subject, subjectLen); subjectPair = (Container *) subjectVal; /* If we need to merge the tables */ if (subjectPair && subjectPair != c) { if (!c->message || !subjectPair->message) { /* One is dummy */ if (!c->message && !subjectPair->message) join_container(subjectPair, c); else if (c->message && !subjectPair->message) { /* It's possible that we're already a child! */ if (c->parent != subjectPair) append_container(subjectPair, c); } else { /* (!c->message && subjectPair->message) */ append_container(c, subjectPair); apr_hash_set(subjectSet, subject, subjectLen, c); delete_from_hash(p, rootSet, subjectPair); } } else { /* Both aren't dummies */ /* We are Reply */ if (is_reply(c->message) && !is_reply(subjectPair->message)) append_container(subjectPair, c); else if (!is_reply(c->message) && is_reply(subjectPair->message)) { append_container(c, subjectPair); apr_hash_set(subjectSet, subject, subjectLen, c); delete_from_hash(p, rootSet, subjectPair); } else { /* We are both replies. */ c = merge_container(p, c, subjectPair); apr_hash_set(subjectSet, subject, subjectLen, c); delete_from_hash(p, rootSet, subjectPair); } } } } /* Now, we are done threading. We want to return a sorted container * back to our caller. All children of the root set need to be in * order and then we need to issue an ordering to the root set. */ tmp = NULL; /* Sort siblings */ for (hashIndex = apr_hash_first(p, subjectSet); hashIndex; hashIndex = apr_hash_next(hashIndex)) { apr_hash_this(hashIndex, (void *) &hashKey, &hashLen, &hashVal); c = (Container *) hashVal; sort_siblings(c); if (tmp) c->next = tmp; tmp = c; } return (Container *) mbox_sort_linked_list(tmp, 3, compare_siblings, NULL, NULL); }
/* TODO: fix this function below, it's too ugly and bulky and weird **/ static void process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync_ sync_mode, bool primary) { VALUE user_defaults; VALUE hash_blend; /* if a hash doesn't exist then create one */ if(!is_a_hash(*hash_arg)) *hash_arg = rb_hash_new(); /* init the action to default values */ initialize_action_struct(cur, *hash_arg, sync_mode); /* get the user default options & merge with given options */ user_defaults = get_image_local(cur->tex->image, USER_DEFAULTS); hash_blend = rb_funcall(user_defaults, rb_intern("merge"), 1, *hash_arg); rb_funcall(*hash_arg, rb_intern("merge!"), 1, hash_blend); if(has_optional_hash_arg(*hash_arg, "color")) { VALUE c = get_from_hash(*hash_arg, "color"); cur->color = convert_rb_color_to_rgba(c); if(c == string2sym("random")) { set_hash_value(*hash_arg, "color", convert_rgba_to_rb_color(&cur->color)); } } /* shadows */ if(RTEST(get_from_hash(*hash_arg, "shadow"))) { cur->pen.color_mult.red = 0.66; cur->pen.color_mult.green = 0.66; cur->pen.color_mult.blue = 0.66; cur->pen.color_mult.alpha = 1; cur->pen.has_color_control_transform = true; } /* tolerance */ if(RTEST(get_from_hash(*hash_arg, "tolerance"))) { cur->pen.tolerance = NUM2DBL(get_from_hash(*hash_arg, "tolerance")); /* maximum length of hypotonese extended in 4-space (color space) is sqrt(4) */ if (cur->pen.tolerance >= 2) cur->pen.tolerance = 2; if (cur->pen.tolerance < 0) cur->pen.tolerance = 0; cur->pen.has_tolerance = true; } /* lerp */ if(RTEST(get_from_hash(*hash_arg, "lerp"))) { cur->pen.lerp = NUM2DBL(get_from_hash(*hash_arg, "lerp")); /* bounds */ if(cur->pen.lerp > 1.0) cur->pen.lerp = 1.0; if(cur->pen.lerp < 0.0) cur->pen.lerp = 0.0; cur->pen.has_lerp = true; } /* sync mode */ if(has_optional_hash_arg(*hash_arg, "sync_mode")) { VALUE user_sync_mode = get_from_hash(*hash_arg, "sync_mode"); Check_Type(user_sync_mode, T_SYMBOL); if(user_sync_mode == string2sym("lazy_sync")) cur->sync_mode = lazy_sync; else if(user_sync_mode == string2sym("eager_sync")) cur->sync_mode = eager_sync; else if(user_sync_mode == string2sym("no_sync")) cur->sync_mode = no_sync; else rb_raise(rb_eArgError, "unrecognized sync mode: %s\n. Allowable modes are " ":lazy_sync, :eager_sync, :no_sync.", sym2string(user_sync_mode)); delete_from_hash(*hash_arg, "sync_mode"); } /* prepare color selection */ prepare_color_select(cur); /* process drawing mode */ prepare_drawing_mode(cur); /* process the color_control block or transform (if there is one) */ prepare_color_control(cur); /* process the filling texture (if there is one) */ prepare_fill_texture(cur); /* does the user want to blend alpha values ? */ prepare_alpha_blend(cur); }
/** midpoint circle algorithm **/ void circle_do_action(int x1, int y1, int r, texture_info * tex, VALUE hash_arg, texplay_sync sync_mode, bool primary, action_struct * payload) { int x, y; float p; action_struct cur; bool fill = false; draw_prologue(&cur, tex, x1 - r, y1 - r, x1 + r, y1 + r, &hash_arg, sync_mode, primary, &payload); if(is_a_hash(hash_arg)) { /* make our private copy of the hash so we can mess with it */ hash_arg = rb_obj_dup(hash_arg); if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) { fill = true; /* to prevent infinite recursion set line thickness to 1 :D NB: a filled circle uses lines and a thick line uses filled circles :D */ delete_from_hash(hash_arg, "thickness"); } } x = 0 ; y = r; p = 5 / 4 - r; if(!fill) { while (x <= y) { set_pixel_color_with_style(payload, tex, x1 + x, y1 + y); set_pixel_color_with_style(payload, tex, x1 + x, y1 - y); set_pixel_color_with_style(payload, tex, x1 - x, y1 + y); set_pixel_color_with_style(payload, tex, x1 - x, y1 - y); set_pixel_color_with_style(payload, tex, x1 + y, y1 + x); set_pixel_color_with_style(payload, tex, x1 + y, y1 - x); set_pixel_color_with_style(payload, tex, x1 - y, y1 + x); set_pixel_color_with_style(payload, tex, x1 - y, y1 - x); if (p < 0) { p += 2 * x + 3; } else { y--; p += 2 * (x - y) + 5; } x++; } } else { while (x <= y) { line_do_action(x1 - x, y1 + y, x1 + x, y1 + y, tex, hash_arg, no_sync, false, payload); line_do_action(x1 - x, y1 - y, x1 + x, y1 - y, tex, hash_arg, no_sync, false, payload); line_do_action(x1 - y, y1 + x, x1 + y, y1 + x, tex, hash_arg, no_sync, false, payload); line_do_action(x1 - y, y1 - x, x1 + y, y1 - x, tex, hash_arg, no_sync, false, payload); if (p < 0) { p += 2 * x + 3; } else { y--; p += 2 * (x - y) + 5; } x++; } } draw_epilogue(&cur, tex, primary); }