8#define IDEBUG(...)     Ase::debug ("inifile", __VA_ARGS__) 
   10#define ISASCIINLSPACE(c)    (c == ' ' || (c >= 9 && c <= 13))                   
   11#define ISASCIIWHITESPACE(c) (c == ' ' || c == '\t' || (c >= 11 && c <= 13))     
   42parse_whitespaces (
const char **stringp, 
int min_spaces)
 
   44  const char *p = *stringp;
 
   45  while (ISASCIIWHITESPACE (*p))
 
   47  if (p - *stringp >= min_spaces)
 
   56skip_whitespaces (
const char **stringp)
 
   58  return parse_whitespaces (stringp, 0);
 
   62scan_escaped (
const char **stringp, 
size_t *linenop, 
const char term)
 
   64  const char *p = *stringp;
 
   65  size_t lineno = *linenop;
 
   74    else if (p[0] == 
'\\' && p[1])
 
   88  const char *s = str.
data();
 
   89  const char *e = s + str.size();
 
   90  while (e > s && ISASCIINLSPACE (e[-1]))
 
   92  const size_t l = e - s;
 
   93  str.erase (str.begin() + l, str.end());
 
   94  return String (str.data(), str.size()); 
 
   98scan_value (
const char **stringp, 
size_t *linenop, 
String *valuep, 
const char *termchars = 
"")
 
  100  const char *p = *stringp;
 
  101  size_t lineno = *linenop;
 
  109        if (p[1] == 
'\n' || (p[1] == 
'\r' && p[2] == 
'\n'))
 
  111            p += 1 + (p[1] == 
'\r');
 
  118        v += 
String (
"\\") + p[0];
 
  123        if (scan_escaped (&p, &lineno, d[0]))
 
  132        if (p[1] && p[1] != 
'\n')
 
  136        if (!strchr (termchars, p[0]))
 
  142      case 0: 
case '\n': 
case ';': 
case '#':
 
  145        *valuep = string_rtrim (v); 
 
  151skip_line (
const char **stringp, 
size_t *linenop, 
String *textp)
 
  153  const char *p = *stringp, *
const start = p;
 
  154  size_t lineno = *linenop;
 
  155  while (*p && *p != 
'\n')
 
  158    *textp = 
String (start, p - start);
 
  170skip_commentline (
const char **stringp, 
size_t *linenop, 
String *commentp = NULL)
 
  172  const char *p = *stringp;
 
  173  skip_whitespaces (&p);
 
  174  if (*p != 
'#' && *p != 
';')
 
  178  return skip_line (stringp, linenop, commentp);
 
  182skip_to_eol (
const char **stringp, 
size_t *linenop)
 
  184  const char *p = *stringp;
 
  185  if (*p == 
'#' || *p == 
';')
 
  186    return skip_commentline (stringp, linenop);
 
  205parse_assignment (
const char **stringp, 
size_t *linenop, 
String *keyp, 
String *localep, 
String *valuep)
 
  207  const char *p = *stringp;
 
  208  size_t lineno = *linenop;
 
  209  String key, locale, value;
 
  211  success = success && skip_whitespaces (&p);
 
  212  success = success && scan_value (&p, &lineno, &key, 
"[]=:");
 
  213  success = success && skip_whitespaces (&p);
 
  214  if (success && *p == 
'[')
 
  217      success = success && skip_whitespaces (&p);
 
  218      success = success && scan_value (&p, &lineno, &locale, 
"[]");
 
  219      success = success && skip_whitespaces (&p);
 
  223      success = success && skip_whitespaces (&p);
 
  227  if (*p != 
'=' && *p != 
':')
 
  230  success = success && skip_whitespaces (&p);
 
  231  success = success && scan_value (&p, &lineno, &value);
 
  232  success = success && skip_to_eol (&p, &lineno);
 
  244parse_section (
const char **stringp, 
size_t *linenop, 
String *sectionp)
 
  246  const char *p = *stringp;
 
  247  size_t lineno = *linenop;
 
  250  success = success && skip_whitespaces (&p);
 
  254  success = success && skip_whitespaces (&p);
 
  255  success = success && scan_value (&p, &lineno, §ion, 
"[]");
 
  256  success = success && skip_whitespaces (&p);
 
  260  success = success && skip_whitespaces (&p);
 
  261  success = success && skip_to_eol (&p, &lineno);
 
  271IniFile::load_ini (
const String &inputname, 
const String &data)
 
  273  const char *p = 
