📄 su_taglist.c
字号:
/**Filter a tag list. * * The function tl_afilter() will build a tag list containing tags specified * in @a filter and extracted from @a src. It will allocate the memory used by * tag list via the specified memory @a home, which may be also @c NULL. * * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(), * TAG_FILTER(), TAG_ANY(), #ns_tag_class */tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[]){ tagi_t *dst, *d, *t_end = NULL; void *b, *end = NULL; size_t len; /* Calculate length of the result */ t_end = tl_filter(NULL, filter, src, &end); len = ((char *)t_end - (char *)NULL) + ((char *)end - (char*)NULL); if (len == 0) return NULL; /* Allocate the result */ if (!(dst = su_alloc(home, len))) return NULL; /* Build the result */ b = (dst + (t_end - (tagi_t *)NULL)); d = tl_filter(dst, filter, src, (void **)&b); /* Ensure that everything is consistent */ assert(d == dst + (t_end - (tagi_t *)NULL)); assert(b == (char *)dst + len); return dst;}/** Filter tag list @a src with given tags. * * @sa tl_afilter(), tl_filtered_tlist(), TAG_FILTER(), TAG_ANY(), #ns_tag_class */tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[], tag_type_t tag, tag_value_t value, ...){ tagi_t *tl; ta_list ta; ta_start(ta, tag, value); tl = tl_afilter(home, ta_args(ta), src); ta_end(ta); return tl;}/** Create a filtered tag list. * * @sa tl_afilter(), tl_tfilter(), TAG_FILTER(), TAG_ANY(), #ns_tag_class */tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[], tag_type_t tag, tag_value_t value, ...){ tagi_t *tl; ta_list ta; ta_start(ta, tag, value); tl = tl_afilter(home, filter, ta_args(ta)); ta_end(ta); return tl;}/** Remove listed tags from the list @a lst. */int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...){ tagi_t *l, *l_next; int retval = 0; ta_list ta; ta_start(ta, tag, value); for (l = lst; l; l = l_next) { if ((l_next = (tagi_t *)t_next(l))) { if (tl_find(ta_args(ta), l->t_tag)) l->t_tag = tag_skip; else retval++; } } ta_end(ta); return retval;}/** Calculate length of a tag list with a @c va_list. */size_t tl_vlen(va_list ap){ size_t len = 0; tagi_t tagi[2] = {{ NULL }}; do { tagi->t_tag = va_arg(ap, tag_type_t ); tagi->t_value = va_arg(ap, tag_value_t); len += sizeof(tagi_t); } while (!t_end(tagi)); return len;}/** Convert va_list to tag list */tagi_t *tl_vlist(va_list ap){ tagi_t *t, *rv; va_list aq; va_copy(aq, ap); rv = malloc(tl_vlen(aq)); va_end(aq); for (t = rv; t; t++) { t->t_tag = va_arg(ap, tag_type_t); t->t_value = va_arg(ap, tag_value_t); if (t_end(t)) break; } return rv;}tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap){ tagi_t *t, *rv; tagi_t tagi[1]; size_t size; tagi->t_tag = tag, tagi->t_value = value; if (!t_end(tagi)) { va_list aq; va_copy(aq, ap); size = sizeof(tagi) + tl_vlen(aq); va_end(aq); } else size = sizeof(tagi); t = rv = malloc(size); for (;t;) { *t++ = *tagi; if (t_end(tagi)) break; tagi->t_tag = va_arg(ap, tag_type_t); tagi->t_value = va_arg(ap, tag_value_t); } assert((char *)rv + size == (char *)t); return rv;}/** Make a tag list until TAG_NEXT() or TAG_END() */tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...){ va_list ap; tagi_t *t; va_start(ap, value); t = tl_vlist2(tag, value, ap); va_end(ap); return t;}/** Calculate length of a linear tag list. */size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap){ size_t len = sizeof(tagi_t); tagi_t const *next; tagi_t tagi[3]; tagi[0].t_tag = tag; tagi[0].t_value = value; tagi[1].t_tag = tag_any; tagi[1].t_value = 0; for (;;) { next = tl_next(tagi); if (next != tagi + 1) break; if (tagi->t_tag != tag_skip) len += sizeof(tagi_t); tagi->t_tag = va_arg(ap, tag_type_t); tagi->t_value = va_arg(ap, tag_value_t); } for (; next; next = tl_next(next)) len += sizeof(tagi_t); return len;}/** Make a linear tag list. */tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap){ va_list aq; tagi_t *t, *rv; tagi_t const *next; tagi_t tagi[2]; size_t size; va_copy(aq, ap); size = tl_vllen(tag, value, aq); va_end(aq); t = rv = malloc(size); if (rv == NULL) return rv; tagi[0].t_tag = tag; tagi[0].t_value = value; tagi[1].t_tag = tag_any; tagi[1].t_value = 0; for (;;) { next = tl_next(tagi); if (next != tagi + 1) break; if (tagi->t_tag != tag_skip) *t++ = *tagi; tagi->t_tag = va_arg(ap, tag_type_t); tagi->t_value = va_arg(ap, tag_value_t); } for (; next; next = tl_next(next)) *t++ = *next; t->t_tag = NULL; t->t_value = 0; t++; assert((char *)rv + size == (char *)t); return rv;}/** Make a linear tag list until TAG_END(). * */tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...){ va_list ap; tagi_t *t; va_start(ap, value); t = tl_vllist(tag, value, ap); va_end(ap); return t;}/** Free a tag list allocated by tl_list(), tl_llist() or tl_vlist(). */void tl_vfree(tagi_t *t){ if (t) free(t);}/** Convert a string to the a value of a tag. */int t_scan(tag_type_t tt, su_home_t *home, char const *s, tag_value_t *return_value){ if (tt == NULL || s == NULL || return_value == NULL) return -1; if (tt->tt_class->tc_scan) { return tt->tt_class->tc_scan(tt, home, s, return_value); } else { /* Not implemented */ *return_value = (tag_value_t)0; return -2; }}/* ====================================================================== *//* null tag */tagi_t const *t_null_next(tagi_t const *t){ return NULL;}tagi_t *t_null_move(tagi_t *dst, tagi_t const *src){ memset(dst, 0, sizeof(*dst)); return dst + 1;}tagi_t *t_null_dup(tagi_t *dst, tagi_t const *src, void **bb){ memset(dst, 0, sizeof(*dst)); return dst + 1;}tagi_t *t_null_copy(tagi_t *dst, tagi_t const *src, void **bb){ memset(dst, 0, sizeof(*dst)); return dst + 1;}tagi_t const * t_null_find(tag_type_t tt, tagi_t const lst[]){ return NULL;}tagi_t *t_null_filter(tagi_t *dst, tagi_t const filter[], tagi_t const *src, void **bb){ if (TAG_TYPE_OF(src) == tag_null) { if (dst) { dst->t_tag = NULL; dst->t_value = 0; } return dst + 1; } return dst;}tag_class_t null_tag_class[1] = {{ sizeof(null_tag_class), /* tc_next */ t_null_next, /* tc_len */ NULL, /* tc_move */ t_null_move, /* tc_xtra */ NULL, /* tc_dup */ t_null_dup, /* tc_free */ NULL, /* tc_find */ t_null_find, /* tc_snprintf */ NULL, /* tc_filter */ t_null_filter, /* tc_ref_set */ NULL, /* tc_scan */ NULL, }};tag_typedef_t tag_null = TAG_TYPEDEF(tag_null, null);/* ====================================================================== *//* end tag */tagi_t *t_end_filter(tagi_t *dst, tagi_t const filter[], tagi_t const *src, void **bb){ return dst;}tag_class_t end_tag_class[1] = {{ sizeof(end_tag_class), /* tc_next */ NULL, /* tc_len */ NULL, /* tc_move */ NULL, /* tc_xtra */ NULL, /* tc_dup */ NULL, /* tc_free */ NULL, /* tc_find */ NULL, /* tc_snprintf */ NULL, /* tc_filter */ t_end_filter, /* tc_ref_set */ NULL, /* tc_scan */ NULL, }};/* ====================================================================== *//* skip tag - placeholder in tag list */tagi_t const *t_skip_next(tagi_t const *t){ return t + 1;}tagi_t *t_skip_move(tagi_t *dst, tagi_t const *src){ return dst;}size_t t_skip_len(tagi_t const *t){ return 0;}tagi_t *t_skip_dup(tagi_t *dst, tagi_t const *src, void **bb){ return dst;}tagi_t *t_skip_filter(tagi_t *dst, tagi_t const filter[], tagi_t const *src, void **bb){ return dst;}tag_class_t skip_tag_class[1] = {{ sizeof(skip_tag_class), /* tc_next */ t_skip_next, /* tc_len */ t_skip_len, /* tc_move */ t_skip_move, /* tc_xtra */ NULL, /* tc_dup */ t_skip_dup, /* tc_free */ NULL, /* tc_find */ t_null_find, /* tc_snprintf */ NULL, /* tc_filter */ t_skip_filter, /* tc_ref_set */ NULL, /* tc_scan */ NULL, }};tag_typedef_t tag_skip = TAG_TYPEDEF(tag_skip, skip);/* ====================================================================== *//* next tag - jump to next tag list */tagi_t const *t_next_next(tagi_t const *t){ return (tagi_t *)(t->t_value);}tagi_t *t_next_move(tagi_t *dst, tagi_t const *src){ if (!src->t_value) return t_null_move(dst, src); return dst;}size_t t_next_len(tagi_t const *t){ if (!t->t_value) return sizeof(*t); return 0;}tagi_t *t_next_dup(tagi_t *dst, tagi_t const *src, void **bb){ if (!src->t_value) return t_null_dup(dst, src, bb); return dst;}tagi_t *t_next_filter(tagi_t *dst, tagi_t const filter[], tagi_t const *src, void **bb){ return dst;}tag_class_t next_tag_class[1] = {{ sizeof(next_tag_class), /* tc_next */ t_next_next, /* tc_len */ t_next_len, /* tc_move */ t_next_move, /* tc_xtra */ NULL, /* tc_dup */ t_next_dup, /* tc_free */ NULL, /* tc_find */ t_null_find, /* tc_snprintf */ NULL, /* tc_filter */ t_next_filter, /* tc_ref_set */ NULL, /* tc_scan */ NULL, }};tag_typedef_t tag_next = TAG_TYPEDEF(tag_next, next);/* ====================================================================== *//* filter tag - use function to filter tag */tagi_t *t_filter_with(tagi_t *dst, tagi_t const *t, tagi_t const *src, void **bb){ tag_filter_f *function; if (!src || !t) return dst; function = (tag_filter_f *)t->t_value; if (!function || !function(t, src)) return dst; if (dst) { return t_dup(dst, src, bb); } else { dst = (tagi_t *)((char *)dst + t_len(src)); *bb = (char *)*bb + t_xtra(src, (size_t)*bb); return dst; }} tag_class_t filter_tag_class[1] = {{ sizeof(filter_tag_class), /* tc_next */ NULL, /* tc_len */ NULL, /* tc_move */ NULL, /* tc_xtra */ NULL, /* tc_dup */ NULL, /* tc_free */ NULL, /* tc_find */ NULL, /* tc_snprintf */ NULL, /* tc_filter */ t_filter_with, /* tc_ref_set */ NULL, /* tc_scan */ NULL, }};/** Filter tag - apply function in order to filter tag. */tag_typedef_t tag_filter = TAG_TYPEDEF(tag_filter, filter);/* ====================================================================== *//* any tag - match to any tag when filtering */tagi_t *t_any_filter(tagi_t *dst, tagi_t const filter[], tagi_t const *src, void **bb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -