in system/vi/vi.c [4215:4519]
static void vi_parsecolon(FAR struct vi_s *vi)
{
FAR const char *filename = NULL;
uint8_t cmd = CMD_NONE;
bool done = false;
bool forced;
int col;
int ch;
viinfo("Parse: \"%s\"\n", vi->scratch);
/* NUL terminate the command */
vi->scratch[vi->cmdlen] = '\0';
/* Convert "wq" into "qw" */
if (vi->cmdlen > 1 && vi->scratch[0] == KEY_COLMODE_WRITE &&
vi->scratch[1] == KEY_COLMODE_QUIT)
{
vi->scratch[0] = KEY_COLMODE_QUIT;
vi->scratch[1] = KEY_COLMODE_WRITE;
}
/* Then parse the contents of the scratch buffer */
for (col = 0; col < vi->cmdlen && !done; col++)
{
/* Get the next command character from the scratch buffer */
ch = vi->scratch[col];
/* Check if the next after that is KEY_COLMODE_FORCE */
forced = false;
if (col < vi->cmdlen && vi->scratch[col + 1] == KEY_COLMODE_FORCE)
{
/* Yes.. the operation is forced */
forced = true;
col++;
}
/* Then process the command character */
switch (ch)
{
case KEY_COLMODE_READ:
{
/* Reading a file should not be forced */
if (cmd == CMD_NONE && !forced)
{
cmd = CMD_READ;
}
else
{
/* The read operation is not compatible with writing or
* quitting
*/
goto errout_bad_command;
}
}
break;
case KEY_COLMODE_WRITE:
{
/* Are we just writing? Or writing then quitting? */
if (cmd == CMD_NONE)
{
/* Just writing.. do we force overwriting? */
cmd = (forced ? CMD_OWRITE : CMD_WRITE);
}
else if (cmd == CMD_QUIT)
{
/* Both ... do we force overwriting the file? */
cmd = (forced ? CMD_OWRITE_QUIT : CMD_WRITE_QUIT);
}
else
{
/* Anything else,
* including a forced quit is a syntax error
*/
goto errout_bad_command;
}
}
break;
case KEY_COLMODE_QUIT:
{
/* Are we just quitting? Or writing then quitting? */
if (cmd == CMD_NONE)
{
/* Just quitting... should we discard any changes? */
cmd = (forced ? CMD_DISCARD : CMD_QUIT);
}
/* If we are also writing, then it makes no sense to force the
* quit operation.
*/
else if (cmd == CMD_WRITE && !forced)
{
cmd = CMD_WRITE_QUIT;
}
else if (cmd == CMD_OWRITE && !forced)
{
cmd = CMD_OWRITE_QUIT;
}
else
{
/* Quit is not compatible with reading */
goto errout_bad_command;
}
}
break;
default:
{
/* Ignore whitespace */
if (ch != ' ')
{
/* Anything else terminates the loop */
done = true;
/* If there is anything else on the line, then it must be
* a file name. If we are writing (or reading with an
* empty text buffer), then we will need to copy the file
* into the filename storage area.
*/
if (ch != '\0')
{
/* For now, just remember where the file is in the
* scratch buffer.
*/
filename = &vi->scratch[col];
}
}
}
break;
}
}
/* Did we find any valid command? A read command requires a filename.
* A filename where one is not needed is also an error.
*/
viinfo("cmd=%d filename=\"%s\"\n", cmd, vi->filename);
if (cmd == CMD_NONE || (IS_READ(cmd) && !filename) ||
(!USES_FILE(cmd) && filename))
{
goto errout_bad_command;
}
/* Are we writing to a new filename? If we are not forcing the write,
* then we have to check if the file exists.
*/
if (filename && IS_NOWRITE(cmd))
{
/* Check if the file exists */
if (vi_checkfile(vi, filename))
{
/* It does... show an error and exit */
vi_error(vi, g_fmtfileexists);
goto errout;
}
}
/* Check if we are trying to quit with un-saved changes. The user must
* force quitting in this case.
*/
if (vi->modified && IS_NDISCARD(cmd))
{
/* Show an error and exit */
vi_error(vi, g_fmtmodified);
goto errout;
}
/* Are we now committed to reading the file? */
if (IS_READ(cmd))
{
/* Was the text buffer empty? */
bool empty = (vi->textsize == 0);
/* Yes.. get the cursor position of the beginning of the next line */
off_t pos = vi_nextline(vi, vi->curpos);
/* Then read the file into the text buffer at that position. */
if (vi_insertfile(vi, pos, filename))
{
/* Was the text buffer empty before we inserted the file? */
if (empty)
{
/* Yes.. then we want to save the filename and mark the text
* as unmodified.
*/
strlcpy(vi->filename, filename, MAX_FILENAME);
vi->modified = false;
}
else
{
/* No.. then we want to retain the filename and mark the text
* as modified.
*/
vi->modified = true;
}
}
}
/* Are we now committed to writing the file? */
if (IS_WRITE(cmd))
{
/* If we are writing to a new file, then we need to copy the filename
* from the scratch buffer to the filename buffer.
*/
if (filename)
{
strlcpy(vi->filename, filename, MAX_FILENAME);
}
/* If it is not a new file and if there are no changes to the text
* buffer, then ignore the write.
*/
if (filename || vi->modified)
{
vi_clearbottomline(vi);
vi_putch(vi, '"');
vi_write(vi, vi->filename, strlen(vi->filename));
vi_putch(vi, '"');
vi_putch(vi, ' ');
/* Now, finally, we can save the file */
if (!vi_savetext(vi, vi->filename, 0, vi->textsize))
{
/* An error occurred while saving the file and we are
* not forcing the quit operation. So error out without
* quitting until the user decides what to do about
* the save failure.
*/
goto errout;
}
/* The text buffer contents are no longer modified */
if (!IS_QUIT(cmd))
{
vi_setcursor(vi, vi->cursor.row, vi->cursor.column);
}
vi->modified = false;
}
}
/* Are we committed to exit-ing? */
if (IS_QUIT(cmd))
{
/* Yes... free resources and exit */
vi_putch(vi, '\n');
vi_release(vi);
exit(EXIT_SUCCESS);
}
/* Otherwise, revert to command mode */
vi_exitsubmode(vi, MODE_COMMAND);
return;
errout_bad_command:
vi_error(vi, g_fmtnotcmd, vi->scratch);
errout:
vi_exitsubmode(vi, MODE_COMMAND);
}