LCOV - code coverage report
Current view: top level - src/tools/kdb/gen/highlevel - highlevel.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 246 280 87.9 %
Date: 2019-09-12 12:28:41 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "highlevel.hpp"
      10             : 
      11             : #include "common.hpp"
      12             : #include "enums.hpp"
      13             : #include "structs.hpp"
      14             : 
      15             : #include <command.hpp>
      16             : #include <modules.hpp>
      17             : 
      18             : #include <kdb.h>
      19             : #include <kdbease.h>
      20             : #include <kdbhelper.h>
      21             : #include <kdbplugin.h>
      22             : #include <kdbtypes.h>
      23             : 
      24             : #include <fstream>
      25             : #include <memory>
      26             : #include <regex>
      27             : #include <set>
      28             : #include <streambuf>
      29             : #include <string>
      30             : 
      31             : const char * HighlevelGenTemplate::Params::InitFunctionName = "initFn";
      32             : const char * HighlevelGenTemplate::Params::HelpFunctionName = "helpFn";
      33             : const char * HighlevelGenTemplate::Params::SpecloadFunctionName = "specloadFn";
      34             : const char * HighlevelGenTemplate::Params::TagPrefix = "tagPrefix";
      35             : const char * HighlevelGenTemplate::Params::EnumConversion = "enumConv";
      36             : const char * HighlevelGenTemplate::Params::AdditionalHeaders = "headers";
      37             : const char * HighlevelGenTemplate::Params::GenerateSetters = "genSetters";
      38             : const char * HighlevelGenTemplate::Params::EmbeddedSpec = "embeddedSpec";
      39             : const char * HighlevelGenTemplate::Params::SpecValidation = "specValidation";
      40             : const char * HighlevelGenTemplate::Params::InstallPrefix = "installPrefix";
      41             : 
      42             : enum class EmbeddedSpec
      43             : {
      44             :         Full,
      45             :         Defaults,
      46             :         None
      47             : };
      48             : 
      49             : enum class SpecValidation
      50             : {
      51             :         None,
      52             :         Minimal,
      53             :         Full // TODO: implement?
      54             : };
      55             : 
      56          27 : static std::string createIncludeGuard (const std::string & fileName)
      57             : {
      58          27 :         std::string result;
      59          54 :         result.resize (fileName.length ());
      60         108 :         std::transform (fileName.begin (), fileName.end (), result.begin (), ::toupper);
      61          27 :         escapeNonAlphaNum (result);
      62          27 :         return result;
      63             : }
      64             : 
      65          24 : static inline std::string getArgName (const kdb::Key & key, kdb_long_long_t index, const std::string & defaultPrefix)
      66             : {
      67          48 :         auto indexStr = std::to_string (index);
      68         168 :         auto metaName = "gen/arg/name/#" + std::string (indexStr.length () - 1, '_') + indexStr;
      69          48 :         return key.hasMeta (metaName) ? key.getMeta<std::string> (metaName) : defaultPrefix + indexStr;
      70             : }
      71             : 
      72          24 : static inline std::string getArgDescription (const kdb::Key & key, kdb_long_long_t index, const std::string & kind)
      73             : {
      74          48 :         auto indexStr = std::to_string (index);
      75         168 :         auto metaName = "gen/arg/description/#" + std::string (indexStr.length () - 1, '_') + indexStr;
      76          24 :         return key.hasMeta (metaName) ? key.getMeta<std::string> (metaName) :
      77         120 :                                         "Replaces occurence no. " + indexStr + " of " + kind + " in the keyname.";
      78             : }
      79             : 
      80          85 : static void getKeyArgs (const kdb::Key & key, const size_t parentKeyParts, kainjow::mustache::list & args, std::string & fmtString)
      81             : {
      82             :         using namespace kainjow::mustache;
      83         170 :         auto parts = getKeyParts (key);
      84         595 :         parts.erase (parts.begin (), parts.begin () + parentKeyParts);
      85             : 
      86         170 :         std::stringstream fmt;
      87             : 
      88          85 :         size_t pos = 1;
      89          85 :         size_t names = 1;
      90          85 :         size_t indices = 1;
      91         467 :         for (const auto & part : parts)
      92             :         {
      93         127 :                 if (part == "_")
      94             :                 {
      95          50 :                         const std::string & argName = getArgName (key, names, "name");
      96             :                         auto arg = object{ { "native_type", "const char *" },
      97             :                                            { "name", argName },
      98             :                                            { "code", argName },
      99             :                                            { "index?", false },
     100          90 :                                            { "description", getArgDescription (key, names, "_") } };
     101          20 :                         args.push_back (arg);
     102          10 :                         fmt << "%s/";
     103          10 :                         ++pos;
     104          10 :                         ++names;
     105             :                 }
     106         117 :                 else if (part == "#")
     107             :                 {
     108          70 :                         const std::string & argName = getArgName (key, indices, "index");
     109             : 
     110          42 :                         std::string argCode = "elektra_len (" + argName + "), elektra_len (";
     111          42 :                         argCode += argName + "), \"#___________________\", (long long) ";
     112          14 :                         argCode += argName;
     113             : 
     114             :                         auto arg = object{ { "native_type", "kdb_long_long_t" },
     115             :                                            { "name", argName },
     116             :                                            { "code", argCode },
     117             :                                            { "index?", true },
     118         126 :                                            { "description", getArgDescription (key, indices, "#") } };
     119          28 :                         args.push_back (arg);
     120          14 :                         fmt << "%*.*s%lld/";
     121          14 :                         pos += 4;
     122          14 :                         ++indices;
     123             :                 }
     124             :                 else
     125             :                 {
     126             :                         // escape backslashes first too avoid collision
     127         309 :                         fmt << std::regex_replace (part, std::regex ("[\\\\/]"), "\\\\$0") << "/";
     128             :                 }
     129             :         }
     130             : 
     131          85 :         if (!args.empty ())
     132             :         {
     133         132 :                 args.back ()["last?"] = true;
     134             :         }
     135             : 
     136         170 :         if (args.size () > 1)
     137             :         {
     138          14 :                 args[args.size () - 2]["last_but_one?"] = true;
     139             :         }
     140             : 
     141         170 :         fmtString = fmt.str ();
     142          85 :         fmtString.pop_back ();
     143          85 : }
     144             : 
     145          54 : static std::string keySetToCCode (kdb::KeySet & set)
     146             : {
     147             :         using namespace kdb;
     148             :         using namespace kdb::tools;
     149             : 
     150         108 :         Modules modules;
     151         324 :         PluginPtr plugin = modules.load ("c", KeySet ());
     152             : 
     153         216 :         auto file = "/tmp/elektra.highlevelgen." + std::to_string (std::time (nullptr));
     154         108 :         Key errorKey ("", KEY_VALUE, file.c_str (), KEY_END);
     155          54 :         if (plugin->set (set, errorKey) == ELEKTRA_PLUGIN_STATUS_ERROR)
     156             :         {
     157           0 :                 throw CommandAbortException ("c (plugin) failed");
     158             :         }
     159             : 
     160         108 :         std::ifstream is (file);
     161         108 :         std::string line;
     162             : 
     163         108 :         std::stringstream ss;
     164         744 :         while (std::getline (is, line))
     165             :         {
     166         318 :                 ss << line << std::endl;
     167             :         }
     168             : 
     169         108 :         return ss.str ();
     170             : }
     171             : 
     172           2 : static void keySetToQuickdump (kdb::KeySet & set, const std::string & path, const std::string & parent)
     173             : {
     174             :         using namespace kdb;
     175             :         using namespace kdb::tools;
     176             : 
     177           4 :         Modules modules;
     178           4 :         KeySet config;
     179           6 :         config.append (Key ("system/noparent", KEY_END));
     180          10 :         PluginPtr plugin = modules.load ("quickdump", config);
     181             : 
     182           6 :         Key parentKey (parent.c_str (), KEY_VALUE, path.c_str (), KEY_END);
     183           2 :         if (plugin->set (set, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR)
     184             :         {
     185           0 :                 throw CommandAbortException ("quickdump failed");
     186             :         }
     187           2 : }
     188             : 
     189          27 : static kdb::KeySet cascadingToSpec (const kdb::KeySet & ks)
     190             : {
     191          27 :         auto result = kdb::KeySet (ks.size (), KS_END);
     192         617 :         for (auto it = ks.begin (); it != ks.end (); ++it)
     193             :         {
     194         804 :                 if (it->isCascading ())
     195             :                 {
     196         550 :                         auto specKey = kdb::Key (it->dup ());
     197         330 :                         specKey.setName ("spec" + specKey.getName ());
     198         110 :                         result.append (specKey);
     199             :                 }
     200         804 :                 if (it->isSpec ())
     201             :                 {
     202         474 :                         result.append (*it);
     203             :                 }
     204             :         }
     205          27 :         return result;
     206             : }
     207             : 
     208          27 : kainjow::mustache::data HighlevelGenTemplate::getTemplateData (const std::string & outputName, const std::string & part,
     209             :                                                                const kdb::KeySet & keySet, const std::string & parentKey) const
     210             : {
     211             :         using namespace kainjow::mustache;
     212             : 
     213          54 :         auto headerFile = outputName + ".h";
     214          54 :         auto includeGuard = createIncludeGuard (headerFile);
     215         216 :         auto initFunctionName = getParameter (Params::InitFunctionName, "loadConfiguration");
     216         216 :         auto helpFunctionName = getParameter (Params::HelpFunctionName, "printHelpMessage");
     217         216 :         auto specloadFunctionName = getParameter (Params::SpecloadFunctionName, "exitForSpecload");
     218         216 :         auto tagPrefix = getParameter (Params::TagPrefix, "ELEKTRA_TAG_");
     219         216 :         auto installPrefix = getParameter (Params::InstallPrefix, "/usr/local");
     220         243 :         auto additionalHeaders = split (getParameter (Params::AdditionalHeaders), ',');
     221         216 :         auto enumConversionString = getParameter (Params::EnumConversion, "auto");
     222         108 :         auto generateSetters = getBoolParameter (Params::GenerateSetters, true);
     223         351 :         auto specHandling = getParameter<EmbeddedSpec> (Params::EmbeddedSpec, { { "", EmbeddedSpec::Full },
     224             :                                                                                 { "full", EmbeddedSpec::Full },
     225             :                                                                                 { "defaults", EmbeddedSpec::Defaults },
     226          27 :                                                                                 { "none", EmbeddedSpec::None } });
     227         324 :         auto specValidation = getParameter<SpecValidation> (
     228             :                 Params::SpecValidation,
     229          27 :                 { { "", SpecValidation::None }, { "none", SpecValidation::None }, { "minimal", SpecValidation::Minimal } });
     230             : 
     231         351 :         auto enumConversion = getParameter<EnumConversion> (Params::EnumConversion, { { "", EnumConversion::Auto },
     232             :                                                                                       { "auto", EnumConversion::Auto },
     233             :                                                                                       { "switch", EnumConversion::Trie },
     234          27 :                                                                                       { "strcmp", EnumConversion::Strcmp } });
     235             : 
     236             : 
     237          54 :         std::string cascadingParent;
     238          54 :         std::string specParentName;
     239          54 :         kdb::KeySet ks;
     240             : 
     241          27 :         if (parentKey[0] == '/')
     242             :         {
     243          27 :                 cascadingParent = parentKey;
     244          54 :                 specParentName = "spec" + parentKey;
     245          81 :                 ks = cascadingToSpec (keySet);
     246             :         }
     247           0 :         else if (parentKey.substr (0, 5) == "spec/")
     248             :         {
     249           0 :                 cascadingParent = parentKey.substr (4);
     250           0 :                 specParentName = parentKey;
     251           0 :                 ks = keySet;
     252             :         }
     253             :         else
     254             :         {
     255           0 :                 throw CommandAbortException ("parentKey has to start with spec/ or /");
     256             :         }
     257             : 
     258             :         auto data = object{ { "header_file", headerFile },
     259             :                             { "include_guard", includeGuard },
     260             :                             { "spec_parent_key", specParentName },
     261             :                             { "parent_key", cascadingParent },
     262             :                             { "init_function_name", initFunctionName },
     263             :                             { "help_function_name", helpFunctionName },
     264             :                             { "specload_function_name", specloadFunctionName },
     265             :                             { "generate_setters?", generateSetters },
     266          54 :                             { "embed_spec?", specHandling == EmbeddedSpec::Full },
     267          27 :                             { "embed_defaults?", specHandling == EmbeddedSpec::Defaults },
     268          27 :                             { "spec_as_defaults?", specHandling == EmbeddedSpec::Full },
     269         351 :                             { "more_headers", list (additionalHeaders.begin (), additionalHeaders.end ()) } };
     270             : 
     271          54 :         list enums;
     272          54 :         list structs;
     273          54 :         list keys;
     274          54 :         list unions;
     275             : 
     276          81 :         auto specParent = kdb::Key (specParentName, KEY_END);
     277             : 
     278          54 :         EnumProcessor enumProcessor (enumConversion);
     279          54 :         StructProcessor structProcessor (specParent, ks);
     280             : 
     281          27 :         auto parentLength = specParentName.length ();
     282             : 
     283          54 :         kdb::KeySet spec;
     284          54 :         kdb::KeySet defaults;
     285             : 
     286         135 :         kdb::Key parent = ks.lookup (specParent).dup ();
     287         108 :         parent.setName ("");
     288          27 :         spec.append (parent);
     289             : 
     290          54 :         auto parentKeyParts = getKeyParts (specParent);
     291             : 
     292         135 :         auto mountpoint = parent.getMeta<std::string> ("mountpoint");
     293             : 
     294          54 :         std::regex appNameRegex ("/sw/[^/]+/[^/]+/#0/current");
     295          54 :         std::string appName;
     296          54 :         std::string appNameWithOrg;
     297          27 :         if (std::regex_match (cascadingParent, appNameRegex))
     298             :         {
     299           0 :                 appName = parentKeyParts[3];
     300           0 :                 escapeNonAlphaNum (appName);
     301           0 :                 std::string orgName = parentKeyParts[2];
     302           0 :                 escapeNonAlphaNum (orgName);
     303           0 :                 appNameWithOrg = orgName + "/" + appName;
     304             :         }
     305             :         else
     306             :         {
     307          54 :                 appName = cascadingParent.substr (1);
     308          27 :                 escapeNonAlphaNum (appName);
     309             :                 appNameWithOrg = appName;
     310             :         }
     311             : 
     312          27 :         if (part == ".mount.sh")
     313             :         {
     314         112 :                 return object{ { "parent_key", cascadingParent },
     315             :                                { "spec_parent_key", specParentName },
     316          16 :                                { "mount_file", appName + ".overlay.spec.eqd" },
     317             :                                { "spec_mount_file", mountpoint },
     318          16 :                                { "direct_file?", specHandling != EmbeddedSpec::Full },
     319             :                                { "org_and_app", appNameWithOrg },
     320          64 :                                { "app", appName } };
     321             :         }
     322             : 
     323         275 :         for (auto it = ks.begin (); it != ks.end (); ++it)
     324             :         {
     325         195 :                 kdb::Key key = *it;
     326             : 
     327         220 :                 if (!key.isSpec () || !key.isBelow (specParent))
     328             :                 {
     329          25 :                         continue;
     330             :                 }
     331             : 
     332         267 :                 kdb::Key specKey = key.dup ();
     333         273 :                 specKey.setName (specKey.getName ().substr (parentLength));
     334          91 :                 spec.append (specKey);
     335             : 
     336          91 :                 if (!hasType (key))
     337             :                 {
     338             :                         continue;
     339             :                 }
     340             : 
     341         170 :                 auto type = getType (key);
     342         170 :                 auto name = key.getName ();
     343          85 :                 name.erase (0, sizeof ("spec") - 1);
     344             : 
     345         170 :                 std::string fmtString;
     346         170 :                 list args;
     347         170 :                 getKeyArgs (key, parentKeyParts.size (), args, fmtString);
     348             : 
     349         342 :                 if (!key.hasMeta ("default") && !key.hasMeta ("require"))
     350             :                 {
     351           3 :                         throw CommandAbortException ("The key '" + name +
     352           3 :                                                      "' doesn't have a default value and is not marked with 'require'!");
     353             :                 }
     354             : 
     355         336 :                 kdb::Key defaultsKey (key.getName ().substr (parentLength), KEY_END);
     356         672 :                 defaultsKey.setMeta ("default", key.getMeta<std::string> ("default"));
     357         672 :                 defaultsKey.setMeta ("type", key.getMeta<std::string> ("type"));
     358          84 :                 defaults.append (defaultsKey);
     359             : 
     360             :                 std::unordered_set<std::string> allowedTypes = { "enum",
     361             :                                                                  "string",
     362             :                                                                  "boolean",
     363             :                                                                  "char",
     364             :                                                                  "octet",
     365             :                                                                  "short",
     366             :                                                                  "unsigned_short",
     367             :                                                                  "long",
     368             :                                                                  "unsigned_long",
     369             :                                                                  "long_long",
     370             :                                                                  "unsigned_long_long",
     371             :                                                                  "float",
     372             :                                                                  "double",
     373             :                                                                  "long_double",
     374             :                                                                  "struct",
     375             :                                                                  "struct_ref",
     376        3360 :                                                                  "discriminator" };
     377             : 
     378         252 :                 if (allowedTypes.find (type) == allowedTypes.end ())
     379             :                 {
     380           0 :                         auto msg = "The key '" + name;
     381           0 :                         msg += "' has an unsupported type ('" + type + "')!";
     382           0 :                         throw CommandAbortException (msg);
     383             :                 }
     384             : 
     385          84 :                 if (type == "discriminator")
     386             :                 {
     387           0 :                         type = "enum";
     388           0 :                         specKey.setMeta ("type", "enum");
     389             :                 }
     390             : 
     391          84 :                 bool isString = type == "string";
     392         252 :                 auto nativeType = isString ? "const char *" : "kdb_" + type + "_t";
     393         168 :                 auto typeName = snakeCaseToPascalCase (type);
     394             : 
     395         168 :                 auto tagName = getTagName (key, specParentName);
     396             : 
     397         252 :                 auto isArray = key.getBaseName () == "#";
     398             : 
     399         168 :                 object keyObject = { { "name", name.substr (cascadingParent.size () + 1) }, // + 2 to remove slash
     400             :                                      { "native_type", nativeType },
     401         252 :                                      { "macro_name", tagPrefix + snakeCaseToMacroCase (tagName) },
     402         168 :                                      { "tag_name", snakeCaseToPascalCase (tagName) },
     403             :                                      { "type_name", typeName },
     404             :                                      { "is_string?", isString },
     405         840 :                                      { "is_array?", isArray } };
     406             : 
     407          84 :                 if (!args.empty ())
     408             :                 {
     409         198 :                         keyObject["args?"] = object{ { "args", args } };
     410         110 :                         keyObject["args"] = args;
     411         110 :                         keyObject["fmt_string"] = fmtString;
     412             :                 }
     413             : 
     414          84 :                 if (isArray)
     415             :                 {
     416          28 :                         if (args.size () > 1)
     417             :                         {
     418             :                                 // remove last argument and last part of format string
     419          12 :                                 auto arrayArgs = list{ args.begin (), args.end () - 1 };
     420          12 :                                 arrayArgs.back ()["last?"] = true;
     421             : 
     422          10 :                                 keyObject["array_args?"] =
     423          14 :                                         object ({ { "args", arrayArgs }, { "fmt_string", fmtString.substr (0, fmtString.rfind ('/')) } });
     424             :                         }
     425             :                         // remove last part ('/#') from name
     426          84 :                         keyObject["array_name"] = name.substr (cascadingParent.size () + 1, name.size () - cascadingParent.size () - 3);
     427             :                 }
     428             : 
     429          84 :                 if (type == "enum")
     430             :                 {
     431          20 :                         auto enumData = enumProcessor.process (key, tagName);
     432             : 
     433         100 :                         keyObject["type_name"] = enumData["type_name"].string_value ();
     434         100 :                         keyObject["native_type"] = enumData["native_type"].string_value ();
     435             : 
     436          50 :                         if (enumData["new"].is_true ())
     437             :                         {
     438           8 :                                 enums.emplace_back (enumData);
     439             :                         }
     440             :                 }
     441          74 :                 else if (type == "struct_ref")
     442             :                 {
     443             :                         bool allocate;
     444           8 :                         std::string dummyString;
     445             : 
     446             :                         bool processed;
     447           4 :                         if (isArray)
     448             :                         {
     449             :                                 processed = StructFieldsProcessor::processArrayStructRef (key, specParent, ks, typeName, nativeType,
     450           4 :                                                                                           allocate, dummyString);
     451             :                         }
     452             :                         else
     453             :                         {
     454             :                                 processed = StructFieldsProcessor::processStructRef (key, specParent, ks, typeName, nativeType, allocate,
     455           0 :                                                                                      dummyString);
     456             :                         }
     457             : 
     458           4 :                         if (processed)
     459             :                         {
     460          20 :                                 keyObject["type_name"] = typeName;
     461          20 :                                 keyObject["native_type"] = nativeType;
     462          20 :                                 keyObject["is_struct_ref?"] = true;
     463          24 :                                 keyObject["alloc?"] = allocate;
     464          20 :                                 keyObject["generate_setters?"] = false;
     465             :                         }
     466             :                         else
     467             :                         {
     468           0 :                                 continue;
     469             :                         }
     470             :                 }
     471          70 :                 else if (type == "struct")
     472             :                 {
     473          28 :                         auto maxDepth = key.hasMeta ("gen/struct/depth") ? key.getMeta<kdb::short_t> ("gen/struct/depth") : 1;
     474          12 :                         auto baseDepth = getKeyParts (key).size ();
     475             : 
     476          12 :                         kdb::KeySet subkeys;
     477          60 :                         for (auto cur = it + 1; cur != ks.end (); ++cur)
     478             :                         {
     479          66 :                                 if (cur->isBelow (key))
     480             :                                 {
     481          36 :                                         if (StructProcessor::isFieldIgnored (*cur))
     482             :                                         {
     483           0 :                                                 continue;
     484             :                                         }
     485             : 
     486          54 :                                         auto parts = getKeyParts (*cur);
     487          36 :                                         if (parts.size () <= baseDepth + maxDepth)
     488             :                                         {
     489         112 :                                                 if (std::any_of (parts.begin () + baseDepth, parts.end () - 1,
     490          70 :                                                                  [](const std::string & s) { return s == "_" || s == "#"; }) ||
     491          32 :                                                     parts.back () == "_")
     492             :                                                 {
     493           0 :                                                         throw CommandAbortException ("struct cannot contain globbed keys (_, #).");
     494             :                                                 }
     495             : 
     496          48 :                                                 subkeys.append (*cur);
     497             :                                         }
     498           6 :                                         else if (parts.size () <= baseDepth + maxDepth + 1 && parts.back () == "#")
     499             :                                         {
     500           6 :                                                 subkeys.append (*cur);
     501             :                                         }
     502             :                                 }
     503             :                                 else
     504             :                                 {
     505             :                                         break;
     506             :                                 }
     507             :                         }
     508             : 
     509          12 :                         kainjow::mustache::list structUnions;
     510          12 :                         auto structData = structProcessor.process (key, subkeys, tagName, specParentName, structUnions);
     511             : 
     512          24 :                         for (const auto & u : structUnions)
     513             :                         {
     514           0 :                                 unions.push_back (u);
     515             :                         }
     516             : 
     517          60 :                         keyObject["type_name"] = structData["type_name"].string_value ();
     518          60 :                         keyObject["native_type"] = structData["native_type"].string_value ();
     519          30 :                         keyObject["is_struct?"] = true;
     520          60 :                         keyObject["alloc?"] = structData["alloc?"].is_true ();
     521          60 :                         keyObject["generate_setters?"] = structData["generate_setters?"].is_true ();
     522             : 
     523          30 :                         if (structData["new"].is_true ())
     524             :                         {
     525           6 :                                 structs.emplace_back (structData);
     526             :                         }
     527             :                 }
     528             : 
     529          84 :                 keys.emplace_back (keyObject);
     530             :         }
     531             : 
     532          18 :         kdb::KeySet contract;
     533          54 :         contract.append (kdb::Key ("system/elektra/ensure/plugins/global/gopts", KEY_VALUE, "mounted", KEY_END));
     534             : 
     535          18 :         if (specValidation == SpecValidation::Minimal)
     536             :         {
     537           0 :                 contract.append (kdb::Key ("system/elektra/highlevel/validation", KEY_VALUE, "minimal", KEY_END));
     538             :         }
     539             : 
     540         144 :         data["keys_count"] = std::to_string (keys.size ());
     541          90 :         data["keys"] = keys;
     542          90 :         data["enums"] = enums;
     543          90 :         data["unions"] = unions;
     544          90 :         data["structs"] = structs;
     545         108 :         data["spec"] = keySetToCCode (spec);
     546         108 :         data["defaults"] = keySetToCCode (defaults);
     547         108 :         data["contract"] = keySetToCCode (contract);
     548          90 :         data["specload_arg"] = "--elektra-spec";
     549             : 
     550          18 :         if (part == ".spec.eqd")
     551             :         {
     552           4 :                 keySetToQuickdump (spec, outputName + part, specParentName);
     553             :                 return kainjow::mustache::data (false);
     554             :         }
     555             : 
     556          16 :         return data;
     557             : }
     558             : 
     559         162 : std::string HighlevelGenTemplate::escapeFunction (const std::string & str) const
     560             : {
     561         324 :         std::stringstream ss;
     562        2426 :         for (const auto & c : str)
     563             :         {
     564        1778 :                 switch (c)
     565             :                 {
     566             :                 case '\a':
     567           0 :                         ss << "\\a";
     568             :                         break;
     569             :                 case '\b':
     570           0 :                         ss << "\\b";
     571             :                         break;
     572             :                 case '\f':
     573           0 :                         ss << "\\f";
     574             :                         break;
     575             :                 case '\n':
     576           0 :                         ss << "\\n";
     577             :                         break;
     578             :                 case '\r':
     579           0 :                         ss << "\\r";
     580             :                         break;
     581             :                 case '\t':
     582           0 :                         ss << "\\t";
     583             :                         break;
     584             :                 case '\v':
     585           0 :                         ss << "\\v";
     586             :                         break;
     587             :                 case '\\':
     588           0 :                         ss << "\\\\";
     589             :                         break;
     590             :                 case '\'':
     591           0 :                         ss << "\\'";
     592             :                         break;
     593             :                 case '"':
     594           0 :                         ss << "\\\"";
     595             :                         break;
     596             :                 default:
     597        1778 :                         if (isprint (c))
     598             :                         {
     599        1778 :                                 ss << c;
     600             :                         }
     601             :                         else
     602             :                         {
     603           0 :                                 ss << "\\x" << std::hex << std::setw (2) << static_cast<unsigned char> (c);
     604             :                         }
     605             :                 }
     606             :         }
     607             : 
     608         324 :         return ss.str ();
     609             : }
     610             : 
     611           9 : std::vector<std::string> HighlevelGenTemplate::getActualParts () const
     612             : {
     613           9 :         std::vector<std::string> parts (GenTemplate::getActualParts ());
     614          81 :         if (getParameter (Params::EmbeddedSpec, "full") == "full")
     615             :         {
     616          49 :                 parts.erase (std::remove (parts.begin (), parts.end (), ".spec.eqd"), parts.end ());
     617             :         }
     618           9 :         return parts;
     619        7164 : }

Generated by: LCOV version 1.13