// // aegis - project change supervisor // Copyright (C) 2001-2009, 2011, 2012, 2014 Peter Miller // Copyright (C) 2008, 2009 Walter Franzini // // 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 #include #include #include #define ONE_OR_MORE (-1) typedef nstring (*func_ptr)(change::pointer cp, const wstring_list &args); struct table_ty { const char *name; func_ptr func; int num_args; }; static nstring change_number_get(change::pointer cp, const wstring_list &) { return nstring::format("%ld", cp->number_get_mzd()); } static nstring change_attribute_get(change::pointer cp, const wstring_list &arg) { assert(arg.size() >= 3); nstring name = arg[2].to_nstring(); nstring value(change_attributes_find(cp, name.get_ref())); return value; } static nstring get_brief_description(change::pointer cp, const wstring_list &) { // // We don't actually return the whole brief description, just the // first line, or the first 80 characters, whichever is shortest. // cstate_ty *cstate_data = cp->cstate_get(); nstring s(cstate_data->brief_description); size_t len = 0; for (; len < s.size() && len < 80; ++len) if (s[len] == '\n') break; return s.substr(0, len); } static nstring get_delta(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_awaiting_development: case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: case cstate_state_awaiting_integration: return ""; case cstate_state_being_integrated: case cstate_state_completed: break; } return nstring::format("%ld", cstate_data->delta_number); } static nstring get_delta_uuid(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_being_integrated: case cstate_state_completed: return nstring(cstate_data->delta_uuid); case cstate_state_awaiting_development: case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: case cstate_state_awaiting_integration: break; } return ""; } static nstring get_development_directory(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_awaiting_development: case cstate_state_completed: return ""; case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: case cstate_state_awaiting_integration: case cstate_state_being_integrated: break; } return nstring(cp->development_directory_get(0)); } static nstring get_developer(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_awaiting_development: return ""; case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: case cstate_state_awaiting_integration: case cstate_state_being_integrated: case cstate_state_completed: break; } return nstring(cp->developer_name()); } static nstring get_integration_directory(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); if (cstate_data->state != cstate_state_being_integrated) return ""; return nstring(cp->integration_directory_get(0)); } static nstring calc_date_string(time_t when, const wstring_list &arg) { nstring fmt = arg.unsplit(2, arg.size()).to_nstring(); struct tm *the_time = localtime(&when); // // The strftime is locale dependent. // language_human(); char buf[1000]; strftime(buf, sizeof(buf), fmt.c_str(), the_time); language_C(); return nstring(buf); } static nstring get_integrate_pass_date(change::pointer cp, const wstring_list &arg) { cstate_ty *cstate_data = cp->cstate_get(); if (cstate_data->state != cstate_state_completed) return ""; time_t when = cp->completion_timestamp(); return calc_date_string(when, arg); } static nstring get_integrator(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_awaiting_development: case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: case cstate_state_awaiting_integration: return ""; case cstate_state_being_integrated: case cstate_state_completed: break; } return nstring(cp->integrator_name()); } static nstring get_reviewer(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data; cstate_data = cp->cstate_get(); switch (cstate_data->state) { case cstate_state_awaiting_development: case cstate_state_being_developed: case cstate_state_awaiting_review: case cstate_state_being_reviewed: return ""; case cstate_state_awaiting_integration: case cstate_state_being_integrated: case cstate_state_completed: break; } return nstring(cp->reviewer_name()); } static nstring get_state(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); return nstring(cstate_state_ename(cstate_data->state)); } static nstring get_cause(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); return nstring(change_cause_ename(cstate_data->cause)); } static nstring get_uuid(change::pointer cp, const wstring_list &) { cstate_ty *cstate_data = cp->cstate_get(); return nstring(cstate_data->uuid); } static nstring get_version(change::pointer cp, const wstring_list &) { return cp->version_get(); } static nstring get_debian_version(change::pointer cp, const wstring_list &) { return cp->version_debian_get(); } static nstring get_rpm_version(change::pointer cp, const wstring_list &) { return cp->version_rpm_get(); } static nstring get_cstate_file(change::pointer cp, const wstring_list &) { return cp->cstate_filename_get(); } static nstring get_fstate_path(change::pointer cp, const wstring_list &) { nstring_list path; while (cp) { nstring filename = cp->fstate_filename_get(); // If an ancestor branch does not yet have an fstate-file; // omit // it from the list, it will only upset the DMT. os_become_orig(); if (os_exists(filename)) path.push_back(filename); os_become_undo(); if (cp->is_trunk()) break; cp = cp->project_get()->change_get(); } return path.unsplit(":"); } static table_ty table[] = { { "attribute", change_attribute_get, 1 }, { "brief_description", get_brief_description, 0 }, { "cause", get_cause, 0 }, { "cstate-file", get_cstate_file, 0 }, { "completion_date", get_integrate_pass_date, ONE_OR_MORE }, { "cstate-file", get_cstate_file, 0 }, { "date", get_integrate_pass_date, ONE_OR_MORE }, { "debian-version", get_debian_version, 0 }, { "delta", get_delta, 0 }, { "delta_uuid", get_delta_uuid, 0 }, { "description", get_brief_description, 0 }, { "developer", get_developer, 0 }, { "development_directory", get_development_directory, 0 }, { "fstate-path", get_fstate_path, 0 }, { "integrate_pass_date", get_integrate_pass_date, ONE_OR_MORE }, { "integration_directory", get_integration_directory, 0 }, { "integrator", get_integrator, 0 }, { "number", change_number_get, 0 }, { "reviewer", get_reviewer, 0 }, { "rpm-version", get_rpm_version, 0 }, { "state", get_state, 0 }, { "uuid", get_uuid, 0 }, { "version", get_version, 0 }, }; static symtab_ty *stp; static table_ty * find_func(const nstring &name) { if (!stp) { stp = new symtab_ty(SIZEOF(table)); for (table_ty *tp = table; tp < ENDOF(table); ++tp) { nstring s(tp->name); stp->assign(s, tp); } } table_ty *result = (table_ty *)stp->query(name); if (!result) { nstring s(stp->query_fuzzy(name.downcase())); if (!s.empty()) { sub_context_ty sc; sc.var_set_string("Name", name); sc.var_set_string("Guess", s); sc.error_intl(i18n("no \"$name\", guessing \"$guess\"")); result = (table_ty *)stp->query(s); assert(result); } } return result; } static const char * requires_at_least_n_arguments(int n) { switch (n) { case 1: return i18n("requires at least one argument"); case 2: return i18n("requires two or more arguments"); } return i18n("invalid function arguments"); } static const char * requires_exactly_n_arguments(int n) { switch (n) { case 0: return i18n("requires zero arguments"); case 1: return i18n("requires one argument"); case 2: return i18n("requires two arguments"); case 3: return i18n("requires three arguments"); } return i18n("invalid function arguments"); } // // NAME // sub_change - the change substitution // // SYNOPSIS // wstring_ty *sub_change(wstring_list_ty *arg); // // DESCRIPTION // The sub_change function implements the change substitution. // The change substitution is replaced by the change number. // // ARGUMENTS // arg - list of arguments, including the function name as [0] // // RETURNS // a pointer to a string in dynamic memory; // or NULL on error, setting suberr appropriately. // wstring sub_change_number(sub_context_ty *scp, const wstring_list &arg) { trace(("sub_change()\n{\n")); change::pointer cp = sub_context_change_get(scp); wstring result; if (!cp || cp->is_bogus()) { scp->error_set(i18n("not valid in current context")); trace(("}\n")); return result; } if (arg.size() <= 1) { nstring s(change_number_get(cp, arg)); result = wstring(s); trace(("return %p;\n", result.get_ref())); trace(("}\n")); return result; } nstring s = arg[1].to_nstring(); table_ty *tp = find_func(s); if (!tp) { scp->error_set(i18n("unknown substitution variant")); trace(("}\n")); return result; } int num_args = tp->num_args; bool at_least = false; if (num_args < 0) { num_args = -num_args; at_least = true; } if (at_least && (arg.size() < (size_t)num_args + 2)) { scp->error_set(requires_at_least_n_arguments(num_args)); trace(("}\n")); return result; } else if (!at_least && (arg.size() != (size_t)num_args + 2)) { scp->error_set(requires_exactly_n_arguments(num_args)); trace(("}\n")); return result; } s = tp->func(cp, arg); if (s.empty()) { scp->error_set(i18n("not valid in current context")); trace(("}\n")); return result; } result = wstring(s); trace(("return %p;\n", result.get_ref())); trace(("}\n")); return result; } // vim: set ts=8 sw=4 et :