Я использую 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);

}

2 ответа2

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

Сначала вы должны скомпилировать с помощью gcc -Wall -g и научиться использовать отладчик gdb . Убедитесь, что эта command имеет значение, которое вы хотите иметь. (Я не уверен, что это будет работать так, как вы хотите, если в каком-либо каталоге или имени файла есть пробелы).

Использование sprintf устарело и опасно (возможно переполнение буфера). Используйте snprintf (3) или (специфичный для GNU libc) asprintf.

Затем, я думаю, что ваш вызов system возвращает код, отличный от 0.Вы никогда не должны игнорировать результат функции system библиотеки. Смотрите этот ответ для более подробной информации.

По крайней мере, вы должны иметь

int editfailedcode = system(command);

и покажите editfailedcode (фактически обработайте его) с помощью command когда editfailedcode не равен нулю.

И наконец, условием является использование переменной среды EDITOR . Прочтите справочную страницу (7) .

Вы уверены, что /home/user/.di существует и является записываемым каталогом? Вы можете использовать системный вызов stat(2), чтобы проверить это.

Кроме того, поскольку вы уже используете ncurses , вы можете использовать его для своего внутреннего редактора ....

Кстати, вы могли бы использовать strace(1) (возможно, как strace -f), чтобы выяснить, какой системный вызов не работает и почему ...

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .