Esempio n. 1
0
void rtrimcl(char * const str)
{ char *p;

  assert(str);

  p = strchr(str, '\0');
  while (--p >= str && isargdelim(*p))
    ;
  p[1] = '\0';
}
Esempio n. 2
0
char *ltrimcl(const char *str)
{ char c;

  assert(str);

  while ((c = *str++) != '\0' && isargdelim(c))
    ;

  return (char *)str - 1;		/* strip const */
}
Esempio n. 3
0
char *skipQuoteArg(const char * const pp)
{
	char *p;

	assert(pp);

	p = (char*)pp - 1;
	while(*(p = skipquote(p + 1)) != 0 && !isargdelim(*p));

	return p;
}
Esempio n. 4
0
char *skipqword(const char *pp, const char * const stop)
{	size_t len;
	int quote = 0;

	len = stop? strlen(stop): 0;

	if(*pp) do {
		if(quote) {
			if(quote == *pp)
				quote = 0;
		} else if(strchr(QUOTE_STR, *pp))
			quote = *pp;
		else if(len? (memcmp(pp, stop, len) == 0): isargdelim(*pp))
			break;
	} while(*++pp);

	return (char *) pp;		/* strip const */
}
Esempio n. 5
0
File: if.c Progetto: FDOS/freecom
int cmd_if(char *param)
{

#define X_EXEC 1

	char *pp;

	int x_flag = 0;       /* when set cause 'then' clause to be exec'ed */
	int negate = 0;       /* NOT keyword present */
	int ignore_case = 0;  /* /I option, case insensitive compare */


	/* First check if param exists */
	assert(param);

	/* check for options, note non-options must be treated as part of comparision */
      if (matchtok(param, "/I")||matchtok(param, "/i"))
        ignore_case++;

	/* next check if param string begins with word 'not' */
	if(matchtok(param, "not"))
		negate = X_EXEC;            /* Remember 'NOT' */

	/* Check for 'exist' form */

	if(matchtok(param, "exist")) {
		struct dos_ffblk f;
		isr olderrhandler;

		if(!*param) {
			/* syntax error */
			error_if_exist();
			return 0;
		}

		pp = skip_word(param);
		*pp++ = '\0';

		/* don't show abort/retry/fail if no disk in drive */
		get_isr(0x24, olderrhandler);
#ifdef XMS_SWAP
		set_isrfct(0x24, autofail_err_handler);  /* always fails */
#else
		set_isrfct(0x24, dummy_criter_handler);  /* always fails */
#endif

		if(dos_findfirst(param, &f, FA_NORMAL|FA_ARCH|FA_SYSTEM|FA_RDONLY|FA_HIDDEN) == 0)
			x_flag = X_EXEC;
		dos_findclose(&f);
        
		/* restore critical error handler */
		set_isrfct(0x24, olderrhandler);
	}

	/* Check for 'errorlevel' form */

	else if(matchtok(param, "errorlevel")) {
		int n = 0;

#if 0
		if(!isdigit(*param)) {
			error_if_errorlevel();
			return 0;
		}

		pp = param;
		do  n = n * 10 + (*pp - '0');
		while (isdigit(*++pp));

		if(*pp && !isargdelim(*pp)) {
			error_if_errorlevel_number();
			return 0;
		}
#else
		/* Add this COMMAND bug as someone tries to use:
			IF ERRORLEVEL H<upper-case_letter>
			-or-
			IF ERRORLEVEL x<lower-case_letter>

			to match the errorlevel against drive letters.
			NOT supported by 4dos or WinNT.

			HA --> maps to errorlevel 1
			xa --> same

			HB & xb --> to 2
			a.s.o.
		*/

		if(!*param) {
			error_if_errorlevel();
			return 0;
		}
		pp = param;
		do  n = n * 10 + (*pp - '0');
		while(*++pp && !isargdelim(*pp));
		n &= 255;
		dprintf( ("IF: checking for ERRORLEVEL >= %u\n", n) );
#endif

		if(errorlevel >= n)
			x_flag = X_EXEC;
	}

	/* Check that '==' is present, syntax error if not */
	else {
		size_t len;
		char *r;      /* right operand */

		pp = skipqword(param, "==");

		if(*pp != '=' || pp[1] != '=') {
			error_syntax(0);
			return 0;
		}

		*pp = '\0';     /* param[] points to the left operand */

		/* skip over the '==' and subsquent spaces and
			assign the end of the right operator to pp */
		pp = skipqword(r = ltrimcl(pp + 2), 0);

		/*	now: param := beginning of the left operand
			r := beginning of the right operand
			pp := end of right operand
		*/

		rtrimcl(param);      /* ensure that spurious whitespaces are ignored */
		len = strlen(param);

		/* check if strings differ */
		if ( ((pp - r) == len) &&
		     ((ignore_case && strnicmp(param, r, len) == 0) ||
		      (memcmp(param, r, len) == 0)) )
			x_flag = X_EXEC;
	}

	if(x_flag ^ negate)		/* perform the command */
		if(!*(pp = ltrimcl(pp)))
			error_if_command();
		else
			parsecommandline(pp, FALSE);

	return 0;
}
Esempio n. 6
0
/*
 * do the prompt/input/process loop
 *
 *  If xflg is true, the function will not go interactive, but returns.
 *  If commandline != NULL, this command is processed first.
 *
 *  Return: 0: on success
 */
