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