data.c_str();
 
  278      const size_t lineno = nextno;
 
  279      String text, key, locale, *debugp = 0 ? &text : NULL; 
 
  280      if (skip_commentline (&p, &nextno, debugp))
 
  283            printerr (
"%s:%d: #%s\n", inputname.c_str(), lineno, debugp->c_str());
 
  285      else if (parse_section (&p, &nextno, &text))
 
  288            printerr (
"%s:%d: %s\n", inputname.c_str(), lineno, text.c_str());
 
  290          if (strchr (section.c_str(), 
'"'))
 
  294                if (s.c_str()[0] == 
'"')
 
  299      else if (parse_assignment (&p, &nextno, &key, &locale, &text))
 
  302            printerr (
"%s:%d:\t%s[%s] = %s\n", inputname.c_str(), lineno, key.c_str(), locale.c_str(), 
string_to_cquote (text));
 
  305            k += 
"[" + locale + 
"]";
 
  306          if (strchr (section.c_str(), 
'=') || 
strchr (key.c_str(), 
'.'))
 
  307            IDEBUG (
"%s:%d: invalid key name: %s.%s", inputname.c_str(), lineno, section.c_str(), k.c_str());
 
  309            sections_[section].push_back (k + 
"=" + text);
 
  311      else if (skip_line (&p, &nextno, debugp))
 
  314            printerr (
"%s:%d:~ %s\n", inputname.c_str(), lineno, debugp->c_str());
 
  323  load_ini (name, inidata);
 
  324  if (sections_.
empty())
 
 
  332  if (sections_.
empty())
 
 
  344  sections_  = source.sections_;
 
 
  351  return !sections_.
empty();
 
 
  355IniFile::section (
const String &name)
 const 
  357  SectionMap::const_iterator cit = sections_.
find (name);
 
  358  if (cit != sections_.
end())
 
  360  static const StringS empty_dummy;
 
  367  SectionMap::const_iterator cit = sections_.
find (section);
 
  368  return cit != sections_.
end();
 
 
  375  for (
auto it : sections_)
 
 
  384  SectionMap::const_iterator cit = sections_.
find (section);
 
  385  if (cit != sections_.
end())
 
  386    for (
auto s : cit->second)
 
  387      opts.
push_back (s.substr (0, s.find (
'=')));
 
 
  394  SectionMap::const_iterator cit = sections_.
find (section);
 
  395  if (cit == sections_.
end())
 
  397  for (
auto s : cit->second)
 
 
  407  for (
auto it : sections_)
 
  408    for (
auto s : it.second)
 
 
  421  const StringS &sv = section (secname);
 
  424  const size_t l = dotpath.
size() - (d - p); 
 
  426    if (kv.size() > l && kv[l] == 
'=' && 
memcmp (kv.data(), d, l) == 0)
 
  429          *valuep = kv.
substr (l + 1);
 
 
  448  for (
const char *p = input.
c_str(); *p; p++)
 
  456          case 'n':     v += 
'\n';      
break;
 
  457          case 'r':     v += 
'\r';      
break;
 
  458          case 't':     v += 
'\t';      
break;
 
  459          case 'b':     v += 
'\b';      
break;
 
  460          case 'f':     v += 
'\f';      
break;
 
  461          case 'v':     v += 
'\v';      
break;
 
  462          default:      v += p[1];      
