/*
    shell_quotearg - quote arguments for the shell in single quotation marks
    Heiner Steven <heiner.steven@nexgo.de>, Public Domain

    usage:
    	unsigned len;
	char *path, quotedpath[PATH_LEN];

    	len = shell_quotearg(path, quotedpath, sizeof(quotedpath));
	if (len == 0) {
	    fprintf(stderr, "ERROR: path buffer too small (%d bytes)\n",
	    	    sizeof(quotedpath));
	}

	printf("path=<%s>, quotedpath=<%s>\n", path, quotedpath);


    Basically we quote an argument in apostrophes, e.g.
    	one two
    becomes
    	'one two'

    If the string contains an apostrophe itself, we have a special case
    because the shell cannot handle it (the shell syntax 'doesn\'t' will
    not work). Instead we close the current argument word, add a quoted
    apostrophe, and open a new argument word:
         _____   _  _
    	'doesn' \' 't'

    The result buffer must be large enough for the expanded result. The
    worst case regarding expansion are alternating characters and
    apostrophes:

    	a'b'c'd'             (length 8) get converted to
	'a'\''b'\''c'\''d'\' (length 20)

    Maximum size of the result:

    	2 + 5 * length(result) / 2 + 1

    Explanation:
     o	leading + trailing apostrophy
     o	one pair of character and apostrophy (two characters) get
	represented as five characters: a' -> a'\''
     o	String terminator

    A result buffer roughly three times the size of the input buffer
    should be safe.

    Return value:
      Length of the resulting string (not counting the terminating '\0'),
      or 0 in case of errors, e.g. result buffer too small
*/

#include <assert.h>

unsigned shell_quotearg(const char *arg, char *buf, size_t bufsize)
{
    const char *src;
    char *dst, *endp;
    bool_t instring;

    assert(arg);
    assert (buf && bufsize >= 3);	/* Smallest result: "''" */

    endp = &buf[bufsize];
    src = arg;
    dst = buf;
    instring = false;		/* Are we within a ' string? */
    while (*src && dst < endp - 1) {
    	if (*src != '\'') {
	    if (!instring) {
	    	if (dst+2 >= endp) return 0;
	    	*dst++ = '\'';
		instring = true;
	    }
	    *dst++ = *src++;
	    continue;
	}

	if (instring) {
	    if (dst+3 >= endp) return 0;
	    *dst++ = '\'';
	    *dst++ = '\\';
	    *dst++ = '\'';
	    instring = false;
	} else {
	    if (dst+2 >= endp) return 0;
	    *dst++ = '\\';
	    *dst++ = '\'';
	}
	src++;
    }

    if (instring) {
	if (dst+1 >= endp) return 0;
    	*dst++ = '\'';
    }

    *dst = '\0';
    return dst - buf;
}

