1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1999, 2001-2008, 2012 Peter Miller
4 // Copyright (C) 2008 Walter Franzini
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see
18 // <http://www.gnu.org/licenses/>.
19 //
20
21 #include <common/ac/assert.h>
22
23 #include <common/mem.h>
24 #include <common/symtab.h>
25 #include <common/trace.h>
26 #include <libaegis/ael/attribu_list.h>
27 #include <libaegis/ael/build_header.h>
28 #include <libaegis/ael/change/by_state.h>
29 #include <libaegis/ael/change/inappropriat.h>
30 #include <libaegis/ael/column_width.h>
31 #include <libaegis/change.h>
32 #include <libaegis/change/identifier.h>
33 #include <libaegis/col.h>
34 #include <libaegis/option.h>
35 #include <libaegis/output.h>
36 #include <libaegis/project.h>
37 #include <libaegis/project/history.h>
38 #include <libaegis/user.h>
39
40
41 static int
single_bit(int n)42 single_bit(int n)
43 {
44 int result;
45
46 // see if no bits are set
47 if (!n)
48 return -1;
49
50 //
51 // see if more than 1 bit is set
52 // (only works on 2s compliment machines)
53 //
54 if ((n & -n) != n)
55 return -1;
56
57 //
58 // will need to extend this for 64bit machines,
59 // if ever have >32 states
60 //
61 result = 0;
62 if (n & 0xFFFF0000)
63 result += 16;
64 if (n & 0xFF00FF00)
65 result += 8;
66 if (n & 0xF0F0F0F0)
67 result += 4;
68 if (n & 0xCCCCCCCC)
69 result += 2;
70 if (n & 0xAAAAAAAA)
71 result++;
72 return result;
73 }
74
75
76 static void
output_reaper(void * p)77 output_reaper(void *p)
78 {
79 output::pointer *opp = (output::pointer *)p;
80 delete opp;
81 }
82
83
84 void
list_changes_in_state_mask_by_user(change_identifier & cid,int state_mask,string_ty * login)85 list_changes_in_state_mask_by_user(change_identifier &cid, int state_mask,
86 string_ty *login)
87 {
88 output::pointer number_col;
89 output::pointer state_col;
90 output::pointer description_col;
91 int j;
92 string_ty *line1;
93 string_ty *line2;
94 symtab_ty *attr_col_stp = 0;
95
96 if (cid.set())
97 list_change_inappropriate();
98
99 //
100 // Check that the specified user exists.
101 //
102 if (login)
103 user_ty::create(nstring(login));
104
105 //
106 // create the columns
107 //
108 col::pointer colp = col::open((string_ty *)0);
109 line1 =
110 str_format("Project \"%s\"", project_name_get(cid.get_pp()).c_str());
111 j = single_bit(state_mask);
112 if (j >= 0)
113 {
114 line2 =
115 str_format
116 (
117 "List of Changes %s",
118 cstate_state_ename((cstate_state_ty)j)
119 );
120 }
121 else
122 {
123 j = single_bit(~state_mask);
124 if (j >= 0)
125 {
126 line2 =
127 str_format
128 (
129 "List of Changes not %s",
130 cstate_state_ename((cstate_state_ty)j)
131 );
132 }
133 else
134 line2 = str_from_c("List of Changes");
135 }
136 colp->title(line1->str_text, line2->str_text);
137 str_free(line1);
138 str_free(line2);
139
140 int left = 0;
141 number_col = colp->create(left, left + CHANGE_WIDTH, "Change\n-------");
142 left += CHANGE_WIDTH + 1;
143
144 if (!option_terse_get())
145 {
146 state_col =
147 colp->create(left, left + STATE_WIDTH, "State\n-------");
148 left += STATE_WIDTH + 1;
149
150 attr_col_stp = new symtab_ty(5);
151 attr_col_stp->set_reap(output_reaper);
152 for (j = 0; ; ++j)
153 {
154 long change_number = 0;
155 if (!project_change_nth(cid.get_pp(), j, &change_number))
156 break;
157 change::pointer cp = change_alloc(cid.get_pp(), change_number);
158 change_bind_existing(cp);
159 cstate_ty *cstate_data = cp->cstate_get();
160 if
161 (
162 (state_mask & (1 << cstate_data->state))
163 &&
164 //
165 // If no user has been specified, we don't care who the
166 // owner of the change is.
167 //
168 (!login || str_equal(login, cp->developer_name()))
169 &&
170 cstate_data->attribute
171 )
172 {
173 for (size_t k = 0; k < cstate_data->attribute->length; ++k)
174 {
175 attributes_ty *ap = cstate_data->attribute->list[k];
176 if (ael_attribute_listable(ap))
177 {
178 string_ty *lc_name = str_downcase(ap->name);
179 void *p = attr_col_stp->query(lc_name);
180 if (!p)
181 {
182 string_ty *s = ael_build_header(ap->name);
183 output::pointer op =
184 colp->create
185 (
186 left,
187 left + ATTR_WIDTH,
188 s->str_text
189 );
190 str_free(s);
191 attr_col_stp->assign
192 (
193 lc_name,
194 new output::pointer(op)
195 );
196 left += ATTR_WIDTH + 1;
197 }
198 str_free(lc_name);
199 }
200 }
201 }
202 change_free(cp);
203 }
204
205 description_col =
206 colp->create(left, 0, "Description\n-------------");
207 }
208
209 //
210 // list the project's changes
211 //
212 for (j = 0; ; ++j)
213 {
214 long change_number = 0;
215 if (!project_change_nth(cid.get_pp(), j, &change_number))
216 break;
217 change::pointer cp = change_alloc(cid.get_pp(), change_number);
218 change_bind_existing(cp);
219 cstate_ty *cstate_data = cp->cstate_get();
220 if
221 (
222 (state_mask & (1 << cstate_data->state))
223 &&
224 //
225 // If no user has been specified, we don't care who the
226 // owner of the change is.
227 //
228 (!login || str_equal(login, cp->developer_name()))
229 )
230 {
231 number_col->fprintf("%4ld", magic_zero_decode(change_number));
232 if (state_col)
233 {
234 state_col->fputs(cstate_state_ename(cstate_data->state));
235 if
236 (
237 option_verbose_get()
238 &&
239 cstate_data->state == cstate_state_being_developed
240 )
241 {
242 state_col->end_of_line();
243 state_col->fputs(cp->developer_name());
244 }
245 if
246 (
247 option_verbose_get()
248 &&
249 cstate_data->state == cstate_state_being_integrated
250 )
251 {
252 state_col->end_of_line();
253 state_col->fputs(cp->integrator_name());
254 }
255 }
256 if (description_col && cstate_data->brief_description)
257 {
258 description_col->fputs(cstate_data->brief_description);
259 }
260 if (attr_col_stp && cstate_data->attribute)
261 {
262 for (size_t k = 0; k < cstate_data->attribute->length; ++k)
263 {
264 attributes_ty *ap = cstate_data->attribute->list[k];
265 if (ap->name && ap->value)
266 {
267 string_ty *lc_name = str_downcase(ap->name);
268 void *vp = attr_col_stp->query(lc_name);
269 if (vp)
270 {
271 output::pointer op = *(output::pointer *)vp;
272 assert(op);
273 op->fputs(ap->value);
274 }
275 str_free(lc_name);
276 }
277 }
278 }
279 colp->eoln();
280 }
281 change_free(cp);
282 }
283 if (attr_col_stp)
284 delete attr_col_stp;
285 trace(("}\n"));
286 }
287
288
289 void
list_changes_in_state_mask(change_identifier & cid,int state_mask)290 list_changes_in_state_mask(change_identifier &cid, int state_mask)
291 {
292 list_changes_in_state_mask_by_user(cid, state_mask, 0);
293 }
294
295
296 // vim: set ts=8 sw=4 et :
297