/********************************************************************/ /** 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 #include #include #include #include #include #include #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; }