Estoy usando ncurses para crear una tui para moverme a través de directorios. Tengo el programa abriendo archivos editables en vi usando una llamada al sistema
def_prog_mode();
endwin();
sprintf(command, "%s %s", di->Settings.editor, di->Directory.File[di->Variables.item_selection].Path);
system(command);
reset_prog_mode();
pero cuando salgo de vi para volver al programa vi informa el error
E138: Can't write viminfo file /home/user/.di/.viminfo!
Press ENTER or type command to continue
.di es el archivo de configuración de mi programa y no tengo idea de por qué está tratando de incluirse en la ruta del archivo .viminfo.
¿Alguien tiene alguna idea de cómo solucionar esto? Todas mis variables tienen el prefijo di_, por lo que no tengo idea de por qué sucede esto. ¡Toda ayuda es muy apreciada!
- El error ocurre dentro de vi y no en mi programa.
- No hay desbordamiento en sprintf porque todo tiene un carácter de terminación nulo colocado en el final.
- La preferencia del editor viene como un valor predeterminado de vi, pero es manipulada por el usuario a través del archivo de configuración.
- /home/user/.di no es una carpeta, es un archivo y solo se llama en la adquisición de los contenidos de los archivos de configuración, y en la creación inicial y el llenado del archivo y todas las instancias de fopen se cierran inmediatamente después.
- El propósito de no usar ncurses para crear un editor es darle al usuario la opción de usar su propio editor (muchos disponibles en el servidor que se usa)
- No parece haber un fallo de syscall. Este estilo parece ser un error por parte de vi.
Solo para tener en cuenta: este es un problema meramente molesto. La falla en vi no causa una falla en mi programa.
Esto se implementó en mi programa en mi reciente reescritura de todo el programa. Permite al usuario cambiar la configuración en un archivo de configuración ".di" en el directorio de inicio. Desde esta implementación, al salir de vi (o vim), vi (o vim) declara el error y luego regresa con éxito al programa.
#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);
}
command
buffer antes de ejecutarsystem(command)
can't write viminfo file
Da muchas respuestas relevantes.(absolute path to file)
no es un nombre de archivo. Si resulta que es su nombre de archivo, no puede funcionar (porque necesita escapar de esos espacios, y el paréntesis, para elsh
contenersystem(command)
....)Respuestas:
Mi página de manual de getenv dice:
Rompiste esa regla aquí:
Por lo tanto, está modificando la memoria que no debe modificar, en particular, está modificando el valor de la variable de entorno HOME (además, probablemente esté matando a otra variable de entorno o corrompiendo de cualquier otra forma lo que venga después de HOME en la memoria) .
vim
hereda el nuevo valor de$HOME
y trata de usarlo como su directorio personal, incluido el depósito de suviminfo
cosas allíDebe copiar getenv ("HOME") en su propio búfer, y asegurarse de que el búfer tenga suficiente espacio para la copia más lo que desea añadirle. Una forma de hacerlo es con
asprintf
:fuente
Primero, debes compilar con
gcc -Wall -g
y aprender a usar elgdb
depurador Mira estocommand
tiene el valor que quieres que tenga. (No estoy seguro de que funcionaría como desea si algún directorio o nombre de archivo tiene espacios en él).Utilizando
sprintf
está en desuso y es peligroso (posible desbordamiento del búfer). Utilizar snprintf (3) o (específico de libc de GNU) asprintf .Entonces, supongo que tu llamada a
system
devuelve un código que no es 0. Nunca debe ignorar el resultado desystem
función de biblioteca. Ver esta respuesta para más detalles.Por lo menos, deberías tener
y mostrar el
editfailedcode
(En realidad manejarlo) con elcommand
cuandoeditfailedcode
no es cero.Y por fin, la convención es utilizar el
EDITOR
Variable ambiental. Leer ambiente (7) página de manualEstás seguro que
/home/user/.di
Existe y es un directorio escribible? Es posible que desee utilizar el stat (2) syscall para comprobar que.Además, ya que estás usando
ncurses
ya, puedes considerar usarlo para tu propio editor interno ...Por cierto, podrías usar strace (1) (tal vez como
strace -f
) para averiguar qué syscall está fallando y por qué ...fuente
sprintf
así que debes usarsnprintf
; debe verificar -a través del depurador o al registrar- qué comando exacto está ejecutando y cuál es el código de retorno dado porsystem(command)
; en efectovi
Podría fallar y usted debería manejar tales fallas ....