1 /*
2 * aegis - project change supervisor
3 * Copyright (C) 2001-2008, 2012 Peter Miller
4 * Copyright (C) 2020 Aryeh M. Friedman
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 (at
9 * 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 GNU
14 * 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 <http://www.gnu.org/licenses/>.
18 */
19
20 %define api.prefix {format_sccs_gram_}
21 %{
22
23 #include <common/ac/assert.h>
24 #include <common/ac/stdio.h>
25 #include <common/ac/stdlib.h>
26
27 #include <common/debug.h>
28 #include <common/gettime.h>
29 #include <common/itab.h>
30 #include <common/str_list.h>
31 #include <libaegis/help.h>
32
33 #include <aeimport/format/sccs/gram.h>
34 #include <aeimport/format/sccs/lex.h>
35 #include <aeimport/format/version.h>
36 #include <aeimport/format/version_list.h>
37
38 #ifdef DEBUG
39 #undef YYDEBUG
40 #define YYDEBUG 1
41 #endif
42
43 %}
44
45 %token COMMENT
46 %token DELTA_BEGIN
47 %token DELTA_END
48 %token D_KEYWORD
49 %token E_KEYWORD
50 %token FLAGS
51 %token HEADER
52 %token I_KEYWORD
53 %token JUNK
54 %token MR
55 %token MR_EXCLUDE
56 %token MR_IGNORE
57 %token MR_INCLUDE
58 %token STRING
59 %token SUMMARY
60 %token TEXTLINE
61 %token TITLE_BEGIN
62 %token TITLE_END
63 %token USERS_BEGIN
64 %token USERS_END
65
66 %union {
67 string_ty *lv_string;
68 long lv_long;
69 }
70
71 %type <lv_long> date_and_time number
72 %type <lv_string> COMMENT STRING TEXTLINE
73
74 %{
75
76 static format_version_ty *current;
77 static itab_ty *itp;
78 static string_ty *pfn;
79 static string_ty *lfn;
80
81
82 static format_version_ty *
find(int n)83 find(int n)
84 {
85 format_version_ty *fvp;
86
87 assert(itp);
88 fvp = (format_version_ty *)itab_query(itp, n);
89 if (!fvp)
90 {
91 fvp = new format_version_ty();
92 itab_assign(itp, n, fvp);
93 fvp->filename_physical = str_copy(pfn);
94 fvp->filename_logical = str_copy(lfn);
95 }
96 return fvp;
97 }
98
99
100 static int
count_the_dots(string_ty * s)101 count_the_dots(string_ty *s)
102 {
103 const char *cp;
104 int result;
105
106 result = 0;
107 for (cp = s->str_text; *cp; ++cp)
108 if (*cp == '.')
109 ++result;
110 return result;
111 }
112
113
114 static void
walker(itab_ty *,itab_key_ty,void * data,void *)115 walker(itab_ty *, itab_key_ty, void *data, void *)
116 {
117 format_version_ty *fvp;
118 int ndots;
119 size_t j;
120
121 fvp = (format_version_ty *)data;
122 if (fvp->after_branch)
123 {
124 ndots = count_the_dots(fvp->edit);
125 for (j = 0; j < fvp->after_branch->length; ++j)
126 {
127 format_version_ty *after;
128
129 after = fvp->after_branch->item[j];
130 if (after->edit && count_the_dots(after->edit) <= ndots)
131 {
132 fvp->after = after;
133 if (j + 1 < fvp->after_branch->length)
134 {
135 fvp->after_branch->item[j] =
136 fvp->after_branch->item[fvp->after_branch->length - 1];
137 }
138 fvp->after_branch->length--;
139 if (fvp->after_branch->length == 0)
140 {
141 format_version_list_delete(fvp->after_branch, 0);
142 fvp->after_branch = 0;
143 }
144 break;
145 }
146 }
147 }
148 }
149
150
151 format_version_ty *
sccs_parse(string_ty * physical,string_ty * logical)152 sccs_parse(string_ty *physical, string_ty *logical)
153 {
154 extern int yyparse(void);
155 format_version_ty *result;
156
157 itp = itab_alloc();
158 pfn = physical;
159 lfn = logical;
160
161 sccs_lex_open(physical);
162 #if YYDEBUG
163 { extern int yydebug; yydebug = 1; }
164 #endif
165 yyparse();
166 sccs_lex_close();
167
168 itab_walk(itp, walker, 0);
169
170 result = find(1);
171 itab_free(itp);
172 itp = 0;
173 return result;
174 }
175
176 %}
177
178 %%
179
180 sccsfile
181 : header deltas users flags title body
182 ;
183
184 header
185 : HEADER ignore_arguments
186 ;
187
188 deltas
189 : delta
190 | deltas delta
191 ;
192
193 delta
194 : summary delta_begin delta_lines delta_end
195 ;
196
197 summary
198 : SUMMARY ignore_arguments
199 ;
200
201 delta_begin
202 : DELTA_BEGIN STRING STRING date_and_time STRING number number
203 {
204 format_version_ty *before;
205
206 /*
207 * $2 some kind of state info, we ignore it
208 * $3 sid
209 * $4 time_t
210 * $5 who
211 * $6 number of this delta
212 * $7 number of predecessor
213 */
214 before = $7 ? find($7) : 0;
215 str_free($2);
216 current = find($6);
217 current->edit = $3;
218 current->when = $4;
219 current->who = $5 ;
220 current->before = before;
221 if (before)
222 {
223 if (!before->after_branch)
224 {
225 before->after_branch = format_version_list_new();
226 }
227 format_version_list_append(before->after_branch, current);
228 }
229 }
230 ;
231
232 date_and_time
233 : STRING STRING
234 {
235 string_list_ty sl;
236 string_ty *s;
237 time_t t;
238
239 /*
240 * Convert from the emminently sensable YY/MM/DD
241 * into the hideous american MM/DD/YY
242 */
243 sl.split($1, "/");
244 str_free($1);
245 while (sl.nstrings < 3)
246 sl.push_back(str_from_c(""));
247 s =
248 str_format
249 (
250 "%s/%s/%s %s GMT",
251 sl.string[1]->str_text,
252 sl.string[2]->str_text,
253 sl.string[0]->str_text,
254 $2->str_text
255 );
256 str_free($2);
257 t = date_scan(s->str_text);
258 if (t == (time_t)-1)
259 fatal_date_unknown(s->str_text);
260 str_free(s);
261 $$ = t;
262 }
263 ;
264
265 number
266 : STRING
267 {
268 char *cp = 0;
269 $$ = strtol($1->str_text, &cp, 10);
270 if ($1->str_length && *cp != 0)
271 yyerror("number expected");
272 str_free($1);
273 }
274 ;
275
276 delta_lines
277 : /* empty */
278 | delta_lines delta_line
279 ;
280
281 delta_line
282 : comment
283 | mr
284 | included
285 | excluded
286 | ignored
287 | error
288 ;
289
290 comment
291 : COMMENT
292 {
293 string_ty *s;
294
295 assert(current);
296 if (current)
297 {
298 if (current->description)
299 {
300 s =
301 str_format
302 (
303 "%s\n%s",
304 current->description->str_text,
305 $1->str_text
306 );
307 str_free(current->description);
308 current->description = s;
309 }
310 else
311 current->description = str_copy($1);
312 }
313 str_free($1);
314 }
315 ;
316
317 mr
318 : MR ignore_arguments
319 ;
320
321 included
322 : MR_INCLUDE ignore_arguments
323 ;
324
325 excluded
326 : MR_EXCLUDE ignore_arguments
327 ;
328
329 ignored
330 : MR_IGNORE ignore_arguments
331 ;
332
333 delta_end
334 : DELTA_END ignore_arguments
335 {
336 assert(current);
337 if (!current->description)
338 {
339 current->description = str_from_c("no description");
340 }
341 current = 0;
342 }
343 ;
344
345 users
346 : users_start textlines_opt users_end
347 ;
348
349 users_start
350 : USERS_BEGIN ignore_arguments
351 ;
352
353 users_end
354 : USERS_END ignore_arguments
355 ;
356
357 flags
358 : /* empty */
359 | flags flag
360 ;
361
362 flag
363 : FLAGS ignore_arguments
364 ;
365
366 ignore_arguments
367 : /* empty */
368 | ignore_arguments STRING
369 { str_free($2); }
370 ;
371
372 title
373 : title_begin textlines_opt title_end
374 ;
375
376 title_begin
377 : TITLE_BEGIN ignore_arguments
378 ;
379
380 title_end
381 : TITLE_END ignore_arguments
382 ;
383
384 body
385 : /* empty */
386 | body I_stuff
387 | body D_stuff
388 | body E_stuff
389 | body error
390 ;
391
392 /* ^AI <n> */
393 I_stuff
394 : I_KEYWORD ignore_arguments textlines_opt
395 ;
396
397 /* ^AD <n> */
398 D_stuff
399 : D_KEYWORD ignore_arguments textlines_opt
400 ;
401
402 /* ^AE <n> */
403 E_stuff
404 : E_KEYWORD ignore_arguments textlines_opt
405 ;
406
407 textlines_opt
408 : /* empty */
409 | textlines_opt TEXTLINE
410 { str_free($2); }
411 ;
412
413
414 /* vim: set ts=8 sw=4 et : */
415