summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README18
-rwxr-xr-xautogen.sh155
-rw-r--r--doc/calcurse.1.txt11
-rw-r--r--doc/manual.txt26
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/apoint.c325
-rw-r--r--src/args.c134
-rw-r--r--src/calcurse.c814
-rw-r--r--src/calcurse.h149
-rw-r--r--src/calendar.c25
-rw-r--r--src/custom.c8
-rw-r--r--src/day.c947
-rw-r--r--src/event.c75
-rw-r--r--src/help.c33
-rw-r--r--src/ical.c31
-rw-r--r--src/interaction.c899
-rw-r--r--src/io.c93
-rw-r--r--src/keys.c32
-rw-r--r--src/llist.c47
-rw-r--r--src/llist.h10
-rw-r--r--src/recur.c428
-rw-r--r--src/todo.c164
-rw-r--r--src/utils.c24
-rw-r--r--src/wins.c9
-rw-r--r--test/Makefile.am3
-rwxr-xr-xtest/bug-002.sh16
-rw-r--r--test/data/apts141
-rw-r--r--test/data/apts-bug-0022
29 files changed, 2295 insertions, 2326 deletions
diff --git a/README b/README
index 72f4611..97fdbcd 100644
--- a/README
+++ b/README
@@ -31,11 +31,19 @@ Contributors
------------
* RegEx support: Erik Saule
-* German translation: Michael Schulz, Chris M., Benjamin Moeller
-* Spanish translation: Jose Lopez
-* Dutch translation: Jeremy Roon
-* French translation: Erik Saule
-* Russian translation: Aleksey Mechonoshin
+* Dutch translation: Jeremy Roon, 2007-2010
+* French translation: Frédéric Culot, 2006-2010
+* French translation: Toucouch, 2007
+* French translation: Erik Saule, 2011-2012
+* French translation: Stéphane Aulery, 2012
+* French translation: Baptiste Jonglez, 2012
+* German translation: Michael Schulz, 2006-2010
+* German translation: Chris M., 2006
+* German translation: Benjamin Moeller, 2010
+* German translation: Lukas Fleischer, 2011-2012
+* Portuguese (Brazil) translation: Rafael Ferreira, 2012
+* Russian translation: Aleksey Mechonoshin, 2011-2012
+* Spanish translation: Jose Lopez, 2006-2010
Also check the `Thanks` section in the manual for a list of people who have
contributed by reporting bugs, sending fixes, or suggesting improvements.
diff --git a/autogen.sh b/autogen.sh
index cb7514f..85a987f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2004-2011 calcurse Development Team <misc@calcurse.org>
+# Copyright (c) 2004-2012 calcurse Development Team <misc@calcurse.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -28,153 +28,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
-#
-# autogen.sh - Generates all the necessary files to build calcurse from
-# cvs tree.
-#
-
-PKG_NAME=calcurse
-AC_VERSION="2 59"
-AUTOCONF_VERSION=2.59
-AC_FLAGS=
-AM_VERSION="1 9"
-AUTOMAKE_VERSION=1.9
-AM_FLAGS="--foreign --copy --add-missing"
-GETTEXT_VERSION="0 14"
-GETTEXT_FLAGS="--copy --no-changelog"
-ACLOCAL_FLAGS="-I m4"
-SRCDIR=`dirname $0`
-test -z "$SRCDIR" && SRCDIR=.
-export AUTOMAKE_VERSION AUTOCONF_VERSION
-
-# Function to check if we are at the top level of calcurse package.
-check_directory_level()
-{
- (test -f $SRCDIR/configure.ac) || {
- printf "\n\n**Error**: Directory "\`$SRCDIR\'" does not appear to"
- printf "\nbe the top-level $PKG_NAME directory.\n"
- exit 1
- }
-}
-
-# Clean previous files before running scripts
-clean_old_files()
-{
- printf "Cleaning old files ... "
- rm -rf configure config.log aclocal.m4 \
- config.status config autom4te.cache \
- po/Makefile.in.in ABOUT-NLS
- printf "done\n"
-}
-
-# Clean useless backup files
-clean_backup_files()
-{
- printf "Cleaning backup files ... "
- rm -rf configure.ac\~ Makefile.am\~
- printf "done\n"
-}
-
-# Function to check for a program availability
-check_program()
-{
- PROGRAM=$1
- printf "Checking for $PROGRAM ... "
- ($PROGRAM --version) < /dev/null > /dev/null 2>&1 || {
- printf "\n\n**Error**: You must have $PROGRAM installed."
- printf "\nDownload the appropriate package for your distribution,"
- printf "\nor get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
- printf "\n"
- exit 1
- }
- FOUND=`which $PROGRAM`
- printf "$FOUND\n"
-}
-
-# Function to check a program's version
-# (there must be a better way, but I am not good at sed...)
-check_program_version()
-{
- PROGRAM=$1; MAJOR=$2; MINOR=$3
- printf "Checking that $PROGRAM version is at least $MAJOR.$MINOR ... "
- VERSION=`$PROGRAM --version | head -n 1 | rev | cut -d' ' -f1 | rev`
- MAJOR_FOUND=`echo $VERSION | cut -d. -f1`
- MINOR_FOUND=`echo $VERSION | sed 's/[a-zA-Z-].*//' | cut -d. -f2`
- [ -z "$MINOR_FOUND" ] && MINOR_FOUND=0
-
- WRONG=
- if [ "$MAJOR_FOUND" -lt "$MAJOR" ]; then
- WRONG=1
- elif [ "$MAJOR_FOUND" -eq "$MAJOR" ]; then
- if [ "$MINOR_FOUND" -lt "$MINOR" ]; then
- WRONG=1
- fi
- fi
- if [ ! -z "$WRONG" ]; then
- printf "\n\n**Error**: found version $MAJOR_FOUND.$MINOR_FOUND,"
- printf "\nwhich is too old. You should upgrade $PROGRAM."
- printf "\nDownload the appropriate package for your distribution,"
- printf "\nor get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
- printf "\n"
- exit 1
- else
- printf "OK, found $MAJOR_FOUND.$MINOR_FOUND\n"
- fi
-}
-
-# Dirty hack to run gettextize: problem is that it demands to
-# press Return no matter what... This gets rid of that demand.
-run_gettext()
-{
- PROGRAM=gettextize
- printf "Running $PROGRAM $GETTEXT_FLAGS ... "
- sed 's:read .*< /dev/tty::' `which $PROGRAM` > my-gettextize
- chmod +x my-gettextize
- (printf "\n" | ./my-gettextize $GETTEXT_FLAGS > /dev/null 2>&1) || {
- printf "\n\n**Error**: $PROGRAM failed.\n"
- exit 1
- }
-
- # now restore the files modified by gettextize
- (test -f configure.ac~) && mv -f configure.ac~ configure.ac
- (test -f Makefile.am~) && mv -f Makefile.am~ Makefile.am
- mv -f po/Makevars.template po/Makevars
- rm my-gettextize
- printf "OK\n"
-}
-
-# Function to run a program
-run_program()
-{
- PROGRAM=$1
- shift
- PROGRAM_FLAGS=$@
- printf "Running $PROGRAM $PROGRAM_FLAGS ... "
- $PROGRAM $PROGRAM_FLAGS > /dev/null 2>&1 || {
- printf "\n\n**Error**: $PROGRAM failed.\n"
- exit 1
- }
- printf "OK\n"
-}
-
-# Main
-echo " --- $PKG_NAME autogen script ---\n"
-check_directory_level
-clean_old_files
-check_program gettext
-check_program gettextize
-check_program_version gettext $GETTEXT_VERSION
-check_program aclocal
-check_program autoheader
-check_program automake
-check_program_version automake $AM_VERSION
-check_program autoconf
-check_program_version autoconf $AC_VERSION
-run_gettext
-run_program aclocal $ACLOCAL_FLAGS
-run_program autoheader
-run_program automake $AM_FLAGS
-run_program autoconf $AC_FLAGS
-clean_backup_files
-printf "\nYou can now run the configure script to obtain $PKG_NAME Makefile.\n"
+aclocal -I m4
+autoheader
+automake --foreign --copy --add-missing
+autoconf
diff --git a/doc/calcurse.1.txt b/doc/calcurse.1.txt
index 6768088..2383e95 100644
--- a/doc/calcurse.1.txt
+++ b/doc/calcurse.1.txt
@@ -42,7 +42,7 @@ Synopsis
--------
[verse]
-*calcurse* [*-h*|*-v*] [*-an*] [*-t*[num]] [*-c*<file> | *-D*<dir>]
+*calcurse* [*-h*|*-v*] [*-an*] [*-t*[num]] [*-c*<file>] [*-D*<dir>]
[*-i*<file>] [*-x*[format]] [*-d* <date>|<num>]
[*-s*[date]] [*-r*[range]] [*-S* <regex>] [*--status*]
@@ -65,9 +65,8 @@ The following options are supported:
from which to read the appointments can be specified using the *-c* flag.
*-c* <file>, *--calendar* <file>::
- Specify the calendar file to use. The default calendar is
- *~/.calcurse/apts* (see section 'FILES' below). This option is incompatible
- with -*D*.
+ Specify the calendar file to use. The default calendar is *~/.calcurse/apts*
+ (see section 'FILES' below). This option has precedence over *-D*.
*-d* <date|num>, *--day* <date|num>::
Print the appointments for the given date or for the given number of
@@ -100,8 +99,8 @@ menu. Four formats are available:
appointments can be specified using the *-c* flag.
*-D* <dir>, *--directory* <dir>::
- Specify the data directory to use. This option is incompatible with -c.
- If not specified, the default directory is *~/.calcurse/*.
+ Specify the data directory to use. If not specified, the default directory is
+ *~/.calcurse/*.
*--format-apt* <format>::
Specify a format to control the output of appointments in non-interactive
diff --git a/doc/manual.txt b/doc/manual.txt
index 2ff8a9a..7f8ac93 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -181,8 +181,9 @@ long options are supported):
from which to read the appointments can be specified using the `-c` flag.
`-c <file>, --calendar <file>`::
- Specify the calendar file to use. The default calendar is
- `~/.calcurse/apts` (see section <<basics_files,calcurse files>>).
+ Specify the calendar file to use. The default calendar is `~/.calcurse/apts`
+ (see section <<basics_files,calcurse files>>). This option has precedence
+ over `-D`.
`-d <date|num>, --day <date|num>`::
Print the appointments for the given date or for the given number of
@@ -206,8 +207,8 @@ Note: as for the `-a` flag, the calendar from which to read the appointments
can be specified using the `-c` flag.
`-D <dir>, --directory <dir>`::
- Specify the data directory to use. This option is incompatible with -c.
- If not specified, the default directory is `~/.calcurse/`.
+ Specify the data directory to use. If not specified, the default directory is
+ `~/.calcurse/`.
`--format-apt <format>`::
Specify a format to control the output of appointments in non-interactive
@@ -1291,20 +1292,23 @@ So here is a list of contributing persons I would like to thank :
* Joel for its calendar script which inspired `calcurse` calendar view
-* Michael Schulz and Chris M. for the german translation of `calcurse` and its
- manual
+* Jeremy Roon for the Dutch translation
-* Jose Lopez for the spanish translation of `calcurse` and its manual
+* Frédéric Culot, Toucouch, Erik Saule, Stéphane Aulery
+ and Baptiste Jonglez for the French translation
-* Neil Williams for the english translation
+* Michael Schulz, Chris M., Benjamin Moeller and Lukas Fleischer for the German
+ translation
-* Leandro Noferini for the italian translation
+* Rafael Ferreira for the Portuguese (Brazil) translation
+
+* Aleksey Mechonoshin for the Russian translation
+
+* Jose Lopez for the Spanish translation
* Tony for its patch which helped improving the recur_item_inday() function,
and for implementing the date format configuration options
-* Jeremy Roon for the dutch translation
-
* Erik Saule for its patch implementing the `-N`, `-s`, `-S`, `-r` and `-D`
flags
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6b3969a..0827a52 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ src/event.c
src/getstring.c
src/help.c
src/ical.c
+src/interaction.c
src/io.c
src/keys.c
src/llist.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 7eab77f..cb44177 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@ calcurse_SOURCES = \
getstring.c \
help.c \
ical.c \
+ interaction.c \
io.c \
keys.c \
llist.c \
diff --git a/src/apoint.c b/src/apoint.c
index 03ccb36..a756fac 100644
--- a/src/apoint.c
+++ b/src/apoint.c
@@ -42,35 +42,30 @@
#include "calcurse.h"
llist_ts_t alist_p;
-static struct apoint bkp_cut_apoint;
static int hilt;
-void apoint_free_bkp(void)
-{
- if (bkp_cut_apoint.mesg) {
- mem_free(bkp_cut_apoint.mesg);
- bkp_cut_apoint.mesg = 0;
- }
- erase_note(&bkp_cut_apoint.note);
-}
-
-static void apoint_free(struct apoint *apt)
+void apoint_free(struct apoint *apt)
{
mem_free(apt->mesg);
erase_note(&apt->note);
mem_free(apt);
}
-static void apoint_dup(struct apoint *in, struct apoint *bkp)
+struct apoint *apoint_dup(struct apoint *in)
{
- EXIT_IF(!in || !bkp, _("null pointer"));
+ EXIT_IF(!in, _("null pointer"));
- bkp->start = in->start;
- bkp->dur = in->dur;
- bkp->state = in->state;
- bkp->mesg = mem_strdup(in->mesg);
+ struct apoint *apt = mem_malloc(sizeof(struct apoint));
+ apt->start = in->start;
+ apt->dur = in->dur;
+ apt->state = in->state;
+ apt->mesg = mem_strdup(in->mesg);
if (in->note)
- bkp->note = mem_strdup(in->note);
+ apt->note = mem_strdup(in->note);
+ else
+ apt->note = NULL;
+
+ return apt;
}
void apoint_llist_init(void)
@@ -135,204 +130,9 @@ struct apoint *apoint_new(char *mesg, char *note, long start, long dur,
return apt;
}
-/*
- * Add an item in either the appointment or the event list,
- * depending if the start time is entered or not.
- */
-void apoint_add(void)
+unsigned apoint_inday(struct apoint *i, long *start)
{
-#define LTIME 6
-#define LDUR 12
- const char *mesg_1 =
- _("Enter start time ([hh:mm]), leave blank for an all-day event : ");
- const char *mesg_2 =
- _
- ("Enter end time ([hh:mm]) or duration ([+hh:mm], [+xxxdxxhxxm] or [+mm]) : ");
- const char *mesg_3 = _("Enter description :");
- const char *format_message_1 =
- _("You entered an invalid start time, should be [hh:mm]");
- const char *format_message_2 =
- _
- ("Invalid end time/duration, should be [hh:mm], [+hh:mm], [+xxxdxxhxxm] or [+mm]");
- const char *enter_str = _("Press [Enter] to continue");
- int Id = 1;
- char item_time[LDUR] = "";
- char item_mesg[BUFSIZ] = "";
- long apoint_start;
- unsigned heures, minutes;
- unsigned apoint_duration;
- unsigned end_h, end_m;
- int is_appointment = 1;
-
- /* Get the starting time */
- for (;;) {
- status_mesg(mesg_1, "");
- if (getstring(win[STA].p, item_time, LTIME, 0, 1) != GETSTRING_ESC) {
- if (strlen(item_time) == 0) {
- is_appointment = 0;
- break;
- }
-
- if (parse_time(item_time, &heures, &minutes) == 1)
- break;
- else {
- status_mesg(format_message_1, enter_str);
- wgetch(win[STA].p);
- }
- } else
- return;
- }
-
- /*
- * Check if an event or appointment is entered,
- * depending on the starting time, and record the
- * corresponding item.
- */
- if (is_appointment) { /* Get the appointment duration */
- item_time[0] = '\0';
- for (;;) {
- status_mesg(mesg_2, "");
- if (getstring(win[STA].p, item_time, LDUR, 0, 1) != GETSTRING_ESC) {
- if (*item_time == '+' && parse_duration(item_time + 1,
- &apoint_duration) == 1)
- break;
- else if (parse_time(item_time, &end_h, &end_m) == 1) {
- if (end_h < heures || ((end_h == heures) && (end_m < minutes))) {
- apoint_duration = MININSEC - minutes + end_m
- + (24 + end_h - (heures + 1)) * MININSEC;
- } else {
- apoint_duration = MININSEC - minutes
- + end_m + (end_h - (heures + 1)) * MININSEC;
- }
- break;
- } else {
- status_mesg(format_message_2, enter_str);
- wgetch(win[STA].p);
- }
- } else
- return;
- }
- } else /* Insert the event Id */
- Id = 1;
-
- status_mesg(mesg_3, "");
- if (getstring(win[STA].p, item_mesg, BUFSIZ, 0, 1) == GETSTRING_VALID) {
- if (is_appointment) {
- apoint_start = date2sec(*calendar_get_slctd_day(), heures, minutes);
- apoint_new(item_mesg, 0L, apoint_start, min2sec(apoint_duration), 0L);
- if (notify_bar())
- notify_check_added(item_mesg, apoint_start, 0L);
- } else
- event_new(item_mesg, 0L, date2sec(*calendar_get_slctd_day(), 0, 0), Id);
-
- if (hilt == 0)
- hilt++;
- }
- wins_erase_status_bar();
-}
-
-/* Delete an item from the appointment list. */
-void apoint_delete(unsigned *nb_events, unsigned *nb_apoints)
-{
- const char *del_app_str = _("Do you really want to delete this item ?");
- long date;
- int nb_items = *nb_apoints + *nb_events;
- int to_be_removed = 0;
-
- date = calendar_get_slctd_day_sec();
-
- if (nb_items == 0)
- return;
-
- if (conf.confirm_delete) {
- if (status_ask_bool(del_app_str) != 1) {
- wins_erase_status_bar();
- return;
- }
- }
-
- if (nb_items != 0) {
- switch (day_erase_item(date, hilt, ERASE_DONT_FORCE)) {
- case EVNT:
- case RECUR_EVNT:
- (*nb_events)--;
- to_be_removed = 1;
- break;
- case APPT:
- case RECUR_APPT:
- (*nb_apoints)--;
- to_be_removed = 3;
- break;
- case 0:
- return;
- default:
- EXIT(_("no such type"));
- /* NOTREACHED */
- }
-
- if (hilt > 1)
- hilt--;
- if (apad.first_onscreen >= to_be_removed)
- apad.first_onscreen = apad.first_onscreen - to_be_removed;
- if (nb_items == 1)
- hilt = 0;
- }
-}
-
-/* Cut an item, so that it can be pasted somewhere else later. */
-int apoint_cut(unsigned *nb_events, unsigned *nb_apoints)
-{
- const int NBITEMS = *nb_apoints + *nb_events;
- int item_type, to_be_removed;
- long date;
-
- if (NBITEMS == 0)
- return 0;
-
- date = calendar_get_slctd_day_sec();
- item_type = day_cut_item(date, hilt);
- if (item_type == EVNT || item_type == RECUR_EVNT) {
- (*nb_events)--;
- to_be_removed = 1;
- } else if (item_type == APPT || item_type == RECUR_APPT) {
- (*nb_apoints)--;
- to_be_removed = 3;
- } else
- EXIT(_("no such type"));
- /* NOTREACHED */
-
- if (hilt > 1)
- hilt--;
- if (apad.first_onscreen >= to_be_removed)
- apad.first_onscreen = apad.first_onscreen - to_be_removed;
- if (NBITEMS == 1)
- hilt = 0;
-
- return item_type;
-}
-
-/* Paste a previously cut item. */
-void apoint_paste(unsigned *nb_events, unsigned *nb_apoints, int cut_item_type)
-{
- int item_type;
- long date;
-
- date = calendar_get_slctd_day_sec();
- item_type = day_paste_item(date, cut_item_type);
- if (item_type == EVNT || item_type == RECUR_EVNT)
- (*nb_events)++;
- else if (item_type == APPT || item_type == RECUR_APPT)
- (*nb_apoints)++;
- else
- return;
-
- if (hilt == 0)
- hilt++;
-}
-
-unsigned apoint_inday(struct apoint *i, long start)
-{
- return (i->start <= start + DAYINSEC && i->start + i->dur > start);
+ return (i->start <= *start + DAYINSEC && i->start + i->dur > *start);
}
void apoint_sec2str(struct apoint *o, long day, char *start, char *end)
@@ -410,49 +210,21 @@ struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end, char state,
return apoint_new(buf, note, tstart, tend - tstart, state);
}
-/* Retrieve an appointment from the list, given the day and item position. */
-struct apoint *apoint_get(long day, int pos)
+void apoint_delete(struct apoint *apt)
{
- llist_item_t *i = LLIST_TS_FIND_NTH(&alist_p, pos, day, apoint_inday);
-
- if (i)
- return LLIST_TS_GET_DATA(i);
-
- EXIT(_("item not found"));
- /* NOTREACHED */
-}
+ LLIST_TS_LOCK(&alist_p);
-void apoint_delete_bynum(long start, unsigned num, enum eraseflg flag)
-{
- llist_item_t *i;
+ llist_item_t *i = LLIST_TS_FIND_FIRST(&alist_p, apt, NULL);
int need_check_notify = 0;
- LLIST_TS_LOCK(&alist_p);
- i = LLIST_TS_FIND_NTH(&alist_p, num, start, apoint_inday);
-
if (!i)
EXIT(_("no such appointment"));
- struct apoint *apt = LLIST_TS_GET_DATA(i);
-
- switch (flag) {
- case ERASE_FORCE_ONLY_NOTE:
- erase_note(&apt->note);
- break;
- case ERASE_CUT:
- apoint_free_bkp();
- apoint_dup(apt, &bkp_cut_apoint);
- erase_note(&apt->note);
- /* FALLTHROUGH */
- default:
- if (notify_bar())
- need_check_notify = notify_same_item(apt->start);
- LLIST_TS_REMOVE(&alist_p, i);
- mem_free(apt->mesg);
- mem_free(apt);
- if (need_check_notify)
- notify_check_next_app(0);
- break;
- }
+
+ if (notify_bar())
+ need_check_notify = notify_same_item(apt->start);
+ LLIST_TS_REMOVE(&alist_p, i);
+ if (need_check_notify)
+ notify_check_next_app(0);
LLIST_TS_UNLOCK(&alist_p);
}
@@ -509,9 +281,9 @@ void apoint_scroll_pad_up(int nb_events_inday)
apad.first_onscreen = item_first_line;
}
-static int apoint_starts_after(struct apoint *apt, long time)
+static int apoint_starts_after(struct apoint *apt, long *time)
{
- return apt->start > time;
+ return apt->start > *time;
}
/*
@@ -523,7 +295,7 @@ struct notify_app *apoint_check_next(struct notify_app *app, long start)
llist_item_t *i;
LLIST_TS_LOCK(&alist_p);
- i = LLIST_TS_FIND_FIRST(&alist_p, start, apoint_starts_after);
+ i = LLIST_TS_FIND_FIRST(&alist_p, &start, apoint_starts_after);
if (i) {
struct apoint *apt = LLIST_TS_GET_DATA(i);
@@ -544,34 +316,13 @@ struct notify_app *apoint_check_next(struct notify_app *app, long start)
/*
* Switch notification state.
*/
-void apoint_switch_notify(void)
+void apoint_switch_notify(struct apoint *apt)
{
- struct day_item *p;
- long date;
- int apoint_nb = 0, need_chk_notify;
-
- p = day_get_item(hilt);
- if (p->type != APPT && p->type != RECUR_APPT)
- return;
-
- date = calendar_get_slctd_day_sec();
-
- if (p->type == RECUR_APPT) {
- recur_apoint_switch_notify(date, p->appt_pos);
- return;
- } else if (p->type == APPT)
- apoint_nb = day_item_nb(date, hilt, APPT);
-
- need_chk_notify = 0;
LLIST_TS_LOCK(&alist_p);
- struct apoint *apt = apoint_get(date, apoint_nb);
-
apt->state ^= APOINT_NOTIFY;
if (notify_bar())
notify_check_added(apt->mesg, apt->start, apt->state);
- if (need_chk_notify)
- notify_check_next_app(0);
LLIST_TS_UNLOCK(&alist_p);
}
@@ -605,9 +356,8 @@ void apoint_update_panel(int which_pan)
/* Draw the scrollbar if necessary. */
if ((apad.length >= app_length) || (apad.first_onscreen > 0)) {
- float ratio = ((float)app_length) / ((float)apad.length);
- int sbar_length = (int)(ratio * app_length);
- int highend = (int)(ratio * apad.first_onscreen);
+ int sbar_length = app_length * app_length / apad.length;
+ int highend = app_length * apad.first_onscreen / apad.length;
unsigned hilt_bar = (which_pan == APP) ? 1 : 0;
int sbar_top = highend + title_lines + 1;
@@ -624,17 +374,14 @@ void apoint_update_panel(int which_pan)
win[APP].x + win[APP].w - 3 * bordr);
}
-void apoint_paste_item(void)
+void apoint_paste_item(struct apoint *apt, long date)
{
- long bkp_time, bkp_start;
+ apt->start = date + get_item_time(apt->start);
- bkp_time = get_item_time(bkp_cut_apoint.start);
- bkp_start = calendar_get_slctd_day_sec() + bkp_time;
- apoint_new(bkp_cut_apoint.mesg, bkp_cut_apoint.note, bkp_start,
- bkp_cut_apoint.dur, bkp_cut_apoint.state);
+ LLIST_TS_LOCK(&alist_p);
+ LLIST_TS_ADD_SORTED(&alist_p, apt, apoint_cmp_start);
+ LLIST_TS_UNLOCK(&alist_p);
if (notify_bar())
- notify_check_added(bkp_cut_apoint.mesg, bkp_start, bkp_cut_apoint.state);
-
- apoint_free_bkp();
+ notify_check_added(apt->mesg, apt->start, apt->state);
}
diff --git a/src/args.c b/src/args.c
index 01f24e9..57aeac8 100644
--- a/src/args.c
+++ b/src/args.c
@@ -41,7 +41,6 @@
#include <limits.h>
#include <getopt.h>
#include <time.h>
-#include <regex.h>
#include "calcurse.h"
@@ -63,7 +62,7 @@ static void usage(void)
const char *arg_usage =
_("Usage: calcurse [-g|-h|-v] [-an] [-t[num]] [-i<file>] [-x[format]]\n"
" [-d <date>|<num>] [-s[date]] [-r[range]]\n"
- " [-c<file> | -D<dir>] [-S<regex>] [--status]\n"
+ " [-c<file>] [-D<dir>] [-S<regex>] [--status]\n"
" [--read-only]\n");
fputs(arg_usage, stdout);
}
@@ -113,9 +112,9 @@ static void help_arg(void)
" Don't save configuration nor appointments/todos. Use with care.\n"
"\nFiles:\n"
" -c <file>, --calendar <file>\n"
- " specify the calendar <file> to use (incompatible with '-D').\n"
+ " specify the calendar <file> to use (has precedence over '-D').\n"
"\n -D <dir>, --directory <dir>\n"
- " specify the data directory to use (incompatible with '-c').\n"
+ " specify the data directory to use.\n"
"\tIf not specified, the default directory is ~/.calcurse\n"
"\nNon-interactive:\n"
" -a, --appointment\n"
@@ -289,123 +288,21 @@ static void arg_print_date(long date)
static int
app_arg(int add_line, struct date *day, long date, const char *fmt_apt,
const char *fmt_rapt, const char *fmt_ev, const char *fmt_rev,
- regex_t * regex)
+ regex_t *regex)
{
- llist_item_t *i, *j;
- long today;
- unsigned print_date = 1;
- int app_found = 0;
-
if (date == 0)
- today = get_sec_date(*day);
- else
- today = date;
+ date = get_sec_date(*day);
- /*
- * Calculate and print the selected date if there is an event for
- * that date and it is the first one, and then print all the events for
- * that date.
- */
- LLIST_FIND_FOREACH(&recur_elist, today, recur_event_inday, i) {
- struct recur_event *re = LLIST_GET_DATA(i);
- if (regex && regexec(regex, re->mesg, 0, 0, 0) != 0)
- continue;
+ int n = day_store_items(date, NULL, NULL, regex);
- app_found = 1;
- if (add_line) {
+ if (n > 0) {
+ if (add_line)
fputs("\n", stdout);
- add_line = 0;
- }
- if (print_date) {
- arg_print_date(today);
- print_date = 0;
- }
- print_recur_event(fmt_rev, today, re);
- }
-
- LLIST_FIND_FOREACH_CONT(&eventlist, today, event_inday, i) {
- struct event *ev = LLIST_TS_GET_DATA(i);
- if (regex && regexec(regex, ev->mesg, 0, 0, 0) != 0)
- continue;
-
- app_found = 1;
- if (add_line) {
- fputs("\n", stdout);
- add_line = 0;
- }
- if (print_date) {
- arg_print_date(today);
- print_date = 0;
- }
- print_event(fmt_ev, today, ev);
- }
-
- /* Same process is performed but this time on the appointments. */
- LLIST_TS_LOCK(&alist_p);
- LLIST_TS_LOCK(&recur_alist_p);
-
- /*
- * Iterate over regular appointments and recurrent ones simultaneously (fixes
- * http://lists.calcurse.org/bugs/msg00002.html).
- */
- i = LLIST_TS_FIND_FIRST(&alist_p, today, apoint_inday);
- j = LLIST_TS_FIND_FIRST(&recur_alist_p, today, recur_apoint_inday);
- while (i || j) {
- struct apoint *apt = LLIST_TS_GET_DATA(i);
- struct recur_apoint *ra = LLIST_TS_GET_DATA(j);
- unsigned occurrence;
-
- while (i && regex && regexec(regex, apt->mesg, 0, 0, 0) != 0) {
- i = LLIST_TS_FIND_NEXT(i, today, apoint_inday);
- apt = LLIST_TS_GET_DATA(i);
- }
-
- while (j && regex && regexec(regex, ra->mesg, 0, 0, 0) != 0) {
- j = LLIST_TS_FIND_NEXT(j, today, recur_apoint_inday);
- ra = LLIST_TS_GET_DATA(j);
- }
-
- if (apt && ra) {
- if (recur_apoint_find_occurrence(ra, today, &occurrence) &&
- apt->start <= occurrence)
- ra = NULL;
- else
- apt = NULL;
- }
-
- if (apt) {
- app_found = 1;
- if (add_line) {
- fputs("\n", stdout);
- add_line = 0;
- }
- if (print_date) {
- arg_print_date(today);
- print_date = 0;
- }
- print_apoint(fmt_apt, today, apt);
- i = LLIST_TS_FIND_NEXT(i, today, apoint_inday);
- } else if (ra) {
- app_found = 1;
- if (add_line) {
- fputs("\n", stdout);
- add_line = 0;
- }
- if (print_date) {
- arg_print_date(today);
- print_date = 0;
- }
- recur_apoint_find_occurrence(ra, today, &occurrence);
- print_recur_apoint(fmt_rapt, today, occurrence, ra);
- apt = NULL;
- j = LLIST_TS_FIND_NEXT(j, today, recur_apoint_inday);
- }
+ arg_print_date(date);
+ day_write_stdout(date, fmt_apt, fmt_rapt, fmt_ev, fmt_rev);
}
- LLIST_TS_UNLOCK(&recur_alist_p);
- LLIST_TS_UNLOCK(&alist_p);
-
- return app_found;
+ return n;
}
/*
@@ -548,9 +445,7 @@ int parse_args(int argc, char **argv)
int unknown_flag = 0;
/* Command-line flags */
int aflag = 0; /* -a: print appointments for current day */
- int cflag = 0; /* -c: specify the calendar file to use */
int dflag = 0; /* -d: print appointments for a specified days */
- int Dflag = 0; /* -D: specify data directory to use */
int hflag = 0; /* -h: print help text */
int gflag = 0; /* -g: run garbage collector */
int iflag = 0; /* -i: import data */
@@ -619,7 +514,6 @@ int parse_args(int argc, char **argv)
load_data++;
break;
case 'c':
- cflag = 1;
multiple_flag++;
cfile = optarg;
load_data++;
@@ -631,7 +525,6 @@ int parse_args(int argc, char **argv)
ddate = optarg;
break;
case 'D':
- Dflag = 1;
datadir = optarg;
break;
case 'h':
@@ -741,11 +634,6 @@ int parse_args(int argc, char **argv)
usage_try();
return EXIT_FAILURE;
/* Incorrect arguments */
- } else if (Dflag && cflag) {
- fputs(_("Options '-D' and '-c' cannot be used at the same time\n"), stderr);
- usage();
- usage_try();
- return EXIT_FAILURE;
} else if (Sflag && !(aflag || dflag || rflag || sflag || tflag)) {
fputs(_("Option '-S' must be used with either '-d', '-r', '-s', "
"'-a' or '-t'\n"), stderr);
diff --git a/src/calcurse.c b/src/calcurse.c
index 09baab5..000436c 100644
--- a/src/calcurse.c
+++ b/src/calcurse.c
@@ -38,6 +38,11 @@
#include "calcurse.h"
+#define HANDLE_KEY(key, fn) case key: fn(); break;
+
+struct day_items_nb inday;
+int count, reg;
+
/*
* Store the events and appointments for the selected day and reset the
* appointment highlight pointer if a new day was selected.
@@ -53,6 +58,418 @@ static struct day_items_nb do_storage(int day_changed)
return inday;
}
+static inline void key_generic_change_view(void)
+{
+ wins_reset_status_page();
+ wins_slctd_next();
+
+ /* Select the event to highlight. */
+ switch (wins_slctd()) {
+ case TOD:
+ if ((todo_hilt() == 0) && (todo_nb() > 0))
+ todo_hilt_set(1);
+ break;
+ case APP:
+ if ((apoint_hilt() == 0) && ((inday.nb_events + inday.nb_apoints) > 0))
+ apoint_hilt_set(1);
+ break;
+ default:
+ break;
+ }
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_other_cmd(void)
+{
+ wins_other_status_page(wins_slctd());
+ wins_update(FLAG_STA);
+}
+
+static inline void key_generic_goto(void)
+{
+ wins_erase_status_bar();
+ calendar_set_current_date();
+ calendar_change_day(conf.input_datefmt);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+}
+
+static inline void key_generic_goto_today(void)
+{
+ wins_erase_status_bar();
+ calendar_set_current_date();
+ calendar_goto_today();
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+}
+
+static inline void key_view_item(void)
+{
+ if ((wins_slctd() == APP) && (apoint_hilt() != 0))
+ day_popup_item(day_get_item(apoint_hilt()));
+ else if ((wins_slctd() == TOD) && (todo_hilt() != 0))
+ item_in_popup(NULL, NULL, todo_saved_mesg(), _("To do :"));
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_config_menu(void)
+{
+ wins_erase_status_bar();
+ custom_config_main();
+ inday = do_storage(0);
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_add_appt(void)
+{
+ interact_day_item_add();
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+}
+
+static inline void key_generic_add_todo(void)
+{
+ interact_todo_add();
+ if (todo_hilt() == 0 && todo_nb() == 1)
+ todo_hilt_increase(1);
+ wins_update(FLAG_TOD | FLAG_STA);
+}
+
+static inline void key_add_item(void)
+{
+ switch (wins_slctd()) {
+ case APP:
+ interact_day_item_add();
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+ case TOD:
+ interact_todo_add();
+ if (todo_hilt() == 0 && todo_nb() == 1)
+ todo_hilt_increase(1);
+ wins_update(FLAG_TOD | FLAG_STA);
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void key_edit_item(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0) {
+ interact_day_item_edit();
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+ } else if (wins_slctd() == TOD && todo_hilt() != 0) {
+ interact_todo_edit();
+ wins_update(FLAG_TOD | FLAG_STA);
+ }
+}
+
+static inline void key_del_item(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0) {
+ interact_day_item_delete(&inday.nb_events, &inday.nb_apoints, reg);
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+ } else if (wins_slctd() == TOD && todo_hilt() != 0) {
+ interact_todo_delete();
+ wins_update(FLAG_TOD | FLAG_STA);
+ }
+}
+
+static inline void key_generic_copy(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0) {
+ interact_day_item_copy(&inday.nb_events, &inday.nb_apoints, reg);
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_generic_paste(void)
+{
+ if (wins_slctd() == APP) {
+ interact_day_item_paste(&inday.nb_events, &inday.nb_apoints, reg);
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_repeat_item(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0)
+ interact_day_item_repeat();
+ inday = do_storage(0);
+ wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
+}
+
+static inline void key_flag_item(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0) {
+ day_item_switch_notify(day_get_item(apoint_hilt()));
+ inday = do_storage(0);
+ wins_update(FLAG_APP);
+ } else if (wins_slctd() == TOD && todo_hilt() != 0) {
+ todo_flag(todo_get_item(todo_hilt()));
+ wins_update(FLAG_TOD);
+ }
+}
+
+static inline void key_pipe_item(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0)
+ interact_day_item_pipe();
+ else if (wins_slctd() == TOD && todo_hilt() != 0)
+ interact_todo_pipe();
+ wins_update(FLAG_ALL);
+}
+
+static inline void change_priority(int diff)
+{
+ if (wins_slctd() == TOD && todo_hilt() != 0) {
+ todo_chg_priority(todo_get_item(todo_hilt()), diff);
+ if (todo_hilt_pos() < 0)
+ todo_set_first(todo_hilt());
+ else if (todo_hilt_pos() >= win[TOD].h - 4)
+ todo_set_first(todo_hilt() - win[TOD].h + 5);
+ wins_update(FLAG_TOD);
+ }
+}
+
+static inline void key_raise_priority(void)
+{
+ change_priority(1);
+}
+
+static inline void key_lower_priority(void)
+{
+ change_priority(-1);
+}
+
+static inline void key_edit_note(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0) {
+ day_edit_note(day_get_item(apoint_hilt()), conf.editor);
+ inday = do_storage(0);
+ } else if (wins_slctd() == TOD && todo_hilt() != 0)
+ todo_edit_note(todo_get_item(todo_hilt()), conf.editor);
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_view_note(void)
+{
+ if (wins_slctd() == APP && apoint_hilt() != 0)
+ day_view_note(day_get_item(apoint_hilt()), conf.pager);
+ else if (wins_slctd() == TOD && todo_hilt() != 0)
+ todo_view_note(todo_get_item(todo_hilt()), conf.pager);
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_help(void)
+{
+ wins_status_bar();
+ help_screen();
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_save(void)
+{
+ io_save_cal(IO_SAVE_DISPLAY_BAR);
+ wins_update(FLAG_STA);
+}
+
+static inline void key_generic_import(void)
+{
+ wins_erase_status_bar();
+ io_import_data(IO_IMPORT_ICAL, NULL);
+ calendar_monthly_view_cache_set_invalid();
+ inday = do_storage(0);
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_export()
+{
+ const char *export_msg = _("Export to (i)cal or (p)cal format?");
+ const char *export_choices = _("[ip]");
+ const int nb_export_choices = 2;
+
+ wins_erase_status_bar();
+
+ switch (status_ask_choice(export_msg, export_choices, nb_export_choices)) {
+ case 1:
+ io_export_data(IO_EXPORT_ICAL);
+ break;
+ case 2:
+ io_export_data(IO_EXPORT_PCAL);
+ break;
+ default: /* User escaped */
+ break;
+ }
+
+ inday = do_storage(0);
+ wins_update(FLAG_ALL);
+}
+
+static inline void key_generic_prev_day(void)
+{
+ calendar_move(DAY_PREV, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_move_left(void)
+{
+ if (wins_slctd() == CAL)
+ key_generic_prev_day();
+}
+
+static inline void key_generic_next_day(void)
+{
+ calendar_move(DAY_NEXT, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_move_right(void)
+{
+ if (wins_slctd() == CAL)
+ key_generic_next_day();
+}
+
+static inline void key_generic_prev_week(void)
+{
+ calendar_move(WEEK_PREV, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_move_up(void)
+{
+ if (wins_slctd() == CAL) {
+ key_generic_prev_week();
+ } else if (wins_slctd() == APP) {
+ if (count >= apoint_hilt())
+ count = apoint_hilt() - 1;
+ apoint_hilt_decrease(count);
+ apoint_scroll_pad_up(inday.nb_events);
+ wins_update(FLAG_APP);
+ } else if (wins_slctd() == TOD) {
+ if (count >= todo_hilt())
+ count = todo_hilt() - 1;
+ todo_hilt_decrease(count);
+ if (todo_hilt_pos() < 0)
+ todo_first_increase(todo_hilt_pos());
+ wins_update(FLAG_TOD);
+ }
+}
+
+static inline void key_generic_next_week(void)
+{
+ calendar_move(WEEK_NEXT, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_move_down(void)
+{
+ if (wins_slctd() == CAL) {
+ key_generic_next_week();
+ } else if (wins_slctd() == APP) {
+ if (count > inday.nb_events + inday.nb_apoints - apoint_hilt())
+ count = inday.nb_events + inday.nb_apoints - apoint_hilt();
+ apoint_hilt_increase(count);
+ apoint_scroll_pad_down(inday.nb_events, win[APP].h);
+ wins_update(FLAG_APP);
+ } else if (wins_slctd() == TOD) {
+ if (count > todo_nb() - todo_hilt())
+ count = todo_nb() - todo_hilt();
+ todo_hilt_increase(count);
+ if (todo_hilt_pos() >= win[TOD].h - 4)
+ todo_first_increase(todo_hilt_pos() - win[TOD].h + 5);
+ wins_update(FLAG_TOD);
+ }
+}
+
+static inline void key_generic_prev_month(void)
+{
+ calendar_move(MONTH_PREV, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_generic_next_month(void)
+{
+ calendar_move(MONTH_NEXT, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_generic_prev_year(void)
+{
+ calendar_move(YEAR_PREV, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_generic_next_year(void)
+{
+ calendar_move(YEAR_NEXT, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+}
+
+static inline void key_start_of_week(void)
+{
+ if (wins_slctd() == CAL) {
+ calendar_move(WEEK_START, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_end_of_week(void)
+{
+ if (wins_slctd() == CAL) {
+ calendar_move(WEEK_END, count);
+ inday = do_storage(1);
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_generic_scroll_up(void)
+{
+ if (wins_slctd() == CAL) {
+ calendar_view_prev();
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_generic_scroll_down(void)
+{
+ if (wins_slctd() == CAL) {
+ calendar_view_next();
+ wins_update(FLAG_CAL | FLAG_APP);
+ }
+}
+
+static inline void key_generic_quit(void)
+{
+ if (conf.auto_save)
+ io_save_cal(IO_SAVE_DISPLAY_BAR);
+ if (conf.auto_gc)
+ note_gc();
+
+ if (conf.confirm_quit) {
+ if (status_ask_bool(_("Do you really want to quit ?")) == 1)
+ exit_calcurse(EXIT_SUCCESS);
+ else {
+ wins_erase_status_bar();
+ wins_update(FLAG_STA);
+ }
+ } else
+ exit_calcurse(EXIT_SUCCESS);
+}
+
/*
* Calcurse is a text-based personal organizer which helps keeping track
* of events and everyday tasks. It contains a calendar, a 'todo' list,
@@ -62,10 +479,7 @@ static struct day_items_nb do_storage(int day_changed)
*/
int main(int argc, char **argv)
{
- struct day_items_nb inday;
int no_data_file = 1;
- int cut_item = 0;
- int count;
#if ENABLE_NLS
setlocale(LC_ALL, "");
@@ -174,363 +588,53 @@ int main(int argc, char **argv)
wins_reset();
}
- key = keys_getch(win[STA].p, &count);
+ key = keys_getch(win[STA].p, &count, &reg);
switch (key) {
case KEY_GENERIC_REDRAW:
resize = 1;
break;
- case KEY_GENERIC_CHANGE_VIEW:
- wins_reset_status_page();
- wins_slctd_next();
-
- /* Select the event to highlight. */
- switch (wins_slctd()) {
- case TOD:
- if ((todo_hilt() == 0) && (todo_nb() > 0))
- todo_hilt_set(1);
- break;
- case APP:
- if ((apoint_hilt() == 0) && ((inday.nb_events + inday.nb_apoints) > 0))
- apoint_hilt_set(1);
- break;
- default:
- break;
- }
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_OTHER_CMD:
- wins_other_status_page(wins_slctd());
- wins_update(FLAG_STA);
- break;
-
- case KEY_GENERIC_GOTO:
- case KEY_GENERIC_GOTO_TODAY:
- wins_erase_status_bar();
- calendar_set_current_date();
- if (key == KEY_GENERIC_GOTO_TODAY)
- calendar_goto_today();
- else
- calendar_change_day(conf.input_datefmt);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- break;
-
- case KEY_VIEW_ITEM:
- if ((wins_slctd() == APP) && (apoint_hilt() != 0))
- day_popup_item();
- else if ((wins_slctd() == TOD) && (todo_hilt() != 0))
- item_in_popup(NULL, NULL, todo_saved_mesg(), _("To do :"));
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_CONFIG_MENU:
- wins_erase_status_bar();
- custom_config_main();
- inday = do_storage(0);
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_ADD_APPT:
- apoint_add();
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- break;
-
- case KEY_GENERIC_ADD_TODO:
- todo_new_item();
- if (todo_hilt() == 0 && todo_nb() == 1)
- todo_hilt_increase(1);
- wins_update(FLAG_TOD | FLAG_STA);
- break;
-
- case KEY_ADD_ITEM:
- switch (wins_slctd()) {
- case APP:
- apoint_add();
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- break;
- case TOD:
- todo_new_item();
- if (todo_hilt() == 0 && todo_nb() == 1)
- todo_hilt_increase(1);
- wins_update(FLAG_TOD | FLAG_STA);
- break;
- default:
- break;
- }
- break;
-
- case KEY_EDIT_ITEM:
- if (wins_slctd() == APP && apoint_hilt() != 0) {
- day_edit_item();
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- } else if (wins_slctd() == TOD && todo_hilt() != 0) {
- todo_edit_item();
- wins_update(FLAG_TOD | FLAG_STA);
- }
- break;
-
- case KEY_DEL_ITEM:
- if (wins_slctd() == APP && apoint_hilt() != 0) {
- apoint_delete(&inday.nb_events, &inday.nb_apoints);
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- } else if (wins_slctd() == TOD && todo_hilt() != 0) {
- todo_delete();
- wins_update(FLAG_TOD | FLAG_STA);
- }
- break;
-
- case KEY_GENERIC_CUT:
- if (wins_slctd() == APP && apoint_hilt() != 0) {
- cut_item = apoint_cut(&inday.nb_events, &inday.nb_apoints);
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_PASTE:
- if (wins_slctd() == APP) {
- apoint_paste(&inday.nb_events, &inday.nb_apoints, cut_item);
- cut_item = 0;
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_REPEAT_ITEM:
- if (wins_slctd() == APP && apoint_hilt() != 0)
- recur_repeat_item();
- inday = do_storage(0);
- wins_update(FLAG_CAL | FLAG_APP | FLAG_STA);
- break;
-
- case KEY_FLAG_ITEM:
- if (wins_slctd() == APP && apoint_hilt() != 0) {
- apoint_switch_notify();
- inday = do_storage(0);
- wins_update(FLAG_APP);
- } else if (wins_slctd() == TOD && todo_hilt() != 0) {
- todo_flag();
- wins_update(FLAG_TOD);
- }
- break;
-
- case KEY_PIPE_ITEM:
- if (wins_slctd() == APP && apoint_hilt() != 0)
- day_pipe_item();
- else if (wins_slctd() == TOD && todo_hilt() != 0)
- todo_pipe_item();
- wins_update(FLAG_ALL);
- break;
-
- case KEY_RAISE_PRIORITY:
- case KEY_LOWER_PRIORITY:
- if (wins_slctd() == TOD && todo_hilt() != 0) {
- todo_chg_priority(key);
- if (todo_hilt_pos() < 0)
- todo_set_first(todo_hilt());
- else if (todo_hilt_pos() >= win[TOD].h - 4)
- todo_set_first(todo_hilt() - win[TOD].h + 5);
- wins_update(FLAG_TOD);
- }
- break;
-
- case KEY_EDIT_NOTE:
- if (wins_slctd() == APP && apoint_hilt() != 0) {
- day_edit_note(conf.editor);
- inday = do_storage(0);
- } else if (wins_slctd() == TOD && todo_hilt() != 0)
- todo_edit_note(conf.editor);
- wins_update(FLAG_ALL);
- break;
-
- case KEY_VIEW_NOTE:
- if (wins_slctd() == APP && apoint_hilt() != 0)
- day_view_note(conf.pager);
- else if (wins_slctd() == TOD && todo_hilt() != 0)
- todo_view_note(conf.pager);
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_HELP:
- wins_status_bar();
- help_screen();
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_SAVE:
- io_save_cal(IO_SAVE_DISPLAY_BAR);
- wins_update(FLAG_STA);
- break;
-
- case KEY_GENERIC_IMPORT:
- wins_erase_status_bar();
- io_import_data(IO_IMPORT_ICAL, NULL);
- inday = do_storage(0);
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_EXPORT:
- wins_erase_status_bar();
- io_export_bar();
- while ((key = wgetch(win[STA].p)) != 'q') {
- switch (key) {
- case 'I':
- case 'i':
- io_export_data(IO_EXPORT_ICAL);
- break;
- case 'P':
- case 'p':
- io_export_data(IO_EXPORT_PCAL);
- break;
- }
- wins_reset();
- wins_update(FLAG_ALL);
- wins_erase_status_bar();
- io_export_bar();
- }
- inday = do_storage(0);
- wins_update(FLAG_ALL);
- break;
-
- case KEY_GENERIC_PREV_DAY:
- case KEY_MOVE_LEFT:
- if (wins_slctd() == CAL || key == KEY_GENERIC_PREV_DAY) {
- calendar_move(DAY_PREV, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_NEXT_DAY:
- case KEY_MOVE_RIGHT:
- if (wins_slctd() == CAL || key == KEY_GENERIC_NEXT_DAY) {
- calendar_move(DAY_NEXT, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_PREV_WEEK:
- case KEY_MOVE_UP:
- if (wins_slctd() == CAL || key == KEY_GENERIC_PREV_WEEK) {
- calendar_move(WEEK_PREV, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- } else if (wins_slctd() == APP) {
- if (count >= apoint_hilt())
- count = apoint_hilt() - 1;
- apoint_hilt_decrease(count);
- apoint_scroll_pad_up(inday.nb_events);
- wins_update(FLAG_APP);
- } else if (wins_slctd() == TOD) {
- if (count >= todo_hilt())
- count = todo_hilt() - 1;
- todo_hilt_decrease(count);
- if (todo_hilt_pos() < 0)
- todo_first_increase(todo_hilt_pos());
- wins_update(FLAG_TOD);
- }
- break;
-
- case KEY_GENERIC_NEXT_WEEK:
- case KEY_MOVE_DOWN:
- if (wins_slctd() == CAL || key == KEY_GENERIC_NEXT_WEEK) {
- calendar_move(WEEK_NEXT, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- } else if (wins_slctd() == APP) {
- if (count > inday.nb_events + inday.nb_apoints - apoint_hilt())
- count = inday.nb_events + inday.nb_apoints - apoint_hilt();
- apoint_hilt_increase(count);
- apoint_scroll_pad_down(inday.nb_events, win[APP].h);
- wins_update(FLAG_APP);
- } else if (wins_slctd() == TOD) {
- if (count > todo_nb() - todo_hilt())
- count = todo_nb() - todo_hilt();
- todo_hilt_increase(count);
- if (todo_hilt_pos() >= win[TOD].h - 4)
- todo_first_increase(todo_hilt_pos() - win[TOD].h + 5);
- wins_update(FLAG_TOD);
- }
- break;
-
- case KEY_GENERIC_PREV_MONTH:
- calendar_move(MONTH_PREV, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- break;
-
- case KEY_GENERIC_NEXT_MONTH:
- calendar_move(MONTH_NEXT, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- break;
-
- case KEY_GENERIC_PREV_YEAR:
- calendar_move(YEAR_PREV, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- break;
-
- case KEY_GENERIC_NEXT_YEAR:
- calendar_move(YEAR_NEXT, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- break;
-
- case KEY_START_OF_WEEK:
- if (wins_slctd() == CAL) {
- calendar_move(WEEK_START, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_END_OF_WEEK:
- if (wins_slctd() == CAL) {
- calendar_move(WEEK_END, count);
- inday = do_storage(1);
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_SCROLL_UP:
- if (wins_slctd() == CAL) {
- calendar_view_prev();
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_SCROLL_DOWN:
- if (wins_slctd() == CAL) {
- calendar_view_next();
- wins_update(FLAG_CAL | FLAG_APP);
- }
- break;
-
- case KEY_GENERIC_QUIT:
- if (conf.auto_save)
- io_save_cal(IO_SAVE_DISPLAY_BAR);
- if (conf.auto_gc)
- note_gc();
-
- if (conf.confirm_quit) {
- if (status_ask_bool(_("Do you really want to quit ?")) == 1)
- exit_calcurse(EXIT_SUCCESS);
- else {
- wins_erase_status_bar();
- wins_update(FLAG_STA);
- break;
- }
- } else
- exit_calcurse(EXIT_SUCCESS);
- break;
+ HANDLE_KEY(KEY_GENERIC_CHANGE_VIEW, key_generic_change_view);
+ HANDLE_KEY(KEY_GENERIC_OTHER_CMD, key_generic_other_cmd);
+ HANDLE_KEY(KEY_GENERIC_GOTO, key_generic_goto);
+ HANDLE_KEY(KEY_GENERIC_GOTO_TODAY, key_generic_goto_today);
+ HANDLE_KEY(KEY_VIEW_ITEM, key_view_item);
+ HANDLE_KEY(KEY_GENERIC_CONFIG_MENU, key_generic_config_menu);
+ HANDLE_KEY(KEY_GENERIC_ADD_APPT, key_generic_add_appt);
+ HANDLE_KEY(KEY_GENERIC_ADD_TODO, key_generic_add_todo);
+ HANDLE_KEY(KEY_ADD_ITEM, key_add_item);
+ HANDLE_KEY(KEY_EDIT_ITEM, key_edit_item);
+ HANDLE_KEY(KEY_DEL_ITEM, key_del_item);
+ HANDLE_KEY(KEY_GENERIC_COPY, key_generic_copy);
+ HANDLE_KEY(KEY_GENERIC_PASTE, key_generic_paste);
+ HANDLE_KEY(KEY_REPEAT_ITEM, key_repeat_item);
+ HANDLE_KEY(KEY_FLAG_ITEM, key_flag_item);
+ HANDLE_KEY(KEY_PIPE_ITEM, key_pipe_item);
+ HANDLE_KEY(KEY_RAISE_PRIORITY, key_raise_priority);
+ HANDLE_KEY(KEY_LOWER_PRIORITY, key_lower_priority);
+ HANDLE_KEY(KEY_EDIT_NOTE, key_edit_note);
+ HANDLE_KEY(KEY_VIEW_NOTE, key_view_note);
+ HANDLE_KEY(KEY_GENERIC_HELP, key_generic_help);
+ HANDLE_KEY(KEY_GENERIC_SAVE, key_generic_save);
+ HANDLE_KEY(KEY_GENERIC_IMPORT, key_generic_import);
+ HANDLE_KEY(KEY_GENERIC_EXPORT, key_generic_export);
+ HANDLE_KEY(KEY_GENERIC_PREV_DAY, key_generic_prev_day);
+ HANDLE_KEY(KEY_MOVE_LEFT, key_move_left);
+ HANDLE_KEY(KEY_GENERIC_NEXT_DAY, key_generic_next_day);
+ HANDLE_KEY(KEY_MOVE_RIGHT, key_move_right);
+ HANDLE_KEY(KEY_GENERIC_PREV_WEEK, key_generic_prev_week);
+ HANDLE_KEY(KEY_MOVE_UP, key_move_up);
+ HANDLE_KEY(KEY_GENERIC_NEXT_WEEK, key_generic_next_week);
+ HANDLE_KEY(KEY_MOVE_DOWN, key_move_down);
+ HANDLE_KEY(KEY_GENERIC_PREV_MONTH, key_generic_prev_month);
+ HANDLE_KEY(KEY_GENERIC_NEXT_MONTH, key_generic_next_month);
+ HANDLE_KEY(KEY_GENERIC_PREV_YEAR, key_generic_prev_year);
+ HANDLE_KEY(KEY_GENERIC_NEXT_YEAR, key_generic_next_year);
+ HANDLE_KEY(KEY_START_OF_WEEK, key_start_of_week);
+ HANDLE_KEY(KEY_END_OF_WEEK, key_end_of_week);
+ HANDLE_KEY(KEY_GENERIC_SCROLL_UP, key_generic_scroll_up);
+ HANDLE_KEY(KEY_GENERIC_SCROLL_DOWN, key_generic_scroll_down);
+ HANDLE_KEY(KEY_GENERIC_QUIT, key_generic_quit);
case KEY_RESIZE:
case ERR:
diff --git a/src/calcurse.h b/src/calcurse.h
index d7b5093..6a6deaf 100644
--- a/src/calcurse.h
+++ b/src/calcurse.h
@@ -53,6 +53,7 @@
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
+#include <regex.h>
#include "llist.h"
#include "htable.h"
@@ -143,6 +144,8 @@
#define DAYINSEC (DAYINMIN * MININSEC)
#define HOURINSEC (HOURINMIN * MININSEC)
+#define MAXDAYSPERMONTH 31
+
/* Calendar window. */
#define CALHEIGHT 12
@@ -157,6 +160,9 @@
#define KEYS_LABELEN 8 /* length of command description */
#define KEYS_CMDS_PER_LINE 6 /* max number of commands per line */
+/* Register definitions. */
+#define REG_BLACK_HOLE 37
+
/* Size of the hash table the note garbage collector uses. */
#define NOTE_GC_HSIZE 1024
@@ -308,18 +314,6 @@ struct day_items_nb {
unsigned nb_apoints;
};
-/* Generic item description (to hold appointments, events...). */
-struct day_item {
- long start; /* seconds since 1 jan 1970 */
- long appt_dur; /* appointment duration in seconds */
- int type; /* (recursive or normal) event or appointment */
- int evnt_id; /* event identifier */
- int appt_pos; /* real position in recurrent list */
- char state; /* appointment state */
- char *mesg; /* item description */
- char *note; /* note attached to item */
-};
-
struct excp {
long st; /* beggining of the considered day, in seconds */
};
@@ -361,6 +355,21 @@ struct recur_event {
char *note; /* note attached to event */
};
+/* Generic pointer data type for appointments and events. */
+union aptev_ptr {
+ struct apoint *apt;
+ struct event *ev;
+ struct recur_apoint *rapt;
+ struct recur_event *rev;
+};
+
+/* Generic item description (to hold appointments, events...). */
+struct day_item {
+ int type; /* (recursive or normal) event or appointment */
+ long start; /* start time of the repetition occurrence */
+ union aptev_ptr item; /* pointer to the actual item */
+};
+
/* Available view for the calendar panel. */
enum {
CAL_MONTH_VIEW,
@@ -389,7 +398,7 @@ enum key {
KEY_GENERIC_HELP,
KEY_GENERIC_QUIT,
KEY_GENERIC_SAVE,
- KEY_GENERIC_CUT,
+ KEY_GENERIC_COPY,
KEY_GENERIC_PASTE,
KEY_GENERIC_CHANGE_VIEW,
KEY_GENERIC_IMPORT,
@@ -526,14 +535,6 @@ enum item_type {
MAX_TYPES = APPT
};
-/* Flags used to adapt processing when erasing an item. */
-enum eraseflg {
- ERASE_DONT_FORCE,
- ERASE_FORCE,
- ERASE_FORCE_ONLY_NOTE,
- ERASE_CUT
-};
-
/* Return codes for the getstring() function. */
enum getstr {
GETSTRING_VALID,
@@ -602,6 +603,8 @@ enum save_display {
/* apoint.c */
extern llist_ts_t alist_p;
void apoint_free_bkp(void);
+struct apoint *apoint_dup(struct apoint *);
+void apoint_free(struct apoint *);
void apoint_llist_init(void);
void apoint_llist_free(void);
void apoint_hilt_set(int);
@@ -609,22 +612,17 @@ void apoint_hilt_decrease(int);
void apoint_hilt_increase(int);
int apoint_hilt(void);
struct apoint *apoint_new(char *, char *, long, long, char);
-void apoint_add(void);
-void apoint_delete(unsigned *, unsigned *);
-int apoint_cut(unsigned *, unsigned *);
-void apoint_paste(unsigned *, unsigned *, int);
-unsigned apoint_inday(struct apoint *, long);
+unsigned apoint_inday(struct apoint *, long *);
void apoint_sec2str(struct apoint *, long, char *, char *);
void apoint_write(struct apoint *, FILE *);
struct apoint *apoint_scan(FILE *, struct tm, struct tm, char, char *);
-struct apoint *apoint_get(long, int);
-void apoint_delete_bynum(long, unsigned, enum eraseflg);
+void apoint_delete(struct apoint *);
void apoint_scroll_pad_down(int, int);
void apoint_scroll_pad_up(int);
struct notify_app *apoint_check_next(struct notify_app *, long);
-void apoint_switch_notify(void);
+void apoint_switch_notify(struct apoint *);
void apoint_update_panel(int);
-void apoint_paste_item(void);
+void apoint_paste_item(struct apoint *, long);
/* args.c */
int parse_args(int, char **);
@@ -644,6 +642,7 @@ void calendar_store_current_date(struct date *);
void calendar_init_slctd_day(void);
struct date *calendar_get_slctd_day(void);
long calendar_get_slctd_day_sec(void);
+void calendar_monthly_view_cache_set_invalid(void);
void calendar_update_panel(struct window *);
void calendar_goto_today(void);
void calendar_change_day(int);
@@ -674,21 +673,28 @@ void custom_config_main(void);
/* day.c */
void day_free_list(void);
+char *day_item_get_mesg(struct day_item *);
+char *day_item_get_note(struct day_item *);
+void day_item_erase_note(struct day_item *);
+long day_item_get_duration(struct day_item *);
+int day_item_get_state(struct day_item *);
+void day_item_add_exc(struct day_item *, long);
+void day_item_fork(struct day_item *, struct day_item *);
+int day_store_items(long, unsigned *, unsigned *, regex_t *);
struct day_items_nb *day_process_storage(struct date *, unsigned,
struct day_items_nb *);
void day_write_pad(long, int, int, int);
-void day_popup_item(void);
+void day_write_stdout(long, const char *, const char *, const char *,
+ const char *);
+void day_popup_item(struct day_item *);
int day_check_if_item(struct date);
unsigned day_chk_busy_slices(struct date, int, int *);
-void day_edit_item(void);
-int day_erase_item(long, int, enum eraseflg);
-int day_cut_item(long, int);
-int day_paste_item(long, int);
+struct day_item *day_cut_item(long, int);
+int day_paste_item(struct day_item *, long);
struct day_item *day_get_item(int);
-int day_item_nb(long, int, int);
-void day_edit_note(const char *);
-void day_view_note(const char *);
-void day_pipe_item(void);
+void day_edit_note(struct day_item *, const char *);
+void day_view_note(struct day_item *, const char *);
+void day_item_switch_notify(struct day_item *);
/* dmon.c */
void dmon_start(int);
@@ -697,15 +703,16 @@ void dmon_stop(void);
/* event.c */
extern llist_t eventlist;
void event_free_bkp(void);
+struct event *event_dup(struct event *);
+void event_free(struct event *);
void event_llist_init(void);
void event_llist_free(void);
struct event *event_new(char *, char *, long, int);
-unsigned event_inday(struct event *, long);
+unsigned event_inday(struct event *, long *);
void event_write(struct event *, FILE *);
struct event *event_scan(FILE *, struct tm, int, char *);
-struct event *event_get(long, int);
-void event_delete_bynum(long, unsigned, enum eraseflg);
-void event_paste_item(void);
+void event_delete(struct event *);
+void event_paste_item(struct event *, long);
/* help.c */
void help_wins_init(struct scrollwin *, int, int, int, int);
@@ -720,6 +727,20 @@ void ical_import_data(FILE *, FILE *, unsigned *, unsigned *, unsigned *,
unsigned *, unsigned *);
void ical_export_data(FILE *);
+/* interaction.c */
+void interact_day_item_add(void);
+void interact_day_item_delete(unsigned *, unsigned *, unsigned);
+void interact_day_item_edit(void);
+void interact_day_item_pipe(void);
+void interact_day_item_repeat(void);
+void interact_day_item_cut_free(unsigned);
+void interact_day_item_copy(unsigned *, unsigned *, unsigned);
+void interact_day_item_paste(unsigned *, unsigned *, unsigned);
+void interact_todo_add(void);
+void interact_todo_delete(void);
+void interact_todo_edit(void);
+void interact_todo_pipe(void);
+
/* io.c */
unsigned io_fprintln(const char *, const char *, ...);
void io_init(const char *, const char *);
@@ -737,7 +758,6 @@ void io_check_file(char *, int *);
int io_check_data_files(void);
void io_startup_screen(int);
void io_export_data(enum export_type);
-void io_export_bar(void);
void io_import_data(enum import_type, const char *);
struct io_file *io_log_init(void);
void io_log_print(struct io_file *, int, const char *);
@@ -757,7 +777,7 @@ void keys_free(void);
void keys_dump_defaults(char *);
const char *keys_get_label(enum key);
enum key keys_get_action(int);
-enum key keys_getch(WINDOW * win, int *);
+enum key keys_getch(WINDOW * win, int *, int *);
int keys_assign_binding(int, enum key);
void keys_remove_binding(int, enum key);
int keys_str2int(const char *);
@@ -843,8 +863,12 @@ void pcal_export_data(FILE *);
/* recur.c */
extern llist_ts_t recur_alist_p;
extern llist_t recur_elist;
+struct recur_event *recur_event_dup(struct recur_event *);
+struct recur_apoint *recur_apoint_dup(struct recur_apoint *);
void recur_event_free_bkp(void);
void recur_apoint_free_bkp(void);
+void recur_event_free(struct recur_event *);
+void recur_apoint_free(struct recur_apoint *);
void recur_apoint_llist_init(void);
void recur_apoint_llist_free(void);
void recur_event_llist_free(void);
@@ -867,18 +891,17 @@ unsigned recur_item_find_occurrence(long, long, llist_t *, int,
unsigned recur_apoint_find_occurrence(struct recur_apoint *, long, unsigned *);
unsigned recur_event_find_occurrence(struct recur_event *, long, unsigned *);
unsigned recur_item_inday(long, long, llist_t *, int, int, long, long);
-unsigned recur_apoint_inday(struct recur_apoint *, long);
-unsigned recur_event_inday(struct recur_event *, long);
-void recur_event_erase(long, unsigned, unsigned, enum eraseflg);
-void recur_apoint_erase(long, unsigned, unsigned, enum eraseflg);
-void recur_repeat_item(void);
+unsigned recur_apoint_inday(struct recur_apoint *, long *);
+unsigned recur_event_inday(struct recur_event *, long *);
+void recur_event_add_exc(struct recur_event *, long);
+void recur_apoint_add_exc(struct recur_apoint *, long);
+void recur_event_erase(struct recur_event *);
+void recur_apoint_erase(struct recur_apoint *);
void recur_exc_scan(llist_t *, FILE *);
struct notify_app *recur_apoint_check_next(struct notify_app *, long, long);
-struct recur_apoint *recur_get_apoint(long, int);
-struct recur_event *recur_get_event(long, int);
-void recur_apoint_switch_notify(long, int);
-void recur_event_paste_item(void);
-void recur_apoint_paste_item(void);
+void recur_apoint_switch_notify(struct recur_apoint *);
+void recur_event_paste_item(struct recur_event *, long);
+void recur_apoint_paste_item(struct recur_apoint *, long);
/* sigs.c */
void sigs_init(void);
@@ -886,6 +909,7 @@ unsigned sigs_set_hdlr(int, void (*)(int));
/* todo.c */
extern llist_t todolist;
+struct todo *todo_get_item(int);
void todo_hilt_set(int);
void todo_hilt_decrease(int);
void todo_hilt_increase(int);
@@ -897,17 +921,16 @@ void todo_first_increase(int);
void todo_first_decrease(int);
int todo_hilt_pos(void);
char *todo_saved_mesg(void);
-void todo_new_item(void);
struct todo *todo_add(char *, int, char *);
void todo_write(struct todo *, FILE *);
-void todo_flag(void);
-void todo_delete(void);
-void todo_chg_priority(int);
-void todo_edit_item(void);
+void todo_delete_note(struct todo *);
+void todo_delete(struct todo *);
+void todo_flag(struct todo *);
+void todo_chg_priority(struct todo *, int);
void todo_update_panel(int);
-void todo_edit_note(const char *);
-void todo_view_note(const char *);
-void todo_pipe_item(void);
+void todo_edit_note(struct todo *, const char *);
+void todo_view_note(struct todo *, const char *);
+void todo_free(struct todo *);
void todo_init_list(void);
void todo_free_list(void);
diff --git a/src/calendar.c b/src/calendar.c
index df247df..3d7698e 100644
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -77,6 +77,10 @@ static void (*draw_calendar[CAL_VIEWS]) (struct window *, struct date *,
unsigned) = {
draw_monthly_view, draw_weekly_view};
+static int monthly_view_cache[MAXDAYSPERMONTH];
+static int monthly_view_cache_valid = 0;
+static int monthly_view_cache_month = 0;
+
/* Switch between calendar views (monthly view is selected by default). */
void calendar_view_next(void)
{
@@ -264,6 +268,11 @@ static int date_change(struct tm *date, int delta_month, int delta_day)
}
}
+void calendar_monthly_view_cache_set_invalid(void)
+{
+ monthly_view_cache_valid = 0;
+}
+
/* Draw the monthly view inside calendar panel. */
static void
draw_monthly_view(struct window *cwin, struct date *current_day,
@@ -315,13 +324,25 @@ draw_monthly_view(struct window *cwin, struct date *current_day,
day_1_sav = (c_day_1 + 1) * 3 + c_day_1 - 7;
+ /* invalidate cache if a new month is selected */
+ if (yr * YEARINMONTHS + mo != monthly_view_cache_month) {
+ monthly_view_cache_month = yr * YEARINMONTHS + mo;
+ monthly_view_cache_valid = 0;
+ }
+
for (c_day = 1; c_day <= numdays; ++c_day, ++c_day_1, c_day_1 %= 7) {
check_day.dd = c_day;
check_day.mm = slctd_day.mm;
check_day.yyyy = slctd_day.yyyy;
/* check if the day contains an event or an appointment */
- item_this_day = day_check_if_item(check_day);
+ if (monthly_view_cache_valid) {
+ item_this_day = monthly_view_cache[c_day - 1];
+ }
+ else {
+ item_this_day = monthly_view_cache[c_day - 1] =
+ day_check_if_item(check_day);
+ }
/* Go to next line, the week is over. */
if (!c_day_1 && 1 != c_day) {
@@ -357,6 +378,8 @@ draw_monthly_view(struct window *cwin, struct date *current_day,
}
WINS_CALENDAR_UNLOCK;
}
+
+ monthly_view_cache_valid = 1;
}
static int weeknum(const struct tm *t, int firstweekday)
diff --git a/src/custom.c b/src/custom.c
index 72c531b..185f65a 100644
--- a/src/custom.c
+++ b/src/custom.c
@@ -226,7 +226,7 @@ void custom_layout_config(void)
display_layout_config(&conf_win, mark, cursor);
clear();
- while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) {
+ while ((ch = keys_getch(win[STA].p, NULL, NULL)) != KEY_GENERIC_QUIT) {
need_reset = 0;
switch (ch) {
case KEY_GENERIC_HELP:
@@ -310,7 +310,7 @@ void custom_sidebar_config(void)
bindings_size, NULL);
wins_doupdate();
- while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) {
+ while ((ch = keys_getch(win[STA].p, NULL, NULL)) != KEY_GENERIC_QUIT) {
switch (ch) {
case KEY_MOVE_UP:
wins_sbar_winc();
@@ -528,7 +528,7 @@ void custom_color_config(void)
theme_changed);
clear();
- while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) {
+ while ((ch = keys_getch(win[STA].p, NULL, NULL)) != KEY_GENERIC_QUIT) {
need_reset = 0;
theme_changed = 0;
@@ -921,7 +921,7 @@ void custom_keys_config(void)
for (;;) {
int ch;
- ch = keys_getch(win[STA].p, NULL);
+ ch = keys_getch(win[STA].p, NULL, NULL);
switch (ch) {
case KEY_MOVE_UP:
if (selrow > 0) {
diff --git a/src/day.c b/src/day.c
index 29c03e4..978e9d2 100644
--- a/src/day.c
+++ b/src/day.c
@@ -42,16 +42,7 @@
#include "calcurse.h"
-struct day_saved_item {
- char start[BUFSIZ];
- char end[BUFSIZ];
- char state;
- char type;
- char *mesg;
-};
-
static llist_t day_items;
-static struct day_saved_item day_saved_item;
static void day_free(struct day_item *day)
{
@@ -74,26 +65,6 @@ void day_free_list(void)
LLIST_FREE(&day_items);
}
-/* Add an event in the current day list */
-static struct day_item *day_add_event(int type, char *mesg, char *note,
- long nday, int id)
-{
- struct day_item *day;
-
- day = mem_malloc(sizeof(struct day_item));
- day->mesg = mesg;
- day->note = note;
- day->type = type;
- day->appt_dur = 0;
- day->appt_pos = 0;
- day->start = nday;
- day->evnt_id = id;
-
- LLIST_ADD(&day_items, day);
-
- return day;
-}
-
static int day_cmp_start(struct day_item *a, struct day_item *b)
{
if (a->type <= EVNT) {
@@ -107,26 +78,130 @@ static int day_cmp_start(struct day_item *a, struct day_item *b)
return a->start < b->start ? -1 : (a->start == b->start ? 0 : 1);
}
-/* Add an appointment in the current day list. */
-static struct day_item *day_add_apoint(int type, char *mesg, char *note,
- long start, long dur, char state,
- int real_pos)
+/* Add an item to the current day list. */
+static void day_add_item(int type, long start, union aptev_ptr item)
{
- struct day_item *day;
-
- day = mem_malloc(sizeof(struct day_item));
- day->mesg = mesg;
- day->note = note;
- day->start = start;
- day->appt_dur = dur;
- day->appt_pos = real_pos;
- day->state = state;
+ struct day_item *day = mem_malloc(sizeof(struct day_item));
day->type = type;
- day->evnt_id = 0;
+ day->start = start;
+ day->item = item;
LLIST_ADD_SORTED(&day_items, day, day_cmp_start);
+}
- return day;
+/* Get the message of an item. */
+char *day_item_get_mesg(struct day_item *day)
+{
+ switch (day->type) {
+ case APPT:
+ return day->item.apt->mesg;
+ case EVNT:
+ return day->item.ev->mesg;
+ case RECUR_APPT:
+ return day->item.rapt->mesg;
+ case RECUR_EVNT:
+ return day->item.rev->mesg;
+ default:
+ return NULL;
+ }
+}
+
+/* Get the note attached to an item. */
+char *day_item_get_note(struct day_item *day)
+{
+ switch (day->type) {
+ case APPT:
+ return day->item.apt->note;
+ case EVNT:
+ return day->item.ev->note;
+ case RECUR_APPT:
+ return day->item.rapt->note;
+ case RECUR_EVNT:
+ return day->item.rev->note;
+ default:
+ return NULL;
+ }
+}
+
+/* Get the note attached to an item. */
+void day_item_erase_note(struct day_item *day)
+{
+ switch (day->type) {
+ case APPT:
+ erase_note(&day->item.apt->note);
+ break;
+ case EVNT:
+ erase_note(&day->item.ev->note);
+ break;
+ case RECUR_APPT:
+ erase_note(&day->item.rapt->note);
+ break;
+ case RECUR_EVNT:
+ erase_note(&day->item.rev->note);
+ break;
+ }
+}
+
+/* Get the duration of an item. */
+long day_item_get_duration(struct day_item *day)
+{
+ switch (day->type) {
+ case APPT:
+ return day->item.apt->dur;
+ case RECUR_APPT:
+ return day->item.rapt->dur;
+ default:
+ return 0;
+ }
+}
+
+/* Get the notification state of an item. */
+int day_item_get_state(struct day_item *day)
+{
+ switch (day->type) {
+ case APPT:
+ return day->item.apt->state;
+ case RECUR_APPT:
+ return day->item.rapt->state;
+ default:
+ return APOINT_NULL;
+ }
+}
+
+/* Add an exception to an item. */
+void day_item_add_exc(struct day_item *day, long date)
+{
+ switch (day->type) {
+ case RECUR_EVNT:
+ recur_event_add_exc(day->item.rev, date);
+ case RECUR_APPT:
+ recur_apoint_add_exc(day->item.rapt, date);
+ }
+}
+
+/* Clone the actual item. */
+void day_item_fork(struct day_item *day_in, struct day_item *day_out)
+{
+ day_out->type = day_in->type;
+ day_out->start = day_in->start;
+
+ switch (day_in->type) {
+ case APPT:
+ day_out->item.apt = apoint_dup(day_in->item.apt);
+ break;
+ case EVNT:
+ day_out->item.ev = event_dup(day_in->item.ev);
+ break;
+ case RECUR_APPT:
+ day_out->item.rapt = recur_apoint_dup(day_in->item.rapt);
+ break;
+ case RECUR_EVNT:
+ day_out->item.rev = recur_event_dup(day_in->item.rev);
+ break;
+ default:
+ EXIT(_("unknown item type"));
+ /* NOTREACHED */
+ }
}
/*
@@ -136,14 +211,20 @@ static struct day_item *day_add_apoint(int type, char *mesg, char *note,
* dedicated to the selected day.
* Returns the number of events for the selected day.
*/
-static int day_store_events(long date)
+static int day_store_events(long date, regex_t *regex)
{
llist_item_t *i;
+ union aptev_ptr p;
int e_nb = 0;
- LLIST_FIND_FOREACH_CONT(&eventlist, date, event_inday, i) {
+ LLIST_FIND_FOREACH_CONT(&eventlist, &date, event_inday, i) {
struct event *ev = LLIST_TS_GET_DATA(i);
- day_add_event(EVNT, ev->mesg, ev->note, ev->day, ev->id);
+
+ if (regex && regexec(regex, ev->mesg, 0, 0, 0) != 0)
+ continue;
+
+ p.ev = ev;
+ day_add_item(EVNT, ev->day, p);
e_nb++;
}
@@ -157,14 +238,20 @@ static int day_store_events(long date)
* dedicated to the selected day.
* Returns the number of recurrent events for the selected day.
*/
-static int day_store_recur_events(long date)
+static int day_store_recur_events(long date, regex_t *regex)
{
llist_item_t *i;
+ union aptev_ptr p;
int e_nb = 0;
- LLIST_FIND_FOREACH(&recur_elist, date, recur_event_inday, i) {
+ LLIST_FIND_FOREACH(&recur_elist, &date, recur_event_inday, i) {
struct recur_event *rev = LLIST_TS_GET_DATA(i);
- day_add_event(RECUR_EVNT, rev->mesg, rev->note, rev->day, rev->id);
+
+ if (regex && regexec(regex, rev->mesg, 0, 0, 0) != 0)
+ continue;
+
+ p.rev = rev;
+ day_add_item(RECUR_EVNT, rev->day, p);
e_nb++;
}
@@ -178,20 +265,25 @@ static int day_store_recur_events(long date)
* structure dedicated to the selected day.
* Returns the number of appointments for the selected day.
*/
-static int day_store_apoints(long date)
+static int day_store_apoints(long date, regex_t *regex)
{
llist_item_t *i;
+ union aptev_ptr p;
int a_nb = 0;
LLIST_TS_LOCK(&alist_p);
- LLIST_TS_FIND_FOREACH(&alist_p, date, apoint_inday, i) {
+ LLIST_TS_FIND_FOREACH(&alist_p, &date, apoint_inday, i) {
struct apoint *apt = LLIST_TS_GET_DATA(i);
+ if (regex && regexec(regex, apt->mesg, 0, 0, 0) != 0)
+ continue;
+
+ p.apt = apt;
+
if (apt->start >= date + DAYINSEC)
break;
- day_add_apoint(APPT, apt->mesg, apt->note, apt->start, apt->dur,
- apt->state, 0);
+ day_add_item(APPT, apt->start, p);
a_nb++;
}
LLIST_TS_UNLOCK(&alist_p);
@@ -206,18 +298,24 @@ static int day_store_apoints(long date)
* structure dedicated to the selected day.
* Returns the number of recurrent appointments for the selected day.
*/
-static int day_store_recur_apoints(long date)
+static int day_store_recur_apoints(long date, regex_t *regex)
{
llist_item_t *i;
+ union aptev_ptr p;
int a_nb = 0;
LLIST_TS_LOCK(&recur_alist_p);
- LLIST_TS_FIND_FOREACH(&recur_alist_p, date, recur_apoint_inday, i) {
+ LLIST_TS_FIND_FOREACH(&recur_alist_p, &date, recur_apoint_inday, i) {
struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
+
+ if (regex && regexec(regex, rapt->mesg, 0, 0, 0) != 0)
+ continue;
+
+ p.rapt = rapt;
+
unsigned real_start;
if (recur_apoint_find_occurrence(rapt, date, &real_start)) {
- day_add_apoint(RECUR_APPT, rapt->mesg, rapt->note, real_start,
- rapt->dur, rapt->state, a_nb);
+ day_add_item(RECUR_APPT, real_start, p);
a_nb++;
}
}
@@ -234,27 +332,27 @@ static int day_store_recur_apoints(long date)
* and the length of the new pad to write is returned.
* The number of events and appointments in the current day are also updated.
*/
-static int
-day_store_items(long date, unsigned *pnb_events, unsigned *pnb_apoints)
+int
+day_store_items(long date, unsigned *pnb_events, unsigned *pnb_apoints,
+ regex_t *regex)
{
- int pad_length;
int nb_events, nb_recur_events;
int nb_apoints, nb_recur_apoints;
day_free_list();
day_init_list();
- nb_recur_events = day_store_recur_events(date);
- nb_events = day_store_events(date);
- *pnb_events = nb_events;
- nb_recur_apoints = day_store_recur_apoints(date);
- nb_apoints = day_store_apoints(date);
- *pnb_apoints = nb_apoints;
- pad_length = (nb_recur_events + nb_events + 1 +
- 3 * (nb_recur_apoints + nb_apoints));
- *pnb_apoints += nb_recur_apoints;
- *pnb_events += nb_recur_events;
-
- return pad_length;
+
+ nb_recur_events = day_store_recur_events(date, regex);
+ nb_events = day_store_events(date, regex);
+ nb_recur_apoints = day_store_recur_apoints(date, regex);
+ nb_apoints = day_store_apoints(date, regex);
+
+ if (pnb_apoints)
+ *pnb_apoints = nb_apoints + nb_recur_apoints;
+ if (pnb_events)
+ *pnb_events = nb_events + nb_recur_events;
+
+ return nb_events + nb_recur_events + nb_apoints + nb_recur_apoints;
}
/*
@@ -281,7 +379,8 @@ struct day_items_nb *day_process_storage(struct date *slctd_date,
delwin(apad.ptrwin);
/* Store the events and appointments (recursive and normal items). */
- apad.length = day_store_items(date, &inday->nb_events, &inday->nb_apoints);
+ day_store_items(date, &inday->nb_events, &inday->nb_apoints, NULL);
+ apad.length = (inday->nb_events + 1 + 3 * inday->nb_apoints);
/* Create the new pad with its new length. */
if (day_changed)
@@ -292,40 +391,36 @@ struct day_items_nb *day_process_storage(struct date *slctd_date,
}
/*
- * Returns a structure of type apoint_llist_node_t given a structure of type
- * day_item_s
- */
-static void day_item_s2apoint_s(struct apoint *a, struct day_item *p)
-{
- a->state = p->state;
- a->start = p->start;
- a->dur = p->appt_dur;
- a->mesg = p->mesg;
-}
-
-/*
* Print an item date in the appointment panel.
*/
static void
-display_item_date(int incolor, struct apoint *i, int type, long date,
- int y, int x)
+display_item_date(struct day_item *day, int incolor, long date, int y, int x)
{
WINDOW *win;
char a_st[100], a_end[100];
+ /* FIXME: Redesign apoint_sec2str() and remove the need for a temporary
+ * appointment item here. */
+ struct apoint apt_tmp;
+ apt_tmp.start = day->start;
+ apt_tmp.dur = day_item_get_duration(day);
+
win = apad.ptrwin;
- apoint_sec2str(i, date, a_st, a_end);
+ apoint_sec2str(&apt_tmp, date, a_st, a_end);
if (incolor == 0)
custom_apply_attr(win, ATTR_HIGHEST);
- if (type == RECUR_EVNT || type == RECUR_APPT)
- if (i->state & APOINT_NOTIFY)
+
+ if (day->type == RECUR_EVNT || day->type == RECUR_APPT) {
+ if (day_item_get_state(day) & APOINT_NOTIFY)
mvwprintw(win, y, x, " *!%s -> %s", a_st, a_end);
else
mvwprintw(win, y, x, " * %s -> %s", a_st, a_end);
- else if (i->state & APOINT_NOTIFY)
+ } else if (day_item_get_state(day) & APOINT_NOTIFY) {
mvwprintw(win, y, x, " -!%s -> %s", a_st, a_end);
- else
+ } else {
mvwprintw(win, y, x, " - %s -> %s", a_st, a_end);
+ }
+
if (incolor == 0)
custom_remove_attr(win, ATTR_HIGHEST);
}
@@ -334,8 +429,7 @@ display_item_date(int incolor, struct apoint *i, int type, long date,
* Print an item description in the corresponding panel window.
*/
static void
-display_item(int incolor, char *msg, int recur, int note, int width, int y,
- int x)
+display_item(struct day_item *day, int incolor, int width, int y, int x)
{
WINDOW *win;
int ch_recur, ch_note;
@@ -345,18 +439,20 @@ display_item(int incolor, char *msg, int recur, int note, int width, int y,
if (width <= 0)
return;
+ char *mesg = day_item_get_mesg(day);
+
win = apad.ptrwin;
- ch_recur = (recur) ? '*' : ' ';
- ch_note = (note) ? '>' : ' ';
+ ch_recur = (day->type == RECUR_EVNT || day->type == RECUR_APPT) ? '*' : ' ';
+ ch_note = day_item_get_note(day) ? '>' : ' ';
if (incolor == 0)
custom_apply_attr(win, ATTR_HIGHEST);
- if (utf8_strwidth(msg) < width)
- mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_note, msg);
+ if (utf8_strwidth(mesg) < width)
+ mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_note, mesg);
else {
- for (i = 0; msg[i] && width > 0; i++) {
- if (!UTF8_ISCONT(msg[i]))
- width -= utf8_width(&msg[i]);
- buf[i] = msg[i];
+ for (i = 0; mesg[i] && width > 0; i++) {
+ if (!UTF8_ISCONT(mesg[i]))
+ width -= utf8_width(&mesg[i]);
+ buf[i] = mesg[i];
}
if (i)
buf[i - 1] = 0;
@@ -371,15 +467,12 @@ display_item(int incolor, char *msg, int recur, int note, int width, int y,
/*
* Write the appointments and events for the selected day in a pad.
* An horizontal line is drawn between events and appointments, and the
- * item selected by user is highlighted. This item is also saved inside
- * structure (pointed by day_saved_item), to be later displayed in a
- * popup window if requested.
+ * item selected by user is highlighted.
*/
void day_write_pad(long date, int width, int length, int incolor)
{
llist_item_t *i;
- struct apoint a;
- int line, item_number, recur;
+ int line, item_number;
const int x_pos = 0;
unsigned draw_line = 0;
@@ -387,19 +480,11 @@ void day_write_pad(long date, int width, int length, int incolor)
LLIST_FOREACH(&day_items, i) {
struct day_item *day = LLIST_TS_GET_DATA(i);
- if (day->type == RECUR_EVNT || day->type == RECUR_APPT)
- recur = 1;
- else
- recur = 0;
+
/* First print the events for current day. */
if (day->type < RECUR_APPT) {
item_number++;
- if (item_number - incolor == 0) {
- day_saved_item.type = day->type;
- day_saved_item.mesg = day->mesg;
- }
- display_item(item_number - incolor, day->mesg, recur,
- (day->note != NULL) ? 1 : 0, width - 7, line, x_pos);
+ display_item(day, item_number - incolor, width - 7, line, x_pos);
line++;
draw_line = 1;
} else {
@@ -411,32 +496,62 @@ void day_write_pad(long date, int width, int length, int incolor)
}
/* Last print the appointments for current day. */
item_number++;
- day_item_s2apoint_s(&a, day);
- if (item_number - incolor == 0) {
- day_saved_item.type = day->type;
- day_saved_item.mesg = day->mesg;
- apoint_sec2str(&a, date, day_saved_item.start, day_saved_item.end);
- }
- display_item_date(item_number - incolor, &a, day->type,
- date, line + 1, x_pos);
- display_item(item_number - incolor, day->mesg, 0,
- (day->note != NULL) ? 1 : 0, width - 7, line + 2, x_pos);
+ display_item_date(day, item_number - incolor, date, line + 1, x_pos);
+ display_item(day, item_number - incolor, width - 7, line + 2, x_pos);
line += 3;
}
}
}
+/* Write the appointments and events for the selected day to stdout. */
+void day_write_stdout(long date, const char *fmt_apt, const char *fmt_rapt,
+ const char *fmt_ev, const char *fmt_rev)
+{
+ llist_item_t *i;
+
+ LLIST_FOREACH(&day_items, i) {
+ struct day_item *day = LLIST_TS_GET_DATA(i);
+
+ switch (day->type) {
+ case APPT:
+ print_apoint(fmt_apt, date, day->item.apt);
+ break;
+ case EVNT:
+ print_event(fmt_ev, date, day->item.ev);
+ break;
+ case RECUR_APPT:
+ print_recur_apoint(fmt_rapt, date, day->start, day->item.rapt);
+ break;
+ case RECUR_EVNT:
+ print_recur_event(fmt_rev, date, day->item.rev);
+ break;
+ default:
+ EXIT(_("unknown item type"));
+ /* NOTREACHED */
+ }
+ }
+}
+
/* Display an item inside a popup window. */
-void day_popup_item(void)
+void day_popup_item(struct day_item *day)
{
- if (day_saved_item.type == EVNT || day_saved_item.type == RECUR_EVNT)
- item_in_popup(NULL, NULL, day_saved_item.mesg, _("Event :"));
- else if (day_saved_item.type == APPT || day_saved_item.type == RECUR_APPT)
- item_in_popup(day_saved_item.start, day_saved_item.end,
- day_saved_item.mesg, _("Appointment :"));
- else
+ if (day->type == EVNT || day->type == RECUR_EVNT) {
+ item_in_popup(NULL, NULL, day_item_get_mesg(day), _("Event :"));
+ } else if (day->type == APPT || day->type == RECUR_APPT) {
+ char a_st[100], a_end[100];
+
+ /* FIXME: Redesign apoint_sec2str() and remove the need for a temporary
+ * appointment item here. */
+ struct apoint apt_tmp;
+ apt_tmp.start = day->start;
+ apt_tmp.dur = day_item_get_duration(day);
+ apoint_sec2str(&apt_tmp, calendar_get_slctd_day_sec(), a_st, a_end);
+
+ item_in_popup(a_st, a_end, day_item_get_mesg(day), _("Appointment :"));
+ } else {
EXIT(_("unknown item type"));
- /* NOTREACHED */
+ /* NOTREACHED */
+ }
}
/*
@@ -447,21 +562,21 @@ int day_check_if_item(struct date day)
{
const long date = date2sec(day, 0, 0);
- if (LLIST_FIND_FIRST(&recur_elist, date, recur_event_inday))
+ if (LLIST_FIND_FIRST(&recur_elist, (long *)&date, recur_event_inday))
return 1;
LLIST_TS_LOCK(&recur_alist_p);
- if (LLIST_TS_FIND_FIRST(&recur_alist_p, date, recur_apoint_inday)) {
+ if (LLIST_TS_FIND_FIRST(&recur_alist_p, (long *)&date, recur_apoint_inday)) {
LLIST_TS_UNLOCK(&recur_alist_p);
return 1;
}
LLIST_TS_UNLOCK(&recur_alist_p);
- if (LLIST_FIND_FIRST(&eventlist, date, event_inday))
+ if (LLIST_FIND_FIRST(&eventlist, (long *)&date, event_inday))
return 1;
LLIST_TS_LOCK(&alist_p);
- if (LLIST_TS_FIND_FIRST(&alist_p, date, apoint_inday)) {
+ if (LLIST_TS_FIND_FIRST(&alist_p, (long *)&date, apoint_inday)) {
LLIST_TS_UNLOCK(&alist_p);
return 1;
}
@@ -502,7 +617,7 @@ unsigned day_chk_busy_slices(struct date day, int slicesno, int *slices)
#define SLICENUM(tsec) ((tsec) / slicelen % slicesno)
LLIST_TS_LOCK(&recur_alist_p);
- LLIST_TS_FIND_FOREACH(&recur_alist_p, date, recur_apoint_inday, i) {
+ LLIST_TS_FIND_FOREACH(&recur_alist_p, (long *)&date, recur_apoint_inday, i) {
struct apoint *rapt = LLIST_TS_GET_DATA(i);
long start = get_item_time(rapt->start);
long end = get_item_time(rapt->start + rapt->dur);
@@ -515,7 +630,7 @@ unsigned day_chk_busy_slices(struct date day, int slicesno, int *slices)
LLIST_TS_UNLOCK(&recur_alist_p);
LLIST_TS_LOCK(&alist_p);
- LLIST_TS_FIND_FOREACH(&alist_p, date, apoint_inday, i) {
+ LLIST_TS_FIND_FOREACH(&alist_p, (long *)&date, apoint_inday, i) {
struct apoint *apt = LLIST_TS_GET_DATA(i);
long start = get_item_time(apt->start);
long end = get_item_time(apt->start + apt->dur);
@@ -534,466 +649,56 @@ unsigned day_chk_busy_slices(struct date day, int slicesno, int *slices)
return 1;
}
-/* Request the user to enter a new time. */
-static int day_edit_time(int time, unsigned *new_hour, unsigned *new_minute)
-{
- char *timestr = date_sec2date_str(time, "%H:%M");
- const char *msg_time = _("Enter the new time ([hh:mm]) : ");
- const char *enter_str = _("Press [Enter] to continue");
- const char *fmt_msg = _("You entered an invalid time, should be [hh:mm]");
-
- for (;;) {
- status_mesg(msg_time, "");
- if (updatestring(win[STA].p, &timestr, 0, 1) == GETSTRING_VALID) {
- if (parse_time(timestr, new_hour, new_minute) == 1) {
- mem_free(timestr);
- return 1;
- } else {
- status_mesg(fmt_msg, enter_str);
- wgetch(win[STA].p);
- }
- } else
- return 0;
- }
-}
-
-/* Request the user to enter a new time or duration. */
-static int day_edit_duration(int start, int dur, unsigned *new_duration)
-{
- char *timestr = date_sec2date_str(start + dur, "%H:%M");
- const char *msg_time =
- _
- ("Enter new end time ([hh:mm]) or duration ([+hh:mm], [+xxxdxxhxxm] or [+mm]) : ");
- const char *enter_str = _("Press [Enter] to continue");
- const char *fmt_msg = _("You entered an invalid time, should be [hh:mm]");
- long newtime;
- unsigned hr, mn;
-
- for (;;) {
- status_mesg(msg_time, "");
- if (updatestring(win[STA].p, &timestr, 0, 1) == GETSTRING_VALID) {
- if (*timestr == '+' && parse_duration(timestr + 1, new_duration) == 1) {
- *new_duration *= MININSEC;
- break;
- } else if (parse_time(timestr, &hr, &mn) == 1) {
- newtime = update_time_in_date(start + dur, hr, mn);
- *new_duration = (newtime > start) ? newtime - start :
- DAYINSEC + newtime - start;
- break;
- } else {
- status_mesg(fmt_msg, enter_str);
- wgetch(win[STA].p);
- }
- } else
- return 0;
- }
-
- mem_free(timestr);
- return 1;
-}
-
-/* Request the user to enter a new end time or duration. */
-static void update_start_time(long *start, long *dur)
-{
- long newtime;
- unsigned hr, mn;
- int valid_date;
- const char *msg_wrong_time =
- _("Invalid time: start time must be before end time!");
- const char *msg_enter = _("Press [Enter] to continue");
-
- do {
- day_edit_time(*start, &hr, &mn);
- newtime = update_time_in_date(*start, hr, mn);
- if (newtime < *start + *dur) {
- *dur -= (newtime - *start);
- *start = newtime;
- valid_date = 1;
- } else {
- status_mesg(msg_wrong_time, msg_enter);
- wgetch(win[STA].p);
- valid_date = 0;
- }
- }
- while (valid_date == 0);
-}
-
-static void update_duration(long *start, long *dur)
-{
- unsigned newdur;
-
- day_edit_duration(*start, *dur, &newdur);
- *dur = newdur;
-}
-
-static void update_desc(char **desc)
-{
- status_mesg(_("Enter the new item description:"), "");
- updatestring(win[STA].p, desc, 0, 1);
-}
-
-static void update_rept(struct rpt **rpt, const long start)
-{
- int newtype, newfreq, date_entered;
- long newuntil;
- char outstr[BUFSIZ];
- char *freqstr, *timstr;
- const char *msg_rpt_prefix = _("Enter the new repetition type:");
- const char *msg_rpt_daily = _("(d)aily");
- const char *msg_rpt_weekly = _("(w)eekly");
- const char *msg_rpt_monthly = _("(m)onthly");
- const char *msg_rpt_yearly = _("(y)early");
-
- /* Find the current repetition type. */
- const char *rpt_current;
- char msg_rpt_current[BUFSIZ];
- switch (recur_def2char((*rpt)->type)) {
- case 'D':
- rpt_current = msg_rpt_daily;
- break;
- case 'W':
- rpt_current = msg_rpt_weekly;
- break;
- case 'M':
- rpt_current = msg_rpt_monthly;
- break;
- case 'Y':
- rpt_current = msg_rpt_yearly;
- break;
- default:
- /* NOTREACHED, but makes the compiler happier. */
- rpt_current = msg_rpt_daily;
- }
-
- snprintf(msg_rpt_current, BUFSIZ, _("(currently using %s)"), rpt_current);
-
- char msg_rpt_asktype[BUFSIZ];
- snprintf(msg_rpt_asktype, BUFSIZ, "%s %s, %s, %s, %s ? %s",
- msg_rpt_prefix,
- msg_rpt_daily,
- msg_rpt_weekly, msg_rpt_monthly, msg_rpt_yearly, msg_rpt_current);
-
- const char *msg_rpt_choice = _("[dwmy]");
- const char *msg_wrong_freq = _("The frequence you entered is not valid.");
- const char *msg_wrong_time =
- _("Invalid time: start time must be before end time!");
- const char *msg_wrong_date = _("The entered date is not valid.");
- const char *msg_fmts =
- _("Possible formats are [%s] or '0' for an endless repetition.");
- const char *msg_enter = _("Press [Enter] to continue");
-
- switch (status_ask_choice(msg_rpt_asktype, msg_rpt_choice, 4)) {
- case 1:
- newtype = 'D';
- break;
- case 2:
- newtype = 'W';
- break;
- case 3:
- newtype = 'M';
- break;
- case 4:
- newtype = 'Y';
- break;
- default:
- return;
- }
-
- do {
- status_mesg(_("Enter the new repetition frequence:"), "");
- freqstr = mem_malloc(BUFSIZ);
- snprintf(freqstr, BUFSIZ, "%d", (*rpt)->freq);
- if (updatestring(win[STA].p, &freqstr, 0, 1) == GETSTRING_VALID) {
- newfreq = atoi(freqstr);
- mem_free(freqstr);
- if (newfreq == 0) {
- status_mesg(msg_wrong_freq, msg_enter);
- wgetch(win[STA].p);
- }
- } else {
- mem_free(freqstr);
- return;
- }
- }
- while (newfreq == 0);
-
- do {
- snprintf(outstr, BUFSIZ, _("Enter the new ending date: [%s] or '0'"),
- DATEFMT_DESC(conf.input_datefmt));
- status_mesg(outstr, "");
- timstr = date_sec2date_str((*rpt)->until, DATEFMT(conf.input_datefmt));
- if (updatestring(win[STA].p, &timstr, 0, 1) != GETSTRING_VALID) {
- mem_free(timstr);
- return;
- }
- if (strcmp(timstr, "0") == 0) {
- newuntil = 0;
- date_entered = 1;
- } else {
- struct tm lt;
- time_t t;
- struct date new_date;
- int newmonth, newday, newyear;
-
- if (parse_date(timstr, conf.input_datefmt, &newyear, &newmonth,
- &newday, calendar_get_slctd_day())) {
- t = start;
- localtime_r(&t, &lt);
- new_date.dd = newday;
- new_date.mm = newmonth;
- new_date.yyyy = newyear;
- newuntil = date2sec(new_date, lt.tm_hour, lt.tm_min);
- if (newuntil < start) {
- status_mesg(msg_wrong_time, msg_enter);
- wgetch(win[STA].p);
- date_entered = 0;
- } else
- date_entered = 1;
- } else {
- snprintf(outstr, BUFSIZ, msg_fmts, DATEFMT_DESC(conf.input_datefmt));
- status_mesg(msg_wrong_date, outstr);
- wgetch(win[STA].p);
- date_entered = 0;
- }
- }
- }
- while (date_entered == 0);
-
- mem_free(timstr);
- (*rpt)->type = recur_char2def(newtype);
- (*rpt)->freq = newfreq;
- (*rpt)->until = newuntil;
-}
-
-/* Edit an already existing item. */
-void day_edit_item(void)
-{
- struct day_item *p;
- struct recur_event *re;
- struct event *e;
- struct recur_apoint *ra;
- struct apoint *a;
- long date;
- int item_num;
- int need_check_notify = 0;
-
- item_num = apoint_hilt();
- p = day_get_item(item_num);
- date = calendar_get_slctd_day_sec();
-
- switch (p->type) {
- case RECUR_EVNT:
- re = recur_get_event(date, day_item_nb(date, item_num, RECUR_EVNT));
- const char *choice_recur_evnt[2] = {
- _("Description"),
- _("Repetition"),
- };
- switch (status_ask_simplechoice(_("Edit: "), choice_recur_evnt, 2)) {
- case 1:
- update_desc(&re->mesg);
- break;
- case 2:
- update_rept(&re->rpt, re->day);
- break;
- default:
- return;
- }
- break;
- case EVNT:
- e = event_get(date, day_item_nb(date, item_num, EVNT));
- update_desc(&e->mesg);
- break;
- case RECUR_APPT:
- ra = recur_get_apoint(date, day_item_nb(date, item_num, RECUR_APPT));
- const char *choice_recur_appt[4] = {
- _("Start time"),
- _("End time"),
- _("Description"),
- _("Repetition"),
- };
- switch (status_ask_simplechoice(_("Edit: "), choice_recur_appt, 4)) {
- case 1:
- need_check_notify = 1;
- update_start_time(&ra->start, &ra->dur);
- break;
- case 2:
- update_duration(&ra->start, &ra->dur);
- break;
- case 3:
- if (notify_bar())
- need_check_notify = notify_same_recur_item(ra);
- update_desc(&ra->mesg);
- break;
- case 4:
- need_check_notify = 1;
- update_rept(&ra->rpt, ra->start);
- break;
- default:
- return;
- }
- break;
- case APPT:
- a = apoint_get(date, day_item_nb(date, item_num, APPT));
- const char *choice_appt[3] = {
- _("Start time"),
- _("End time"),
- _("Description"),
- };
- switch (status_ask_simplechoice(_("Edit: "), choice_appt, 3)) {
- case 1:
- need_check_notify = 1;
- update_start_time(&a->start, &a->dur);
- break;
- case 2:
- update_duration(&a->start, &a->dur);
- break;
- case 3:
- if (notify_bar())
- need_check_notify = notify_same_item(a->start);
- update_desc(&a->mesg);
- break;
- default:
- return;
- }
- break;
- }
-
- if (need_check_notify)
- notify_check_next_app(1);
-}
-
-/*
- * In order to erase an item, we need to count first the number of
- * items for each type (in order: recurrent events, events,
- * recurrent appointments and appointments) and then to test the
- * type of the item to be deleted.
- */
-int day_erase_item(long date, int item_number, enum eraseflg flag)
-{
- struct day_item *p;
-
- const char *erase_warning =
- _("This item is recurrent. "
- "Delete (a)ll occurences or just this (o)ne ?");
- const char *erase_choices = _("[ao]");
- const int nb_erase_choices = 2;
-
- const char *note_warning =
- _("This item has a note attached to it. "
- "Delete (i)tem or just its (n)ote ?");
- const char *note_choices = _("[in]");
- const int nb_note_choices = 2;
- int ans;
- unsigned delete_whole;
-
- p = day_get_item(item_number);
- if (flag == ERASE_DONT_FORCE) {
- if (p->note == NULL)
- ans = 1;
- else
- ans = status_ask_choice(note_warning, note_choices, nb_note_choices);
-
- switch (ans) {
- case 1:
- flag = ERASE_FORCE;
- break;
- case 2:
- flag = ERASE_FORCE_ONLY_NOTE;
- break;
- default: /* User escaped */
- return 0;
- }
- }
- if (p->type == EVNT) {
- event_delete_bynum(date, day_item_nb(date, item_number, EVNT), flag);
- } else if (p->type == APPT) {
- apoint_delete_bynum(date, day_item_nb(date, item_number, APPT), flag);
- } else {
- if (flag == ERASE_FORCE_ONLY_NOTE)
- ans = 1;
- else
- ans = status_ask_choice(erase_warning, erase_choices, nb_erase_choices);
-
- switch (ans) {
- case 1:
- delete_whole = 1;
- break;
- case 2:
- delete_whole = 0;
- break;
- default:
- return 0;
- }
-
- if (p->type == RECUR_EVNT) {
- recur_event_erase(date, day_item_nb(date, item_number, RECUR_EVNT),
- delete_whole, flag);
- } else {
- recur_apoint_erase(date, p->appt_pos, delete_whole, flag);
- }
- }
- if (flag == ERASE_FORCE_ONLY_NOTE)
- return 0;
- else
- return p->type;
-}
-
/* Cut an item so it can be pasted somewhere else later. */
-int day_cut_item(long date, int item_number)
+struct day_item *day_cut_item(long date, int item_number)
{
- const int DELETE_WHOLE = 1;
- struct day_item *p;
+ struct day_item *p = day_get_item(item_number);
- p = day_get_item(item_number);
switch (p->type) {
case EVNT:
- event_delete_bynum(date, day_item_nb(date, item_number, EVNT), ERASE_CUT);
+ event_delete(p->item.ev);
break;
case RECUR_EVNT:
- recur_event_erase(date, day_item_nb(date, item_number, RECUR_EVNT),
- DELETE_WHOLE, ERASE_CUT);
+ recur_event_erase(p->item.rev);
break;
case APPT:
- apoint_delete_bynum(date, day_item_nb(date, item_number, APPT), ERASE_CUT);
+ apoint_delete(p->item.apt);
break;
case RECUR_APPT:
- recur_apoint_erase(date, p->appt_pos, DELETE_WHOLE, ERASE_CUT);
+ recur_apoint_erase(p->item.rapt);
break;
default:
EXIT(_("unknwon type"));
/* NOTREACHED */
}
- return p->type;
+ return p;
}
/* Paste a previously cut item. */
-int day_paste_item(long date, int cut_item_type)
+int day_paste_item(struct day_item *p, long date)
{
- int pasted_item_type;
-
- pasted_item_type = cut_item_type;
- switch (cut_item_type) {
+ switch (p->type) {
case 0:
return 0;
case EVNT:
- event_paste_item();
+ event_paste_item(p->item.ev, date);
break;
case RECUR_EVNT:
- recur_event_paste_item();
+ recur_event_paste_item(p->item.rev, date);
break;
case APPT:
- apoint_paste_item();
+ apoint_paste_item(p->item.apt, date);
break;
case RECUR_APPT:
- recur_apoint_paste_item();
+ recur_apoint_paste_item(p->item.rapt, date);
break;
default:
EXIT(_("unknwon type"));
/* NOTREACHED */
}
- return pasted_item_type;
+ return p->type;
}
/* Returns a structure containing the selected item. */
@@ -1002,117 +707,45 @@ struct day_item *day_get_item(int item_number)
return LLIST_GET_DATA(LLIST_NTH(&day_items, item_number - 1));
}
-/* Returns the real item number, given its type. */
-int day_item_nb(long date, int day_num, int type)
-{
- int i, nb_item[MAX_TYPES];
- llist_item_t *j;
-
- for (i = 0; i < MAX_TYPES; i++)
- nb_item[i] = 0;
-
- j = LLIST_FIRST(&day_items);
- for (i = 1; i < day_num; i++) {
- struct day_item *day = LLIST_TS_GET_DATA(j);
- nb_item[day->type - 1]++;
- j = LLIST_TS_NEXT(j);
- }
-
- return nb_item[type - 1];
-}
-
/* Attach a note to an appointment or event. */
-void day_edit_note(const char *editor)
+void day_edit_note(struct day_item *p, const char *editor)
{
- struct day_item *p;
- struct recur_apoint *ra;
- struct apoint *a;
- struct recur_event *re;
- struct event *e;
- long date;
- int item_num;
+ char *note;
- item_num = apoint_hilt();
- p = day_get_item(item_num);
- edit_note(&p->note, editor);
+ note = day_item_get_note(p);
+ edit_note(&note, editor);
- date = calendar_get_slctd_day_sec();
switch (p->type) {
case RECUR_EVNT:
- re = recur_get_event(date, day_item_nb(date, item_num, RECUR_EVNT));
- re->note = p->note;
+ p->item.rev->note = note;
break;
case EVNT:
- e = event_get(date, day_item_nb(date, item_num, EVNT));
- e->note = p->note;
+ p->item.ev->note = note;
break;
case RECUR_APPT:
- ra = recur_get_apoint(date, day_item_nb(date, item_num, RECUR_APPT));
- ra->note = p->note;
+ p->item.rapt->note = note;
break;
case APPT:
- a = apoint_get(date, day_item_nb(date, item_num, APPT));
- a->note = p->note;
+ p->item.apt->note = note;
break;
}
}
/* View a note previously attached to an appointment or event */
-void day_view_note(const char *pager)
+void day_view_note(struct day_item *p, const char *pager)
{
- struct day_item *p = day_get_item(apoint_hilt());
- view_note(p->note, pager);
+ view_note(day_item_get_note(p), pager);
}
-/* Pipe an appointment or event to an external program. */
-void day_pipe_item(void)
+/* Switch notification state for an item. */
+void day_item_switch_notify(struct day_item *p)
{
- char cmd[BUFSIZ] = "";
- char const *arg[] = { cmd, NULL };
- int pout;
- int pid;
- FILE *fpout;
- int item_num;
- long date;
- struct day_item *p;
- struct recur_apoint *ra;
- struct apoint *a;
- struct recur_event *re;
- struct event *e;
-
- status_mesg(_("Pipe item to external command:"), "");
- if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID)
- return;
-
- wins_prepare_external();
- if ((pid = shell_exec(NULL, &pout, *arg, arg))) {
- fpout = fdopen(pout, "w");
-
- item_num = apoint_hilt();
- p = day_get_item(item_num);
- date = calendar_get_slctd_day_sec();
- switch (p->type) {
- case RECUR_EVNT:
- re = recur_get_event(date, day_item_nb(date, item_num, RECUR_EVNT));
- recur_event_write(re, fpout);
- break;
- case EVNT:
- e = event_get(date, day_item_nb(date, item_num, EVNT));
- event_write(e, fpout);
- break;
- case RECUR_APPT:
- ra = recur_get_apoint(date, day_item_nb(date, item_num, RECUR_APPT));
- recur_apoint_write(ra, fpout);
- break;
- case APPT:
- a = apoint_get(date, day_item_nb(date, item_num, APPT));
- apoint_write(a, fpout);
- break;
- }
-
- fclose(fpout);
- child_wait(NULL, &pout, pid);
- press_any_key();
+ switch (p->type) {
+ case RECUR_APPT:
+ recur_apoint_switch_notify(p->item.rapt);
+ break;
+ case APPT:
+ apoint_switch_notify(p->item.apt);
+ break;
}
- wins_unprepare_external();
}
diff --git a/src/event.c b/src/event.c
index 203af44..dca6820 100644
--- a/src/event.c
+++ b/src/event.c
@@ -42,33 +42,28 @@
#include "calcurse.h"
llist_t eventlist;
-static struct event bkp_cut_event;
-void event_free_bkp(void)
-{
- if (bkp_cut_event.mesg) {
- mem_free(bkp_cut_event.mesg);
- bkp_cut_event.mesg = 0;
- }
- erase_note(&bkp_cut_event.note);
-}
-
-static void event_free(struct event *ev)
+void event_free(struct event *ev)
{
mem_free(ev->mesg);
erase_note(&ev->note);
mem_free(ev);
}
-static void event_dup(struct event *in, struct event *bkp)
+struct event *event_dup(struct event *in)
{
- EXIT_IF(!in || !bkp, _("null pointer"));
+ EXIT_IF(!in, _("null pointer"));
- bkp->id = in->id;
- bkp->day = in->day;
- bkp->mesg = mem_strdup(in->mesg);
+ struct event *ev = mem_malloc(sizeof(struct event));
+ ev->id = in->id;
+ ev->day = in->day;
+ ev->mesg = mem_strdup(in->mesg);
if (in->note)
- bkp->note = mem_strdup(in->note);
+ ev->note = mem_strdup(in->note);
+ else
+ ev->note = NULL;
+
+ return ev;
}
void event_llist_init(void)
@@ -104,9 +99,9 @@ struct event *event_new(char *mesg, char *note, long day, int id)
}
/* Check if the event belongs to the selected day */
-unsigned event_inday(struct event *i, long start)
+unsigned event_inday(struct event *i, long *start)
{
- return (i->day < start + DAYINSEC && i->day >= start);
+ return (i->day < *start + DAYINSEC && i->day >= *start);
}
/* Write to file the event in user-friendly format */
@@ -151,47 +146,19 @@ struct event *event_scan(FILE * f, struct tm start, int id, char *note)
return event_new(buf, note, tstart, id);
}
-/* Retrieve an event from the list, given the day and item position. */
-struct event *event_get(long day, int pos)
-{
- llist_item_t *i = LLIST_FIND_NTH(&eventlist, pos, day, event_inday);
-
- if (i)
- return LLIST_TS_GET_DATA(i);
-
- EXIT(_("event not found"));
- /* NOTREACHED */
-}
-
/* Delete an event from the list. */
-void event_delete_bynum(long start, unsigned num, enum eraseflg flag)
+void event_delete(struct event *ev)
{
- llist_item_t *i = LLIST_FIND_NTH(&eventlist, num, start, event_inday);
+ llist_item_t *i = LLIST_FIND_FIRST(&eventlist, ev, NULL);
if (!i)
EXIT(_("no such appointment"));
- struct event *ev = LLIST_TS_GET_DATA(i);
-
- switch (flag) {
- case ERASE_FORCE_ONLY_NOTE:
- erase_note(&ev->note);
- break;
- case ERASE_CUT:
- event_free_bkp();
- event_dup(ev, &bkp_cut_event);
- erase_note(&ev->note);
- /* FALLTHROUGH */
- default:
- LLIST_REMOVE(&eventlist, i);
- mem_free(ev->mesg);
- mem_free(ev);
- break;
- }
+
+ LLIST_REMOVE(&eventlist, i);
}
-void event_paste_item(void)
+void event_paste_item(struct event *ev, long date)
{
- event_new(bkp_cut_event.mesg, bkp_cut_event.note,
- date2sec(*calendar_get_slctd_day(), 0, 0), bkp_cut_event.id);
- event_free_bkp();
+ ev->day = date;
+ LLIST_ADD_SORTED(&eventlist, ev, event_cmp_day);
}
diff --git a/src/help.c b/src/help.c
index 84abdd5..a8d3edb 100644
--- a/src/help.c
+++ b/src/help.c
@@ -60,7 +60,7 @@ typedef enum {
HELP_GOTO,
HELP_DELETE,
HELP_ADD,
- HELP_CUT_PASTE,
+ HELP_COPY_PASTE,
HELP_EDIT,
HELP_ENOTE,
HELP_VNOTE,
@@ -126,7 +126,7 @@ help_write_pad(struct window *win, char *title, char *text, enum key action)
case KEY_GENERIC_NEXT_YEAR:
case KEY_GENERIC_GOTO_TODAY:
case KEY_GENERIC_CREDITS:
- case KEY_GENERIC_CUT:
+ case KEY_GENERIC_COPY:
case KEY_GENERIC_PASTE:
break;
default:
@@ -261,9 +261,9 @@ static int wanted_page(int ch)
page = HELP_DELETE;
break;
- case KEY_GENERIC_CUT:
+ case KEY_GENERIC_COPY:
case KEY_GENERIC_PASTE:
- page = HELP_CUT_PASTE;
+ page = HELP_COPY_PASTE;
break;
case KEY_EDIT_ITEM:
@@ -536,21 +536,18 @@ void help_screen(void)
keys_action_firstkey(KEY_ADD_ITEM),
keys_action_firstkey(KEY_ADD_ITEM));
- hscr[HELP_CUT_PASTE].title = _("Cut and Paste\n");
- snprintf(hscr[HELP_CUT_PASTE].text, HELPTEXTSIZ,
+ hscr[HELP_COPY_PASTE].title = _("Copy and Paste\n");
+ snprintf(hscr[HELP_COPY_PASTE].text, HELPTEXTSIZ,
_
- ("Cut and paste the currently selected item. This is useful to quickly\n"
- "move an item from one date to another.\n"
- "To do so, one must first highlight the item that needs to be moved,\n"
- "then press '%s' to cut this item. It will be removed from the panel.\n"
+ (
+ "Copy and paste the currently selected item. This is useful to quickly\n"
+ "copy an item from one date to another. To do so, one must first\n"
+ "highlight the item that needs to be copied, then press '%s' to copy.\n"
"Once the new date is chosen in the calendar, the appointment panel must\n"
- "be selected and the '%s' key must be pressed to paste the item.\n"
- "The item will appear again in the appointment panel, assigned to the\n"
- "newly selected date.\n\n"
- "Be careful that if two cuts are performed successively without pasting\n"
- "between them, the item that was cut at first will be lost, together\n"
- "with its associated note if it had one."),
- keys_action_firstkey(KEY_GENERIC_CUT),
+ "be selected and the '%s' key must be pressed to paste the item. The item\n"
+ "will appear in the appointment panel, assigned to the newly selected\n"
+ "date.\n\n"),
+ keys_action_firstkey(KEY_GENERIC_COPY),
keys_action_firstkey(KEY_GENERIC_PASTE));
hscr[HELP_EDIT].title = _("Edit Item\n");
@@ -796,7 +793,7 @@ void help_screen(void)
}
wins_scrollwin_display(&hwin);
- ch = keys_getch(win[STA].p, NULL);
+ ch = keys_getch(win[STA].p, NULL, NULL);
}
wins_scrollwin_delete(&hwin);
if (need_resize)
diff --git a/src/ical.c b/src/ical.c
index ca10865..18c6bb5 100644
--- a/src/ical.c
+++ b/src/ical.c
@@ -237,13 +237,13 @@ static void ical_export_todo(FILE * stream)
}
/* Print a header to describe import log report format. */
-static void ical_log_init(FILE * log, float version)
+static void ical_log_init(FILE * log, int major, int minor)
{
const char *header =
"+-------------------------------------------------------------------+\n"
"| Calcurse icalendar import log. |\n"
"| |\n"
- "| Items imported from icalendar file, version %1.1f |\n"
+ "| Items imported from icalendar file, version %d.%d |\n"
"| Some items could not be imported, they are described hereafter. |\n"
"| The log line format is as follows: |\n"
"| |\n"
@@ -256,7 +256,7 @@ static void ical_log_init(FILE * log, float version)
"+-------------------------------------------------------------------+\n\n";
if (log)
- fprintf(log, header, version);
+ fprintf(log, header, major, minor);
}
/*
@@ -419,25 +419,25 @@ static int ical_readline(FILE * fdi, char *buf, char *lstore, unsigned *ln)
return 1;
}
-static float
-ical_chk_header(FILE * fd, char *buf, char *lstore, unsigned *lineno)
+static int
+ical_chk_header(FILE * fd, char *buf, char *lstore, unsigned *lineno,
+ int *major, int *minor)
{
- const int HEADER_MALFORMED = -1;
const char icalheader[] = "BEGIN:VCALENDAR";
- float version;
if (!ical_readline(fd, buf, lstore, lineno))
- return HEADER_MALFORMED;
+ return 0;
str_toupper(buf);
if (strncmp(buf, icalheader, sizeof(icalheader) - 1) != 0)
- return HEADER_MALFORMED;
+ return 0;
- while (!sscanf(buf, "VERSION:%f", &version)) {
+ while (!sscanf(buf, "VERSION:%d.%d", major, minor)) {
if (!ical_readline(fd, buf, lstore, lineno))
- return HEADER_MALFORMED;
+ return 0;
}
- return version;
+
+ return 1;
}
/*
@@ -1055,15 +1055,14 @@ ical_import_data(FILE * stream, FILE * log, unsigned *events, unsigned *apoints,
const char vevent[] = "BEGIN:VEVENT";
const char vtodo[] = "BEGIN:VTODO";
char buf[BUFSIZ], lstore[BUFSIZ];
- float ical_version;
+ int major, minor;
ical_readline_init(stream, buf, lstore, lines);
- ical_version = ical_chk_header(stream, buf, lstore, lines);
- RETURN_IF(ical_version < 0,
+ RETURN_IF(!ical_chk_header(stream, buf, lstore, lines, &major, &minor),
_("Warning: ical header malformed or wrong version number. "
"Aborting..."));
- ical_log_init(log, ical_version);
+ ical_log_init(log, major, minor);
while (ical_readline(stream, buf, lstore, lines)) {
(*lines)++;
diff --git a/src/interaction.c b/src/interaction.c
new file mode 100644
index 0000000..635f78a
--- /dev/null
+++ b/src/interaction.c
@@ -0,0 +1,899 @@
+/*
+ * Calcurse - text-based organizer
+ *
+ * Copyright (c) 2004-2012 calcurse Development Team <misc@calcurse.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Send your feedback or comments to : misc@calcurse.org
+ * Calcurse home page : http://calcurse.org
+ *
+ */
+
+#include "calcurse.h"
+
+struct day_item day_cut[38] = { { 0, 0, { NULL } } };
+
+/* Request the user to enter a new time. */
+static int day_edit_time(int time, unsigned *new_hour, unsigned *new_minute)
+{
+ char *timestr = date_sec2date_str(time, "%H:%M");
+ const char *msg_time = _("Enter the new time ([hh:mm] or [hhmm]) : ");
+ const char *enter_str = _("Press [Enter] to continue");
+ const char *fmt_msg = _("You entered an invalid time, should be [hh:mm] or [hhmm]");
+
+ for (;;) {
+ status_mesg(msg_time, "");
+ if (updatestring(win[STA].p, &timestr, 0, 1) == GETSTRING_VALID) {
+ if (parse_time(timestr, new_hour, new_minute) == 1) {
+ mem_free(timestr);
+ return 1;
+ } else {
+ status_mesg(fmt_msg, enter_str);
+ wgetch(win[STA].p);
+ }
+ } else
+ return 0;
+ }
+}
+
+/* Request the user to enter a new time or duration. */
+static int day_edit_duration(int start, int dur, unsigned *new_duration)
+{
+ char *timestr = date_sec2date_str(start + dur, "%H:%M");
+ const char *msg_time =
+ _
+ ("Enter new end time ([hh:mm], [hhmm]) or duration ([+hh:mm], [+xxxdxxhxxm] or [+mm]) : ");
+ const char *enter_str = _("Press [Enter] to continue");
+ const char *fmt_msg = _("You entered an invalid time, should be [hh:mm] or [hhmm]");
+ long newtime;
+ unsigned hr, mn;
+
+ for (;;) {
+ status_mesg(msg_time, "");
+ if (updatestring(win[STA].p, &timestr, 0, 1) == GETSTRING_VALID) {
+ if (*timestr == '+' && parse_duration(timestr + 1, new_duration) == 1) {
+ *new_duration *= MININSEC;
+ break;
+ } else if (parse_time(timestr, &hr, &mn) == 1) {
+ newtime = update_time_in_date(start + dur, hr, mn);
+ *new_duration = (newtime > start) ? newtime - start :
+ DAYINSEC + newtime - start;
+ break;
+ } else {
+ status_mesg(fmt_msg, enter_str);
+ wgetch(win[STA].p);
+ }
+ } else
+ return 0;
+ }
+
+ mem_free(timestr);
+ return 1;
+}
+
+/* Request the user to enter a new end time or duration. */
+static void update_start_time(long *start, long *dur)
+{
+ long newtime;
+ unsigned hr, mn;
+ int valid_date;
+ const char *msg_wrong_time =
+ _("Invalid time: start time must be before end time!");
+ const char *msg_enter = _("Press [Enter] to continue");
+
+ do {
+ day_edit_time(*start, &hr, &mn);
+ newtime = update_time_in_date(*start, hr, mn);
+ if (newtime < *start + *dur) {
+ *dur -= (newtime - *start);
+ *start = newtime;
+ valid_date = 1;
+ } else {
+ status_mesg(msg_wrong_time, msg_enter);
+ wgetch(win[STA].p);
+ valid_date = 0;
+ }
+ }
+ while (valid_date == 0);
+}
+
+static void update_duration(long *start, long *dur)
+{
+ unsigned newdur;
+
+ day_edit_duration(*start, *dur, &newdur);
+ *dur = newdur;
+}
+
+static void update_desc(char **desc)
+{
+ status_mesg(_("Enter the new item description:"), "");
+ updatestring(win[STA].p, desc, 0, 1);
+}
+
+static void update_rept(struct rpt **rpt, const long start)
+{
+ int newtype, newfreq, date_entered;
+ long newuntil;
+ char outstr[BUFSIZ];
+ char *freqstr, *timstr;
+ const char *msg_rpt_prefix = _("Enter the new repetition type:");
+ const char *msg_rpt_daily = _("(d)aily");
+ const char *msg_rpt_weekly = _("(w)eekly");
+ const char *msg_rpt_monthly = _("(m)onthly");
+ const char *msg_rpt_yearly = _("(y)early");
+
+ /* Find the current repetition type. */
+ const char *rpt_current;
+ char msg_rpt_current[BUFSIZ];
+ switch (recur_def2char((*rpt)->type)) {
+ case 'D':
+ rpt_current = msg_rpt_daily;
+ break;
+ case 'W':
+ rpt_current = msg_rpt_weekly;
+ break;
+ case 'M':
+ rpt_current = msg_rpt_monthly;
+ break;
+ case 'Y':
+ rpt_current = msg_rpt_yearly;
+ break;
+ default:
+ /* NOTREACHED, but makes the compiler happier. */
+ rpt_current = msg_rpt_daily;
+ }
+
+ snprintf(msg_rpt_current, BUFSIZ, _("(currently using %s)"), rpt_current);
+
+ char msg_rpt_asktype[BUFSIZ];
+ snprintf(msg_rpt_asktype, BUFSIZ, "%s %s, %s, %s, %s ? %s",
+ msg_rpt_prefix,
+ msg_rpt_daily,
+ msg_rpt_weekly, msg_rpt_monthly, msg_rpt_yearly, msg_rpt_current);
+
+ const char *msg_rpt_choice = _("[dwmy]");
+ const char *msg_wrong_freq = _("The frequence you entered is not valid.");
+ const char *msg_wrong_time =
+ _("Invalid time: start time must be before end time!");
+ const char *msg_wrong_date = _("The entered date is not valid.");
+ const char *msg_fmts =
+ _("Possible formats are [%s] or '0' for an endless repetition.");
+ const char *msg_enter = _("Press [Enter] to continue");
+
+ switch (status_ask_choice(msg_rpt_asktype, msg_rpt_choice, 4)) {
+ case 1:
+ newtype = 'D';
+ break;
+ case 2:
+ newtype = 'W';
+ break;
+ case 3:
+ newtype = 'M';
+ break;
+ case 4:
+ newtype = 'Y';
+ break;
+ default:
+ return;
+ }
+
+ do {
+ status_mesg(_("Enter the new repetition frequence:"), "");
+ freqstr = mem_malloc(BUFSIZ);
+ snprintf(freqstr, BUFSIZ, "%d", (*rpt)->freq);
+ if (updatestring(win[STA].p, &freqstr, 0, 1) == GETSTRING_VALID) {
+ newfreq = atoi(freqstr);
+ mem_free(freqstr);
+ if (newfreq == 0) {
+ status_mesg(msg_wrong_freq, msg_enter);
+ wgetch(win[STA].p);
+ }
+ } else {
+ mem_free(freqstr);
+ return;
+ }
+ }
+ while (newfreq == 0);
+
+ do {
+ snprintf(outstr, BUFSIZ, _("Enter the new ending date: [%s] or '0'"),
+ DATEFMT_DESC(conf.input_datefmt));
+ status_mesg(outstr, "");
+ timstr = date_sec2date_str((*rpt)->until, DATEFMT(conf.input_datefmt));
+ if (updatestring(win[STA].p, &timstr, 0, 1) != GETSTRING_VALID) {
+ mem_free(timstr);
+ return;
+ }
+ if (strcmp(timstr, "0") == 0) {
+ newuntil = 0;
+ date_entered = 1;
+ } else {
+ struct tm lt;
+ time_t t;
+ struct date new_date;
+ int newmonth, newday, newyear;
+
+ if (parse_date(timstr, conf.input_datefmt, &newyear, &newmonth,
+ &newday, calendar_get_slctd_day())) {
+ t = start;
+ localtime_r(&t, &lt);
+ new_date.dd = newday;
+ new_date.mm = newmonth;
+ new_date.yyyy = newyear;
+ newuntil = date2sec(new_date, lt.tm_hour, lt.tm_min);
+ if (newuntil < start) {
+ status_mesg(msg_wrong_time, msg_enter);
+ wgetch(win[STA].p);
+ date_entered = 0;
+ } else
+ date_entered = 1;
+ } else {
+ snprintf(outstr, BUFSIZ, msg_fmts, DATEFMT_DESC(conf.input_datefmt));
+ status_mesg(msg_wrong_date, outstr);
+ wgetch(win[STA].p);
+ date_entered = 0;
+ }
+ }
+ }
+ while (date_entered == 0);
+
+ mem_free(timstr);
+ (*rpt)->type = recur_char2def(newtype);
+ (*rpt)->freq = newfreq;
+ (*rpt)->until = newuntil;
+}
+
+/* Edit an already existing item. */
+void interact_day_item_edit(void)
+{
+ struct day_item *p;
+ struct recur_event *re;
+ struct event *e;
+ struct recur_apoint *ra;
+ struct apoint *a;
+ int need_check_notify = 0;
+
+ p = day_get_item(apoint_hilt());
+
+ switch (p->type) {
+ case RECUR_EVNT:
+ re = p->item.rev;
+ const char *choice_recur_evnt[2] = {
+ _("Description"),
+ _("Repetition"),
+ };
+ switch (status_ask_simplechoice(_("Edit: "), choice_recur_evnt, 2)) {
+ case 1:
+ update_desc(&re->mesg);
+ break;
+ case 2:
+ update_rept(&re->rpt, re->day);
+ break;
+ default:
+ return;
+ }
+ break;
+ case EVNT:
+ e = p->item.ev;
+ update_desc(&e->mesg);
+ break;
+ case RECUR_APPT:
+ ra = p->item.rapt;
+ const char *choice_recur_appt[4] = {
+ _("Start time"),
+ _("End time"),
+ _("Description"),
+ _("Repetition"),
+ };
+ switch (status_ask_simplechoice(_("Edit: "), choice_recur_appt, 4)) {
+ case 1:
+ need_check_notify = 1;
+ update_start_time(&ra->start, &ra->dur);
+ break;
+ case 2:
+ update_duration(&ra->start, &ra->dur);
+ break;
+ case 3:
+ if (notify_bar())
+ need_check_notify = notify_same_recur_item(ra);
+ update_desc(&ra->mesg);
+ break;
+ case 4:
+ need_check_notify = 1;
+ update_rept(&ra->rpt, ra->start);
+ break;
+ default:
+ return;
+ }
+ break;
+ case APPT:
+ a = p->item.apt;
+ const char *choice_appt[3] = {
+ _("Start time"),
+ _("End time"),
+ _("Description"),
+ };
+ switch (status_ask_simplechoice(_("Edit: "), choice_appt, 3)) {
+ case 1:
+ need_check_notify = 1;
+ update_start_time(&a->start, &a->dur);
+ break;
+ case 2:
+ update_duration(&a->start, &a->dur);
+ break;
+ case 3:
+ if (notify_bar())
+ need_check_notify = notify_same_item(a->start);
+ update_desc(&a->mesg);
+ break;
+ default:
+ return;
+ }
+ break;
+ }
+
+ calendar_monthly_view_cache_set_invalid();
+
+ if (need_check_notify)
+ notify_check_next_app(1);
+}
+
+/* Pipe an appointment or event to an external program. */
+void interact_day_item_pipe(void)
+{
+ char cmd[BUFSIZ] = "";
+ char const *arg[] = { cmd, NULL };
+ int pout;
+ int pid;
+ FILE *fpout;
+ struct day_item *p;
+
+ status_mesg(_("Pipe item to external command:"), "");
+ if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID)
+ return;
+
+ wins_prepare_external();
+ if ((pid = shell_exec(NULL, &pout, *arg, arg))) {
+ fpout = fdopen(pout, "w");
+
+ p = day_get_item(apoint_hilt());
+ switch (p->type) {
+ case RECUR_EVNT:
+ recur_event_write(p->item.rev, fpout);
+ break;
+ case EVNT:
+ event_write(p->item.ev, fpout);
+ break;
+ case RECUR_APPT:
+ recur_apoint_write(p->item.rapt, fpout);
+ break;
+ case APPT:
+ apoint_write(p->item.apt, fpout);
+ break;
+ }
+
+ fclose(fpout);
+ child_wait(NULL, &pout, pid);
+ press_any_key();
+ }
+ wins_unprepare_external();
+}
+
+/*
+ * Add an item in either the appointment or the event list,
+ * depending if the start time is entered or not.
+ */
+void interact_day_item_add(void)
+{
+#define LTIME 6
+#define LDUR 12
+ const char *mesg_1 =
+ _("Enter start time ([hh:mm] or [hhmm]), leave blank for an all-day event : ");
+ const char *mesg_2 =
+ _
+ ("Enter end time ([hh:mm] or [hhmm]) or duration ([+hh:mm], [+xxxdxxhxxm] or [+mm]) : ");
+ const char *mesg_3 = _("Enter description :");
+ const char *format_message_1 =
+ _("You entered an invalid start time, should be [hh:mm] or [hhmm]");
+ const char *format_message_2 =
+ _
+ ("Invalid end time/duration, should be [hh:mm], [hhmm], [+hh:mm], [+xxxdxxhxxm] or [+mm]");
+ const char *enter_str = _("Press [Enter] to continue");
+ int Id = 1;
+ char item_time[LDUR] = "";
+ char item_mesg[BUFSIZ] = "";
+ long apoint_start;
+ unsigned heures, minutes;
+ unsigned apoint_duration;
+ unsigned end_h, end_m;
+ int is_appointment = 1;
+
+ /* Get the starting time */
+ for (;;) {
+ status_mesg(mesg_1, "");
+ if (getstring(win[STA].p, item_time, LTIME, 0, 1) != GETSTRING_ESC) {
+ if (strlen(item_time) == 0) {
+ is_appointment = 0;
+ break;
+ }
+
+ if (parse_time(item_time, &heures, &minutes) == 1)
+ break;
+ else {
+ status_mesg(format_message_1, enter_str);
+ wgetch(win[STA].p);
+ }
+ } else
+ return;
+ }
+
+ /*
+ * Check if an event or appointment is entered,
+ * depending on the starting time, and record the
+ * corresponding item.
+ */
+ if (is_appointment) { /* Get the appointment duration */
+ item_time[0] = '\0';
+ for (;;) {
+ status_mesg(mesg_2, "");
+ if (getstring(win[STA].p, item_time, LDUR, 0, 1) != GETSTRING_ESC) {
+ if (*item_time == '+' && parse_duration(item_time + 1,
+ &apoint_duration) == 1)
+ break;
+ else if (parse_time(item_time, &end_h, &end_m) == 1) {
+ if (end_h < heures || ((end_h == heures) && (end_m < minutes))) {
+ apoint_duration = MININSEC - minutes + end_m
+ + (24 + end_h - (heures + 1)) * MININSEC;
+ } else {
+ apoint_duration = MININSEC - minutes
+ + end_m + (end_h - (heures + 1)) * MININSEC;
+ }
+ break;
+ } else {
+ status_mesg(format_message_2, enter_str);
+ wgetch(win[STA].p);
+ }
+ } else
+ return;
+ }
+ } else /* Insert the event Id */
+ Id = 1;
+
+ status_mesg(mesg_3, "");
+ if (getstring(win[STA].p, item_mesg, BUFSIZ, 0, 1) == GETSTRING_VALID) {
+ if (is_appointment) {
+ apoint_start = date2sec(*calendar_get_slctd_day(), heures, minutes);
+ apoint_new(item_mesg, 0L, apoint_start, min2sec(apoint_duration), 0L);
+ if (notify_bar())
+ notify_check_added(item_mesg, apoint_start, 0L);
+ } else
+ event_new(item_mesg, 0L, date2sec(*calendar_get_slctd_day(), 0, 0), Id);
+
+ if (apoint_hilt() == 0)
+ apoint_hilt_increase(1);
+ }
+
+ calendar_monthly_view_cache_set_invalid();
+
+ wins_erase_status_bar();
+}
+
+/* Delete an item from the appointment list. */
+void interact_day_item_delete(unsigned *nb_events, unsigned *nb_apoints,
+ unsigned reg)
+{
+ const char *del_app_str = _("Do you really want to delete this item ?");
+
+ const char *erase_warning =
+ _("This item is recurrent. "
+ "Delete (a)ll occurences or just this (o)ne ?");
+ const char *erase_choices = _("[ao]");
+ const int nb_erase_choices = 2;
+
+ const char *note_warning =
+ _("This item has a note attached to it. "
+ "Delete (i)tem or just its (n)ote ?");
+ const char *note_choices = _("[in]");
+ const int nb_note_choices = 2;
+
+ long date = calendar_get_slctd_day_sec();
+ int nb_items = *nb_apoints + *nb_events;
+ int to_be_removed = 0;
+
+ if (nb_items == 0)
+ return;
+
+ struct day_item *p = day_get_item(apoint_hilt());
+
+ if (conf.confirm_delete) {
+ if (status_ask_bool(del_app_str) != 1) {
+ wins_erase_status_bar();
+ return;
+ }
+ }
+
+ if (day_item_get_note(p)) {
+ switch (status_ask_choice(note_warning, note_choices, nb_note_choices)) {
+ case 1:
+ break;
+ case 2:
+ day_item_erase_note(p);
+ return;
+ default: /* User escaped */
+ return;
+ }
+ }
+
+ if (p->type == RECUR_EVNT || p->type == RECUR_APPT) {
+ switch (status_ask_choice(erase_warning, erase_choices, nb_erase_choices)) {
+ case 1:
+ break;
+ case 2:
+ day_item_add_exc(p, date);
+ return;
+ default:
+ return;
+ }
+ }
+
+ interact_day_item_cut_free(reg);
+ p = day_cut_item(date, apoint_hilt());
+ day_cut[reg].type = p->type;
+ day_cut[reg].item = p->item;
+
+ switch (p->type) {
+ case EVNT:
+ case RECUR_EVNT:
+ (*nb_events)--;
+ to_be_removed = 1;
+ break;
+ case APPT:
+ case RECUR_APPT:
+ (*nb_apoints)--;
+ to_be_removed = 3;
+ break;
+ default:
+ EXIT(_("no such type"));
+ /* NOTREACHED */
+ }
+
+ calendar_monthly_view_cache_set_invalid();
+
+ if (apoint_hilt() > 1)
+ apoint_hilt_decrease(1);
+ if (apad.first_onscreen >= to_be_removed)
+ apad.first_onscreen = apad.first_onscreen - to_be_removed;
+ if (nb_items == 1)
+ apoint_hilt_set(0);
+}
+
+/* Request user to enter a new todo item. */
+void interact_todo_add(void)
+{
+ int ch = 0;
+ const char *mesg = _("Enter the new ToDo item : ");
+ const char *mesg_id =
+ _("Enter the ToDo priority [1 (highest) - 9 (lowest)] :");
+ char todo_input[BUFSIZ] = "";
+
+ status_mesg(mesg, "");
+ if (getstring(win[STA].p, todo_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
+ while ((ch < '1') || (ch > '9')) {
+ status_mesg(mesg_id, "");
+ ch = wgetch(win[STA].p);
+ }
+ todo_add(todo_input, ch - '0', NULL);
+ todo_set_nb(todo_nb() + 1);
+ }
+}
+
+/* Delete an item from the ToDo list. */
+void interact_todo_delete(void)
+{
+ const char *del_todo_str = _("Do you really want to delete this task ?");
+ const char *erase_warning =
+ _("This item has a note attached to it. "
+ "Delete (t)odo or just its (n)ote ?");
+ const char *erase_choice = _("[tn]");
+ const int nb_erase_choice = 2;
+ int answer;
+
+ if ((todo_nb() <= 0) ||
+ (conf.confirm_delete && (status_ask_bool(del_todo_str) != 1))) {
+ wins_erase_status_bar();
+ return;
+ }
+
+ /* This todo item doesn't have any note associated. */
+ if (todo_get_item(todo_hilt())->note == NULL)
+ answer = 1;
+ else
+ answer = status_ask_choice(erase_warning, erase_choice, nb_erase_choice);
+
+ switch (answer) {
+ case 1:
+ todo_delete(todo_get_item(todo_hilt()));
+ todo_set_nb(todo_nb() - 1);
+ if (todo_hilt() > 1)
+ todo_hilt_decrease(1);
+ if (todo_nb() == 0)
+ todo_hilt_set(0);
+ if (todo_hilt_pos() < 0)
+ todo_first_decrease(1);
+ break;
+ case 2:
+ todo_delete_note(todo_get_item(todo_hilt()));
+ break;
+ default:
+ wins_erase_status_bar();
+ return;
+ }
+}
+
+/* Edit the description of an already existing todo item. */
+void interact_todo_edit(void)
+{
+ struct todo *i;
+ const char *mesg = _("Enter the new ToDo description :");
+
+ status_mesg(mesg, "");
+ i = todo_get_item(todo_hilt());
+ updatestring(win[STA].p, &i->mesg, 0, 1);
+}
+
+/* Pipe a todo item to an external program. */
+void interact_todo_pipe(void)
+{
+ char cmd[BUFSIZ] = "";
+ char const *arg[] = { cmd, NULL };
+ int pout;
+ int pid;
+ FILE *fpout;
+ struct todo *todo;
+
+ status_mesg(_("Pipe item to external command:"), "");
+ if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID)
+ return;
+
+ wins_prepare_external();
+ if ((pid = shell_exec(NULL, &pout, *arg, arg))) {
+ fpout = fdopen(pout, "w");
+
+ todo = todo_get_item(todo_hilt());
+ todo_write(todo, fpout);
+
+ fclose(fpout);
+ child_wait(NULL, &pout, pid);
+ press_any_key();
+ }
+ wins_unprepare_external();
+}
+
+/*
+ * Ask user for repetition characteristics:
+ * o repetition type: daily, weekly, monthly, yearly
+ * o repetition frequence: every X days, weeks, ...
+ * o repetition end date
+ * and then delete the selected item to recreate it as a recurrent one
+ */
+void interact_day_item_repeat(void)
+{
+ struct tm lt;
+ time_t t;
+ int date_entered = 0;
+ int year = 0, month = 0, day = 0;
+ struct date until_date;
+ char outstr[BUFSIZ];
+ char user_input[BUFSIZ] = "";
+ const char *msg_rpt_prefix = _("Enter the repetition type:");
+ const char *msg_rpt_daily = _("(d)aily");
+ const char *msg_rpt_weekly = _("(w)eekly");
+ const char *msg_rpt_monthly = _("(m)onthly");
+ const char *msg_rpt_yearly = _("(y)early");
+ const char *msg_type_choice = _("[dwmy]");
+ const char *mesg_freq_1 = _("Enter the repetition frequence:");
+ const char *mesg_wrong_freq = _("The frequence you entered is not valid.");
+ const char *mesg_until_1 =
+ _("Enter the ending date: [%s] or '0' for an endless repetition");
+ const char *mesg_wrong_1 = _("The entered date is not valid.");
+ const char *mesg_wrong_2 =
+ _("Possible formats are [%s] or '0' for an endless repetition");
+ const char *wrong_type_1 = _("This item is already a repeated one.");
+ const char *wrong_type_2 = _("Press [ENTER] to continue.");
+ const char *mesg_older =
+ _("Sorry, the date you entered is older than the item start time.");
+
+ char msg_asktype[BUFSIZ];
+ snprintf(msg_asktype, BUFSIZ, "%s %s, %s, %s, %s",
+ msg_rpt_prefix,
+ msg_rpt_daily, msg_rpt_weekly, msg_rpt_monthly, msg_rpt_yearly);
+
+ int type = 0, freq = 0;
+ int item_nb;
+ struct day_item *p;
+ struct recur_apoint *ra;
+ long until, date;
+
+ item_nb = apoint_hilt();
+ p = day_get_item(item_nb);
+ if (p->type != APPT && p->type != EVNT) {
+ status_mesg(wrong_type_1, wrong_type_2);
+ wgetch(win[STA].p);
+ return;
+ }
+
+ switch (status_ask_choice(msg_asktype, msg_type_choice, 4)) {
+ case 1:
+ type = RECUR_DAILY;
+ break;
+ case 2:
+ type = RECUR_WEEKLY;
+ break;
+ case 3:
+ type = RECUR_MONTHLY;
+ break;
+ case 4:
+ type = RECUR_YEARLY;
+ break;
+ default:
+ return;
+ }
+
+ while (freq == 0) {
+ status_mesg(mesg_freq_1, "");
+ if (getstring(win[STA].p, user_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
+ freq = atoi(user_input);
+ if (freq == 0) {
+ status_mesg(mesg_wrong_freq, wrong_type_2);
+ wgetch(win[STA].p);
+ }
+ user_input[0] = '\0';
+ } else
+ return;
+ }
+
+ while (!date_entered) {
+ snprintf(outstr, BUFSIZ, mesg_until_1, DATEFMT_DESC(conf.input_datefmt));
+ status_mesg(outstr, "");
+ if (getstring(win[STA].p, user_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
+ if (strlen(user_input) == 1 && strcmp(user_input, "0") == 0) {
+ until = 0;
+ date_entered = 1;
+ } else {
+ if (parse_date(user_input, conf.input_datefmt,
+ &year, &month, &day, calendar_get_slctd_day())) {
+ t = p->start;
+ localtime_r(&t, &lt);
+ until_date.dd = day;
+ until_date.mm = month;
+ until_date.yyyy = year;
+ until = date2sec(until_date, lt.tm_hour, lt.tm_min);
+ if (until < p->start) {
+ status_mesg(mesg_older, wrong_type_2);
+ wgetch(win[STA].p);
+ date_entered = 0;
+ } else {
+ date_entered = 1;
+ }
+ } else {
+ snprintf(outstr, BUFSIZ, mesg_wrong_2,
+ DATEFMT_DESC(conf.input_datefmt));
+ status_mesg(mesg_wrong_1, outstr);
+ wgetch(win[STA].p);
+ date_entered = 0;
+ }
+ }
+ } else
+ return;
+ }
+
+ date = calendar_get_slctd_day_sec();
+ if (p->type == EVNT) {
+ struct event *ev = p->item.ev;
+ recur_event_new(ev->mesg, ev->note, ev->day, ev->id, type, freq, until,
+ NULL);
+ } else if (p->type == APPT) {
+ struct apoint *apt = p->item.apt;
+ ra = recur_apoint_new(apt->mesg, apt->note, apt->start, apt->dur,
+ apt->state, type, freq, until, NULL);
+ if (notify_bar())
+ notify_check_repeated(ra);
+ } else {
+ EXIT(_("wrong item type"));
+ /* NOTREACHED */
+ }
+
+ interact_day_item_cut_free(REG_BLACK_HOLE);
+ p = day_cut_item(date, item_nb);
+ day_cut[REG_BLACK_HOLE].type = p->type;
+ day_cut[REG_BLACK_HOLE].item = p->item;
+
+ calendar_monthly_view_cache_set_invalid();
+}
+
+/* Free the current cut item, if any. */
+void interact_day_item_cut_free(unsigned reg)
+{
+ switch (day_cut[reg].type) {
+ case 0:
+ /* No previous item, don't free anything. */
+ break;
+ case APPT:
+ apoint_free(day_cut[reg].item.apt);
+ break;
+ case EVNT:
+ event_free(day_cut[reg].item.ev);
+ break;
+ case RECUR_APPT:
+ recur_apoint_free(day_cut[reg].item.rapt);
+ break;
+ case RECUR_EVNT:
+ recur_event_free(day_cut[reg].item.rev);
+ break;
+ }
+}
+
+/* Copy an item, so that it can be pasted somewhere else later. */
+void interact_day_item_copy(unsigned *nb_events, unsigned *nb_apoints,
+ unsigned reg)
+{
+ const int NBITEMS = *nb_apoints + *nb_events;
+
+ if (NBITEMS == 0 || reg == REG_BLACK_HOLE)
+ return;
+
+ interact_day_item_cut_free(reg);
+ day_item_fork(day_get_item(apoint_hilt()), &day_cut[reg]);
+}
+
+/* Paste a previously cut item. */
+void interact_day_item_paste(unsigned *nb_events, unsigned *nb_apoints,
+ unsigned reg)
+{
+ int item_type;
+ struct day_item day;
+
+ if (reg == REG_BLACK_HOLE || !day_cut[reg].type)
+ return;
+
+ day_item_fork(&day_cut[reg], &day);
+ item_type = day_paste_item(&day, calendar_get_slctd_day_sec());
+
+ calendar_monthly_view_cache_set_invalid();
+
+ if (item_type == EVNT || item_type == RECUR_EVNT)
+ (*nb_events)++;
+ else if (item_type == APPT || item_type == RECUR_APPT)
+ (*nb_apoints)++;
+ else
+ return;
+
+ if (apoint_hilt() == 0)
+ apoint_hilt_increase(1);
+}
diff --git a/src/io.c b/src/io.c
index 0cc394e..3f66d0b 100644
--- a/src/io.c
+++ b/src/io.c
@@ -231,7 +231,6 @@ void io_init(const char *cfile, const char *datadir)
snprintf(path_todo, BUFSIZ, "%s/" TODO_PATH_NAME, home);
snprintf(path_conf, BUFSIZ, "%s/" CONF_PATH_NAME, home);
snprintf(path_notes, BUFSIZ, "%s/" NOTES_DIR_NAME, home);
- snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH_NAME, home);
snprintf(path_keys, BUFSIZ, "%s/" KEYS_PATH_NAME, home);
snprintf(path_cpid, BUFSIZ, "%s/" CPID_PATH_NAME, home);
snprintf(path_dpid, BUFSIZ, "%s/" DPID_PATH_NAME, home);
@@ -249,43 +248,48 @@ void io_init(const char *cfile, const char *datadir)
snprintf(path_dpid, BUFSIZ, "%s/" DPID_PATH, home);
snprintf(path_dmon_log, BUFSIZ, "%s/" DLOG_PATH, home);
snprintf(path_notes, BUFSIZ, "%s/" NOTES_DIR, home);
- if (cfile == NULL) {
- snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH, home);
+ }
+
+ if (cfile == NULL) {
+ if (datadir != NULL) {
+ snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH_NAME, home);
} else {
- snprintf(apts_file, BUFSIZ, "%s", cfile);
- strncpy(path_apts, apts_file, BUFSIZ);
- /* 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':
- puts(_("aborting...\n"));
- exit_calcurse(EXIT_FAILURE);
- break;
-
- case 'Y':
- case 'y':
- data_file = fopen(path_apts, "w");
- if (data_file == NULL) {
- perror(path_apts);
- exit_calcurse(EXIT_FAILURE);
- } else {
- printf(_("%s successfully created\n"), path_apts);
- puts(_("starting interactive mode...\n"));
- }
- break;
-
- default:
- puts(_("aborting...\n"));
+ snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH, home);
+ }
+ } else {
+ snprintf(apts_file, BUFSIZ, "%s", cfile);
+ strncpy(path_apts, apts_file, BUFSIZ);
+ /* 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':
+ puts(_("aborting...\n"));
+ exit_calcurse(EXIT_FAILURE);
+ break;
+
+ case 'Y':
+ case 'y':
+ data_file = fopen(path_apts, "w");
+ if (data_file == NULL) {
+ perror(path_apts);
exit_calcurse(EXIT_FAILURE);
- break;
+ } else {
+ printf(_("%s successfully created\n"), path_apts);
+ puts(_("starting interactive mode...\n"));
}
+ break;
+
+ default:
+ puts(_("aborting...\n"));
+ exit_calcurse(EXIT_FAILURE);
+ break;
}
- file_close(data_file, __FILE_POS__);
}
+ file_close(data_file, __FILE_POS__);
}
}
@@ -913,29 +917,6 @@ void io_export_data(enum export_type type)
}
}
-/* Draws the export format selection bar */
-void io_export_bar(void)
-{
- int smlspc, spc;
-
- smlspc = 2;
- spc = 15;
-
- custom_apply_attr(win[STA].p, ATTR_HIGHEST);
- mvwaddstr(win[STA].p, 0, 2, "Q");
- mvwaddstr(win[STA].p, 1, 2, "I");
- mvwaddstr(win[STA].p, 0, 2 + spc, "P");
- custom_remove_attr(win[STA].p, ATTR_HIGHEST);
-
- mvwaddstr(win[STA].p, 0, 2 + smlspc, _("Exit"));
- mvwaddstr(win[STA].p, 1, 2 + smlspc, _("Ical"));
- mvwaddstr(win[STA].p, 0, 2 + spc + smlspc, _("Pcal"));
-
- wnoutrefresh(win[STA].p);
- wmove(win[STA].p, 0, 0);
- wins_doupdate();
-}
-
static FILE *get_import_stream(enum export_type type)
{
FILE *stream;
diff --git a/src/keys.c b/src/keys.c
index 56562ed..a908bd0 100644
--- a/src/keys.c
+++ b/src/keys.c
@@ -56,14 +56,14 @@ static struct keydef_s keydef[NBKEYS] = {
{"generic-help", "?"},
{"generic-quit", "q Q"},
{"generic-save", "s S C-s"},
- {"generic-cut", "C-x"},
- {"generic-paste", "C-v"},
+ {"generic-copy", "c"},
+ {"generic-paste", "p C-v"},
{"generic-change-view", "TAB"},
{"generic-import", "i I"},
{"generic-export", "x X"},
{"generic-goto", "g G"},
{"generic-other-cmd", "o O"},
- {"generic-config-menu", "c C"},
+ {"generic-config-menu", "C"},
{"generic-redraw", "C-r"},
{"generic-add-appt", "C-a"},
{"generic-add-todo", "C-t"},
@@ -179,12 +179,13 @@ enum key keys_get_action(int pressed)
return actions[pressed];
}
-enum key keys_getch(WINDOW * win, int *count)
+enum key keys_getch(WINDOW * win, int *count, int *reg)
{
int ch = '0';
- if (count) {
+ if (count && reg) {
*count = 0;
+ *reg = 0;
do {
*count = *count * 10 + ch - '0';
ch = wgetch(win);
@@ -193,8 +194,23 @@ enum key keys_getch(WINDOW * win, int *count)
if (*count == 0)
*count = 1;
- } else
+
+ if (ch == '"') {
+ ch = wgetch(win);
+ if (ch >= '1' && ch <= '9') {
+ *reg = ch - '1' + 1;
+ }
+ else if (ch >= 'a' && ch <= 'z') {
+ *reg = ch - 'a' + 10;
+ }
+ else if (ch == '_') {
+ *reg = REG_BLACK_HOLE;
+ }
+ ch = wgetch(win);
+ }
+ } else {
ch = wgetch(win);
+ }
switch (ch) {
case KEY_RESIZE:
@@ -444,7 +460,7 @@ void keys_popup_info(enum key key)
_("Display hints whenever some help screens are available.");
info[KEY_GENERIC_QUIT] = _("Exit from the current menu, or quit calcurse.");
info[KEY_GENERIC_SAVE] = _("Save calcurse data.");
- info[KEY_GENERIC_CUT] = _("Cut the item that is currently selected.");
+ info[KEY_GENERIC_COPY] = _("Copy the item that is currently selected.");
info[KEY_GENERIC_PASTE] = _("Paste an item at the current position.");
info[KEY_GENERIC_CHANGE_VIEW] =
_("Select next panel in calcurse main screen.");
@@ -522,7 +538,7 @@ void keys_popup_info(enum key key)
#define WINCOL (col - 4)
infowin = popup(WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2,
keydef[key].label, info[key], 1);
- keys_getch(infowin, NULL);
+ keys_getch(infowin, NULL, NULL);
delwin(infowin);
#undef WINROW
#undef WINCOL
diff --git a/src/llist.c b/src/llist.c
index 847b795..f771ef3 100644
--- a/src/llist.c
+++ b/src/llist.c
@@ -112,7 +112,7 @@ llist_item_t *llist_next(llist_item_t * i)
* Return the successor of a list item if it is matched by some filter
* callback. Return NULL otherwise.
*/
-llist_item_t *llist_next_filter(llist_item_t * i, long data,
+llist_item_t *llist_next_filter(llist_item_t * i, void *data,
llist_fn_match_t fn_match)
{
if (i && i->next && fn_match(i->next->data, data))
@@ -205,14 +205,21 @@ void llist_remove(llist_t * l, llist_item_t * i)
/*
* Find the first item matched by some filter callback.
*/
-llist_item_t *llist_find_first(llist_t * l, long data,
+llist_item_t *llist_find_first(llist_t * l, void *data,
llist_fn_match_t fn_match)
{
llist_item_t *i;
- for (i = l->head; i; i = i->next) {
- if (fn_match(i->data, data))
- return i;
+ if (fn_match) {
+ for (i = l->head; i; i = i->next) {
+ if (fn_match(i->data, data))
+ return i;
+ }
+ } else {
+ for (i = l->head; i; i = i->next) {
+ if (i->data == data)
+ return i;
+ }
}
return NULL;
@@ -221,14 +228,21 @@ llist_item_t *llist_find_first(llist_t * l, long data,
/*
* Find the next item matched by some filter callback.
*/
-llist_item_t *llist_find_next(llist_item_t * i, long data,
+llist_item_t *llist_find_next(llist_item_t * i, void *data,
llist_fn_match_t fn_match)
{
if (i) {
i = i->next;
- for (; i; i = i->next) {
- if (fn_match(i->data, data))
- return i;
+ if (fn_match) {
+ for (; i; i = i->next) {
+ if (fn_match(i->data, data))
+ return i;
+ }
+ } else {
+ for (; i; i = i->next) {
+ if (i->data == data)
+ return i;
+ }
}
}
@@ -238,7 +252,7 @@ llist_item_t *llist_find_next(llist_item_t * i, long data,
/*
* Find the nth item matched by some filter callback.
*/
-llist_item_t *llist_find_nth(llist_t * l, int n, long data,
+llist_item_t *llist_find_nth(llist_t * l, int n, void *data,
llist_fn_match_t fn_match)
{
llist_item_t *i;
@@ -246,9 +260,16 @@ llist_item_t *llist_find_nth(llist_t * l, int n, long data,
if (n < 0)
return NULL;
- for (i = l->head; i; i = i->next) {
- if (fn_match(i->data, data) && (n-- == 0))
- return i;
+ if (fn_match) {
+ for (i = l->head; i; i = i->next) {
+ if (fn_match(i->data, data) && (n-- == 0))
+ return i;
+ }
+ } else {
+ for (i = l->head; i; i = i->next) {
+ if ((i->data == data) && (n-- == 0))
+ return i;
+ }
}
return NULL;
diff --git a/src/llist.h b/src/llist.h
index c795f37..a786358 100644
--- a/src/llist.h
+++ b/src/llist.h
@@ -48,7 +48,7 @@ struct llist {
};
typedef int (*llist_fn_cmp_t) (void *, void *);
-typedef int (*llist_fn_match_t) (void *, long);
+typedef int (*llist_fn_match_t) (void *, void *);
typedef void (*llist_fn_free_t) (void *);
/* Initialization and deallocation. */
@@ -65,10 +65,10 @@ void llist_free_inner(llist_t *, llist_fn_free_t);
llist_item_t *llist_first(llist_t *);
llist_item_t *llist_nth(llist_t *, int);
llist_item_t *llist_next(llist_item_t *);
-llist_item_t *llist_next_filter(llist_item_t *, long, llist_fn_match_t);
-llist_item_t *llist_find_first(llist_t *, long, llist_fn_match_t);
-llist_item_t *llist_find_next(llist_item_t *, long, llist_fn_match_t);
-llist_item_t *llist_find_nth(llist_t *, int, long, llist_fn_match_t);
+llist_item_t *llist_next_filter(llist_item_t *, void *, llist_fn_match_t);
+llist_item_t *llist_find_first(llist_t *, void *, llist_fn_match_t);
+llist_item_t *llist_find_next(llist_item_t *, void *, llist_fn_match_t);
+llist_item_t *llist_find_nth(llist_t *, int, void *, llist_fn_match_t);
#define LLIST_FIRST(l) llist_first(l)
#define LLIST_NTH(l, n) llist_nth(l, n)
diff --git a/src/recur.c b/src/recur.c
index 5c32bca..1c593c2 100644
--- a/src/recur.c
+++ b/src/recur.c
@@ -44,8 +44,6 @@
llist_ts_t recur_alist_p;
llist_t recur_elist;
-static struct recur_event bkp_cut_recur_event;
-static struct recur_apoint bkp_cut_recur_apoint;
static void free_exc(struct excp *exc)
{
@@ -85,71 +83,55 @@ static void exc_dup(llist_t * in, llist_t * exc)
}
}
-void recur_event_free_bkp(void)
+struct recur_event *recur_event_dup(struct recur_event *in)
{
- if (bkp_cut_recur_event.mesg) {
- mem_free(bkp_cut_recur_event.mesg);
- bkp_cut_recur_event.mesg = 0;
- }
- if (bkp_cut_recur_event.rpt) {
- mem_free(bkp_cut_recur_event.rpt);
- bkp_cut_recur_event.rpt = 0;
- }
- free_exc_list(&bkp_cut_recur_event.exc);
- erase_note(&bkp_cut_recur_event.note);
-}
-
-void recur_apoint_free_bkp(void)
-{
- if (bkp_cut_recur_apoint.mesg) {
- mem_free(bkp_cut_recur_apoint.mesg);
- bkp_cut_recur_apoint.mesg = 0;
- }
- if (bkp_cut_recur_apoint.rpt) {
- mem_free(bkp_cut_recur_apoint.rpt);
- bkp_cut_recur_apoint.rpt = 0;
- }
- free_exc_list(&bkp_cut_recur_apoint.exc);
- erase_note(&bkp_cut_recur_apoint.note);
-}
+ EXIT_IF(!in, _("null pointer"));
-static void recur_event_dup(struct recur_event *in, struct recur_event *bkp)
-{
- EXIT_IF(!in || !bkp, _("null pointer"));
+ struct recur_event *rev = mem_malloc(sizeof(struct recur_event));
- bkp->id = in->id;
- bkp->day = in->day;
- bkp->mesg = mem_strdup(in->mesg);
+ rev->id = in->id;
+ rev->day = in->day;
+ rev->mesg = mem_strdup(in->mesg);
- bkp->rpt = mem_malloc(sizeof(struct rpt));
- bkp->rpt->type = in->rpt->type;
- bkp->rpt->freq = in->rpt->freq;
- bkp->rpt->until = in->rpt->until;
+ rev->rpt = mem_malloc(sizeof(struct rpt));
+ rev->rpt->type = in->rpt->type;
+ rev->rpt->freq = in->rpt->freq;
+ rev->rpt->until = in->rpt->until;
- exc_dup(&bkp->exc, &in->exc);
+ exc_dup(&rev->exc, &in->exc);
if (in->note)
- bkp->note = mem_strdup(in->note);
+ rev->note = mem_strdup(in->note);
+ else
+ rev->note = NULL;
+
+ return rev;
}
-static void recur_apoint_dup(struct recur_apoint *in, struct recur_apoint *bkp)
+struct recur_apoint *recur_apoint_dup(struct recur_apoint *in)
{
- EXIT_IF(!in || !bkp, _("null pointer"));
+ EXIT_IF(!in, _("null pointer"));
+
+ struct recur_apoint *rapt = mem_malloc(sizeof(struct recur_apoint));
- bkp->start = in->start;
- bkp->dur = in->dur;
- bkp->state = in->state;
- bkp->mesg = mem_strdup(in->mesg);
+ rapt->start = in->start;
+ rapt->dur = in->dur;
+ rapt->state = in->state;
+ rapt->mesg = mem_strdup(in->mesg);
- bkp->rpt = mem_malloc(sizeof(struct rpt));
- bkp->rpt->type = in->rpt->type;
- bkp->rpt->freq = in->rpt->freq;
- bkp->rpt->until = in->rpt->until;
+ rapt->rpt = mem_malloc(sizeof(struct rpt));
+ rapt->rpt->type = in->rpt->type;
+ rapt->rpt->freq = in->rpt->freq;
+ rapt->rpt->until = in->rpt->until;
- exc_dup(&bkp->exc, &in->exc);
+ exc_dup(&rapt->exc, &in->exc);
if (in->note)
- bkp->note = mem_strdup(in->note);
+ rapt->note = mem_strdup(in->note);
+ else
+ rapt->note = NULL;
+
+ return rapt;
}
void recur_apoint_llist_init(void)
@@ -157,7 +139,7 @@ void recur_apoint_llist_init(void)
LLIST_TS_INIT(&recur_alist_p);
}
-static void recur_apoint_free(struct recur_apoint *rapt)
+void recur_apoint_free(struct recur_apoint *rapt)
{
mem_free(rapt->mesg);
if (rapt->note)
@@ -168,7 +150,7 @@ static void recur_apoint_free(struct recur_apoint *rapt)
mem_free(rapt);
}
-static void recur_event_free(struct recur_event *rev)
+void recur_event_free(struct recur_event *rev)
{
mem_free(rev->mesg);
if (rev->note)
@@ -550,9 +532,9 @@ static long diff_years(struct tm lt_start, struct tm lt_end)
return lt_end.tm_year - lt_start.tm_year;
}
-static int exc_inday(struct excp *exc, long day_start)
+static int exc_inday(struct excp *exc, long *day_start)
{
- return (exc->st >= day_start && exc->st < day_start + DAYINSEC);
+ return (exc->st >= *day_start && exc->st < *day_start + DAYINSEC);
}
/*
@@ -626,7 +608,7 @@ recur_item_find_occurrence(long item_start, long item_dur, llist_t * item_exc,
lt_item_day.tm_isdst = lt_day.tm_isdst;
t = mktime(&lt_item_day);
- if (LLIST_FIND_FIRST(item_exc, t, exc_inday))
+ if (LLIST_FIND_FIRST(item_exc, &t, exc_inday))
return 0;
if (rpt_until != 0 && t > rpt_until)
@@ -678,16 +660,36 @@ recur_item_inday(long item_start, long item_dur, llist_t * item_exc,
rpt_freq, rpt_until, day_start, NULL);
}
-unsigned recur_apoint_inday(struct recur_apoint *rapt, long day_start)
+unsigned recur_apoint_inday(struct recur_apoint *rapt, long *day_start)
{
return recur_item_inday(rapt->start, rapt->dur, &rapt->exc, rapt->rpt->type,
- rapt->rpt->freq, rapt->rpt->until, day_start);
+ rapt->rpt->freq, rapt->rpt->until, *day_start);
}
-unsigned recur_event_inday(struct recur_event *rev, long day_start)
+unsigned recur_event_inday(struct recur_event *rev, long *day_start)
{
return recur_item_inday(rev->day, DAYINSEC, &rev->exc, rev->rpt->type,
- rev->rpt->freq, rev->rpt->until, day_start);
+ rev->rpt->freq, rev->rpt->until, *day_start);
+}
+
+/* Add an exception to a recurrent event. */
+void
+recur_event_add_exc(struct recur_event *rev, long date)
+{
+ recur_add_exc(&rev->exc, date);
+}
+
+/* Add an exception to a recurrent appointment. */
+void
+recur_apoint_add_exc(struct recur_apoint *rapt, long date)
+{
+ int need_check_notify = 0;
+
+ if (notify_bar())
+ need_check_notify = notify_same_recur_item(rapt);
+ recur_add_exc(&rapt->exc, date);
+ if (need_check_notify)
+ notify_check_next_app(0);
}
/*
@@ -695,40 +697,14 @@ unsigned recur_event_inday(struct recur_event *rev, long day_start)
* or delete only one occurence of the recurrent event.
*/
void
-recur_event_erase(long start, unsigned num, unsigned delete_whole,
- enum eraseflg flag)
+recur_event_erase(struct recur_event *rev)
{
- llist_item_t *i;
-
- i = LLIST_FIND_NTH(&recur_elist, num, start, recur_event_inday);
+ llist_item_t *i = LLIST_FIND_FIRST(&recur_elist, rev, NULL);
if (!i)
EXIT(_("event not found"));
- struct recur_event *rev = LLIST_GET_DATA(i);
-
- if (delete_whole) {
- switch (flag) {
- case ERASE_FORCE_ONLY_NOTE:
- erase_note(&rev->note);
- break;
- case ERASE_CUT:
- recur_event_free_bkp();
- recur_event_dup(rev, &bkp_cut_recur_event);
- erase_note(&rev->note);
- /* FALLTHROUGH */
- default:
- LLIST_REMOVE(&recur_elist, i);
- mem_free(rev->mesg);
- if (rev->rpt) {
- mem_free(rev->rpt);
- rev->rpt = 0;
- }
- free_exc_list(&rev->exc);
- mem_free(rev);
- break;
- }
- } else
- recur_add_exc(&rev->exc, start);
+
+ LLIST_REMOVE(&recur_elist, i);
}
/*
@@ -736,184 +712,23 @@ recur_event_erase(long start, unsigned num, unsigned delete_whole,
* or delete only one occurence of the recurrent appointment.
*/
void
-recur_apoint_erase(long start, unsigned num, unsigned delete_whole,
- enum eraseflg flag)
+recur_apoint_erase(struct recur_apoint *rapt)
{
- llist_item_t *i;
- int need_check_notify = 0;
+ LLIST_TS_LOCK(&recur_alist_p);
- i = LLIST_TS_FIND_NTH(&recur_alist_p, num, start, recur_apoint_inday);
+ llist_item_t *i = LLIST_TS_FIND_FIRST(&recur_alist_p, rapt, NULL);
+ int need_check_notify = 0;
if (!i)
EXIT(_("appointment not found"));
- struct recur_apoint *rapt = LLIST_GET_DATA(i);
- LLIST_TS_LOCK(&recur_alist_p);
- if (notify_bar() && flag != ERASE_FORCE_ONLY_NOTE)
+ if (notify_bar())
need_check_notify = notify_same_recur_item(rapt);
- if (delete_whole) {
- switch (flag) {
- case ERASE_FORCE_ONLY_NOTE:
- erase_note(&rapt->note);
- break;
- case ERASE_CUT:
- recur_apoint_free_bkp();
- recur_apoint_dup(rapt, &bkp_cut_recur_apoint);
- erase_note(&rapt->note);
- /* FALLTHROUGH */
- default:
- LLIST_TS_REMOVE(&recur_alist_p, i);
- mem_free(rapt->mesg);
- if (rapt->rpt) {
- mem_free(rapt->rpt);
- rapt->rpt = 0;
- }
- free_exc_list(&rapt->exc);
- mem_free(rapt);
- if (need_check_notify)
- notify_check_next_app(0);
- break;
- }
- } else {
- recur_add_exc(&rapt->exc, start);
- if (need_check_notify)
- notify_check_next_app(0);
- }
- LLIST_TS_UNLOCK(&recur_alist_p);
-}
-
-/*
- * Ask user for repetition characteristics:
- * o repetition type: daily, weekly, monthly, yearly
- * o repetition frequence: every X days, weeks, ...
- * o repetition end date
- * and then delete the selected item to recreate it as a recurrent one
- */
-void recur_repeat_item(void)
-{
- struct tm lt;
- time_t t;
- int date_entered = 0;
- int year = 0, month = 0, day = 0;
- struct date until_date;
- char outstr[BUFSIZ];
- char user_input[BUFSIZ] = "";
- const char *msg_rpt_prefix = _("Enter the repetition type:");
- const char *msg_rpt_daily = _("(d)aily");
- const char *msg_rpt_weekly = _("(w)eekly");
- const char *msg_rpt_monthly = _("(m)onthly");
- const char *msg_rpt_yearly = _("(y)early");
- const char *msg_type_choice = _("[dwmy]");
- const char *mesg_freq_1 = _("Enter the repetition frequence:");
- const char *mesg_wrong_freq = _("The frequence you entered is not valid.");
- const char *mesg_until_1 =
- _("Enter the ending date: [%s] or '0' for an endless repetition");
- const char *mesg_wrong_1 = _("The entered date is not valid.");
- const char *mesg_wrong_2 =
- _("Possible formats are [%s] or '0' for an endless repetition");
- const char *wrong_type_1 = _("This item is already a repeated one.");
- const char *wrong_type_2 = _("Press [ENTER] to continue.");
- const char *mesg_older =
- _("Sorry, the date you entered is older than the item start time.");
-
- char msg_asktype[BUFSIZ];
- snprintf(msg_asktype, BUFSIZ, "%s %s, %s, %s, %s",
- msg_rpt_prefix,
- msg_rpt_daily, msg_rpt_weekly, msg_rpt_monthly, msg_rpt_yearly);
-
- int type = 0, freq = 0;
- int item_nb;
- struct day_item *p;
- struct recur_apoint *ra;
- long until, date;
-
- item_nb = apoint_hilt();
- p = day_get_item(item_nb);
- if (p->type != APPT && p->type != EVNT) {
- status_mesg(wrong_type_1, wrong_type_2);
- wgetch(win[STA].p);
- return;
- }
+ LLIST_TS_REMOVE(&recur_alist_p, i);
+ if (need_check_notify)
+ notify_check_next_app(0);
- switch (status_ask_choice(msg_asktype, msg_type_choice, 4)) {
- case 1:
- type = RECUR_DAILY;
- break;
- case 2:
- type = RECUR_WEEKLY;
- break;
- case 3:
- type = RECUR_MONTHLY;
- break;
- case 4:
- type = RECUR_YEARLY;
- break;
- default:
- return;
- }
-
- while (freq == 0) {
- status_mesg(mesg_freq_1, "");
- if (getstring(win[STA].p, user_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
- freq = atoi(user_input);
- if (freq == 0) {
- status_mesg(mesg_wrong_freq, wrong_type_2);
- wgetch(win[STA].p);
- }
- user_input[0] = '\0';
- } else
- return;
- }
-
- while (!date_entered) {
- snprintf(outstr, BUFSIZ, mesg_until_1, DATEFMT_DESC(conf.input_datefmt));
- status_mesg(outstr, "");
- if (getstring(win[STA].p, user_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
- if (strlen(user_input) == 1 && strcmp(user_input, "0") == 0) {
- until = 0;
- date_entered = 1;
- } else {
- if (parse_date(user_input, conf.input_datefmt,
- &year, &month, &day, calendar_get_slctd_day())) {
- t = p->start;
- localtime_r(&t, &lt);
- until_date.dd = day;
- until_date.mm = month;
- until_date.yyyy = year;
- until = date2sec(until_date, lt.tm_hour, lt.tm_min);
- if (until < p->start) {
- status_mesg(mesg_older, wrong_type_2);
- wgetch(win[STA].p);
- date_entered = 0;
- } else {
- date_entered = 1;
- }
- } else {
- snprintf(outstr, BUFSIZ, mesg_wrong_2,
- DATEFMT_DESC(conf.input_datefmt));
- status_mesg(mesg_wrong_1, outstr);
- wgetch(win[STA].p);
- date_entered = 0;
- }
- }
- } else
- return;
- }
-
- date = calendar_get_slctd_day_sec();
- if (p->type == EVNT) {
- recur_event_new(p->mesg, p->note, p->start, p->evnt_id, type, freq,
- until, NULL);
- } else if (p->type == APPT) {
- ra = recur_apoint_new(p->mesg, p->note, p->start, p->appt_dur,
- p->state, type, freq, until, NULL);
- if (notify_bar())
- notify_check_repeated(ra);
- } else {
- EXIT(_("wrong item type"));
- /* NOTREACHED */
- }
- day_erase_item(date, item_nb, ERASE_FORCE);
+ LLIST_TS_UNLOCK(&recur_alist_p);
}
/*
@@ -959,7 +774,7 @@ struct notify_app *recur_apoint_check_next(struct notify_app *app, long start,
unsigned real_recur_start_time;
LLIST_TS_LOCK(&recur_alist_p);
- LLIST_TS_FIND_FOREACH(&recur_alist_p, app->time, recur_apoint_starts_before,
+ LLIST_TS_FIND_FOREACH(&recur_alist_p, &app->time, recur_apoint_starts_before,
i) {
struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
@@ -976,102 +791,57 @@ struct notify_app *recur_apoint_check_next(struct notify_app *app, long start,
return app;
}
-/* Returns a structure containing the selected recurrent appointment. */
-struct recur_apoint *recur_get_apoint(long date, int num)
-{
- llist_item_t *i = LLIST_TS_FIND_NTH(&recur_alist_p, num, date,
- recur_apoint_inday);
-
- if (i)
- return LLIST_TS_GET_DATA(i);
-
- EXIT(_("item not found"));
- /* NOTREACHED */
-}
-
-/* Returns a structure containing the selected recurrent event. */
-struct recur_event *recur_get_event(long date, int num)
-{
- llist_item_t *i = LLIST_FIND_NTH(&recur_elist, num, date,
- recur_event_inday);
-
- if (i)
- return LLIST_GET_DATA(i);
-
- EXIT(_("item not found"));
- /* NOTREACHED */
-}
-
/* Switch recurrent item notification state. */
-void recur_apoint_switch_notify(long date, int recur_nb)
+void recur_apoint_switch_notify(struct recur_apoint *rapt)
{
- llist_item_t *i;
-
LLIST_TS_LOCK(&recur_alist_p);
- i = LLIST_TS_FIND_NTH(&recur_alist_p, recur_nb, date, recur_apoint_inday);
-
- if (!i)
- EXIT(_("item not found"));
- struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
rapt->state ^= APOINT_NOTIFY;
-
if (notify_bar())
notify_check_repeated(rapt);
LLIST_TS_UNLOCK(&recur_alist_p);
}
-void recur_event_paste_item(void)
+void recur_event_paste_item(struct recur_event *rev, long date)
{
- long new_start, time_shift;
+ long time_shift;
llist_item_t *i;
- new_start = date2sec(*calendar_get_slctd_day(), 0, 0);
- time_shift = new_start - bkp_cut_recur_event.day;
+ time_shift = date - rev->day;
+ rev->day += time_shift;
- bkp_cut_recur_event.day += time_shift;
- if (bkp_cut_recur_event.rpt->until != 0)
- bkp_cut_recur_event.rpt->until += time_shift;
- LLIST_FOREACH(&bkp_cut_recur_event.exc, i) {
+ if (rev->rpt->until != 0)
+ rev->rpt->until += time_shift;
+
+ LLIST_FOREACH(&rev->exc, i) {
struct excp *exc = LLIST_GET_DATA(i);
exc->st += time_shift;
}
- recur_event_new(bkp_cut_recur_event.mesg, bkp_cut_recur_event.note,
- bkp_cut_recur_event.day, bkp_cut_recur_event.id,
- bkp_cut_recur_event.rpt->type,
- bkp_cut_recur_event.rpt->freq,
- bkp_cut_recur_event.rpt->until, &bkp_cut_recur_event.exc);
- recur_event_free_bkp();
+ LLIST_ADD_SORTED(&recur_elist, rev, recur_event_cmp_day);
}
-void recur_apoint_paste_item(void)
+void recur_apoint_paste_item(struct recur_apoint *rapt, long date)
{
- long new_start, time_shift;
+ long time_shift;
llist_item_t *i;
- new_start = date2sec(*calendar_get_slctd_day(),
- get_item_hour(bkp_cut_recur_apoint.start),
- get_item_min(bkp_cut_recur_apoint.start));
- time_shift = new_start - bkp_cut_recur_apoint.start;
+ time_shift = (date + get_item_time(rapt->start)) - rapt->start;
+ rapt->start += time_shift;
+
+ if (rapt->rpt->until != 0)
+ rapt->rpt->until += time_shift;
- bkp_cut_recur_apoint.start += time_shift;
- if (bkp_cut_recur_apoint.rpt->until != 0)
- bkp_cut_recur_apoint.rpt->until += time_shift;
- LLIST_FOREACH(&bkp_cut_recur_event.exc, i) {
+ LLIST_FOREACH(&rapt->exc, i) {
struct excp *exc = LLIST_GET_DATA(i);
exc->st += time_shift;
}
- recur_apoint_new(bkp_cut_recur_apoint.mesg, bkp_cut_recur_apoint.note,
- bkp_cut_recur_apoint.start, bkp_cut_recur_apoint.dur,
- bkp_cut_recur_apoint.state, bkp_cut_recur_apoint.rpt->type,
- bkp_cut_recur_apoint.rpt->freq,
- bkp_cut_recur_apoint.rpt->until, &bkp_cut_recur_apoint.exc);
+ LLIST_TS_LOCK(&recur_alist_p);
+ LLIST_TS_ADD_SORTED(&recur_alist_p, rapt, recur_apoint_cmp_start);
+ LLIST_TS_UNLOCK(&recur_alist_p);
if (notify_bar())
- notify_check_repeated(&bkp_cut_recur_apoint);
-
- recur_apoint_free_bkp();
+ notify_check_repeated(rapt);
}
diff --git a/src/todo.c b/src/todo.c
index bb29f61..af25a60 100644
--- a/src/todo.c
+++ b/src/todo.c
@@ -47,7 +47,7 @@ static int first = 1;
static char *msgsav;
/* Returns a structure containing the selected item. */
-static struct todo *todo_get_item(int item_number)
+struct todo *todo_get_item(int item_number)
{
return LLIST_GET_DATA(LLIST_NTH(&todolist, item_number - 1));
}
@@ -117,26 +117,6 @@ char *todo_saved_mesg(void)
return msgsav;
}
-/* Request user to enter a new todo item. */
-void todo_new_item(void)
-{
- int ch = 0;
- const char *mesg = _("Enter the new ToDo item : ");
- const char *mesg_id =
- _("Enter the ToDo priority [1 (highest) - 9 (lowest)] :");
- char todo_input[BUFSIZ] = "";
-
- status_mesg(mesg, "");
- if (getstring(win[STA].p, todo_input, BUFSIZ, 0, 1) == GETSTRING_VALID) {
- while ((ch < '1') || (ch > '9')) {
- status_mesg(mesg_id, "");
- ch = wgetch(win[STA].p);
- }
- todo_add(todo_input, ch - '0', NULL);
- todos++;
- }
-}
-
static int todo_cmp_id(struct todo *a, struct todo *b)
{
/*
@@ -176,27 +156,20 @@ void todo_write(struct todo *todo, FILE * f)
}
/* Delete a note previously attached to a todo item. */
-static void todo_delete_note_bynum(unsigned num)
+void todo_delete_note(struct todo *todo)
{
- llist_item_t *i = LLIST_NTH(&todolist, num);
-
- if (!i)
- EXIT(_("no such todo"));
- struct todo *todo = LLIST_TS_GET_DATA(i);
-
if (!todo->note)
EXIT(_("no note attached"));
erase_note(&todo->note);
}
/* Delete an item from the todo linked list. */
-static void todo_delete_bynum(unsigned num)
+void todo_delete(struct todo *todo)
{
- llist_item_t *i = LLIST_NTH(&todolist, num);
+ llist_item_t *i = LLIST_FIND_FIRST(&todolist, todo, NULL);
if (!i)
EXIT(_("no such todo"));
- struct todo *todo = LLIST_TS_GET_DATA(i);
LLIST_REMOVE(&todolist, i);
mem_free(todo->mesg);
@@ -210,57 +183,11 @@ static void todo_delete_bynum(unsigned num)
* This way, it is easy to retrive its original priority if the user decides
* that in fact it was not completed.
*/
-void todo_flag(void)
+void todo_flag(struct todo *t)
{
- struct todo *t;
-
- t = todo_get_item(hilt);
t->id = -t->id;
}
-/* Delete an item from the ToDo list. */
-void todo_delete(void)
-{
- const char *del_todo_str = _("Do you really want to delete this task ?");
- const char *erase_warning =
- _("This item has a note attached to it. "
- "Delete (t)odo or just its (n)ote ?");
- const char *erase_choice = _("[tn]");
- const int nb_erase_choice = 2;
- int answer;
-
- if ((todos <= 0) ||
- (conf.confirm_delete && (status_ask_bool(del_todo_str) != 1))) {
- wins_erase_status_bar();
- return;
- }
-
- /* This todo item doesn't have any note associated. */
- if (todo_get_item(hilt)->note == NULL)
- answer = 1;
- else
- answer = status_ask_choice(erase_warning, erase_choice, nb_erase_choice);
-
- switch (answer) {
- case 1:
- todo_delete_bynum(hilt - 1);
- todos--;
- if (hilt > 1)
- hilt--;
- if (todos == 0)
- hilt = 0;
- if (hilt - first < 0)
- first--;
- break;
- case 2:
- todo_delete_note_bynum(hilt - 1);
- break;
- default:
- wins_erase_status_bar();
- return;
- }
-}
-
/*
* Returns the position into the linked list corresponding to the
* given todo item.
@@ -281,54 +208,30 @@ static int todo_get_position(struct todo *needle)
}
/* Change an item priority by pressing '+' or '-' inside TODO panel. */
-void todo_chg_priority(int action)
+void todo_chg_priority(struct todo *backup, int diff)
{
- struct todo *backup;
char backup_mesg[BUFSIZ];
int backup_id;
char backup_note[MAX_NOTESIZ + 1];
- backup = todo_get_item(hilt);
strncpy(backup_mesg, backup->mesg, strlen(backup->mesg) + 1);
backup_id = backup->id;
if (backup->note)
strncpy(backup_note, backup->note, MAX_NOTESIZ + 1);
else
backup_note[0] = '\0';
- switch (action) {
- case KEY_RAISE_PRIORITY:
- if (backup_id > 1)
- backup_id--;
- else
- return;
- break;
- case KEY_LOWER_PRIORITY:
- if (backup_id > 0 && backup_id < 9)
- backup_id++;
- else
- return;
- break;
- default:
- EXIT(_("no such action"));
- /* NOTREACHED */
- }
- todo_delete_bynum(hilt - 1);
+ backup_id += diff;
+ if (backup_id < 1)
+ backup_id = 1;
+ else if (backup_id > 9)
+ backup_id = 9;
+
+ todo_delete(todo_get_item(hilt));
backup = todo_add(backup_mesg, backup_id, backup_note);
hilt = todo_get_position(backup);
}
-/* Edit the description of an already existing todo item. */
-void todo_edit_item(void)
-{
- struct todo *i;
- const char *mesg = _("Enter the new ToDo description :");
-
- status_mesg(mesg, "");
- i = todo_get_item(hilt);
- updatestring(win[STA].p, &i->mesg, 0, 1);
-}
-
/* Display todo items in the corresponding panel. */
static void
display_todo_item(int incolor, char *msg, int prio, int note, int width, int y,
@@ -397,9 +300,8 @@ void todo_update_panel(int which_pan)
/* Draw the scrollbar if necessary. */
if (todos > max_items) {
- float ratio = ((float)max_items) / ((float)todos);
- int sbar_length = (int)(ratio * (max_items + 1));
- int highend = (int)(ratio * first);
+ int sbar_length = max_items * (max_items + 1) / todos;
+ int highend = max_items * first / todos;
unsigned hilt_bar = (which_pan == TOD) ? 1 : 0;
int sbar_top = highend + title_lines;
@@ -413,48 +315,18 @@ void todo_update_panel(int which_pan)
}
/* Attach a note to a todo */
-void todo_edit_note(const char *editor)
+void todo_edit_note(struct todo *i, const char *editor)
{
- struct todo *i = todo_get_item(hilt);
edit_note(&i->note, editor);
}
/* View a note previously attached to a todo */
-void todo_view_note(const char *pager)
+void todo_view_note(struct todo *i, const char *pager)
{
- struct todo *i = todo_get_item(hilt);
view_note(i->note, pager);
}
-/* Pipe a todo item to an external program. */
-void todo_pipe_item(void)
-{
- char cmd[BUFSIZ] = "";
- char const *arg[] = { cmd, NULL };
- int pout;
- int pid;
- FILE *fpout;
- struct todo *todo;
-
- status_mesg(_("Pipe item to external command:"), "");
- if (getstring(win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID)
- return;
-
- wins_prepare_external();
- if ((pid = shell_exec(NULL, &pout, *arg, arg))) {
- fpout = fdopen(pout, "w");
-
- todo = todo_get_item(hilt);
- todo_write(todo, fpout);
-
- fclose(fpout);
- child_wait(NULL, &pout, pid);
- press_any_key();
- }
- wins_unprepare_external();
-}
-
-static void todo_free(struct todo *todo)
+void todo_free(struct todo *todo)
{
mem_free(todo->mesg);
erase_note(&todo->note);
diff --git a/src/utils.c b/src/utils.c
index da8eade..60b0278 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -97,15 +97,15 @@ void exit_calcurse(int status)
void free_user_data(void)
{
+ unsigned i;
+
day_free_list();
event_llist_free();
- event_free_bkp();
apoint_llist_free();
- apoint_free_bkp();
recur_apoint_llist_free();
recur_event_llist_free();
- recur_apoint_free_bkp();
- recur_event_free_bkp();
+ for (i = 0; i <= 37; i++)
+ interact_day_item_cut_free(i);
todo_free_list();
notify_free_app();
}
@@ -501,8 +501,8 @@ draw_scrollbar(WINDOW * win, int y, int x, int length,
* long to fit in its corresponding panel window.
*/
void
-item_in_popup(const char *saved_a_start, const char *saved_a_end,
- const char *msg, const char *pop_title)
+item_in_popup(const char *a_start, const char *a_end, const char *msg,
+ const char *pop_title)
{
WINDOW *popup_win, *pad;
const int margin_left = 4, margin_top = 4;
@@ -511,9 +511,9 @@ item_in_popup(const char *saved_a_start, const char *saved_a_end,
pad = newpad(padl, padw);
popup_win = popup(winl, winw, 1, 2, pop_title, NULL, 1);
- if (strcmp(pop_title, _("Appointment")) == 0) {
- mvwprintw(popup_win, margin_top, margin_left, "- %s -> %s",
- saved_a_start, saved_a_end);
+ if (a_start && a_end) {
+ mvwprintw(popup_win, margin_top, margin_left, "- %s -> %s", a_start,
+ a_end);
}
mvwaddstr(pad, 0, margin_left, msg);
wmove(win[STA].p, 0, 0);
@@ -751,9 +751,11 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute)
if (*p == ':') {
if ((++n) > 1)
return 0;
- } else if ((*p >= '0') && (*p <= '9'))
+ } else if ((*p >= '0') && (*p <= '9')) {
+ if ((n == 0) && (p == (string + 2)) && *(p + 1))
+ n++;
in[n] = in[n] * 10 + (int)(*p - '0');
- else
+ } else
return 0;
}
diff --git a/src/wins.c b/src/wins.c
index 249610c..65b2d96 100644
--- a/src/wins.c
+++ b/src/wins.c
@@ -301,9 +301,8 @@ void wins_scrollwin_display(struct scrollwin *sw)
const int visible_lines = sw->win.h - sw->pad.y - 1;
if (sw->total_lines > visible_lines) {
- float ratio = ((float)visible_lines) / ((float)sw->total_lines);
- int sbar_length = (int)(ratio * visible_lines);
- int highend = (int)(ratio * sw->first_visible_line);
+ int sbar_length = visible_lines * visible_lines / sw->total_lines;
+ int highend = visible_lines * sw->first_visible_line / sw->total_lines;
int sbar_top = highend + sw->pad.y + 1;
if ((sbar_top + sbar_length) > sw->win.h - 1)
@@ -637,7 +636,7 @@ void wins_status_bar(void)
struct binding help = { _("Help"), KEY_GENERIC_HELP };
struct binding quit = { _("Quit"), KEY_GENERIC_QUIT };
struct binding save = { _("Save"), KEY_GENERIC_SAVE };
- struct binding cut = { _("Cut"), KEY_GENERIC_CUT };
+ struct binding copy = { _("Copy"), KEY_GENERIC_COPY };
struct binding paste = { _("Paste"), KEY_GENERIC_PASTE };
struct binding chgvu = { _("Chg Win"), KEY_GENERIC_CHANGE_VIEW };
struct binding import = { _("Import"), KEY_GENERIC_IMPORT };
@@ -688,7 +687,7 @@ void wins_status_bar(void)
&help, &quit, &save, &chgvu, &import, &export, &add, &del, &edit, &view,
&pipe, &draw, &rept, &flag, &enote, &vnote, &up, &down, &gpday, &gnday,
&gpweek, &gnweek, &gpmonth, &gnmonth, &gpyear, &gnyear, &togo, &today,
- &conf, &appt, &todo, &cut, &paste
+ &conf, &appt, &todo, &copy, &paste
};
struct binding *bindings_todo[] = {
diff --git a/test/Makefile.am b/test/Makefile.am
index 85c8a1d..354a46e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,7 +15,8 @@ TESTS = \
range-003.sh \
appointment-001.sh \
next-001.sh \
- search-001.sh
+ search-001.sh \
+ bug-002.sh
TESTS_ENVIRONMENT = \
CALCURSE='$(top_builddir)/src/calcurse' \
diff --git a/test/bug-002.sh b/test/bug-002.sh
new file mode 100755
index 0000000..4784b59
--- /dev/null
+++ b/test/bug-002.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-bug-002" \
+ -d05/03/2012
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+05/03/12:
+ - 10:45 -> 12:45
+ Quantum Mechanics
+ - 18:30 -> 21:30
+ German Class
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/data/apts b/test/data/apts
index 33de89b..c21bf24 100644
--- a/test/data/apts
+++ b/test/data/apts
@@ -658,3 +658,144 @@
04/27/2032 [1] Cringing Osborne
05/26/2032 [1] Confine lames
08/03/2032 [1] Ceremonial straw's antelope's Mercer Kathiawar's
+01/01/1902 [1] Swastikas seeking
+01/01/1902 [1] Elongate wallpaper's midterms classify
+01/01/1902 [1] Seedy locoweed persecutor
+01/01/1902 [1] Acidifies flack's evaporating
+01/01/1902 [1] Aniakchak Pantagruel
+01/01/1902 [1] Imperishables
+01/01/1902 [1] Stuff hysteresis
+01/01/1902 [1] Area
+01/01/1902 [1] Brandished eyrie cloying emcees
+01/01/1902 [1] Exceptionable
+01/01/1902 [1] Acanthi kinked hardtack's mumps
+01/01/1902 [1] Cesspool's murdered cod's Washingtonians
+01/01/1902 [1] Snow
+01/01/1902 [1] Kibitz subcontinent hogwash's displaying quarto
+01/01/1902 [1] Mischievousness's species adultery's petrochemicals Remus
+01/01/1902 [1] Insecure Taiyuan Chungking's Tm's
+01/01/1902 [1] Minuscules pompadours fourfold incognito
+01/01/1902 [1] Geography's Delaney's
+01/01/1902 [1] Skilled bastardized dormers Buckingham munitions
+01/01/1902 [1] Also
+01/01/1902 [1] Marquis's
+01/01/1902 [1] Malamud's
+01/01/1902 [1] Gilda
+01/01/1902 [1] Roe's apace disinfectants metered spinals
+01/01/1902 [1] Locals goutiest Gomulka's
+01/01/1902 [1] Surgery's apple covertly
+01/01/1902 [1] Shantung Earlene pillage leer complainant's
+01/01/1902 [1] Bach's
+01/01/1902 [1] Luisa's Chimborazo's shuffleboard's
+01/01/1902 [1] Tiffed Garcia Elton's
+01/01/1902 [1] Peculiarities Jewishnesses attenuate
+01/01/1902 [1] Wallpapered tampers Dhaka transgression's alohas
+01/01/1902 [1] Roam psycho's
+01/01/1902 [1] Automobiles beguiles
+01/01/1902 [1] Dumfounds medial lark's
+01/01/1902 [1] Haggler's ablative safeguard
+01/01/1902 [1] Broomsticks
+01/01/1902 [1] Therapist cooker's flutes He's
+01/01/1902 [1] Bonny strode Pasteur's inconsequentially Gamble's
+01/01/1902 [1] Corporate
+01/01/1902 [1] Lina's
+01/01/1902 [1] Kodachrome wicks callus's Genaro's
+01/01/1902 [1] Brokers horsefly repudiating knob
+01/01/1902 [1] Reflecting championing stringent Talmudic
+01/01/1902 [1] Noncommercial employes
+01/01/1902 [1] Competitively
+01/01/1902 [1] Garish duplicator edible battery's mock
+01/01/1902 [1] Flocks subornation's trawlers naming's
+01/01/1902 [1] Gruffness Gethsemane
+01/01/1902 [1] Absalom humankind editorship
+01/01/1902 [1] Ampule's Orinoco's nontransferable misspends
+01/01/1902 [1] Each Moselle's discussants flashlight's
+01/01/1902 [1] Electron's reproaches picker grayer
+01/01/1902 [1] Armrests Jamestown's nuke's motif undertaker
+01/01/1902 [1] Navigation's
+01/01/1902 [1] Pearl's Morin telescopes Emanuel's
+01/01/1902 [1] Mutating postnatal Tate familiarize discomfort
+01/01/1902 [1] Offsets debits
+01/01/1902 [1] Institutes's Canton susceptibility's hankie's
+01/01/1902 [1] Haleakala's Goldie's Set
+01/01/1902 [1] Hypocrite's bridal populars
+01/01/1902 [1] Lankiness
+01/01/1902 [1] Rinds weekdays
+01/01/1902 [1] Win hydrangea's display pelvic yukking
+01/01/1902 [1] Homer's strafes
+01/01/1902 [1] Rigor's sociopaths bashing outwore catalepsy
+01/01/1902 [1] Montaigne loophole
+01/01/1902 @ 00:01 -> 01/02/1902 @ 09:18 |Calibrator's
+01/01/1902 @ 05:03 -> 01/06/1902 @ 02:46 |Refresh prepackaged wieners
+01/01/1902 @ 01:58 -> 01/06/1902 @ 07:39 |Strontium's
+01/01/1902 @ 06:11 -> 01/01/1902 @ 10:15 |Abets reject pullbacks finaglers unroll
+01/01/1902 @ 02:55 -> 01/01/1902 @ 17:43 |Monterrey apprehensive Lonnie's
+01/01/1902 @ 03:19 -> 01/03/1902 @ 16:25 |Gill machination geranium's fathomless extraordinary
+01/01/1902 @ 06:15 -> 01/02/1902 @ 06:07 |Protruded vanguard
+01/01/1902 @ 02:31 -> 01/01/1902 @ 13:18 |Expo
+01/01/1902 @ 06:11 -> 01/05/1902 @ 10:50 |Placebos hugeness flailing ironing's
+01/01/1902 @ 07:40 -> 01/02/1902 @ 23:52 |Septembers astuter Jarvis caliper
+01/01/1902 @ 06:51 -> 01/05/1902 @ 07:33 |Asthma
+01/01/1902 @ 09:01 -> 01/04/1902 @ 14:26 |Monograph's
+01/01/1902 @ 00:37 -> 01/01/1902 @ 00:53 |Portal's Leach's Sara Asiatic Holly
+01/01/1902 @ 02:05 -> 01/02/1902 @ 00:41 |Yesteryear's
+01/01/1902 @ 06:52 -> 01/05/1902 @ 13:44 |Colluding steamrolled
+01/01/1902 @ 06:28 -> 01/06/1902 @ 07:57 |Incubuses flat prison Ryukyu's
+01/01/1902 @ 06:04 -> 01/02/1902 @ 09:50 |Synods
+01/01/1902 @ 05:17 -> 01/01/1902 @ 20:13 |Eucalyptus's Araby
+01/01/1902 @ 04:12 -> 01/02/1902 @ 11:28 |Superstitious
+01/01/1902 @ 03:07 -> 01/02/1902 @ 14:53 |Chanted pumice's scalding prier
+01/01/1902 @ 01:26 -> 01/05/1902 @ 11:35 |Beethoven materialism signposting bucktoothed
+01/01/1902 @ 05:31 -> 01/02/1902 @ 11:34 |Isolated affair ritual's Hanukkahs Riel
+01/01/1902 @ 03:26 -> 01/02/1902 @ 15:16 |Supernumeraries incontrovertibly embolden iterate
+01/01/1902 @ 07:17 -> 01/05/1902 @ 00:07 |Federals spanner
+01/01/1902 @ 07:02 -> 01/03/1902 @ 22:41 |Unzipped earthing alleyways bankers
+01/01/1902 @ 08:24 -> 01/03/1902 @ 20:18 |Diesel ferrules Valkyrie's
+01/01/1902 @ 03:32 -> 01/01/1902 @ 04:06 |Winch
+01/01/1902 @ 09:01 -> 01/04/1902 @ 09:21 |Smartens promulgates uncharted McIntosh's
+01/01/1902 @ 00:59 -> 01/05/1902 @ 04:39 |Ho Nikolayev succumbing observances
+01/01/1902 @ 07:03 -> 01/02/1902 @ 11:52 |Kiwanis's Iceland
+01/01/1902 @ 08:13 -> 01/03/1902 @ 07:30 |Bawdily anviled crayfishes neuters
+01/01/1902 @ 01:46 -> 01/01/1902 @ 18:09 |Blenheim
+01/01/1902 @ 01:02 -> 01/04/1902 @ 12:06 |Posse overspreads psalm lamebrain's primps
+01/01/1902 @ 02:16 -> 01/04/1902 @ 13:18 |Sass organism's horses Melanesian
+01/01/1902 @ 09:01 -> 01/03/1902 @ 04:00 |Commons's
+01/01/1902 @ 06:16 -> 01/05/1902 @ 05:33 |Bungle head radiation's
+01/01/1902 @ 03:31 -> 01/03/1902 @ 05:20 |Psycho's
+01/01/1902 @ 06:58 -> 01/03/1902 @ 02:04 |Nomadic Gewürztraminer overrules
+01/01/1902 @ 07:25 -> 01/02/1902 @ 11:22 |Crematory amorphousness
+01/01/1902 @ 08:18 -> 01/04/1902 @ 11:42 |Charity's
+01/01/1902 @ 05:19 -> 01/04/1902 @ 22:02 |Fronde petrochemical's capitalistic
+01/01/1902 @ 02:09 -> 01/02/1902 @ 14:02 |Concurs windowed
+01/01/1902 @ 03:20 -> 01/03/1902 @ 10:01 |Condillac
+01/01/1902 @ 04:28 -> 01/02/1902 @ 09:33 |Carrie cued melodramatics
+01/01/1902 @ 06:55 -> 01/02/1902 @ 03:06 |Ferocity
+01/01/1902 @ 08:42 -> 01/01/1902 @ 20:57 |Simenon Kojak amening plagiarist
+01/01/1902 @ 08:30 -> 01/05/1902 @ 02:27 |Marshall
+01/01/1902 @ 05:38 -> 01/03/1902 @ 22:47 |Hokkaido's diseases
+01/01/1902 @ 07:21 -> 01/02/1902 @ 04:40 |Senility's
+01/01/1902 @ 03:29 -> 01/03/1902 @ 23:54 |Albumin altimeters Senghor's
+01/01/1902 @ 04:46 -> 01/03/1902 @ 12:02 |Lynnette Zane kimono's backlash
+01/01/1902 @ 05:32 -> 01/04/1902 @ 23:07 |Interfaced Hepplewhite slipped
+01/01/1902 @ 07:28 -> 01/02/1902 @ 19:34 |Discretion bauble varsity's
+01/01/1902 @ 06:18 -> 01/05/1902 @ 02:47 |Damned
+01/01/1902 @ 01:43 -> 01/04/1902 @ 22:12 |Doting
+01/01/1902 @ 03:23 -> 01/03/1902 @ 12:31 |Access Yang bethinks vectored broad
+01/01/1902 @ 02:50 -> 01/03/1902 @ 20:32 |Tasseled
+01/01/1902 @ 06:52 -> 01/03/1902 @ 10:06 |Ventriloquist's indisputable squats Fenian's slowdown's
+01/01/1902 @ 06:31 -> 01/04/1902 @ 21:25 |Learning
+01/01/1902 @ 00:44 -> 01/01/1902 @ 14:29 |Blondes Sasquatch cablecasted
+01/01/1902 @ 06:16 -> 01/04/1902 @ 20:13 |Papillae hairpin ailerons
+01/01/1902 @ 00:22 -> 01/02/1902 @ 11:54 |Menses enrichment afloat failed incorruptible
+01/01/1902 @ 08:13 -> 01/01/1902 @ 17:50 |Motown's factors disappearing
+01/01/1902 @ 08:40 -> 01/06/1902 @ 04:00 |Observable parleys industrialization Cambrian boxwood's
+01/01/1902 @ 04:56 -> 01/03/1902 @ 00:14 |Summer Mujib humbles fatherless foretelling
+01/01/1902 @ 00:08 -> 01/02/1902 @ 20:46 |Binnacles
+01/01/1902 @ 04:38 -> 01/03/1902 @ 00:50 |Packard's
+01/01/1902 @ 08:49 -> 01/03/1902 @ 12:10 |Hypnotist reappraisal rehiring Castaneda
+01/01/1902 @ 02:26 -> 01/06/1902 @ 03:30 |Jataka backwards
+01/01/1902 @ 00:07 -> 01/05/1902 @ 01:15 |Zeno Goldberg's Iberia's truants coiffured
+01/01/1902 @ 00:59 -> 01/04/1902 @ 19:16 |Lounges
+01/01/1902 @ 00:05 -> 01/03/1902 @ 13:11 |Heisenberg Jewries hookier misfortunes auspiciousness
+01/01/1902 @ 08:02 -> 01/01/1902 @ 11:59 |District
+01/01/1902 @ 02:54 -> 01/05/1902 @ 06:18 |Grin menstruation's
diff --git a/test/data/apts-bug-002 b/test/data/apts-bug-002
new file mode 100644
index 0000000..6ced520
--- /dev/null
+++ b/test/data/apts-bug-002
@@ -0,0 +1,2 @@
+03/22/2012 @ 18:30 -> 03/22/2012 @ 21:30 {1W -> 06/21/2012} |German Class
+04/19/2012 @ 10:45 -> 04/19/2012 @ 12:45 {1W -> 05/06/2012} |Quantum Mechanics