break;
 
  468        if (scan_escaped (&p, &dummy, start[-1]))
 
 
  507IniWriter::find_section (
String name, 
bool create)
 
  509  for (
size_t i = 0; i < sections_.
size(); i++)
 
  510    if (sections_[i].name == name)
 
  511      return §ions_[i];
 
  514      const size_t i = sections_.
size();
 
  516      sections_[i].name = name;
 
  517      return §ions_[i];
 
  523IniWriter::find_entry (IniWriter::Section §ion, 
String name, 
bool create)
 
  525  for (
size_t i = 0; i < section.entries.size(); i++)
 
  526    if (section.entries[i].size() > name.size() &&
 
  527        section.entries[i][name.size()] == 
'=' &&
 
  528        section.entries[i].compare (0, name.size(), name) == 0)
 
  532      const size_t i = section.entries.
size();
 
  533      section.entries.push_back (name + 
"=");
 
  543  const size_t p = key.
rfind (
'.');
 
  544  if (p <= 0 || p + 1 >= key.
size())
 
  546      warning (
"%s: invalid key: %s", __func__, key);
 
  549  Section *section = find_section (key.
substr (0, p), 
true);
 
  551  const size_t idx = find_entry (*section, entry_key, 
true);
 
  552  section->entries[idx] = entry_key + 
"=" + value;
 
 
  560  for (
size_t i = 0; i < sections_.
size(); i++)
 
  561    if (!sections_[i].entries.
empty())
 
  563        String sec = sections_[i].name;
 
  565        if (d >= 0 && d < sec.
size())
 
  567        s += 
String (
"[") + sec + 
"]\n";
 
  568        for (
size_t j = 0; j < sections_[i].entries.
size(); j++)
 
  570            const String raw = sections_[i].entries[j];
 
  571            const size_t p = raw.
find (
'=');
 
 
Binary large object storage container.
 
String name()
Retrieve the Blob's filename or url.
 
String string()
Copy Blob data into a zero terminated string.
 
Class to parse INI configuration file sections and values.
 
bool has_value(const String &dotpath, String *valuep=NULL) const
Check and possibly retrieve value if present.
 
bool has_raw_value(const String &dotpath, String *valuep=NULL) const
Check and possibly retrieve raw value if present.
 
StringS attributes(const String §ion) const
List all attributes available in section.
 
bool has_attribute(const String §ion, const String &key) const
Return if section contains key.
 
IniFile & operator=(const IniFile &source)
Assignment operator.
 
bool has_sections() const
Checks if IniFile is non-empty.
 
bool has_section(const String §ion) const
Check presence of a section.
 
static String cook_string(const String &input_string)
Unquote contents of input_string
 
StringS sections() const
List all sections.
 
String raw_value(const String &dotpath) const
Retrieve raw (uncooked) value of section.attribute[locale].
 
IniFile(const String &name, const String &inidata)
Load INI file from immediate data.
 
StringS raw_values() const
List all section.attribute=value pairs.
 
String value_as_string(const String &dotpath) const
Retrieve value of section.attribute[locale].
 
void set(String key, String value)
Set (or add) a value with INI file semantics: section.key = value.
 
String output()
Generate INI file syntax for all values store in the class.
 
The Anklang C++ API namespace.
 
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
 
String string_from_cquote(const String &input)
Parse a possibly quoted C string into regular string.
 
String string_join(const String &junctor, const StringS &strvec)
 
StringS string_split(const String &string, const String &splitter, size_t maxn)
 
bool string_is_canonified(const String &string, const String &valid_chars)
Check if string_canonify() would modify string.
 
std::vector< String > StringS
Convenience alias for a std::vector<std::string>.
 
const String & string_set_ascii_alnum()
Returns a string containing all of 0-9, A-Z and a-z.
 
std::string String
Convenience alias for std::string.
 
String string_to_cquote(const String &str)
Returns a string as C string including double quotes.