cmd->words[cmd->nwords++] = q;
cmd->words[cmd->nwords++] = dupstr(q);
struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags){    char *line;    int linelen, linesize;    struct sftp_command *cmd;    char *p, *q, *r;    int quoting;    if ((mode == 0) || (modeflags & 1)) {	printf("psftp> ");    }    fflush(stdout);    cmd = snew(struct sftp_command);    cmd->words = NULL;    cmd->nwords = 0;    cmd->wordssize = 0;    line = NULL;    linesize = linelen = 0;    while (1) {	int len;	char *ret;	linesize += 512;	line = sresize(line, linesize, char);	ret = fgets(line + linelen, linesize - linelen, fp);	if (!ret || (linelen == 0 && line[0] == '\0')) {	    cmd->obey = sftp_cmd_quit;	    if ((mode == 0) || (modeflags & 1))		printf("quit\n");	    return cmd;		       /* eof */	}	len = linelen + strlen(line + linelen);	linelen += len;	if (line[linelen - 1] == '\n') {	    linelen--;	    line[linelen] = '\0';	    break;	}    }    if (modeflags & 1) {	printf("%s\n", line);    }    p = line;    while (*p && (*p == ' ' || *p == '\t'))	p++;    if (*p == '!') {	/*	 * Special case: the ! command. This is always parsed as	 * exactly two words: one containing the !, and the second	 * containing everything else on the line.	 */	cmd->nwords = cmd->wordssize = 2;	cmd->words = sresize(cmd->words, cmd->wordssize, char *);	cmd->words[0] = "!";	cmd->words[1] = p+1;    } else {	/*	 * Parse the command line into words. The syntax is:	 *  - double quotes are removed, but cause spaces within to be	 *    treated as non-separating.	 *  - a double-doublequote pair is a literal double quote, inside	 *    _or_ outside quotes. Like this:	 *	 *      firstword "second word" "this has ""quotes"" in" and""this""	 *	 * becomes	 *	 *      >firstword<	 *      >second word<	 *      >this has "quotes" in<	 *      >and"this"<	 */	while (*p) {	    /* skip whitespace */	    while (*p && (*p == ' ' || *p == '\t'))		p++;	    /* mark start of word */	    q = r = p;		       /* q sits at start, r writes word */	    quoting = 0;	    while (*p) {		if (!quoting && (*p == ' ' || *p == '\t'))		    break;		       /* reached end of word */		else if (*p == '"' && p[1] == '"')		    p += 2, *r++ = '"';    /* a literal quote */		else if (*p == '"')		    p++, quoting = !quoting;		else		    *r++ = *p++;	    }	    if (*p)		p++;		       /* skip over the whitespace */	    *r = '\0';	    if (cmd->nwords >= cmd->wordssize) {		cmd->wordssize = cmd->nwords + 16;		cmd->words = sresize(cmd->words, cmd->wordssize, char *);	    }	    cmd->words[cmd->nwords++] = q;	}    }    /*     * Now parse the first word and assign a function.     */    if (cmd->nwords == 0)	cmd->obey = sftp_cmd_null;    else {	const struct sftp_cmd_lookup *lookup;	lookup = lookup_command(cmd->words[0]);	if (!lookup)	    cmd->obey = sftp_cmd_unknown;	else	    cmd->obey = lookup->obey;    }    return cmd;}