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