/** * 同じキーがあれば上書き * なければ追加 * 例外発生時はNULLを返す * keyのカウンタを増やす */ HashValueEntry *refmap_add(RefMap *rm, Value key, int overwrite, int raise_error) { HashValueEntry *ep, **epp; uint32_t hash; if (!map_search_sub(&epp, &hash, rm, key)) { return NULL; } ep = *epp; if (ep != NULL) { if (overwrite) { // 一致(上書き) if (Value_isref(ep->val)) { RefHeader *rh = Value_ref_header(ep->val); if (rh->nref > 0 && --rh->nref == 0) { Value_release_ref(ep->val); } } ep->val = VALUE_NULL; return ep; } else { if (raise_error) { throw_errorf(fs->mod_lang, "IndexError", "Duplicate key detected"); return NULL; } else { return ep; } } } else { // 一致しない(追加) ep = malloc(sizeof(HashValueEntry)); ep->next = NULL; ep->hash = hash; ep->key = Value_cp(key); ep->val = VALUE_NULL; *epp = ep; rm->count++; if (rm->count > rm->entry_num) { map_grow_entry(rm); } return ep; } }
static void xmlelem_add_attr(Ref *r, const char *ckey, const char *cval) { RefMap *rm; Value key; HashValueEntry *ve; if (Value_isref(r->v[INDEX_ELEM_ATTR])) { rm = Value_vp(r->v[INDEX_ELEM_ATTR]); } else { rm = fs->refmap_new(0); r->v[INDEX_ELEM_ATTR] = vp_Value(rm); } key = fs->cstr_Value(fs->cls_str, ckey, -1); ve = fs->refmap_add(rm, key, TRUE, FALSE); fs->unref(key); fs->unref(ve->val); ve->val = fs->cstr_Value(fs->cls_str, cval, -1); }
/** * XMLPatternListから、XMLNodeを選択 */ static int select_xml_match_node(Ref *r, XMLPattern *pat) { XMLAttrPattern *attr; for (attr = pat->attr; attr != NULL; attr = attr->next) { switch (attr->type) { case XT_ANY: break; case XT_NAME: { RefStr *name = Value_vp(r->v[INDEX_ELEM_NAME]); if (!str_eq(name->c, name->size, attr->val.p, attr->val.size)) { return FALSE; } break; } case XT_ATTR_EQ: case XT_ATTR_MATCH: case XT_ATTR_FIRST: { HashValueEntry *he; Value key; RefStr *val; Value v_rm = r->v[INDEX_ELEM_ATTR]; key = fs->cstr_Value(fs->cls_str, attr->key.p, attr->key.size); // Str#_op_eqでは、例外が発生しないのでチェックを省略 if (!Value_isref(v_rm)) { break; } fs->refmap_get(&he, Value_vp(v_rm), key); if (he == NULL) { return FALSE; } val = Value_vp(he->val); switch (attr->type) { case XT_ATTR_EXIST: break; case XT_ATTR_EQ: if (!str_eq(val->c, val->size, attr->val.p, attr->val.size)) { return FALSE; } break; case XT_ATTR_MATCH: { int i = 0; int asize = attr->val.size; int found = FALSE; for (;;) { while (i < val->size - asize && isspace_fox(val->c[i])) { i++; } if (memcmp(val->c, attr->val.p + i, asize) == 0) { if (i + asize == val->size || isspace_fox(val->c[i + asize])) { found = TRUE; break; } } while (i < val->size - asize && !isspace_fox(val->c[i])) { i++; } if (i >= val->size - asize) { break; } } if (!found) { return FALSE; } break; } case XT_ATTR_FIRST: { int asize = attr->val.size; int found = FALSE; if (val->size >= asize && memcmp(val->c, attr->val.p, asize) == 0) { if (val->size == asize || !isalnumu_fox(val->c[asize])) { found = TRUE; } } if (!found) { return FALSE; } break; } } break; } default: return FALSE; } } return TRUE; }