diff options
Diffstat (limited to 'windows/winutils.c')
-rw-r--r-- | windows/winutils.c | 788 |
1 files changed, 0 insertions, 788 deletions
diff --git a/windows/winutils.c b/windows/winutils.c deleted file mode 100644 index dec8984b..00000000 --- a/windows/winutils.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * winutils.c: miscellaneous Windows utilities for GUI apps - */ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - -#include "putty.h" -#include "misc.h" - -#ifdef TESTMODE -/* Definitions to allow this module to be compiled standalone for testing - * split_into_argv(). */ -#define smalloc malloc -#define srealloc realloc -#define sfree free -#endif - -/* - * GetOpenFileName/GetSaveFileName tend to muck around with the process' - * working directory on at least some versions of Windows. - * Here's a wrapper that gives more control over this, and hides a little - * bit of other grottiness. - */ - -struct filereq_tag { - TCHAR cwd[MAX_PATH]; -}; - -/* - * `of' is expected to be initialised with most interesting fields, but - * this function does some administrivia. (assume `of' was memset to 0) - * save==1 -> GetSaveFileName; save==0 -> GetOpenFileName - * `state' is optional. - */ -bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save) -{ - TCHAR cwd[MAX_PATH]; /* process CWD */ - bool ret; - - /* Get process CWD */ - if (preserve) { - DWORD r = GetCurrentDirectory(lenof(cwd), cwd); - if (r == 0 || r >= lenof(cwd)) - /* Didn't work, oh well. Stop trying to be clever. */ - preserve = false; - } - - /* Open the file requester, maybe setting lpstrInitialDir */ - { -#ifdef OPENFILENAME_SIZE_VERSION_400 - of->lStructSize = OPENFILENAME_SIZE_VERSION_400; -#else - of->lStructSize = sizeof(*of); -#endif - of->lpstrInitialDir = (state && state->cwd[0]) ? state->cwd : NULL; - /* Actually put up the requester. */ - ret = save ? GetSaveFileName(of) : GetOpenFileName(of); - } - - /* Get CWD left by requester */ - if (state) { - DWORD r = GetCurrentDirectory(lenof(state->cwd), state->cwd); - if (r == 0 || r >= lenof(state->cwd)) - /* Didn't work, oh well. */ - state->cwd[0] = '\0'; - } - - /* Restore process CWD */ - if (preserve) - /* If it fails, there's not much we can do. */ - (void) SetCurrentDirectory(cwd); - - return ret; -} - -filereq *filereq_new(void) -{ - filereq *ret = snew(filereq); - ret->cwd[0] = '\0'; - return ret; -} - -void filereq_free(filereq *state) -{ - sfree(state); -} - -/* - * Message box with optional context help. - */ - -static HWND message_box_owner; - -/* Callback function to launch context help. */ -static VOID CALLBACK message_box_help_callback(LPHELPINFO lpHelpInfo) -{ - const char *context = NULL; -#define CHECK_CTX(name) \ - do { \ - if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \ - context = WINHELP_CTX_ ## name; \ - } while (0) - CHECK_CTX(errors_hostkey_absent); - CHECK_CTX(errors_hostkey_changed); - CHECK_CTX(errors_cantloadkey); - CHECK_CTX(option_cleanup); - CHECK_CTX(pgp_fingerprints); -#undef CHECK_CTX - if (context) - launch_help(message_box_owner, context); -} - -int message_box(HWND owner, LPCTSTR text, LPCTSTR caption, - DWORD style, DWORD helpctxid) -{ - MSGBOXPARAMS mbox; - - /* - * We use MessageBoxIndirect() because it allows us to specify a - * callback function for the Help button. - */ - mbox.cbSize = sizeof(mbox); - /* Assumes the globals `hinst' and `hwnd' have sensible values. */ - mbox.hInstance = hinst; - mbox.hwndOwner = message_box_owner = owner; - mbox.lpfnMsgBoxCallback = &message_box_help_callback; - mbox.dwLanguageId = LANG_NEUTRAL; - mbox.lpszText = text; - mbox.lpszCaption = caption; - mbox.dwContextHelpId = helpctxid; - mbox.dwStyle = style; - if (helpctxid != 0 && has_help()) mbox.dwStyle |= MB_HELP; - return MessageBoxIndirect(&mbox); -} - -/* - * Display the fingerprints of the PGP Master Keys to the user. - */ -void pgp_fingerprints_msgbox(HWND owner) -{ - message_box( - owner, - "These are the fingerprints of the PuTTY PGP Master Keys. They can\n" - "be used to establish a trust path from this executable to another\n" - "one. See the manual for more information.\n" - "(Note: these fingerprints have nothing to do with SSH!)\n" - "\n" - "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR - " (" PGP_MASTER_KEY_DETAILS "):\n" - " " PGP_MASTER_KEY_FP "\n\n" - "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR - ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" - " " PGP_PREV_MASTER_KEY_FP, - "PGP fingerprints", MB_ICONINFORMATION | MB_OK, - HELPCTXID(pgp_fingerprints)); -} - -/* - * Helper function to remove the border around a dialog item such as - * a read-only edit control. - */ -void MakeDlgItemBorderless(HWND parent, int id) -{ - HWND child = GetDlgItem(parent, id); - LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE); - LONG_PTR exstyle = GetWindowLongPtr(child, GWL_EXSTYLE); - style &= ~WS_BORDER; - exstyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE); - SetWindowLongPtr(child, GWL_STYLE, style); - SetWindowLongPtr(child, GWL_EXSTYLE, exstyle); - SetWindowPos(child, NULL, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); -} - -/* - * Handy wrapper around GetDlgItemText which doesn't make you invent - * an arbitrary length limit on the output string. Returned string is - * dynamically allocated; caller must free. - */ -char *GetDlgItemText_alloc(HWND hwnd, int id) -{ - char *ret = NULL; - size_t size = 0; - - do { - sgrowarray_nm(ret, size, size); - GetDlgItemText(hwnd, id, ret, size); - } while (!memchr(ret, '\0', size-1)); - - return ret; -} - -/* - * Split a complete command line into argc/argv, attempting to do it - * exactly the same way the Visual Studio C library would do it (so - * that our console utilities, which receive argc and argv already - * broken apart by the C library, will have their command lines - * processed in the same way as the GUI utilities which get a whole - * command line and must call this function). - * - * Does not modify the input command line. - * - * The final parameter (argstart) is used to return a second array - * of char * pointers, the same length as argv, each one pointing - * at the start of the corresponding element of argv in the - * original command line. So if you get half way through processing - * your command line in argc/argv form and then decide you want to - * treat the rest as a raw string, you can. If you don't want to, - * `argstart' can be safely left NULL. - */ - -/* - * The precise argument-breaking rules vary with compiler version, or - * rather, with the crt0-type startup code that comes with each - * compiler's C library. We do our best to match the compiler version, - * so that we faithfully imitate in our GUI utilities what the - * corresponding set of CLI utilities can't be prevented from doing. - * - * The basic rules are: - * - * - Single quotes are not special characters. - * - * - Double quotes are removed, but within them spaces cease to be - * special. - * - * - Backslashes are _only_ special when a sequence of them appear - * just before a double quote. In this situation, they are treated - * like C backslashes: so \" just gives a literal quote, \\" gives - * a literal backslash and then opens or closes a double-quoted - * segment, \\\" gives a literal backslash and then a literal - * quote, \\\\" gives two literal backslashes and then opens/closes - * a double-quoted segment, and so forth. Note that this behaviour - * is identical inside and outside double quotes. - * - * - Two successive double quotes become one literal double quote, - * but only _inside_ a double-quoted segment. Outside, they just - * form an empty double-quoted segment (which may cause an empty - * argument word). - * - * That only leaves the interesting question of what happens when one - * or more backslashes precedes two or more double quotes, starting - * inside a double-quoted string. - * - * I investigated this in an ordinary CLI program, using the - * toolchain's crt0 to split a command line of the form - * - * "a\\\"""b c" d - * - * Here I tabulate number of backslashes (across the top) against - * number of quotes (down the left), and indicate how many backslashes - * are output, how many quotes are output, and whether a quoted - * segment is open at the end of the sequence: - * - * backslashes - * - * 0 1 2 3 4 - * - * 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y - * --------+----------------------------- - * 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n - * q 2 0,1,y | 0,1,n 1,1,y 1,1,n 2,1,y - * u 3 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n - * o 4 0,2,y | 0,2,n 1,2,y 1,2,n 2,2,y - * t 5 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n - * e 6 0,3,y | 0,3,n 1,3,y 1,3,n 2,3,y - * s 7 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n - * 8 0,4,y | 0,4,n 1,4,y 1,4,n 2,4,y - * - * The row at the top of this table, with quotes=0, demonstrates what - * I claimed above, that when a sequence of backslashes are not - * followed by a double quote, they don't act specially at all. The - * rest of the table shows that the backslashes escape each other in - * pairs (so that with 2n or 2n+1 input backslashes you get n output - * ones); if there's an odd number of input backslashes then the last - * one escapes the first double quote (so you get a literal quote and - * enter a quoted string); thereafter, each input quote character - * either opens or closes a quoted string, and if it closes one, it - * generates a literal " as a side effect. - * - * But here's the corresponding table from the older Visual Studio 7: - * - * backslashes - * - * 0 1 2 3 4 - * - * 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y - * --------+----------------------------- - * 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n - * q 2 0,1,n | 0,1,n 1,1,n 1,1,n 2,1,n - * u 3 0,1,y | 0,2,n 1,1,y 1,2,n 2,1,y - * o 4 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n - * t 5 0,2,n | 0,2,n 1,2,n 1,2,n 2,2,n - * e 6 0,2,y | 0,3,n 1,2,y 1,3,n 2,2,y - * s 7 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n - * 8 0,3,n | 0,3,n 1,3,n 1,3,n 2,3,n - * 9 0,3,y | 0,4,n 1,3,y 1,4,n 2,3,y - * 10 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n - * 11 0,4,n | 0,4,n 1,4,n 1,4,n 2,4,n - * - * There is very weird mod-3 behaviour going on here in the - * number of quotes, and it even applies when there aren't any - * backslashes! How ghastly. - * - * With a bit of thought, this extremely odd diagram suddenly - * coalesced itself into a coherent, if still ghastly, model of - * how things work: - * - * - As before, backslashes are only special when one or more - * of them appear contiguously before at least one double - * quote. In this situation the backslashes do exactly what - * you'd expect: each one quotes the next thing in front of - * it, so you end up with n/2 literal backslashes (if n is - * even) or (n-1)/2 literal backslashes and a literal quote - * (if n is odd). In the latter case the double quote - * character right after the backslashes is used up. - * - * - After that, any remaining double quotes are processed. A - * string of contiguous unescaped double quotes has a mod-3 - * behaviour: - * - * * inside a quoted segment, a quote ends the segment. - * * _immediately_ after ending a quoted segment, a quote - * simply produces a literal quote. - * * otherwise, outside a quoted segment, a quote begins a - * quoted segment. - * - * So, for example, if we started inside a quoted segment - * then two contiguous quotes would close the segment and - * produce a literal quote; three would close the segment, - * produce a literal quote, and open a new segment. If we - * started outside a quoted segment, then two contiguous - * quotes would open and then close a segment, producing no - * output (but potentially creating a zero-length argument); - * but three quotes would open and close a segment and then - * produce a literal quote. - */ - -/* - * We select between two behaviours depending on the version of Visual - * Studio (see large comment below). I don't know exactly when the bug - * fix happened, but I know that VS7 had the odd mod-3 behaviour. - */ -#if _MSC_VER < 1400 -#define MOD3 1 -#else -#define MOD3 0 -#endif - -void split_into_argv(char *cmdline, int *argc, char ***argv, - char ***argstart) -{ - char *p; - char *outputline, *q; - char **outputargv, **outputargstart; - int outputargc; - - /* - * First deal with the simplest of all special cases: if there - * aren't any arguments, return 0,NULL,NULL. - */ - while (*cmdline && isspace(*cmdline)) cmdline++; - if (!*cmdline) { - if (argc) *argc = 0; - if (argv) *argv = NULL; - if (argstart) *argstart = NULL; - return; - } - - /* - * This will guaranteeably be big enough; we can realloc it - * down later. - */ - outputline = snewn(1+strlen(cmdline), char); - outputargv = snewn(strlen(cmdline)+1 / 2, char *); - outputargstart = snewn(strlen(cmdline)+1 / 2, char *); - - p = cmdline; q = outputline; outputargc = 0; - - while (*p) { - bool quote; - - /* Skip whitespace searching for start of argument. */ - while (*p && isspace(*p)) p++; - if (!*p) break; - - /* We have an argument; start it. */ - outputargv[outputargc] = q; - outputargstart[outputargc] = p; - outputargc++; - quote = false; - - /* Copy data into the argument until it's finished. */ - while (*p) { - if (!quote && isspace(*p)) - break; /* argument is finished */ - - if (*p == '"' || *p == '\\') { - /* - * We have a sequence of zero or more backslashes - * followed by a sequence of zero or more quotes. - * Count up how many of each, and then deal with - * them as appropriate. - */ - int i, slashes = 0, quotes = 0; - while (*p == '\\') slashes++, p++; - while (*p == '"') quotes++, p++; - - if (!quotes) { - /* - * Special case: if there are no quotes, - * slashes are not special at all, so just copy - * n slashes to the output string. - */ - while (slashes--) *q++ = '\\'; - } else { - /* Slashes annihilate in pairs. */ - while (slashes >= 2) slashes -= 2, *q++ = '\\'; - - /* One remaining slash takes out the first quote. */ - if (slashes) quotes--, *q++ = '"'; - - if (quotes > 0) { - /* Outside a quote segment, a quote starts one. */ - if (!quote) quotes--; - -#if !MOD3 - /* New behaviour: produce n/2 literal quotes... */ - for (i = 2; i <= quotes; i += 2) *q++ = '"'; - /* ... and end in a quote segment iff 2 divides n. */ - quote = (quotes % 2 == 0); -#else - /* Old behaviour: produce (n+1)/3 literal quotes... */ - for (i = 3; i <= quotes+1; i += 3) *q++ = '"'; - /* ... and end in a quote segment iff 3 divides n. */ - quote = (quotes % 3 == 0); -#endif - } - } - } else { - *q++ = *p++; - } - } - - /* At the end of an argument, just append a trailing NUL. */ - *q++ = '\0'; - } - - outputargv = sresize(outputargv, outputargc, char *); - outputargstart = sresize(outputargstart, outputargc, char *); - - if (argc) *argc = outputargc; - if (argv) *argv = outputargv; else sfree(outputargv); - if (argstart) *argstart = outputargstart; else sfree(outputargstart); -} - -#ifdef TESTMODE - -const struct argv_test { - const char *cmdline; - const char *argv[10]; -} argv_tests[] = { - /* - * We generate this set of tests by invoking ourself with - * `-generate'. - */ -#if !MOD3 - /* Newer behaviour, with no weird mod-3 glitch. */ - {"ab c\" d", {"ab", "c d", NULL}}, - {"a\"b c\" d", {"ab c", "d", NULL}}, - {"a\"\"b c\" d", {"ab", "c d", NULL}}, - {"a\"\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"a\"\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"a\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"a\\b c\" d", {"a\\b", "c d", NULL}}, - {"a\\\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\\\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"a\\\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\\\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"a\\\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}}, - {"a\\\\b c\" d", {"a\\\\b", "c d", NULL}}, - {"a\\\\\"b c\" d", {"a\\b c", "d", NULL}}, - {"a\\\\\"\"b c\" d", {"a\\b", "c d", NULL}}, - {"a\\\\\"\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"a\\\\\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"a\\\\\\b c\" d", {"a\\\\\\b", "c d", NULL}}, - {"a\\\\\\\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"a\\\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}}, - {"a\\\\\\\\b c\" d", {"a\\\\\\\\b", "c d", NULL}}, - {"a\\\\\\\\\"b c\" d", {"a\\\\b c", "d", NULL}}, - {"a\\\\\\\\\"\"b c\" d", {"a\\\\b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}}, - {"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b c", "d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}}, - {"\"ab c\" d", {"ab c", "d", NULL}}, - {"\"a\"b c\" d", {"ab", "c d", NULL}}, - {"\"a\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"\"a\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"\"a\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"\"a\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"\"a\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"\"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}}, - {"\"a\\b c\" d", {"a\\b c", "d", NULL}}, - {"\"a\\\"b c\" d", {"a\"b c", "d", NULL}}, - {"\"a\\\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"\"a\\\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"\"a\\\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\\\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"\"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"\"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}}, - {"\"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b", "c d", NULL}}, - {"\"a\\\\b c\" d", {"a\\\\b c", "d", NULL}}, - {"\"a\\\\\"b c\" d", {"a\\b", "c d", NULL}}, - {"\"a\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"\"a\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"\"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}}, - {"\"a\\\\\\b c\" d", {"a\\\\\\b c", "d", NULL}}, - {"\"a\\\\\\\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\b c\" d", {"a\\\\\\\\b c", "d", NULL}}, - {"\"a\\\\\\\\\"b c\" d", {"a\\\\b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"b c\" d", {"a\\\\\"b c", "d", NULL}}, - {"\"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b c", "d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"\"b c", "d", NULL}}, -#else /* MOD3 */ - /* VS7 mod-3 behaviour. */ - {"ab c\" d", {"ab", "c d", NULL}}, - {"a\"b c\" d", {"ab c", "d", NULL}}, - {"a\"\"b c\" d", {"ab", "c d", NULL}}, - {"a\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\"\"\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"a\"\"\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\\b c\" d", {"a\\b", "c d", NULL}}, - {"a\\\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\\\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"a\\\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"a\\\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\\\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"a\\\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"a\\\\b c\" d", {"a\\\\b", "c d", NULL}}, - {"a\\\\\"b c\" d", {"a\\b c", "d", NULL}}, - {"a\\\\\"\"b c\" d", {"a\\b", "c d", NULL}}, - {"a\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\"\"\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"a\\\\\"\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\\b c\" d", {"a\\\\\\b", "c d", NULL}}, - {"a\\\\\\\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"a\\\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"a\\\\\\\\b c\" d", {"a\\\\\\\\b", "c d", NULL}}, - {"a\\\\\\\\\"b c\" d", {"a\\\\b c", "d", NULL}}, - {"a\\\\\\\\\"\"b c\" d", {"a\\\\b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}}, - {"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"\"ab c\" d", {"ab c", "d", NULL}}, - {"\"a\"b c\" d", {"ab", "c d", NULL}}, - {"\"a\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"\"a\"\"\"b c\" d", {"a\"b c", "d", NULL}}, - {"\"a\"\"\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"\"a\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"\"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"\"a\\b c\" d", {"a\\b c", "d", NULL}}, - {"\"a\\\"b c\" d", {"a\"b c", "d", NULL}}, - {"\"a\\\"\"b c\" d", {"a\"b", "c d", NULL}}, - {"\"a\\\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\\\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}}, - {"\"a\\\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}}, - {"\"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"\"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}}, - {"\"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}}, - {"\"a\\\\b c\" d", {"a\\\\b c", "d", NULL}}, - {"\"a\\\\\"b c\" d", {"a\\b", "c d", NULL}}, - {"\"a\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"\"a\\\\\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\b c\" d", {"a\\\\\\b c", "d", NULL}}, - {"\"a\\\\\\\"b c\" d", {"a\\\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}}, - {"\"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\b c\" d", {"a\\\\\\\\b c", "d", NULL}}, - {"\"a\\\\\\\\\"b c\" d", {"a\\\\b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}}, - {"\"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}}, -#endif /* MOD3 */ -}; - -int main(int argc, char **argv) -{ - int i, j; - - if (argc > 1) { - /* - * Generation of tests. - * - * Given `-splat <args>', we print out a C-style - * representation of each argument (in the form "a", "b", - * NULL), backslash-escaping each backslash and double - * quote. - * - * Given `-split <string>', we first doctor `string' by - * turning forward slashes into backslashes, single quotes - * into double quotes and underscores into spaces; and then - * we feed the resulting string to ourself with `-splat'. - * - * Given `-generate', we concoct a variety of fun test - * cases, encode them in quote-safe form (mapping \, " and - * space to /, ' and _ respectively) and feed each one to - * `-split'. - */ - if (!strcmp(argv[1], "-splat")) { - int i; - char *p; - for (i = 2; i < argc; i++) { - putchar('"'); - for (p = argv[i]; *p; p++) { - if (*p == '\\' || *p == '"') - putchar('\\'); - putchar(*p); - } - printf("\", "); - } - printf("NULL"); - return 0; - } - - if (!strcmp(argv[1], "-split") && argc > 2) { - char *str = malloc(20 + strlen(argv[0]) + strlen(argv[2])); - char *p, *q; - - q = str + sprintf(str, "%s -splat ", argv[0]); - printf(" {\""); - for (p = argv[2]; *p; p++, q++) { - switch (*p) { - case '/': printf("\\\\"); *q = '\\'; break; - case '\'': printf("\\\""); *q = '"'; break; - case '_': printf(" "); *q = ' '; break; - default: putchar(*p); *q = *p; break; - } - } - *p = '\0'; - printf("\", {"); - fflush(stdout); - - system(str); - - printf("}},\n"); - - return 0; - } - - if (!strcmp(argv[1], "-generate")) { - char *teststr, *p; - int i, initialquote, backslashes, quotes; - - teststr = malloc(200 + strlen(argv[0])); - - for (initialquote = 0; initialquote <= 1; initialquote++) { - for (backslashes = 0; backslashes < 5; backslashes++) { - for (quotes = 0; quotes < 9; quotes++) { - p = teststr + sprintf(teststr, "%s -split ", argv[0]); - if (initialquote) *p++ = '\''; - *p++ = 'a'; - for (i = 0; i < backslashes; i++) *p++ = '/'; - for (i = 0; i < quotes; i++) *p++ = '\''; - *p++ = 'b'; - *p++ = '_'; - *p++ = 'c'; - *p++ = '\''; - *p++ = '_'; - *p++ = 'd'; - *p = '\0'; - - system(teststr); - } - } - } - return 0; - } - - fprintf(stderr, "unrecognised option: \"%s\"\n", argv[1]); - return 1; - } - - /* - * If we get here, we were invoked with no arguments, so just - * run the tests. - */ - - for (i = 0; i < lenof(argv_tests); i++) { - int ac; - char **av; - - split_into_argv(argv_tests[i].cmdline, &ac, &av); - - for (j = 0; j < ac && argv_tests[i].argv[j]; j++) { - if (strcmp(av[j], argv_tests[i].argv[j])) { - printf("failed test %d (|%s|) arg %d: |%s| should be |%s|\n", - i, argv_tests[i].cmdline, - j, av[j], argv_tests[i].argv[j]); - } -#ifdef VERBOSE - else { - printf("test %d (|%s|) arg %d: |%s| == |%s|\n", - i, argv_tests[i].cmdline, - j, av[j], argv_tests[i].argv[j]); - } -#endif - } - if (j < ac) - printf("failed test %d (|%s|): %d args returned, should be %d\n", - i, argv_tests[i].cmdline, ac, j); - if (argv_tests[i].argv[j]) - printf("failed test %d (|%s|): %d args returned, should be more\n", - i, argv_tests[i].cmdline, ac); - } - - return 0; -} - -#endif |