E138:无法写入 viminfo 文件

E138:无法写入 viminfo 文件

我正在使用 ncurses 创建一个 tui 来在目录中移动。我让程序使用系统调用在 vi 中打开可编辑文件

def_prog_mode();
endwin();
sprintf(command, "%s %s", di->Settings.editor, di->Directory.File[di->Variables.item_selection].Path);
system(command);
reset_prog_mode();

但是当我退出 vi 并返回到程序 vi 时,报告错误

E138: Can't write viminfo file /home/user/.di/.viminfo!
Press ENTER or type command to continue

.di 是我的程序的配置文件,我不知道为什么它试图将自己包含在 .viminfo 文件的路径中。

有人知道如何解决这个问题吗?我的所有变量都以 di_ 为前缀,所以我不知道为什么会发生这种情况。非常感谢大家的帮助!

  1. 该错误发生在 vi 中,而不是我的程序中。
  2. sprintf 中没有溢出,因为每个字符的末尾都有一个空终止字符。
  3. 编辑器首选项是 vi 的默认设置,但用户可以通过配置文件进行操作。
  4. /home/user/.di 不是一个文件夹,它是一个文件,并且只在获取设置文件内容时调用,并且在文件的初始创建和填充之后所有 fopen 实例都会立即关闭。
  5. 不使用 ncurses 创建编辑器的目的是为了让用户可以选择使用自己的编辑器(服务器上有许多可用的编辑器)
  6. 似乎没有系统调用失败。这似乎仍然是 vi 的错误。


请注意:这只是一个烦人的问题。vi 中的故障不会导致我的程序故障。


在我最近重写整个程序时,我已将此功能实现到我的程序中。它允许用户在主目录中的配置文件“.di”中更改设置。自从实现此功能以来,退出 vi(或 vim)时,vi(或 vim)会显示错误,然后成功返回到程序。

#include "di.h"

void settings(DI *di, int mode) {

    check_settings_exist(di);

    switch (mode) {

        case 0 :
            read_settings(di);
            break;

        case 1 :
            write_settings(di);
            break;

    }

}

void check_settings_exist(DI *di) {

    if (!di->Settings.file_location) {

        char *di_settings_file_path = (char *) getenv("HOME");
        strcat(di_settings_file_path, "/");
        strcat(di_settings_file_path, di_default_settings_file);
        strcat(di_settings_file_path, "\0");

        di->Settings.file_location = (char *) calloc(sizeof(di_settings_file_path) + 12, sizeof(char));
        strcpy(di->Settings.file_location, di_settings_file_path);

    }

    if(access(di->Settings.file_location, F_OK)) {

        int counter;
        FILE * di_settings_file = fopen(di->Settings.file_location, "w+");

        for (counter = 0; di_settings_file_default[counter][0]; counter++) {

            fprintf(di_settings_file, "%s%s\n", di_settings_file_default[counter][0], di_settings_file_default[counter][1]);

        }

        fclose(di_settings_file);

    }

}

void read_settings(DI *di) {

    FILE * di_settings_file = fopen(di->Settings.file_location, "r");

    di->Settings.editor = calloc(16, sizeof(char));
    di->Settings.deletion_mode = calloc(16, sizeof(char));

    fscanf(di_settings_file, "%*[^:]:%[^\n]\n", di->Settings.editor);
    fscanf(di_settings_file, "%*[^:]:%[^\n]\n", di->Settings.deletion_mode);

    fclose(di_settings_file);

}

void write_settings(DI *di) {

    FILE * di_settings_file = fopen(di->Settings.file_location, "w+");

    //

    fclose(di_settings_file);

}

答案1

我的 getenv 手册页说:

As typically implemented, getenv() returns a pointer to a string within
the  environment  list.   The  caller must take care not to modify this
string, since that would change the environment of the process.

你在这里违反了这条规则:

char *di_settings_file_path = (char *) getenv("HOME");
strcat(di_settings_file_path, "/");
strcat(di_settings_file_path, di_default_settings_file);
strcat(di_settings_file_path, "\0");

因此,您正在修改不应该修改的内存,特别是您正在修改 HOME 环境变量的值(此外,您可能正在终止其他环境变量,或者以其他方式破坏内存中 HOME 之后的任何内容)。

vim继承的新值$HOME并尝试将其用作您的主目录,包括将其viminfo内容存放在那里。

您需要将 getenv("HOME") 复制到您自己的缓冲区中,并确保缓冲区有足够的空间容纳副本以及您想要附加到其中的内容。一种方式是使用asprintf

asprintf(&di_settings_file_path , "%s/%s",
    getenv("HOME"), di_default_settings_file);
/* ... use it ... */
free(di_settings_file_path);

答案2

首先,您应该使用调试器进行编译gcc -Wall -g并学习使用它gdb。检查它command是否具有您想要的值。(如果某些目录或文件名中有空格,我不确定它是否能按您想要的方式工作)。

使用sprintf已弃用且危险(可能导致缓冲区溢出)。使用snprintf(3)或(GNU libc 特定)打印函数

那么,我猜你对的调用返回了一个非 0 代码。你永远不应该忽略库函数 system的结果。参见system这个答案更多细节。

至少你应该

int editfailedcode = system(command);

并显示当非零时editfailedcode(实际处理它) 。commandeditfailedcode

最后,惯例是使用EDITOR环境变量。阅读环境(7)请参阅手册页。

您确定该/home/user/.di目录存在且可写吗?您可能需要使用统计(2)系统调用来检查。

此外,既然您ncurses已经在使用,您可以考虑将其用于您自己的内部编辑器......

顺便说一句,你可以使用strace(1)(也许strace -f)找出哪个系统调用失败以及原因......

相关内容