Skip to content

Commit

Permalink
Added quote().
Browse files Browse the repository at this point in the history
New function to quote strings for passing to the command prompt.
Protect metacharacters with ^ when quoting.  Always quote when
metacharacters are present even if we wouldn't otherwise.
  • Loading branch information
Iain Patterson committed Jul 28, 2016
1 parent caaaa12 commit 2a259b5
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
109 changes: 109 additions & 0 deletions nssm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,115 @@ int str_number(const TCHAR *string, unsigned long *number) {
return str_number(string, number, &bogus);
}

/* Does a char need to be escaped? */
static bool needs_escape(const TCHAR c) {
if (c == _T('"')) return true;
if (c == _T('&')) return true;
if (c == _T('%')) return true;
if (c == _T('^')) return true;
if (c == _T('<')) return true;
if (c == _T('>')) return true;
if (c == _T('|')) return true;
return false;
}

/* Does a char need to be quoted? */
static bool needs_quote(const TCHAR c) {
if (c == _T(' ')) return true;
if (c == _T('\t')) return true;
if (c == _T('\n')) return true;
if (c == _T('\v')) return true;
if (c == _T('"')) return true;
if (c == _T('*')) return true;
return needs_escape(c);
}

/* https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ */
/* http://www.robvanderwoude.com/escapechars.php */
int quote(const TCHAR *unquoted, TCHAR *buffer, size_t buflen) {
size_t i, j, n;
size_t len = _tcslen(unquoted);
if (len > buflen - 1) return 1;

bool escape = false;
bool quotes = false;

for (i = 0; i < len; i++) {
if (needs_escape(unquoted[i])) {
escape = quotes = true;
break;
}
if (needs_quote(unquoted[i])) quotes = true;
}
if (! quotes) {
memmove(buffer, unquoted, (len + 1) * sizeof(TCHAR));
return 0;
}

/* "" */
size_t quoted_len = 2;
if (escape) quoted_len += 2;
for (i = 0; ; i++) {
n = 0;

while (i != len && unquoted[i] == _T('\\')) {
i++;
n++;
}

if (i == len) {
quoted_len += n * 2;
break;
}
else if (unquoted[i] == _T('"')) quoted_len += n * 2 + 2;
else quoted_len += n + 1;
if (needs_escape(unquoted[i])) quoted_len += n;
}
if (quoted_len > buflen - 1) return 1;

TCHAR *s = buffer;
if (escape) *s++ = _T('^');
*s++ = _T('"');

for (i = 0; ; i++) {
n = 0;

while (i != len && unquoted[i] == _T('\\')) {
i++;
n++;
}

if (i == len) {
for (j = 0; j < n * 2; j++) {
if (escape) *s++ = _T('^');
*s++ = _T('\\');
}
break;
}
else if (unquoted[i] == _T('"')) {
for (j = 0; j < n * 2 + 1; j++) {
if (escape) *s++ = _T('^');
*s++ = _T('\\');
}
if (escape && needs_escape(unquoted[i])) *s++ = _T('^');
*s++ = unquoted[i];
}
else {
for (j = 0; j < n; j++) {
if (escape) *s++ = _T('^');
*s++ = _T('\\');
}
if (escape && needs_escape(unquoted[i])) *s++ = _T('^');
*s++ = unquoted[i];
}
}
if (escape) *s++ = _T('^');
*s++ = _T('"');
*s++ = _T('\0');

return 0;
}

/* Remove basename of a path. */
void strip_basename(TCHAR *buffer) {
size_t len = _tcslen(buffer);
Expand Down
1 change: 1 addition & 0 deletions nssm.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#endif

int str_equiv(const TCHAR *, const TCHAR *);
int quote(const TCHAR *, TCHAR *, size_t);
void strip_basename(TCHAR *);
int str_number(const TCHAR *, unsigned long *, TCHAR **);
int str_number(const TCHAR *, unsigned long *);
Expand Down

0 comments on commit 2a259b5

Please sign in to comment.