/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2022 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "hunspelltrace.hxx" #include #include #include #include "affentry.hxx" #include "affixmgr.hxx" #include "csutil.hxx" void trace(const TraceCtx& context, const char* format, ...) { va_list args; va_start(args, format); va_list measure; va_copy(measure, args); int len = vsnprintf(nullptr, 0, format, measure); va_end(measure); std::string line; if (len > 0) { // vsnprintf writes its own terminator, so make room for it and drop it // again. line.resize(len + 1); vsnprintf(&line[0], len + 1, format, args); line.pop_back(); } va_end(args); context.emit(line); } std::string trace_flag(const AffixMgr* pAMgr, unsigned short flag) { // hunspell marks the hidden capitalised form of a word with a flag of its // own, which no affix file ever writes. Give that one a name, because the // character it encodes to is not one a reader can look up if (flag == ONLYUPCASEFLAG) return "(onlyupcase)"; return pAMgr->encode_flag(flag); } std::string trace_flags(const AffixMgr* pAMgr, const unsigned short* astr, int alen) { if (!pAMgr || !astr || alen <= 0) return "(none)"; std::string result; for (int i = 0; i < alen; ++i) { if (i) result.push_back(','); result.append(trace_flag(pAMgr, astr[i])); } return result; } void trace_affix(const TraceCtx& context, const char* verb, const AffixMgr* pAMgr, const AffEntry& entry) { // the rule file wrote a condition the stripping already forces, so hunspell // dropped it. Say so, or the dot looks like the file's own text const char* redundant = (entry.opts & aeREDUNDANTCOND) != 0 ? " redundant=Y" : ""; trace(context, "%s flag=%s strip=\"%s\" add=\"%s\" cont=%s cond=\"%s\"%s at=aff:%d" " xprod=%c hdr=aff:%d", verb, trace_flag(pAMgr, entry.aflag).c_str(), entry.strip.c_str(), entry.appnd.c_str(), trace_flags(pAMgr, entry.contclass, entry.contclasslen).c_str(), entry.get_condition().c_str(), redundant, entry.line, entry.xprod, entry.headerline); } void trace_test(const TraceCtx& context, const char* name, const AffixMgr* pAMgr, unsigned short flag, const char* where, const unsigned short* astr, int alen, const char* outcome) { trace(context, "test %s flag=%s in=%s have=%s -> %s", name, trace_flag(pAMgr, flag).c_str(), where, trace_flags(pAMgr, astr, alen).c_str(), outcome); } void trace_circumfix(const TraceCtx& context, const AffixMgr* pAMgr, unsigned short flag, PfxEntry* pfx, SfxEntry* sfx, bool in_prefix, bool in_suffix) { const char* outcome; if (in_prefix && in_suffix) outcome = "pass, both halves carry the flag"; else if (!in_prefix && !in_suffix) outcome = "pass, neither affix is half of a circumfix"; else if (in_suffix) outcome = "fail, this circumfix suffix needs its prefix"; else outcome = "fail, this circumfix prefix needs its suffix"; std::string pfx_cont = pfx ? trace_flags(pAMgr, pfx->getCont(), pfx->getContLen()) : "(none)"; std::string sfx_cont = trace_flags(pAMgr, sfx->getCont(), sfx->getContLen()); trace(context, "test circumfix flag=%s pfx-cont=%s sfx-cont=%s -> %s", trace_flag(pAMgr, flag).c_str(), pfx_cont.c_str(), sfx_cont.c_str(), outcome); } void trace_form(const TraceCtx& context, const AffixMgr* pAMgr, const std::string& surface, const char* stem, PfxEntry* pfx, SfxEntry* sfx) { std::string line = "form \"" + surface + "\" = "; if (pfx) line += "pfx(" + pAMgr->encode_flag(pfx->getFlag()) + ":\"" + pfx->getKey() + "\") + "; line += '"'; line += stem; line += '"'; if (sfx) line += " + sfx(" + pAMgr->encode_flag(sfx->getFlag()) + ":\"" + sfx->getAffix() + "\")"; context.emit(line); }