int process_input(int xflag, char *commandline)
{
    /* Dimensionate parsedline that no sprintf() can overflow the buffer
     */
  char parsedline[MAX_INTERNAL_COMMAND_SIZE + sizeof(errorlevel) * 8]
    , *readline;
#if 0
/* Return the maximum pointer into parsedline to add 'numbytes' bytes */
#define parsedMax(numbytes)   \
  (parsedline + MAX_INTERNAL_COMMAND_SIZE - 1 - (numbytes))
  char *evar;
  char *tp;
  char *cp;
#endif
  char *ip;
#if 0
  char forvar;
#endif
  int echothisline;
  int tracethisline;

  do
  {
#ifdef FEATURE_LONG_FILENAMES
    if( toupper( *getEnv( "LFN" ) ) == 'N' )
         __supportlfns = 0;
    else __supportlfns = 1;
#endif
  	interactive_command = 0;		/* not directly entered by user */
  	echothisline = tracethisline = 0;
    if(commandline) {
      ip = commandline;
      readline = commandline = 0;
    } else {
    if ((readline = malloc(MAX_INTERNAL_COMMAND_SIZE + 1)) == 0)
    {
      error_out_of_memory();
      return 1;
    }

      if (0 == (ip = readbatchline(&echothisline, readline,
                      MAX_INTERNAL_COMMAND_SIZE)))
      { /* if no batch input then... */
      if (xflag   /* must not go interactive */
       || (fdattr(0) & 0x84) == 0x84  /* input is NUL device */
       || feof(stdin))    /* no further input */
      {
        free(readline);
        break;
      }

      /* Go Interactive */
		interactive_command = 1;		/* directly entered by user */
		/* Ensure the prompt starts at column #0 */
		if(echo && (mywherex()>1))
			outc('\n');
      readcommand(ip = readline, MAX_INTERNAL_COMMAND_SIZE);
      tracemode = 0;          /* reset trace mode */
      }
    }

    	/* Make sure there is no left-over from last run */
    currCmdHelpScreen = 0;

    /* 
     * The question mark '?' has a double meaning:
     *	C:\> ?
     *		==> Display short help
     *
     *	C:\> ? command arguments
     *		==> enable tracemode for just this line
     */
    if(*(ip = ltrimcl(ip)) == '?') {
    	 ip = ltrimcl(ip + 1);
    	 if(!*ip) {		/* is short help command */
#ifdef INCLUDE_CMD_QUESTION
    	 	showcmds(ip);
#endif
			free(readline);
			continue;
		}
		/* this-line-tracemode */
		echothisline = 0;
		tracethisline = 1;
	}

#if 0
  /* The FOR hack
    If the line matches /^\s*for\s+\%[a-z]\s/, the FOR hack
    becomes active, because FOR requires the sequence "%<ch>"
    in its input.
    When the percent (%) expansion is made later on, any
    sequence "%<ch>" is retained.
  */
  cp = ip;
  if(matchtok(cp, "for") && *cp == '%' && isalpha(cp[1])
   && isargdelim(cp[2]))   /* activate FOR hack */
    forvar = toupper(cp[1]);
  else forvar = 0;

#else
	if(cmd_for_hackery(ip)) {
		free(readline);
		continue;
	}
#endif

	{	int rc = expandEnvVars(ip, parsedline);
		free(readline);
		if(!rc) {
			error_line_too_long();
			continue;
		}
	}
  
    if (echothisline)           /* Echo batch file line */
    {
      printprompt();
      puts(parsedline);
    }

    if (*parsedline)
    {
      if(swapOnExec != ERROR)
      	swapOnExec = defaultToSwap;
      if(tracethisline)
      	++tracemode;
      parsecommandline(parsedline, TRUE);
      if(tracethisline)
      	--tracemode;
    }
  }
  while (!canexit || !exitflag);

  return 0;
}
Esempio n. 7
0
static void docommand(char *line)
{
  /*
   * look through the internal commands and determine whether or not this
   * command is one of them.  If it is, call the command.  If not, call
   * execute to run it as an external program.
   *
   * line - the command line of the program to run
   */
  char *cp;
  char *rest;            /* pointer to the rest of the command line */
  struct CMD *cmdptr = 0;

#ifdef FEATURE_INSTALLABLE_COMMANDS
	/* Duplicate the command line into such buffer in order to
		allow Installable Commands to alter the command line.
		*line cannot be modified as pipes would be destroyed. */
	/* Place both buffers immediately following each other in
		order to make sure the contents of args can be appended
		to com without any buffer overflow checks.
		*2 -> one buffer for com and one for args
		+2 -> max length byte of com + cur length of com
		+3 -> max length byte of args + cur length of args + additional '\0'
	*/
	char *buf = malloc(2+2*BUFFER_SIZE_MUX_AE+2+1);
#define args  (buf + 2)
#define ARGS_BUFFER_SIZE (2 + BUFFER_SIZE_MUX_AE + 3)
#define com (buf + ARGS_BUFFER_SIZE)
#define BUFFER_SIZE BUFFER_SIZE_MUX_AE
#else
	char *com = malloc(MAX_INTERNAL_COMMAND_SIZE);
#define args line
#define buf com
#define BUFFER_SIZE MAX_INTERNAL_COMMAND_SIZE
#endif

  assert(line);

	if(!buf) {
	  error_out_of_memory();
	  return;
	}

  /* delete leading spaces, but keep trailing whitespaces */
  line = ltrimcl(line);

#ifdef FEATURE_INSTALLABLE_COMMANDS
#if BUFFER_SIZE < MAX_INTERNAL_COMMAND_SIZE
	if(strlen(line) > BUFFER_SIZE) {
		error_line_too_long();
		goto errRet;
	}
#endif
	strcpy(args, line);
#endif

  if (*(rest = args))                    /* Anything to do ? */
  {
    cp = com;

  /* Copy over 1st word as upper case */
  /* Internal commands are constructed out of non-delimiter
  	characters; ? had been parsed already */
    while(*rest && is_fnchar(*rest) && !strchr(QUOTE_STR, *rest))
      *cp++ = toupper(*rest++);

    if(*rest && strchr(QUOTE_STR, *rest))
      /* If the first word is quoted, it is no internal command */
      cp = com;   /* invalidate it */
    *cp = '\0';                 /* Terminate first word */

	if(*com) {
#ifdef FEATURE_INSTALLABLE_COMMANDS
		int tryMUXAE;
		for(tryMUXAE = MUX_AE_MAX_REPEAT_CALL; tryMUXAE > 0; --tryMUXAE) {
			/* Check for installed COMMAND extension */
			switch(runExtension(com, args)) {
				case 1:		/* OK, done */
					goto errRet;
				case 0:		/* no extension */
					tryMUXAE = 0;
			}
			/* reset the argument pointer */
			rest = &args[(unsigned char)com[-1]];

			dprintf( ("[Command on return of Installable Commands check: >%s]\n", com) );
#ifndef NDEBUG
			dprintf( ("[Command line: >") );
			for(cp = args; cp < rest; ++cp)
				dprintf( ("%c", *cp) );
			dprintf( ("|%s]\n", rest) );
#endif	/* !defined(NDEBUG) */

#endif

		/* Scan internal command table */
		for (cmdptr = internalCommands
		 ; cmdptr->name && strcmp(com, cmdptr->name) != 0
		 ; cmdptr++);

    if(cmdptr && cmdptr->name) {    /* internal command found */

#ifdef FEATURE_INSTALLABLE_COMMANDS
	cp = realloc(buf, ARGS_BUFFER_SIZE);
#ifndef NDEBUG
	if(cp != buf) {
		dprintf( ("[INTERNAL error: realloc() returned wrong result]") );
		buf = cp;
	}
#endif
#else
	free(buf);  buf = 0;	/* no further useage of this buffer */
#endif
      switch(cmdptr->flags & (CMD_SPECIAL_ALL | CMD_SPECIAL_DIR)) {
      case CMD_SPECIAL_ALL: /* pass everything into command */
        break;
      case CMD_SPECIAL_DIR: /* pass '\\' & '.' too */
        if(*rest == '\\' || *rest == '.' || *rest == ':') break;
      default:        /* pass '/', ignore ',', ';' & '=' */
        if(!*rest || *rest == '/') break;
        if(isargdelim(*rest)) {
			rest = ltrimcl(rest);
			break;
		}

        /* else syntax error */
        error_syntax(0);
        goto errRet;
      }

        currCmdHelpScreen = cmdptr->help_id;
        /* JPP this will print help for any command */
        if(memcmp(ltrimcl(rest), "/?", 2) == 0)  {
          displayString(currCmdHelpScreen);
        } else {
          dprintf(("CMD '%s' : '%s'\n", cmdptr->name, rest));
          cmdptr->func(rest);
        }
        goto errRet;
	}
#ifdef FEATURE_INSTALLABLE_COMMANDS
	  }
#endif
      }

        free(buf); buf = 0;		/* no longer used */
        /* no internal command --> spawn an external one */
        cp = unquote(line, rest = skip_word(line));
        if(!cp) {
          error_out_of_memory();
          goto errRet;
        }
		execute(cp, rest);
		free(cp);
      }

#undef com
#undef args
#undef BUFFER_SIZE
#undef ARGS_BUFFER_SIZE

errRet:
	  free(buf);
}
Esempio n. 8
0
File: redir.c Progetto: FDOS/freecom
int get_redirection(char *s, char **ifn, char **ofn, int *ofatt)
{
  /*
   * Gets the redirection info from the command line and copies the
   * file names into ifn and ofn removing them from the command line.
   * The names are allocated here and passed back to the caller, on
   * malloc() failure, -1 is returned. These names are trimmed,
   * meaning they do not contain any leading or trailing whitespaces.
   *
   * Converts remaining command line into a series of null terminated
   * strings defined by the pipe char '|'. Each string corresponds
   * to a single executable command. A double null terminates the
   * command strings.
   *
   * Check for, but do not implement, output append redirect.
   *
   * Return number of command strings found.
   *
   */

  int num = 1;
  int ch;

  char *dp = s;
  char *sp = s;

  assert(s);
  assert(ifn);
  assert(ofn);
  assert(ofatt);

  /* find and remove all the redirections first */

  while ((ch = *dp++ = *sp++) != 0)
    switch (ch)
    {
      case '"':               /* No redirects inside quotes */
/*      case '\'':			single quotes don't quote ska*/
        {
          char *p;
          int len;

          /* If there is no closing quote, then go to end of line. */
          if ((p = strchr(sp, ch)) == 0)
          {
            p = sp + strlen(sp) - 1;
          }

          /* closing quote found, move that area */
          /* need memmove() because both areas overlap each other */
          memmove(dp, sp, len = p - sp + 1);
          dp += len;
          sp += len;

        }
        break;

      case '<':
      case '>':
        {
          /* MS-DOS ignores multiple redirection symbols and uses the last */
          /* redirection, so we'll emulate that and not check */

          char **op = (ch == '<') ? ifn : ofn;
          char *p;

          if ((ch == '>') && (*sp == '>'))      /* Append request ? */
          {
            *ofatt = O_CREAT | O_APPEND | O_WRONLY;
            sp++;
          }

          p = sp = ltrimcl(sp);

          while (*sp && !is_redir(*sp) && !isargdelim(*sp)) ++sp;
          free(*op);            /* ignore any previous one */
          ch = *sp;
          *sp = '\0';
          if ((*op = strdup(p)) == 0)
          {                     /* out of mem */
            error_out_of_memory();
            return -1;
          }

          *sp = ch;
          --dp;                 /* ignore the already copied '<' or '>' */
        }
        break;

      case '|':

        dp[-1] = '\0';          /* overwrite the already copied '|' */
        ++num;
        break;

    }                           /* end switch */

  return num;
}
Esempio n. 9
0
/*
 * do the prompt/input/process loop
 *
 *  If xflg is true, the function will not go interactive, but returns.
 *  If commandline != NULL, this command is processed first.
 *
 *  Return: 0: on success
 */
