diff --git a/README.md b/README.md index f7e48cd..9cce09b 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,6 @@ Start desktoptest on specified directories: Example using cmd on Windows (KDE installed): set KDE_SHARE="%SYSTEMDRIVE%\ProgramData\KDE\share" - dub run desktopfile:desktoptest -- %KDE_SHARE%\applications %KDE_SHARE%\templates" %KDE_SHARE%\desktop-directories %KDE_SHARE%\autostart + dub run desktopfile:desktoptest -- %KDE_SHARE%\applications %KDE_SHARE%\templates %KDE_SHARE%\desktop-directories %KDE_SHARE%\autostart \ No newline at end of file diff --git a/examples/desktoptest/source/app.d b/examples/desktoptest/source/app.d index bdf5d53..4572bc5 100644 --- a/examples/desktoptest/source/app.d +++ b/examples/desktoptest/source/app.d @@ -14,7 +14,9 @@ void main(string[] args) version(OSX) {} else version(Posix) { import standardpaths; - desktopDirs = applicationsPaths() ~ writablePath(StandardPath.desktop); + string[] dataPaths = standardPaths(StandardPath.data); + + desktopDirs = applicationsPaths() ~ dataPaths.map!(s => buildPath(s, "desktop-directories")).array ~ dataPaths.map!(s => buildPath(s, "templates")).array ~ writablePath(StandardPath.desktop); } else version(Windows) { try { auto root = environment.get("SYSTEMDRIVE", "C:"); @@ -33,7 +35,7 @@ void main(string[] args) if (!desktopDirs.length) { writeln("No desktop directories given nor could be detected"); - writefln("Usage: %s [DIR]...", args[0]); + writefln("Usage: %s [DIRECTORY]...", args[0]); return; } @@ -43,11 +45,17 @@ void main(string[] args) foreach(entry; dir.dirEntries(SpanMode.depth).filter!(a => a.isFile() && (a.extension == ".desktop" || a.extension == ".directory"))) { debug writeln(entry); try { - new DesktopFile(entry); + auto df = new DesktopFile(entry); + if (!df.execString().empty) { + auto execArgs = df.expandExecString(); + } } catch(IniLikeException e) { stderr.writefln("Error reading %s: at %s: %s", entry, e.lineNumber, e.msg); } + catch(DesktopExecException e) { + stderr.writefln("Error while expanding Exec value of %s: %s", entry, e.msg); + } catch(Exception e) { stderr.writefln("Error reading %s: %s", entry, e.msg); } diff --git a/source/desktopfile.d b/source/desktopfile.d index f52c89e..4aeac2f 100644 --- a/source/desktopfile.d +++ b/source/desktopfile.d @@ -128,9 +128,9 @@ private @trusted string unescapeQuotedArgument(string value) nothrow pure while(i < value.length) { if (isWhite(value[i])) { i++; - } else if (value[i] == '"') { - i++; - size_t start = i; + } else if (value[i] == '"' || value[i] == '\'') { + char delimeter = value[i]; + size_t start = ++i; bool inQuotes = true; bool wasSlash; @@ -141,7 +141,7 @@ private @trusted string unescapeQuotedArgument(string value) nothrow pure continue; } - if (value[i] == '"' && (value[i-1] != '\\' || (value[i-1] == '\\' && wasSlash) )) { + if (value[i] == delimeter && (value[i-1] != '\\' || (value[i-1] == '\\' && wasSlash) )) { inQuotes = false; break; } @@ -149,25 +149,21 @@ private @trusted string unescapeQuotedArgument(string value) nothrow pure i++; } if (inQuotes) { - throw new DesktopExecException("Missing pair double quote"); + throw new DesktopExecException("Missing pair quote"); } - result ~= value[start..i]; + result ~= value[start..i].unescapeQuotedArgument(); i++; } else { size_t start = i; - i++; - while(i < value.length) { - if (isWhite(value[i])) { - break; - } + while(i < value.length && !isWhite(value[i])) { i++; } result ~= value[start..i]; } } - return result.map!(s => s.unescapeQuotedArgument); + return result; } /// @@ -190,6 +186,10 @@ unittest assert(equal(unquoteExecString(`"\\" `), [`\`])); assert(equal(unquoteExecString(`"\\\\" `), [`\\`])); + + assert(equal(unquoteExecString(`'quoted cmd' arg`), [`quoted cmd`, `arg`])); + + assertThrown!DesktopExecException(unquoteExecString(`cmd "quoted arg`)); } @trusted string[] parseExecString(string execString) pure @@ -225,8 +225,12 @@ unittest } else if (token == "%d" || token == "%D" || token == "%n" || token == "%N" || token == "%m" || token == "%v") { continue; } else { - if (token.length == 2 && token[0] == '%') { - throw new DesktopExecException("Unknown field code: " ~ token); + if (token.length >= 2 && token[0] == '%') { + if (token[1] == '%') { + toReturn ~= token[1..$]; + } else { + throw new DesktopExecException("Unknown field code: " ~ token); + } } else { toReturn ~= token; } @@ -362,7 +366,7 @@ struct DesktopAction * Pid of started process. * Throws: * ProcessException on failure to start the process. - * Exception if expanded exec string is empty. + * DesktopExecException if exec string is invalid. * See_Also: execString */ @safe Pid start(string locale = null) const { @@ -1037,7 +1041,7 @@ Icon=folder`; * Pid of started process. * Throws: * ProcessException on failure to start the process. - * Exception if expanded exec string is empty. + * DesktopExecException if exec string is invalid. * See_Also: determineTerminalEmulator, start, expandExecString */ @trusted Pid startApplication(in string[] urls = null, string locale = null, lazy string[] terminalCommand = getTerminalCommand) const @@ -1058,8 +1062,8 @@ Icon=folder`; } ///ditto, but uses the only url. - @trusted Pid startApplication(string url, string locale = null, lazy string[] preferableTerminal = getTerminalCommand) const { - return startApplication([url], locale, preferableTerminal); + @trusted Pid startApplication(string url, string locale = null, lazy string[] terminalCommand = getTerminalCommand) const { + return startApplication([url], locale, terminalCommand); } /** @@ -1070,7 +1074,7 @@ Icon=folder`; * Pid of started process. * Throws: * ProcessException on failure to start the process. - * Exception if desktop file does not define URL. + * Exception if desktop file does not define URL or it's empty. * See_Also: start */ @trusted Pid startLink() const { @@ -1103,7 +1107,7 @@ Icon=folder`; case DesktopFile.Type.Link: return startLink(); case DesktopFile.Type.Directory: - throw new Exception("Don't know how to start directory"); + throw new Exception("Don't know how to start Directory"); case DesktopFile.Type.Unknown: throw new Exception("Unknown desktop entry type"); }