static void vi_parsecolon()

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);
}