aboutsummaryrefslogtreecommitdiffstats
path: root/src/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c494
1 files changed, 256 insertions, 238 deletions
diff --git a/src/io.c b/src/io.c
index 5c6d254..d596aab 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1,7 +1,7 @@
/*
* Calcurse - text-based organizer
*
- * Copyright (c) 2004-2017 calcurse Development Team <misc@calcurse.org>
+ * Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,8 +50,8 @@
struct ht_keybindings_s {
const char *label;
- enum key key;
- HTABLE_ENTRY(ht_keybindings_s);
+ enum vkey key;
+ HTABLE_ENTRY(ht_keybindings_s);
};
static void load_keys_ht_getkey(struct ht_keybindings_s *, const char **,
@@ -136,24 +136,52 @@ unsigned io_fprintln(const char *fname, const char *fmt, ...)
/*
* Initialization of data paths. The cfile argument is the variable
* which contains the calendar file. If none is given, then the default
- * one (~/.calcurse/apts) is taken. If the one given does not exist, it
- * is created.
+ * one (~/.local/share/calcurse/apts) is taken. If the one given does not exist,
+ * it is created.
* The datadir argument can be used to specify an alternative data root dir.
* The confdir argument can be used to specify an alternative configuration dir.
+ * If ~/.calcurse exists, it will be used instead for backward compatibility.
*/
void io_init(const char *cfile, const char *datadir, const char *confdir)
{
- if (!datadir) {
- if (!(datadir = getenv("HOME")))
- datadir = ".";
- asprintf(&path_ddir, "%s%s", datadir, "/" DIR_NAME);
- } else
- asprintf(&path_ddir, "%s%s", datadir, "/");
+ char* home_dir = getenv("HOME");
+ char* legacy_dir = NULL;
+
+ if (home_dir) {
+ asprintf(&legacy_dir, "%s%s", home_dir, "/" DIR_NAME_LEGACY);
+ if (!io_dir_exists(legacy_dir)) {
+ mem_free(legacy_dir);
+ legacy_dir = NULL;
+ }
+ }
- if (!confdir)
- asprintf(&path_cdir, "%s%s", path_ddir, "/");
+ if (datadir)
+ asprintf(&path_ddir, "%s%s", datadir, "/");
+ else if (legacy_dir)
+ path_ddir = mem_strdup(legacy_dir);
+ else if ((path_ddir = getenv("XDG_DATA_HOME")))
+ asprintf(&path_ddir, "%s%s", path_ddir, "/" DIR_NAME);
+ else if (home_dir)
+ asprintf(&path_ddir, "%s%s", home_dir, "/.local/share/" DIR_NAME);
else
+ path_ddir = mem_strdup("./." DIR_NAME);
+
+
+ if (confdir)
asprintf(&path_cdir, "%s%s", confdir, "/");
+ else if (datadir)
+ path_cdir = mem_strdup(path_ddir);
+ else if (legacy_dir)
+ path_cdir = mem_strdup(legacy_dir);
+ else if ((path_cdir = getenv("XDG_CONFIG_HOME")))
+ asprintf(&path_cdir, "%s%s", path_cdir, "/" DIR_NAME);
+ else if (home_dir)
+ asprintf(&path_cdir, "%s%s", home_dir, "/.config/" DIR_NAME);
+ else
+ path_cdir = mem_strdup("./." DIR_NAME);
+
+ if (legacy_dir)
+ mem_free(legacy_dir);
/* Data files */
if (cfile) {
@@ -209,25 +237,25 @@ void io_dump_apts(const char *fmt_apt, const char *fmt_rapt,
LLIST_FOREACH(&recur_elist, i) {
struct recur_event *rev = LLIST_GET_DATA(i);
- time_t day = update_time_in_date(rev->day, 0, 0);
+ time_t day = DAY(rev->day);
print_recur_event(fmt_rev, day, rev);
}
LLIST_TS_FOREACH(&recur_alist_p, i) {
struct recur_apoint *rapt = LLIST_GET_DATA(i);
- time_t day = update_time_in_date(rapt->start, 0, 0);
+ time_t day = DAY(rapt->start);
print_recur_apoint(fmt_rapt, day, rapt->start, rapt);
}
LLIST_TS_FOREACH(&alist_p, i) {
struct apoint *apt = LLIST_TS_GET_DATA(i);
- time_t day = update_time_in_date(apt->start, 0, 0);
+ time_t day = DAY(apt->start);
print_apoint(fmt_apt, day, apt);
}
LLIST_FOREACH(&eventlist, i) {
struct event *ev = LLIST_TS_GET_DATA(i);
- time_t day = update_time_in_date(ev->day, 0, 0);
+ time_t day = DAY(ev->day);
print_event(fmt_ev, day, ev);
}
}
@@ -525,13 +553,13 @@ void io_load_app(struct item_filter *filter)
FILE *data_file;
int c, is_appointment, is_event, is_recursive;
struct tm start, end, until, lt;
- llist_t exc;
+ struct rpt rpt;
time_t t;
int id = 0;
- int freq;
char type, state = 0L;
char note[MAX_NOTESIZ + 1], *notep;
unsigned line = 0;
+ char *scan_error;
t = time(NULL);
localtime_r(&t, &lt);
@@ -544,9 +572,10 @@ void io_load_app(struct item_filter *filter)
rewind(data_file);
for (;;) {
- LLIST_INIT(&exc);
is_appointment = is_event = is_recursive = 0;
line++;
+ scan_error = NULL;
+
c = getc(data_file);
if (c == EOF)
break;
@@ -602,102 +631,113 @@ void io_load_app(struct item_filter *filter)
if (c == '{') {
is_recursive = 1;
- if (fscanf(data_file, " %d%c ", &freq, &type) != 2)
+ if (fscanf(data_file, " %d%c ", &rpt.freq, &type) != 2)
io_load_error(path_apts, line,
_("syntax error in item repetition"));
-
+ else
+ rpt.type = recur_char2def(type);
c = getc(data_file);
- if (c == '}') { /* endless recurrent item */
- until.tm_year = 0;
- while ((c = getc(data_file)) == ' ') ;
- ungetc(c, data_file);
- } else if (c == '-' && getc(data_file) == '>') {
+ /* Optional until date */
+ if (c == '-' && getc(data_file) == '>') {
if (fscanf
(data_file, " %d / %d / %d ",
&until.tm_mon, &until.tm_mday,
&until.tm_year) != 3)
io_load_error(path_apts, line,
- _("syntax error in item repetition"));
+ _("syntax error in until date"));
+ if (!check_date(until.tm_year, until.tm_mon,
+ until.tm_mday))
+ io_load_error(path_apts, line,
+ _("until date error"));
+ until.tm_hour = 0;
+ until.tm_min = 0;
+ until.tm_sec = 0;
+ until.tm_isdst = -1;
+ until.tm_year -= 1900;
+ until.tm_mon--;
+ rpt.until = mktime(&until);
c = getc(data_file);
- if (c == '!') {
- ungetc(c, data_file);
- recur_exc_scan(&exc, data_file);
- while ((c =
- getc(data_file)) == ' ') ;
- ungetc(c, data_file);
- } else if (c == '}') {
- while ((c =
- getc(data_file)) == ' ') ;
- ungetc(c, data_file);
- } else {
+ } else
+ rpt.until = 0;
+ /* Optional bymonthday list */
+ if (c == 'd') {
+ if (rpt.type == RECUR_WEEKLY)
io_load_error(path_apts, line,
- _("syntax error in item repetition"));
- }
- } else if (c == '!') { /* endless item with exceptions */
+ _("BYMONTHDAY illegal with WEEKLY"));
ungetc(c, data_file);
- recur_exc_scan(&exc, data_file);
- while ((c = getc(data_file)) == ' ') ;
+ recur_bymonthday(&rpt.bymonthday, data_file);
+ c = getc(data_file);
+ } else
+ LLIST_INIT(&rpt.bymonthday);
+ /* Optional bywday list */
+ if (c == 'w') {
ungetc(c, data_file);
- until.tm_year = 0;
- } else {
+ recur_bywday(rpt.type, &rpt.bywday, data_file);
+ c = getc(data_file);
+ } else
+ LLIST_INIT(&rpt.bywday);
+ /* Optional bymonth list */
+ if (c == 'm') {
+ ungetc(c, data_file);
+ recur_bymonth(&rpt.bymonth, data_file);
+ c = getc(data_file);
+ } else
+ LLIST_INIT(&rpt.bymonth);
+ /* Optional exception dates */
+ if (c == '!') {
+ ungetc(c, data_file);
+ recur_exc_scan(&rpt.exc, data_file);
+ c = getc(data_file);
+ } else
+ LLIST_INIT(&rpt.exc);
+ /* End of recurrence rule */
+ if (c != '}')
io_load_error(path_apts, line,
- _("wrong format in the appointment or event"));
- /* NOTREACHED */
- }
- } else {
- ungetc(c, data_file);
+ _("missing end of recurrence"));
+ while ((c = getc(data_file)) == ' ') ;
}
/* Check if a note is attached to the item. */
- c = getc(data_file);
if (c == '>') {
note_read(note, data_file);
+ c = getc(data_file);
notep = note;
- } else {
+ } else
notep = NULL;
- ungetc(c, data_file);
- }
/*
* Last: read the item description and load it into its
* corresponding linked list, depending on the item type.
*/
if (is_appointment) {
- c = getc(data_file);
- if (c == '!') {
+ if (c == '!')
state |= APOINT_NOTIFY;
- while ((c = getc(data_file)) == ' ') ;
- ungetc(c, data_file);
- } else if (c == '|') {
+ else if (c == '|')
state = 0L;
- while ((c = getc(data_file)) == ' ') ;
- ungetc(c, data_file);
- } else {
+ else
io_load_error(path_apts, line,
- _("syntax error in item repetition"));
- }
- if (is_recursive) {
- recur_apoint_scan(data_file, start, end,
- type, freq, until, notep,
- &exc, state, filter);
- } else {
- apoint_scan(data_file, start, end, state,
+ _("syntax error in item state"));
+
+ if (is_recursive)
+ scan_error = recur_apoint_scan(data_file, start, end, state,
+ notep, filter, &rpt);
+ else
+ scan_error = apoint_scan(data_file, start, end, state,
notep, filter);
- }
} else if (is_event) {
- if (is_recursive) {
- recur_event_scan(data_file, start, id,
- type, freq, until, notep,
- &exc, filter);
- } else {
- event_scan(data_file, start, id, notep,
- filter);
- }
+ ungetc(c, data_file);
+ if (is_recursive)
+ scan_error = recur_event_scan(data_file, start, id, notep,
+ filter, &rpt);
+ else
+ scan_error = event_scan(data_file, start, id, notep, filter);
} else {
io_load_error(path_apts, line,
_("wrong format in the appointment or event"));
/* NOTREACHED */
}
+ if (scan_error)
+ io_load_error(path_apts, line, scan_error);
}
file_close(data_file, __FILE_POS__);
}
@@ -900,16 +940,6 @@ load_keys_ht_compare(struct ht_keybindings_s *data1,
}
/*
- * isblank(3) is protected by the __BSD_VISIBLE macro and this fails to be
- * visible in some specific cases. Thus replace it by the following is_blank()
- * function.
- */
-static int is_blank(int c)
-{
- return c == ' ' || c == '\t';
-}
-
-/*
* Load user-definable keys from file.
* A hash table is used to speed up loading process in avoiding string
* comparisons.
@@ -918,21 +948,21 @@ static int is_blank(int c)
*/
void io_load_keys(const char *pager)
{
- struct ht_keybindings_s keys[NBKEYS];
+ struct ht_keybindings_s virt_keys[NBVKEYS], *ht_elm, ht_entry;
FILE *keyfp;
- char buf[BUFSIZ];
+ char buf[BUFSIZ], key_label[BUFSIZ], key_str[BUFSIZ];
+ char *p, *msg;
struct io_file *log;
- int i, skipped, loaded, line;
- const int MAX_ERRORS = 5;
+ int i, n, skipped, loaded, line, assigned, undefined, key;
keys_init();
struct ht_keybindings ht_keys = HTABLE_INITIALIZER(&ht_keys);
- for (i = 0; i < NBKEYS; i++) {
- keys[i].key = (enum key)i;
- keys[i].label = keys_get_label((enum key)i);
- HTABLE_INSERT(ht_keybindings, &ht_keys, &keys[i]);
+ for (i = 0; i < NBVKEYS; i++) {
+ virt_keys[i].key = (enum vkey)i;
+ virt_keys[i].label = keys_get_label((enum vkey)i);
+ HTABLE_INSERT(ht_keybindings, &ht_keys, &virt_keys[i]);
}
keyfp = fopen(path_keys, "r");
@@ -941,111 +971,97 @@ void io_load_keys(const char *pager)
log = io_log_init();
skipped = loaded = line = 0;
while (fgets(buf, BUFSIZ, keyfp) != NULL) {
- char key_label[BUFSIZ], *p;
- struct ht_keybindings_s *ht_elm, ht_entry;
- const int AWAITED = 1;
- int assigned;
-
line++;
- if (skipped > MAX_ERRORS) {
- const char *too_many =
- _("\nToo many errors while reading configuration file!\n"
- "Please backup your keys file, remove it from directory, "
- "and launch calcurse again.\n");
-
- io_log_print(log, line, too_many);
- break;
- }
- for (p = buf; is_blank((int)*p); p++) ;
- if (p != buf)
- memmove(buf, p, strlen(p));
- if (buf[0] == '#' || buf[0] == '\n')
+ p = buf;
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p == '#' || *p == '\n')
continue;
- if (sscanf(buf, "%s", key_label) != AWAITED) {
+ /* Find the virtual key by key label. */
+ if (sscanf(p, "%s", key_label) != 1) {
skipped++;
io_log_print(log, line,
_("Could not read key label"));
continue;
}
-
- /* Skip legacy entries. */
- if (strcmp(key_label, "generic-cut") == 0)
- continue;
-
+ p += strlen(key_label);
ht_entry.label = key_label;
- p = buf + strlen(key_label) + 1;
- ht_elm =
- HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry);
+ ht_elm = HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry);
if (!ht_elm) {
skipped++;
- io_log_print(log, line,
- _("Key label not recognized"));
+ asprintf(&msg,
+ _("Key label not recognized: \"%s\""),
+ key_label);
+ io_log_print(log, line, msg);
+ mem_free(msg);
continue;
}
- assigned = 0;
- for (;;) {
- char key_ch[BUFSIZ], tmpbuf[BUFSIZ];
-
- while (*p == ' ')
- p++;
- (void)strncpy(tmpbuf, p, BUFSIZ);
- tmpbuf[BUFSIZ - 1] = '\0';
- if (sscanf(tmpbuf, "%s", key_ch) == AWAITED) {
- int ch;
-
- if ((ch = keys_str2int(key_ch)) < 0) {
- char *unknown_key;
+ /* Assign keyboard keys to the virtual key. */
+ assigned = undefined = 0;
+ for (;;) {
+ if (sscanf(p, "%s%n", key_str, &n) != 1) {
+ if (assigned || undefined)
+ loaded++;
+ else {
skipped++;
- asprintf(&unknown_key,
- _("Error reading key: \"%s\""),
- key_ch);
- io_log_print(log, line, unknown_key);
- mem_free(unknown_key);
- } else {
- int used;
-
- used =
- keys_assign_binding(ch,
- ht_elm->
- key);
- if (used) {
- char *already_assigned;
-
- skipped++;
- asprintf(&already_assigned,
- _("\"%s\" assigned multiple times!"),
- key_ch);
- io_log_print(log, line,
- already_assigned);
- mem_free(already_assigned);
- } else {
- assigned++;
- }
+ asprintf(&msg,
+ _("No keys assigned to "
+ "\"%s\"."),
+ key_label);
+ io_log_print(log, line, msg);
+ mem_free(msg);
}
- p += strlen(key_ch) + 1;
- } else {
- if (assigned)
- loaded++;
break;
}
+ p += n;
+ if (!strcmp(key_str, "UNDEFINED")) {
+ undefined++;
+ keys_assign_binding(-1, ht_elm->key);
+ } else if ((key = keys_str2int(key_str)) < 0) {
+ skipped++;
+ asprintf(&msg,
+ _("Keyname not recognized: \"%s\""),
+ key_str);
+ io_log_print(log, line, msg);
+ mem_free(msg);
+ } else if (keys_assign_binding(key, ht_elm->key)) {
+ skipped++;
+ asprintf(&msg,
+ _("\"%s\" assigned twice: \"%s\"."),
+ key_str, key_label);
+ io_log_print(log, line, msg);
+ mem_free(msg);
+ } else
+ assigned++;
}
}
file_close(keyfp, __FILE_POS__);
+ if (loaded < NBVKEYS && (i = keys_fill_missing()) < 1) {
+ skipped++;
+ strcpy(key_label, keys_get_label((enum vkey)(-i)));
+ strcpy(key_str, keys_get_binding((enum vkey)(-i)));
+ asprintf(&msg, _("Action \"%s\" absent, but default key \"%s\" "
+ "assigned to another action."),
+ key_label, key_str);
+ io_log_print(log, line, msg);
+ mem_free(msg);
+ }
file_close(log->fd, __FILE_POS__);
if (skipped > 0) {
- const char *view_log =
- _("There were some errors when loading keys file.");
- io_log_display(log, view_log, pager);
+ msg = _("Errors in the keys file.");
+ io_log_display(log, msg, pager);
+ WARN_MSG(_("Remove offending line(s) from the keys file, "
+ "aborting..."));
+ exit_calcurse(EXIT_FAILURE);
}
io_log_free(log);
- EXIT_IF(skipped > MAX_ERRORS,
- _("Too many errors while reading keys file, aborting..."));
- if (loaded < NBKEYS)
- keys_fill_missing();
- if (keys_check_missing_bindings())
- WARN_MSG(_("Some actions do not have any associated key bindings!"));
+ /* Default keys were inserted. */
+ if (loaded < NBVKEYS)
+ io_save_keys();
+ /* Should never occur. */
+ EXIT_IF(keys_check_missing(),
+ _("Some actions do not have any associated key bindings!"));
}
int io_check_dir(const char *dir)
@@ -1053,19 +1069,42 @@ int io_check_dir(const char *dir)
if (read_only)
return -1;
+ char *path = mem_strdup(dir);
+ char *index;
+
+ int existed = 1, failed = 0;
errno = 0;
- if (mkdir(dir, 0700) != 0) {
- if (errno != EEXIST) {
- fprintf(stderr,
- _("FATAL ERROR: could not create %s: %s\n"),
- dir, strerror(errno));
- exit_calcurse(EXIT_FAILURE);
- } else {
- return 1;
+ for (index = path + 1; *index; index++) {
+ if (*index == '/') {
+ *index = '\0';
+ if (mkdir(path, 0700) != 0) {
+ if (errno != EEXIST) {
+ failed = 1;
+ break;
+ }
+ } else {
+ existed = 0;
+ }
+ *index = '/';
}
+ }
+
+ if (!failed && mkdir(path, 0700) != 0) {
+ if (errno != EEXIST)
+ failed = 1;
} else {
- return 0;
+ existed = 0;
}
+
+ if(failed) {
+ fprintf(stderr,
+ _("FATAL ERROR: could not create %s: %s\n"),
+ path, strerror(errno));
+ exit_calcurse(EXIT_FAILURE);
+ }
+
+ mem_free(path);
+ return existed;
}
unsigned io_dir_exists(const char *path)
@@ -1114,11 +1153,15 @@ int io_check_file(const char *file)
* Checks if data files exist. If not, create them.
* The following structure has to be created:
*
- * <datadir> <configdir> (default for both: $HOME/.calcurse/)
+ * <datadir> <configdir>
* | |
* |__ apts |___ conf
* |__ todo |___ keys
* |__ notes/ |___ hooks/
+ *
+ * Defaults:
+ * - datadir: $XDG_DATA_HOME/calcurse (~/.local/share/calcurse)
+ * - configdir: $XDG_CONFIG_HOME/calcurse (~/.config/calcurse)
*/
int io_check_data_files(void)
{
@@ -1140,21 +1183,6 @@ int io_check_data_files(void)
return missing;
}
-/* Draw the startup screen */
-void io_startup_screen(int no_data_file)
-{
- const char *enter = _("Press [ENTER] to continue");
-
- if (no_data_file)
- status_mesg(_("Welcome to Calcurse. Missing data files were created."),
- enter);
- else
- status_mesg(_("Data files found. Data will be loaded now."),
- enter);
-
- keys_wait_for_any_key(win[KEY].p);
-}
-
/* Export calcurse data. */
void io_export_data(enum export_type type, int export_uid)
{
@@ -1185,38 +1213,36 @@ void io_export_data(enum export_type type, int export_uid)
else if (type == IO_EXPORT_PCAL)
pcal_export_data(stream);
- if (show_dialogs() && ui_mode == UI_CURSES) {
+ if (!quiet && ui_mode == UI_CURSES) {
fclose(stream);
status_mesg(success, enter);
keys_wait_for_any_key(win[KEY].p);
}
}
-static FILE *get_import_stream(enum import_type type)
+static FILE *get_import_stream(enum import_type type, char **stream_name)
{
FILE *stream = NULL;
- char *stream_name;
const char *ask_fname =
_("Enter the file name to import data from:");
const char *wrong_file =
_("The file cannot be accessed, please enter another file name.");
const char *press_enter = _("Press [ENTER] to continue.");
- stream_name = mem_malloc(BUFSIZ);
- memset(stream_name, 0, BUFSIZ);
+ *stream_name = mem_malloc(BUFSIZ);
+ memset(*stream_name, 0, BUFSIZ);
while (stream == NULL) {
status_mesg(ask_fname, "");
- if (updatestring(win[STA].p, &stream_name, 0, 1)) {
- mem_free(stream_name);
+ if (updatestring(win[STA].p, stream_name, 0, 1)) {
+ mem_free(*stream_name);
return NULL;
}
- stream = fopen(stream_name, "r");
+ stream = fopen(*stream_name, "r");
if (stream == NULL) {
status_mesg(wrong_file, press_enter);
keys_wait_for_any_key(win[KEY].p);
}
}
- mem_free(stream_name);
return stream;
}
@@ -1227,7 +1253,7 @@ static FILE *get_import_stream(enum import_type type)
* A temporary log file is created in /tmp to store the import process report,
* and is cleared at the end.
*/
-void io_import_data(enum import_type type, const char *stream_name,
+int io_import_data(enum import_type type, char *stream_name,
const char *fmt_ev, const char *fmt_rev,
const char *fmt_apt, const char *fmt_rapt,
const char *fmt_todo)
@@ -1254,7 +1280,7 @@ void io_import_data(enum import_type type, const char *stream_name,
"Aborting..."));
break;
case UI_CURSES:
- stream = get_import_stream(type);
+ stream = get_import_stream(type, &stream_name);
break;
default:
EXIT(_("FATAL ERROR: wrong import mode"));
@@ -1262,7 +1288,7 @@ void io_import_data(enum import_type type, const char *stream_name,
}
if (stream == NULL)
- return;
+ return 0;
memset(&stats, 0, sizeof stats);
@@ -1270,11 +1296,11 @@ void io_import_data(enum import_type type, const char *stream_name,
if (log == NULL) {
if (stream != stdin)
file_close(stream, __FILE_POS__);
- return;
+ return 0;
}
if (type == IO_IMPORT_ICAL)
- ical_import_data(stream, log->fd, &stats.events,
+ ical_import_data(stream_name, stream, log->fd, &stats.events,
&stats.apoints, &stats.todos,
&stats.lines, &stats.skipped, fmt_ev, fmt_rev,
fmt_apt, fmt_rapt, fmt_todo);
@@ -1295,7 +1321,7 @@ void io_import_data(enum import_type type, const char *stream_name,
stats.todos);
asprintf(&stats_str[3], _("%d skipped"), stats.skipped);
- if (ui_mode == UI_CURSES && show_dialogs()) {
+ if (ui_mode == UI_CURSES && !quiet) {
char *read, *stat;
asprintf(&read, proc_report, stats.lines);
@@ -1306,7 +1332,7 @@ void io_import_data(enum import_type type, const char *stream_name,
mem_free(read);
mem_free(stat);
keys_wait_for_any_key(win[KEY].p);
- } else if (ui_mode == UI_CMDLINE && show_dialogs()) {
+ } else if (ui_mode == UI_CMDLINE && !quiet) {
printf(proc_report, stats.lines);
printf("\n%s / %s / %s / %s\n", stats_str[0], stats_str[1],
stats_str[2], stats_str[3]);
@@ -1325,7 +1351,13 @@ void io_import_data(enum import_type type, const char *stream_name,
mem_free(stats_str[1]);
mem_free(stats_str[2]);
mem_free(stats_str[3]);
- io_log_free(log);
+ if (ui_mode == UI_CURSES)
+ mem_free(stream_name);
+ if (!stats.skipped) {
+ io_log_free(log);
+ return 1;
+ } else
+ return 0;
}
struct io_file *io_log_init(void)
@@ -1343,7 +1375,7 @@ struct io_file *io_log_init(void)
ERROR_MSG(_("Warning: could not create temporary log file, Aborting..."));
goto error;
}
- strncpy(log->name, logname, sizeof(log->name));
+ log->name = mem_strdup(logname);
log->fd = fopen(log->name, "w");
if (log->fd == NULL) {
ERROR_MSG(_("Warning: could not open temporary log file, Aborting..."));
@@ -1393,6 +1425,7 @@ void io_log_free(struct io_file *log)
EXIT_IF(unlink(log->name) != 0,
_("Warning: could not erase temporary log file %s, Aborting..."),
log->name);
+ mem_free(log->name);
mem_free(log);
}
@@ -1401,7 +1434,8 @@ static void *io_psave_thread(void *arg)
{
int delay = conf.periodic_save;
EXIT_IF(delay < 0, _("Invalid delay"));
- char *mesg = _("Periodic save: data files have changed. Save cancelled.");
+ char *mesg = _("Periodic save cancelled. Data files have changed. "
+ "Save and merge interactively");
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
for (;;) {
@@ -1521,22 +1555,6 @@ unsigned io_get_pid(char *file)
}
/*
- * Check whether a file is empty.
- */
-int io_file_is_empty(char *file)
-{
- FILE *fp;
- int ret = -1;
-
- if (file && (fp = fopen(file, "r"))) {
- ret = (fgetc(fp) == '\n' && fgetc(fp) == EOF) || feof(fp);
- fclose(fp);
- }
-
- return ret;
-}
-
-/*
* Check whether two files are equal.
*/
int io_files_equal(const char *file1, const char *file2)