238 lines
5.5 KiB
C
238 lines
5.5 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
argv.h
|
|
|
|
Abstract:
|
|
|
|
Implementation of CommandLineToArgv() API
|
|
|
|
Author:
|
|
|
|
Hakki T. Bostanci (hakkib) 06-Apr-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef __ARGV_H
|
|
#define __ARGV_H
|
|
|
|
#include <assert.h>
|
|
|
|
#ifndef ASSERT
|
|
#define ASSERT assert
|
|
#endif //ASSERT
|
|
|
|
PTSTR *
|
|
CommandLineToArgv(
|
|
PCTSTR pCmdLine,
|
|
int *pNumArgs
|
|
);
|
|
|
|
#ifdef IMPLEMENT_ARGV
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Parse_Cmdline
|
|
//
|
|
// Stolen directly from NT sources
|
|
//
|
|
|
|
void Parse_Cmdline (
|
|
LPCTSTR cmdstart,
|
|
LPTSTR*argv,
|
|
LPTSTR lpstr,
|
|
INT *numargs,
|
|
INT *numbytes
|
|
)
|
|
{
|
|
LPCTSTR p;
|
|
TCHAR c;
|
|
INT inquote; /* 1 = inside quotes */
|
|
INT copychar; /* 1 = copy char to *args */
|
|
WORD numslash; /* num of backslashes seen */
|
|
|
|
*numbytes = 0;
|
|
*numargs = 1; /* the program name at least */
|
|
|
|
/* first scan the program name, copy it, and count the bytes */
|
|
p = cmdstart;
|
|
if (argv)
|
|
*argv++ = lpstr;
|
|
|
|
/* A quoted program name is handled here. The handling is much
|
|
simpler than for other arguments. Basically, whatever lies
|
|
between the leading double-quote and next one, or a terminal null
|
|
character is simply accepted. Fancier handling is not required
|
|
because the program name must be a legal NTFS/HPFS file name.
|
|
Note that the double-quote characters are not copied, nor do they
|
|
contribute to numbytes. */
|
|
if (*p == TEXT('\"'))
|
|
{
|
|
/* scan from just past the first double-quote through the next
|
|
double-quote, or up to a null, whichever comes first */
|
|
while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
|
|
{
|
|
*numbytes += sizeof(TCHAR);
|
|
if (lpstr)
|
|
*lpstr++ = *p;
|
|
}
|
|
/* append the terminating null */
|
|
*numbytes += sizeof(TCHAR);
|
|
if (lpstr)
|
|
*lpstr++ = TEXT('\0');
|
|
|
|
/* if we stopped on a double-quote (usual case), skip over it */
|
|
if (*p == TEXT('\"'))
|
|
p++;
|
|
}
|
|
else
|
|
{
|
|
/* Not a quoted program name */
|
|
do {
|
|
*numbytes += sizeof(TCHAR);
|
|
if (lpstr)
|
|
*lpstr++ = *p;
|
|
|
|
c = (TCHAR) *p++;
|
|
|
|
} while (c > TEXT(' '));
|
|
|
|
if (c == TEXT('\0'))
|
|
{
|
|
p--;
|
|
}
|
|
else
|
|
{
|
|
if (lpstr)
|
|
*(lpstr - 1) = TEXT('\0');
|
|
}
|
|
}
|
|
|
|
inquote = 0;
|
|
|
|
/* loop on each argument */
|
|
for ( ; ; )
|
|
{
|
|
if (*p)
|
|
{
|
|
while (*p == TEXT(' ') || *p == TEXT('\t'))
|
|
++p;
|
|
}
|
|
|
|
if (*p == TEXT('\0'))
|
|
break; /* end of args */
|
|
|
|
/* scan an argument */
|
|
if (argv)
|
|
*argv++ = lpstr; /* store ptr to arg */
|
|
++*numargs;
|
|
|
|
/* loop through scanning one argument */
|
|
for ( ; ; )
|
|
{
|
|
copychar = 1;
|
|
/* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
|
|
2N+1 backslashes + " ==> N backslashes + literal "
|
|
N backslashes ==> N backslashes */
|
|
numslash = 0;
|
|
while (*p == TEXT('\\'))
|
|
{
|
|
/* count number of backslashes for use below */
|
|
++p;
|
|
++numslash;
|
|
}
|
|
if (*p == TEXT('\"'))
|
|
{
|
|
/* if 2N backslashes before, start/end quote, otherwise
|
|
copy literally */
|
|
if (numslash % 2 == 0)
|
|
{
|
|
if (inquote)
|
|
if (p[1] == TEXT('\"'))
|
|
p++; /* Double quote inside quoted string */
|
|
else /* skip first quote char and copy second */
|
|
copychar = 0;
|
|
else
|
|
copychar = 0; /* don't copy quote */
|
|
|
|
inquote = !inquote;
|
|
}
|
|
numslash /= 2; /* divide numslash by two */
|
|
}
|
|
|
|
/* copy slashes */
|
|
while (numslash--)
|
|
{
|
|
if (lpstr)
|
|
*lpstr++ = TEXT('\\');
|
|
*numbytes += sizeof(TCHAR);
|
|
}
|
|
|
|
/* if at end of arg, break loop */
|
|
if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
|
|
break;
|
|
|
|
/* copy character into argument */
|
|
if (copychar)
|
|
{
|
|
if (lpstr)
|
|
*lpstr++ = *p;
|
|
*numbytes += sizeof(TCHAR);
|
|
}
|
|
++p;
|
|
}
|
|
|
|
/* null-terminate the argument */
|
|
|
|
if (lpstr)
|
|
*lpstr++ = TEXT('\0'); /* terminate string */
|
|
*numbytes += sizeof(TCHAR);
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CommandLineToArgv
|
|
//
|
|
|
|
PTSTR *
|
|
CommandLineToArgv(
|
|
PCTSTR pCmdLine,
|
|
int *pNumArgs
|
|
)
|
|
{
|
|
ASSERT(pNumArgs);
|
|
|
|
INT numbytes = 0;
|
|
|
|
Parse_Cmdline(pCmdLine, 0, 0, pNumArgs, &numbytes);
|
|
|
|
PTSTR *argv = (PTSTR *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
*pNumArgs * sizeof(PTSTR) + numbytes
|
|
);
|
|
|
|
if (argv)
|
|
{
|
|
Parse_Cmdline(
|
|
pCmdLine,
|
|
argv,
|
|
(PTSTR) ((PBYTE) argv + *pNumArgs * sizeof(PTSTR)),
|
|
pNumArgs,
|
|
&numbytes
|
|
);
|
|
}
|
|
|
|
return argv;
|
|
}
|
|
|
|
#endif //IMPLEMENT_ARGV
|
|
|
|
#endif //__ARGV_H
|