Bug#260446: [libapt-pkg] No way to escape quotes in configuration files
Package: apt
Version: 0.5.26
Severity: minor
The apt configuration class can't reliably be used to store and
retrieve configuration data, because it doesn't provide any mechanism
for escaping quotation marks. In other words, storing a string like
'mail -s "the subject" foo' in a configuration file seems to be
impossible.
A simple way of solving this is to allow quotation marks to be
escaped:
Program::MailCmd "mail -s \"the subject\" foo";
*pokes around*
Apparently %-escapes are already understood by libapt, so all that's
needed is to escape outgoing quotation marks...but placing %-escapes in
a configuration file manually doesn't seem to work.aaa Ok, that only
works for tag names. Tag values are handled by ParseCWord.
I've attached a patch that does the following:
- modifies LoadConfigFile to ignore backslash-escaped metacharacters.
- modifies Dump to backslash-escape outgoing backslashes and
quotation marks.
- modifies ParseCWord to handle backslash-escapes.
It seems to work in my tests here.
Daniel
-- System Information:
Debian Release: testing/unstable
APT prefers unstable
APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.6.6
Locale: LANG=en_US, LC_CTYPE=en_US (ignored: LC_ALL set to en_US)
Versions of packages apt depends on:
ii libc6 2.3.2.ds1-13 GNU C Library: Shared libraries an
ii libgcc1 1:3.3.4-3 GCC support library
ii libstdc++5 1:3.3.4-3 The GNU Standard C++ Library v3
-- no debconf information
--- /tmp/apt-0.6.25/apt-pkg/contrib/configuration.cc 2004-05-08 18:10:10.000000000 -0400
+++ apt-pkg/contrib/configuration.cc 2004-07-20 13:32:31.000000000 -0400
@@ -397,6 +397,26 @@
return Exists(Name);
}
+
+static string escape(const string &input)
+{
+ string::size_type start=0,end=input.find_first_of("\\\"");
+ string rval;
+
+ while(end!=string::npos)
+ {
+ rval+=string(input, start, end-start);
+ rval+='\\';
+ rval+=input[end];
+
+ start=end+1;
+ end=input.find_first_of("\\\"", start);
+ }
+
+ rval+=string(input, start);
+
+ return rval;
+}
/*}}}*/
// Configuration::Dump - Dump the config /*{{{*/
// ---------------------------------------------------------------------
@@ -408,7 +428,7 @@
const Configuration::Item *Top = Tree(0);
for (; Top != 0;)
{
- str << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
+ str << Top->FullTag() << " \"" << escape(Top->Value) << "\";" << endl;
if (Top->Child != 0)
{
@@ -491,8 +511,21 @@
// Discard single line comments
bool InQuote = false;
+ bool BackslashEscape = false;
for (char *I = Buffer; *I != 0; I++)
{
+ if(BackslashEscape == true)
+ {
+ BackslashEscape=false;
+ continue;
+ }
+
+ if (*I == '\\')
+ {
+ BackslashEscape = true;
+ continue;
+ }
+
if (*I == '"')
InQuote = !InQuote;
if (InQuote == true)
@@ -507,8 +540,21 @@
// Look for multi line comments
InQuote = false;
+ BackslashEscape = false;
for (char *I = Buffer; *I != 0; I++)
{
+ if (BackslashEscape == true)
+ {
+ BackslashEscape = false;
+ continue;
+ }
+
+ if (*I == '\\')
+ {
+ BackslashEscape = true;
+ continue;
+ }
+
if (*I == '"')
InQuote = !InQuote;
if (InQuote == true)
@@ -541,8 +587,24 @@
// We now have a valid line fragment
InQuote = false;
+ BackslashEscape = false;
for (char *I = Buffer; *I != 0;)
{
+ if(BackslashEscape == true)
+ {
+ // Put this character into the buffer unconditionally
+ BackslashEscape=false;
+ ++I;
+ continue;
+ }
+
+ if(*I == '\\')
+ {
+ BackslashEscape = true;
+ ++I;
+ continue;
+ }
+
if (*I == '"')
InQuote = !InQuote;
--- /tmp/apt-0.6.25/apt-pkg/contrib/strutl.cc 2003-07-18 10:15:11.000000000 -0400
+++ apt-pkg/contrib/strutl.cc 2004-07-20 13:33:24.000000000 -0400
@@ -100,6 +100,8 @@
understand [] brackets.*/
bool ParseQuoteWord(const char *&String,string &Res)
{
+ cout << String << endl;
+
// Skip leading whitespace
const char *C = String;
for (;*C != 0 && *C == ' '; C++);
@@ -176,7 +178,12 @@
if (*C == '"')
{
for (C++; *C != 0 && *C != '"'; C++)
+ {
+ if(*C=='\\' && *(C+1)!=0)
+ ++C;
+
*Buf++ = *C;
+ }
if (*C == 0)
return false;
Reply to: