1 /*
2  * t_tag.c
3  *
4  * tagutil's tag routines.
5  */
6 #include <string.h>
7 
8 #include "t_config.h"
9 #include "t_toolkit.h"
10 #include "t_tag.h"
11 #include "t_taglist.h"
12 
13 
14 struct t_taglist *
t_taglist_new(void)15 t_taglist_new(void)
16 {
17 	struct t_taglist *ret;
18 
19 	ret = malloc(sizeof(struct t_taglist));
20 	if (ret == NULL)
21 		return (NULL);
22 
23 	ret->count = 0;
24 	TAILQ_INIT(ret->tags);
25 
26 	return (ret);
27 }
28 
29 struct t_taglist *
t_taglist_clone(const struct t_taglist * tlist)30 t_taglist_clone(const struct t_taglist *tlist)
31 {
32 	struct t_taglist *clone;
33 	struct t_tag *t;
34 
35 	if (tlist == NULL)
36 		return (NULL);
37 
38 	clone = t_taglist_new();
39 	if (clone == NULL)
40 		return (NULL);
41 	TAILQ_FOREACH(t, tlist->tags, entries) {
42 		if (t_taglist_insert(clone, t->key, t->val) != 0) {
43 			t_taglist_delete(clone);
44 			return (NULL);
45 		}
46 	}
47 
48 	return (clone);
49 }
50 
51 int
t_taglist_insert(struct t_taglist * tlist,const char * key,const char * val)52 t_taglist_insert(struct t_taglist *tlist, const char *key, const char *val)
53 {
54 	struct t_tag *t;
55 
56 	assert(tlist != NULL);
57 	assert(key != NULL);
58 	assert(val != NULL);
59 
60 	t = t_tag_new(key, val);
61 	if (t == NULL)
62 		return (-1);
63 
64 	TAILQ_INSERT_TAIL(tlist->tags, t, entries);
65 	tlist->count++;
66 	return (0);
67 }
68 
69 
70 struct t_taglist *
t_taglist_find_all(const struct t_taglist * tlist,const char * key)71 t_taglist_find_all(const struct t_taglist *tlist, const char *key)
72 {
73 	struct t_taglist *r;
74 	const struct t_tag *t;
75 
76 	assert(tlist != NULL);
77 	assert(key != NULL);
78 	if ((r = t_taglist_new()) == NULL)
79 		goto error;
80 
81 	TAILQ_FOREACH(t, tlist->tags, entries) {
82 		if (t_tag_keycmp(t->key, key) == 0) {
83 			if (t_taglist_insert(r, t->key, t->val) != 0)
84 				goto error;
85 		}
86 	}
87 
88 	return (r);
89 	/* NOTREACHED */
90 error:
91 	t_taglist_delete(r);
92 	return (NULL);
93 }
94 
95 
96 struct t_tag *
t_taglist_tag_at(const struct t_taglist * tlist,unsigned int index)97 t_taglist_tag_at(const struct t_taglist *tlist, unsigned int index)
98 {
99 	struct t_tag *t;
100 
101 	assert(tlist != NULL);
102 
103 	t = TAILQ_FIRST(tlist->tags);
104 	while (t != NULL && index-- > 0)
105 		t = TAILQ_NEXT(t, entries);
106 
107 	return (t);
108 }
109 
110 
111 char *
t_taglist_join(const struct t_taglist * tlist,const char * glue)112 t_taglist_join(const struct t_taglist *tlist, const char *glue)
113 {
114 	struct sbuf *sb;
115 	struct t_tag *t, *last;
116 	char *ret;
117 
118 	assert(tlist != NULL);
119 	assert(glue != NULL);
120 
121 	sb = sbuf_new_auto();
122 	if (sb == NULL)
123 		return (NULL);
124 
125 	last = TAILQ_LAST(tlist->tags, t_tagQ);
126 	TAILQ_FOREACH(t, tlist->tags, entries) {
127 		(void)sbuf_cat(sb, t->val);
128 		if (t != last)
129 			(void)sbuf_cat(sb, glue);
130 	}
131 
132 	if (sbuf_finish(sb) == -1) {
133 		sbuf_delete(sb);
134 		return (NULL);
135 	}
136 	ret = strdup(sbuf_data(sb));
137 	sbuf_delete(sb);
138 
139 	return (ret);
140 }
141 
142 
143 void
t_taglist_delete(struct t_taglist * tlist)144 t_taglist_delete(struct t_taglist *tlist)
145 {
146 	struct t_tag *t1, *t2;
147 
148 	if (tlist == NULL)
149 		return;
150 
151 	t1 = TAILQ_FIRST(tlist->tags);
152 	while (t1 != NULL) {
153 		t2 = TAILQ_NEXT(t1, entries);
154 		t_tag_delete(t1);
155 		t1 = t2;
156 	}
157 	free(tlist);
158 }
159