int process_input(int xflag, char *commandline)
{
    /* Dimensionate parsedline that no sprintf() can overflow the buffer
     */
  char parsedline[MAX_INTERNAL_COMMAND_SIZE + sizeof(errorlevel) * 8]
    , *readline;
/* Return the maximum pointer into parsedline to add 'numbytes' bytes */
#define parsedMax(numbytes)   \
  (parsedline + MAX_INTERNAL_COMMAND_SIZE - 1 - (numbytes))
  char *evar;
  char *tp;
  char *ip;
  char *cp;
  char forvar;
  int echothisline;
  int tracethisline;

  do
  {
  	interactive_command = 0;		/* not directly entered by user */
  	echothisline = tracethisline = 0;
    if(commandline) {
      ip = commandline;
      readline = commandline = 0;
    } else {
    if ((readline = malloc(MAX_INTERNAL_COMMAND_SIZE + 1)) == 0)
    {
      error_out_of_memory();
      return 1;
    }

      if (0 == (ip = readbatchline(&echothisline, readline,
                      MAX_INTERNAL_COMMAND_SIZE)))
      { /* if no batch input then... */
      if (xflag   /* must not go interactive */
       || (fdattr(0) & 0x84) == 0x84  /* input is NUL device */
       || feof(stdin))    /* no further input */
      {
        free(readline);
        break;
      }

      /* Go Interactive */
		interactive_command = 1;		/* directly entered by user */
      readcommand(ip = readline, MAX_INTERNAL_COMMAND_SIZE);
      tracemode = 0;          /* reset trace mode */
      }
    }

    /* 
     * The question mark '?' has a double meaning:
     *	C:\> ?
     *		==> Display short help
     *
     *	C:\> ? command arguments
     *		==> enable tracemode for just this line
     */
    if(*(ip = ltrimcl(ip)) == '?') {
    	 ip = ltrimcl(ip + 1);
    	 if(!*ip) {		/* is short help command */
#ifdef INCLUDE_CMD_QUESTION
    	 	showcmds(ip);
#endif
			free(readline);
			continue;
		}
		/* this-line-tracemode */
		echothisline = 0;
		tracethisline = 1;
	}

  /* The FOR hack
    If the line matches /^\s*for\s+\%[a-z]\s/, the FOR hack
    becomes active, because FOR requires the sequence "%<ch>"
    in its input.
    When the percent (%) expansion is made later on, any
    sequence "%<ch>" is retained.
  */
  cp = ip;
  if(matchtok(cp, "for") && *cp == '%' && isalpha(cp[1])
   && isargdelim(cp[2]))   /* activate FOR hack */
    forvar = toupper(cp[1]);
  else forvar = 0;

  cp = parsedline;
    while (*ip)
    {
      /* Assume that at least one character is added, place the
        test here to simplify the switch() statement */
      if(cp >= parsedMax(1)) {
        cp = 0;    /* error condition */
        break;
      }
      if (*ip == '%')
      {
        switch (*++ip)
        {
          case '\0':    /* FOR hack forvar == 0 if no FOR is active */
            *cp++ = '%';
            break;

          case '%':
            *cp++ = *ip++;
            break;

          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            if (0 != (tp = find_arg(*ip - '0')))
            {
              if(cp >= parsedMax(strlen(tp))) {
                cp = 0;
                goto intBufOver;
              }
              cp = stpcpy(cp, tp);
              ip++;
            }
            else
              *cp++ = '%';
              /* Let the digit be copied in the cycle */

            break;

          case '?':
            /* overflow check: parsedline has that many character
              "on reserve" */
            cp += sprintf(cp, "%u", errorlevel);
            ip++;
            break;

          default:
            if(forvar == toupper(*ip)) {    /* FOR hack */
              *cp++ = '%';			/* let the var be copied in next cycle */
              break;
            }
            if ((tp = strchr(ip, '%')) != 0)
            {
              *tp = '\0';

              if ((evar = getEnv(ip)) != 0) {
                if(cp >= parsedMax(strlen(evar))) {
                  cp = 0;
                  goto intBufOver;
                }
                cp = stpcpy(cp, evar);
               }

              ip = tp + 1;
            }
            break;
        }
        continue;
      }

      if (iscntrl(*ip)) {
        *cp++ = ' ';
        ++ip;
      } else 
      	*cp++ = *ip++;
    }

intBufOver:
    free(readline);

  if(!cp) {     /* internal buffer overflow */
    error_line_too_long();
    continue;
  }

    *cp = '\0';   /* terminate copied string */

    if (echothisline)           /* Echo batch file line */
    {
      printprompt();
      puts(parsedline);
    }

    if (*parsedline)
    {
      if(swapOnExec != ERROR)
      	swapOnExec = defaultToSwap;
      if(tracethisline)
      	++tracemode;
      parsecommandline(parsedline);
      if(tracethisline)
      	--tracemode;
      if (echothisline || echo)
        putchar('\n');
    }
  }
  while (!canexit || !exitflag);

  return 0;
}
Esempio n. 10
0
static void docommand(char *line)
{
  /*
   * look through the internal commands and determine whether or not this
   * command is one of them.  If it is, call the command.  If not, call
   * execute to run it as an external program.
   *
   * line - the command line of the program to run
   */

#ifdef FEATURE_INSTALLABLE_COMMANDS
	/* Duplicate the command line into such buffer in order to
		allow Installable Commands to alter the command line.
		*line cannot be modified as pipes would be destroyed. */
	/* Place both buffers immediately following each other in
		order to make sure the contents of args can be appended
		to com without any buffer overflow checks.
		*2 -> one buffer for com and one for args
		+2 -> max length byte of com + cur length of com
		+3 -> max length byte of args + cur length of args + additional '\0'
	*/
	char buf[2+2*BUFFER_SIZE_MUX_AE+2+1];
#define com  (buf + 2)
#define args (buf + 2 + BUFFER_SIZE_MUX_AE + 2)
#define BUFFER_SIZE BUFFER_SIZE_MUX_AE
#else
	char com[MAX_INTERNAL_COMMAND_SIZE];
#define BUFFER_SIZE MAX_INTERNAL_COMMAND_SIZE
#endif
  char *cp;
  char *rest;            /* pointer to the rest of the command line */

  struct CMD *cmdptr;

  assert(line);

  /* delete leading spaces, but keep trailing whitespaces */
  line = ltrimcl(line);

#ifdef FEATURE_INSTALLABLE_COMMANDS
#if BUFFER_SIZE < MAX_INTERNAL_COMMAND_SIZE
	if(strlen(line) > BUFFER_SIZE) {
		error_line_too_long();
		return;
	}
#endif
	line = strcpy(args, line);
#endif

  if (*(rest = line))                    /* Anything to do ? */
  {
    cp = com;

  /* Copy over 1st word as lower case */
  /* Internal commands are constructed out of non-delimiter
  	characters; ? had been parsed already */
    while(*rest && is_fnchar(*rest) && !strchr(QUOTE_STR, *rest))
      *cp++ = toupper(*rest++);

    if(*rest && strchr(QUOTE_STR, *rest))
      /* If the first word is quoted, it is no internal command */
      cp = com;   /* invalidate it */
    *cp = '\0';                 /* Terminate first word */

	if(*com) {
#ifdef FEATURE_INSTALLABLE_COMMANDS
		/* Check for installed COMMAND extension */
		if(runExtension(com, args))
			return;		/* OK, executed! */

		dprintf( ("[Command on return of Installable Commands check: >%s<]\n", com) );
#endif

		/* Scan internal command table */
		for (cmdptr = internalCommands
		 ; cmdptr->name && strcmp(com, cmdptr->name) != 0
		 ; cmdptr++);

	}

    if(*com && cmdptr->name) {    /* internal command found */
      switch(cmdptr->flags & (CMD_SPECIAL_ALL | CMD_SPECIAL_DIR)) {
      case CMD_SPECIAL_ALL: /* pass everything into command */
        break;
      case CMD_SPECIAL_DIR: /* pass '\\' & '.' too */
        if(*rest == '\\' || *rest == '.' || *rest == ':') break;
      default:        /* pass '/', ignore ',', ';' & '=' */
        if(!*rest || *rest == '/') break;
        if(isargdelim(*rest)) {
			rest = ltrimcl(rest);
			break;
		}

        /* else syntax error */
        error_syntax(0);
        return;
      }

        /* JPP this will print help for any command */
        if (strstr(rest, "/?"))
        {
          displayString(cmdptr->help_id);
        }
        else
        {
          dprintf(("CMD '%s' : '%s'\n", com, rest));
          cmdptr->func(rest);
        }
      } else {
#ifdef FEATURE_INSTALLABLE_COMMANDS
		if(*com) {		/* external command */
			/* Installable Commands are allowed to change both:
				"com" and "args". Therefore, we may need to
				reconstruct the external command line */
			/* Because com and *rest are located within the very same
				buffer and rest is definitely terminated with '\0',
				the followinf memmove() operation is fully robust
				against buffer overflows */
			memmove(com + strlen(com), rest, strlen(rest) + 1);
			/* Unsave, but probably more efficient operation:
				strcat(com, rest);
					-- 2000/12/10 ska*/
			line = com;
		}
#endif
        /* no internal command --> spawn an external one */
        cp = unquote(line, rest = skip_word(line));
        if(!cp) {
          error_out_of_memory();
          return;
        }
		execute(cp, ltrimsp(rest));
		free(cp);
      }
  }
#undef line
#undef com
#undef args
#undef BUFFER_SIZE
}