Initial revision
This commit is contained in:
484
src/io.c
Executable file
484
src/io.c
Executable file
@@ -0,0 +1,484 @@
|
||||
/* $calcurse: io.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
|
||||
|
||||
/*
|
||||
* Calcurse - text-based organizer
|
||||
* Copyright (c) 2004-2006 Frederic Culot
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Send your feedback or comments to : calcurse@culot.org
|
||||
* Calcurse home page : http://culot.org/calcurse
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ncurses.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include "utils.h"
|
||||
#include "custom.h"
|
||||
#include "todo.h"
|
||||
#include "event.h"
|
||||
#include "apoint.h"
|
||||
#include "recur.h"
|
||||
#include "io.h"
|
||||
#include "vars.h"
|
||||
|
||||
/*
|
||||
* Initialization of data paths. The argument cfile 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.
|
||||
*/
|
||||
void
|
||||
io_init(char *cfile)
|
||||
{
|
||||
FILE *data_file;
|
||||
char *home;
|
||||
char apts_file[MAX_LENGTH] = "";
|
||||
int ch;
|
||||
|
||||
home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
home = ".";
|
||||
}
|
||||
snprintf(path_dir, MAX_LENGTH, "%s/" DIR_NAME, home);
|
||||
snprintf(path_todo, MAX_LENGTH, "%s/" TODO_PATH, home);
|
||||
snprintf(path_conf, MAX_LENGTH, "%s/" CONF_PATH, home);
|
||||
if (cfile == NULL) {
|
||||
snprintf(path_apts, MAX_LENGTH, "%s/" APTS_PATH, home);
|
||||
} else {
|
||||
snprintf(apts_file, MAX_LENGTH, "%s", cfile);
|
||||
strncpy(path_apts, apts_file, MAX_LENGTH);
|
||||
/* check if the file exists, otherwise create it */
|
||||
data_file = fopen(path_apts, "r");
|
||||
if (data_file == NULL) {
|
||||
printf(_("%s does not exist, create it now [y or n] ? "), path_apts);
|
||||
ch = getchar();
|
||||
switch (ch) {
|
||||
case 'N':
|
||||
case 'n':
|
||||
printf(_("aborting...\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
case 'y':
|
||||
data_file = fopen(path_apts, "w");
|
||||
if (data_file == NULL) {
|
||||
perror(path_apts);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
printf(_("%s successfully created\n"),path_apts);
|
||||
printf(_("starting interactive mode...\n"));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf(_("aborting...\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(data_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* get data from file */
|
||||
void extract_data(char *dst_data, const char *org, int len)
|
||||
{
|
||||
for (;;) {
|
||||
if (*org == '\n' || *org == '\0')
|
||||
break;
|
||||
*dst_data++ = *org++;
|
||||
}
|
||||
*dst_data = '\0';
|
||||
}
|
||||
|
||||
/* Save the calendar data */
|
||||
void
|
||||
save_cal(bool auto_save, bool confirm_quit,
|
||||
bool confirm_delete, bool skip_system_dialogs,
|
||||
bool skip_progress_bar, bool week_begins_on_monday,
|
||||
int colr, int layout)
|
||||
{
|
||||
FILE *data_file;
|
||||
struct event_s *k;
|
||||
struct apoint_s *j;
|
||||
struct todo_s *i;
|
||||
char *access_pb = _("Problems accessing data file ...");
|
||||
char *config_txt =
|
||||
"#\n# Calcurse configuration file\n#\n# This file sets the configuration options used by Calcurse. These\n# options are usually set from within Calcurse. A line beginning with \n# a space or tab is considered to be a continuation of the previous line.\n# For a variable to be unset its value must be blank.\n# To set a variable to the empty string its value should be \"\".\n# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n";
|
||||
char *save_success = _("The data files were successfully saved");
|
||||
char *enter = _("Press [ENTER] to continue");
|
||||
bool save = true, show_bar = false;
|
||||
|
||||
if (!skip_progress_bar) show_bar = true;
|
||||
|
||||
/* Save the user configuration. */
|
||||
|
||||
if (show_bar) progress_bar(save, 1);
|
||||
data_file = fopen(path_conf, "w");
|
||||
if (data_file == (FILE *) 0)
|
||||
status_mesg(access_pb, "");
|
||||
else {
|
||||
fprintf(data_file, "%s\n", config_txt);
|
||||
|
||||
fprintf(data_file,
|
||||
"# If this option is set to yes, automatic save is done when quitting\n");
|
||||
fprintf(data_file, "auto_save=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(auto_save) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# If this option is set to yes, confirmation is required before quitting\n");
|
||||
fprintf(data_file, "confirm_quit=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(confirm_quit) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# If this option is set to yes, confirmation is required before deleting an event\n");
|
||||
fprintf(data_file, "confirm_delete=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(confirm_delete) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# If this option is set to yes, messages about loaded and saved data will not be displayed\n");
|
||||
fprintf(data_file, "skip_system_dialogs=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(skip_system_dialogs) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# If this option is set to yes, progress bar appearing when saving data will not be displayed\n");
|
||||
fprintf(data_file, "skip_progress_bar=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(skip_progress_bar) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# If this option is set to yes, monday is the first day of the week, else it is sunday\n");
|
||||
fprintf(data_file, "week_begins_on_monday=\n");
|
||||
fprintf(data_file, "%s\n",
|
||||
(week_begins_on_monday) ? "yes" : "no");
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# This is the color theme used for menus (1 to 8) :\n");
|
||||
fprintf(data_file, "color-theme=\n");
|
||||
fprintf(data_file, "%d\n", colr);
|
||||
|
||||
fprintf(data_file,
|
||||
"\n# This is the layout of the calendar (1 to 4) :\n");
|
||||
fprintf(data_file, "layout=\n");
|
||||
fprintf(data_file, "%d\n", layout);
|
||||
fclose(data_file);
|
||||
}
|
||||
|
||||
/* Save the todo data file. */
|
||||
if (show_bar) progress_bar(save, 2);
|
||||
data_file = fopen(path_todo, "w");
|
||||
if (data_file == (FILE *) 0)
|
||||
status_mesg(access_pb, "");
|
||||
else {
|
||||
for (i = todolist; i != 0; i = i->next)
|
||||
fprintf(data_file, "%s\n", i->mesg);
|
||||
fclose(data_file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the apts data file, which contains the
|
||||
* appointments first, and then the events.
|
||||
* Recursive items are written first.
|
||||
*/
|
||||
if (show_bar) progress_bar(save, 3);
|
||||
data_file = fopen(path_apts, "w");
|
||||
if (data_file == (FILE *) 0)
|
||||
status_mesg(access_pb, "");
|
||||
else {
|
||||
recur_save_data(data_file);
|
||||
for (j = apointlist; j != 0; j = j->next)
|
||||
apoint_write(j, data_file);
|
||||
for (k = eventlist; k != 0; k = k->next)
|
||||
event_write(k, data_file);
|
||||
fclose(data_file);
|
||||
}
|
||||
|
||||
|
||||
/* Print a message telling data were saved */
|
||||
if (!skip_system_dialogs){
|
||||
status_mesg(save_success, enter);
|
||||
wgetch(swin);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check what type of data is written in the appointment file,
|
||||
* and then load either: a new appointment, a new event, or a new
|
||||
* recursive item (which can also be either an event or an appointment).
|
||||
*/
|
||||
void load_app()
|
||||
{
|
||||
FILE *data_file;
|
||||
int c, is_appointment, is_event, is_recursive;
|
||||
struct tm start, end, until, *lt;
|
||||
time_t t;
|
||||
int id = 0;
|
||||
int freq;
|
||||
char type;
|
||||
char *error =
|
||||
_("FATAL ERROR in load_app: wrong format in the appointment or event\n");
|
||||
|
||||
t = time(NULL);
|
||||
lt = localtime(&t);
|
||||
start = end = until = *lt;
|
||||
|
||||
data_file = fopen(path_apts, "r");
|
||||
for (;;) {
|
||||
is_appointment = is_event = is_recursive = 0;
|
||||
c = getc(data_file);
|
||||
if (c == EOF)
|
||||
break;
|
||||
ungetc(c, data_file);
|
||||
|
||||
/* Read the date first: it is common to both events
|
||||
* and appointments.
|
||||
*/
|
||||
if (fscanf(data_file, "%u / %u / %u ",
|
||||
&start.tm_mon, &start.tm_mday, &start.tm_year) != 3) {
|
||||
fputs(_("FATAL ERROR in load_app: "
|
||||
"syntax error in the item date\n"), stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Read the next character : if it is an '@' then we have
|
||||
* an appointment, else if it is an '[' we have en event.
|
||||
*/
|
||||
c = getc(data_file);
|
||||
|
||||
if (c == '@')
|
||||
is_appointment = 1;
|
||||
else if (c == '[')
|
||||
is_event = 1;
|
||||
else {
|
||||
fputs(_("FATAL ERROR in load_app: "
|
||||
"no event nor appointment found\n"), stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ungetc(c, data_file);
|
||||
|
||||
/* Read the remaining informations. */
|
||||
if (is_appointment) {
|
||||
fscanf(data_file, "@ %u : %u -> %u / %u / %u @ %u : %u ",
|
||||
&start.tm_hour, &start.tm_min,
|
||||
&end.tm_mon, &end.tm_mday, &end.tm_year,
|
||||
&end.tm_hour, &end.tm_min);
|
||||
} else if (is_event) {
|
||||
fscanf(data_file, "[%d] ", &id);
|
||||
} else { /* NOT REACHED */
|
||||
fputs(error, stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Check if we have a recursive item. */
|
||||
c = getc(data_file);
|
||||
|
||||
if (c == '{') {
|
||||
ungetc(c, data_file);
|
||||
is_recursive = 1;
|
||||
fscanf(data_file, "{ %d%c ", &freq, &type);
|
||||
/* Check if we have an endless recurrent item. */
|
||||
c = getc(data_file);
|
||||
if (c == '}') {
|
||||
ungetc(c, data_file);
|
||||
fscanf(data_file, "} ");
|
||||
until.tm_year = 0;
|
||||
if (is_appointment)
|
||||
c = getc(data_file); // useless '|'
|
||||
} else if (c == '-') {
|
||||
ungetc(c, data_file);
|
||||
fscanf(data_file, " -> %u / %u / %u } ",
|
||||
&until.tm_mon, &until.tm_mday,
|
||||
&until.tm_year);
|
||||
if (is_appointment)
|
||||
c = getc(data_file); // useless '|'
|
||||
} else { /* NOT REACHED */
|
||||
fputs(error, stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (is_event) // if appointment we have a useless '|'
|
||||
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) {
|
||||
if (is_recursive) {
|
||||
recur_apoint_scan(data_file, start, end,
|
||||
type, freq, until);
|
||||
} else {
|
||||
apoint_scan(data_file, start, end);
|
||||
}
|
||||
} else if (is_event) {
|
||||
if (is_recursive) {
|
||||
recur_event_scan(data_file, start, id,
|
||||
type, freq, until);
|
||||
} else {
|
||||
event_scan(data_file, start, id);
|
||||
}
|
||||
} else { /* NOT REACHED */
|
||||
fputs(error, stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
fclose(data_file);
|
||||
}
|
||||
|
||||
/* Load the todo data */
|
||||
int
|
||||
load_todo(int colr)
|
||||
{
|
||||
FILE *data_file;
|
||||
char *mesg_line1 = _("Failed to open todo file");
|
||||
char *mesg_line2 = _("Press [ENTER] to continue");
|
||||
int nb_tod = 0;
|
||||
char buf[100], e_todo[100];
|
||||
|
||||
data_file = fopen(path_todo, "r");
|
||||
if (data_file == NULL) {
|
||||
status_mesg(mesg_line1, mesg_line2);
|
||||
wgetch(swin);
|
||||
}
|
||||
for (;;) {
|
||||
if (fgets(buf, 99, data_file) == NULL) {
|
||||
break;
|
||||
}
|
||||
extract_data(e_todo, buf, strlen(buf));
|
||||
todo_add(e_todo);
|
||||
++nb_tod;
|
||||
}
|
||||
fclose(data_file);
|
||||
return nb_tod;
|
||||
}
|
||||
|
||||
/* Checks if data files exist. If not, create them */
|
||||
int check_data_files()
|
||||
{
|
||||
FILE *data_file;
|
||||
int no_data_file;
|
||||
|
||||
no_data_file = 0;
|
||||
/* Create the calcurse repertory if not present. */
|
||||
mkdir(path_dir, 0700);
|
||||
|
||||
data_file = fopen(path_todo, "r");
|
||||
if (data_file == NULL) {
|
||||
no_data_file++;
|
||||
data_file = fopen(path_todo, "w");
|
||||
if (data_file == NULL) {
|
||||
perror(path_todo);
|
||||
return no_data_file;
|
||||
}
|
||||
}
|
||||
fclose(data_file);
|
||||
|
||||
data_file = fopen(path_apts, "r");
|
||||
if (data_file == NULL) {
|
||||
no_data_file++;
|
||||
data_file = fopen(path_apts, "w");
|
||||
if (data_file == NULL) {
|
||||
perror(path_apts);
|
||||
return no_data_file;
|
||||
}
|
||||
}
|
||||
fclose(data_file);
|
||||
|
||||
data_file = fopen(path_conf, "r");
|
||||
if (data_file == NULL) {
|
||||
no_data_file++;
|
||||
data_file = fopen(path_conf, "w");
|
||||
if (data_file == NULL) {
|
||||
perror(path_conf);
|
||||
return no_data_file;
|
||||
}
|
||||
}
|
||||
fclose(data_file);
|
||||
return no_data_file;
|
||||
}
|
||||
|
||||
/* Draw the startup screen */
|
||||
void startup_screen(bool skip_dialogs, int no_data_file, int colr)
|
||||
{
|
||||
char *welcome_mesg = _("Welcome to Calcurse. Missing data files were created.");
|
||||
char *data_mesg = _("Data files found. Data will be loaded now.");
|
||||
char *enter = _("Press [ENTER] to continue");
|
||||
|
||||
if (no_data_file != 0) {
|
||||
status_mesg(welcome_mesg, enter);
|
||||
wgetch(swin);
|
||||
} else if (!skip_dialogs){
|
||||
status_mesg(data_mesg, enter);
|
||||
wgetch(swin);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a progress bar while saving or loading data. */
|
||||
void progress_bar(bool save, int progress)
|
||||
{
|
||||
int i, nbd = 4;
|
||||
char *mesg_sav = _("Saving...");
|
||||
char *mesg_load = _("Loading...");
|
||||
char *barchar = "|";
|
||||
char *data[4] = {
|
||||
"[ ]",
|
||||
"[ conf ]",
|
||||
"[ todo ]",
|
||||
"[ apts ]"};
|
||||
int ipos = strlen(data[1]) + 2;
|
||||
int epos[4];
|
||||
int sleep_time = 125000;
|
||||
|
||||
/* progress bar length init. */
|
||||
epos[0] = floor(col / nbd);
|
||||
epos[1] = 2*epos[0];
|
||||
epos[2] = 3*epos[0];
|
||||
epos[3] = col - 2;
|
||||
|
||||
/* Display which data is being saved. */
|
||||
if (save)
|
||||
status_mesg(mesg_sav, data[progress]);
|
||||
else
|
||||
status_mesg(mesg_load, data[progress]);
|
||||
|
||||
/* Draw the progress bar. */
|
||||
mvwprintw(swin, 1, ipos, barchar);
|
||||
mvwprintw(swin, 1, epos[nbd - 1], barchar);
|
||||
custom_apply_attr(swin, ATTR_HIGHEST);
|
||||
for (i = ipos + 1; i < epos[progress]; i++)
|
||||
mvwaddch(swin, 1, i, ' ' | A_REVERSE);
|
||||
custom_remove_attr(swin, ATTR_HIGHEST);
|
||||
wmove(swin, 0, 0);
|
||||
wrefresh(swin);
|
||||
usleep(sleep_time);
|
||||
}
|
||||
Reference in New Issue
Block a user