aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README18
-rwxr-xr-xautogen.sh156
-rw-r--r--configure.ac5
-rw-r--r--doc/calcurse.1.txt11
-rw-r--r--doc/manual.txt26
-rw-r--r--po/Makevars41
-rw-r--r--po/POTFILES.in1
-rw-r--r--po/calcurse.pot380
-rw-r--r--src/Makefile.am1
-rw-r--r--src/apoint.c327
-rw-r--r--src/args.c206
-rw-r--r--src/calcurse.c819
-rw-r--r--src/calcurse.h178
-rw-r--r--src/calendar.c38
-rw-r--r--src/config.c31
-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.c209
-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.c171
-rw-r--r--src/utils.c24
-rw-r--r--src/vars.c2
-rw-r--r--src/wins.c130
-rw-r--r--test/Makefile.am8
-rwxr-xr-xtest/bug-002.sh16
-rw-r--r--test/data/apts141
-rw-r--r--test/data/apts-bug-0022
-rw-r--r--test/data/apts-recur12
-rwxr-xr-xtest/recur-001.sh50
-rwxr-xr-xtest/recur-002.sh14
-rwxr-xr-xtest/recur-003.sh17
-rwxr-xr-xtest/recur-004.sh18
-rwxr-xr-xtest/recur-005.sh18
-rw-r--r--test/run-test.c3
42 files changed, 2844 insertions, 2740 deletions
diff --git a/.gitignore b/.gitignore
index d298069..380478a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@ ABOUT-NLS
Makefile
Makefile.in
Makefile.in.in
-Makevars
aclocal.m4
configure
depcomp
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..2d68a81 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,9 @@
# (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"
+autopoint --force
+aclocal -I m4
+autoheader
+automake --foreign --copy --add-missing
+autoconf
diff --git a/configure.ac b/configure.ac
index 33b72ca..e32b027 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,7 @@ AC_INIT([calcurse],
AM_INIT_AUTOMAKE
#m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION([0.14.1])
AC_CONFIG_SRCDIR([src/calcurse.c])
AC_CONFIG_HEADER([config.h])
#-------------------------------------------------------------------------------
@@ -139,10 +140,6 @@ AC_MSG_CHECKING([if memory debug should be used])
AC_MSG_RESULT($memdebug)
AM_CONDITIONAL(CALCURSE_MEMORY_DEBUG, test x$memdebug = xyes)
#-------------------------------------------------------------------------------
-# xgettext options
-#-------------------------------------------------------------------------------
-AM_XGETTEXT_OPTION([--no-location --keyword=_ --keyword=N_])
-#-------------------------------------------------------------------------------
# Create Makefiles
#-------------------------------------------------------------------------------
AC_OUTPUT(Makefile doc/Makefile src/Makefile test/Makefile scripts/Makefile \
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/Makevars b/po/Makevars
new file mode 100644
index 0000000..9f5b66a
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --no-location --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
+# package. (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.) Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright. The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = calcurse Development Team <misc@calcurse.org>
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+# in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+# understood.
+# - Strings which make invalid assumptions about notation of date, time or
+# money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS = bugs@calcurse.org
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used. It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
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/po/calcurse.pot b/po/calcurse.pot
index ec032a0..e97e741 100644
--- a/po/calcurse.pot
+++ b/po/calcurse.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: calcurse 3.0.0\n"
"Report-Msgid-Bugs-To: bugs@calcurse.org\n"
-"POT-Creation-Date: 2012-06-24 01:09+0200\n"
+"POT-Creation-Date: 2012-11-23 22:49+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -21,46 +21,16 @@ msgstr ""
msgid "null pointer"
msgstr ""
-msgid "Enter start time ([hh:mm]), leave blank for an all-day event : "
-msgstr ""
-
-msgid ""
-"Enter end time ([hh:mm]) or duration ([+hh:mm], [+xxxdxxhxxm] or [+mm]) : "
-msgstr ""
-
-msgid "Enter description :"
-msgstr ""
-
-msgid "You entered an invalid start time, should be [hh:mm]"
-msgstr ""
-
-msgid ""
-"Invalid end time/duration, should be [hh:mm], [+hh:mm], [+xxxdxxhxxm] or "
-"[+mm]"
-msgstr ""
-
-msgid "Press [Enter] to continue"
-msgstr ""
-
-msgid "Do you really want to delete this item ?"
-msgstr ""
-
-msgid "no such type"
-msgstr ""
-
msgid "date error in appointment"
msgstr ""
-msgid "item not found"
-msgstr ""
-
msgid "no such appointment"
msgstr ""
msgid ""
"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"
msgstr ""
@@ -105,10 +75,10 @@ msgid ""
"\n"
"Files:\n"
" -c <file>, --calendar <file>\n"
-"\tspecify the calendar <file> to use (incompatible with '-D').\n"
+"\tspecify the calendar <file> to use (has precedence over '-D').\n"
"\n"
" -D <dir>, --directory <dir>\n"
-"\tspecify the data directory to use (incompatible with '-c').\n"
+"\tspecify the data directory to use.\n"
"\tIf not specified, the default directory is ~/.calcurse\n"
"\n"
"Non-interactive:\n"
@@ -212,15 +182,18 @@ msgstr ""
msgid "Argument for '-x' should be either 'ical' or 'pcal'\n"
msgstr ""
-msgid "Options '-D' and '-c' cannot be used at the same time\n"
-msgstr ""
-
msgid "Option '-S' must be used with either '-d', '-r', '-s', '-a' or '-t'\n"
msgstr ""
msgid "To do :"
msgstr ""
+msgid "Export to (i)cal or (p)cal format?"
+msgstr ""
+
+msgid "[ip]"
+msgstr ""
+
msgid "Do you really want to quit ?"
msgstr ""
@@ -447,104 +420,18 @@ msgid ""
"(Press [ENTER] to continue)"
msgstr ""
-msgid "Event :"
-msgstr ""
-
-msgid "Appointment :"
-msgstr ""
-
msgid "unknown item type"
msgstr ""
-msgid "Enter the new time ([hh:mm]) : "
-msgstr ""
-
-msgid "You entered an invalid time, should be [hh:mm]"
-msgstr ""
-
-msgid ""
-"Enter new end time ([hh:mm]) or duration ([+hh:mm], [+xxxdxxhxxm] or "
-"[+mm]) : "
-msgstr ""
-
-msgid "Invalid time: start time must be before end time!"
-msgstr ""
-
-msgid "Enter the new item description:"
-msgstr ""
-
-msgid "Enter the new repetition type:"
-msgstr ""
-
-msgid "(d)aily"
-msgstr ""
-
-msgid "(w)eekly"
-msgstr ""
-
-msgid "(m)onthly"
-msgstr ""
-
-msgid "(y)early"
-msgstr ""
-
-#, c-format
-msgid "(currently using %s)"
-msgstr ""
-
-msgid "[dwmy]"
-msgstr ""
-
-msgid "The frequence you entered is not valid."
-msgstr ""
-
-msgid "The entered date is not valid."
-msgstr ""
-
-#, c-format
-msgid "Possible formats are [%s] or '0' for an endless repetition."
-msgstr ""
-
-msgid "Enter the new repetition frequence:"
-msgstr ""
-
-#, c-format
-msgid "Enter the new ending date: [%s] or '0'"
-msgstr ""
-
-msgid "Description"
-msgstr ""
-
-msgid "Repetition"
-msgstr ""
-
-msgid "Edit: "
-msgstr ""
-
-msgid "Start time"
-msgstr ""
-
-msgid "End time"
-msgstr ""
-
-msgid "This item is recurrent. Delete (a)ll occurences or just this (o)ne ?"
-msgstr ""
-
-msgid "[ao]"
-msgstr ""
-
-msgid "This item has a note attached to it. Delete (i)tem or just its (n)ote ?"
+msgid "Event :"
msgstr ""
-msgid "[in]"
+msgid "Appointment :"
msgstr ""
msgid "unknwon type"
msgstr ""
-msgid "Pipe item to external command:"
-msgstr ""
-
#, c-format
msgid "Could not stop daemon properly: %s\n"
msgstr ""
@@ -610,9 +497,6 @@ msgstr ""
msgid "date error in the event\n"
msgstr ""
-msgid "event not found"
-msgstr ""
-
msgid "Internal error: line too long"
msgstr ""
@@ -872,23 +756,19 @@ msgid ""
" event next time you launch Calcurse."
msgstr ""
-msgid "Cut and Paste\n"
+msgid "Copy and Paste\n"
msgstr ""
#, c-format
msgid ""
-"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"
+"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"
-"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."
msgstr ""
msgid "Edit Item\n"
@@ -1182,6 +1062,165 @@ msgstr ""
msgid "Warning: ical header malformed or wrong version number. Aborting..."
msgstr ""
+msgid "Enter the new time ([hh:mm] or [hhmm]) : "
+msgstr ""
+
+msgid "Press [Enter] to continue"
+msgstr ""
+
+msgid "You entered an invalid time, should be [hh:mm] or [hhmm]"
+msgstr ""
+
+msgid ""
+"Enter new end time ([hh:mm], [hhmm]) or duration ([+hh:mm], [+xxxdxxhxxm] or "
+"[+mm]) : "
+msgstr ""
+
+msgid "Invalid time: start time must be before end time!"
+msgstr ""
+
+msgid "Enter the new item description:"
+msgstr ""
+
+msgid "Enter the new repetition type:"
+msgstr ""
+
+msgid "(d)aily"
+msgstr ""
+
+msgid "(w)eekly"
+msgstr ""
+
+msgid "(m)onthly"
+msgstr ""
+
+msgid "(y)early"
+msgstr ""
+
+#, c-format
+msgid "(currently using %s)"
+msgstr ""
+
+msgid "[dwmy]"
+msgstr ""
+
+msgid "The frequence you entered is not valid."
+msgstr ""
+
+msgid "The entered date is not valid."
+msgstr ""
+
+#, c-format
+msgid "Possible formats are [%s] or '0' for an endless repetition."
+msgstr ""
+
+msgid "Enter the new repetition frequence:"
+msgstr ""
+
+#, c-format
+msgid "Enter the new ending date: [%s] or '0'"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Repetition"
+msgstr ""
+
+msgid "Edit: "
+msgstr ""
+
+msgid "Start time"
+msgstr ""
+
+msgid "End time"
+msgstr ""
+
+msgid "Pipe item to external command:"
+msgstr ""
+
+msgid ""
+"Enter start time ([hh:mm] or [hhmm]), leave blank for an all-day event : "
+msgstr ""
+
+msgid ""
+"Enter end time ([hh:mm] or [hhmm]) or duration ([+hh:mm], [+xxxdxxhxxm] or "
+"[+mm]) : "
+msgstr ""
+
+msgid "Enter description :"
+msgstr ""
+
+msgid "You entered an invalid start time, should be [hh:mm] or [hhmm]"
+msgstr ""
+
+msgid ""
+"Invalid end time/duration, should be [hh:mm], [hhmm], [+hh:mm], "
+"[+xxxdxxhxxm] or [+mm]"
+msgstr ""
+
+msgid "Do you really want to delete this item ?"
+msgstr ""
+
+msgid "This item is recurrent. Delete (a)ll occurences or just this (o)ne ?"
+msgstr ""
+
+msgid "[ao]"
+msgstr ""
+
+msgid "This item has a note attached to it. Delete (i)tem or just its (n)ote ?"
+msgstr ""
+
+msgid "[in]"
+msgstr ""
+
+msgid "no such type"
+msgstr ""
+
+msgid "Enter the new ToDo item : "
+msgstr ""
+
+msgid "Enter the ToDo priority [1 (highest) - 9 (lowest)] :"
+msgstr ""
+
+msgid "Do you really want to delete this task ?"
+msgstr ""
+
+msgid "This item has a note attached to it. Delete (t)odo or just its (n)ote ?"
+msgstr ""
+
+msgid "[tn]"
+msgstr ""
+
+msgid "Enter the new ToDo description :"
+msgstr ""
+
+msgid "Enter the repetition type:"
+msgstr ""
+
+msgid "Enter the repetition frequence:"
+msgstr ""
+
+#, c-format
+msgid "Enter the ending date: [%s] or '0' for an endless repetition"
+msgstr ""
+
+#, c-format
+msgid "Possible formats are [%s] or '0' for an endless repetition"
+msgstr ""
+
+msgid "This item is already a repeated one."
+msgstr ""
+
+msgid "Press [ENTER] to continue."
+msgstr ""
+
+msgid "Sorry, the date you entered is older than the item start time."
+msgstr ""
+
+msgid "wrong item type"
+msgstr ""
+
msgid "Saving..."
msgstr ""
@@ -1200,9 +1239,6 @@ msgstr ""
msgid "The file cannot be accessed, please enter another file name."
msgstr ""
-msgid "Press [ENTER] to continue."
-msgstr ""
-
#, c-format
msgid "Failed to open \"%s\", - %s\n"
msgstr ""
@@ -1311,12 +1347,6 @@ msgstr ""
msgid "wrong export mode"
msgstr ""
-msgid "Ical"
-msgstr ""
-
-msgid "Pcal"
-msgstr ""
-
msgid "Enter the file name to import data from:"
msgstr ""
@@ -1432,7 +1462,7 @@ msgstr ""
msgid "Save calcurse data."
msgstr ""
-msgid "Cut the item that is currently selected."
+msgid "Copy the item that is currently selected."
msgstr ""
msgid "Paste an item at the current position."
@@ -1709,30 +1739,10 @@ msgstr ""
msgid "date error in event"
msgstr ""
-msgid "appointment not found"
-msgstr ""
-
-msgid "Enter the repetition type:"
-msgstr ""
-
-msgid "Enter the repetition frequence:"
-msgstr ""
-
-#, c-format
-msgid "Enter the ending date: [%s] or '0' for an endless repetition"
-msgstr ""
-
-#, c-format
-msgid "Possible formats are [%s] or '0' for an endless repetition"
-msgstr ""
-
-msgid "This item is already a repeated one."
-msgstr ""
-
-msgid "Sorry, the date you entered is older than the item start time."
+msgid "event not found"
msgstr ""
-msgid "wrong item type"
+msgid "appointment not found"
msgstr ""
msgid "syntax error in item date"
@@ -1746,36 +1756,15 @@ msgstr ""
msgid "Error setting signal #%d : %s\n"
msgstr ""
-msgid "Enter the new ToDo item : "
-msgstr ""
-
-msgid "Enter the ToDo priority [1 (highest) - 9 (lowest)] :"
-msgstr ""
-
-msgid "no such todo"
-msgstr ""
-
msgid "no note attached"
msgstr ""
-msgid "Do you really want to delete this task ?"
-msgstr ""
-
-msgid "This item has a note attached to it. Delete (t)odo or just its (n)ote ?"
-msgstr ""
-
-msgid "[tn]"
+msgid "no such todo"
msgstr ""
msgid "todo not found"
msgstr ""
-msgid "no such action"
-msgstr ""
-
-msgid "Enter the new ToDo description :"
-msgstr ""
-
msgid "/!\\ INTERNAL ERROR /!\\"
msgstr ""
@@ -1794,9 +1783,6 @@ msgstr ""
msgid "error in mktime"
msgstr ""
-msgid "Appointment"
-msgstr ""
-
msgid "could not convert string"
msgstr ""
@@ -1907,7 +1893,7 @@ msgstr ""
msgid "Save"
msgstr ""
-msgid "Cut"
+msgid "Copy"
msgstr ""
msgid "Paste"
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..9b9257f 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);
}
@@ -581,7 +332,7 @@ void apoint_update_panel(int which_pan)
{
int title_xpos;
int bordr = 1;
- int title_lines = 3;
+ int title_lines = conf.compact_panels ? 1 : 3;
int app_width = win[APP].w - bordr;
int app_length = win[APP].h - bordr - title_lines;
long date;
@@ -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..85c91cb 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"
@@ -270,11 +269,9 @@ static void next_arg(void)
static void arg_print_date(long date)
{
char date_str[BUFSIZ];
- time_t t;
struct tm lt;
- t = date;
- localtime_r(&t, &lt);
+ localtime_r((time_t *)&date, &lt);
strftime(date_str, BUFSIZ, conf.output_datefmt, &lt);
fputs(date_str, stdout);
fputs(":\n", stdout);
@@ -289,123 +286,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;
}
/*
@@ -443,10 +338,7 @@ date_arg(const char *ddate, int add_line, const char *fmt_apt,
const char *fmt_rapt, const char *fmt_ev, const char *fmt_rev,
regex_t * regex)
{
- int i;
struct date day;
- int numdays = 0, num_digit = 0;
- int arg_len = 0;
static struct tm t;
time_t timer;
@@ -454,25 +346,18 @@ date_arg(const char *ddate, int add_line, const char *fmt_apt,
* Check (with the argument length) if a date or a number of days
* was entered, and then call app_arg() to print appointments
*/
- arg_len = strlen(ddate);
- if (arg_len <= 4) { /* a number of days was entered */
- for (i = 0; i <= arg_len - 1; i++) {
- if (isdigit(ddate[i]))
- num_digit++;
- }
- if (num_digit == arg_len)
- numdays = atoi(ddate);
-
+ if (strlen(ddate) <= 4 && is_all_digit(ddate)) {
/*
- * Get current date, and print appointments for each day
- * in the chosen interval. app_found and add_line are used
- * to format the output correctly.
+ * A number of days was entered. Get current date and print appointments
+ * for each day in the chosen interval. app_found and add_line are used to
+ * format the output correctly.
*/
timer = time(NULL);
localtime_r(&timer, &t);
- display_app(&t, numdays, add_line, fmt_apt, fmt_rapt, fmt_ev, fmt_rev,
+ display_app(&t, atoi(ddate), add_line, fmt_apt, fmt_rapt, fmt_ev, fmt_rev,
regex);
- } else { /* a date was entered */
+ } else {
+ /* A date was entered. */
if (parse_date(ddate, conf.input_datefmt, (int *)&day.yyyy,
(int *)&day.mm, (int *)&day.dd, NULL)) {
app_arg(add_line, &day, 0, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, regex);
@@ -498,7 +383,7 @@ date_arg_extended(const char *startday, const char *range, int add_line,
const char *fmt_apt, const char *fmt_rapt,
const char *fmt_ev, const char *fmt_rev, regex_t * regex)
{
- int i, numdays = 1, error = 0, arg_len = 0;
+ int numdays = 1, error = 0;
static struct tm t;
time_t timer;
@@ -506,13 +391,11 @@ date_arg_extended(const char *startday, const char *range, int add_line,
* Check arguments and extract information
*/
if (range != NULL) {
- arg_len = strlen(range);
- for (i = 0; i <= arg_len - 1; i++) {
- if (!isdigit(range[i]))
- error = 1;
- }
- if (!error)
+ if (is_all_digit(range)) {
numdays = atoi(range);
+ } else {
+ error = 1;
+ }
}
timer = time(NULL);
localtime_r(&timer, &t);
@@ -548,9 +431,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 +500,6 @@ int parse_args(int argc, char **argv)
load_data++;
break;
case 'c':
- cflag = 1;
multiple_flag++;
cfile = optarg;
load_data++;
@@ -631,7 +511,6 @@ int parse_args(int argc, char **argv)
ddate = optarg;
break;
case 'D':
- Dflag = 1;
datadir = optarg;
break;
case 'h':
@@ -741,11 +620,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);
@@ -767,10 +641,10 @@ int parse_args(int argc, char **argv)
non_interactive = 1;
} else if (gflag) {
io_init(cfile, datadir);
- io_check_dir(path_dir, NULL);
- io_check_dir(path_notes, NULL);
- io_check_file(path_apts, NULL);
- io_check_file(path_todo, NULL);
+ io_check_dir(path_dir);
+ io_check_dir(path_notes);
+ io_check_file(path_apts);
+ io_check_file(path_todo);
io_load_app();
io_load_todo();
note_gc();
@@ -778,12 +652,12 @@ int parse_args(int argc, char **argv)
} else if (multiple_flag) {
if (load_data) {
io_init(cfile, datadir);
- io_check_dir(path_dir, NULL);
- io_check_dir(path_notes, NULL);
+ io_check_dir(path_dir);
+ io_check_dir(path_notes);
}
if (iflag) {
- io_check_file(path_apts, NULL);
- io_check_file(path_todo, NULL);
+ io_check_file(path_apts);
+ io_check_file(path_todo);
/* Get default pager in case we need to show a log file. */
vars_init();
io_load_app();
@@ -794,8 +668,8 @@ int parse_args(int argc, char **argv)
non_interactive = 1;
}
if (xflag) {
- io_check_file(path_apts, NULL);
- io_check_file(path_todo, NULL);
+ io_check_file(path_apts);
+ io_check_file(path_todo);
io_load_app();
io_load_todo();
io_export_data(xfmt);
@@ -803,20 +677,20 @@ int parse_args(int argc, char **argv)
return non_interactive;
}
if (tflag) {
- io_check_file(path_todo, NULL);
+ io_check_file(path_todo);
io_load_todo();
todo_arg(tnum, fmt_todo, preg);
non_interactive = 1;
}
if (nflag) {
- io_check_file(path_apts, NULL);
+ io_check_file(path_apts);
io_load_app();
next_arg();
non_interactive = 1;
}
if (dflag || rflag || sflag) {
- io_check_file(path_apts, NULL);
- io_check_file(path_conf, NULL);
+ io_check_file(path_apts);
+ io_check_file(path_conf);
io_load_app();
config_load(); /* To get output date format. */
if (dflag)
@@ -828,8 +702,8 @@ int parse_args(int argc, char **argv)
} else if (aflag) {
struct date day;
- io_check_file(path_apts, NULL);
- io_check_file(path_conf, NULL);
+ io_check_file(path_apts);
+ io_check_file(path_conf);
vars_init();
config_load(); /* To get output date format. */
io_load_app();
diff --git a/src/calcurse.c b/src/calcurse.c
index 09baab5..c55db55 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, "");
@@ -135,7 +549,8 @@ int main(int argc, char **argv)
vars_init();
wins_init();
- wins_slctd_init();
+ /* Default to the calendar panel -- this is overridden later. */
+ wins_slctd_set(CAL);
notify_init_bar();
wins_reset_status_page();
@@ -155,7 +570,7 @@ int main(int argc, char **argv)
io_startup_screen(no_data_file);
}
inday = *day_process_storage(0, 0, &inday);
- wins_slctd_set(CAL);
+ wins_slctd_set(conf.default_panel);
wins_update(FLAG_ALL);
/* Start miscellaneous threads. */
@@ -174,363 +589,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 2992db8..093b9af 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,8 +144,10 @@
#define DAYINSEC (DAYINMIN * MININSEC)
#define HOURINSEC (HOURINMIN * MININSEC)
+#define MAXDAYSPERMONTH 31
+
/* Calendar window. */
-#define CALHEIGHT 12
+#define CALHEIGHT 8
/* Key definitions. */
#define CTRLVAL 0x1F
@@ -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
@@ -227,6 +233,15 @@
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
+enum win {
+ CAL,
+ APP,
+ TOD,
+ NOT,
+ STA,
+ NBWINS
+};
+
/* General configuration variables. */
struct conf {
unsigned auto_save;
@@ -234,6 +249,8 @@ struct conf {
unsigned periodic_save;
unsigned confirm_quit;
unsigned confirm_delete;
+ enum win default_panel;
+ unsigned compact_panels;
unsigned system_dialogs;
unsigned progress_bar;
const char *editor;
@@ -308,18 +325,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 +366,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 +409,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,
@@ -440,15 +460,6 @@ struct binding {
enum key action;
};
-enum win {
- CAL,
- APP,
- TOD,
- NOT,
- STA,
- NBWINS
-};
-
#define FLAG_CAL (1 << CAL)
#define FLAG_APP (1 << APP)
#define FLAG_TOD (1 << TOD)
@@ -526,14 +537,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 +605,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 +614,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 +644,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 +675,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 +705,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 +729,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 *);
@@ -731,13 +754,12 @@ void io_save_cal(enum save_display);
void io_load_app(void);
void io_load_todo(void);
void io_load_keys(const char *);
-void io_check_dir(char *, int *);
-unsigned io_file_exist(char *);
-void io_check_file(char *, int *);
+int io_check_dir(const char *);
+unsigned io_file_exist(const char *);
+int io_check_file(const char *);
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 +779,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 +865,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 +893,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);
@@ -888,6 +913,7 @@ void sigs_unignore(void);
/* 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);
@@ -899,17 +925,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);
@@ -1009,7 +1034,6 @@ unsigned wins_sbar_wperc(void);
void wins_set_sbar_width(unsigned);
void wins_sbar_winc(void);
void wins_sbar_wdec(void);
-void wins_slctd_init(void);
enum win wins_slctd(void);
void wins_slctd_set(enum win);
void wins_slctd_next(void);
diff --git a/src/calendar.c b/src/calendar.c
index df247df..0eebd4e 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,12 +268,17 @@ 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,
unsigned sunday_first)
{
- const int OFFY = 2 + (CALHEIGHT - 9) / 2;
+ const int OFFY = CALHEIGHT / 2 - (conf.compact_panels ? 3 : 1);
struct date check_day;
int c_day, c_day_1, day_1_sav, numdays, j;
unsigned yr, mo;
@@ -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)
@@ -437,7 +460,7 @@ draw_weekly_view(struct window *cwin, struct date *current_day,
{
#define DAYSLICESNO 6
const int WCALWIDTH = 30;
- const int OFFY = 2 + (CALHEIGHT - 9) / 2;
+ const int OFFY = CALHEIGHT / 2 - (conf.compact_panels ? 3 : 1);
struct tm t;
int OFFX, j, c_wday, days_to_remove, weeknum;
@@ -461,7 +484,8 @@ draw_weekly_view(struct window *cwin, struct date *current_day,
weeknum = ISO8601weeknum(&t);
WINS_CALENDAR_LOCK;
custom_apply_attr(cwin->p, ATTR_HIGHEST);
- mvwprintw(cwin->p, 2, cwin->w - 9, "(# %02d)", weeknum);
+ mvwprintw(cwin->p, conf.compact_panels ? 0 : 2, cwin->w - 9, "(# %02d)",
+ weeknum);
custom_remove_attr(cwin->p, ATTR_HIGHEST);
WINS_CALENDAR_UNLOCK;
@@ -555,8 +579,10 @@ void calendar_update_panel(struct window *cwin)
calendar_store_current_date(&current_day);
WINS_CALENDAR_LOCK;
- erase_window_part(cwin->p, 1, 3, cwin->w - 2, cwin->h - 2);
- mvwhline(cwin->p, 2, 1, ACS_HLINE, cwin->w - 2);
+ erase_window_part(cwin->p, 1, conf.compact_panels ? 1 : 3, cwin->w - 2,
+ cwin->h - 2);
+ if (!conf.compact_panels)
+ mvwhline(cwin->p, 2, 1, ACS_HLINE, cwin->w - 2);
WINS_CALENDAR_UNLOCK;
sunday_first = calendar_week_begins_on_monday()? 0 : 1;
diff --git a/src/config.c b/src/config.c
index 06a8124..da562b2 100644
--- a/src/config.c
+++ b/src/config.c
@@ -59,6 +59,8 @@ static int config_parse_str(char *, const char *);
static int config_serialize_str(char *, const char *);
static int config_parse_calendar_view(void *, const char *);
static int config_serialize_calendar_view(char *, void *);
+static int config_parse_default_panel(void *, const char *);
+static int config_serialize_default_panel(char *, void *);
static int config_parse_first_day_of_week(void *, const char *);
static int config_serialize_first_day_of_week(char *, void *);
static int config_parse_color_theme(void *, const char *);
@@ -84,6 +86,9 @@ static int config_serialize_input_datefmt(char *, void *);
static const struct confvar confmap[] = {
{"appearance.calendarview", config_parse_calendar_view,
config_serialize_calendar_view, NULL},
+ {"appearance.compactpanels", CONFIG_HANDLER_BOOL(conf.compact_panels)},
+ {"appearance.defaultpanel", config_parse_default_panel,
+ config_serialize_default_panel, NULL},
{"appearance.layout", config_parse_layout, config_serialize_layout, NULL},
{"appearance.notifybar", CONFIG_HANDLER_BOOL(nbar.show)},
{"appearance.sidebarwidth", config_parse_sidebar_width,
@@ -206,6 +211,20 @@ static int config_parse_calendar_view(void *dummy, const char *val)
return 1;
}
+static int config_parse_default_panel(void *dummy, const char *val)
+{
+ if (!strcmp(val, "calendar"))
+ conf.default_panel = CAL;
+ else if (!strcmp(val, "appointments"))
+ conf.default_panel = APP;
+ else if (!strcmp(val, "todo"))
+ conf.default_panel = TOD;
+ else
+ return 0;
+
+ return 1;
+}
+
static int config_parse_first_day_of_week(void *dummy, const char *val)
{
if (!strcmp(val, "monday"))
@@ -368,6 +387,18 @@ static int config_serialize_calendar_view(char *buf, void *dummy)
return 1;
}
+static int config_serialize_default_panel(char *buf, void *dummy)
+{
+ if (conf.default_panel == CAL)
+ strcpy(buf, "calendar");
+ else if (conf.default_panel == APP)
+ strcpy(buf, "appointments");
+ else
+ strcpy(buf, "todo");
+
+ return 1;
+}
+
static int config_serialize_first_day_of_week(char *buf, void *dummy)
{
if (calendar_week_begins_on_monday())
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 70f1400..df95ccf 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);
@@ -520,7 +635,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);
@@ -543,466 +658,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. */
@@ -1011,117 +716,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..b8fccfd 100644
--- a/src/io.c
+++ b/src/io.c
@@ -151,7 +151,6 @@ static void progress_bar(progress_bar_t type, int progress)
static FILE *get_export_stream(enum export_type type)
{
FILE *stream;
- int cancel;
char *home, *stream_name;
const char *question = _("Choose the file used to export calcurse data:");
const char *wrong_name =
@@ -169,8 +168,7 @@ static FILE *get_export_stream(enum export_type type)
while (stream == NULL) {
status_mesg(question, "");
- cancel = updatestring(win[STA].p, &stream_name, 0, 1);
- if (cancel) {
+ if (updatestring(win[STA].p, &stream_name, 0, 1)) {
mem_free(stream_name);
return NULL;
}
@@ -231,7 +229,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 +246,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__);
}
}
@@ -425,6 +427,12 @@ void io_save_cal(enum save_display display)
pthread_mutex_unlock(&io_save_mutex);
}
+static void io_load_error(const char *filename, unsigned line,
+ const char *mesg)
+{
+ EXIT("%s:%u: %s", filename, line, mesg);
+}
+
/*
* Check what type of data is written in the appointment file,
* and then load either: a new appointment, a new event, or a new
@@ -441,6 +449,7 @@ void io_load_app(void)
int freq;
char type, state = 0L;
char note[MAX_NOTESIZ + 1], *notep;
+ unsigned line = 0;
t = time(NULL);
localtime_r(&t, &lt);
@@ -452,6 +461,7 @@ void io_load_app(void)
for (;;) {
LLIST_INIT(&exc);
is_appointment = is_event = is_recursive = 0;
+ line++;
c = getc(data_file);
if (c == EOF)
break;
@@ -462,7 +472,7 @@ void io_load_app(void)
*/
if (fscanf(data_file, "%d / %d / %d ",
&start.tm_mon, &start.tm_mday, &start.tm_year) != 3)
- EXIT(_("syntax error in the item date"));
+ io_load_error(path_apts, line, _("syntax error in the item date"));
/* Read the next character : if it is an '@' then we have
* an appointment, else if it is an '[' we have en event.
@@ -474,7 +484,7 @@ void io_load_app(void)
else if (c == '[')
is_event = 1;
else
- EXIT(_("no event nor appointment found"));
+ io_load_error(path_apts, line, _("no event nor appointment found"));
/* Read the remaining informations. */
if (is_appointment) {
@@ -482,14 +492,16 @@ void io_load_app(void)
&start.tm_hour, &start.tm_min,
&end.tm_mon, &end.tm_mday, &end.tm_year,
&end.tm_hour, &end.tm_min) != 7)
- EXIT(_("syntax error in item time or duration"));
+ io_load_error(path_apts, line,
+ _("syntax error in item time or duration"));
} else if (is_event) {
if (fscanf(data_file, " %d ", &id) != 1 || getc(data_file) != ']')
- EXIT(_("syntax error in item identifier"));
+ io_load_error(path_apts, line, _("syntax error in item identifier"));
while ((c = getc(data_file)) == ' ') ;
ungetc(c, data_file);
} else {
- EXIT(_("wrong format in the appointment or event"));
+ io_load_error(path_apts, line,
+ _("wrong format in the appointment or event"));
/* NOTREACHED */
}
@@ -499,7 +511,7 @@ void io_load_app(void)
if (c == '{') {
is_recursive = 1;
if (fscanf(data_file, " %d%c ", &freq, &type) != 2)
- EXIT(_("syntax error in item repetition"));
+ io_load_error(path_apts, line, _("syntax error in item repetition"));
c = getc(data_file);
if (c == '}') { /* endless recurrent item */
@@ -509,7 +521,7 @@ void io_load_app(void)
} else if (c == '-' && getc(data_file) == '>') {
if (fscanf(data_file, " %d / %d / %d ", &until.tm_mon,
&until.tm_mday, &until.tm_year) != 3)
- EXIT(_("syntax error in item repetition"));
+ io_load_error(path_apts, line, _("syntax error in item repetition"));
c = getc(data_file);
if (c == '!') {
ungetc(c, data_file);
@@ -519,14 +531,15 @@ void io_load_app(void)
while ((c = getc(data_file)) == ' ') ;
ungetc(c, data_file);
} else
- EXIT(_("syntax error in item repetition"));
+ io_load_error(path_apts, line, _("syntax error in item repetition"));
} else if (c == '!') { /* endless item with exceptions */
ungetc(c, data_file);
recur_exc_scan(&exc, data_file);
c = getc(data_file);
until.tm_year = 0;
} else {
- EXIT(_("wrong format in the appointment or event"));
+ io_load_error(path_apts, line,
+ _("wrong format in the appointment or event"));
/* NOTREACHED */
}
} else
@@ -557,7 +570,7 @@ void io_load_app(void)
while ((c = getc(data_file)) == ' ') ;
ungetc(c, data_file);
} else
- EXIT(_("syntax error in item repetition"));
+ io_load_error(path_apts, line, _("syntax error in item repetition"));
if (is_recursive) {
recur_apoint_scan(data_file, start, end,
type, freq, until, notep, &exc, state);
@@ -571,7 +584,8 @@ void io_load_app(void)
event_scan(data_file, start, id, notep);
}
} else {
- EXIT(_("wrong format in the appointment or event"));
+ io_load_error(path_apts, line,
+ _("wrong format in the appointment or event"));
/* NOTREACHED */
}
}
@@ -586,17 +600,19 @@ void io_load_todo(void)
int nb_tod = 0;
int c, id;
char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1];
+ unsigned line = 0;
data_file = fopen(path_todo, "r");
EXIT_IF(data_file == NULL, _("failed to open todo file"));
for (;;) {
+ line++;
c = getc(data_file);
if (c == EOF)
break;
else if (c == '[') { /* new style with id */
if (fscanf(data_file, " %d ", &id) != 1 || getc(data_file) != ']')
- EXIT(_("syntax error in item identifier"));
+ io_load_error(path_todo, line, _("syntax error in item identifier"));
while ((c = getc(data_file)) == ' ') ;
ungetc(c, data_file);
} else {
@@ -777,10 +793,10 @@ void io_load_keys(const char *pager)
WARN_MSG(_("Some actions do not have any associated key bindings!"));
}
-void io_check_dir(char *dir, int *missing)
+int io_check_dir(const char *dir)
{
if (read_only)
- return;
+ return -1;
errno = 0;
if (mkdir(dir, 0700) != 0) {
@@ -788,45 +804,46 @@ void io_check_dir(char *dir, int *missing)
fprintf(stderr, _("FATAL ERROR: could not create %s: %s\n"), dir,
strerror(errno));
exit_calcurse(EXIT_FAILURE);
+ } else {
+ return 1;
}
} else {
- if (missing)
- (*missing)++;
+ return 0;
}
}
-unsigned io_file_exist(char *file)
+unsigned io_file_exist(const char *file)
{
FILE *fd;
- if (!file)
- return 0;
-
- if ((fd = fopen(file, "r")) == NULL)
+ if (file && (fd = fopen(file, "r")) != NULL) {
+ fclose(fd);
+ return 1;
+ }
+ else {
return 0;
-
- fclose(fd);
-
- return 1;
+ }
}
-void io_check_file(char *file, int *missing)
+int io_check_file(const char *file)
{
if (read_only)
- return;
+ return -1;
errno = 0;
- if (!io_file_exist(file)) {
+ if (io_file_exist(file)) {
+ return 1;
+ } else {
FILE *fd;
- if (missing)
- (*missing)++;
if ((fd = fopen(file, "w")) == NULL) {
fprintf(stderr, _("FATAL ERROR: could not create %s: %s\n"), file,
strerror(errno));
exit_calcurse(EXIT_FAILURE);
}
file_close(fd, __FILE_POS__);
+
+ return 0;
}
}
@@ -844,17 +861,15 @@ void io_check_file(char *file, int *missing)
*/
int io_check_data_files(void)
{
- int missing, missing_keys;
+ int missing = 0;
- missing = missing_keys = 0;
- errno = 0;
- io_check_dir(path_dir, &missing);
- io_check_dir(path_notes, &missing);
- io_check_file(path_todo, &missing);
- io_check_file(path_apts, &missing);
- io_check_file(path_conf, &missing);
- io_check_file(path_keys, &missing_keys);
- if (missing_keys) {
+ missing += io_check_dir(path_dir) ? 0 : 1;
+ missing += io_check_dir(path_notes) ? 0 : 1;
+ missing += io_check_file(path_todo) ? 0 : 1;
+ missing += io_check_file(path_apts) ? 0 : 1;
+ missing += io_check_file(path_conf) ? 0 : 1;
+
+ if (!io_check_file(path_keys)) {
missing++;
keys_dump_defaults(path_keys);
}
@@ -879,14 +894,13 @@ void io_startup_screen(int no_data_file)
/* Export calcurse data. */
void io_export_data(enum export_type type)
{
- FILE *stream;
+ FILE *stream = NULL;
const char *success = _("The data were successfully exported");
const char *enter = _("Press [ENTER] to continue");
if (type < IO_EXPORT_ICAL || type >= IO_EXPORT_NBTYPES)
EXIT(_("unknown export type"));
- stream = 0;
switch (ui_mode) {
case UI_CMDLINE:
stream = stdout;
@@ -913,46 +927,20 @@ 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;
+ FILE *stream = NULL;
char *stream_name;
const char *ask_fname = _("Enter the file name to import data from:");
const char *wrong_file =
_("The file cannot be accessed, please enter another file name.");
const char *press_enter = _("Press [ENTER] to continue.");
- int cancel;
- stream = NULL;
stream_name = mem_malloc(BUFSIZ);
memset(stream_name, 0, BUFSIZ);
while (stream == NULL) {
status_mesg(ask_fname, "");
- cancel = updatestring(win[STA].p, &stream_name, 0, 1);
- if (cancel) {
+ if (updatestring(win[STA].p, &stream_name, 0, 1)) {
mem_free(stream_name);
return NULL;
}
@@ -1090,13 +1078,10 @@ void io_log_print(struct io_file *log, int line, const char *msg)
void io_log_display(struct io_file *log, const char *msg, const char *pager)
{
- int ans;
-
RETURN_IF(log == NULL, _("No log file to display!"));
if (ui_mode == UI_CMDLINE) {
printf("\n%s [y/n] ", msg);
- ans = fgetc(stdin);
- if (ans == 'y') {
+ if (fgetc(stdin) == 'y') {
const char *arg[] = { pager, log->name, NULL };
int pid;
@@ -1125,9 +1110,7 @@ static pthread_t io_t_psave;
/* Thread used to periodically save data. */
static void *io_psave_thread(void *arg)
{
- int delay;
-
- delay = conf.periodic_save;
+ int delay = conf.periodic_save;
EXIT_IF(delay < 0, _("Invalid delay"));
for (;;) {
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..2a207e2 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,
@@ -372,13 +275,16 @@ void todo_update_panel(int which_pan)
llist_item_t *i;
int len = win[TOD].w - 8;
int num_todo = 0;
- int y_offset = 3, x_offset = 1;
+ int title_lines = conf.compact_panels ? 1 : 3;
+ int y_offset = title_lines, x_offset = 1;
int t_realpos = -1;
- int title_lines = 3;
int todo_lines = 1;
int max_items = win[TOD].h - 4;
int incolor = -1;
+ if ((int)win[TOD].h < 4)
+ return;
+
/* Print todo item in the panel. */
erase_window_part(win[TOD].p, 1, title_lines, win[TOD].w - 2, win[TOD].h - 2);
LLIST_FOREACH(&todolist, i) {
@@ -397,9 +303,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 +318,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/vars.c b/src/vars.c
index b6bddcb..ac6654c 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -134,6 +134,8 @@ void vars_init(void)
conf.auto_save = 1;
conf.auto_gc = 0;
conf.periodic_save = 0;
+ conf.default_panel = CAL;
+ conf.compact_panels = 0;
conf.system_dialogs = 1;
conf.progress_bar = 1;
strncpy(conf.output_datefmt, "%D", 3);
diff --git a/src/wins.c b/src/wins.c
index ea7fd9f..23894e7 100644
--- a/src/wins.c
+++ b/src/wins.c
@@ -216,12 +216,6 @@ void wins_sbar_wdec(void)
sbarwidth_perc--;
}
-/* Initialize the selected window in calcurse's interface. */
-void wins_slctd_init(void)
-{
- wins_slctd_set(CAL);
-}
-
/* Returns an enum which corresponds to the window which is selected. */
enum win wins_slctd(void)
{
@@ -245,7 +239,8 @@ void wins_slctd_next(void)
static void wins_init_panels(void)
{
- win[CAL].p = newwin(CALHEIGHT, wins_sbar_width(), win[CAL].y, win[CAL].x);
+ win[CAL].p = newwin(CALHEIGHT + (conf.compact_panels ? 2 : 4),
+ wins_sbar_width(), win[CAL].y, win[CAL].x);
wins_show(win[CAL].p, _("Calendar"));
win[APP].p = newwin(win[APP].h, win[APP].w, win[APP].y, win[APP].x);
@@ -301,9 +296,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)
@@ -363,11 +357,14 @@ void wins_show(WINDOW * win, const char *label)
int width = getmaxx(win);
box(win, 0, 0);
- mvwaddch(win, 2, 0, ACS_LTEE);
- mvwhline(win, 2, 1, ACS_HLINE, width - 2);
- mvwaddch(win, 2, width - 1, ACS_RTEE);
- print_in_middle(win, 1, 0, width, label);
+ if (!conf.compact_panels) {
+ mvwaddch(win, 2, 0, ACS_LTEE);
+ mvwhline(win, 2, 1, ACS_HLINE, width - 2);
+ mvwaddch(win, 2, width - 1, ACS_RTEE);
+
+ print_in_middle(win, 1, 0, width, label);
+ }
}
/*
@@ -375,6 +372,10 @@ void wins_show(WINDOW * win, const char *label)
*/
void wins_get_config(void)
{
+ enum win win_master;
+ enum win win_slave[1];
+ unsigned master_is_left;
+
/* Get the screen configuration */
getmaxyx(stdscr, row, col);
@@ -396,88 +397,31 @@ void wins_get_config(void)
win[NOT].x = 0;
}
- win[CAL].w = wins_sbar_width();
- win[CAL].h = CALHEIGHT;
+ win[CAL].h = CALHEIGHT + (conf.compact_panels ? 2 : 4);
- if (layout <= 4) { /* APPOINTMENT is the biggest panel */
- win[APP].w = col - win[CAL].w;
- win[APP].h = row - (win[STA].h + win[NOT].h);
- win[TOD].w = win[CAL].w;
+ if (layout <= 4) {
+ win_master = APP;
+ win_slave[0] = ((layout - 1) % 2 == 0) ? CAL : TOD;
+ win_slave[1] = ((layout - 1) % 2 == 1) ? CAL : TOD;
win[TOD].h = row - (win[CAL].h + win[STA].h + win[NOT].h);
- } else { /* TODO is the biggest panel */
- win[TOD].w = col - win[CAL].w;
- win[TOD].h = row - (win[STA].h + win[NOT].h);
- win[APP].w = win[CAL].w;
+ } else {
+ win_master = TOD;
+ win_slave[0] = ((layout - 1) % 2 == 0) ? CAL : APP;
+ win_slave[1] = ((layout - 1) % 2 == 1) ? CAL : APP;
win[APP].h = row - (win[CAL].h + win[STA].h + win[NOT].h);
}
+ master_is_left = ((layout - 1) % 4 < 2);
- /* defining the layout */
- switch (layout) {
- case 1:
- win[APP].y = 0;
- win[APP].x = 0;
- win[CAL].y = 0;
- win[TOD].x = win[APP].w;
- win[TOD].y = win[CAL].h;
- win[CAL].x = win[APP].w;
- break;
- case 2:
- win[APP].y = 0;
- win[APP].x = 0;
- win[TOD].y = 0;
- win[TOD].x = win[APP].w;
- win[CAL].x = win[APP].w;
- win[CAL].y = win[TOD].h;
- break;
- case 3:
- win[APP].y = 0;
- win[TOD].x = 0;
- win[CAL].x = 0;
- win[CAL].y = 0;
- win[APP].x = win[CAL].w;
- win[TOD].y = win[CAL].h;
- break;
- case 4:
- win[APP].y = 0;
- win[TOD].x = 0;
- win[TOD].y = 0;
- win[CAL].x = 0;
- win[APP].x = win[CAL].w;
- win[CAL].y = win[TOD].h;
- break;
- case 5:
- win[TOD].y = 0;
- win[TOD].x = 0;
- win[CAL].y = 0;
- win[APP].y = win[CAL].h;
- win[APP].x = win[TOD].w;
- win[CAL].x = win[TOD].w;
- break;
- case 6:
- win[TOD].y = 0;
- win[TOD].x = 0;
- win[APP].y = 0;
- win[APP].x = win[TOD].w;
- win[CAL].x = win[TOD].w;
- win[CAL].y = win[APP].h;
- break;
- case 7:
- win[TOD].y = 0;
- win[APP].x = 0;
- win[CAL].x = 0;
- win[CAL].y = 0;
- win[TOD].x = win[CAL].w;
- win[APP].y = win[CAL].h;
- break;
- case 8:
- win[TOD].y = 0;
- win[APP].x = 0;
- win[CAL].x = 0;
- win[APP].y = 0;
- win[TOD].x = win[CAL].w;
- win[CAL].y = win[APP].h;
- break;
- }
+ win[win_master].x = master_is_left ? 0 : wins_sbar_width();
+ win[win_master].y = 0;
+ win[win_master].w = col - wins_sbar_width();
+ win[win_master].h = row - (win[STA].h + win[NOT].h);
+
+ win[win_slave[0]].x = win[win_slave[1]].x =
+ master_is_left ? win[win_master].w : 0;
+ win[win_slave[0]].y = 0;
+ win[win_slave[1]].y = win[win_slave[0]].h;
+ win[win_slave[0]].w = win[win_slave[1]].w = wins_sbar_width();
}
/* draw panel border in color */
@@ -641,7 +585,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 };
@@ -692,7 +636,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..76a40fb 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,7 +15,13 @@ TESTS = \
range-003.sh \
appointment-001.sh \
next-001.sh \
- search-001.sh
+ search-001.sh \
+ bug-002.sh \
+ recur-001.sh \
+ recur-002.sh \
+ recur-003.sh \
+ recur-004.sh \
+ recur-005.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
diff --git a/test/data/apts-recur b/test/data/apts-recur
new file mode 100644
index 0000000..0fdfe3e
--- /dev/null
+++ b/test/data/apts-recur
@@ -0,0 +1,12 @@
+01/01/2000 [1] {1D} Each day since 2000-01-01
+01/01/2000 [1] {1W} Each Saturday since 2000-01-01
+01/01/2000 [1] {1M} Each first day of the month since 2000-01-01
+01/01/2000 [1] {1Y} Every year on January, 1st since year 2000
+01/01/2000 [1] {2D} Every second day since 2000-01-01
+01/01/2000 [1] {4W} Every 28 days since 2000-01-01
+01/01/2000 [1] {7D} Same as "01/01/2000 [1] {1W}"
+01/01/2000 [1] {3D -> 12/31/2000} Every three days in year 2000
+01/01/2000 [1] {3D !01/04/2000} Every three days, but not on 2000-01-04
+01/01/2000 @ 16:00 -> 01/02/2000 @ 02:00 {2D} |Recurrent appointment
+01/01/2000 @ 00:00 -> 01/07/2000 @ 00:00 {1W} |Another recurrent appointment
+01/01/2000 @ 00:00 -> 01/07/2000 @ 00:00 {1D} |Third recurrent appointment
diff --git a/test/recur-001.sh b/test/recur-001.sh
new file mode 100755
index 0000000..307c174
--- /dev/null
+++ b/test/recur-001.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-recur" \
+ -s01/01/2000 -r8 --format-recur-apt=''
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+01/01/00:
+ * Each day since 2000-01-01
+ * Each Saturday since 2000-01-01
+ * Each first day of the month since 2000-01-01
+ * Every year on January, 1st since year 2000
+ * Every second day since 2000-01-01
+ * Every 28 days since 2000-01-01
+ * Same as "01/01/2000 [1] {1W}"
+ * Every three days in year 2000
+ * Every three days, but not on 2000-01-04
+
+01/02/00:
+ * Each day since 2000-01-01
+
+01/03/00:
+ * Each day since 2000-01-01
+ * Every second day since 2000-01-01
+
+01/04/00:
+ * Each day since 2000-01-01
+ * Every three days in year 2000
+
+01/05/00:
+ * Each day since 2000-01-01
+ * Every second day since 2000-01-01
+
+01/06/00:
+ * Each day since 2000-01-01
+
+01/07/00:
+ * Each day since 2000-01-01
+ * Every second day since 2000-01-01
+ * Every three days in year 2000
+ * Every three days, but not on 2000-01-04
+
+01/08/00:
+ * Each day since 2000-01-01
+ * Each Saturday since 2000-01-01
+ * Same as "01/01/2000 [1] {1W}"
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/recur-002.sh b/test/recur-002.sh
new file mode 100755
index 0000000..d302971
--- /dev/null
+++ b/test/recur-002.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-recur" \
+ -d02/01/2000 --format-recur-apt=''
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+02/01/00:
+ * Each day since 2000-01-01
+ * Each first day of the month since 2000-01-01
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/recur-003.sh b/test/recur-003.sh
new file mode 100755
index 0000000..fadaea0
--- /dev/null
+++ b/test/recur-003.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-recur" \
+ -d01/01/2001 --format-recur-apt=''
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+01/01/01:
+ * Each day since 2000-01-01
+ * Each first day of the month since 2000-01-01
+ * Every year on January, 1st since year 2000
+ * Every second day since 2000-01-01
+ * Every three days, but not on 2000-01-04
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/recur-004.sh b/test/recur-004.sh
new file mode 100755
index 0000000..39ea193
--- /dev/null
+++ b/test/recur-004.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-recur" \
+ -d01/01/2000 --format-recur-event=''
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+01/01/00:
+ - 00:00 -> ..:..
+ Another recurrent appointment
+ - 00:00 -> ..:..
+ Third recurrent appointment
+ - 16:00 -> ..:..
+ Recurrent appointment
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/recur-005.sh b/test/recur-005.sh
new file mode 100755
index 0000000..6f9d4c3
--- /dev/null
+++ b/test/recur-005.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ "$1" = 'actual' ]; then
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/apts-recur" \
+ -d01/10/2000 --format-recur-event=''
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+01/10/00:
+ - ..:.. -> ..:..
+ Another recurrent appointment
+ - ..:.. -> 02:00
+ Recurrent appointment
+ - 00:00 -> ..:..
+ Third recurrent appointment
+EOD
+else
+ ./run-test "$0"
+fi
diff --git a/test/run-test.c b/test/run-test.c
index c779be7..fb5bcb4 100644
--- a/test/run-test.c
+++ b/test/run-test.c
@@ -183,6 +183,9 @@ static int run_test(const char *name, int expect_failure)
}
}
+ if (fgets(buf2, BUFSIZ, fpin2))
+ ret = 0;
+
if (fpin1)
fclose(fpin1);
if (fpin2)