/* * aegis - project change supervisor * Copyright (C) 2001-2008, 2012, 2014 Peter Miller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #undef YYDEBUG #define YYDEBUG 1 #endif %} %token COMMENT %token DELTA_BEGIN %token DELTA_END %token D_KEYWORD %token E_KEYWORD %token FLAGS %token HEADER %token I_KEYWORD %token JUNK %token MR %token MR_EXCLUDE %token MR_IGNORE %token MR_INCLUDE %token STRING %token SUMMARY %token TEXTLINE %token TITLE_BEGIN %token TITLE_END %token USERS_BEGIN %token USERS_END %union { nstring *lv_string; long lv_long; } %type date_and_time number %type COMMENT STRING TEXTLINE %destructor { delete $$; } %{ static format_version *current; static itab_ty *itp; static nstring pfn; static nstring lfn; static format_version * find(int n) { assert(itp); format_version *fvp = (format_version *)itab_query(itp, n); if (!fvp) { fvp = new format_version(); itab_assign(itp, n, fvp); fvp->filename_physical = pfn; fvp->filename_logical = lfn; fvp->edit.push_back(nstring::format("%d", n)); } return fvp; } static void walker(itab_ty *, itab_key_ty, void *data, void *) { format_version *fvp = (format_version *)data; if (fvp->after_branch) { size_t ndots = fvp->edit.front().count_the_dots(); for (size_t j = 0; j < fvp->after_branch->length; ++j) { format_version *after = fvp->after_branch->item[j]; if ( !after->edit.empty() && after->edit.front().count_the_dots() <= ndots ) { fvp->after = after; if (j + 1 < fvp->after_branch->length) { fvp->after_branch->item[j] = fvp->after_branch->item[fvp->after_branch->length - 1]; } fvp->after_branch->length--; if (fvp->after_branch->length == 0) { delete fvp->after_branch; fvp->after_branch = NULL; } break; } } } } format_version * sccs_parse(const nstring &physical, const nstring &logical) { itp = itab_alloc(); pfn = physical; lfn = logical; sccs_lex_open(physical); #if YYDEBUG { extern int yydebug; yydebug = 1; } #endif { extern int yyparse(void); yyparse(); } sccs_lex_close(); itab_walk(itp, walker, 0); format_version *result = find(1); // FIXME: manual says largest sid itab_free(itp); itp = 0; return result; } %} %% sccsfile : header deltas users flags title body ; header : HEADER ignore_arguments ; deltas : delta | deltas delta ; delta : summary delta_begin delta_lines delta_end ; summary : SUMMARY ignore_arguments ; delta_begin : DELTA_BEGIN STRING STRING date_and_time STRING number number { format_version *before; (void)$2; /* * $2 some kind of state info, we ignore it * $3 edit * $4 time_t * $5 who * $6 number of this delta * $7 number of predecessor */ before = $7 ? find($7) : 0; current = find($6); current->edit.push_front_unique(*$3); current->when = $4; current->who.push_back_unique(*$5); nstring sid = nstring::format("%ld", $6); current->edit.push_back_unique(sid); current->before = before; if (before) { if (!before->after_branch) { before->after_branch = new format_version_list(); } before->after_branch->append(current); } } ; date_and_time : STRING STRING { // // make time_t value from strings // nstring_list sl1; sl1.split(*$1, "/"); while (sl1.size() < 3) sl1.push_back("0"); nstring_list sl2; sl2.split(*$2, ":"); while (sl2.size() < 3) sl2.push_back("0"); static struct tm tm_zero; struct tm temp = tm_zero; temp.tm_year = fix_tm_year(sl1[0].to_long()); temp.tm_mon = sl1[1].to_long() - 1; temp.tm_mday = sl1[2].to_long(); temp.tm_hour = sl2[0].to_long(); temp.tm_min = sl2[1].to_long(); temp.tm_sec = sl2[2].to_long(); time_t t = mktime(&temp); if (t == (time_t)-1) { nstring s = nstring(*$1) + " " + nstring(*$2); fatal_date_unknown(s.c_str()); } trace_time(t); $$ = t; } ; number : STRING { char *cp = 0; $$ = strtol($1->c_str(), &cp, 10); if ($1->size() && *cp != 0) yyerror("number expected"); } ; delta_lines : /* empty */ | delta_lines delta_line ; delta_line : comment | mr | included | excluded | ignored | error ; comment : COMMENT { assert(current); if (current) { nstring_list log; log.split(*$1, "\n", true); current->description.push_back_unique(log); } } ; mr : MR ignore_arguments ; included : MR_INCLUDE ignore_arguments ; excluded : MR_EXCLUDE ignore_arguments ; ignored : MR_IGNORE ignore_arguments ; delta_end : DELTA_END ignore_arguments { assert(current); if (current->description.empty()) { current->description.push_back("no description"); } current = NULL; } ; users : users_start textlines_opt users_end ; users_start : USERS_BEGIN ignore_arguments ; users_end : USERS_END ignore_arguments ; flags : /* empty */ | flags flag ; flag : FLAGS ignore_arguments ; ignore_arguments : /* empty */ | ignore_arguments STRING { (void)$2; } ; title : title_begin textlines_opt title_end ; title_begin : TITLE_BEGIN ignore_arguments ; title_end : TITLE_END ignore_arguments ; body : /* empty */ | body I_stuff | body D_stuff | body E_stuff | body error ; /* ^AI */ I_stuff : I_KEYWORD ignore_arguments textlines_opt ; /* ^AD */ D_stuff : D_KEYWORD ignore_arguments textlines_opt ; /* ^AE */ E_stuff : E_KEYWORD ignore_arguments textlines_opt ; textlines_opt : /* empty */ | textlines_opt TEXTLINE { (void)$2; } ; /* vim: set ts=8 sw=4 et : */