312 lines
7 KiB
C
312 lines
7 KiB
C
|
/********************************************************************/
|
||
|
/** Microsoft LAN Manager **/
|
||
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
||
|
/********************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Switches.c - switch handling routines
|
||
|
*
|
||
|
* ??/??/??, ??????, initial code
|
||
|
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
|
||
|
* 12/04/88, erichn, DOS LM integration
|
||
|
* 06/08/89, erichn, canonicalization sweep, stronger typing
|
||
|
* 02/20/91, danhi, change to use lm 16/32 mapping layer
|
||
|
*/
|
||
|
|
||
|
|
||
|
#define INCL_NOCOMMON
|
||
|
#include <os2.h>
|
||
|
#include <apperr.h>
|
||
|
#include <lmerr.h>
|
||
|
#include <stdio.h>
|
||
|
#include <process.h>
|
||
|
#include <ctype.h>
|
||
|
#include <malloc.h>
|
||
|
#include "netcmds.h"
|
||
|
#include "nettext.h"
|
||
|
|
||
|
/* External variables */
|
||
|
|
||
|
int DOSNEAR FASTCALL firstswitch(TCHAR *known)
|
||
|
{
|
||
|
if (SwitchList[0] == NULL)
|
||
|
return 0;
|
||
|
if (sw_compare(known, SwitchList[0]) >= 0)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Is the cmd line a valid form of NET ADMIN /C
|
||
|
*/
|
||
|
int DOSNEAR FASTCALL IsAdminCommand(VOID)
|
||
|
{
|
||
|
if (!SwitchList[0] || !ArgList[1])
|
||
|
return 0;
|
||
|
_tcsupr(SwitchList[0]);
|
||
|
return (IsComputerName(ArgList[1]) &&
|
||
|
(sw_compare(swtxt_SW_ADMIN_COMMAND, SwitchList[0]) >= 0));
|
||
|
}
|
||
|
|
||
|
/*** noswitch, oneswitch, twoswitch
|
||
|
*
|
||
|
* noswitch() Returns TRUE is no switches on the command line
|
||
|
* oneswitch() Returns TRUE is there is exactly one switch
|
||
|
* twoswitch() Returns TRUE is there are exactly two switches
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int DOSNEAR FASTCALL noswitch(VOID)
|
||
|
{
|
||
|
return (SwitchList[0] == NULL);
|
||
|
}
|
||
|
|
||
|
int DOSNEAR FASTCALL oneswitch(VOID)
|
||
|
{
|
||
|
return ((SwitchList[0] != NULL) && (SwitchList[1] == NULL));
|
||
|
}
|
||
|
|
||
|
int DOSNEAR FASTCALL twoswitch(VOID)
|
||
|
{
|
||
|
return ((SwitchList[0] != NULL) && (SwitchList[1] != NULL)
|
||
|
&& (SwitchList[2] == NULL));
|
||
|
}
|
||
|
|
||
|
/*** noswitch_optional, oneswitch_optional
|
||
|
*
|
||
|
* as above, except that the switch provided as argument is considered
|
||
|
* an optional switch that will be allowed. So if you say
|
||
|
* oneswitch_optional("/FOO"), then one switch (any switch) is OK,
|
||
|
* and so is two switches if one of them is "/FOO".
|
||
|
*/
|
||
|
int DOSNEAR FASTCALL noswitch_optional(TCHAR *optional_switch )
|
||
|
{
|
||
|
return ( noswitch() ||
|
||
|
( oneswitch() &&
|
||
|
(sw_compare(optional_switch, SwitchList[0]) >= 0) )
|
||
|
) ;
|
||
|
}
|
||
|
|
||
|
int DOSNEAR FASTCALL oneswitch_optional(TCHAR *optional_switch )
|
||
|
{
|
||
|
return ( oneswitch() ||
|
||
|
( twoswitch() &&
|
||
|
( (sw_compare(optional_switch, SwitchList[0]) >= 0) ||
|
||
|
(sw_compare(optional_switch, SwitchList[1]) >= 0) ) )
|
||
|
) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***
|
||
|
* o n l y s w i t c h
|
||
|
*
|
||
|
* Returns TRUE if the first switch matches the named switch, and it
|
||
|
* is the only switch.
|
||
|
*/
|
||
|
int DOSNEAR FASTCALL onlyswitch(TCHAR *known)
|
||
|
{
|
||
|
return (oneswitch() && firstswitch(known));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** ValidateSwitches
|
||
|
*
|
||
|
* Given a list of valid switches, check each entry in the switch
|
||
|
* list.
|
||
|
*
|
||
|
* This function not only checks for invalid switches, but also
|
||
|
* attempts to discern ambiguous usages. A usage is ambiguous if
|
||
|
* it does not match any valid swithc exactly, and it a partial
|
||
|
* match of more than one switch. See sw_compare(). This
|
||
|
* algorithm can be fooled by nasty lists of valid switches, such
|
||
|
* as one which lists the same switch twice.
|
||
|
*
|
||
|
* The function has been modified to canonicalize the SwitchList.
|
||
|
* It replaces an '=' in /x=value with a ':'; it translates
|
||
|
* switches if needed, (see switches.h); and it expands unambiguous
|
||
|
* partial matches to the full switch name.
|
||
|
*
|
||
|
* Returns:
|
||
|
* 1: All switches OK
|
||
|
* *: If any error, prints a message and exits.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int DOSNEAR FASTCALL ValidateSwitches(USHORT cmd, SWITCHTAB valid_list[])
|
||
|
{
|
||
|
USHORT match;
|
||
|
int comp_result;
|
||
|
USHORT candidate; /* most recent NEAR match */
|
||
|
USHORT i,j;
|
||
|
TCHAR * good_one; /* which element (cmd_line or trans) of the valid_list */
|
||
|
int needed;
|
||
|
TCHAR FAR * sepptr;
|
||
|
|
||
|
for (i = 0; SwitchList[i]; i++)
|
||
|
{
|
||
|
sepptr = _tcschr(SwitchList[i], ':');
|
||
|
if (sepptr)
|
||
|
*sepptr = NULLC;
|
||
|
_tcsupr(SwitchList[i]);
|
||
|
if (sepptr)
|
||
|
*sepptr = ':';
|
||
|
|
||
|
candidate = 0;
|
||
|
match = 0;
|
||
|
|
||
|
for (j = 0; valid_list[j].cmd_line; j++)
|
||
|
{
|
||
|
comp_result = sw_compare(valid_list[j].cmd_line, SwitchList[i]);
|
||
|
|
||
|
if (comp_result == 0)
|
||
|
{
|
||
|
candidate = j;
|
||
|
match = 1;
|
||
|
break;
|
||
|
}
|
||
|
else if (comp_result == 1)
|
||
|
{
|
||
|
match++;
|
||
|
candidate = j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (match == 0)
|
||
|
{
|
||
|
if (! _tcscmp(swtxt_SW_HELP, SwitchList[i]))
|
||
|
help_help(cmd, ALL);
|
||
|
|
||
|
if (! _tcscmp(swtxt_SW_SYNTAX, SwitchList[i]))
|
||
|
help_help(cmd, USAGE_ONLY);
|
||
|
|
||
|
IStrings[0] = SwitchList[i];
|
||
|
ErrorPrint(APE_SwUnkSw, 1);
|
||
|
help_help(cmd, USAGE_ONLY);
|
||
|
}
|
||
|
else if (match > 1)
|
||
|
{
|
||
|
IStrings[0] = SwitchList[i];
|
||
|
ErrorPrint(APE_SwAmbSw, 1);
|
||
|
help_help(cmd, USAGE_ONLY);
|
||
|
}
|
||
|
|
||
|
switch(valid_list[candidate].arg_ok)
|
||
|
{
|
||
|
case NO_ARG:
|
||
|
if (sepptr)
|
||
|
{
|
||
|
ErrorPrint(APE_InvalidSwitchArg, 0);
|
||
|
help_help(cmd, USAGE_ONLY);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ARG_OPT:
|
||
|
break;
|
||
|
|
||
|
case ARG_REQ:
|
||
|
if (!sepptr)
|
||
|
{
|
||
|
ErrorPrint(APE_InvalidSwitchArg, 0);
|
||
|
help_help(cmd, USAGE_ONLY);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* (expansion || translation) required ? */
|
||
|
if (comp_result || valid_list[candidate].translation)
|
||
|
{
|
||
|
if (valid_list[candidate].translation)
|
||
|
good_one = valid_list[candidate].translation;
|
||
|
else
|
||
|
good_one = valid_list[candidate].cmd_line;
|
||
|
|
||
|
needed = _tcslen(good_one);
|
||
|
|
||
|
if (sepptr)
|
||
|
needed += _tcslen(sepptr);
|
||
|
|
||
|
if ((SwitchList[i] = calloc(needed+1, sizeof(TCHAR))) == NULL)
|
||
|
ErrorExit(NERR_InternalError);
|
||
|
|
||
|
_tcscpy(SwitchList[i], good_one);
|
||
|
|
||
|
if (sepptr)
|
||
|
_tcscat(SwitchList[i], sepptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** sw_compare
|
||
|
*
|
||
|
* Compare a known switch name to a switch string passed from
|
||
|
* the command line.
|
||
|
*
|
||
|
* The command-line switch may still retain the "excess baggage"
|
||
|
* of a value (as in /B:1024). The comparison is not sensitive
|
||
|
* to case, and should be DBCS compatible as it uses the runtime
|
||
|
* library to do all searches and compares.
|
||
|
*
|
||
|
* Returns:
|
||
|
* -1: No match
|
||
|
* 0: Exact match to full length of known switch
|
||
|
* 1: Partial match; matches initial substring of
|
||
|
* known switch
|
||
|
*
|
||
|
* The difference between return 0/1 is used by ValidateSwitches()
|
||
|
* to detect the presence of a possibly ambiguous usage. Once
|
||
|
* that function has checked all switches, further compares can
|
||
|
* treat results 0 & 1 from this function as "match".
|
||
|
*/
|
||
|
|
||
|
int DOSNEAR FASTCALL sw_compare(TCHAR *known, TCHAR *cand)
|
||
|
{
|
||
|
register unsigned int complen;
|
||
|
|
||
|
/* Try to find end of switch name by looking */
|
||
|
/* the for separator between name and value, */
|
||
|
/* otherwise use total length. */
|
||
|
|
||
|
complen = _tcscspn(cand, TEXT(":"));
|
||
|
|
||
|
if (complen < 2) /* Special check for empty switch SLASH */
|
||
|
return -1;
|
||
|
|
||
|
if (complen > _tcslen(known))
|
||
|
return -1;
|
||
|
|
||
|
if (_tcsncmp(known,cand,complen) != 0)
|
||
|
return -1;
|
||
|
|
||
|
if (complen == _tcslen(known))
|
||
|
return 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Used only by interpre.c
|
||
|
*/
|
||
|
|
||
|
int DOSNEAR FASTCALL CheckSwitch(TCHAR *x)
|
||
|
{
|
||
|
register TCHAR **p;
|
||
|
|
||
|
for (p=SwitchList; *p; p++)
|
||
|
if (sw_compare(x,*p) >= 0)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|