1 /* changelogs.c:
2 *
3 ****************************************************************
4 * Copyright (C) 2003 Tom Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11 #include "hackerlab/bugs/panic.h"
12 #include "hackerlab/char/char-class.h"
13 #include "hackerlab/char/str.h"
14 #include "hackerlab/vu/safe.h"
15 #include "hackerlab/rx-posix/regex.h"
16 #include "tla/libarch/patch-logs.h"
17 #include "tla/libarch/inv-ids.h"
18 #include "tla/libarch/namespace.h"
19 #include "tla/libarch/changelogs.h"
20
21
22
23 #define arch_changelog_id_re "^([ix]_automatic-ChangeLog--)(" arch_archive_re ")/(" arch_base_re ")(--" arch_base_re ")?(--" arch_vsn_re ")$"
24
25
26 /* __STDC__ prototypes for static functions */
27 static regex_t * changelog_id_pattern (void);
28 static void generate_changelog_entry (int out_fd, const t_uchar * archive, const t_uchar * version, const t_uchar * patch_lvl, const t_uchar * file, int no_files);
29 static void changelog_file_list (int out_fd, assoc_table headers, const t_uchar * header, const t_uchar * exclude);
30 static void changelog_file_pair_list (int out_fd, assoc_table headers, const t_uchar * header);
31
32
33
34 int
arch_id_indicates_changelog(const t_uchar * id)35 arch_id_indicates_changelog (const t_uchar * id)
36 {
37 regex_t * pattern;
38
39 pattern = changelog_id_pattern ();
40
41 if (!regexec (pattern, id, 0, 0, 0))
42 return 1;
43 else
44 return 0;
45 }
46
47 void
arch_parse_changelog_id(t_uchar ** archive,t_uchar ** version,const t_uchar * id)48 arch_parse_changelog_id (t_uchar ** archive, t_uchar ** version, const t_uchar * id)
49 {
50 regex_t * pattern;
51 regmatch_t pmatch[6];
52
53 pattern = changelog_id_pattern ();
54
55 invariant (!regexec (pattern, id, 6, pmatch, 0));
56 *archive = str_save_n (0, id + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
57 *version = str_save_n (0, id + pmatch[3].rm_so, pmatch[5].rm_eo - pmatch[3].rm_so);
58 }
59
60
61 void
arch_generate_changelog(int out_fd,const t_uchar * tree_root,int no_files,int untagged,const t_uchar * new_entry_patch_lvl,const t_uchar * new_entry_file,const t_uchar * archive,const t_uchar * version)62 arch_generate_changelog (int out_fd,
63 const t_uchar * tree_root,
64 int no_files,
65 int untagged,
66 const t_uchar * new_entry_patch_lvl,
67 const t_uchar * new_entry_file,
68 const t_uchar * archive,
69 const t_uchar * version)
70 {
71 rel_table log_ls;
72 int lim;
73 int x;
74
75 if (!arch_valid_package_name (version, arch_no_archive, arch_req_version, 0))
76 {
77 safe_printfmt (2, "changelog: invalid version name (%s)\n", version);
78 exit (1);
79 }
80
81 log_ls = arch_logs (tree_root, archive, version, 0);
82 arch_sort_table_by_patch_level_field (1, log_ls, 0);
83
84 {
85 t_uchar * tag_name;
86
87 if (untagged)
88 tag_name = "non-id";
89 else if (arch_implicit_id_tagging == arch_tree_id_tagging_method (0, tree_root, 0))
90 tag_name = "tag";
91 else
92 tag_name = "arch-tag";
93
94 safe_printfmt (out_fd, "# do not edit -- automatically generated by arch changelog\n# %s: automatic-ChangeLog--%s/%s\n#\n\n", tag_name, archive, version);
95 }
96
97 if (new_entry_patch_lvl)
98 {
99 generate_changelog_entry (out_fd, archive, version, new_entry_patch_lvl, new_entry_file, no_files);
100 }
101
102 lim = rel_n_records (log_ls);
103 for (x = 0; x < lim; ++x)
104 {
105 generate_changelog_entry (out_fd, archive, version, rel_peek_str (log_ls, x, 0), rel_peek_str (log_ls, x, 1), no_files);
106 }
107
108 rel_free_table (log_ls);
109 }
110
111
112
113
114
115 static regex_t *
changelog_id_pattern(void)116 changelog_id_pattern (void)
117 {
118 static int compiled = 0;
119 static regex_t pattern;
120
121 if (!compiled)
122 {
123 if (regcomp (&pattern, arch_changelog_id_re, REG_EXTENDED))
124 panic ("unable to compile arch_changelog_id_re");
125 compiled = 1;
126 }
127
128 return &pattern;
129 }
130
131
132
133 static void
generate_changelog_entry(int out_fd,const t_uchar * archive,const t_uchar * version,const t_uchar * patch_lvl,const t_uchar * file,int no_files)134 generate_changelog_entry (int out_fd, const t_uchar * archive, const t_uchar * version, const t_uchar * patch_lvl, const t_uchar * file, int no_files)
135 {
136 int in_fd;
137 t_uchar * log = 0;
138 size_t len;
139 assoc_table headers = 0;
140 t_uchar * body = 0;
141
142 in_fd = safe_open (file, O_RDONLY, 0);
143 safe_file_to_string (&log, &len, in_fd);
144 safe_close (in_fd);
145 log = lim_realloc (0, log, len + 1);
146 log[len] = 0;
147 headers = 0;
148 body = 0;
149 arch_parse_log (0, &headers, (const t_uchar **)&body, log);
150 lim_free (0, log);
151
152 /* print the first line (date, creator, patch level)
153 */
154
155 {
156 const t_uchar * raw_date;
157 t_uchar * cooked_date = 0;
158 const t_uchar * creator;
159
160 raw_date = assoc_get_str_taking (headers, rel_make_field_str ("standard-date"));
161 if (raw_date)
162 {
163 const t_uchar * from;
164 const t_uchar * to;
165
166 from = raw_date;
167 while (*from && char_is_space (*from))
168 ++from;
169
170 to = from;
171 while (*to && !char_is_space (*to))
172 ++to;
173 while (*to && char_is_space (*to))
174 ++to;
175 while (*to && !char_is_space (*to))
176 ++to;
177
178 cooked_date = str_save_n (0, from, to - from);
179 cooked_date = str_realloc_cat (0, cooked_date, " GMT");
180 }
181 else
182 {
183 cooked_date = str_save (0, "\?\?\?\?-\?\?-\?\? GMT");
184 }
185
186 creator = assoc_get_str_taking (headers, rel_make_field_str ("creator"));
187 if (!creator)
188 creator = "????";
189
190 safe_printfmt (out_fd, "%s\t%s\t%s\n", cooked_date, creator, patch_lvl);
191 lim_free (0, cooked_date);
192 }
193
194 safe_printfmt (out_fd, "\n");
195
196 /* Print the summary: */
197
198 {
199 const t_uchar * summary;
200
201 summary = assoc_get_str_taking (headers, rel_make_field_str ("summary"));
202 if (!summary)
203 summary = "";
204
205 safe_printfmt (out_fd, " Summary:\n %s\n", summary);
206 }
207
208 /* Print the revision name: */
209 {
210 const t_uchar * revision;
211
212 revision = assoc_get_str_taking (headers, rel_make_field_str ("revision"));
213 if (!revision)
214 revision = "";
215
216 safe_printfmt (out_fd, " Revision:\n %s\n", revision);
217 }
218
219 safe_printfmt (out_fd, "\n");
220
221 /* Print the revision body: */
222 {
223 t_uchar * eol;
224 t_uchar * pos;
225
226 pos = body;
227 while (*pos)
228 {
229 eol = str_chr_index (pos, '\n');
230
231 if (eol)
232 {
233 safe_printfmt (out_fd, " %.*s\n", (int)(eol - pos), pos);
234 pos = eol + 1;
235 }
236 else
237 {
238 safe_printfmt (out_fd, " %s\n", pos);
239 break;
240 }
241 }
242 }
243
244 safe_printfmt (out_fd, "\n");
245
246 /* file lists */
247
248 if (!no_files)
249 {
250 t_uchar * revision = 0;
251 t_uchar * fqrev = 0;
252 t_uchar * excluded_patch_file = 0;
253
254 revision = str_alloc_cat_many (0, version, "--", patch_lvl, str_end);
255 fqrev = arch_fully_qualify (archive, revision);
256
257 excluded_patch_file = arch_log_file (".", archive, revision);
258
259 changelog_file_list (out_fd, headers, "new-files", excluded_patch_file + 2);
260 changelog_file_list (out_fd, headers, "removed-files", 0);
261 changelog_file_list (out_fd, headers, "modified-files", 0);
262 changelog_file_pair_list (out_fd, headers, "renamed-files");
263 changelog_file_list (out_fd, headers, "new-directories", 0);
264 changelog_file_list (out_fd, headers, "removed-directories", 0);
265 changelog_file_list (out_fd, headers, "modified-directories", 0);
266 changelog_file_pair_list (out_fd, headers, "renamed-directories");
267 changelog_file_list (out_fd, headers, "new-patches", fqrev);
268
269 lim_free (0, revision);
270 lim_free (0, fqrev);
271 lim_free (0, excluded_patch_file);
272 }
273
274 safe_printfmt (out_fd, "\n");
275
276 lim_free (0, body);
277 free_assoc_table (headers);
278 }
279
280 static void
changelog_file_list(int out_fd,assoc_table headers,const t_uchar * header,const t_uchar * exclude)281 changelog_file_list (int out_fd, assoc_table headers, const t_uchar * header, const t_uchar * exclude)
282 {
283 const t_uchar * value;
284 int width;
285 int items_on_line;
286 int printed_header;
287
288
289 value = assoc_get_str_taking (headers, rel_make_field_str (header));
290 if (!value)
291 return;
292
293 printed_header = 0;
294 width = 0;
295 items_on_line = 0;
296
297 while (1)
298 {
299 const t_uchar * end;
300
301 while (char_is_space (*value))
302 ++value;
303
304 if (!*value)
305 break;
306
307 end = value;
308 while (*end && !char_is_space (*end))
309 ++end;
310
311 if (!exclude || str_cmp_n (exclude, str_length (exclude), value, end - value))
312 {
313 if (!printed_header)
314 {
315 t_uchar * fixed_header = 0;
316
317 fixed_header = str_save (0, header);
318 {
319 t_uchar * h;
320 for (h = fixed_header; *h; ++h)
321 if (*h == '-')
322 *h = ' ';
323 safe_printfmt (out_fd, " %s:\n ", fixed_header);
324 }
325 lim_free (0, fixed_header);
326 printed_header = 1;
327 }
328
329
330 if ((items_on_line == 0) || ((width + (1 + end - value)) < 64))
331 {
332 width += (end - value) + 1;
333 ++items_on_line;
334 safe_printfmt (out_fd, " %.*s", (int)(end - value), value);
335 }
336 else
337 {
338 safe_printfmt (out_fd, "\n %.*s", (int)(end - value), value);
339 width = (end - value) + 1;
340 items_on_line = 1;
341 }
342 }
343
344 value = end;
345 }
346
347 if (printed_header)
348 safe_printfmt (out_fd, "\n\n");
349 }
350
351
352 static void
changelog_file_pair_list(int out_fd,assoc_table headers,const t_uchar * header)353 changelog_file_pair_list (int out_fd, assoc_table headers, const t_uchar * header)
354 {
355 const t_uchar * value;
356 int printed_header = 0;
357
358 value = assoc_get_str_taking (headers, rel_make_field_str (header));
359 if (!value)
360 return;
361
362 while (1)
363 {
364 const t_uchar * end_1;
365 const t_uchar * start_2;
366 const t_uchar * end_2;
367
368 while (char_is_space (*value))
369 ++value;
370
371 if (!*value)
372 break;
373
374 end_1 = value;
375 while (*end_1 && !char_is_space (*end_1))
376 ++end_1;
377
378 if (!*end_1)
379 panic ("corrupt log file");
380
381 start_2 = end_1;
382
383 while (char_is_space (*start_2))
384 ++start_2;
385
386 if (!*start_2)
387 panic ("corrupt log file");
388
389 end_2 = start_2;
390 while (*end_2 && !char_is_space (*end_2))
391 ++end_2;
392
393 if (!printed_header)
394 {
395 t_uchar * fixed_header = 0;
396
397 fixed_header = str_save (0, header);
398 {
399 t_uchar * h;
400 for (h = fixed_header; *h; ++h)
401 if (*h == '-')
402 *h = ' ';
403 safe_printfmt (out_fd, " %s:\n", fixed_header);
404 }
405 lim_free (0, fixed_header);
406 printed_header = 1;
407 }
408
409 safe_printfmt (out_fd, " %.*s\n ==> %.*s\n", (end_1 - value), value, (end_2 - start_2), start_2);
410 value = end_2;
411 }
412
413 if (printed_header)
414 safe_printfmt (out_fd, "\n");
415 }
416
417
418
419
420
421 /* tag: Tom Lord Wed May 14 12:14:01 2003 (changelogs.c)
422 */
423